[Go] Gophercon 2024 - Go Project Guide A-Z

Small Projects

  • Low traffic → Limited user base
  • Simple functionality → Undefined user states in new services
  • Need for rapid development → Early feature experimentation required for hypothesis validation

For a Simple CLI Tool


For a Simple API Server

Take a minimalistic approach using standard libraries to build and expand APIs incrementally.


Feature-Oriented Project Patterns

Using Handler Struct (Class-based DI)

Pass required parameters for each method via function inputs:

Injecting Dependencies via HTTP HandlerFunc

Use closures internally to capture dependencies. This design is clean, allows for scoped dependency injection, and is highly testable.

TypeAdvantagesWhen to Use
Handler- Easier management of complex state- Clearly structured dependencies- Easy to extend- Good for interface implementation- Helps organize complex logicComplex business logic, many dependencies, stateful apps
HandlerFunc- Quick to write- Simple DI with closures- Functional composition- Ideal for prototyping- Easy mocking for testingSimple handlers, small apps, microservices

Code Pattern for Enterprise-Scale Services

Apply a Layered Architecture:

Layer Breakdown

  • Presenter = Converts between Domain Model and API Model
  • Handler = Serves API Models
    • Handles HTTP/gRPC requests and responses
    • Clearly separates presentation from application logic
  • Usecase = Executes business logic
    • Depends on Services or Repositories
    • Avoids using API or DB-specific models, focusing on domain logic
  • (Service) = Implements complex business logic
    • Extracted when Usecases become complex or involve multiple dependencies
    • Usecases orchestrate; Services execute logic (similar to xxxExecutor pattern)
  • Repository = Manages CRUD for domain models
    • Encapsulates data access logic
    • Inverts dependency: Repositories return domain models and depend on domain layer
  • (Recorder) = Manages DB-specific models
    • Used for handling NoSQL/RDBMS-specific logic
    • Enables DB migrations by swapping out recorder DI

Test Code per Layer

Use the mocking library counterfeiter.

FeatureGo MockeryCounterfeiter
Mock CreationEasy auto-generation with argsFake objects allow for advanced simulation
Setup EaseSimple and intuitiveIdeal for complex test scenarios
Test MaintainabilityBest for simple interfacesLong-term test stability with fake objects
Best Use CaseIsolated module testingComplex logic and varied response scenarios

Fake mocks are usually stored within the same layer they belong to.


Closing Thoughts

  • While Go’s ecosystem has experimented with many structural approaches, no clear standard has emerged. This pattern seems highly practical.
  • Concern: Does a layered architecture cause unnecessary data structure conversions? (e.g., Presentation, Business, Data layers could each use separate structs for a single API)
  • Service vs. Usecase? Seems to hinge on whether multiple services are involved.
  • On APM: What about cost? → APM isn’t applied globally. It is only used for business-critical logic.