0

recently I started a personal application using Angular 16 and NestJS as backend. I'm newbie with these technologies and I like all related with design patterns and architectural styles, so I would like to implement clean architecture in nestJS. I've seen videos explaining layers, folders structures, however trying to applying them, I've been facing difficulties to carry out a good separation of concerns related with what should be in which layer.

Here is my folder structure:

enter image description here

My project uses libraries such as JWT, TypeORM, Swagger, automapper, etc. and the difficulties are related with the decorators these libraries impose to the different classes forcing me to change the layer the classes have to reside.

The main reason as far I understand is because the innest layer such as domain should not depends on any external libraries/dependencies, however, my entities or domain models into domain layer requires ORM decorators to work as expected and decorators depends on the library, so I had to move these classes to infrastructure as seen below:

enter image description here

Same happened with DTOs that use swagger decorators, and interfaces that depends on such DTOs. I had to move many things causing that infrastructure layer get heavy containing a lot of folders and with a major responability and domain and application layers turned into a super thin layers with few files.

This kind of dependencies made me reconsider if trying to implement clean architecture is worth or better use the normal folder distribution.

Can you help me about this or what am I wrong?

thanks

Aldemar Cuartas Carvajal
  • 1,573
  • 3
  • 20
  • 39

1 Answers1

0

my entities or domain models into domain layer requires ORM decorators to work as expected and decorators depends on the library

You don't have to do that. The ORM entities should be separated from the domain objects.

E.g. create a user DTO that is responsible just for the ORM related stuff. I usually call it DTO to make clear that it is just a data structure to transfer data, hence data transfer object. This DTO doesn't have any logic in it.

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class UserDTO {
    @PrimaryGeneratedColumn()
    id: string

    @Column()
    firstName: string

    @Column()
    lastName: string

    @Column()
    isActive: boolean
}

and then you create a domain object, or the "real" entity, that encapsulates domain logic.

export class User {
    id: string
    firstName: string
    lastName: string
    isActive: boolean
}

At first sight it doesn't seem to make sense. You have two nearly identical classes. But the first one's property names map to db columns. The fact that those classes are often looking very similar is just an accident. They can be different in some use cases.

The mapping between the DTO and the domain object is done in the repository implementation or a mapper that this implementation uses.

If you go that way you can:

  • change the representation in the database
  • use another framework
  • use another database

without touching the domain object at all.

René Link
  • 48,224
  • 13
  • 108
  • 140