Clean Architecture .NET Core (Part 1: Introduction)

What is Clean Architecture?

  1. Produce bugs often
  2. Debugging and/or adding new features is painful
  3. Cannot write tests without database/ web server
  4. Other developers cannot understand the intent of the code
  5. has presentation logic mixed with business logic or business logic mixed in with data access logic

Congratulations! you write bug laden code!, wait.. so there’s no solution for that? Well.. all you have to do is follow best practices. Like SOLID or any other design pattern. They all have the same objective, which is the separation of concerns. They all achieve this separation by dividing the software into layers. Each has at least one layer for business rules, and another for interfaces.

The secret to building a large project that is easy to maintain is this: separating the files or classes into components that can change independently of other components. Let’s illustrate that with a couple of images.

Image courtesy : pusher.com

In image (a), if you want to replace the scissors with a knife, what do you have to do? Needless to say that it is a hectic job. In image (b), how do we replace the scissors? We only have to pull the scissors’ string out from under the Post-it notes and add a new string that is tied to a knife. Way easier. The Post-it notes don’t care because the string wasn’t even tied to it.

The architecture represented by the second image was obviously easier to change. The key rule behind Clean Architecture is exactly this, or more technically, the Dependency Rule, which states that source code dependencies can only point inwards. So what does this mean? Take a look.

Image courtesy : fullstackmark.com

Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in the an inner circle. That includes, functions, classes. variables, or any other named software entity. The gist of this is simply that dependencies are encapsulated in each “ring” of the architecture model and these dependencies can only point inward.

Entities : Encapsulate enterprise wide business rules.

For example, charging 10% interest on a loan is a rule that a bank might have. This would be true whether the interest was calculated on paper or using a computer. The entities know nothing of the other layers. They don’t depend on anything. That is, they don’t use the names of any other classes or components that are in the outer layers.

Use cases : Contains application specific business rules.

Gather Info for New Loan Input: Name, Address, Birthdate, etc.
Output: Same info + credit score
Rules:1.Validate name
2.Validate address, etc.
3.Get credit score
4.If credit score < 500 activate Denial
5.Else create Customer (entity) and activate Loan Estimation

The use cases interact with and depend on the entities, but they know nothing about the layers further out. They don’t care if it’s a web page or an iPhone app. They don’t care if the data is stored in the cloud or in a local SQLite database.

We do, however, expect that changes to the operation of the application will affect the use-cases and therefore the software in this layer. If the details of a use-case change, then some code in this layer will certainly be affected.

Interface Adapters : Convert data from the format most convenient for the use cases and entities.

No code inward of this circle should know anything at all about the database. If the database is a SQL database, then all the SQL should be restricted to this layer.

Frameworks and Drivers : Where all the I/O components go.

Crossing boundaries

It shows the Controllers and Presenters communicating with the Use Cases in the next layer. Note the flow of control. It begins in the controller, moves through the use case, and then winds up executing in the presenter. How do we implement this? “Dependency Inversion Principle”.

Dependency Inversion Principle (DIP)

So instead of having a stable class use the name of a volatile class like this:

You could make an interface that the volatile class implements:

For example, consider that the use case needs to call the presenter. However, this call must not be direct because that would violate The Dependency Rule: No name in an outer circle can be mentioned by an inner circle. So we have the use case call an interface (Shown here as Use Case Output Port) in the inner circle, and have the presenter in the outer circle implement it.

What data crosses the boundaries?

  • We don’t want to cheat and pass Entities or Database rows.
  • We don’t want the data structures to have any kind of dependency that violates The Dependency Rule.

Conclusion

Up Next..

Systems Design • Social Innovation • Cloud • ML