DDD in Golang

Cấu trúc chung của một dự án Go thiết kế theo kiểu DDD (Domain – Driven Development).

project-root/
├── cmd/ # Application entry points (e.g., main.go for server, CLI)
│ └── server/
│ └── main.go
├── internal/ # Core DDD layers, restricted to project
│ ├── domain/ # Core business logic, pure and dependency-free
│ │ ├── entities/ # Aggregates, entities, value objects
│ │ │ ├── user.go
│ │ │ └── product.go
│ │ ├── repositories/ # Repository interfaces for persistence
│ │ │ ├── user_repository.go
│ │ │ └── product_repository.go
│ │ └── events/ # Domain events (optional, for event-driven design)
│ │ └── user_created.go
│ ├── application/ # Use cases, orchestrates domain logic
│ │ ├── commands/ # Command handlers for mutating state
│ │ │ ├── create_user_command.go
│ │ │ └── create_product_command.go
│ │ ├── queries/ # Query handlers for retrieving data
│ │ │ └── find_user_by_id.go
│ │ └── services/ # Application services (optional, for complex use cases)
│ ├── infrastructure/ # Technical implementations (DB, external services)
│ │ ├── db/ # Database-related code
│ │ │ ├── models/ # DB-specific models (if needed)
│ │ │ │ ├── user_model.go
│ │ │ │ └── product_model.go
│ │ │ └── migrations/ # Schema migrations
│ │ │ ├── 000001_create_users_table.up.sql
│ │ │ └── 000001_create_users_table.down.sql
│ │ ├── repositories/ # Concrete repository implementations
│ │ │ ├── user_repository.go
│ │ │ └── product_repository.go
│ │ └── external/ # External services (e.g., APIs, message queues)
│ ├── interface/ # Adapters for external interaction (REST, gRPC, CLI)
│ │ ├── api/ # HTTP API handlers
│ │ │ ├── rest/ # REST controllers
│ │ │ │ └── user_controller.go
│ │ │ └── grpc/ # gRPC services (if used)
│ │ └── cli/ # CLI commands (if needed)
├── migrations/ # Database migrations (alternative location)
├── pkg/ # Reusable, non-DDD-specific utilities (optional)
├── tests/ # Integration or cross-layer tests
├── go.mod # Go module definition
└── README.md

Một phiên bản khác:

cmd/
    app/                # main entrypoints (wire up app, configs, deps)
        main.go
internal/
    domain/             # Core business logic (entities, value objects, interfaces)
        user/
            user.go
            repository.go
        order/
            order.go
            repository.go
    application/        # Use cases (application services, orchestrating domain logic)
        user/
            service.go
        order/
            service.go
    infrastructure/     # Adapters: DB, external APIs, messaging, logging
        persistence/
            user_repository_pg.go
            order_repository_pg.go
        http/
            router.go
            user_handler.go
            order_handler.go
    interfaces/         # (sometimes merged into infrastructure/http)
        grpc/           # gRPC handlers if used
        http/           # REST handlers
pkg/                    # Optional shared libraries (e.g. errors, utils)
db/
    migrations/          # SQL migration files (Goose, sql-migrate, etc.)

Layer responsibilities

  • Domain Layer (internal/domain/)
    • Pure business rules, independent of frameworks
    • Entities (User, Order)
    • Value objects (Email, Money)
    • Interfaces (UserRepository, OrderRepository)
  • Application Layer (internal/application/)
    • Orchestrates use cases
    • Calls domain entities & repositories
    • Contains services like RegisterUser, PlaceOrder
  • Infrastructure Layer (internal/infrastructure/)
    • Actual implementations of repositories (PostgresUserRepo)
    • External API clients
    • Logging, emailing, caching
  • Interfaces Layer (internal/interfaces/)
    • Exposes the app to the outside world
    • HTTP/REST handlers, gRPC services, CLI adapters
    • Calls application services
  • cmd/
    • Wires dependencies together (repositories → services → handlers → router)

🔹 Data flow (request cycle)

HTTP Request → Interface (Handler) → Application (Service/UseCase) → Domain (Entities + Repository Interface) → Infrastructure (Repository Implementation → DB)


🔹 Example: User registration flow

  1. Handler (interfaces/http/user_handler.go) → parses request JSON
  2. Calls UserService.Register() (application/user/service.go)
  3. Service creates a User entity (domain/user/user.go)
  4. Calls UserRepository.Save() (domain interface)
  5. Infra PgUserRepository.Save() (infrastructure/persistence/user_repository_pg.go) executes SQL

🔹 Why this structure works

  • Domain = heart → independent of frameworks/libraries
  • Application = orchestration → only coordinates, no infra logic
  • Infrastructure = details → can swap Postgres → Mongo without touching domain
  • Interfaces = delivery mechanisms → REST, gRPC, CLI

Một comment rất hay:

Some references:

https://github.com/percybolmer/ddd-go

https://github.com/sklinkert/go-ddd/issues/29

https://www.damianopetrungaro.com/posts/ddd-how-i-structure-idiomatic-golang-services/

https://github.com/damianopetrungaro/go-ddd/tree/main

https://www.damianopetrungaro.com/posts/ddd-using-golang-strategic-design/

https://www.damianopetrungaro.com/posts/ddd-using-golang-tactical-design/

(Có thể bài dưới rút gọn ddd quá mức ?)

https://programmingpercy.tech/blog/how-to-domain-driven-design-ddd-golang/

Code có 2 branches, một cho ddd và 1 cho ddd rút gọn: https://github.com/percybolmer/ddd-go

Conclusion:

  1. Xem video này: https://www.youtube.com/watch?v=6zuJXIbOyhs&t=126s&ab_channel=ProgrammingPercy

2) Hiểu cấu trúc này https://github.com/percybolmer/ddd-go

3) Áp dụng theo cấu trúc này: https://github.com/sklinkert/go-ddd

1 thought on “DDD in Golang”

Leave a Comment