Software Architecture and Abstractions for newbie
Tags: abstract, architecture, patterns
Published: 2022-04-23 23:21:00

How many times have you come across terms like: **inversion of control** (IoC), **dependency inversion** (DI - DIv), **dependency injection** (DI - DIj) and **abstraction**, a lot of times, right?
And I am sure that many times you have been practicing them without understanding in depth what is all that, so today is our day and I promise you that we are going to learn these terms in an easy way in a non-technical language for you to appropriate these concepts.

Well but to address these issues we must start at the origin of everything, the **software architecture**.

At the beginning when software development started everything was darkness, as something new it is normal that as the techniques and complexity of programming and algorithms advanced, problems of **construction**, **scalability**, **maintenance** began to be found, and back in the 60s concepts such as **modularity**, **inheritance**, **encapsulation** began to be touched, but it was finally in the 90s where the term **architecture** was used in contrast to the word **design**, evoking notions of **abstraction** and **standards**, then the light at the end of the tunnel began to be created.


## What is software architecture?

![Software architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ryqrovqh0muv7kbnyo0p.gif)

We can define it in one word, **decisions**, and they are the **design decisions** that are made to meet the quality attributes when we have a problem to solve through software solutions, and these decisions, good or bad, **model the structure at the level macro** of the parts of that system and that modeling is done through software architecture patterns.

### What is the patterns?

![Patterns](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udy98hwzpxfh83v1odjz.gif)

There are two types of patterns in the software world, **software architecture patterns** and **software design patterns**.

#### What are software architecture patterns?

![Architecture patterns](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evw18hzizq5r0n7nm1zc.gif)

They are **archetypes** (structures) that tell us how the parts of a software system **relate/interact** at the **macro level**, and some of there are: 
> Client - server, Microkernel, Dashboard, Peer to peer (P2P), Events broker pattern (Agent), Events bus pattern, Model view controller (MVC), N-Tires, Multilayer, Microservices, and others.
 
I leave you the task to read about them.

#### What are software design patterns?

![Dessign patterns](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uylxlm4bejg3rkc2gio0.gif)

They are **base templates** that have already been tested to solve **common problems** encountered in the software development process. They are classified into three groups (**creative**, **structural**, **behavioral**) and there are many, but here are just a few.
The **creative group** models the creation of concrete and abstract objects.
In the **structural group**, objects are modeled to form larger structures and complement their functionality.
And the **behavioral group** models how to interact and responsibilities in groups of objects.
> Factory, Abstract factory, Strategy, Façade, Composite, Builder, Singleton, Data transfer object (DTO) and many others.

I leave you the task to read about them.

To learn about patterns, you ca go to: 
[Patterns](https://refactoring.guru/design-patterns)


## Now, what is abstraction?

![Abstraction](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gv01o82pjngo08gctyo.gif)

In simple words abstraction can be defined as **the separation of what and how**, that is, separating **what something does** from **how it does it**.

So, **the what** is the action (Interface, Abstract class), this action receives or not input parameters and gives us a result. 
**The how** is what is done (behavior) with those parameters and its internal objects to return the result, that is the **concrete Class** or implementation.

```ts
// Artifact in Application Layer
// This is the what, the compromise or contract
interface ILogProvider {
  logEvent(event: EventLog): Promise<void>;
  logError(error: ErrorLog): Promise<void>;
}
// Or like abstract class
abstract class LogProviderContract {
  abstract logEvent(event: EventLog): Promise<void>;
  abstract logError(error: ErrorLog): Promise<void>;
}

// Artifact in Adapters Layer
// And this is the how, the concrete Class or implementation
class LogProvider implements ILogProvider {
  constructor(private readonly logger: Logger) {}

  async logEvent(event: EventLog): Promise<void> {
    return this.logger.info(event);
  }

  async logError(error: ErrorLog): Promise<void> {
    return this.logger.error(error);
  }
}
```

The architecture of **ports and adapters** is based on this concept and what we must be clear is that a **port is an interface or contract** which must be in the **application layer** while the **adapter is the concrete class** that implements that interface/contract (secondary adapter in this case*), and it is also good to know that there are two types of adapters, the **primary or driving adapters** which are entry points to your application, for example a controller, and the **secondary or driven adapters** that must implement a port (interface - contract) and are injected to the **application layer** to perform functions such as access to data and services.

So, having understood what abstraction is, we can then review the following concepts.


## What is the inversion of control (IoC)?

![IoC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wg1l11254d66w5jai8pa.gif)

Basically it is to delegate, **to delegate control** of certain aspects of an application to a third party.
This third party is usually a framework or service, and can control from the lifecycle of objects (DIj) to that of the application itself, it can also control events and invoke application actions to those events (UI), it can also control data persistence and service providers.


## What is dependency inversion (DIv)?

![DIv](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vkjl81mjl2itofcgkbt.gif)

DIv basically is **abstraction** and since we already know that it is abstraction, then it is time to talk about its main function, and this function is to **decouple the layers** of your software solution.

This is one of the **SOLID** (DIvP) principles and landing its compendiums to a non-technical language we can say that:

- **Important classes** should not depend on **less important classes**, both should depend on abstractions.
- **The what** should not depend on **the how**, **the how** should depend on **the what**.


## What is dependency injection (DIj)?

![DIj](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahn4cc4jlpc4jebla2gb.gif)

It is about separating the **construction/creation** (instances) from the **execution context** where the object interacts.

It is to **delegate** the **creation of objects** to a third party, in this case to a **dependency injection container** (DIjC) with the intention of **decoupling** the core of our application from the outside world, that of **"trivial"** things.

Now, you can learn more about this topics in the next resource: 
[Dependency inversion and injection](https://dev.to/vickodev/nodejs-dependency-injection-make-it-easy-4pdp)


## Question?

Is posible to use Dependency Injection without using Dependency Inversion?

![Question](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7u98mnwqbyg34ed4bu5.gif)

The short answer is a partial Yes, but it is **not recommended** because in strongly typed languages it will generate a **coupling** between objects of different layers and performing end to end tests in certain cases will be very complex, however, in languages like **JavaScript** this is very common and it is considered **good practice** because this language has no interfaces or abstract classes* (Specifications before ES6), and not having defined types, it is better to use an injected module through a method to import it directly into the dependent module, therefore the mock of that injected artifact will be easily emulated.


## What is Clean Architecture (CA)?

![CA](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6p6u34eptbb06jpi44l8.gif)

It can be defined as a **framework** or **set of best practices** aimed at facilitating the **construction**, **testability** and **maintenance** of a software product.

The term was coined by Robert C. Martin and in this compendium he took part of other architectural concepts "**Tiers and Layers**, **Onion**, **Hexagonal** (Ports and Adapters)" that have as main objective the **abstraction**, structuring the code through layers and isolating the inner world (application and business logic) from "**trivial**" things like the outside world.

![CA diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqnat34povcwvcn5zui9.png)

The **entities** are the **domain or business logic**, the **use cases** are the **application logic** that orchestrates the domain artifacts, the **adapters** are the **entry and exit points** of your application, and the external world **infrastructure** are the **connections**, **services** and **frameworks** that enable the entry and exit points to enter and send the data being processed.

![CA folders structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bczq914h0cpsyh4bnl0a.png)

In a software solution these layers look more or less like the directories in the previous image.

## Clean Architecture basic rules

- Coupling is only allowed between a layer and its inner neighboring layer, except for the domain layer, it can be everywhere and at best abstracted to layers more external to the adapters layer. *

- An inner layer must not depend on (be coupled to) an outer layer.

_* Part of this is negotiated with the technical team._


## How to do Clean Architecture and not fail in the attempt?

At first doing CA can be very complicated if you don't have enough experience, but like many things in life if you have a map or a practical and illustrative guide the mission becomes much easier because it shows you step by step the details that you must take into account to achieve your purpose.

For this reason we have created a diagram and its equivalence in code to help you in the task of abstracting the layers of your software solutions.

### Magical formula
![Magical formula](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8a558p8iq359o906eubt.png)

### In code, it looks something like this:

```ts
// Application layer
interface IChatProvider {
  send(recipient: string, text: string): Promise<void>;
  read(): Promise<Message[]>;
}

// Adapter layer
interface IChatClient {
  send(message: Message): Promise<boolean>;
  read(recipient: string): Promise<Message[]>;
}

class ChatProvider implements IChatProvider {
  #address: string;
  #chatClient: IChatClient;
  #messages: Message[] = [];
  
  async send(recipient: string, text: string): Promise<boolean> {
    // implementation
  }
  async read(): Promise<Message[]> {
    // implementation
  }
}

// Infrastructure layer
class ChatConnection {
  #connected: boolean = false;
  #chatIO: ChatIO;

  connect(host: string, port: number): boolean {
    // implementation
  }
  disconnect(): boolean {
    // implementation
  }
}

class ChatClient implements IChatClient {
  #connection: ChatConnection;

  async send(message: Message): Promise<boolean> {
    // implementation
  }
  async read(recipient: string): Promise<Message[]> {
    // implementation
  }
}
```

Well, this is all I have to share in this article and I hope I have contributed to your knowledge by explaining these concepts in simpler terms because handling them in such technical terms can be a bit complicated to understand these concepts.

If you find any inaccuracies I appreciate the feedback. :)

Now, the next step for you is learn about Clean Architecture in the next resource, good luck!! 
[Clean Architecture using NodeJs and TypeScript](https://dev.to/vickodev/nodetskeleton-clean-arquitecture-template-project-for-nodejs-gge)