Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
I’ve written about organizing code by feature and vertical slices instead of technical concern quite a bit on this blog. However, it doesn’t seem to have caught on as much as I’ve hoped. I’m always seeing posts on Twitter about this concept where people finally catch on and make the discovery.
YouTube
Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.
Technical Concern
I’ve always found it interesting that layers or technical concerns ended up being seemingly the most important thing when organizing code. I’m curious how this came to be. My guess is there are many reasons, but I think project template/scaffolding are a culprit.
If you create a brand new ASP.NET Core MVC application, you’re going to get a folder for Models, Views, and Controllers. By default everything is organized by technical concern.
What I find interesting about this is you usually end up having Models, Views, and Controllers all be a 1:1:1. Meaning a ViewModel is likely only used in one View which is only used in one Controller Action. If this is the case, why benefit does having these files/classes live in a project structure based on technical concern?
What does your application do?
I care about capabilities. Features. I care about what an application does.
When I’m looking at a project structure and see a ManageController file, that gives me no insights into features or capabilities that bring to the system. Looking at this project structure below, of course, it’s an e-commerce site, but what are the rich set of features it provides?
Change
When I was creating systems in layers, my pain point was making simple changes to an existing feature or adding a new feature.
Having to edit multiple files across multiple projects seemed absurd and cumbersome.
Data is flowing throw layers. When a user invokes a request, data must flow through all the layers to ultimately hit a database. The same occurs when you need to present data to a user.
In some situations, you could be editing more than 6 files for a simple change.
- DataAccess/ShoppingCartModel.cs
- DataAccess/ShoppingCartRepository.cs
- BusinessLogic/ShoppingCartServices.cs
- Controllers/ShoppingCartController.cs
- ViewModels/ShoppingCartViewModel.cs
- Views/ShoppingCart/View.cshtml
Organize Code by Feature
When you start organizing code by feature you get the benefit of not having to jump around a codebase. Things that related in behavior are placed together. From the screenshot above, if you need to make a change to how products are added to a Shopping Cart, guess which file you’d be changing?
Layers in Features
I’m not saying to throw out layers. Layers ultimately live inside the vertical slice of a feature.
The way I like to describe this is think of your system/service as a cake that has multiple layers. Each layer represents a technical concern. If you have a data access layer, it controls all of the data access within that service/system.
Instead of it being application wide, cut a slice out of that cake.
You still have layers. You still have technical responsibilities, but you’ve made those boundaries to within the vertical slice of a feature.
Dependencies
The biggest win when you start organizing by feature, is now your dependencies are within the vertical slice. This allows you to manage dependencies per vertical slice.
If you wanted to move from EF6 to EF Core, you could do this one vertical slice at a time. It does not mean you have to re-write an entire data access layer to migrate from one to the other.