Search Knowledge

© 2026 LIBREUNI PROJECT

Software Architecture / Design Analysis

Styles, Tactics & Structural Patterns

Styles, Tactics & Structural Patterns

Architectural styles are reusable structural answers to recurring forces. The Azure Architecture Center presents styles such as layered, microservices, event-driven, and CQRS as choices with known benefits and liabilities, not as maturity levels. Layered architecture manages dependency direction and separation of concerns. Hexagonal architecture protects the domain from infrastructure details. Event-driven architecture decouples producers from consumers in time. Microservices align deployable units with ownership boundaries.

The mistake is treating styles as identities. A system is rarely “a microservices architecture” in a pure sense. It may use a modular monolith for core transactions, event-driven integration for downstream workflows, a data lake for analytics, and serverless functions for low-risk automation. Senior architects compose styles deliberately and explain which forces each style addresses.

Code
left to right direction
rectangle "Architectural Forces" as Forces
rectangle "Layered" as Layered
rectangle "Hexagonal" as Hex
rectangle "Event Driven" as Event
rectangle "Microservices" as Micro
rectangle "Pipeline" as Pipe
rectangle "Composed System" as System

Forces --> Layered : dependency control
Forces --> Hex : domain isolation
Forces --> Event : temporal decoupling
Forces --> Micro : team autonomy
Forces --> Pipe : transformation flow
Layered --> System
Hex --> System
Event --> System
Micro --> System
Pipe --> System
Architectural ForcesLayeredHexagonalEvent DrivenMicroservicesPipelineComposed Systemdependency controldomain isolationtemporal decouplingteam autonomytransformation flow

Layered and Hexagonal Thinking

Layered architecture is useful when dependency direction matters: interface layer calls application services, application services coordinate domain behavior, domain rules avoid infrastructure dependencies, and infrastructure implements persistence, messaging, and external adapters. The risk is that layers become pass-through bureaucracy or that domain logic leaks into controllers and repositories.

Hexagonal architecture sharpens the dependency rule by putting the domain and application core at the center. Ports define what the core needs or offers. Adapters translate between external technologies and those ports. This style is valuable when domain behavior must survive framework changes, external providers, or testing needs. It is less valuable when the system is mostly CRUD with little domain complexity; then strict ports may become ceremony.

Code
left to right direction
rectangle "Driving Adapters" as Driving {
rectangle "Web UI" as Web
rectangle "CLI" as CLI
}
rectangle "Application Core" as Core {
rectangle "Use Cases" as UseCases
rectangle "Domain Model" as Domain
rectangle "Ports" as Ports
}
rectangle "Driven Adapters" as Driven {
database "Database" as DB
queue "Message Broker" as Broker
rectangle "Payment Provider" as Pay
}

Web --> UseCases
CLI --> UseCases
UseCases --> Domain
UseCases --> Ports
Ports --> DB
Ports --> Broker
Ports --> Pay
Driving AdaptersApplication CoreDriven AdaptersWeb UICLIUse CasesDomain ModelPortsDatabaseMessage BrokerPayment Provider

Event-Driven Style

Event-driven architecture is powerful when facts need to be observed by multiple consumers, producers should not know every downstream workflow, or systems need replay and temporal decoupling. It changes the design vocabulary from “call this thing now” to “this fact happened.” That shift supports extensibility, but it also introduces schema governance, ordering concerns, idempotency, observability challenges, and eventual consistency.

Events should represent business facts, not database accidents. “OrderPaid” is meaningful. “PaymentRowUpdated” is a leaky implementation signal. Consumers should be able to interpret the event without depending on private producer internals. Producers should document event versioning, delivery guarantees, retention, and whether consumers may replay.

Code
left to right direction
rectangle "Order Service" as Order
queue "Event Log" as Log
rectangle "Fulfillment" as Fulfillment
rectangle "Invoicing" as Invoicing
rectangle "Customer Messaging" as Messaging
rectangle "Analytics Projection" as Analytics

Order --> Log : OrderPaid
Log --> Fulfillment : reserve and ship
Log --> Invoicing : create invoice
Log --> Messaging : send receipt
Log --> Analytics : update metrics
Order ServiceEvent LogFulfillmentInvoicingCustomer MessagingAnalytics ProjectionOrderPaidreserve and shipcreate invoicesend receiptupdate metrics

Service-Oriented and Microservice Styles

Microservices are not small classes over HTTP. They are independently deployable services aligned to business capabilities and owned by teams that can operate them. The main architectural benefit is not that services are small. It is that change, deployment, scaling, and failure can be isolated around meaningful boundaries.

The costs are real. Distributed systems require network-aware design, observability, versioned contracts, deployment automation, data ownership, incident response, and higher cognitive overhead. When these capabilities are weak, microservices can create more coordination than they remove. A senior architect asks whether the organization needs independent deployment enough to pay the operational price.

Code
left to right direction
rectangle "Capability Service" as Service {
rectangle "API Contract" as API
rectangle "Business Logic" as Logic
database "Owned Data" as Data
rectangle "Runbook and Alerts" as Ops
}
rectangle "Owning Team" as Team
rectangle "Consumers" as Consumers
rectangle "Platform" as Platform

Team --> Service : builds and operates
Consumers --> API : depend on contract
Logic --> Data : owns invariants
Service --> Platform : uses paved road
Ops --> Team : feedback
Capability ServiceAPI ContractBusiness LogicOwned DataRunbook and AlertsOwning TeamConsumersPlatformbuilds and operatesdepend on contractowns invariantsuses paved roadfeedback

Choosing and Composing Styles

Style choice should follow forces. If you need strong transactional consistency and a small team, a modular monolith may be superior. If you need multiple downstream reactions and audit replay, event-driven integration may be worth the governance overhead. If you need long-lived domain behavior insulated from infrastructure churn, ports and adapters can help. If you need independent scaling of a read-heavy capability, CQRS and materialized views may be relevant.

The best architecture descriptions often say “we use this style here, but not there.” That sentence is a sign of thoughtfulness. It avoids one-size-fits-all design and lets each part of the system pay only for the complexity it needs.

Practice

For a system you know, identify three different architectural forces. Propose one style or tactic for each force and name the cost it introduces. Then draw a hybrid architecture that uses at least two styles. The result should not be beautiful; it should be honest about where each style earns its keep.

References & Further Reading