borjapazr / express-typescript-skeleton

πŸ”°πŸ¦Έ Template to start developing a REST API with Node.js (Express), TypeScript, Ts.ED, ESLint, Prettier, Husky, Prisma, etc.
https://express-typescript-skeleton.bpaz.dev/api/docs
MIT License
500 stars 61 forks source link

πŸ’‘ Discussion: Vertical Slice Architecture #413

Open robertgr991 opened 9 months ago

robertgr991 commented 9 months ago

Feature Request Checklist

Overview

This is more of a discussion than a feature request.

What do you think about organizing the features using the architecture that is commonly known as "Vertical Slice architecture"?

The current structure is:

The proposed structure would organize every logic of a feature in a feature folder:

I think this will improve cohesion and reduce coupling by setting clear features boundaries. Each boundary can specify exactly what should be shared with other parts of the system. Having each logic of a feature in a feature root folder will also help when traversing the code and learning about what the feature has implemented.

References

Additional Info

No response

borjapazr commented 9 months ago

Hello, @robertgr991 πŸ‘‹!

First of all, thank you very much for opening this issue and contributing to this project.

The truth is that I agree with you. I had been wanting to implement Vertical Slice Architecture in this project for some time, but due to lack of time, I never took the step. I believe that, together with DDD principles and a Hexagonal/Clean Architecture, you can create projects that scale very well and, most importantly, that are maintainable over time.

Regarding the structure you propose, what do you think if we adapt it this way? πŸ€”

.
β”œβ”€β”€ apps
β”‚Β Β  β”œβ”€β”€ console
β”‚Β Β  β”œβ”€β”€ graphql
β”‚Β Β  β”œβ”€β”€ grpc
β”‚Β Β  └── rest
β”œβ”€β”€ modules
β”‚Β Β  β”œβ”€β”€ module1
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ application
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ domain
β”‚Β Β  β”‚Β Β  └── infrastructure
β”‚Β Β  └── module2
β”‚Β Β      β”œβ”€β”€ application
β”‚Β Β      β”œβ”€β”€ domain
β”‚Β Β      └── infrastructure
└── shared
    β”œβ”€β”€ application
    β”œβ”€β”€ domain
    └── infrastructure

This type of division, paying attention to the Screaming Architecture, could indicate the following:

I would like to hear your opinion about this proposal. In this way we can reach a structure that is as appropriate as possible and that can fit a large majority of developers who have the same concerns as us.

Thanks again πŸ˜‰

robertgr991 commented 9 months ago

Hello!

Thank you for the detailed response!

This step is an important one and it's better that you didn't proceed with it in a hurry.

I agree with your proposal, here are my thoughts:

As a side note, this changes will steer the template a little bit away from it's initial objective of proposing a template for a REST API.

borjapazr commented 9 months ago

Hello again, @robertgr991 !

This is my humble opinion. As I said in the previous comment, I am open to any other proposal.

Thank you again.

robertgr991 commented 9 months ago

I think we should continue with the use case of implementing one Bounded Context as this is also easier to adopt. The means of communicating between Bounded Context can be different depending of the context and it's more difficult to create a boilerplate for it.

Your arguments for keeping the Presentation logic decoupled from each module are good and I agree, in this case, as presentation layer is the least coupled with the other layers and the flexibility of removing/moving a specific system with relative ease, speaks for itself. This will also set the rule that it's not the responsibility of the module to present itself, so to speak. Keeping the presentation layer inside each module may also contradict Screaming Architecture because technology-related terms would be used for those filenames.

As I recall, DDD doesn't have specific terminology for the Presentation Layer and different architectures use different terms, but, to be fair, I think presentation is more concise and more frequently used in literature. apps may also sound similar to application layer to someone new to the architecture.

I think, so far, this clarifies the direction in which the architecture should point to, unless others join the discussion.

PS: What do you think about Architectural Decision Records? Should a boilerplate have an opinion on this matter?

borjapazr commented 9 months ago

Hello again, @robertgr991 .

Thank you very much for your reasoning and for giving your opinion regarding these issues. My opinion is the same as yours. As a summary, here are the basics we have established after adopting the use of Vertical Slice Architecture.

As a result, the target structure is as follows:

.
β”œβ”€β”€ modules
β”‚Β Β  β”œβ”€β”€ module1
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ application
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ domain
β”‚Β Β  β”‚Β Β  └── infrastructure
β”‚Β Β  └── module2
β”‚Β Β      β”œβ”€β”€ application
β”‚Β Β      β”œβ”€β”€ domain
β”‚Β Β      └── infrastructure
β”œβ”€β”€ presentation
β”‚Β Β  β”œβ”€β”€ console
β”‚Β Β  β”œβ”€β”€ graphql
β”‚Β Β  β”œβ”€β”€ grpc
β”‚Β Β  └── rest
└── shared
    β”œβ”€β”€ application
    β”œβ”€β”€ domain
    └── infrastructure

On the other hand, linking to the question that you asked in your previous comment, I would like to comment on the following:

PS: Sorry for opening so many topics, but this way we can discuss interesting questions and give our opinion to improve this template.

Thank you very much for your time πŸ™.

robertgr991 commented 9 months ago

Hello!

It's good to discuss these various topics as it sparks different ideas and also acts as a learning/recalling exercise.

borjapazr commented 9 months ago

Hello again!

PS: As new topics arise, for example, applying Vertical Slice Architecture, creating Use Case Interfaces, creating Architectural Decision Records, etc. I will create different issues to implement these functionalities or improvements.

Thanks again!

robertgr991 commented 9 months ago

I should have worded it better. I was trying to say that in presentation layer it is expected to reside the logic of communication with the "outside world" while Integration Events is an internal communication. But I see your point. I've seen this implemented in different ways, in presentation layer, in infrastructure layer of the Shared Kernel. I think this is more of an infrastructure problem than a presentation one, but I don't know if this should reside in the shared layer. What do you think about this?

In the end, this is more of a personal preference, as both presentation and shared/infrastructure will only act as a glue for the actual Use Cases.

borjapazr commented 9 months ago

Hello again,

I've been giving this matter some thought. My opinion regarding where the Integration Events should be captured is as follows:

Now, another topic occurs to me that is quite curious. And it is how you would implement Webhooks in an application that follows this type of architecture we are dealing with. For you, are Webhooks part of the presentation layer or should it be treated as something in the domain? That is, if you had to call an endpoint registered by a subscriber (webhook url/callback) every time a certain event is triggered in the system, how would you model it? I can think of two main options:

I would like to know your opinion on this 😊