Vertical Slice Architecture (VSA)
Vertical Slice allows you to organize your projects per feature rather than per technicals and with it you gain visibility in what the project actually do.
You don't need to have folders like "Services" (that don't mean anything because everything in code can be seen as a service..) or "Entities", (entities mean different things in different contexts).
You don't need to be the best creative guy giving the best names for your files/classes.
You don't need to be the super architect when you start the project too.
VSA gives you more granular control over how you want to implement a feature
Queries and Commands are a simple seggregation of responsabilities that we can implement differently over each Feature.
Create(resourceName) can be seen as a Command because you instruct to execute create your resource.
GetList(ResourceName) can be seen as a Query because you can invoke it many times and should give you typically the same result and should be indempotent.
In a query you want to use a microORM "Dapper" which is ultrafast mini-orm or standard ADO.NET to achieve speed.
In a command you use "EF" or "Hibernate" because you don't bother losing extra 200ms for inserts.
Basically in your queries you want speed and control, and on your commands you use an ORM which is slower but easier to do complex inserts in multiple tables, for example.
You don't need to specific your architecture in the beginning, but as you go along you use what most suits you. This allows you to avoid abstractions and specially allows you to get access to all APIs in the libraries you choose.
By abstracting things you lose access to the underlying implementation details. Example is an ORM, when you abstract it as a Repository or UnitOfWork - you lose access to ChangeTracker, LazyLoading. - Repositories don't need to know what these are, but you as a developer want to control it no matter what.
These are some things that we gain naturally for implementing VCA Architecture.
Lets go back to the structure that is suggested (context use case) instead of folders containing technicals elements like..
** User.csproj
root/
├── app.config
├── Services/
├── Views/
├── Repositories/
└── User/
With Vertical Slice Architecture you get something like:
** User.csproj
root/
├── app.config
├── Infrastructure/ # Reusable code, extensions, helpers, etc.
│
├── Domain/ # Domain entities and boundaries
│ ├── User.cs
│ └── Address.cs
│
├── Features/ # Feature-specific code
│ ├── CreateUser/ # Sub-directory for CreateUser feature
│ │ ├── CreateUserController.cs # Handler for the endpoint and action
│ │ ├── CreateUserCommand.cs # Command to add User to DB
│ │ └── CreateUserMapper.cs # Mapper from request to UserAggregate
│ │
│ ├── ListUsers/ # Sub-directory for ListUsers feature
│ │ ├── ListUserController.cs # Handler for query invocation
│ │ └── ListUsersQuery.cs # Query for fetching users
│ │
│ └── AppendAddress/ # Sub-directory for AppendAddress feature
│ └── ...feature-related files...cs
If you have more contexts, like Cart, where the User has Cart to make orders to be delivered at home, we can organize all of this under another project (DLL) and you can follow the same structure for Cart and make the features your system offers in that project inside the features, improving Cohesion.
** UserCart.csproj
root/
├── Domain/ # Domain entities and boundaries
│ └── Cart.cs # Represents the Cart domain entity
│
├── Features/ # Feature-specific code
│ └── AddItemToCart/ # Sub-directory for AddItemToCart feature
│ ├── AddItemToCartController.cs # Handler for the endpoint and action
│ ├── AddItemToCartCommand.cs # Command to add an item to the Cart
│ └── AddItemToCartMapper.cs # Mapper from request to CartAggregate
This gives context to what the system do, and overall all dependencies are closer to each other and independent improving much more the Cohesion. Regarding the coupling, mostly everything is under the same folder, so your dependencies should be easy to find and Inject.
Working in this way you also avoid Git conflicts, mostly because you are working feature independent of other possible developers in the same project.
Using Technical terms in a project makes it more spaguetti, because we lose track of things already done and you can't DRY (don't repeat yourself). Lots of times you don't know what is done already, files aren't cohesive and you aren't aware of their existance, ending up creating other code with other API that does exactly the same.
Everything is feature related and should be close by so that you know you aren't repeating code already done.
Keep in mind things that are sharable can be to a common library, or a Infrastructure folder in the same project, making clear what is reusable.
The following is a Rider project done in C# using feature approach and you are looking into the /api/user/create endpoint.
