A Microsoft Software Engineer's Take on Milan Jovanović's Pragmatic Clean Architecture Course
My reflection and feedback on Pragmatic Clean Architecture, a .NET Architecture course made by Milan Jovanović.
Overview
So I’ve recently completed Milan’s course on Pragmatic Clean Architecture and thought that I would give it my honest review. Given that I’ve started writing on here and filming on my YouTube, it felt like the perfect opportunity to give guidance to others who are also thinking about purchasing the course.
First of all, who is Milan? Milan Jovanović is a Software Architect who has been a .NET engineer for the past 8 years. He is well known on YouTube, LinkedIn and his newsletter as a fountain of knowledge in the .NET space. I have been following Milan for some time and wanted to learn more about how he architects his systems.
Now, before I start getting into the nitty gritty, I want to be very clear that I have not been paid in any way and I purchased the course myself. Milan provides a lot of free resources and isn’t greedy with his knowledge, and as someone who is striving to create more and more content myself, I have a lot of respect for the way he provides content and knowledge.
The main reason I decided to purchase Milan’s course was due to his architecture knowledge and domain driven design expertise. I have been a software engineer for 9 years, and in that time I have seen domain driven design implemented in many solutions, but there have been many instances where it was still tightly coupled, or, in my opinion, not as scalable as it could be. From seeing Milan’s posts and YouTube, I knew he had experiences with doing this with .NET and I wanted to learn from his knowledge.
The Best Bits…
First let’s start with the cost, Milan’s course is currently retailed at $247, and when I purchased it, it was on special offer (it was $149, I think). For a course that provides 7 hours of video content, the source code, templates to use for your project and pipeline, and postman collections, I personally believe this is a reasonable price.
Milan gives a great overview of Domain Driven Design and why it’s used, he also provides information about what the different layers are and what they are meant to be used for.
I love the use of Mediatr and the CQRS pattern. This is probably my favourite thing from the course and I absolutely love it. I think it’s a really nice and clean way to structure your code, keeping it decoupled from various parts of the system.
I’ve seen a lot of Value Objects that just look overly complex, Milan’s approach to using records is very pragmatic and, what I deem, super clean.
The domain event pattern is a very nice way of publishing events and again, keeps the solution from being tightly coupled. Combine that with the outbox-pattern that he explains in the advanced feature section and we’re on to a winner. I actually wish I watched this a couple months back as I implemented something similar with background processes and event hubs, but definitely not as clean.
I really like the use of Results/Errors rather than in a lot of solutions I’ve worked in that have thrown exceptions all the time. I think this allows for a lot more control, as realistically we should only be throwing exceptions for things we don’t expect to occur. I do believe the course could have benefited from explaining the alternative that is commonly used and why this pattern is cleaner. But regardless, this is a really nice way of dealing with results and errors.
Milan goes through how to implement various middlewares and behaviours, these are very useful when working with an objected oriented programming language such as C#, especially for logging and exception handling. I really recommend you implement them as they generally make the rest of your solution much cleaner, as you only have to focus on your domain logic.
The additional content such as adding Serilog, Caching, health checks and outbox pattern was super informative and again great examples of how to utilise .NET as effectively as possible.
I really enjoyed the sections where Milan refactored code to improve it. Examples being when he changed the domain events to use the outbox pattern and when he refactored the controllers to use minimal API’s. I think the refactoring is a great way of seeing how much better it looks afterwards, more of this in future works please!
Things to consider…
Milan clearly explains that the course is for .NET developers with at least one year of experience, you may struggle with this course if you cannot navigate around C# and .NET. It requires that as a pre-requisite.
There were a few patterns such as Unit of Work and Repository Pattern that are used throughout the course which aren’t always explained. If you are unfamiliar with them, I would encourage you to read up on them because what being done may not make sense to you if you don’t.
Milan implements a lot of authentication/authorisation in his course, which is predominantly for teaching about how authentication and authorisation works. In a production environment, I strongly suggest you learn how to get the most out of your chosen identity provider as maintaining these things yourself can be such a massive pain, as well as using the recommended OAuth2.0 protocol and grant type for your solution. (I realise I forgot to include this in the re-recording of my video, eeeek, sorry!)
If you are still early on in your career, I would encourage you to write your tests as you go, rather than in one block. I think Milan has a lot of experience of writing clean solutions and systems designs thinking that writing tests after such a large change isn’t too bad, but I would encourage to try and do it as you implement a specific functionality/section so that you keep on top of your changes and don’t miss any gaps.
I personally would only consider switching to dapper for querying, if my EF core queries were slow to warrant that, as I think adding an additional ORM introduces additional complexity and learning for those who aren’t familiar with it. In my experience EF core query slowness usually is caused by bad database design and inefficient usages, rather than EF core itself. My preference would be to stick with one ORM provider, or similar, and only switch when there was reasons and justifications to do so such as significant noticeable performance or specific features that are currently unsupported.
There are a lot of libraries and elements that are used throughout the course, they are also moved through quite quickly. Ensure to vet the libraries and give yourself time digest the different sections so that you truly understand what is being taught and assess if any of the libraries used have vulnerabilities you need to be aware of.
From what I observed, there are a lot of requirements that are being captured as part of the infrastructure layer and background processes that I believe should also be tested. Thus I would also have a unit testing project for the infrastructure layer.
Final thoughts…
I really enjoyed Milan’s course and learned a lot of things that I intend to use in my solutions going forward.
I have been a .NET developer for a long time and thus was already familiar with a lot of the concepts, however, the real value add were the various patterns that utilised in order to create clean, loosely coupled and scalable solutions.
For me, Milan’s course is not here to teach you how to use .NET (though he does have a lot of free content that helps with this), it is here to teach developers who are familiar with .NET how to utilise it using industry best practices and clean architecture.
Basically, what it says on the tin.
If you want to see me delve more into this, I have also created a YouTube video which explains some of the topics mentioned in a little bit more detail:
Your hard work is visible and you’re gonna rock it soon!
Thanks for the review, Jade. Really useful 🙏🙏