I wanted to review these implementations. I tried to look at them from various perspectives and the exercise was quite interesting.
Here is what I found for 3 of them. I will not talk about James Shore implementation. It could be the topic of a dedicated blog post in the future.
The perspectives that interested me were :
- the global workflow of commands
- the coupling between software units
- the unit testing method
Here we go.
Ralf Westphal : an Event-Based Components approach
Ralf has set-up a web site where he describes his solution. It is composed of lots of simple components assembled as if they were electronic components on a board.
See the nice drawings on Ralf google code website. Here is one :
Communication between components is only event based so the follows the flow of events. The config path is pushed to the components that do the reading and the writing. The reader get the data and pushes it to the logic that, in turn, pushes the transformed data to the writer and to the display.
All components are implementations of a public contract. Basically, each public contract describes the pins for soldering the components.
- each basic component has no knowledge of any other component
- each board composed of multiple components has knowledge of the contract implemented by the components that are part of it -- except for the standard components whose instances are created by the board itself.
All basic components are . The event-style output ensures that the behavior of each component is observable hence testable without any fake, stub or mock.
Though, the absence of unit testing for the "domain board" lead to think that the global design was not test-driven.
But we could probably imagine a top down approach where the "domain board" would have been designed using mocks for its inner parts (reader, writer and transformer).
This component approach was new to me and I find it quite impressive and attractive.
My biggest concern is about scaling : what if a system needs thousands of components? In such a case, can we still use really simple piece of information through the pins?
Justin Bozonier : Message Oriented Object Design
Message Oriented Object Design is quite similar to the previous component based approach in the sense that the goes from the initial reader to the final destination going through all needed steps.
This approach features the tell don't ask principle in every piece of software.
The main difference with the component approach is that each object knows the other contracts and directly "tell" the other objects what to do instead of raising an event.
The real implementations of the other objects are, of course, unknown.
This leads to a where each class only has to know few interfaces.
Classes are using stubs behind each interface.
My concern is similar to the previous approach : what about scaling? "tell don't ask" is nice and provide a loosely coupled design but I don't know if this principle can be applied - keeping the same readability level- on programs where the data flow is not so straightforward.
Alexander Beletsky : simple design from requirements to implementation
I have very little to say regarding this approach because I used more or less the same ;-)
Alexander adopts an inside-out design strategy : first the business logic, then moving towards the I/O.
Each design step is using mocks for verifying the interactions with the components that are not yet present. The mock framework is rhino mocks. It is good that some people like it but, to me, the verifications of Moq are much more readable than the expectations of Rhino Mocks.
The resulting design is mostly with a central business logic component that consumes strings as input and stores strings as output, featuring a bidirectional command flow.
The only thing that I do not understand is the use of factories. They usually enhance loose coupling but, in this case, they are not really useful.
Actually, I do not have any conclusion except that lots of different approaches can lead to software that satisfy the same needs while following basic good principles (loose coupling, unit testing...)