Loose Coupling

Anti-pattern: The Distributed Monolith

Avoid splitting your application into microservices before you understand the boundaries.

Tactic: Deploy loosely coupled modules.

DRY introduces coupling

Anti-pattern: Over-Coupling Through “Don’t Repeat Yourself”

Adhering strictly to DRY can lead to strong coupling.

Tactic: Being DRY in Go

A Single Model Couples Your Application

Anti-pattern: The Single Model

In web applications, the views your API returns (read models) are not the same thing you store in the database (write models).

  • Don’t give a single model more than one responsibility.
  • Don’t use more than one tag per structure field.

Tactic: One Model, One Responsibility.

  • Aim for loose coupling by using separate models.
  • Use separate models for different purposes and write clear functions to convert between them.

Generate the Boilerplate

Tactic: Generate the Repetitive Parts

  • Use generated code to ensure strong types and compile-time safety.
  • Choose it over reflect.

Don’t overuse libraries

Anti-pattern: Choosing magic to save time writing code

Don’t overuse the libraries to avoid verbosity.

Avoid implicit tag names

Anti-pattern: Omitting Structure Tags

Skipping struct tags can lead to issues if a library uses them.

Tactic: Explicit Structure Tags

  • Always fill the struct tags, even if the field names are match.

Separate Logic from Implementation Details

Validation is just one part of the business logic you find in most web applications.

  • Displaying fields only in particular cases
  • Checking permissions
  • Hiding fields depending on roles
  • Calculating total prices
  • Taking action depending on a few factors

Anti-pattern: Mixing logic and implementation details

Tactic: Application Layer

  • Dedicate a separate layer to your product’s most important code.

The Standard Go Project Structure

Anti-pattern: Overthinking the directory structure

Don’t start the project by separating directories. However you do it, it’s a convention. You’re unlikely to do it right before you’ve written any code.

Tactic: Loosely Coupled Code

  • Focus on how packages and structures reference each other, not just the directory structure.

Keeping it simple

Anti-pattern: Over-simplification

Avoid modeling complex behavior with trivial code.

Tactic: Write obvious code

  • Be explicit, even if it’s verbose.
  • Use encapsulation to ensure your structs are always in a valid state.

Starting with the database schema

Anti-pattern: Starting with the database schema

Avoid basing your models on the database schema. It causes to expose implementation details.

Tactic: Start with the domain

  • Your storage methods should follow the product’s behavior. Don’t leak transactions out of them.

Your Web Application is not a CRUD

Anti-pattern: Starting with a CRUD

Don’t design your application around the idea of four CRUD operations.

Tactic: Understand your domain

  • Spend time to understand how your product works and model it in the code.

Many of the tactics are ideas behind well-known patterns:

  • Single Responsibility Principle from SOLID (a single model responsible for one thing).
  • Clean Architecture (loosely coupled packages, separating logic from details).
  • CQRS (using different read models and write models).

Some are even close to Domain-Driven Design:

  • Value Objects (keeping structures always in a valid state).
  • Aggregate and Repository (saving domain objects transactionally regardless of the number of database tables).
  • Ubiquitous Language (using a language everyone understands).