A Lightning Talk
On 21st of July, I took a part in the lightning.io conference, which took place in Poznań, Poland. The conference itself was quite unusual, because - as its name may suggest - it consisted of lightning talks only. What’s more, each and every attendee was also a speaker.
On one hand, I chose a topic which I was really keen on. On the other, making it fit into 5 minutes was a really difficult task. I had a feeling I could talk on it for several minutes or even hours, but the rules were (almost) inexorable, so I had to make it quick.
Thanks to Mari Carmen (“valakirka”) for providing the photo above!
My presentation was entitled “Application Architecture”, and it was actually concentrated on the things its name says. It was all based on a presentation done by Uncle Bob. You’ve never heard of him? To make things short: if you’ve learned an OOD principle recently, there’s probably an Uncle Bob’s paper from 1992 describing it. That’s the guy.
In general, he pointed out that we lost our way because of the web. For example, people often complain that Cucumber is too slow and that tests run too long because of it. The truth is that the Cucumber itself doesn’t add any significant overhead. The real problem is that testing through the UI is slow, also booting Rails up is slow. That is: we shouldn’t fight the symptoms, we should fight the cause.
We’ve got blinded by the web and made it the central abstraction of our applications. In fact, web should be considered as just one of the available delivery mechanisms, even if there’s only one. Our applications and their structure should reflect their own intent, not web framework’s.
Uncle Bob says that instead of focusing on the delivery mechanisms, we should concentrate on use cases. He suggests a 1-1 relationship between use cases and objects representing them. To avoid confusing with MVC controllers, Uncle Bob called these objects interactors. They implement application-specific business rules, which can’t be put into a framework of any kind. Example interactors could be named AddUserToGroup, FindUser, CancelOrder etc. It’s good if their names are descriptive.
Interactors should know about entities. The latter can also be called business objects: they hold data and perform operations. But they are not to be confused with MVC models - entities must be decoupled from data storage and framework. They also don’t need to know about other components of the application.
And where’s the place for the web? Well, delivery mechanisms are separated from the core of the application by using an interface called boundary. Web could be just one of its implementations, while terminal and WebService could be the others. Of course, when you’re running tests, every regular delivery mechanism is considered harmful. Not only it can skew the results, it can also prolong the response time.
User can interact with a delivery mechanism (that is, a boundary implementation) in both ways: for reading from and for writing to. Delivery mechanism gathers data from the user and builds a request model. Request model is just a data structure, it has no methods. When you look at it, you should not have any clues about what delivery mechanism was used. That is - no session ids and that kind of stuff. Request model is then passed to the interactor.
Interactor ties the whole use case together. When interactor finishes its job, it creates the result model. Again: there are no methods in it, it’s just a dumb set of data. Result model is passed through the boundary to the delivery mechanism. Then delivery mechanism has to figure out how to present the result to the user (in form of a webpage, API response etc.).
What about the MVC as we all know it? The point is, it wasn’t meant to be an architectural pattern. In fact, it was just a small design pattern adapted to be replicated over and over again on the same screen. For example, if you wanted to build a GUI window, you could use one MVC instance for the window title, one for the close button, one for the scrollbar and so on. However, in the web world we decided that there will be only one MVC instance, hence there is just one view representing the whole screen.
What’s even worse, view is often using models directly, whilst it should know nothing about models. In order to isolate them, one can use the presenter pattern which turns the response model into a view model. As a result, one gets a dumb view, which only takes data from the view model and puts it on the screen directly, without any additional processing.
Database also often plays the ungrateful role of being the central abstraction of the application. In fact, applications should be decoupled from specific data storage mechanisms. It can be easily achieved by extracting data operations to an interface, and making application interact with interface methods instead of any specific implementation. By the way, writing unit tests becomes much easier then.
Uncle Bob nicely summed up designing application architecture. He said that it’s all about drawing lines. Once you draw a line, all dependencies that crosses that line should go in one direction. And if you’ve done that, you have a gem.
Extracting core parts of the application is another interesting concept that was going through my mind for some time, but I’ve never had enough courage to put it into practice. Now I do feel encouraged to try this approach.