Instruction file imported from cdalsoniii/brightpath-coder (
.github/instructions/architecture-design-standards.instructions.md). Copyright stays with the author.
Architecture and Design Standards
Design Principles
Simplicity and Modularity
- Follow the KISS principle (Keep It Simple, Stupid)
- Apply DRY (Don't Repeat Yourself) to avoid code duplication
- Practice YAGNI (You Ain't Gonna Need It) - avoid premature features
- Design modules with single, well-defined responsibilities
- Keep functions and classes small and focused
SOLID Principles
- Single Responsibility: Each class/module has one reason to change
- Open/Closed: Open for extension, closed for modification
- Liskov Substitution: Subtypes must be substitutable for base types
- Interface Segregation: Many specific interfaces over one general interface
- Dependency Inversion: Depend on abstractions, not concretions
Separation of Concerns
- Separate business logic from infrastructure code
- Isolate data access from business rules
- Keep presentation logic separate from domain logic
- Use layered architecture (presentation, business, data access)
- Maintain clear boundaries between modules
Scalability and Maintainability
Design for Scale
- Design systems to scale horizontally from day one
- Avoid shared mutable state across instances
- Use stateless services where possible
- Implement caching strategies at multiple levels
- Plan for distributed deployment scenarios
Microservices Considerations
- Use microservices for complex domains with clear boundaries
- Apply domain-driven design to identify service boundaries
- Keep services loosely coupled and highly cohesive
- Design for failure with circuit breakers and fallbacks
- Implement API gateways for cross-cutting concerns
Maintainability
- Write self-documenting code with clear naming
- Keep cognitive complexity low (cyclomatic complexity < 15)
- Minimize dependencies between modules
- Use dependency injection for testability
- Refactor continuously to reduce technical debt
API and Interface Design
API Specifications
- Define API contracts using OpenAPI/Swagger specifications
- Establish API standards early (REST, GraphQL, gRPC)
- Version APIs from the start (e.g., /v1/, /v2/)
- Document all endpoints, parameters, and responses
- Include authentication and authorization requirements
Interface Contracts
- Use interfaces to define contracts between components
- Specify input/output formats explicitly
- Include error response formats in contracts
- Document expected behavior and constraints
- Use contract testing to verify implementations
API Design Best Practices
- Use appropriate HTTP methods (GET, POST, PUT, DELETE, PATCH)
- Return meaningful HTTP status codes
- Include error messages with actionable guidance
- Implement pagination for list endpoints
- Support filtering, sorting, and searching where appropriate
- Use HATEOAS for discoverability (when using REST)
Infrastructure as Code
Environment Parity
- Keep development, staging, and production environments aligned
- Use identical technology stacks across environments
- Automate environment provisioning
- Document environment differences explicitly
- Test in production-like environments
Infrastructure Tools
- Use Terraform, Pulumi, or CloudFormation for infrastructure
- Store infrastructure code in version control
- Use Docker for consistent runtime environments
- Implement infrastructure testing (Terratest, InSpec)
- Document infrastructure architecture with diagrams
Configuration Management
- Externalize configuration from code
- Use environment variables for environment-specific settings
- Store secrets securely (Vault, AWS Secrets Manager, Azure Key Vault)
- Version configuration files
- Validate configuration at startup
Domain-Driven Design
Bounded Contexts
- Identify bounded contexts within the domain
- Define clear boundaries and interfaces between contexts
- Use ubiquitous language within each context
- Map relationships between contexts
- Avoid tight coupling across contexts
Domain Models
- Design rich domain models that encapsulate business logic
- Use entities for objects with identity
- Use value objects for immutable concepts
- Define aggregates with clear boundaries
- Implement domain events for cross-aggregate communication
Layered Architecture
- Presentation Layer: User interface and API controllers
- Application Layer: Orchestration and use cases
- Domain Layer: Business logic and domain models
- Infrastructure Layer: Data persistence and external services
Coupling and Cohesion
Low Coupling
- Minimize dependencies between modules
- Use interfaces to decouple implementations
- Avoid circular dependencies
- Prefer composition over inheritance
- Use events for decoupled communication
High Cohesion
- Group related functionality together
- Keep modules focused on single responsibilities
- Place code close to where it's used
- Avoid mixing concerns in the same module
- Organize by feature/domain, not by type
Architectural Patterns
Common Patterns
- Layered Architecture: Organize by technical concerns
- Hexagonal/Ports & Adapters: Isolate core logic from infrastructure
- Event-Driven: Decouple components via asynchronous events
- CQRS: Separate read and write models
- Event Sourcing: Store state as sequence of events
- Saga Pattern: Manage distributed transactions
Pattern Selection
- Choose patterns based on problem requirements
- Avoid pattern overuse (keep it simple)
- Document pattern usage and rationale
- Be consistent within project/team
- Consider team expertise when selecting patterns
Architectural Decision Records (ADRs)
Decision Documentation
- Document all significant architectural decisions
- Include context, decision, and consequences
- Use a consistent ADR template
- Store ADRs in version control
- Review ADRs during architecture reviews
ADR Template
# ADR-XXX: [Title]
## Status
[Proposed | Accepted | Deprecated | Superseded]
## Context
[What is the issue we're trying to address?]
## Decision
[What is the change we're making?]
## Consequences
[What becomes easier or harder as a result?]
## Alternatives Considered
[What other options did we consider?]
Architecture Reviews
Review Process
- Conduct architecture reviews for significant changes
- Include cross-functional stakeholders
- Review against non-functional requirements
- Document feedback and decisions
- Re-review periodically (annually)
Review Checklist
- Alignment with business objectives
- Scalability and performance considerations
- Security and compliance requirements
- Maintainability and technical debt
- Operational complexity
- Cost implications
- Team capabilities and skills
Non-Functional Requirements
Define NFRs Early
- Performance: Response times, throughput
- Scalability: User load, data volume
- Availability: Uptime targets (SLOs)
- Security: Authentication, authorization, encryption
- Reliability: Error rates, recovery time
- Maintainability: Code quality, testability
- Usability: User experience, accessibility
Measure and Monitor
- Establish baselines for all NFRs
- Monitor metrics continuously
- Set alerts for threshold violations
- Review NFRs in architecture decisions
- Update NFRs as requirements evolve
Technology Selection
Evaluation Criteria
- Alignment with project requirements
- Team expertise and learning curve
- Community support and ecosystem
- Performance characteristics
- Security track record
- Licensing and cost
- Long-term viability and maintenance
Standardization
- Maintain approved technology stack
- Document rationale for technology choices
- Avoid technology proliferation
- Evaluate new technologies through pilots
- Keep technologies up to date