Thursday 14 May 2015

Slicing Up The Cake


As good SOLID developers when we're designing a system we're trying to ensure that the classes within it,
  • Depend on abstractions not implementations.
  • Are loosely coupled to the classes around them. 
  • Have a well defined singular role within the overall design.
A good way of achieving this is to produce a design that uses layers to define how a class fits into the grand plan.
Each layer within the design represents a slice of the functionality required to deliver the overall system, all classes within each layer share a common relationship in the functionality they offer. 
The design has a clear structure, lines of interaction can be easily traced and any piece of the jigsaw can be changed with a predictable and limited impact.
Each layer of the design knows only about the functionality offered by the layer below via the abstractions it presents. 
Passing it Down The Line
Each class has a singular responsibility that involves it knowing how to use its dependencies to deliver the contract defined by the abstractions it presents for the layer above.
The effect of making a change to any implementation of an interface is nil. The implementation of every abstraction can be kept very simple. 
Combining this layered approach with an interface driven design and applying the dependency inversion principle makes these classes very testable. Mocks are passed in, expectations are set and high coverage is achieved.
Up and Down Not Left and Right
Notice how in the diagram the lines showing interactions only go up and down. If a class had lines going left or right to another class within the same layer this would represent a invisible side-effect to the layer above. 
Classes in layer 2 can see every class in layer 3 and should be able to use any of those classes independently without a care for how the layer is implemented.
Invisible interactions between classes will lead to classes above needing to have implied knowledge about the implementation of the abstractions below to account for the side effects, we will have broken the encapsulation that an interface driven design is supposed to bring.
The Surface Area for Change
A second reason to prefer not to have classes on the same layer interacting is in limiting the impact of change.
In the diagram the effect of changing any individual abstraction is only felt by the class that use that interface in the layer above.
If classes within each layer were also interacting the surface area of code that is affected by a change increases. It can then be very easy for a small change to one abstraction to rapidly propagate through that layer, and to layers above, resulting in the entire design being invalidated.
So when your slicing up how your design is going to be implemented make sure your knife is razor sharp and every cut is clean with no rough edges that you could get snagged on in the future. 

No comments:

Post a Comment