At Inspeerity, I finally got a chance to work with a designated architect on the team. They’ve shown me the tremendous value that the right architectural decisions bring to the project. Inspired by that, I will try to explain what those decisions are, how they affect the development cycle, and how Blazor relates to established patterns. All my opinions, of course. Enjoy the read!
What are architectural patterns?
So what do I mean by patterns anyway? In programming, as in life, some problems come up again and again. Architectural patterns are tried and tested ways of structuring your code to solve some of these problems. They are design techniques of a higher level, focused on relations, responsibilities, rules, and guidelines in system structures and communication.
Best thing is, they address the core of the problem, which is architecture, so they can be used regardless of language, framework, or environment. No two implementations will be identical, but if the underlying problem is the same, the right architectural pattern can solve it again and again. This is a field growing in importance especially now, with the popularization of distributed systems.
It’s not just gibberish
Good architectural decisions make all the stages of the product development cycle smoother. Knowing the service structure that will be required – a cost-optimized hosting plan can be selected from the very beginning. Keeping each system block loosely coupled decreases the cost and time of maintenance. It also facilitates agility in delivering feature, which can then be adjusted to consumer needs. Applying architectural patterns decreases the time it takes to go from a business idea to the implementation plan. It also improves communication with development teams, which can also be distributed.
I’d say no more proof is required. Although, what is possible (or indeed necessary) in software architecture evolves over time, as the environment becomes more complex, patterns help address core challenges. Architectural patterns and the role of an Architect – to oversee decisions made in the project – are essential for a product’s success.
Onto the architectural patterns in Blazor
For this article, and so it won’t grow into a book, I will assume that you have a fundamental understanding of all the patterns that will be mentioned. I’ll touch briefly on what they mean and deeper on how they apply in Blazor.
Something most will know – MVVM. Model-View-ViewModel
If you have ever built a .NET application with a user interface before Blazor, you most likely have heard about the MVVM pattern. It was introduced to decouple GUI design from the backend part of the application. To address it, a ViewModel structure was introduced as a communication middleware between the presentation layer (View) and domain layer (Model). It was already broadly utilized in WPF, so would probably be the most widely known.
Blazor enables manipulation of UI with C# code. It also allows separating that code from the actual markup, into a separate file. With that, applying the MVVM pattern can become blurry. It’s important to have a clear understanding of the tasks of the code that’s being written. As long as its primary goal is to enable interactions with the browser, it should be treated as a presentation layer, a View block. That’s how you’d treat script files in other web development frameworks, right? Placement of the underlying .NET code does not affect the architectural pattern structure. One suggestion here though: don’t make code spaghetti. If a razor file becomes too complex, it’s always worth it to separate markup and C#, or even refactor an entire component (more on that in a separate article).
What about the presentation logic layer? Do ViewModels still apply in Blazor? Yes, if you want them to. Patterns are universal in problem-solving, disregarding the advancement of frameworks themselves. ViewModels implementation will be the perfect choice when migrating to new-age web development. The team will already be familiar with architecture fundamentals. Blazor was built on the premise of reusability. And MVVM allows for achieving exactly that. Separation of concerns will also enable high testability of the presentation logic of your application.
How about Vertical Slices?
Vertical Slices architecture slice (pun intended) an application not horizontally but rather by its features. This means separating the code-base according to its functionality. It’s a natural choice, especially for CRUD-like apps. It allows for quick localization of underlying problems or places for an extension. All the files in question are going to be placed next to each other. That might not work well in a complex solution, adding another level of complexity to an already nested project structure.
I’ve been working with a monolith Blazor Server app that follows Vertical Slices principles. CQRS logic was implemented with the help of the MediatR package. Ideally, that requires Request (Query or Command), Handler, and Response objects. Razor markup was separated from the interactivity implementations done in C#. Request class was used as an interaction model and the Response model was utilized as an alert/status model for the UI as well. This allowed it to have a simple razor code-behind file, as its responsibility was only to delegate actions to a proper Handler.
That approach made the best of the world of Blazor and Vertical Slices while limiting implementation complexity to an absolute minimum. Less complexity, means easier maintenance and management of the code, lowering the costs.
One red flag though: are SOLID principles still followed in the aforementioned application and should they?
The Holy Grail – Domain-driven design
As the name implies, everything here is centered on the domain model. Design usually consists of four layers: UI, Application, Infrastructure, and aforementioned Domain. It’s probably the most universal pattern that could be chosen, regardless of what the technology stack is. Should you want to explore more about DDD, I’d highly recommend following Piotr Filipowicz on LinkedIn. And yes, I’ve just plugged my buddy again.
Layering application logic can become a complex topic, so don’t bite off more than you can chew, just because it might be sweet. So when would domain-driven design make the most sense in Blazor? In solutions where WASM and Server are implemented together. Complex challenges require complex solutions. Both processes would be hosted separately, but should be sharing a majority of the logic. DDD addresses that problem. The infrastructure layer is unified for both environments. The Domain is by design a primary source of logic and should keep most of the shared code. To achieve loose coupling, a shared layer has to be introduced, on which all other DDD layers will depend.
BAMStack is the new JAMStack.
JAMStack stands for Java-API-Markup Stack. In this case, the Presentation layer, presentation logic, and backend logic are strongly decoupled. This pattern was tested with Java-based web development first, allowing for great results in terms of scalability.
No wonder then, that BAMStack appeared. It stands for Blazor-API-Markup Stack and was somewhat formalized at the .NET Conf in 2021. Here’s the link if you’d like to see the whole session. The concept was quickly adopted for a variety of reasons. First, an application that follows those principles is highly scalable and has a lot of flexibility in that. The backend and the frontend can be managed separately. Second, the workflow can be easily divided within the team, as cross-sections are very limited, resulting in quicker delivery.
We’re building a BAMStack application for one of our clients at Inspeerity. It’s a perfect fit for that company’s needs. The portal web application was built with Blazor. Portals are complex solutions on their own, so all the logic was encapsulated in an API, allowing us to keep that complexity in check. Having said that, it also proved the efficiency of working with distributed systems. Scalability can be accurately managed, as the overloaded service can be expanded alone, be it API, Blazor Server, or SignalR sockets.
Make a choice…
…but how to make the best one? Well, in the undying wisdom passed down from generation of developers to generation, which rings true in all use-cases: it depends! It depends on your business needs, it also depends on the complexity of the solution that’s required to meet them. Another factor to consider is the consumer base for that product – how big and how active is it going to be?
From a couple of years of my own experience, BAMStack applications that also follow Vertical Slices principles would be the safest choice as of today. Those implementations are the best fit to universally handle the majority of business cases. They also don’t over-complexify structures where it’s not necessary to.
You could always gamble, but with so many options chances are it will be neither optimal nor a good choice. I’d strongly recommend having an architect on board or at least to consult with…
…or let us assist you.
Inspeeriteam would be more than glad to have an opportunity to analyze your needs. Let’s establish the best course of action together. My work buddies excel at what they do, architectures included. We could build something extraordinary in Blazor. But our services are not only limited to .NET.
So how can we bring your vision to life?
Any patterns you’d like to see a deeper dive into? Let us know, we’d be happy to hear your feedback.
But for the next article we’ll take a look at the application state management both on the Server and for WASM. Onto the next one!
Read previous articles:
Part 1 Hi, it’s Blazor. Microsoft Blazor. Have we met?
Part 2 .NET, web applications, cloud, IoT – where to start and why the answer is Blazor?
Part 3 Blazor – one to rule them all. Or is it?
Part 4 How to Start a Blazor Project Right?