Select Page

The importance of Architecture

Like a building, software needs a foundation in order to be built. Before starting with the foundation, as with any engineering work, you need an architect that will create the architecture. This is the normal way to go when building something. Going back to software tho, you don’t need to be a certified architect in order to build an application. But, if you want it to scale, to easily get help from other programmers or to update it to keep up with the competition, you may find out that bad architecture makes a hard life. And you should pay attention to it.

The reason it is so important, among all the above, is that it is the first thing you begin with. Even if you don’t pay attention to it and start coding, your code will still be architectured in a way (though it may not be specifically named).

In this blogpost, I’ll show you three general architecture types when it comes to organizing your code. We will begin with a naive approach where you organize your files in a technical layer approach. We’ll continue with a feature layer approach, where each folder represents a big feature of the project, and then finish with a screaming architecture approach, my personal preference.

The examples follow the NestJS framework, hence the file naming.

Architectures breakdown

Package by layer

As the name says, this architecture style focuses on structuring your code base around technical layers. If we go for a controller-service-repository approach, then we will have three big folders like controllers, services, repositories, with other folders for models and infrastructure code.

While this approach is easy to implement and to grow initially, it will soon be overwhelmed as the application grows and it will make hard for developers to figure out dependencies and what files link to eachother.

How it looks from the outside: Looking at it, we may understand that the project has something to do with files and users, while it uses the controller-service-repository approach. This is pretty much it, we don’t know what business logic it employs or what else it does, you need to check the files for it.

src/
├── controllers/
│ └── file.controller.ts
│ └── user.controller.ts
├── services/
│ └── file.service.ts
│ └── user.service.ts
├── repositories/
│ └── file.repository.ts
│ └── user.repository.ts
├── models/
│ └── file.model.ts
│ └── user.model.ts
└── main.ts

Package by feature

With this approach, we focus on showing the features of the system. If you have a Bank application, you may have some big modules like Cards or Subscriptions, where you put all the files related to that feature there. It doesn’t offer much explanation though and the files may or may not contain more logic than needed. The breakdown isn’t so pronounced, though it is more clean than the previous layer one.

How it looks from the outside: The application clearly has two important logic elements, the users and the files. This makes easy to develop individual parts of the system, because all the code related to that feature is in the same place. While you have all the files related to a feature in the same place, it still doesn’t explain the bussines domains as clearly.

src/ ├── file/ │ ├── file.controller.ts │ ├── file.service.ts │ ├── file.repository.ts │ ├── file.model.ts │ └── file.module.ts ├── user/ │ ├── user.controller.ts │ ├── user.service.ts │ ├── user.repository.ts │ ├── user.model.ts │ └── user.module.ts └── main.ts

Screaming Architecture

Screaming architecture implies screaming at the reader on what the code does. It focuses on domain and bussines logic above everything else. It decouples the technical side from the domain logic and allows you to clearly express your intent on what the application does.

How it looks from the outside: The reader can clearly see that the application is about managing users and files. The folder names are descriptive, same with each components that are container. It also takes from the feature based approach, but on a more granular level, where folders like upload-file and download-file express clearly what features they are, and also should follow the single responsibility principle. One downside for screaming architecture is that it can get fairly complicated if not properly managed.

src/
├── file-management/
│ ├── upload-file/
│ │ ├── upload-file.controller.ts
│ │ ├── upload-file.service.ts
│ │ └── upload-file.use-case.ts
│ ├── download-file/
│ │ ├── download-file.controller.ts
│ │ ├── download-file.service.ts
│ │ └── download-file.use-case.ts
│ └── file.module.ts
├── user-management/
│ ├── create-user/
│ │ ├── create-user.controller.ts
│ │ └── create-user.use-case.ts
│ ├── get-user/
│ │ └── get-user.service.ts
│ └── user.module.ts
└── main.ts

My personal preference

Personally, I go for screaming architecture for all my projects. It doesn’t matter whether I write a frontend or a backend application, the same principle can be applied for both. I try to be as explicit as possible about what logic resides in what folder, so that not only the code can be read like fine prose, but also the file structure of the project. People shouldn’t consume a lot of time to figure out what your project is about. Be explicit in your implementation, follow the SOLID principles, especially the single responsibility principle when designing your features. It is okay to have a big feature divided into smaller ones, just make sure the intent is reflected in the name of the files. And in the code containing them too. Also, take your time to plan it. This process shouldn’t be rushed as it stays with you for the whole lifespan of the application. Re-architecturing later in the process is often costly and a deal-breaker for many. Take your time, plan accordingly, implement and have fun doing it. Did you like this story? You can follow me on LinkedIN for more programming content!