Mastering Modern .NET Architecture & Design Patterns

5 days
untj2
Organized by TJIP
5 days

Architectural Principles

Good architecture is about making good decisions over time, not about following rules or trends. This module explains why clear principles help teams make consistent choices and avoid confusion as systems and requirements change.

  • The role of an Architect
  • What is good Architecture?
  • Architectural Principles: Encapsulation, Separation of Concerns, ...
  • Architectural Drivers

N-Tier Architecture

N-Tier architecture is still very common, often because it feels familiar and safe. This module explains why it became popular, what it does well, and why it can become a problem when applications grow larger.

  • What is N-Tier?
  • Physical Tiers vs. Logical Layers
  • The Standard Layered Stack: Data Access, Business, Presentation
  • The "Database-Centric" Mindset
  • Testability, Maintainability, Performance
  • LAB: Creating a Simple N-Tier Application

Clean Architecture

Clean Architecture tries to keep business logic independent from frameworks and infrastructure. This module explains why this separation makes applications easier to test, change and maintain, while also showing where it can add extra complexity.

  • Dependency Inversion
  • Domain, Application, Infrastructure, Presentation Layers
  • Testability, Maintainability, Performance
  • Domain Modelling with Entities and Value Objects
  • Domain Services and Application Services
  • LAB: Migrating from N-Tier to Clean Architecture

Mapping

Mapping is often used to separate different models in an application, but it is not free. This module explains why mapping exists, what problems it tries to solve, and why too much mapping can slow teams down.

  • To DTO or Not?
  • The Domain Leakage Problem
  • Flattening Objects
  • Manual vs. Automated Mapping
  • Performance and Projections
  • Architectural Purity and Developer Productivity
  • LAB: Using Source Generation for Mapping

Vertical Slices

In layered architectures, small changes often touch many parts of the system. This module explains why organizing code around features can make applications easier to understand, change and maintain.

  • The Layer "Tax"
  • Features over Layers Philosophy
  • Abstraction over DRY
  • Implementation Details
  • Managing Shared Logic
  • The Testing Pyramid vs. The Diamond
  • Maintainability and Performance
  • LAB: Migrating from Clean Architecture to Vertical Slices

Persistence Strategy

Data access is a frequent source of design problems in .NET applications. This module evaluates repository patterns, common pitfalls, and practical DbContext usage in both Clean Architecture and Vertical Slices.

  • Repository Pattern
  • Leaky Abstractions
  • The "Generic Repository" Trap
  • DbContext as a Repository
  • Unit Testing Reality
  • Aggregates
  • LAB: Using DbContext in Clean Architecture

Result Objects and Exceptions

Operations can succeed, fail, be cancelled or return different kinds of results. This module dicusses how to handle these situations clearly and consistently, and how these choices affect control flow, clarity and system behavior.

  • Return Codes
  • Flow Control vs. Error Handling
  • Validation
  • Running Jobs
  • Performance Impact
  • Hidden Side Effects
  • "Try"-pattern
  • Discriminated Unions and "OneOf"
  • LAB: Exploring Trade-offs with FluentResults

Messaging Patterns

Messaging is often introduced to decouple components, but can easily increase complexity. This module explains why messaging patterns exist and how to apply them deliberately without turning systems into hard-to-follow workflows.

  • Pub/Sub and Domain Events
  • Mediator: Hero or Villain?
  • Classical .NET Events
  • Domain and Integration Events
  • In-Memory vs. Out-of-Process
  • CQRS
  • Job Scheduling
  • LAB: Using CQRS in Clean Architecture

Modular Monolith

Microservices introduce significant operational and organizational cost. This module explains why modular monoliths offer a pragmatic alternative that enables strong boundaries without premature distribution.

  • Microservices in a Nutshell
  • The Microservices Tax
  • Modular Monolith as strategic middle ground
  • Module Communication & Integration
  • Data Isolation Strategies
  • Enforcing Boundaries
  • LAB: Migrating from Clean Architecture to Modular Monolith

Monorepo vs Polyrepo

Repository structure influences dependency management, team autonomy and evolution speed. This module explains why neither monorepos nor polyrepos are universally correct and how context determines their effectiveness.

  • Atomic Refactoring
  • The "Dependency Hell" Tax
  • The "Slow Build" Myth
  • Team Ownership
  • Private NuGet feeds
  • "Shared Library" Dependency Tax
  • NuGet Versioning
  • Source Mapping

Quality Gates

Quality does not scale through manual reviews alone. This module explains why automated quality gates are needed to enforce standards, protect architecture and keep delivery predictable.

  • Code Style and Formatting
  • Static Code Analysis Tools
  • Complexity Metrics
  • Roslyn Analyzers
  • Testing & Coverage Thresholds
  • Security & Dependency Audits
  • Architectural Tests
  • AI Code Generation Guidelines
  • Acceptance Criteria
  • Quality Gates in CI/CD
  • LAB: Setting up a Quality Gated Project

Monitoring and Observability

Without observability, systems cannot be trusted in production. This module explains why structured telemetry enables faster diagnosis, better decisions and controlled operational cost.

  • Logging vs Telemetry
  • Structured Logging in .NET
  • Instrumentation and OpenTelemetry
  • Application Health and Lifecycle
  • Distributed Tracing
  • Visualization and Dashboards
  • Cost Control
  • Privacy and PII
  • MTTD and MTTR
  • LAB: OpenTelemetry with Grafana

Branching Strategies and Feature Flags

How teams work with branches has a big impact on delivery speed and risk. This module explains why different branching strategies exist, how feature flags enable trunk-based development, and how the same flags can be used to safely release features and control deployments in production.

  • Branching Strategies: GitFlow vs. Trunk-Based
  • Feature Flags: The Enabler of Trunk-Based
  • Deployment Patterns: Canary, Blue-Green, A/B Testing
  • LAB: Targeting Groups with Feature Flags

Improve your OO-design with S.O.L.I.D principles

The S.O.L.I.D principles were introduced by Robert C. Martin (also known as Uncle Bob) in 2000. The intention behind these principles is to make software designs more understandable, easier to maintain, and easier to extend. These principles are essential for every developer to know because they assist in writing better code and in better understanding code that was written with these principles in mind.

  • S - Single Responsibility
  • O - Open/Closed
  • L - Liskov Substitution
  • I - Interface Segregation
  • D - Dependency Inversion

Introduction to Patterns

One might not believe it, but design patterns did not originate in software architecture. Instead, patterns were first described in the 1970s by a real 'bricks and mortar' architect. A pattern is defined as a reusable solution to a common problem, without dictating the exact implementation. This characteristic makes patterns an ideal learning tool and a powerful means for communicating design ideas. Of course, there are also anti-patterns—approaches that are frequently used but are better avoided.

  • What is a Pattern?
  • The Gang of Four: Erich Gamma, Ralph Johnson, Richard Helm and John Vlissides.
  • Different kinds of design patterns: creational, structural and behavioral patterns.
  • Patterns everywhere: the difference between implementation, design and architecture patterns...
  • When to apply patterns, and when not to
  • Some anti-patterns, such as Loosy-Goosy

Singleton Pattern

We will start with a simple creational pattern, Singleton, and discuss its implementation in C#

  • What is a Singleton?
  • Singleton implementation choices in .NET
  • Why sealing classes is a good idea
  • LAB: Building a Singleton in .NET

Abstract Object Creation with Factories

When developing software, you often find yourself continuously creating new objects. While the fundamental act of creating new objects is not inherently problematic, it can lead to design challenges or increased complexity. Creational patterns such as Factory Method can assist you in managing object creation in a way that is appropriate for the situation.

  • Factory Method - delegating/hiding the creation of objects to a factory
  • Abstract Factory - abstracting to a factory to create families of objects
  • LAB: Implementing an Abstract Factory

The Strategy and Chain-Of-Responsibility Pattern

Strategy and Chain-Of-Responsibility are two behavioral patterns that assist in defining a family of algorithms, encapsulating each one, and making them interchangeable. By applying these patterns, you can allow the client to choose the algorithm that best suits their needs at runtime.

  • Strategy - template method without the annoying inheritance
  • LAB: Sorting Objects using Strategies
  • Chain of Responsibility - strategy to go through a chain of strategies
  • LAB: Using a Chain of Responsibility to implement a Builder

Collection Patterns

Iterators are a fundamental part of the .NET framework. They provide a generic way of navigating through collections. By using the yield keyword, you can create an iterator that returns a sequence of values. This approach is particularly useful when you need to asynchronously iterate over a collection.

  • Iterator - providing a generic way of navigating through collections, yield is your friend, asynchronously iterating a collection
  • Performance considerations on implementing IEnumerable
  • Using Frozen collections

Hide Implementation Details with Facade

Facade is both a GOF pattern and a Microsoft pattern. Here we will discuss the diffences and similarities between the two.

  • Facade - hiding the complexity of subsystems from the caller

Using Value Objects

The Value Object pattern represents objects that are defined by their values rather than a unique identity, such as a Money or EmailAddress type. Value objects are immutable and compared by their properties, making your code more robust, intention-revealing, and less error-prone.

  • Avoiding the Primitive Obsession anti-pattern
  • Best practices for building Value Objects
  • LAB: Building an E-mail Value Object

The answer to the ultimate question of life, the universe and good architecture is: It depends. This training equips .NET architects to make principled trade-off decisions across architectural styles, deployment models and governance practices. It provides the insights needed to structure maintainable projects, enforce quality gates and balance developer productivity with long-term sustainability, without falling into common anti-patterns like leaky abstractions or dependency hell.

Senior .NET developers transitioning to architecture roles, solution architects designing enterprise-grade .NET applications and tech leads responsible for code quality, testing strategy, and architectural governance. Requires solid C#/.NET experience, no prior architecture training needed.

Contact Us
  • Address:
    U2U
    Z.1 Researchpark 110
    1731 Zellik (Brussels)
    BELGIUM
  • Phone: +32 2 466 00 16
  • Email: info@u2u.be
  • Monday - Friday: 9:00 - 17:00
    Saturday - Sunday: Closed
Say Hi
© 2026 U2U All rights reserved.