Software is complex, often too complex for the human mind to comprehend.

As IT professionals exposed to this complexity day in and day out, we create mental models, models that simplify problems down to a level that our puny minds can handle. Design Patterns as popularised by the Gang of Four are a response to the inherent complexity in software. Here we have a set of patterns or models that 9 times out of 10 provide solutions to software architecture challenges. Patterns provide a common language that we can use to describe complex concepts in a consistent way.

Ah, consistency, something that software developers are very familiar with. Consistency is drilled into us at programming school – encapsulate the commonality once and then reuse often. This is what frameworks are all about. Who writes a string class from scratch these days?

So the thing that has amazed me enough to spur me to write this post is why do these fundamentals fall by the wayside when we find ourselves under pressure? Why do people re-invent the wheel when a simple, well known pattern would suffice?

Let me explain a very simple pattern. This is a pattern we are applying in a service based architecture. The idea is simple

  • Each service exposes one of more unit of work.
  • Each unit of work is invoked by a Command message
  • The command message relates directly to the service business domain. It is a command to invoke a business process or operation.
  • Once the unit of work is complete, either successfully or not, this is reported by way of an Event message

The pseudo code for this might be

public void Handle(MortgageApproveCommand message)
{
    ValidateMessage(message);
    var mortgageApproval = Transform(message);
    
    var result = Mortgage.Approve(mortgageApproval);
		
    if (result.OK)
    {
	PublishEvent(new MortgageApprovedEvent
	{
		Result = result
	});
    }
    else
    {
        PublishEvent(new MortgageApprovalFailedEvent
	{
	    Result = result
	});
    }
}

I’m not suggesting this is perfect but it demonstrates how to keep the implementation clean by avoiding the logic of other services creeping in and also how to provide an anti-corruption layer between the service interface and the internal business logic. I also like the simplicity of the command -> process -> event pattern.

I recently reviewed some code implemented by a project team and found this. I’ve mapped the code to a very simple service model (Road and Car) to avoid any complexity related to the real business domains causing confusion.

public void Handle(AccelerateCarCommand message)
{
    Road road = message.CurrentRoad;
    if (road == null)
    {		
        throw new ArgumentNullException("No road");
    }
	
    if (road.SpeedLimit == null)
    {		
        throw new ArgumentNullException ("No speed limit");
    }
	
    if (road.TrafficCondition == null )
    {		
        throw new ArgumentNullException ("No traffic");
    }
	
    var actualSpeed = Car.AccelerateToOptimalSpeed(road);
	
    if (actualSpeed < SpeedLimit)
    {
        road.State = Busy;
    }
    else
    {
        road.State = Clear;
    }

    PublishEvent( new RoadStateChangedEvent
    {
        Road = road
    });
}

So what are the issues with this?

1) Passing Service objects/interface structures into external services

Road road = message.CurrentRoad;
if (road == null)
{
    throw new ArgumentNullException("No road");
}
…

The Car service is passed an instance of a Road. This couples the Road and Car services together. A change to the structure of the Road object now impacts the Car. Ideally the Car would have exposed a command that allowed the caller to pass the Speed Limit and Traffic Conditions without passing the entire state that comprises a Road. Both services do need a shared understanding of these concepts but that does not mean they have to share a representation.

2) Passing Interface object into the business logic

var actualSpeed = Car.AccelerateToOptimalSpeed(road)

Not only does this compound the previous issue but now there is no separation between the service interface and the internal logic. If the interface changes, (which it will do by the way, when you least want it to) it has impact across the implementation not just at the perimeter. There must be an anti-corruption layer between the interface and implementation to allow them to change at different rates. I see this as very similar to the Model-View-ViewModel MVVM pattern you see in many web applications.

3) Changing the state of data you don’t own

if (actualSpeed < SpeedLimit)
{
    road.State = Busy;
}
else
{
    road.State = Clear;
}

Here we are changing the state of Road in the Car service.

With the previous points there are ways to refactor our way out of a corner. However this point, and the following one have much worst smells and they are clues to what was going on in the developer’s mind during implementation.

What I see here is the developer making assumptions about what other services will do. They have changed the state of an object they don’t own because they know how the Road and Car services will coordinate to realise an end to end process. This is just another form of coupling… “implementation coupling”. We are using a nice interface but services on each side of the interface are making assumptions about what that other is doing. Change one implementation and you break the other one.

4) Raising Domain Events the service doesn’t own

PublishEvent( new RoadStateChangedEvent
{
    Road = road
});

This is the second piece of the implementation coupling jigsaw. Now that we have changed the state of the Road, we need the Road service to commit the change. So lets forget the problems associated with implementation coupling for a moment and think about how we would deal with this. I would reach for a Command Message where I called the Road service to commit my change. The command message is a point to point message that is only consumed by the Road service.

So what has the developer done? They are publishing an event!

In this system an Event message is a convention for using a Publisher/Subscriber pattern. By definition the publisher has no knowledge about the message subscribers neither does the publisher know when the message is consumed. There are absolutely no guarantees that the message will reach the Road service and even if it does the service may not be able to process it.

BadEvents

If you are following a domain event model, a domain service should only raise events related to its business domain. Here we are raising an event from the Car service that should be owned by the Road service. Any other service could be subscribing to this event and they will assume that this was raised in response to a state change in the Road service. They may get this event before the Road service has a chance to commit the change and it is entirely possible that the change could be rejected. Any one of the subscribing services may kick off another business process which in turn may trigger further events. A rejection by the Road service would leave all the services that had consumed the event in an inconsistent state.

What a mess!

The implementation that spurred this example emerged from good intentions. What I have presented here was the result of a series of incremented design choices, each one on their own, not too bad, but the result took us a long way from where we needed to be. But going back to the introduction, the real problem is the pattern for building these units of work was not well understood and where it was known there was a lack of buy in. Delivery pressure meant that the team had no time to sit up and understand the pattern or understand the concepts it is built on. Instead they forged ahead reinventing the wheel as they went.

So we are left with coupling and chaos where we should be enjoying simplicity and consistency.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s