Software architectural patterns are one of the more polarizing and controversial topics in the development world.
"Here's all the patterns that every project needs!"
"All patterns are bad and you should feel bad if you use them!"
In this post I will talk about what Architectural Patterns are, when they matter, when to use them and when not to.
I will list out a few patterns in a way that I hope will share understanding rather than dogmatic positions that are often held by tech influencers on social media.
What Are Architectural Patterns?
An architectural pattern is a solution to a specific problem that arises in the design of a project. They come in the form of separating concerns, grouping functionality, abstracting implementation details, and dictating conventions for the team to use.
Patterns can be as simple as breaking features into predictable functions, or to complex layers that handle a multitude of use cases.
When Should One Use Patterns?
When you find your code being hard to navigate, disorganized, difficult to maintain, or having trouble on-boarding new developers, using patterns can make some sense of the chaos.
If you find that your project has a problem, sometimes a pattern will resolve your problem. If your project doesn't have the problem that the pattern addresses, or if you don't understand what problem the pattern address, don't use the pattern.
It's as simple as that.
After 16 years of experience with many CMSs (Content Management Systems), I have found that they benefit greatly from Architectural Patterns, or that the lack of patterns can hinder growth and modernization over the years.
Of all the CMSs I have experience with, mojoPortal is the one I know most about, is dearest to my heart, and the CMS that I will use to showcase my position on patterns.
"I Don't Feel Like I Need Patterns"
This is a good indicator that you don't need patterns. If you are a solo developer, are in a small team, or it's just a side project, there might not be a need for you to even consider a pattern.
If you have a project that later in its lifetime you feel like you would benefit from a pattern, refactoring is always an option.
What are Common Patterns and the Problems They Solve?
There are so many that I couldn't possibly list them, but I'll list a few I've had experience with, and some that I believe to have value in the CMS realm.
Layered (N-Tier) Architecture

If you're familiar with mojoPortal, it mostly implements this pattern.
The idea behind this pattern is to separate functionality concerns into these project layers:
The Data Access Layer holds all implementation code for storing and manipulating data. It becomes the only API for the application to interface with your data, be it from a file, a database engine, or another system.
The Business Layer is the only layer that references the Data Access Layer. It holds domain entities (classes that represent tables in a database for instance) and the logic to bring the data together in code representations of the application features.
The Presentation (Web) Layer is the only layer that references the Business Layer. This layer is for "presenting" the features in the application. It could be a Windows Application or a Web Application, but the main thing it does is give a user interface to the code features from the Business layer.
The reason I said mojoPortal "mostly" implemented this pattern is because while the project is split into the proper layers, a lot of the business logic wound up in the Web (Presentation) Layer. This has made it very difficult to attempt to migrate away from the Web Forms framework it was built on to a more modern and capable framework.
The pros of this pattern are everything is grouped in a logical fashion and you know where everything belongs.
The cons of this pattern are that every layer is tightly coupled to the previous layer. This can be difficult later down the road when replacing dependencies or dealing with providers for services throughout the application. This leads into the next pattern.
Clean Architecture

The purpose of this pattern is much like the previous pattern, but with some tweaks and the implementation of another pattern to facilitate changes to make up for the previous pattern's downfalls.
Much like the Layered Architecture pattern, the application is separated into several projects.
It differs on some key points.
- All interaction between layers is done through the use of contract interfaces.
What this means is unlike layered architecture, instead of directly referencing the implementation of a service, you reference the interface the service implements. This allows for easily swapping out the implementation if needed.
- The layer references are moved around a bit. Rather than each project pointing to the previous project, the projects are placed in an encircling shape, all pointing inward or towards each other in their layer.
The Layers are as such:
The Domain Layer is the ultimate authority of the entire application. It contains all the domain concerns and contracts for the application with no references to any internal or external dependencies. All other layers can use this layer. This layer is often coupled with the Domain Driven Design pattern, but it's not required.
The Application Layer contains the business logic of the application and the contract interfaces that are to be implemented in the Infrastructure layer. Often times this is where the CQRS and/or Vertical Slice patterns are used, but it's not required.
The Infrastructure Layer is where all implementations for the contracted services in the Application are kept. All external dependencies/libraries are abstracted here, allowing for easy replacement from one library to another if needed. An example would be if your project started by supporting SQL Server but later a migration to PostgreSQL was in order, the only assembly that would need to be edited or replaced would be the Infrastructure assembly.
Sometimes the Infrastructure Layer will break out only the database concerns into its own Persistence Layer(s), keeping the database specific code in it's own layer(s), but this is not required.
The Presentation Layer brings everything together through the use of the Inversion of Control Pattern. This allows each layer to register services in the IoC container using the interface contracts and keeping the implementation details hidden from the application. The IoC container handles the dependencies for all services that are registered to it, allowing the system to keep track of lifecycles and dispose of objects so that the implementation reference is kept in one location.
A cool thing about Clean Architecture is that one could have multiple Presentation Layers but share all the core functionality from the Application Layer. Do you need a multi-page website but want to administrate it through a mobile app? The answer could be two Presentation Layers, an MVC/Razor Pages layer for the website, and a Web API layer in conjunction with the mobile app for administration.
The pros of this pattern are that it's incredibly versatile while enforcing strict separation of concerns and external dependencies allowing for a very long-lived application.
The cons of this pattern are that it's moderately complicated, where boilerplate could become monotonous if the application doesn't need to use the pattern.
mojoPortal would have benefited a lot from this pattern being implemented properly, as migrating to .NET (Core) from .NET Framework would have consisted of replacing the Infrastructure layer using the same Application Layer contracts, and rebuilding the Presentation Layer in a .NET (Core) UI framework. The majority of the application wouldn't change.
More Reading:
The Repository and Unit of Work Patterns
The Repository pattern is an excellent pattern for data access. The Unit of Work pattern compliments the Repository pattern by allowing for bundles transactions for data integrity.
The Repository pattern's goal is to abstract repeated logic for data manipulation and querying. It allows you to have a single "GetById" method that works for all tables with the code being written once. It keeps your code DRY and makes it easy to do things like adding global query filters for features like soft deletion.
The Unit of Work pattern creates a "unit of work" for each action you take when mutating data. If you need to save a blog post, but it needs a new category that does not exist, the UoW will prevent bad data from being saved if creating the category fails by not saving the blog post. It's an interface for database transactions, if you're familiar with how those work.
Some people raise issue to the Repository (and Unit of Work) pattern when using Entity Framework, as Entity Framework implements its own versions of those patterns. This is completely understandable for application that will realistically never wish to change the library that connects to the database. However, from experience, I would rather have everything in my application have its own contracts to facilitate that possibility of change.
mojoPortal's Data Access layers all use ADO.NET, and their contracts are the implementations, which has made changing to something like Entity Framework for easy migrations and multiple database providers very hard. If the Repository pattern was between the layers, replacement would be a much more feasible.
More Reading:
The Query Specification Pattern
The Query Specification pattern is another pattern used in tandem with the repository pattern. It allows us to create domain level specifications that we can use in the Application Layer without having to expose an implementation's API.
For instance, we can create a "GetBookWithAuthors" specification that just takes a Book ID, and pass the specification to the Repository's "FirstOrDefaultAsync" method that will be sure that the underlying data access code will return the appropriate Book with Authors for that book.
More Reading:
Plugin Architecture Pattern
The Plugin Architecture Pattern is a pattern that facilitates the ability to add or change functionality of the application with the use of third party bundled code. Most CMSs support this pattern, mojoPortal has its own way of handling modules (plugins) that achieve the same goal.
It's quite simple, the main application provides a set of APIs (the Plugin Interface) that a plugin developer can implement in their plugin, and then register their code with the Plugin Manager, which is responsible for loading and running the Plugin code.
More Reading:
Bringing it all Together
By using the Clean Architectural pattern, we have a good foundation to allow us to plug and play any implementations through the use of contract interfaces and Dependency Injection. In the event that the database code needs to be swapped out, a third party library needs to be replaced due to a security vulnerability, or having the ability to provide different implementations for selection through the application's settings, this will help facilitate these use cases.
Using the Repository, Unit of Work, and Query Specification patterns we can prevent repeating code for querying data and we abstract away data query implementation, and it allows us to support or swap database providers at runtime.
The Plugin pattern allows for us to expand the application in any way that is needed. Be it adding new features (Blog, Forums, Event Calendar, CRM, etc.) or modifying an existing feature (swapping out authentication methods, listening for events to modify data, etc.) it makes the application as flexible as possible.
Conclusion
These are what I believe are the foundational building blocks for a CMS like the next version of mojoPortal could use, and who knows? I might be doing just that. 😉
Does that mean that all applications should use Clean Architecture or the Repository patterns? Clearly not.
Patterns are like shoes, if they fit and do the job that you have a need for, use them, otherwise don't. Just don't make the mistake that if your application doesn't need patterns that no one needs patterns, as many people on the internet so readily declare.