3 minutes
Common Anti-Patterns in Go Web Applications
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).