Skip to main content

Architecture Design

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendix

Introduction

This document is designed for architects and senior developers, systematically explaining how the Sparrow framework implements "Clean Architecture" at the code level. By clarifying the responsibility boundaries and interaction relationships between the application layer, adapter layer, domain layer, and infrastructure layer, it explains the dependency inversion principle, layered design, and modular implementation, providing technical considerations, trade-offs, and extensibility design recommendations for architectural decisions. The document includes multiple architecture and class diagrams to help readers quickly grasp the system overview.

Project Structure

Sparrow adopts a directory organization layered by "concerns", combined with Go modular features, forming clear layered boundaries:

  • Domain Layer (entity): Carries business entities and aggregate roots, defines business invariants and behavioral contracts
  • Use Case Layer (usecase): Encapsulates business use cases and process orchestration, defines repository interfaces and generic query models
  • Adapter Layer (adapter): HTTP routing and handlers, middleware, projections/Saga and other external adapters
  • Infrastructure Layer (bootstrap, config, persistence, messaging, tasks, etc.): Provides runtime environment, configuration, persistence, message bus, task scheduling and other support capabilities

Diagram Sources

Core Components

Application Entry and Container

  • App: Global application object, responsible for configuration loading, logging initialization, HTTP server startup, subprocess lifecycle management, event bus/message bus integration, task scheduler integration
  • Container: Lightweight IoC container, supports anonymous and named dependency registration and resolution, implements dependency injection and singleton caching

Domain Model

  • BaseEntity: Unified entity base class, provides standard fields and timestamps
  • AggregateRoot: Aggregate root interface, defines core contracts such as event sourcing, version control, business validation
  • Task: Task entity, embodies domain layer business objects

Use Cases and Repositories

  • Repository[T]: Use case layer's abstract interface for persistence
  • BaseRepository[T]: Repository generic implementation skeleton, provides default errors and query option tools
  • SessionService: Session management use case, encapsulates business rules and repository interaction

Infrastructure

  • Config: Centralized configuration structure, covers server, logging, database, cache, message middleware, etc.
  • SqlDBRepository[T]: Generic repository implementation based on database/sql, supports soft delete, transactions, conditional queries, pagination, random sampling, etc.
  • StreamHub: Event stream bus based on NATS JetStream, supports subscription, graceful shutdown and startup
  • TaskScheduler: Task scheduler interface, abstracts task scheduling, cancellation, status query and lifecycle management

Architecture Overview

Sparrow's clean architecture is centered on "dependency inversion": upper layers (application layer, adapter layer) only depend on abstractions (interfaces), lower layers (infrastructure layer) implement these abstractions; domain layer is independent of technical details, only exposes interfaces for use case layer consumption. The diagram below shows key components and dependency directions:

Diagram Sources

Detailed Component Analysis

Dependency Injection and Container (IoC)

Design Points:

  • Supports anonymous and named provider registration, prioritizes named matches during resolution, otherwise falls back to anonymous
  • Constructor parameters resolve dependencies by type, automatically caches first resolution result (singleton)
  • Provides convenient resolution by name and instance injection methods

Collaboration with Application Layer:

  • App registers and resolves global services through Container (such as NATS connection, event publisher, task service, etc.)
  • Use case layer obtains repositories, session services and other dependencies through App's resolution methods

Diagram Sources

Domain Layer: Entity and Aggregate Root

  • BaseEntity: Unified entity identifier and timestamp fields, provides consistent lifecycle management for all entities
  • AggregateRoot: Defines interfaces that aggregate roots must implement, including version control, event sourcing (command handling, event application, uncommitted event management), rebuilding state from event stream/snapshot, business validation, etc.
  • Task: Task entity, encapsulates task state machine and retry logic, embodies domain layer business invariants

Diagram Sources

Use Case Layer: Repository and Service

  • Repository[T]: Defines unified abstraction for use case layer persistence, covers CRUD, batch operations, pagination, conditional queries, random sampling, etc.
  • BaseRepository[T]: Provides default implementation skeleton, unified error wrapping, query option building, field validation, etc., concrete database implementations only need to focus on SQL construction and scanning
  • SessionService: Session management use case, combines repository interface, encapsulates business rules (expiration check, auto-renewal, data read/write)

Diagram Sources

Infrastructure Layer: Configuration, Persistence, and Messaging

  • Config: Centralized configuration structure, provides default values and configuration items for each subsystem (server, logging, database, cache, message middleware, permissions, etc.)
  • SqlDBRepository[T]: Generic repository implementation based on database/sql, supports soft delete, transactions, conditional/sorting/pagination, random sampling, batch operations, etc.
  • StreamHub: Event stream bus based on NATS JetStream, encapsulates subscription, startup/shutdown, event handler registration, etc.
  • App: Integrates configuration, container, logging, HTTP server, message bus, task scheduler, provides unified startup/shutdown process and retry mechanism

Diagram Sources

Task Scheduling

  • TaskScheduler: Abstract task scheduler interface, supports scheduling, cancellation, status query, concurrent limit setting, startup/shutdown/graceful shutdown
  • App: Provides task scheduler integration point, convenient for registering and managing task executors during application startup phase

Diagram Sources

Dependency Analysis

Dependency Direction

  • Upper layers (adapters, use cases) only depend on abstractions (interfaces)
  • Lower layers (infrastructure) implement abstractions (concrete repositories, message buses, task schedulers)
  • Domain layer does not depend on any technical details, only exposes interfaces for use case layer

Coupling and Cohesion

  • Through interface segregation and dependency injection, reduces coupling between modules
  • Use case layer and repository interface separation, convenient for replacing different storage implementations

Circular Dependencies

  • Through interfaces and container decoupling, avoids direct circular references

External Dependencies

  • Through go.mod clearly defines third-party library scope, infrastructure layer adapts around these libraries

Diagram Sources

Performance Considerations

Repository Layer

  • Transactions and Batch Operations: SqlDBRepository uses transactions for batch save/delete operations, reduces round-trip overhead
  • Conditional Queries and Pagination: Supports multi-condition, sorting, pagination, avoids loading all data at once
  • Soft Delete: Implements soft delete through deleted_at field, balances auditing and performance

Task Scheduling

  • Concurrent and Sequential: Two scheduler types, can choose execution mode based on task characteristics
  • Supports Maximum Concurrency Limit: Prevents resource contention

Logging and Configuration

  • Centralized Configuration and Pluggable Logging: Convenient for adjusting performance-related parameters in production environment

Troubleshooting Guide

Startup and Retry

  • App provides subprocess exponential backoff retry mechanism, maximum retry count and wait limit are controllable
  • Graceful Shutdown: Unified shutdown process and timeout control, ensures resource release

Repository Errors

  • BaseRepository uniformly wraps common errors like empty ID, empty fields, convenient for problem location
  • SqlDBRepository classifies and handles query exceptions (such as not found, transaction rollback, etc.)

Session Service

  • Expiration check and auto-cleanup, avoids dirty data affecting business

Message Bus

  • StreamHub supports subscriber startup/shutdown, convenient for enabling/disabling event handling during debugging

Conclusion

Sparrow decouples business logic from technical implementation through clean architecture and dependency inversion, forming a high-cohesion, low-coupling layered system. Use case layer abstracts repositories through interfaces, domain layer focuses on business invariants, infrastructure layer provides replaceable implementations, adapter layer handles external interactions. Combined with IoC container, centralized configuration and task/messaging infrastructure, the system has good extensibility and maintainability. It is recommended to follow the principle of "upper layers depend on abstractions, lower layers implement abstractions" when extending new features, continuously maintaining architectural clarity.

Appendix

Key Process Diagram (Startup and Event Subscription)

Diagram Sources