Thursday, January 26, 2017

On Anemic Domain Models


The data model has the responsibility to store data, whereas the domain model has the responsibility to handle business logic. An application can be considered CRUD only if there is no business logic around the data model. Even in this (rare) case, your data model is not your domain model. It just means that, as no business logics is involved, we don’t need any abstraction to manage it, and thus we have no domain model.
 Ouarzy, It Is Not Your Domain.

I really like this observation, in that it gives me some language to distinguish CRUD implementations, where we don't have any invariant to enforce, and anemic domains, where there is an invariant, but we don't keep the invariant and the state changing behavior in the same logical unit.

We probably need more variations here
  • There is no invariant (CRUD)
  • There is an invariant, but it is maintained by human beings -- the invariant is not present in the code
  • There is an invariant in the code, but the code is arranged such that modification of state can happen without maintaining the invariant (anemic)
  • There is an invariant in the code, and the code is arranged so that any change of state is checked against the invariant.
Having some anemic code paths isn't wrong -- it's a desirable property for the software to be able to get out of the way so that the operator in the present can veto the judgment of the implementer in the past. 

But if the software is any good, bypassing the domain model should be unusual enough that additional steps to disable the safeties is acceptable.

Thursday, January 19, 2017

Whatever it takes

Whatever it takes is a large cash bonus, paid up front.

A RESTful supply closet

At stackflow, another question was submitted about REST API design for non CRUD actions.  In thinking about it, I found an analogy that may help explain the point.

Imagine a supply closet; an actual physical closet in the real world.  The stock includes boxes of pencils.  What does a web API for the supply closet look like?

As Jim Webber pointed out years ago, HTTP is a document management application.  So the first thing to realize is that we are trying to create an interface that supports the illusion that the supply closet is a document store.  If we want to know about the current state of the closet, we read the latest report out of the store.  To change the state of the closet, we propose changes to the document store.

How do we convert the current state of the closet to a document?  In the real world (think 1950s office), we would ask the quartermaster for the latest inventory document.  If a recent one is available, the quartermaster gives us a copy of that document.  Otherwise, he can look in the closet, count the boxes, and produce send us a copy of the fresh report.

That, fundamentally, is GET.  We ask the API for a copy of the inventory report.  Maybe the API just copies the report that's posted on the closet door, maybe the API goes inside the closet to count everything, maybe the closet isn't accessible, so we just get the last report the API saw.  Doesn't matter, we got a document.

Now, key in the next stage is to realize that the document is not the closet; when we edit the document, boxes of pencils don't magically appear in the closet.  What we need to implement is the illusion that the closet really is a document store.

In our real world model, we read the inventory report, and there aren't enough pencils.  So we create a new document -- a memo to the quartermaster that says "stock more pencils".  When we deliver the memo to the quartermaster, he decides how to get more pencils for the closet -- maybe he gets boxes out of storage, or buys some from the store next door.  Maybe he updates his todo list (another document)  and tells you he'll get back to you.


This is the basic idiom of HTML forms.  We create (POST) a new document to the API, and the API interprets that document as changes to be made to the closet.  The requisition document and the inventory document are different resources.  For that matter, the collection of requisition documents and the inventory document are different resources.  So you need a different namespace of identifiers to work with.

HTTP (but not HTML) also supports another approach.  Instead of interacting with the closet by submitting new documents, we could interact with the closet by proposing edits to the existing documents.

This, to my mind, feels a bit more declarative -- you describe in the edited document the state that you want the closet to be in, and its up to the API to figure out the details of making that happen.  In our analogy, we've sent to the quartermaster a copy of the inventory with a bunch of corrections made to it, and he changes the state of the closet to match the document.

This is PUT -- specifically a PUT to the inventory resource.  Notice that it doesn't change what work the quartermaster needs to do to fill the closet; it doesn't change his schedule for doing that work, it doesn't change the artifacts that he generates while doing the work.  It just changes which document manipulation illusion we are choosing to support.

Now, HTTP is specific about the behavior of the imaginary document store we are mimicking, which is that PUT is an upsert.  If we want fine grained control of the contents of the closet ("more pencils, leave everything else alone"), then we need to upsert to a resource with a matching grain.

PATCH is another alternative to introducing finer grained resources; we send the patch to the server, it compares the patched version of the inventory document to the original version, and from there decides what changes need to be made to the closet.

These are all variations of the same fundamental idea - the HTTP request describes the desired end state, and the implementation sitting behind the API figures out how to realize that end.

Thursday, January 5, 2017

Backups?

Until you have performed a successful restore, it's not a backup.

Same idea, different spelling: nobody needs backups; what they need are restores.

Wednesday, January 4, 2017

TDD: A Tale of two Katas

Over the Holiday, I decided to re-examine Peter Siebel's Fischer Random Chess Kata.

I have, after all, a lot more laps under my belt than when I was first introduced to it, and I thought some of my recent studies would allow me to flesh things out more thoroughly.

Instead, I got a really educational train wreck out of it.  What I see now, having done the kata twice, is that the exercise (once you get the insight to separate the non determinable generator from the board production rules) is about applying specifications to a value type, rather than evaluating the side effects of behaviors.

You could incrementally develop a query object that verifies that some representation of a fair chess row satisfies the constraints -- the rules would come about as you add new tests to verify that that some input satisfies/does-not-satisfy the specification, until the system under test correctly understands the rules.  Another way of saying the same thing: you could write a factory that accepts as input an unconstrained representation of a row, and produces a validated value type for only those inputs that satisfy the constraints.

But, as RFC 1149.5 taught us, you can't push a stateless query out of a local minima.

Realizing this -- that the battle I thought I was going to write about was doomed before I even reached the first green bar, I decided to turn my attention to the bowling game kata.

Amusingly enough, I started from a first passing test, and then never moved off of the original green bar.

Part of the motivation for the exercise was my recent review of Uncle Bob's Dijkstra's Algorithm kata.  I wanted to play more with the boundaries in the test, and get a better feel for how they arise as a response to the iteration through the tests.

So I copied (less than perfectly) Uncle Bob's first green bar, and then started channeling my inner Kent Beck

Do you have some refactoring to do first?
With that idea in mind, I decided to put my attention on "maximizes clarity".  There's some tension in here -- the pattern that emerges is so obviously generic that one is include to suggest I was the victim of big design up front, and that I wasn't waiting for the duplication in tests to realize that pattern for me.  So on some level, one might argue that I've violated YAGNI.  On the other hand, if you can put a name on something, then it is already been realized -- you are simply choosing to acknowledge that realization, or not.

In doing that, I was surprised -- there are more boundaries in play than I had previously recognized.

There's a boundary between the programmer and the specification designer.  We can't think at the IDE and have it do the right thing, we actually need to type something; furthermore, that thing we type needs to satisfy a generic grammar (the programming language).

The specification designer is code that essentially responsible for "this is what the human being really meant."  It's the little DSL we write that makes introducing new specifications easy.

There's a boundary between specification design and the test harness -- we can certainly generate specifications for a test in more than one way, or re-use a specification for more than one test.  Broadly, the specification is a value type (describing input state and output state) where the test is behavior -- organized interactions with the system under test.

The interface between the test and the system under test is another boundary.  The specification describes state, but it is the responsibility of the test to choose when and how to share that state with the system under test.

Finally, there is the boundary within the system under test -- between the actual production code we are testing, and the adapter logic that aligns the interface exposed by our production code with that of the test harness.

This bothered me for a while - I knew, logically, that this separation was necessary if the production code was have the freedom to evolve.  But I couldn't shake the intuition that I could name that separation now, in which case it should be made explicit.

The following example is clearly pointless code

And yet this is the code we write all the time

And that's not a bad idea -- we are checking that two outcomes, produced in different ways, match.
But the spellings are wrong: the names weren't telling me the whole story. In particular, I'm constantly having problems remembering the convention of which argument comes first.

It finally sank in: the boundary that I am trying to name is time. A better spelling of the above is:

We write a failing test, then update an implementation to satisfy a check written in the past, and then we refactor the implementation, continuing to measure that the check is still satisfied after each change. If we've done it right, then we should be able to use our earliest checks until we get an actual change in the required behavior.

I also prefer a spelling like this, because it helps to break the symmetry that gives me trouble -- I don't need to worry any longer about whether or not I'm respecting screen direction, I just need to distinguish then from now.

The adapter lives in the same space; it's binding the past interface with the present interface.  The simplest thing that could possible work has those two things exactly aligned.  But there's a trap there -- it's going to be a lot easier to make this seam explicit now, when there is only a single test, than later, when you have many tests using the wrong surface to communicate with your production code.

There's another interpretation of this sequence.  In many cases, the implementation we are writing is an internal element of a larger application.  So when we write tests specifically for that internal element, we are (implicitly) creating a miniature application that communicates more directly with that internal element.  The test we have written is communicating with the adapter application, not with the internal element.

This happens organically when you work from the outside in - the tests are always interfacing with the outer surface, while the rich behaviors are developed within.

The notion of the adapter as an application is a deliberate one -- the dependency arrow points from the adapter to the test harness.  The adapter is a service provider, implementing an interface defined by the test harness itself.  The adapter is also interfacing with the production code; so if you were breaking these out into separate modules, the adapter would end up in the composition root.

Key benefit of these separations; when you want to take a new interface out for a "test drive", you don't need to touch the tests in any way -- the adapter application serves as the first consumer of the new production interface.


Note that the checks were defined in the past, which is the heuristic that reminds you that checking is the responsibility of the test harness, not the adapter application.  The only check that the adapter can reliably perform is "is the model in an internally consistent state", which is nice, but the safety to refactor comes from having an independent confirmation that the application outputs are unchanged.

Another benefit to this exercise: it has given me a better understanding of primitive obsession.  Boundaries are about representations, and primitives are a natural language for describing representations.  Ergo, it makes sense that we describe our specifications with primitives, and we use primitives to communicate across the test boundary to the (implicit) adapter application, and from there to our proposed implementation.  If we aren't aware of the intermediate boundaries, or are deferring them, there's bound to be a lot of coupling between our specification design and the production implementation.

Monday, December 26, 2016

Observations on Write Models

I was recently involved in a protracted discussion of write models, specifically within the context of CQRS and event sourcing.  Some of my observations I was learning on the fly; I want to take some time to express them clearly.

For a write (which is to say, a change of state) to use useful, it must be visible -- without a way to retrieve the state written, the write operation itself might as well be implemented as a no-op.

Three useful ways of implementing a write

1) Write into a shared space.  Examples of this include I/O, writing to a database, writing to shared memory.  The write model makes publicly readable writes.

2) Write into a private space, and provide an interface to repeat those writes to some service provider. Changes to state are locally private, the publishing responsibility lives with the service provider.

3) Write into a private space, and provide an interface to query those writes.  Changes to state are locally private, but we also provide an interface that supports reads.


The middle of these options is just a punt -- "we can solve any problem by adding an extra layer of indirection.

The first approach couples the aggregate to the process boundary -- any write to the aggregate is necessarily tied to the write at the boundary.  This is especially visible in Java, where you are likely to have checked exceptions thrown at the boundary, and bubble up through the interface of the aggregate.

The third option leaves the aggregate decoupled from the boundary, the aggregate tracks changes to the local state, but some other service is responsible for making those changes durable.

In DDD, this other service is normally the "repository"; a simplified template of a command handler will typically look something like



Of course, within Repository.save() there must be logic to query the aggregate for state, or to pass to the aggregate some state writer callback. For instance, almost all of the event sourcing frameworks I've seen have all aggregates inherit some common base class that tracks changes and supports a query to fetch those changes to write them to an event store.

I have two concerns with this design -- the first problem is that the Repository, which is supposed to be an abstraction of the persistence layer, seems to know rather a lot about the implementation details of the model.  The second problem is that the repository is supposed to
provide the illusion of an in memory collection of all objects of that type...  provide methods to add and remove objects, which will encapsulate the actual insertion of removal of data in the data store.
That illusion, I find, is not a particularly satisfactory one -- sending data across a process boundary is not like storing an object in memory.  Furthermore, in this definition, we're palming a card; we've switched the vocabulary from objects to data (state).  The conversion of one to the other is implied.

What if we wanted to make this conversion explicit -- what might that look like?  At SCNA 2012, Gary Bernhardt spoke of boundaries, and the roles that value types play.  Mark Seemann touched on a similar theme in 2011 -- noting that applications are not object oriented at the process boundary.  So what happens if we adapt our example with that principle in mind?



State here is a value type - it is part of the API satisfied by the model; in particular, we want that API to be stable between old versions of the model and new versions of the model. The aggregate -- the object which carries with it the business rules that constrain how the state can change, is really an implementation detail within the model itself. Which is to say that in simple cases we may be able to write


That's a bit "cute" for my taste, but it does make it really obvious how the automated tests for the model are going to go.

Written out this style, I tend to think of the model in a slightly different way; the model performs simulations of business use cases on demand, and the application chooses which outcomes to report to the persistence component.

A curiosity that falls out of this design is that one model could support both event persistence and snapshot persistence, leaving the choice up to the application and persistence components.  The model's contribution might look like



Another effect of this design that I like is the tracking of the original state is no longer hidden. If we're going to support "compare and swap persistence", or merge, then we really need to maintain some sense of the starting point, and I'm much happier having that exposed as an immutable value.

Additionally, because the current state isn't lost within the repository abstraction, we can think about resolving merge conflicts in the model, rather that in the application or the persistence component.  In other words, resolving a merge becomes another model simulation, and we can test it without the need to create conflicts via test doubles.

What does all this mean for aggregates?  Well, the persistence component is responsible for writing changes to the book of record, so the aggregate doesn't need to be writing into a public space.  You could have the model pass a writer the the aggregate, where the writer supports a query interface; I don't yet see how that's a win over having the aggregate implementation support queries directly.  So I'm still leaning towards including an interface that returns a representation of the aggregate.

Which means that we could still use the repository illusion, and allow the repository implementation to query that same interface for that representation.  At the whiteboard, I don't like the coupling between the model and persistence; but if it's simpler, and if we understand how to back out the simplification when it no longer meets our needs, then I don't think there's a problem.  It's important not to get locked into a pattern that prevents future innovation.




Sunday, November 6, 2016

A short lesson in unit testing.

I've been reviewing Uncle Bob's essay on Dijkstra's Algorithm, and Greg Young's 2011 Probability Kata.  From this, I've taken away a few sharp lessons.

Test Specifications


It absolutely doesn't matter how you write your test specifications. Ideally, you'd like to maintain flexibility, so the notion of having then in a language agnostic representation where anybody can work on them has merit.
If you are seeing references to your current domain model objects in your test specifications, you are way too tightly coupled.

API

  • Your test specifications don't talk to your implementations
  • Your test specifications don't talk to your implemented apis
  • Your test specifications talk to your TEST api
More carefully, your test api interprets the test specifications, and adapts them to the system under test.


My current interpretation is that the test api should consist of three stages -- Given/When/Then is a pretty good approximation.  We need to load the system under test in the appropriate initial state (Given), we need to exchange a message with it (When), and we need to run checks on the message that we receive in the exchange (Then).

Note that last point - we don't want to be poking around in the internals of anything we are testing; we want any probes to be looking a stable interpretation of the api we are testing.

Evolution over time

Worth repeating for emphasis - we should not need to change our checks when the implementation that we are measuring changes.  We're crossing a process boundary, so the messages connecting the test implementation to the subject should be DTOs in both directions.  For any given implementation, the DTOs should be stable: they are effectively part of the API of the implementation.

But the test design should allow us to swap out one implementation for another with an entirely different API.  That will mean finding the new way to load instances of the implementation, and a new adapter of the messages from the specifications language to the implementations API.  The adapter also brings the api language back to the language of the specification, and the checks do not change.

Think HTTP: the web server offers a stable interface against which a specification can be written.  The implementation of the resources on the web server adapt the incoming messages, creating new representations that can be exchanged with the the domain's API.  The domain responds to the web server, the web server transforms the DTO from the domain model to that which conforms to the specification, and the result is sent back to the client.

So when we are looking at the execution of our specifications, we should be able to find a seam; a point in the execution where the specified inputs (Given, When) are passed to the Test API, and a response is returned that can be checked against Then.



Here in Uncle Bob's code, makePathFinder serves as the seam, although it is an imperfect one. (Editorial note: which is fine. Uncle Bob's kata was about test specifications leading to Dijkstra's algorithm. My kata is about test evolution. Horses for courses.).

The main flaw here is the appearance of the PathFinder type, which is taken from the implementation namespace, rather than the specification namespace. We can't see that from the signature alone, but it becomes clear if we drill deeper into the test implementation

When we see that this is a type built from inputs, rather than from outputs, which is a really big hint that something has gone south. Only messages should be crossing the boundary from the solution to the test, but PathFinder is a type with behavior. The abstraction barrier is leaking. We shouldn't need to change our specification execution when the name of the target changes; that's a violation of encapsulation -- we should be able to replace the connection to the real implementation with a lookup table without needing to make any changes in the execution of the specifications.


Sure, you could sexy it up with an immutable message type, or even a EnumMap to ensure that you don't get confused. The point is to keep in mind that you are checking the specification against plain old data - the response cross the barrier from the system under test to the test, and the test api aligns that response with the representations expected by your speficication.