# Clean Architecture Notes - SOLID (Part 2)

You could follow the previous post [here](https://phamduyhieu.com/clean-architecture-notes-part-1)

To build a building, we need bricks. On the one hand, if the bricks aren’t well made, the architecture of the building doesn’t matter much. On the other hand, you can make a substantial mess with well-made bricks.

![5-dieu-quan-trong-can-chuan-bi-truoc-khi-xay-nha-2019-01-17-15-23-23.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1638696813882/r_5UlciMN.jpeg)

# II. Design Principles

Good software systems begin with clean code. The SOLID principles tell us how to arrange our functions and data structures into classes, and how those classes should be interconnected

Or you could say:

> 
The SOLID principles tell us how to arrange the bricks into walls and rooms

### The Goal

The goal of the principles is the creation of mid-level software structures (module level) that:

 • Tolerate change

 • Are easy to understand

 • Are the basis of components that can be used in many software systems

## 1. Single Responsibility Principle

- A module should be responsible to one, and only one **actor**

=> So that each one has only one reason to change

![SOLID-Principles_-Single-Design-Principle.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638703716096/t7596Ik_3.png)

- SRP is about functions and classes
- At the level of components, it becomes **Common Closure Principle**
- At the architectural level, it becomes the **Axis of Change**

## 2. Open-Closed Principle

- Software classes, modules should be open for extension, but closed for modification

![no_change_but_children.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1638703354033/EdljoDxDK.jpeg)

- Higher-level components in that hierarchy are protected from the changes made to lower-level components

The goal is to make the system easy to extend without incurring a high impact of change. This goal is accomplished by partitioning the system into components, and arranging those components into a dependency hierarchy that protects higher-level components from changes in lower-level components.

## 3. Liskov Substitution Principle

- Objects of a superclass shall be replaceable with objects of its subclasses without breaking the application. 

![Liskov.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638703432083/q1XjGXeAF.png)

- The LSP can, and should, be extended to the level of architecture.

## 4. Interface Segregation Principle

- It is harmful to depend on modules that contain more than you need.

=> if there is any change on the module that you depend on, could lead to recompiled and redeployed, even though nothing that it cared about has actually changed.

**Ex**: In Java, we have 2 classes which implement 1 interface. And each class need only one method from that interface.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638698484205/8eok5gq_a.png)

The design violated the **ISP** so the source code of **User 1** will inadvertently depend on **op2** and
**op3**, even though it doesn’t call them. 

=> **segregating your big interface into smaller and more specific ones.**

## 5. Dependency Inversion Principle

The Dependency Inversion Principle (DIP) tells us that the most flexible
systems are those in which source code dependencies refer only to
**abstractions**, not to concretions.

- Stable Abstractions: interfaces are less volatile than implementations
- Good architects work hard to reduce the **volatility of interfaces**, try to find ways to add functionality to implementations **without making changes to the interfaces**.
- Don’t **refer ** to volatile concrete classes, but refer to abstract interfaces instead. 
- Don’t **derive ** from volatile concrete classes

- Don’t override concrete functions:

> 
Concrete functions often require source code dependencies. When you override those functions, you do not eliminate those dependencies—indeed, you inherit them. To manage those dependencies, you should make the function abstract and create multiple implementations.

=> should create an **interface ** and implement it.

- Never mention the name of anything concrete and volatile

And how to deal with that? We could use **Abstract Factory** pattern to deal with the creation of volatile concrete objects.

**Ex**: The **Application** uses the **ConcreteImpl** through the **Service** interface. However, the **Application** must somehow create instances of the **ConcreteImpl**. 

To achieve this without creating a source code dependency on the **ConcreteImpl**, the **Application** calls the **makeSvc** method of the **ServiceFactory** interface. This method is implemented by the **ServiceFactoryImpl** class, which
derives from **ServiceFactory**. That implementation instantiates the **ConcreteImpl** and returns it as a **Service**. 


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638702294018/JthNWVHM3.png)

You could see that the curve line separates the abstract from the concrete. And the important thing is:

> 
All source code dependencies cross that curved line pointing in the same direction, toward the abstract side

And the source code dependencies are inverted against the **flow of control** - which is why we refer to this principle as Dependency Inversion.


(to be continued)




 
