Reduce complexity in larger systems with Vertical Slice Architecture
Many engineering departments are converting large, complex code bases into something more scalable. The real challenge is managing complexity, and Vertical Slice Architecture is a solid way to do it.
Introduction
Many engineering departments are today faced with the challenge of converting large complex code bases into something more scalable that can meet the expectations of the organisation, often related to time to market and quality of service.
My perspective here is that the true challenge is managing said complexity, and many organisations fail to understand this. Plenty of organisations has gone the path of micro-services with poorly designed domains and architectures which results in a set of complex applications with network overhead.
Larger services, monoliths or what ever you would like to call them, can be extremely powerful without the added network overhead. However, it requires a solid architecture to handle such complexity.
In this article I will present how I find Vertical Slice Architecture to be a very solid approach when you are tasked with reducing complexity, while also being able to deliver.
What is Vertical Slice Architecture?
A few year ago, I found Derek Comartin who runs a great blog and Youtube channel, and got me introduced to VSA. I later found out that the architecture was coined by Jimmy Bogard in 2008. Personally, I am no expert at the architecture, but have gained some experience worth sharing.
VSA focuses on the cohesion of the features your domain is offering, instead of creating technical layers of separation such as the classic Presentation/Application/Domain/Data layers.

In a horizontally separated application, you as the writer of a new feature would need to create classes, in multiple different files and potentially in different modules to allow the creation of a single feature.
On the flip side, you as a maintainer of a feature would need to spend a lot of cognitive energy to see the full picture of how the feature is implemented.
VSA aims to solve these issues, by gathering all the necessary code in a single file or package.
Let’s see some examples from my SaaS project:

Anyone who enters this project can easily find what capabilities my application offers in terms of Bookings, you are able to Create, Edit and Delete bookings but also Create something called a ‘BookableResource’.
If you as a maintainer of the domain, need to figure out how a Booking is created — you have all the information in the ‘CreateBooking’ file and it’s a quite logical naming if you are investigating how a Booking is created.
public class CreateBooking(
ApplicationDbContext context,
IAuthenticatedUser user)
: IAsyncHandler<CreateBookingRequest, CreateBookingResponse>
{
public async Task<CreateBookingResponse> Execute(
CreateBookingRequest request)
{
var booking = new Booking();
booking.SetBookingTime(request.BookedFrom, request.BookedTo);
booking.BookResource(request.Resource);
booking.CreatedBy = user.GetUserId().Id;
booking.OrganizationId = user.GetOrganizationId().Id;
context.Bookings.Add(booking);
await context.SaveChangesAsync();
return new CreateBookingResponse(
booking.Id,
booking.BookedFrom,
booking.BookedTo,
booking.BookableResource);
}
}
public record CreateBookingRequest(
DateTime BookedFrom,
DateTime BookedTo,
BookableResource Resource);
public record CreateBookingResponse(
Guid Id,
DateTime BookedFrom,
DateTime BookedTo,
BookableResource Resource);
The request needed to execute the feature is defined as ‘CreateBookingRequest’ so you know what it takes to create a Booking.
The response which will be returned is also defined in the file, so you know what data to expect.
The handle method will tell you everything you need to know in order to carry out the feature.
If the feature is exposed in, let’s say, a REST API, I would also define that endpoint in the same file.
Coupling between features
There should not be any direct references between your features, ‘EditBooking’ should for example not use ‘GetBooking’ in order to find the Booking object — this should be implemented in the ‘EditBooking’ feature.
public class EditBooking(
ApplicationDbContext context,
IAuthenticatedUser user)
{
public async Task Execute(EditBookingRequest request)
{
var booking =
context.Bookings.FirstOrDefault(
booking =>
booking.Id == request.Id
&& booking.CreatedBy == user.GetUserId().Id);
if (booking is null)
throw new KeyNotFoundException("Could not find Booking");
booking.SetBookingTime(request.BookedFrom, request.BookedTo);
await context.SaveChangesAsync();
}
}
public record EditBookingRequest(
Guid Id,
DateTime BookedFrom,
DateTime BookedTo);
A core strength of VSA is that your features are isolated and independent. Introducing a bug in a creation flow, should not impact your users abilities to edit.
I was once working in a code base, where the developers had chained a ton of features, everything from authentication, to authorization to queries and state changing operations. It got very hard to figure out what was going on, and we were back to a highly coupled and complex solution — so please avoid this..
Separating domains within the application
For my project(s) I have taken inspiration from Modular Monoliths, to create a separation between the different domains in my application. Mainly because I want to keep a clear separation of concern, forcing me to reflect on how a new feature should coexist with the existing features.
Each domain is divided into a package with a set of cohesive features, and there are no direct dependencies between the domains. There might be scenarios where one domain, needs to be aware of something that occurred on another domain — for this I would utilize events.

If there is a need for data retrieval cross domain, I would first consider if the domain is properly modeled. But should it be needed, you could utilize the “public API” approach from Modular Monoliths to ensure low coupling.
Testing Features
We all know testing is important, but if you are in a complex system with high coupling it might become hard to write automated tests. The service class you are depending on might have plenty of injected dependencies that are not relevant for your new feature, but you still have to mock them in order to proceed with your test.
In VSA, since the class you are testing only contains what is needed to carry out the feature, you only need to mock what is relevant for your test.
How can VSA be beneficial in a complex code base?
If you are currently working in such an environment, you likely still have expectations to deliver new features and improve existing features. You might also recognize that there is a fear of introducing unexpected behavior in the application due to high coupling and complexity, leading to longer lead times for your deliveries.
By introducing VSA you can isolate new features from the existing complexity, at least to a significantly higher degree than extending existing horizontal layers. Since you do not rely on large horizontal layers like service classes, you will likely require less mocking and can move forward faster.
Meanwhile, I would set focus on the top user journeys in the application and target these for refactoring. As these are highly likely that you 1) want to ensure is working correctly and 2) want to extend with new features.
By doing so over time, you will end up in a new reality with clear logical boundaries between your domains and a less complex application to maintain and extend.
Closing words
Vertical slice architecture is not always the answer, and the context of your situation plays a larger part. But I do think it’s important for engineers and engineering leaders in these types of situations to not default to a micro-service solution, but rather think of the problem they are actually trying to solve.
On the other hand your team might not have full ownership of the application, or you have strong coupling to modules that block technical upgrades such as language or framework versions. In those scenarios it might be better to extract your domain to a new service.
I would recommend everyone to give vertical slice architecture a try, gain an understanding of the fundamental ideas and see if this approach can benefit you and your team!