home..

Specification By Example

According to Gojko Adzic, the author of ‘Specification by Example’, Specification by Example is a set of process patterns that facilitate change in software products to ensure that the right product is delivered efficiently.”

Illustrating requirements using examples

The requirements are presented as scenarios. A scenario is an example of the system’s behavior from the users’ perspective, and they are specified using the Given-When-Then structure to create a testable specification:

We face business with specific questions they should be able to answer. We are not facing them with abstractions or generalizations. We are dealing only with data that are formally representing preconditions (events), actions (commands) and post conditions (new events):

It also represents an acceptance criterion of the system and acts as a documentation.

specification by example

Refining specifications

It is important to realize that we need to go through all the scenarios, successes and errors. For example, with given OrderPlaced and OrderAccepted events as a precondition, when command MarkOrderAsPrepared is triggered, then Order is successfully prepared (OrderPrepared). But, with only OrderPlaced given as precondition (without OrderAccepted), handling the same command MarkOrderAsPrepared will produce different result/failure (OrderNotPrepared).

It means that order can be marked as prepared only if it was previously accepted.

Automating tests based on examples

We are decoupling the decision-making logic (domain layer) from the state management logic (application/infra layer). This allows keeping the cognitive load low.

onion architecture image

Our main focus is the decision-making process formalized as a set of pure functions. Functions/lambda offers the algebra of manipulating the data (commands, events, state) in a compositional manner, effectively modeling the behavior. This leads to modularity in design and a clear separation of the entity’s structure and functions/behaviour of the entity.

‘FModel library’1 offers generic and abstract components to specialize in for your specific case: Decider, View, Saga. You can read more about it here.

You can create a small DSL in Kotlin to write and run specifications in Given-When-Then structure (testable specification):

private fun <C, S, E> IDecider<C, S, E>.givenEvents(events: Iterable<E>, command: () -> C): Flow<E> {
   val currentState = events.fold(initialState) { s, e -> evolve(s, e) }
   return decide(command(), currentState)
}

private fun <C, S, E> IDecider<C, S, E>.whenCommand(command: C): C = command

private suspend infix fun <E> Flow<E>.thenEvents(expected: Iterable<E>) = toList() shouldContainExactly (expected)

Kotest framework is used in these tests, but you are not required to use Kotest. You can implement these three functions in your favourite test framework/library.

Runnable tests:

test(Place Order") {
   with(orderDecider) {
       givenEvents(emptyList()) {
           whenCommand(PlaceOrderCommand(...))
       } thenEvents listOf(OrderPlacedEvent(...))
   }
}

test(Accept Order - Success") {
   with(orderDecider) {
     givenEvents(listOf(OrderPlacedEvent(...))) {
       whenCommand(AcceptOrderCommand(...))
   } thenEvents listOf(OrderAcceptedEvent(...))
  }
}

test(Accept Order - Error") {
   with(orderDecider) {
     givenEvents(emptyList()) {
       whenCommand(AcceptOrderCommand(...))
   } thenEvents listOf(OrderRejectedEvent(...))
  }
}

Notice how the decision-making process (a Decider) is driven by data in which you make new decisions (events) based on the current state (current events) and action (command) being triggered:

decideFunction: (givenEvents, whenCommand) -> thenEvents

This function is the heart of the Decider component.

You can find more information and test examples within FModel library itself.

In the next blog post we are going to explain how we can use ‘event modeling’2 as a method to initiate collaborative process providing us with a blueprint of the information system, and how we can refine our scenarios to make it effective - event modeling is specification by example.


  1. FModel can be used as a library, or as an inspiration, or both. It provides just enough tactical Domain-Driven Design patterns, optimised for Event Sourcing and CQRS. 

  2. event modeling is a method of describing systems using an example of how information has changed within them over time. 

© 2024 fraktalio d.o.o.