agentsclimarketplace

Clean architecture

Skill krzysztofsurdy/code-virtuoso/skills/knowledge/clean-architecture

Skills, sub-agents, and playbooks for Claude Code, Cursor, and any Agent Skills-compatible AI coding assistant.

Install
npx -y skills add krzysztofsurdy/code-virtuoso --skill clean-architecture

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 20 stars20 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Clean Architecture, Hexagonal Architecture (Ports and Adapters), and Domain-Driven Design fundamentals. Use when the user asks to design system architecture, define layer boundaries, apply DDD tactical patterns (entities, value objects, aggregates, repositories), structure a hexagonal application, enforce dependency rules, or evaluate whether a codebase needs architectural refactoring. Covers bounded contexts, use cases, domain services, and framework-independent design.

SKILL.md

19.0 KB, as published. Nobody here has run it

Clean Architecture & DDD

Architectural patterns and tactical design techniques for building systems where business logic is isolated, testable, and independent of frameworks, databases, and delivery mechanisms. Rooted in the work of Robert C. Martin, Alistair Cockburn, and Eric Evans.

When to Use

  • The domain has meaningful business rules that deserve explicit modeling
  • The system must survive framework upgrades, database migrations, or delivery mechanism changes
  • Multiple entry points (API, CLI, message consumer, scheduled jobs) share the same business logic
  • Long-lived product where maintenance cost outweighs initial development speed
  • Team size or turnover demands clear boundaries and enforceable conventions
  • Testability is a priority — business rules must be verifiable without infrastructure

When NOT to Use

Not every system benefits from this level of architectural rigor. Avoid over-engineering when:

  • The application is a simple CRUD wrapper with no meaningful business logic
  • The project is a short-lived prototype or proof of concept
  • The team is very small and the domain is well understood with few rules
  • The overhead of layer separation exceeds the complexity of the problem
  • A simple framework-centric approach (e.g., MVC with active records) adequately serves the need

The key question: Does the domain have enough complexity to justify the investment? If the answer is no, a simpler architecture is the right choice. You can always introduce boundaries later as complexity grows.

Architecture Styles

Three well-known styles share the same core principle: dependencies point inward, and the domain sits at the center.

StyleOriginKey MetaphorDistinguishing Idea
Clean ArchitectureRobert C. Martin (2012)Concentric circlesExplicit layer names: Entity, Use Case, Interface Adapter, Framework
Hexagonal (Ports & Adapters)Alistair Cockburn (2005)Hexagon with portsSymmetry between driving (primary) and driven (secondary) adapters
Onion ArchitectureJeffrey Palermo (2008)Onion layersEmphasis on domain model at the core, infrastructure at the outer ring

What they share:

  • Domain logic at the center, free of external dependencies
  • The Dependency Rule: source code dependencies always point inward
  • Infrastructure and delivery concerns live in outer layers
  • Communication crosses boundaries through abstractions (interfaces/ports)

For practical purposes, the differences are naming conventions. The principles below apply to all three.

Ports & Adapters Concept

The Hexagonal Architecture introduces a useful vocabulary that applies across all three styles:

  • Ports are interfaces defined by the application. They describe what the application needs from the outside world (driven/secondary ports) or what the outside world can ask of the application (driving/primary ports).
  • Adapters are implementations that connect a port to a specific technology. A database adapter implements a repository port. An HTTP controller is an adapter for a driving port.
  • Driving (primary) adapters initiate interaction with the application: HTTP controllers, CLI commands, message consumers, scheduled jobs.
  • Driven (secondary) adapters are called by the application: database repositories, email senders, payment gateways, file storage.

This symmetry is powerful: the application does not know whether it is being driven by a REST API or a CLI command, and it does not know whether it is persisting to a relational database or an in-memory store.

The Dependency Rule

Source code dependencies must point inward. Nothing in an inner layer can know anything about an outer layer — no names, types, interfaces, or concepts.

This is the single most important rule. Every other guideline flows from it.

What "inward" means:

  • Inner layers define interfaces (ports); outer layers implement them
  • Data crosses boundaries as simple structures (DTOs, primitives), never as framework objects
  • The domain layer never imports from infrastructure, presentation, or application layers
  • The application layer never imports from infrastructure or presentation layers

Why it matters:

  • The domain can be tested without a database, HTTP server, or message broker
  • Frameworks become replaceable implementation details
  • Business rules are readable without understanding deployment topology

How to enforce it:

  • Use static analysis or architecture testing tools to verify import directions
  • Organize code into modules or packages that reflect layers, making violations visible
  • Code reviews should flag any inner-layer import of outer-layer types
  • The Composition Root (application entry point) is the only place that wires all layers together — it is the exception that knows about everything

Layer Reference

LayerDirectionResponsibilityWhat Belongs HereWhat Does NOT Belong
Domain (innermost)Depends on nothingBusiness rules, invariantsEntities, Value Objects, Aggregates, Domain Services, Domain Events, Repository interfacesFramework imports, database queries, HTTP concepts
ApplicationDepends on DomainUse case orchestrationApplication Services, Command/Query objects, DTOs, Port interfacesBusiness logic, direct infrastructure calls
InfrastructureDepends on Application + DomainTechnical capabilitiesRepository implementations, API clients, message queue adapters, file system accessBusiness rules, use case orchestration
Presentation (outermost)Depends on ApplicationUser/system interactionControllers, CLI commands, API endpoints, View ModelsBusiness logic, direct database access

See Layer Details for in-depth guidance on each layer.

DDD Tactical Patterns

Tactical patterns give structure to the domain layer. Each pattern has a specific role and placement within the architecture.

PatternPurposeLayerKey Rule
EntityObject with identity and lifecycleDomainIdentity determines equality
Value ObjectImmutable, identity-less conceptDomainAttribute equality, no side effects
AggregateConsistency boundaryDomainOne aggregate per transaction, reference others by ID
RepositoryCollection-like access to aggregatesInterface in Domain, implementation in InfrastructureOne repository per aggregate root
Domain ServiceStateless cross-entity logicDomainOnly when logic doesn't belong to a single entity
Domain EventRecord of something that happenedDomainNamed in past tense, immutable payload
Application ServiceUse case orchestratorApplicationNo business logic — delegates to domain objects
FactoryComplex object creationDomainEncapsulates construction invariants

See DDD Tactical Patterns for detailed guidance on each pattern.

DDD Strategic Patterns

Strategic patterns address the large-scale structure of a system — how to divide a complex domain into manageable parts and how those parts interact.

Bounded Context

A Bounded Context is a boundary within which a particular domain model is defined and consistent. Each context has its own Ubiquitous Language — the same word can mean different things in different contexts.

Identifying boundaries:

  • Different teams or departments often indicate different contexts
  • When the same term (e.g., "Account") means different things to different stakeholders, they belong in separate contexts
  • A context should be small enough for one team to own
  • Align contexts with business capabilities, not technical layers

Ubiquitous Language

Within each Bounded Context, the team (developers and domain experts) shares a precise vocabulary. Code should use this language directly — class names, method names, and variable names reflect domain concepts exactly as the domain expert would describe them.

Practical tips for maintaining Ubiquitous Language:

  • If a developer cannot explain a class name to a domain expert, the name is wrong
  • Refactor code when the language evolves — renaming is not cosmetic, it is a design activity
  • Avoid technical jargon in domain layer code — use business terms, not implementation terms
  • Document the language in a glossary shared between developers and domain experts

Context Map

A Context Map documents the relationships between Bounded Contexts. It makes integration strategies explicit rather than accidental.

PatternRelationshipWhen to Use
Shared KernelTwo contexts share a subset of the modelClosely collaborating teams willing to coordinate changes
Customer-SupplierUpstream context serves downstream contextDownstream can negotiate with upstream
ConformistDownstream conforms to upstream modelNo negotiating power; upstream won't change
Anti-Corruption LayerTranslation layer protects downstreamIntegrating with legacy or external systems
Open Host ServiceUpstream provides a well-defined protocolMultiple consumers need stable access
Published LanguageShared interchange formatCross-context communication via standard schemas

See Context Mapping for integration patterns and boundary decisions.

Anti-Corruption Layer

When integrating with external or legacy systems, an Anti-Corruption Layer (ACL) translates between the external model and the internal domain model. The ACL prevents foreign concepts from leaking into the domain.

Structure: External system -> ACL (adapter + translator) -> Domain model

The ACL belongs in the infrastructure layer and implements a port defined by the application or domain layer.

CQRS — Command Query Responsibility Segregation

CQRS is a natural companion to Clean Architecture and DDD. It separates the write model (commands) from the read model (queries), allowing each to be optimized independently.

How it fits the architecture:

  • Commands flow through the application layer, modify aggregates, and persist through repositories
  • Queries can bypass the domain layer entirely and read from optimized projections or views
  • The write side enforces business rules through the domain model
  • The read side is optimized for the consumer's needs — no need to reconstruct full aggregates for display purposes

When to consider CQRS:

  • Read and write patterns are significantly different (e.g., complex writes but simple reads, or vice versa)
  • Performance requirements differ between reads and writes
  • The read model needs denormalized views that do not map to the domain model
  • Event sourcing is in use (CQRS is nearly always paired with event sourcing)

When to avoid CQRS:

  • Simple CRUD applications where reads and writes are symmetric
  • The added complexity is not justified by the domain's needs

Event Sourcing — Brief Overview

Event Sourcing stores the state of an aggregate as a sequence of domain events rather than a current-state snapshot. The current state is derived by replaying events.

Relationship to Clean Architecture:

  • Events are part of the domain layer
  • The event store is an infrastructure concern (a specialized repository)
  • Projections (read models) are built from events in the infrastructure or application layer
  • The domain model does not depend on the event store implementation

When to consider: audit requirements, complex state transitions, temporal queries ("what was the state at time X"), or when domain events are already central to the design.

Common Misconceptions

  • "Clean Architecture means lots of boilerplate" — The layers add some structural code, but the trade-off is explicit boundaries. If the boilerplate is overwhelming, the domain may not be complex enough to justify the approach.
  • "Every application needs all four layers" — Small applications may collapse the application and presentation layers. The critical boundary is between domain and infrastructure.
  • "DTOs everywhere means Clean Architecture" — DTOs are a mechanism for crossing boundaries, not the architecture itself. The architecture is about dependency direction.
  • "The domain model must mirror the database schema" — The opposite is true. The domain model reflects business concepts. The infrastructure layer maps between the domain model and the storage schema.
  • "Hexagonal and Clean Architecture are different things" — They are different descriptions of the same core idea. Pick the vocabulary that resonates with your team.
  • "DDD requires Clean Architecture" — DDD tactical patterns can be used without strict layer separation, though they work best together. Conversely, Clean Architecture does not require DDD patterns.
  • "One bounded context = one microservice" — A bounded context is a logical boundary. It may map to a microservice, a module within a monolith, or any other deployment unit.

Common Violations

ViolationSymptomsFix
Domain depends on frameworkDomain classes import HTTP, ORM, or framework annotationsMove infrastructure concerns to outer layers; use plain objects in domain
Business logic in controllerControllers contain conditional logic, validation rules, calculationsExtract logic into domain objects or application services
Anemic domain modelEntities are data bags with only getters/setters; all logic lives in servicesPush behavior into entities and value objects; enforce invariants inside aggregates
Application service contains business rulesApplication layer has complex conditionals, domain calculationsMove rules into domain services or entity methods
Infrastructure leaking inwardDomain layer references database column names, API response shapesIntroduce mapping in infrastructure; keep domain model pure
God aggregateOne aggregate handles too many concerns, grows without limitSplit into smaller aggregates; use domain events for cross-aggregate communication
Shared database between contextsMultiple bounded contexts read/write the same tablesSeparate storage per context; integrate through events or APIs
Circular dependencies between layersInner layer imports from outer layer; compile errors or runtime couplingRe-examine which layer owns the interface; invert the dependency
DTO reuse across boundariesSame data structure used in API response, use case input, and domain logicCreate separate DTOs per boundary; map between them
Missing Anti-Corruption LayerExternal system's model pollutes the domain vocabularyAdd a translation layer in infrastructure

Testing Strategy

The layered architecture enables a clear testing strategy where each layer has a distinct testing approach:

LayerTest TypeDependenciesWhat to Verify
DomainUnit testsNone — pure logicBusiness rules, invariants, value object equality, aggregate consistency
ApplicationUnit tests with mocked portsDomain layer + mocked infrastructure portsUse case orchestration, correct domain method calls, transaction boundaries
InfrastructureIntegration testsReal external systems (database, API, queue)Correct mapping, query behavior, adapter fidelity
PresentationFunctional / acceptance testsFull stack or mocked application layerRequest parsing, response formatting, error handling, status codes

Key principle: The majority of tests should be fast domain unit tests. Infrastructure integration tests are fewer but ensure real systems behave as expected. End-to-end tests cover critical paths but should be minimal.

Quality Checklist

Use this checklist to evaluate whether the architecture is properly structured:

Dependency Rule

  • Domain layer has zero imports from application, infrastructure, or presentation layers
  • Application layer has zero imports from infrastructure or presentation layers
  • All cross-boundary communication uses interfaces/ports defined by the inner layer

Domain Layer

  • Entities enforce their own invariants — invalid state is unrepresentable
  • Value Objects are immutable
  • Aggregates are the unit of consistency — one aggregate per transaction
  • Repository interfaces are defined in the domain, not in infrastructure
  • Domain events capture meaningful state changes

Application Layer

  • Application services orchestrate but contain no business logic
  • Use cases are explicit — each has a clear input, output, and single responsibility
  • DTOs are used to cross boundaries — domain objects do not leak to outer layers

Infrastructure Layer

  • Repository implementations live here, not in the domain
  • External service integrations use adapters that implement ports
  • Framework-specific code is isolated and replaceable

Presentation Layer

  • Controllers are thin — they delegate to application services immediately
  • No business logic in controllers, views, or CLI commands
  • Input validation (format, type) happens here; business validation happens in the domain

Bounded Contexts

  • Each context has its own ubiquitous language
  • Contexts communicate through well-defined interfaces (events, APIs), not shared databases
  • Anti-Corruption Layers protect against external model pollution

Testing

  • Domain logic is testable without any infrastructure
  • Application services are testable with mocked ports
  • Infrastructure adapters have integration tests against real dependencies
  • No test requires a running framework to verify business rules

Best Practices

  • Start with the domain — model business rules first, add infrastructure later
  • Name things after domain concepts, not technical patterns (avoid SomethingManager, SomethingHelper)
  • Keep aggregates small — large aggregates are a design smell indicating misplaced boundaries
  • Prefer composition over inheritance across all layers
  • Use domain events to communicate between aggregates rather than direct coupling
  • Make invalid state unrepresentable — push validation into value objects and entity constructors
  • Keep the application layer thin — if it contains business logic, the domain layer is anemic
  • Refactor toward deeper insight — the first domain model is rarely the best one; evolve it as understanding grows
  • Apply architecture testing to enforce dependency rules automatically
  • Introduce Clean Architecture incrementally — start with the most complex subdomain and expand

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.