[Book Study] Clean Architecture — Part 6

Zong Yuan
6 min readJan 8, 2022

This article covers the Policy And Level & Business Rules.

Policy And Level

Software System are statements of policy.

Example of those statements:

  • Describe how particular business rules are to be calculated
  • How reports are to be formatted
  • How input data are to be validated

And part of the art of software architecture is grouping these policies that change for the same reason, and at the same times, are at the same level and belong together into the same component.

Level mentioned here will be explained later in this chapter.

Directed Acyclic Graph

Software architecture involves forming the regrouped components into a directed acyclic graph.

  • The nodes of the graph are the components that contain same level policies
  • Edges are the dependencies between those components. These dependencies are source code, compile-time dependencies. Such as import in Java, using in C#, require in Ruby.
  • Good architecture make sure lower level components depend on higher level components.

Level

Level is the distance from the inputs and outputs.

The farther a policy is from both the inputs and the outputs of the system, the higher its level.

IO policies are the lowest level policies in the system.

Imagine a simple program that read data from Input, apply some functions on the data, and then write the data to the output as shown in diagram below.

Simple Function Program

As you can see, the data flows and the source code dependencies do not always point in the same direction.

We want source code dependencies to be decoupled from the data flow and coupled to level.

A code example of program above

function foo() {
while (true)
writeToOutput(someFunc(readFromInput()));
}

The high-level someFunc depends on the lower-level readFromInput and writeToOutput in the code example above. As we mentioned, the lower-level components should depend on higher-level components, so this example actually demonstrates an incorrect architecture.

So how do we implement with a better architecture? One of the solution is use interface to decouple from lower-level components.

Use interface to decouple higher level components from lower level components

As you can see from diagram above, both interfaces are located in the higher-level components (same as Some Functions), so the higher-level Some Functions is not longer depends on lower level Reader and Writer.

Example of code

class SomeFunction {
private final ReaderInterface reader;
private final WriterInterface writer;
public SomeFunction(ReaderInterface reader, WriterInterface writer) {
this.reader = reader;
this.writer = writer;
}
public void someFunc() {
while (true)
writer.write(doSomething(reader.read()));
}
}
public static void main() {
ReaderInterface reader = new ReaderImpl();
WriterInterface writer = new WriterImpl();
new SomeFunction(reader, writer).someFunc();
}

There are different implementations to achieve some goals, so here just provide one of the idea of it.

In future, if the reader or writer has to be changed, the impact of changes will be minimized since the higher-level components are not depends on either of them.

Another way to look into this issue is lower-level components should be plugins to the higher-level components.

Business Rules

Critical Business Rules: Business rules that make or save the business money, they might be implemented on a computer or executed manually. These rules would exist even if there were no system to automate them.

Critical Business Data: Data required for Critical Business Rules to be executed. These data would exist even if the system were not automated.

Entities

An Entity is an object within our computer system that embodies a small set of critical business rules operating on Critical Business Data.

The Entity should consists of

  1. Critical Business Data or access to that data
  2. Function interfaces that implement the Critical Business Rules that operate on Critical Business Data

Example

A Loan entity

Figure above shows an example of an Entity. The Loan Entity has three Critical Business Data, and three function interfaces of Critical Business Rules. Note that this entity stands alone as a representative of the business, and it shouldn’t aware of any non business related details such as databases, user interfaces or other third-party frameworks. This entity can serve the business in any other database, UI or framework.

Entity can be a single class, or it can be a group of classes/components that bind Critical Business Data and the Critical Business Rules together.

Don’t have to force everything into single entity such as entity in the Spring Framework. For a Entity + Service + Repository design, I will use Entity as Critical Business Data, while Critical Business Rule can be put in the Service classes or other classes that will be invoked by Service classes.
I might try to avoid @Entity or other annotations that normally used in the Entity classes by using another composed annotation.

Use Cases

A use case is a description of the way that an automated system is used.

Below are some facts about use cases

  • Use cases are those business rules that make or save money for the business by defining and constraining the way that an automated system operates. Which mean use cases wouldn’t be used in a manual environment.
  • Use case specifies and validates the input, decide the output and also the processing steps involved in producing that output.
  • Use case describes application-specific business rules as opposed to the Critical Business Rules within the Entities.
  • Use cases contain the rules that specify how and when the Critical Business Rules within the Entities are invoked, they control the interactions of the Entities.
  • Use case does not describe the user interface directly, it only specify the incoming data and outgoing data. In other words, it only defined the data, but it does not know about whether the data is delivered from a web interface or console. Use case does not know about how the data gets in and out of the system.
  • A use case ins an object. It implements the application-specific business rules. It also includes the input data, the output data and the references to the Entities.

Something to remember that Entities are higher level than Use Cases, thus the Entities shouldn’t know about the use cases; Entities do not depend on use cases.

Example

======================================
Gather Contact Info for New Loan
======================================
Input: Name, Address, Birthdate, Salary,...
Output: Same info for readback + credit score
Primary Course:
1. Accept and validate name
2. Validate address, birthdate, Salary, ...
3. Get credit score
4. If credit score < 500, Denial
5. Else create Customer
and activate Loan Estimation

Take note that the use case control the dance of Entities (Customer, Loan Estimation) and do validation for input data. And also take note that use cases don’t care how the system interact with the user, it just specify a standard and simple data structure for it’s input and output.

Request and Response Models

The input and output of use case (request and response models) should be simple data structures that not dependent on anything.

As mentioned before, the use cases shouldn’t know how system get the input from user/database or send the response back to user. Therefore the request and response models of the use cases should be independent from other details such as framework interface (HttpRequest, HttpResponse, web interface or any kind of user interface.

Avoid the temptation of including Entity objects in the request and response models. Over time, the Entity and request/response models change for different reasons, so tying them together violates the CCP and SRP.

Conclusion

Ideally, the business rules should be the heart of the system, and should be the most independent and reusable code in the system.

Conclusion

This article explains about components’ level and how level affect the dependencies. Besides that, it also defines the Entity and Use Cases.

--

--