Screaming Architecture
Often, developers overlook folder structure because it seems unimportant. However, as a system grows, maintaining it becomes increasingly difficult. A common solution to managing this complexity is to divide and conquer.
Today, you’ll discover a more effective approach to organizing folders that not only clarifies the system’s purpose but also makes it easier to navigate and maintain.
Let’s begin, shall we?
The Problem with Typical Project Structures
Many applications start with a traditional N-layered architecture where inside each layer you have folders grouped by technical responsibilities, such as controllers, entities, services, repositories, and so on.
This approach isn’t exactly bad. It’s simple, intuitive, helps group related code, and works well as long as the project remains small.
However, over time, you notice that:
- directories grow large, complicating navigation and making locating the right service difficult
- changes in one feature require touching many unrelated folders
- understanding what the system actually does requires deep code reading
- business logic becomes scattered across services
Even though some of the issues can be addressed with conventions, IDE navigation tools, or documentation, it does not mean that the underlying problems disappear.
This is where screaming architecture comes into play.
What Screaming Architecture Looks Like
Screaming Architecture is a design philosophy whose core idea says: your project structure should clearly communicate what the system does, not what frameworks or technologies it uses.
When someone opens your repository, it should scream:
“This is an apartment booking system!”
In Screaming Architecture, folders are organized by business concepts, not technical roles.
You still have the same layers as before, but now their internal organization is structured differently:
- The API layer is small enough that further organization is less obvious. However, you can still:
- organize controllers per client type, following the Backend-for-Frontend pattern (for internal usage, mobile client, for external integration, etc)
- organize controllers by feature, as they can span multiple controllers (for example,
TodoController,TodoItemController,TodoListControllercan all reside in the same feature folder)
- if the presentation layer also includes UI concerns (like view controllers, razor pages, and models), you can group them together too
2. The Application layer is split by business features or use cases.
Get iamprovidence’s stories in your inbox
Join Medium for free to get updates from this writer.
A feature is a distinct business capability or functionality that the system provides to its users. (e.g., Apartments, Bookings, Payments).
Inside each folder, you can create subfolders for DTOs, use cases, event handlers, and services — just like before — but now in smaller, more manageable chunks.
3. The Domain layer is also organized by feature; However, if you are following DDD principles, you can also group by aggregate to keep related entities, value objects, enums, and domain services together.
4. While it can sometimes be difficult to define clear boundaries in the previous layers, the Infrastructure layer is usually simpler to organize, as you can split it by responsibility — persistence, caching, logging, and so on.
Of course, if your infrastructure grows large, it’s also recommended to split it further — for example, persistence logic can be organized by entity or feature, etc.
Why Screaming Architecture Matters
With this approach, you gain some conceptual clarity:
- developers are immediately guided on what the system does, as each folder represents a specific business capability
- it’s easier to understand a module, its available use cases, the used infrastructure, etc
- improved cohesion, as related use cases are grouped together
- high coupling within a single use case and its related use cases, while maintaining low coupling between unrelated use cases
Additionally, there are practical benefits as well:
- folders are smaller, making them easier to manage and maintain
- navigation becomes simpler, since connected code typically resides within the same folder
- adding a new feature is easier, as you can identify similar behavior and replicate the structure
- removing a feature is straightforward because you can simply delete the entire folder without affecting unrelated code
- refactoring becomes easier, since it is simpler to move, reorganize, or restructure functionality without impacting other parts of the system
- extracting functionality into a project becomes easier, since related code is already grouped and self-contained
Sum It Up
While organizing a project by folders may seem simple at first, not everyone realizes the impact it can have on maintainability and clarity as the system grows.
Broadly, there are two approaches: a technology-driven structure and a feature-driven structure. Both approaches make sense and can be used effectively.
Although the tech-driven approach is often viewed bad, it remains simple and practical in small projects — perfectly fine as long as it doesn’t create friction or complexity for the team.
On the other hand, feature-based grouping can make the system’s purpose clearer, but overusing it can backfire, leaving a small project cluttered with many folders containing only a single file.
Notice, this principle isn’t limited to backend projects. The same ideas can be applied on the frontend — React, Angular, or other frameworks — by grouping code per feature, pages, components, routes, or state management, improving both clarity and maintainability.
Let me know in the comment section what you think about this architecture💬 Clap if you discover something new here 👋 Support me with a coffee ☕ And follow to receive more insights ✅








