Hi there, my name is Milan, and welcome to my YouTube channel! 👋
My goal with this channel is to share my .NET and C# knowledge with you. I make videos about software engineering and software architecture, distributed systems, Domain-Driven Design, and any software-related topic I find interesting.
Milan Jovanović
CQRS is a pattern, not a library.
You don't need a mediator to implement it.
You don't need reflection magic.
You don't need "handler discovery".
You just need two interfaces:
- ICommandHandler<T>
- IQueryHandler<T>
When you strip away the libraries, CQRS becomes incredibly simple:
• A class to hold data (The Request)
• A class to process it (The Handler)
• A pipeline for cross-cutting concerns (The Decorator)
If you can't "Go To Definition" on your handler, you've over-engineered it.
Keep your architecture boring.
I wrote a guide on implementing "Vanilla CQRS" from scratch: www.milanjovanovic.tech/blog/cqrs-pattern-the-way-…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
10 hours ago | [YT] | 238
View 6 replies
Milan Jovanović
Stop catching architecture violations in Code Reviews.
It’s a waste of your time.
You shouldn't have to leave comments like: "Please remove the reference to Infrastructure in the Domain project".
Automate it.
Treat your architecture rules like unit tests.
If a developer accidentally references the Database from the Core Domain:
❌ The build fails.
❌ They fix it immediately.
❌ You never see the mistake in PR.
This is called Architecture Testing.
It turns "guidelines" into "guardrails".
Here is the library I use to enforce this in .NET: www.milanjovanovic.tech/blog/shift-left-with-archi…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
1 day ago | [YT] | 476
View 14 replies
Milan Jovanović
If you can't build a well-structured Monolith, you can't build Microservices.
You will just build "Distributed Spaghetti".
And trust me, a distributed mess is 10x worse than a centralized one.
The Monolith vs. Microservices debate is misleading.
It assumes the only way to decouple code is to put a network between components.
That is expensive:
❌ Latency (Network calls are slow)
❌ Unreliability (What if the network blips?)
❌ Complexity (Eventual consistency, distributed transactions)
The smarter move? The Modular Monolith.
You get the clean boundaries of microservices, but with the speed of in-memory calls.
• Keep the modules.
• Keep the encapsulation.
• Delete the network overhead.
Only split when you need to scale a specific team or feature independently.
Don't pay the "Microservice Tax" until you actually need to.
I wrote a guide on how to architect for modularity first: www.milanjovanovic.tech/blog/breaking-it-down-how-…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
2 days ago | [YT] | 430
View 12 replies
Milan Jovanović
Most REST APIs are painful to use.
Here are the top 5 mistakes I see.
It’s not because the logic is bad. It’s because the interface is confusing.
I see developers making the same 5 mistakes over and over:
𝟭. 𝗗𝗲𝗲𝗽 𝗨𝗥𝗟 𝗡𝗲𝘀𝘁𝗶𝗻𝗴: /users/{id}/posts/{id}/comments/{id}. This couples your API to your database structure. Stop it.
𝟮. 𝗣𝗼𝗼𝗿 𝗩𝗲𝗿𝘀𝗶𝗼𝗻𝗶𝗻𝗴: Defaulting to /v1/ without a plan. You are creating a maintenance nightmare for your future self.
𝟯. 𝗜𝗴𝗻𝗼𝗿𝗶𝗻𝗴 𝗣𝗮𝗴𝗶𝗻𝗮𝘁𝗶𝗼𝗻: Returning 10,000 records in one go is the fastest way to kill your database.
𝟰. 𝗜𝗻𝗰𝗼𝗻𝘀𝗶𝘀𝘁𝗲𝗻𝘁 𝗘𝗿𝗿𝗼𝗿𝘀: Returning 200 OK with {"error": "failed"} breaks every client-side convention.
𝟱. 𝗦𝗲𝗰𝘂𝗿𝗶𝘁𝘆 𝗮𝘀 𝗮𝗻 𝗔𝗳𝘁𝗲𝗿𝘁𝗵𝗼𝘂𝗴𝗵𝘁: Bolting on auth at the end never works.
Good API design is about empathy for the developer using it.
I wrote a detailed guide on how to fix these (and what to do instead): www.milanjovanovic.tech/blog/the-5-most-common-res…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
3 days ago | [YT] | 524
View 16 replies
Milan Jovanović
Vertical Slice Architecture is great. Until you need to share code.
Then it becomes a mess.
The urge to create a Common project is strong. You have validation logic used in 3 places. You have a pricing algorithm needed by Cart and Checkout.
So you create a Shared Services library. And just like that, you’ve reintroduced the coupling you were trying to escape.
You're slowly rolling to a distributed ball of mud.
So where should the shared logic go?
I use a simple 3-tier framework to decide:
1️⃣ Technical Infrastructure (Logging, Auth, Result Pattern)
✅ Share this freely.
Put it in a Shared.Kernel or Infrastructure project. It rarely changes based on business requirements.
2️⃣ Domain Concepts (Business Rules)
✅ Push this down.
Instead of a shared service, put the logic on your Entities or Value Objects. If Order and Cart both need to validate an address, the Address value object should own that logic.
3️⃣ Feature-Specific Logic
✅ Keep it local.
If CreateOrder and UpdateOrder need the same helper, put it in a Features/Orders/Shared folder. Do not make it global until a completely unrelated feature needs it.
𝗧𝗵𝗲 𝗚𝗼𝗹𝗱𝗲𝗻 𝗥𝘂𝗹𝗲: Duplication is cheaper than the wrong abstraction.
If you abstract too early, you couple features that shouldn't know about each other. If you duplicate code, you just have two files to update.
I wrote a full guide on how to structure this without breaking your architecture.
Read it here: www.milanjovanovic.tech/blog/vertical-slice-archit…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
4 days ago | [YT] | 347
View 16 replies
Milan Jovanović
What does an API Gateway do?
An API Gateway sits between clients and backend services.
It decides where each request should go.
Core benefits:
- Centralized access
- Abstracts backend services
- Boosts performance
- Handles auth and security
It can also manage:
- Caching
- SSL termination
- Load balancing
In .NET, you can build an API Gateway with YARP.
It makes routing and auth easy.
Here's how: www.milanjovanovic.tech/blog/implementing-an-api-g…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
5 days ago | [YT] | 436
View 21 replies
Milan Jovanović
What’s the fastest way to insert 1 million records into your database?
At some point, every app needs to load a LOT of data.
It's smart to optimize this the right way from the start.
Here’s how the main options compare:
𝗘𝗙 𝗖𝗼𝗿𝗲
Simple and familiar. Works fine for smaller batches, but not the fastest.
𝗘𝗙 𝗖𝗼𝗿𝗲 + 𝗘𝘅𝘁𝗲𝗻𝘀𝗶𝗼𝗻𝘀
Faster. Still feels like EF. Good middle ground.
𝗦𝗤𝗟 𝗕𝘂𝗹𝗸 𝗶𝗻𝘀𝗲𝗿𝘁
Fastest option. SqlBulkCopy (SQL Server).
For PostgreSQL, use the COPY command.
See the full benchmark results → www.milanjovanovic.tech/blog/fast-sql-bulk-inserts…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
6 days ago | [YT] | 443
View 49 replies
Milan Jovanović
Most search bars are pretty "dumb".
They are great at matching exact words. But they fail when humans talk like humans.
If someone searches for "White RTX 4070 with at least 12GB VRAM under $800", a standard search engine often breaks. It looks for that exact sentence description and finds nothing.
This is where Typesense comes in.
If you haven't heard of @typesenseofficial, it's a super-fast, open-source search engine. It stores your data in memory (RAM), which makes it incredibly fast. It's a popular alternative to heavy tools like Elasticsearch or expensive ones like Algolia.
And with their newest update, it just got a lot smarter.
They added 𝗡𝗮𝘁𝘂𝗿𝗮𝗹 𝗟𝗮𝗻𝗴𝘂𝗮𝗴𝗲 𝗦𝗲𝗮𝗿𝗰𝗵.
Here is how it works:
You don't need to build complex machine learning tools anymore. Typesense now uses AI to understand the meaning behind a search. It automatically translates a messy human sentence into precise filters.
Let's look at that PC part example.
Imagine a user types:
"I need a white AM5 motherboard with WiFi and at least 3 M.2 slots".
In the past, this would likely return zero results. But Typesense now understands the intent automatically:
1. It sees "AM5" and knows to filter by Socket Type
2. It sees "White" and filters by Color
3. It sees "at least 3" and creates a math rule (>=3) for M.2 Slots
4. It matches "WiFi" to the Features list
It does all of this instantly, in one step.
You get the power of a "smart" search assistant without needing a team of data scientists to build it.
If you want to see how this fits into your architecture, check out Typesense: fandf.co/4bAd9LN
It might be the upgrade your search bar needs.
A huge thank you to Typesnse for sponsoring this post.
P.S. There's a community-built .NET SDK if you want to give it a try. I'll leave the link to it in the comments.
1 week ago | [YT] | 468
View 5 replies
Milan Jovanović
I've been using Clean Architecture for 7+ years.
It’s the only way I build enterprise systems now.
The Problem? ❌
Most projects lack structure. Every team reinvents the wheel, and onboarding takes months because "every app is different."
The Solution? ✅
Clean Architecture.
But most people get it wrong.
It’s not about having 4 specific projects in your solution. It’s not about following a template blindly.
It is strictly about the Direction of Dependencies.
- Core (Domain/App): Defines the abstractions.
- Outer (Infra/API): Implements them.
The beauty is you can package this however you want:
• Traditional Layers
• Vertical Slices (my favorite)
• Modular Components
As long as the dependencies point inward, you win.
Want to see how I structure this in .NET?
Grab my free template here: www.milanjovanovic.tech/templates/clean-architectu…
1 week ago | [YT] | 747
View 27 replies
Milan Jovanović
Folders are not architecture. 📂
You can have the cleanest folder structure in the world, and still have a "Big Ball of Mud."
If your modules can talk to each other freely, you don't have a Modular Monolith. You just have a Monolith with more projects.
The trap is subtle:
- A new feature doesn't fit a specific module.
- "I'll just put it in Core/Shared for now."
- 6 months later, Core depends on everything and everything depends on Core.
Real architecture is restrictive.
It uses compile-time rules to physically prevent Module A from touching Module B's internals.
Here is how to enforce those boundaries strictly: www.milanjovanovic.tech/blog/refactoring-overgrown…
---
Do you want to simplify your development process? Grab my Clean Architecture template here and save days of development time: www.milanjovanovic.tech/templates/clean-architectu…
1 week ago | [YT] | 355
View 20 replies
Load more