software-architecture
Software architecture design from Google Principal Engineers. Use when designing folder structures, implementing Clean Architecture or Hexagonal Architecture, applying Domain-Driven Design (DDD), enfo
Files4
View on GitHubSKILL.md.claude/skills/software-architecture/SKILL.md
GitHubSoftware Architecture - Clean Code & Domain Expertise
Purpose: Design maintainable, scalable software systems using Clean Architecture, DDD, and SOLID principles
Agent: Google Software Architect Use When: Complex business logic, long-term maintainability critical, or code organization guidance needed
Quick Reference
Clean Architecture Layers
External (UI, DB, APIs)
↓
Interface Adapters (Controllers, Gateways)
↓
Use Cases (Business Workflows)
↓
Entities (Core Domain)
Dependency Rule: Dependencies point inward only
Core Concepts
1. Clean Architecture
Purpose: Separate business logic from infrastructure
Layers:
- Entities: Core business objects (no dependencies)
- Use Cases: Business workflows (depends on entities)
- Interface Adapters: Controllers, presenters (depends on use cases)
- Frameworks: UI, DB, external services (depends on adapters)
Benefits:
- ✅ Testable without UI/DB
- ✅ Framework-independent
- ✅ Easy to change infrastructure
- ✅ Business logic is clear
Example Structure:
src/
├── domain/ # Entities, value objects
├── application/ # Use cases, ports
├── infrastructure/ # Database, external APIs
└── presentation/ # Controllers, UI
2. Domain-Driven Design (DDD)
Purpose: Model complex business domains accurately
Key Concepts:
- Ubiquitous Language: Shared vocabulary
- Bounded Contexts: Logical domain boundaries
- Entities: Objects with identity
- Value Objects: Immutable, defined by attributes
- Aggregates: Consistency boundaries
- Domain Events: Things that happened
When to Use:
- Complex business rules
- Multiple teams
- Long-lived projects
- Domain experts available
Example:
// Entity
class Order {
constructor(
private id: OrderId,
private items: OrderItem[],
private status: OrderStatus
) {}
place(): void {
if (this.items.length === 0) {
throw new Error('Cannot place empty order')
}
this.status = OrderStatus.PLACED
}
}
// Value Object
class Money {
constructor(
private amount: number,
private currency: string
) {}
add(other: Money): Money {
return new Money(this.amount + other.amount, this.currency)
}
}
3. SOLID Principles
Single Responsibility: One class, one reason to change Open/Closed: Open for extension, closed for modification Liskov Substitution: Subtypes must be substitutable Interface Segregation: Many specific > one general Dependency Inversion: Depend on abstractions
4. Design Patterns
Creational:
- Factory: Create objects without specifying exact class
- Builder: Construct complex objects step by step
- Singleton: Ensure only one instance exists
Structural:
- Adapter: Make incompatible interfaces work together
- Decorator: Add behavior without modifying original
- Facade: Simplified interface to complex subsystem
Behavioral:
- Strategy: Encapsulate algorithms, make them interchangeable
- Observer: Notify dependents when state changes
- Command: Encapsulate requests as objects
Common Architecture Patterns
Hexagonal Architecture (Ports & Adapters)
┌─────────────────────────────────┐
│ Application Core │
│ (Business Logic, Use Cases) │
│ │
│ Ports (Interfaces): │
│ ├─ Input Ports (Commands) │
│ └─ Output Ports (Repositories) │
└──────────┬──────────────────────┘
│
┌──────┴──────┐
▼ ▼
Adapters Adapters
(HTTP, CLI) (Database, Email)
Benefits: Swap adapters without changing core
CQRS (Command Query Responsibility Segregation)
Commands (Write) Queries (Read)
↓ ↓
Write Model Read Model
↓ ↓
PostgreSQL Elasticsearch
When to Use: Different read/write patterns
Event-Driven Architecture
Service A → Publishes Event → Event Bus → Service B Subscribes
Benefits: Loose coupling, scalability
Folder Structure Examples
Clean Architecture (TypeScript)
src/
├── domain/
│ ├── entities/
│ │ ├── Order.ts
│ │ └── User.ts
│ ├── value-objects/
│ │ └── Money.ts
│ └── repositories/ # Interfaces
│ └── IOrderRepository.ts
│
├── application/
│ ├── use-cases/
│ │ ├── CreateOrder.ts
│ │ └── PlaceOrder.ts
│ └── ports/
│ ├── input/
│ └── output/
│
├── infrastructure/
│ ├── persistence/
│ │ ├── PostgresOrderRepository.ts
│ │ └── migrations/
│ └── external-services/
│ └── StripePaymentService.ts
│
└── presentation/
├── api/
│ ├── controllers/
│ │ └── OrderController.ts
│ └── dto/
└── web/
DDD (Python)
app/
├── domain/
│ ├── model/
│ │ ├── order.py # Aggregate
│ │ ├── order_item.py # Entity
│ │ └── money.py # Value Object
│ ├── events/
│ │ └── order_placed.py
│ └── repositories/
│ └── order_repository.py
│
├── application/
│ ├── commands/
│ │ └── create_order.py
│ └── handlers/
│ └── order_handler.py
│
└── infrastructure/
├── persistence/
│ └── sqlalchemy_order_repo.py
└── messaging/
When to Use Each Pattern
Simple CRUD App
- ✅ Keep it simple: Controllers → Services → Repositories
- ❌ Don't over-architect
- Focus: Readability
Complex Business Logic
- ✅ Clean Architecture or DDD
- ✅ Separate domain from infrastructure
- Focus: Maintainability
Microservices
- ✅ One service = one bounded context
- ✅ Event-driven communication
- Focus: Loose coupling
Legacy Refactoring
- ✅ Strangler Fig pattern
- ✅ Extract domain logic incrementally
- Focus: Gradual improvement
Anti-Patterns to Avoid
❌ Anemic Domain Model: Entities with no behavior ❌ God Objects: One class doing everything ❌ Leaky Abstractions: Domain knowing about HTTP/DB ❌ Circular Dependencies: A depends on B depends on A ❌ Over-Engineering: Using DDD for simple CRUD
Best Practices
- Start Simple: Don't over-architect MVPs
- Evolve Architecture: Refactor as complexity grows
- Test First: If hard to test, architecture is wrong
- Domain First: Model business before infrastructure
- Pragmatic: Balance purity with practicality
Philosophy: "Make it work, make it right, make it fast" - in that order.
Remember: Architecture serves the business, not the other way around.
Created: 2026-02-04 Maintained By: Google Software Architect