Tuesday, January 16, 2018

Events are messages that describe state, not behavior

I have felt, for some time now, that the literature explains event sourcing poorly.

The basic plot, that current state is just a left fold over previous behaviors, is fine, so far as it goes.  But it rather assumes that the audience is clear on what "previous behaviors" means.

And I certainly haven't been.

In many, perhaps even most, domain models can be thought of as state machines:

Cargo begins its life cycle when it is booked, and and our delivery document changes state when the cargo is received, and when an itinerary is selected, it gets loaded in port, the itinerary changes, each of these messages arrives and changes the state of the delivery document.

So we can think of the entire process as a state machine; each message from the outside world causes the model to follow a transition edge out of one state node and into another.

If we choose to save the state of the delivery document, so that we can resume work on it later, there are three approaches we might take
  • We could simply save the entire delivery document as is
  • We could save the sequence of messages that we received
  • We could save a sequence of patch documents that describe the differences between states
Event sourcing is the third one.

We call the patches "events", and they have domain specific semantics; but they are fundamentally dumb documents that decouple the representation of state from the model that generated it.

This decoupling is important, because it allows us to change the model without changing the semantics of the persisted representation.

To demonstrate this, let's imaging a simple trade matching application.  Buy and Sell orders come in from different customers, and the model is responsible for pairing them up.  There might be elaborate rules in place for deciding how matches work, but to save the headache of working them out we'll instead focus our attention on a batch of buy and sell orders that can be paired arbitrarily -- the actual selects are going to be determined by the model's internal tie breaker strategy.

So we'll image that a new burst of messages appear, at some new price -- we don't need to worry about any earlier orders.  The burst begins...

After things have settled down, we restart the service. That means that the in memory state is lost, as has to be recovered from what was written to the persistent store. We now get an additional burst of messages.

Using a first in, first out tiebreaker, we would expect to see pairs (A,1), (B,2), (C,3), and (D,4). If we were using a last in, first out tiebreaker, we would presumably see (D,1), (E,2), (C,3), (B,4).

But what happens if, during the shutdown, we switch from FIFO to LIFO? During the first phase, we see (A,1) matched, as before. After that, we should see (D,2), (E,3), (C,4).

In order to achieve that outcome, the model in the second phase needs knowledge of the (A,1) match before the shutdown. But it can only know about that match if there is evidence of the match written to the persistent store. Without that knowledge, the LIFO strategy would expect that (D,1) were already matched, and would in turn produce (C,2), (E, 3), and (A,4). The last of these conflicts with the original (A,1) match. In other words, we're in a corrupted state.

Writing the entire document to the event store works just fine, we read a representation that suggests that A and 1 are unavailable, and the domain model can proceed accordingly. Writing the sequence of patches works, because when we fold the patches together we get the state document. It's only the middle case, where we wrote out representations that implied a particular model, that we got into trouble.

The middle approach is not wrong, by any means. The LMAX architecture worked this way; they would write the input messages to a journal, and in the event of a failure they would recover by starting a copy of the same model. The replacement of the model behavior happened off hours.

Similarly, if you have the list of inputs and the old behavior, you can recover current state in memory, and then write out a representation of that state that will allow a new model to pick up from where the old left off.

Not wrong, but different. One approach or the other might be more suitable for your unique collection of operational constraints.

Monday, January 15, 2018

Command messages in REST

Kevin Swiber, of SIREN fame, just taught me a nifty trick for describing commands to a resource

Background: commands are semantically unsafe operations, as described in the HTTP specification. They are messages that expect to induce a change of state on the server, they invalidate caches, and so on.

In considering a design that conforms to the REST architectural style, it's useful to ask "how did we do it on the web?" We had URI, and HTTP, and HTML; those elements alone were enough to support catastrophic success.

Now, in HTML, the only readily available link for unsafe operations was the form, which supported only GET and POST. When there's only one road, you take it: servers would send HTML representations that would include Forms, that would describe to the client how to create the command message.

Notice that this is very much a hypermedia approach - if the server wishes to communicate that the command should not be sent, it simply removes the form from the representation.  Elements that are no longer necessary can be removed from the form.  New optional elements can be added by simply including a new input control and providing a reasonable default value.

What this teaches us is that a POST message with an application/x-www-form-urlencoded payload is a perfectly satisfactory way of modeling a command sent to a resource.

But I've got to admit,  that doesn't feel much like "REST".

So here's another way of thinking about it.

HTTP Patch affords the modification of resources.  We tend to think about the payload as a list of changes to make; but another way of thinking about it is that the payload describes a list of commands.  For example, application/json-patch+json is a document that describes operations; add, remove, and so on.

First trick: any resource that supports PATCH application/json-patch+json can just as easily provide the same functionality via POST application/json-patch+json.  The semantics of PATCH are more specific than those of POST, but they don't fundamentally conflict with each other.

Second trick: application/json-patch+json is just a representation of a sequence of operations; with those operations taken specifically from the vocabulary of manipulating a json document.  We don't particularly want to be borrowing those semantics unless they happen to be a particularly good fit for our domain; we likely have our own names for operations, particular parameters, and so on. So we instead might choose our own patch document representation; and write it up so that clients can be coded against it.

Third trick: these media types don't have any magical properties; they are just rules for taking semantic meaning and encoding that meaning as bytes, and then reversing the process at the other end. We can use any byte representation we like, provided that the client and the server agree on the rules being used. We could use text/plain, or application/json. Alas, both of those representations suffer from the problem that we need additional out of band communication to ensure that both ends of the conversation understand the meaning the same way.

Fourth trick: if our command message can be represented as a collection of key/value pairs (likely the case, if we account for hierarchical keys), then application/x-www-form-urlencoding is another possible representation that we might use. It shares the same problem we just saw: the client and server need to agree on semantics. But with one important difference: we already possess a standard format with facilities for describing application/x-www-form-urlencoded representations in band: HTML.

So, yeah -- it's REST.

That still doesn't mean "easy"; the client still has to know what it wants to do, how to find the right form to do it, how to find the fields it wants to set before submitting the form.  In much the same way that JSON Patch puts semantics on top of JSON, you need something that describes your domain semantics on top of HTML (or whatever other hypermedia representation you prefer).

An advantage in this approach is that it allows us to take advantage of the cache invalidation semantics of POST; which is to say, because we are sending the message to be handled by "the" resource, as opposed to some other resource that understands the semantics of a specific command, the caches are able to invalidate the representations that are actually being changed, rather than invalidating an irrelevant side channel.

Thursday, January 4, 2018

Property based testing: Mars Rover

My go to TDD exercise has been the mars rover kata.  Trying a property test first approach to it has been a struggle.  Compared with an example driven approach, there seems to be a whole lot of front loaded pain without an obvious payoff.

I reached out to Paul Holser to see if I was missing a bet, and of course the discussion turned to what sorts of properties I had discovered in the design.

First property: for all inputs, the output is an ordered collection of representations of rover positions.  If we are checking within the domain boundary, this is pretty trivial -- we can use the type system to enforce this constraint.  If we are checking from outside of the boundary, then we're checking that the lines of text/bytes that have been returned to us can be parsed; three entries per represe, the first two entries are coordinates/integers, the last entry is a member of the set of cardinal directions.

Second property: for all inputs, the number of representations in the output equals the number of rovers described by the input.  Rovers are conserved.

Third property: for any inputs, you get the same output each time you run it.

Fourth property: for any pair of inputs, reversing the order of execution does not change the outputs.

In other words, its a pure function.  I don't actually know the battery of tests that you should run to establish this fact.

A rover with an empty instruction set remains at the same coordinates in the same orientation.  This gives us our fifth property: for all inputs, if we replace a single rover's instructions with an empty instruction set (thereby creating a different input), the corresponding output will have the same position.  Note that this indirectly demonstrates that the order of the outputs matches the order of the inputs.

This property would not apply if the rovers moved other than by consuming their own instructions. For example, if one rover were to push another rover out of the way, then the property would not hold.

The above identity leads to two additional properties, both variations of different paths, same destination.

The sixth property takes advantage of the identity to allow us to establish that the behavior of the rovers is consistent with their programs being executed in the right order.  So for all inputs, we can select any rover, and create a new program in the following way: the positions an instructions of the rovers before the selection in the list are copied directly, the positions of the remaining rovers are copied with empty instructions.  We get the corresponding output, and then build a second program -- the output positions are taken as inputs, with empty instruction sets assigned to the rovers before the selected rover, and the original instruction sets assigned to the remainder.  The property to be checked is that the output of this second program matches the original that we started with.

The seventh property is similar; instead of breaking up the original program along neat rover boundaries, we can also split the selected rover's instructions into two pieces, running part of the instruction set with the rovers ahead of it, then running the remaining instructions with the subsequent rovers.

Both of these are basically establishing that we're dealing with a stateless process; the next collection of positions depends only on the current collection of positions and the next instruction.

Up until this point, we haven't really been looking at the semantics of the output at all; we've got a list of coordinates and orientations, but all we've done is check for equality.

Putting this another way, the simplest thing that could possibly work is still to ignore the instruction sets entirely, and simply return the original positions and orientations in each case.

The plateau is rectangular, and presumably the boundary effects are equivalent on all sides.  If you flip the rectangle upside down -- exchanging north for south and east for west -- you get the same configuration of rovers in a different coordinate system.   Right and Left have the same effect on orientation that they did before the flip.  Any interactions with the boundary will still appear at the same points in the evaluations of the rovers.

This yields our eighth property: for any input, if we flip the input position, compute the output, and then flip the output, we should get the same answer that we would get from running the original output as is.

There is a similar result for quarter rotations, if you adjust the input so that the plateau itself is square.

Rotations are mostly immune to boundary effects and collisions, so it's probably reasonable to start there.

One assumption that we probably need to make is that all valid inputs have rovers that start within the region of the specified plateau.  The problem statement doesn't address that point.  I don't think property based testing helps much here - running the checks can only tell you if the test and implementation made compatible assumptions, not correct assumptions.

Property nine: for all inputs, we can select any rover and replace it's original instruction set with one that has all of the move instructions removed.  When we run this program:
  • The coordinates of the output should match those of the input
  • The orientation of the output will match that of the input if, and only if, the difference in the count of left instructions and the count of right instructions is a multiple of four. 
Finally, we have the possibility of an input that forces us to change the position of the rover!

This establishes that we've got four-symmetry, that left and right cancel each other out, and that rotations preserve position.

Property ten: for all inputs, we can select any rover and replace it's original instruction set with a one that elides all of the left and right instructions.  When we run this program, the orientation of the selected rover will be unchanged.

EDIT: come to think of it, any single instruction leaves at least two of the three properties unchanged; the remaining property changes by at most one unit.  The complication of the move instruction is that you need the orientation to know which property is changing in which direction.

We can introduce into this domain the concept of a displacement - we're in a taxicab geometry.  The number of moves in an instruction set establishes an upper bound on the displacement that can be achieved; we know that the rover will be found somewhere in the circle.

Property eleven: for all inputs, we can measure the displacement of the output coordinates from the input coordinates.  For each rover, the displacement will be less than or equal to the count of moves in its instruction set.

Furthermore, if the circle doesn't reach the boundary of the plateau, then we don't need to worry about boundary effects for that rover.  Taking the initial positions of the rovers, and the size of the bounding circles allows us to compute a bounding box; if the box doesn't reach the plateau boundaries, then the simulation is completely free of boundary effects.

If the plateau is large enough to enclose the bounding box at two different locations, then we can establish twelfth property - that of translation symmetry in the following way.  Given any valid input, we can compute the extents of a bounding box that encloses the possible programs of all rovers.  Choose a displacement in positive x and y.  Compute the dimensions of a plateau by adding the displacement to the extent of the bounding box.  Create two inputs using this plateau: for the first, compute the initial positions of the rovers such that the lower left corner of the bounding box is at the origin; for the second, compute initial positions of the rovers such that the upper right corner of the bounding box is at the upper right corner of the plateau.  Note that the relative displacment of the input coordinates of the corresponding rovers should be the same.  Compute outputs for both programs; the displacements of the corresponding outputs should all match.

The thirteenth property also plays with bounding boxes to establish this property - that if the bounding circles of two rovers don't overlap, then they don't have any interference effects.  The check goes something like this: first you run a single program with all of the rovers participating.  Then you run a program that isolates each rover on the same plateau, and confirm that the final positions of the isolated rovers matches that predicted by the single program containing all of the rovers.

It's not clear how you transform input with overlapping bounding circles into one that doesn't have them.  Do you move the rovers? shrink the bounding circles? skip examples that don't match the criteria?

But in the main, it seems to be a very powerful pattern to use an input as a seed from which you can compute an input that has the properties you want to verify -- using an identity transformation wherever possible.

It's not so clear to me that these constraints are driving the design in any useful way.  For example, we don't have any properties that establish that left and right are correctly oriented.  We don't have any tests that actually demonstrate that the rover has moved.

Tuesday, January 2, 2018

Property based testing: thoughts of a novice.

The tension between these two ideas drives me nuts.  Thinking way harder means that I'm not delivering features faster.

Example based testing is straight forward; choose an input, hard code the output, remove the duplication, repeat until you have no more examples that produce the wrong output.  You may even be able to estimate the minimum required number of tests just by thinking about the cyclomatic complexity of the problem.

But this in turn means that you can't easily judge "complete" just from looking at the demonstrated examples.  As Scott Wlaschin points out, a finite suite of example tests can be beaten by a pathological implementation that is fitted to the suite.

Property based tests handle this concern better -- they explore the domain, rather than just sampling it.  That's a lie, of course; what property based tests are really doing is sampling a lot of the domain -- enough that the pathological fake is more expensive than just solving the problem.

My most startling test result, ever, came about from a property test which revealed that I had completely failed to recognize that the properties that I thought would hold were not consistent with the implementation I had chosen.

But it didn't come from randomly exploring the space, but rather choosing an example from the domain that I recognized was "weird".  Fortunately, there were lots of weird values in the domain, and they all demonstrated that my implementation didn't support the property in question.  So I got
"lucky" without having to write four billion tests.

I'm not at all sold on the idea of using a random input generator to find a needle in the haystack.