LEARN BUILD GROW TOGETHER
DEVELOPER LEARNING HUB
Learn. Build. Grow Together.

Practical tutorials, real-world examples and interview preparation.

.NETC#SQL SERVERANGULAR
Home /Architecture Patterns /Architecture Patterns: Complete Developer Learning Guide

Architecture Patterns: Complete Developer Learning Guide

Software Architecture · Beginner to Advanced

Architecture Patterns: Complete Developer Learning Guide

Learn how software systems are structured, how architectural styles shape application boundaries, and how to choose practical architectures for maintainable, scalable, and reliable applications—with examples focused on C# and ASP.NET Core.

Software architecture describes the major structures of a system, the responsibilities assigned to its parts, the boundaries between those parts, and the rules that govern their interactions. An architecture pattern is a reusable high-level approach to organizing a system around a recurring set of requirements and constraints.

This guide explains architecture concepts generically and uses .NET examples to connect them to real application development. It covers traditional application structures, domain-oriented approaches, distributed systems, data and integration patterns, and the trade-offs involved in choosing them.

1. Architecture foundations

What is software architecture?

Software architecture is the set of significant decisions about a system's structure. It identifies components, their responsibilities, communication paths, data ownership, deployment boundaries, and constraints. Architecture is not only a diagram: it is reflected in code, configuration, infrastructure, and team practices.

Architecture pattern vs design pattern

AspectArchitecture patternDesign pattern
ScopeSystem or major subsystem structure.Classes and collaborating objects, generally within a component.
ConcernBoundaries, deployment, communication, data ownership, and system qualities.Object creation, composition, and behavior.
ExamplesLayered, Hexagonal, Microservices, Event-driven.Strategy, Factory, Adapter, Decorator.
RelationshipDefines the broad structure in which design patterns may be used.Helps implement parts of an architecture.

Architecture style, pattern, and reference architecture

  • Architectural style: A broad family of structural constraints and principles, such as event-driven or layered architecture.
  • Architecture pattern: A reusable solution structure for a recurring architectural problem, such as a modular monolith or microservices.
  • Reference architecture: A reusable starting model for a particular domain or platform, which still needs adaptation.
  • Architecture decision: A recorded choice, its context, alternatives, and consequences.
There is no single architecture that is best for every application. The right choice depends on business complexity, team size, deployment needs, operational maturity, security, cost, and expected change.

2. Quality attributes and architectural trade-offs

Architecture should be shaped by the qualities the system must achieve. These are often called quality attributes or non-functional requirements.

Quality attributeWhat it meansQuestions to ask
MaintainabilityHow easily the system can be understood and changed.Can a feature change without touching unrelated modules?
ScalabilityAbility to handle growth in workload or data.Can capacity be increased where the bottleneck exists?
AvailabilityAbility to remain usable when parts fail.What happens when a dependency or instance is unavailable?
ReliabilityAbility to operate correctly over time.Are failures detected, contained, and recovered safely?
PerformanceResponse time, throughput, and resource efficiency.What are the latency and throughput targets?
SecurityProtection of data, identities, and operations.Where are trust boundaries and authorization decisions?
TestabilityAbility to verify behavior at suitable levels.Can core business rules be tested without infrastructure?
DeployabilityAbility to release changes safely and frequently.Can components be deployed independently where needed?
ObservabilityAbility to understand internal behavior from outputs.Can an operator trace a request across dependencies?

Quality attributes can conflict. Strong consistency may increase latency; independent deployment may add distributed-system complexity; high availability can increase infrastructure cost. Architecture makes these trade-offs explicit rather than eliminating them.

3. Layered Architecture

What is it?

Layered Architecture organizes an application into horizontal layers, each with a defined responsibility. A common application structure separates presentation, business logic, and data access.

+--------------------------------------+
| Presentation Layer                   |
| ASP.NET Core Controllers / UI        |
+--------------------------------------+
                   |
                   v
+--------------------------------------+
| Application / Business Layer         |
| Use cases, validation, coordination  |
+--------------------------------------+
                   |
                   v
+--------------------------------------+
| Data Access / Infrastructure Layer   |
| EF Core, SQL Server, external APIs   |
+--------------------------------------+

Typical responsibilities

  • Presentation: Handles HTTP requests, input binding, response formatting, and presentation concerns.
  • Application: Coordinates use cases and invokes domain or infrastructure abstractions.
  • Domain / Business: Contains business rules, policies, and domain behavior.
  • Infrastructure / Data access: Implements persistence, messaging, file storage, and external integrations.

Example .NET solution structure

MyApplication/
  MyApplication.Web/
    Controllers/
    Middleware/
    Program.cs

  MyApplication.Application/
    Orders/
    Customers/
    Interfaces/

  MyApplication.Domain/
    Entities/
    ValueObjects/
    Rules/

  MyApplication.Infrastructure/
    Persistence/
    Repositories/
    ExternalServices/

This folder layout alone does not guarantee layered architecture. The important part is enforcing allowed dependencies and keeping responsibilities in the correct places.

Advantages and limitations

  • Advantages: Familiar structure, clear separation of concerns, straightforward onboarding, and suitable for many business applications.
  • Limitations: Layers can become pass-throughs, business rules can leak into controllers or repositories, and strict layer-by-layer dependencies can make some changes cumbersome.

4. Three-Tier Architecture

Three-Tier Architecture separates an application into three logical or physical tiers: presentation, application logic, and data. A tier is often associated with a deployable or runtime boundary, while a layer is primarily a logical separation in code. The terms are related but not identical.

Browser / Angular Client
          |
          v
Web Tier: ASP.NET Core API
          |
          v
Application Tier: Business Services
          |
          v
Data Tier: SQL Server

A common deployment might host an Angular application as static files, an ASP.NET Core API on an application host, and SQL Server on a separate database host. These tiers can be deployed separately, but they do not have to be separate physical machines in every environment.

When it fits

  • Traditional business applications with a web or desktop client.
  • Systems where database access needs a separate security boundary.
  • Applications that benefit from scaling the web/API tier independently of the database tier.
Three-tier describes a common deployment separation. It does not prescribe how code inside the API should be organized; the API can itself use layered, Clean, or Hexagonal Architecture.

5. Clean Architecture

Core idea

Clean Architecture organizes code around business policies and use cases. Its central rule is the Dependency Rule: source-code dependencies point inward toward policies that are less likely to change. Infrastructure and frameworks are details at the outer boundary.

        +--------------------------------+
        | Frameworks & Infrastructure    |
        | ASP.NET Core, EF Core, SQL      |
        |        +----------------+      |
        |        | Interface      |      |
        |        | Adapters       |      |
        |        |   +--------+   |      |
        |        |   | Use    |   |      |
        |        |   | Cases  |   |      |
        |        |   | +----+ |   |      |
        |        |   | |Domain| |   |      |
        |        |   | +----+ |   |      |
        |        |   +--------+   |      |
        |        +----------------+      |
        +--------------------------------+

Typical project structure

SalesSystem/
  SalesSystem.Domain/
    Entities/
    ValueObjects/
    DomainEvents/

  SalesSystem.Application/
    Orders/
      CreateOrder/
      GetOrder/
    Abstractions/

  SalesSystem.Infrastructure/
    Persistence/
    Email/
    Messaging/

  SalesSystem.Api/
    Controllers/
    Middleware/
    Program.cs

Dependency direction

The API and infrastructure projects can depend on application and domain abstractions. The application layer should not depend directly on EF Core, SQL Server, or ASP.NET Core. Instead, it defines interfaces needed by its use cases; infrastructure supplies implementations.

// Application layer: abstraction owned by the use case
public interface IOrderStore
{
    Task<Order?> GetAsync(
        int id,
        CancellationToken cancellationToken);

    Task AddAsync(
        Order order,
        CancellationToken cancellationToken);
}

// Infrastructure layer: implementation uses EF Core
public sealed class EfOrderStore(AppDbContext db) : IOrderStore
{
    public Task<Order?> GetAsync(
        int id,
        CancellationToken cancellationToken) =>
        db.Orders.SingleOrDefaultAsync(
            x => x.Id == id, cancellationToken);

    public async Task AddAsync(
        Order order,
        CancellationToken cancellationToken)
    {
        await db.Orders.AddAsync(order, cancellationToken);
    }
}

Advantages and limitations

  • Advantages: Business rules are less coupled to frameworks, use cases are easier to test, and infrastructure can be replaced behind abstractions.
  • Limitations: More projects and interfaces can create overhead for small CRUD applications. Teams must understand and enforce dependency direction.
Clean Architecture is an approach, not a required set of project names or folders. Keep the dependency rule and use-case boundaries; adapt the project structure to the size of the system.

6. Onion Architecture

Onion Architecture places the domain model at the center and arranges surrounding layers around it. Dependencies point inward, so the domain does not depend on infrastructure or presentation.

        Infrastructure
      +-------------------+
      | Application       |
      |  +-------------+  |
      |  | Domain      |  |
      |  | Entities    |  |
      |  | Value Types |  |
      |  +-------------+  |
      +-------------------+

Typical rings include Domain Model, Domain Services, Application Services, and Infrastructure. The exact ring names vary by implementation. Interfaces are commonly defined toward the inner layers and implemented by outer layers.

Onion vs Clean Architecture

Both emphasize inward dependencies and keeping domain/application policies independent of infrastructure. They are closely related approaches rather than mutually exclusive competing technologies. Clean Architecture describes a broader set of boundaries and use-case-oriented ideas; Onion Architecture is commonly illustrated as concentric layers around the domain.

.NET use case: a domain-rich business application where entities, value objects, and domain rules should remain independent of EF Core and ASP.NET Core.

7. Hexagonal Architecture (Ports and Adapters)

Core idea

Hexagonal Architecture places the application core behind ports. Ports describe how the core communicates with the outside world; adapters translate external technologies into those ports or expose the core to external actors.

             Web API Adapter
                   |
                   v
          +-------------------+
          |                   |
          |   Application     |---- Port ---- SQL Adapter
          |       Core        |
          |                   |---- Port ---- Message Adapter
          |                   |
          +-------------------+
                   ^
                   |
             Test Adapter
  • Inbound ports: Operations that the application exposes, such as placing an order.
  • Inbound adapters: HTTP controllers, message consumers, command-line interfaces, or test drivers that call those operations.
  • Outbound ports: Interfaces the application needs, such as saving an order or publishing an event.
  • Outbound adapters: EF Core repositories, HTTP clients, file stores, or message brokers that implement those interfaces.

Example port and adapter in C#

// Outbound port owned by the application core
public interface ICustomerDirectory
{
    Task<CustomerInfo?> FindAsync(
        string customerCode,
        CancellationToken cancellationToken);
}

// Outbound adapter in infrastructure
public sealed class HttpCustomerDirectory(
    HttpClient httpClient) : ICustomerDirectory
{
    public Task<CustomerInfo?> FindAsync(
        string customerCode,
        CancellationToken cancellationToken) =>
        httpClient.GetFromJsonAsync<CustomerInfo>(
            $"customers/{Uri.EscapeDataString(customerCode)}",
            cancellationToken);
}

ASP.NET Core dependency injection connects the port to its adapter at startup. The application core does not need to know that the implementation uses HTTP.

When it fits

  • Applications integrating with several external systems.
  • Systems that need strong test seams around infrastructure.
  • Products where database, messaging, or provider technology may change.

8. Modular Monolith Architecture

A modular monolith is one deployable application divided into well-defined modules. Modules own specific business capabilities and communicate through explicit contracts rather than freely accessing one another's internals.

                 ASP.NET Core Host
+--------------------------------------------------+
|                                                  |
|  +-------------+  +-------------+  +-----------+ |
|  | Orders      |  | Customers   |  | Billing   | |
|  | Module      |  | Module      |  | Module    | |
|  | Own rules   |  | Own rules   |  | Own rules | |
|  +-------------+  +-------------+  +-----------+ |
|                                                  |
|          Shared infrastructure / database       |
+--------------------------------------------------+

Important modularity practices

  • Give each module a clear business responsibility.
  • Expose a small public API and keep implementation details internal.
  • Avoid direct access to another module's tables or internal classes.
  • Use explicit contracts or domain events for cross-module collaboration.
  • Test module boundaries and enforce dependency rules in the build.

Advantages

It retains the simpler deployment and in-process communication of a monolith while improving separation of business capabilities. Modules can later become candidates for independent services if a genuine need emerges.

A modular monolith is often a strong starting point for a new business system. It avoids distributed-system overhead while encouraging boundaries that can be validated as the application grows.

9. Microservices Architecture

What is it?

Microservices Architecture structures a system as a set of small, independently deployable services aligned with business capabilities. Each service owns its logic and data and communicates with other services through explicit contracts, commonly HTTP APIs or messaging.

                  API Gateway / Client
                          |
           +--------------+--------------+
           |              |              |
           v              v              v
      Order Service  Customer Service  Payment Service
           |              |              |
           v              v              v
       Order DB       Customer DB      Payment DB

Core characteristics

  • Independent deployment and versioning.
  • Business-capability boundaries rather than technical-layer splitting.
  • Service-owned data and controlled data sharing through contracts.
  • Network communication and independent failure modes.
  • Automation for deployment, monitoring, security, and operations.

Advantages

  • Services can be scaled and released independently.
  • Teams can own services end-to-end.
  • Technology choices can vary where justified.
  • Failures can be isolated when boundaries and resilience are designed correctly.

Challenges

  • Network latency, timeouts, partial failures, and retries.
  • Distributed data consistency and cross-service workflows.
  • Service discovery, API versioning, observability, and security.
  • More deployment pipelines, infrastructure, and operational cost.
  • Testing end-to-end behavior across independently changing services.
Microservices are not simply multiple Web APIs. Splitting a small application into services without business boundaries, automation, monitoring, and operational capability can make it harder to build and support.

10. Event-Driven Architecture

Event-Driven Architecture uses events to communicate that something has happened. Producers publish events, and interested consumers react to them. Components can be loosely coupled because producers do not need direct knowledge of every consumer.

Order API
   |
   v
Order Service ---- publishes ----> Message Broker
                                      |
                       +--------------+-------------+
                       |              |             |
                       v              v             v
                 Email Consumer  Billing Worker  Analytics

Command vs event

CommandEvent
Requests that something should happen.States that something has happened.
Usually addressed to a specific handler or service.Can be consumed by multiple interested subscribers.
Often imperative, e.g. ShipOrder.Usually past tense, e.g. OrderShipped.

Integration events and domain events

A domain event represents something meaningful that occurred inside a domain model. An integration event communicates a committed business fact across a process or service boundary. Do not publish an integration event before the business transaction is safely committed.

Example event contract

public sealed record OrderPlacedIntegrationEvent(
    Guid EventId,
    int OrderId,
    DateTimeOffset OccurredAt,
    decimal Total);

Use stable, versionable contracts. Consumers should tolerate duplicate delivery and handle messages idempotently. Event-driven architecture does not automatically guarantee ordering, exactly-once processing, or successful delivery.

11. Serverless Architecture

Serverless is a cloud execution model in which the cloud provider manages much of the server provisioning and runtime infrastructure. Developers deploy functions or managed services and are commonly billed according to execution, requests, or allocated resources, depending on the service plan.

HTTP Request / Queue Message / Timer
                 |
                 v
          Cloud Function
                 |
        +--------+--------+
        |                 |
        v                 v
   Managed Database   Object Storage

Common use cases

  • Scheduled jobs and background processing.
  • Event-triggered file processing.
  • Lightweight APIs and integration workflows.
  • Automation that runs intermittently.

Advantages and trade-offs

Serverless can reduce infrastructure management and scale automatically for supported workloads. Consider cold-start behavior, execution limits, concurrency, vendor-specific integrations, local testing, observability, and cost under sustained traffic. Serverless does not mean there are no servers; it means the provider manages the underlying infrastructure.

.NET example: Azure Functions can run .NET code in response to HTTP requests, timers, queues, and other supported triggers. Choose the hosting plan and worker model based on the target runtime and workload requirements.

12. Client-Server and API Architecture

Client-server architecture separates clients that request capabilities from servers that provide them. A client may be a browser, Angular application, mobile app, desktop application, or another service.

Angular / Browser / Mobile Client
                |
          HTTPS + JSON
                |
                v
       ASP.NET Core Web API
                |
       Application Services
                |
                v
          SQL Server

Common API styles

  • REST: Resource-oriented HTTP APIs that use HTTP semantics and representations.
  • RPC: Remote procedure calls that expose operations across a network.
  • GraphQL: A query language and runtime that lets clients request shaped data through a schema.
  • gRPC: A high-performance RPC framework commonly using Protocol Buffers and HTTP/2.
  • WebSockets: A full-duplex communication channel useful for real-time interactions.

Choose an API style based on client needs, communication patterns, compatibility, performance, tooling, and team experience. A system can use more than one style at different boundaries.

13. Service-Oriented Architecture (SOA)

SOA organizes business capabilities as interoperable services with explicit contracts. Services may be coarse-grained and can be integrated through enterprise messaging, APIs, or an enterprise service bus (ESB).

SOA and microservices

SOA (common enterprise approach)Microservices (common modern approach)
Often emphasizes enterprise-wide service reuse and integration.Emphasizes independently deployable services aligned to bounded business capabilities.
May use a centralized integration layer or ESB.Often favors lightweight, explicit communication and decentralized governance.
Service granularity can be coarse.Services are typically smaller, but should not be split arbitrarily.
Data ownership and deployment autonomy vary by implementation.Independent service ownership of data and deployment is a common goal.

These are tendencies, not strict definitions. Real systems can combine SOA and microservice ideas. Avoid assuming that one is always newer or better; assess the integration landscape and organizational needs.

14. CQRS (Command Query Responsibility Segregation)

CQRS separates operations that change state (commands) from operations that read data (queries). The separation can be logical within one application or can extend to distinct models and storage systems when justified.

                 Application
                      |
             +--------+--------+
             |                 |
             v                 v
        Command Side       Query Side
        Create / Update    Read / Search
             |                 |
             v                 v
        Write Model        Read Model

Simple .NET example

public sealed record CreateCustomerCommand(
    string Name,
    string Email);

public sealed record GetCustomerQuery(int CustomerId);

Command handlers validate and execute state changes. Query handlers retrieve and shape data for consumers. A simple CQRS implementation can use the same SQL Server database and shared domain model.

When CQRS helps

  • Read and write workflows have significantly different needs.
  • Read models need specialized projections or search capabilities.
  • Use cases benefit from explicit request/handler boundaries.
CQRS does not require event sourcing, separate databases, microservices, or a mediator library. Added complexity is not justified for every CRUD application.

15. Event Sourcing

Event Sourcing stores the sequence of events that led to the current state instead of storing only the latest state. Current state is reconstructed by replaying events, often with snapshots to reduce replay cost.

AccountOpened
      |
      v
MoneyDeposited(500)
      |
      v
MoneyWithdrawn(100)
      |
      v
Current Balance = 400

Important concepts

  • Event store: Append-oriented storage for domain events.
  • Replay: Rebuild state by applying events in sequence.
  • Snapshot: A saved state checkpoint that reduces replay work.
  • Projection: A read model derived from events.
  • Event versioning: Managing changes to event contracts over time.

Benefits and challenges

Event Sourcing can provide a detailed history, support temporal analysis, and make event-driven projections natural. It also introduces complexity around schema evolution, replay, ordering, concurrency, retention, privacy, and rebuilding projections. Sensitive information may need special handling because historical events are difficult to alter or erase safely.

Use it when historical state transitions are central to the business, not merely because an event log sounds useful.

16. Data Architecture Patterns

Database per service

In a microservices system, each service owns its data and exposes it through an API or events. Other services should not directly query its private tables. This supports autonomy but makes cross-service reporting and transactions more involved.

Shared database

Multiple application components use the same database. This can be simple and effective for a modular monolith, but unrestricted cross-module table access can create tight coupling. Use schemas, ownership rules, and module contracts to protect boundaries.

Cache-Aside

The application checks a cache first. On a cache miss, it loads data from the source, stores the result in the cache, and returns it. Cache invalidation, expiration, consistency, and stampede protection must be considered.

Application
    |
    v
Check Cache ---- hit ----> Return
    |
   miss
    v
Database
    |
    v
Populate Cache
    |
    v
Return

Read replicas

Read replicas can offload read workloads from a primary database. Replication lag means a recent write may not be visible immediately on a replica. Route reads according to consistency requirements, not simply because a replica exists.

Polyglot persistence

Polyglot persistence uses different data stores for different needs—for example, relational storage for transactions, a search engine for full-text search, and object storage for files. Each additional data technology adds operational and integration cost; choose it for a demonstrated requirement.

17. Integration and Messaging Patterns

API Gateway

An API Gateway provides an entry point for clients and can route requests, enforce policies, aggregate responses, or translate protocols. It should not become a home for all business logic.

Backend for Frontend (BFF)

BFF provides a client-specific backend for a particular user experience, such as web or mobile. It can shape responses and reduce client orchestration, but multiple BFFs add services to maintain.

Publish-Subscribe

Publishers send messages to a topic or event channel. Subscribers receive messages independently, enabling one event to trigger multiple consumers.

Message queue

A queue decouples producers from consumers and supports asynchronous work. Consider visibility timeouts, retries, dead-letter queues, ordering, message size, and consumer idempotency.

Transactional Outbox

The Outbox pattern solves the dual-write problem: updating a database and publishing a message are two separate operations that can fail independently. The application writes business data and an outbox record in the same database transaction. A background publisher later sends the event and marks it processed.

One database transaction:
  1. Update Order
  2. Insert OutboxMessage
  3. Commit

Background publisher:
  4. Read pending outbox rows
  5. Publish message
  6. Mark row as published

Publishing can happen more than once if the publisher crashes after sending but before recording success. Consumers should therefore be idempotent, and the outbox process needs retry and monitoring.

Saga pattern

A Saga coordinates a business transaction across multiple services as a sequence of local transactions. If a later step fails, compensating actions can attempt to reverse earlier business effects. Compensation is not always a literal rollback; it is a new business action that addresses the completed step.

18. Resilience Patterns

Distributed applications must expect dependencies to fail, respond slowly, or become overloaded. Resilience patterns help limit the impact and recover safely.

PatternPurposeImportant consideration
TimeoutLimits how long an operation may wait.Choose a deadline based on the end-to-end request budget.
Retry with backoffRetries selected transient failures after a delay.Bound retries; retry only when safe and avoid retry storms.
Circuit BreakerTemporarily stops calls to a dependency that is failing.Define thresholds, open duration, and recovery behavior.
BulkheadIsolates resources or workloads.Set capacity limits and understand queueing behavior.
Rate LimitingControls request volume.Choose limits by identity, endpoint, resource, and service capacity.
FallbackProvides a safe alternative when an operation fails.Fallback data must be clearly acceptable and not misleading.

In .NET, use supported HTTP client and resilience integrations for outgoing requests. Do not stack independent retry policies without understanding their combined effect. Apply cancellation, timeouts, idempotency keys, and telemetry consistently.

19. Security Architecture

Security is an architectural concern that crosses application layers and deployment boundaries. It should be designed into identity, data access, network communication, secrets management, and operational processes.

  • Defense in depth: Use multiple complementary controls rather than relying on one perimeter.
  • Least privilege: Give users, services, and workloads only the permissions they need.
  • Zero Trust: Avoid implicit trust based only on network location; verify identity and context explicitly.
  • Authentication: Establish who or what is making a request.
  • Authorization: Decide what the authenticated identity may do.
  • Secrets management: Store credentials and keys in managed secret stores, not source code.
  • Data protection: Apply encryption in transit and at rest where appropriate, plus retention and access controls.
  • Auditability: Record security-relevant actions without logging secrets or unnecessary personal data.

In ASP.NET Core, use established authentication handlers, authorization policies, secure configuration, HTTPS, input validation, and framework protections. Do not invent a custom token or cryptographic protocol when a standard, maintained implementation is available.

20. Deployment and Hosting Patterns

Monolithic deployment

The application is packaged and deployed as one unit. This is straightforward to operate and can be a good fit for many systems.

Independent service deployment

Components are packaged and deployed independently. This enables independent release and scaling but requires service discovery, compatibility management, monitoring, and operational automation.

Containers

Containers package an application and its runtime dependencies into a consistent deployable unit. They improve environment consistency but do not automatically provide orchestration, high availability, or security.

Orchestration

Container orchestration platforms manage scheduling, service discovery, scaling, health checks, and rolling deployments across a cluster. Kubernetes is a widely used example; it adds platform complexity and should be adopted when its capabilities are needed.

Cloud hosting choices

Hosting modelWhat you manageTypical fit
Virtual machines (IaaS)OS configuration, patching, runtime, application, and much of operations.Custom OS requirements or legacy workloads.
Managed application platform (PaaS)Application and configuration; provider manages much of the platform.Web apps and APIs without server administration.
Containers as a serviceContainer image and app configuration; provider manages varying amounts of infrastructure.Portable packaged applications.
Serverless functionsFunction code and trigger/configuration; provider manages execution infrastructure.Event-driven or intermittent workloads.

The correct choice depends on runtime support, networking, scaling, compliance, deployment model, operational skills, and total cost—not just the number of users.

21. Observability: Logs, Metrics, and Traces

Observability helps teams understand what a system is doing internally by examining its outputs. It is essential for diagnosing production issues, especially when a request crosses multiple services.

  • Logs: Timestamped records of events and diagnostic context.
  • Metrics: Numeric measurements over time, such as request rate, error rate, latency, CPU, and queue depth.
  • Distributed traces: Show the path and timing of a request across services and dependencies.

Use correlation and trace identifiers to connect related activity. Avoid logging passwords, access tokens, connection strings, or sensitive personal data. Define service-level indicators and alerts around user-visible outcomes rather than infrastructure metrics alone.

.NET ecosystem: ASP.NET Core integrates with logging, metrics, and tracing abstractions. OpenTelemetry can provide a vendor-neutral approach to collecting and exporting telemetry.

22. Applying Architecture in ASP.NET Core

Example solution layout

Commerce/
  Commerce.Api/
    Controllers/
    Middleware/
    Program.cs

  Commerce.Application/
    Orders/
    Customers/
    Abstractions/

  Commerce.Domain/
    Entities/
    ValueObjects/
    DomainEvents/

  Commerce.Infrastructure/
    Persistence/
    Messaging/
    ExternalClients/

  Commerce.Tests/
    Unit/
    Integration/

Register infrastructure implementations at the composition root

builder.Services.AddScoped<IOrderStore, EfOrderStore>();
builder.Services.AddScoped<IOrderService, OrderService>();

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("Default")));

The composition root is where the application wires abstractions to concrete implementations. In ASP.NET Core, this commonly happens in Program.cs or extension methods called from it.

Keep controllers thin

[ApiController]
[Route("api/orders")]
public sealed class OrdersController : ControllerBase
{
    private readonly IOrderService _orders;

    public OrdersController(IOrderService orders)
        => _orders = orders;

    [HttpGet("{id:int}")]
    public async Task<IActionResult> Get(
        int id,
        CancellationToken cancellationToken)
    {
        var order = await _orders.GetAsync(id, cancellationToken);

        return order is null ? NotFound() : Ok(order);
    }
}

The controller handles HTTP concerns and delegates the use case. The application service coordinates business operations; domain objects enforce domain rules; infrastructure implements persistence and external communication.

Testing at different levels

  • Unit tests: Test domain rules and isolated application behavior.
  • Integration tests: Test boundaries such as EF Core persistence, HTTP clients, and messaging adapters.
  • API tests: Exercise HTTP routes, serialization, authentication, and middleware.
  • End-to-end tests: Verify important user journeys across deployed components.

Do not mock every dependency automatically. Use real implementations in integration tests where they provide stronger confidence, and use test doubles where isolation makes a test clearer and more reliable.

23. Architecture Pattern Comparison

ArchitecturePrimary focusComplexityTypical fit
LayeredSeparate responsibilities into logical layers.Low to mediumTraditional business applications.
Three-TierSeparate presentation, application, and data tiers.Low to mediumClient/server systems and separated hosting.
Clean / Onion / HexagonalProtect core policies through dependency boundaries.MediumBusiness applications with meaningful domain logic or integration needs.
Modular MonolithStrong module boundaries in one deployable.MediumGrowing products and teams that want modularity without distributed operations.
MicroservicesIndependent services and deployments.HighSystems needing service autonomy and capable platform operations.
Event-DrivenAsynchronous event-based collaboration.Medium to highWorkflows with independent consumers and decoupled processing.
ServerlessManaged event-triggered execution.VariesIntermittent tasks and cloud-native integrations.
Event SourcingPersist state transitions as events.HighDomains where historical changes are central.

These patterns are not mutually exclusive. For example, a modular monolith can use Clean Architecture inside each module, expose REST APIs, and use events for background processing.

24. Choosing the Right Architecture

Questions to ask before selecting

  1. Business complexity: Is the application mostly CRUD, or does it contain complex domain rules and workflows?
  2. Team structure: How many teams need to work independently, and who owns production operations?
  3. Deployment needs: Must components be released independently?
  4. Scaling: Is there evidence that different capabilities need different scaling profiles?
  5. Data consistency: Are cross-component transactions required, or can eventual consistency be accepted?
  6. Integration: Does the system need synchronous APIs, asynchronous messaging, or both?
  7. Operations: Can the organization monitor, secure, deploy, and troubleshoot the proposed architecture?
  8. Cost: Does the benefit justify the infrastructure and engineering effort?

A practical starting point

For many new business applications, begin with a well-structured monolith or modular monolith. Use clear boundaries, automated tests, dependency inversion where it provides value, and observable deployment practices. Split a module into a service when there is a measurable reason such as independent scaling, release cadence, ownership, or fault isolation.

Architecture should evolve with evidence. A simple design that meets today's requirements and can be changed safely is usually better than a complex design built for hypothetical scale.

25. Common Architecture Mistakes

  • Choosing technology before requirements: Starting with a framework or cloud service instead of quality attributes and constraints.
  • Premature microservices: Adding network and operational complexity before service boundaries are understood.
  • Big ball of mud: Allowing modules and layers to depend on each other's internals without rules.
  • Over-abstraction: Creating layers and interfaces that only forward calls and add no meaningful boundary.
  • Shared database coupling: Letting supposedly independent services read and write each other's tables.
  • Distributed monolith: Splitting deployment units while keeping tight synchronous dependencies and coordinated releases.
  • Ignoring failure: Assuming remote calls always succeed or that retries are always safe.
  • No observability: Deploying components without logs, metrics, traces, and actionable alerts.
  • Architecture by diagram only: Drawing boundaries but not enforcing them in code, tests, or deployment.
  • Ignoring security early: Adding authentication, authorization, secrets, and audit controls only after features are complete.

26. Practical .NET Architecture Example

Scenario

Imagine a business application with an Angular frontend, an ASP.NET Core Web API, and SQL Server. Users create and review orders, while the system sends notifications after an order is placed.

Start with a modular monolith

BusinessPortal/
  BusinessPortal.Api/
  Modules/
    Orders/
      Orders.Domain/
      Orders.Application/
      Orders.Infrastructure/
    Customers/
      Customers.Domain/
      Customers.Application/
      Customers.Infrastructure/
  Shared/
    Contracts/
  Infrastructure/
    Messaging/
    Observability/

Request flow

Angular UI
   |
   v
ASP.NET Core Orders Endpoint
   |
   v
Place Order Use Case
   |
   +----> Order Domain Rules
   |
   +----> Order Repository (port)
                 |
                 v
          EF Core / SQL Server
                 |
                 v
          Outbox Record
                 |
                 v
          Background Publisher
                 |
                 v
          Message Broker
             /       \
            v         v
      Email Worker  Reporting Worker

Why this is a reasonable starting architecture

  • The API handles HTTP and delegates application work.
  • The order module owns its business rules and persistence boundary.
  • The outbox keeps the order update and event record in one database transaction.
  • Background consumers can be added without making the order request wait for every downstream task.
  • The module can be extracted later if independent deployment or scaling becomes valuable.

Possible evolution

If order processing later needs independent scaling and team ownership, the Orders module may become a separate service. Before extraction, define its data ownership, API/event contracts, operational monitoring, authentication between services, and failure-handling behavior. Do not split solely to increase the number of projects.

27. Architecture Review Checklist

  • Are the business capabilities and system boundaries clearly identified?
  • Are the most important quality attributes measurable?
  • Are dependencies between modules explicit and controlled?
  • Is data ownership clear?
  • Are synchronous and asynchronous communication choices justified?
  • Are timeouts, retries, idempotency, and partial failures considered?
  • Are authentication, authorization, secrets, and data protection designed in?
  • Can the system be tested at unit, integration, and end-to-end levels?
  • Are logs, metrics, traces, and actionable alerts available?
  • Can the team deploy, operate, and recover the system?
  • Are architectural decisions and trade-offs documented?
  • Is the design no more complex than the requirements justify?

28. Architecture Patterns Interview Questions

  1. What is software architecture?
    The significant structures, boundaries, responsibilities, and decisions that shape a software system.
  2. What is the difference between architecture and design patterns?
    Architecture patterns address system-level organization; design patterns address recurring class/object collaboration problems.
  3. Layer vs tier?
    A layer is a logical responsibility boundary in code; a tier commonly represents a runtime or deployment boundary.
  4. What is Clean Architecture?
    An approach that keeps business policies and use cases independent of outer frameworks and infrastructure through inward dependency direction.
  5. What is Hexagonal Architecture?
    An approach that isolates an application core behind ports, with adapters connecting external systems and actors.
  6. Clean vs Onion vs Hexagonal?
    They are related approaches emphasizing dependency inversion and isolation of core logic, with different ways of describing boundaries.
  7. What is a modular monolith?
    One deployable application organized into modules with explicit boundaries and controlled communication.
  8. When should you use microservices?
    When independent deployment, scaling, ownership, or fault isolation provides enough benefit to justify distributed-system complexity.
  9. What is Event-Driven Architecture?
    A style in which components publish and consume events to coordinate work, often asynchronously.
  10. Command vs event?
    A command requests an action; an event records a fact that has occurred.
  11. What is CQRS?
    Separating state-changing commands from data-reading queries.
  12. Does CQRS require separate databases?
    No. It can be implemented with separate code paths and models over one database.
  13. What is Event Sourcing?
    Persisting state changes as an event sequence and deriving current state from those events.
  14. What is the Outbox pattern?
    Writing business data and a message record in one transaction, then publishing the message asynchronously.
  15. What is a Saga?
    A sequence of local transactions across services, coordinated with compensating actions for failures.
  16. What is an API Gateway?
    A client-facing entry point that can route, aggregate, and apply cross-cutting API policies.
  17. What is a BFF?
    A backend tailored to the needs of a particular frontend or client experience.
  18. What is observability?
    The ability to understand system behavior using telemetry such as logs, metrics, and traces.

29. Further Learning and Official Resources

Architecture guidance and framework capabilities evolve. Verify implementation details against the documentation for the .NET, ASP.NET Core, and cloud platform versions you plan to deploy.