DEV Community

Cover image for Clean Architecture (Application Layer)
Julian Lasso 🇨🇴
Julian Lasso 🇨🇴

Posted on

Clean Architecture (Application Layer)

Continuing from the previous post about "Clean Architecture (Domain Layer)", it's the perfect time to delve deep into what the application layer entails in this architectural context.

What Does the Application Layer Entail?

Clean Architecture Diagram

The Application Layer can be considered the epicenter of the project. As its name suggests, it's in this stratum where the application is developed in its tangible form, bringing to life the logic previously defined in the domain layer. In other words, it's the space where use cases are materialized and executed, ultimately defining the application's behavior.

In this layer, I've focused on the following crucial aspects, including:

Commands and Their Validators: Here, commands represent the actions that can be performed within the domain. Validators play a fundamental role in ensuring that the parameters provided to these commands are correct and comply with defined rules.

Use Cases: The Application Layer is where the core logic of the application is concretely implemented. These use cases describe specific scenarios in which the main functionality of the application is used to achieve specific goals.

Persistence: Although the application is not directly connected to a database or other persistence systems at this stage, abstract classes and interfaces are defined here that the future infrastructure layer will use to manage data persistence. This ensures a smooth transition to the infrastructure layer when needed.

You can find the repository for the application layer at the following link, where I have achieved 99% unit test coverage:

Application Layer Repository

Structure

Here is the current structure of the domain layer:

📦src
 ┣ 📂commands
 ┃ ┣ 📂inputs
 ┃ ┃ ┣ 📜complete-to-do-command.input.ts
 ┃ ┃ ┣ 📜create-to-do-command.input.ts
 ┃ ┃ ┣ 📜create-user-command.input.ts
 ┃ ┃ ┣ 📜get-all-to-dos-command.input.ts
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┗ 📜login-command.input.ts
 ┃ ┣ 📂validators
 ┃ ┃ ┣ 📂base
 ┃ ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┃ ┗ 📜validator.base.ts
 ┃ ┃ ┣ 📜complete-to-do.validator.ts
 ┃ ┃ ┣ 📜create-to-do.validator.ts
 ┃ ┃ ┣ 📜get-all-to-dos.validator.ts
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┣ 📜login.validator.ts
 ┃ ┃ ┗ 📜new-user.validator.ts
 ┃ ┣ 📜complete-to-do.command.ts
 ┃ ┣ 📜create-to-do.command.ts
 ┃ ┣ 📜get-all-to-dos.command.ts
 ┃ ┣ 📜index.ts
 ┃ ┣ 📜login.command.ts
 ┃ ┗ 📜new-user.command.ts
 ┣ 📂common
 ┃ ┣ 📂config
 ┃ ┃ ┣ 📜app.config.ts
 ┃ ┃ ┗ 📜index.ts
 ┃ ┣ 📂enums
 ┃ ┃ ┣ 📜config.enum.ts
 ┃ ┃ ┣ 📜db-order.enum.ts
 ┃ ┃ ┗ 📜index.ts
 ┃ ┣ 📂exceptions
 ┃ ┃ ┣ 📜application.exception.ts
 ┃ ┃ ┗ 📜index.ts
 ┃ ┣ 📂interfaces
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┣ 📜jwt-data-user.intertface.ts
 ┃ ┃ ┗ 📜query-options.interface.ts
 ┃ ┣ 📂libs
 ┃ ┃ ┣ 📂jwt
 ┃ ┃ ┃ ┣ 📂interface
 ┃ ┃ ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┃ ┃ ┣ 📜jwt-header.interface.ts
 ┃ ┃ ┃ ┃ ┣ 📜jwt.interface.ts
 ┃ ┃ ┃ ┃ ┗ 📜payload.interface.ts
 ┃ ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┃ ┗ 📜jwt.lib.ts
 ┃ ┃ ┗ 📜index.ts
 ┃ ┗ 📜index.ts
 ┣ 📂persistence
 ┃ ┣ 📂exceptions
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┗ 📜persistence.exception.ts
 ┃ ┣ 📂models
 ┃ ┃ ┣ 📂base
 ┃ ┃ ┃ ┣ 📜document.base.ts
 ┃ ┃ ┃ ┗ 📜index.ts
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┣ 📜to-do.mode.ts
 ┃ ┃ ┗ 📜user.mode.ts
 ┃ ┣ 📂repositories
 ┃ ┃ ┣ 📂base
 ┃ ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┃ ┗ 📜repository.base.ts
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┣ 📜to-dos.repository.ts
 ┃ ┃ ┗ 📜users.repository.ts
 ┃ ┗ 📜index.ts
 ┣ 📂use-cases
 ┃ ┣ 📂base
 ┃ ┃ ┣ 📜index.ts
 ┃ ┃ ┗ 📜use-case.base.ts
 ┃ ┣ 📜complete-to-do.use-case.ts
 ┃ ┣ 📜create-to-do.use-case.ts
 ┃ ┣ 📜create-user.use-case.ts
 ┃ ┣ 📜get-all-to-dos.use-case.ts
 ┃ ┣ 📜index.ts
 ┃ ┗ 📜login.use-case.ts
 ┣ 📜app.ts
 ┗ 📜index.ts
Enter fullscreen mode Exit fullscreen mode

Diagrams

If, for any reason, you don't wish to review the code, here are modeling diagrams for the most relevant sections.

Application and Use Cases

Application and Use Cases

Commands, Inputs, and Validators

Commands, Inputs, and Validators

JWT Handling Library

JWT Handling Library

Persistence

Persistence

What's Next?

The next step is to establish the infrastructure layer, and for that, I'll be working with NestJs, TypeOrm, and PostgreSQL. However, it's important to note that, in theory, the choice of framework, ORM, and the type of database should be transparent to the application layer.

Additionally, it's important to mention that in this application layer, I have used Zod for data validation. Ideally, and in theory, we should avoid any dependencies on external libraries. In this regard, the ideal practice would be to develop our own validation engine, an option I will consider at a later time.

Final Words

As always, I appreciate any doubts, questions, concerns, or contributions you may have.

I am completely open to receiving any kind of feedback. Please don't hesitate to contact me; I will be delighted to hear your comments.

Top comments (0)