Adventures with Clean Architecture
Disclaimer: I am writing this article to help me get to grips with Uncle Bob's Clean Architecture, which to me sounds like a wonderfully elegant approach to building applications. In light of the fact that there are currently not so many examples of how to implement a .Net solution using a Clean Architecture structure and that this is my first attempt to transform the theory into practice this explanation might be wrong ... we'll see.
The Scenario
I will start with a simple scenario to get things going and which will be used to build the application.
Scenario: A runner would like to calculate their running pace given the distance run and time taken to run the distance.
Runners will interact with the application via a website.
Use Case - Calculate runner's average pace
- 1. A runner submits the distance run and the time taken
- 2. System calculates the average pace run by the runner
- 3. System delivers the calculated running pace to the runner
Request:
<distance>
<time-hours>
<time-minuets>
<time-seconds>
Response:
<pace-minuets>
<pace-seconds>
Solution overview
-
The solution wil be made up of two main elements:
the application
the delivery mechanism
The application contains all the business logic and the delivery mechanism a website which will accept input from the user, pass the input data to the application for processing and then display the resulting pace to the user.
The Application
Uncle Bob's Clean Architecture is based upon the Boundary Control Entity pattern, which was developed by Ivar Jacobson.
In order to avoid confusion with the controller in the Model View Controller pattern, Clean Architecture uses the term Interactor or UseCase in place of Control. I prefer to use the latter as I like the emphasis on use cases.
This will be a very simple application, containing one use case which recieves a request model as an input from the delivery mechanism (in this case a website) containing the time and distance, calulates the running pace and returns it to the delivery mechanism in the form of a response model. All of the communication with the delivery mechanism occurs through the boundaries defined for the use case.
As this is a very simple application there are no entities in this example.
The application simply consists of the following types of objects:
Uses Cases
Boundaries
Request Models
Response Models
The use case
For each use case, there is an input and output boundary.
The use case implements the input boundary and uses the output boundary.
The use case contains business logic which will calculate the running pace based on the distance and time information which has been entered via the delivery mechanism (the website) and passed to the use case via the input boundary using the request model. The use case then creates a response model which contains the calculated pace and sends the response model to the delivery mechanism via the output boundary.
The input boundary
The input boundary is an interface which defines the request and methods required by the use case and which the delivery mechanism will use in order to execute the use case. The use case implements this interface.
The output boundary
The output boundary is an interface which will be implemented by the delivery mechanism. The interface contains the signature of a method which the use case will call on the delivery mechanism in order to pass the response model from the application to the delivery mechanism.
The request and response models are simple data structures which are used to pass data from and to the delivery mechanism using the application.
The request model
The request model will be used to contain the data entered by the user of the delivery mechanism (in our case a website) and which will be passed to the use case via the input boundary. The request model is a simple data transfer object containing the distance and the time taken to run the distance:
public double Distance {get;set;}
public int Hours {get;set;}
public int Minuets {get;set;}
public int Seconds {get;set;}
The response model
The response model will be used to hold the result data generated by the use case and which will be passed to the delivery mechanism via the output boundary.
It is nothing more than a data transfer object containing the pace in minuets and seconds:
public int Minuets {get;set;}
public int Seconds {get;set;}
Testing the application
A test driven development (TDD) approach was used while devloping the application using Telerik's JustMock, NCrunch and Microsofts unit testing framework. Using this approach I was able to obtain100% code coverage and a set of passing tests for the application.
The Delivery Mechanism
The delivery mechanism's controller uses the
use case input boundary.
The delivery mechanism's presenter implements the use case output boundary.
I decided to use a standard Microsoft MVC5 website as the delivery mechanism. I used the MVC controller to both use the application input boundary and implement the output boundary.
You can see the application in action on my sandbox website
Trail Harriers