Pragmatic Clean Code Architecture
The Use Case Layer
[ part 1 | part 2 ]
For a couple of years now a topic has been recurrently subject to discussion amongst myself and my colleagues, the Uncle Bob’s Clean Code Architecture.
After some iterations, I’ve managed to get a more clear and pragmatic view about this subject and now it’s time to share.
With help from Uncle Bob’s diagram let me explain the big picture behind this architecture.
Starting from the inside. The inner circles tend to be more abstract and higher level than the rest. Inner circles do not know about outer circles and can’t communicate with the outer layer. Uncle Bob calls it the Dependency Rule, but the main ideia is that there’s only one way to communicate between layers. The closer you get to the core of the circle the closer you are to your business logic.
Well this is not new, there are other types of architectures that tell us that.. I mean, MVC is telling you almost the same thing about the communication between layers and its dependencies, but MVC is for the green layer, not for your application as a whole. This wasn’t clear for me at the beginning, but I bet this will be clearer as you read the rest of the series. Keep in mind that all those names and layers are just semantics.
In these series I will guide you through my evolution of understanding this architecture. This article will be focusing on the Use Case layer, where everything started to make sense for me.
The use case layer is the easiest to understand but probably the hardest to implement in a clear way. Here you can find all the business logic implementation:
Above you can see an example of how we organize the use cases’ code.
By looking at folders/files inside the use cases folder, you can see what are the main actions you can do with this app, and how those actions are implemented. We like to map the resources and actions from our app to folders inside use cases folder. For example, if we have a resource called User and an action AssignBadge, it will be mapped like: /use_cases/users/assign_badge.
In every action folder there’s a base.rb file. This file is the interface for a specific action, it defines the order that the nested use cases are executed and its a standard for our implementation. To know how an action is executed and which steps are made, we just need to look at action’s base.rb file.
Here’s an example for the AssignBadge action:
You may be asking yourself: “But wait, do you map your Web API routes to the use case folders?”… Yes, we do! The use cases are the API from our app, we then expose them as a Web API. It’s that simple and simple is a requirement for our everyday coding.
By extracting all the business logic implementation from controllers and models into this layer, you are separating the application core from whatever interface adapter you use. It can be Rails, Sinatra or even CLI, but the implementation of a use case is business logic, it needs to be independent from the framework you use.
One of the biggest wins of this extraction, is that the Models (Entities) become really small and can even be represented as an OpenStruct object.
I will be talking about the Entities Layer on the next post of the series.
Implementing Use Cases
Now… there are many ways to implement this, but the main idea that you need to keep in mind is that you want to have one or more objects with small responsibilities, that encapsulates application business logic and represents the actions that your application does.
Using the example on the usecasing github page:
Just by looking at the FinalizeInvoiceUseCase, we can tell which are the use case precedences and which is the data flow sequence. This was a game changer for us. It created a standard for our code implementation.
Testing Use Cases
Testing use cases is really simple. There’s an input and an output. In the usecasing gem example, it returns a Context object with every object manipulated inside a use case.
The main advantage is that these use cases are isolated, they are plain ruby objects with small responsibilities and few lines of code.
Our current approach for testing is outside-in method. Our app (or web API) will consume these use cases directly, so we test the output Context of a given use case. Then, if something fails inside the use case, we write a unit test for that specific failure, and so on.
After some iterations, we manage to get 100% coverage for our use cases, and it’s not that hard, they are really small pieces of code.
The clean code architecture is all about understanding the application and how you can isolate the app core from every framework you use.
In the project I’m currently working on, all of our microservices use Grape Framework and structured with these ideas. Each one of them are free to change this framework without the need to change the business logic.
Testing became an easier task because we only need to test small ruby classes and every use case is isolated.
If you have any questions you can reach me via twitter @joaquimadraz or email joaquim.adraz[at]gmail.com.
1. Uncle Bob’s Clean Code Architecture talk — https://www.youtube.com/watch?v=WpkDN78P884