
The Distributed Monolith Trap (And How to Escape It)
Quick takeaways Start with a monolith - don’t create microservices from day one; the overhead isn’t worth it until you have real pain points Microservices solve human problems, not just technical ones - they help teams work independently, not just scale systems Tight coupling over HTTP is still tight coupling - separating services doesn’t automatically give you isolation Watch for signals - lots of calls between services or frequent changes across multiple services suggest wrong boundaries Sometimes joining services is the answer - merging tightly coupled microservices back together can be the right move Introduction We talk about splitting software: when to do it, how to avoid common pitfalls, and why microservices aren’t always the answer.

How to Know If your Software Is Overcomplicated or Oversimplified?
Quick takeaways Complexity comes from two extremes - projects fail both when they’re overcomplicated with unnecessary patterns and when they’re oversimplified for a complex domain Essential vs accidental complexity - essential complexity comes from the domain itself and can’t be removed, accidental complexity is created by poor implementation choices “Keep it simple” is lazy advice - achieving simplicity takes effort; closing your eyes to complexity just pushes it elsewhere Match patterns to the problem - using the same approach everywhere is a red flag; mix simple solutions for simple parts and sophisticated patterns for complex domains Ship fast and iterate - if you can’t deploy daily and fear making changes, something is wrong regardless of whether it’s over or under-engineered Introduction We discuss where complexity in software projects comes from and how to deal with it.

Event-Driven Architecture: The Hard Parts
Quick takeaways Event-driven architecture (EDA) is powerful but tricky – it’s great for scaling and decoupling, but has many hidden traps. Observability is essential – debugging async systems without tracing, logs, and correlation IDs is almost impossible. Use the outbox pattern – it’s the safest way to publish events without losing data. Design events carefully – large, generic events can lead to tight coupling and painful refactors.

Synchronous vs Asynchronous Architecture
Quick takeaways Start with synchronous architecture by default - it’s simpler to understand, debug, and maintain for most use cases Async architecture improves scalability and resilience - message queues and events help handle traffic spikes and failures Design matters more than the technology choice - tight coupling creates the same problems in both sync and async approaches Consider team experience - async architecture require more experienced teams and better tooling to handle new challenges Adjust as your system grows - external APIs, heavy operations, or the need to handle failures gracefully are good use cases Hybrid approach - use both sync and async where they fit best, rather than forcing one over the other Introduction In this episode, we discuss when to choose synchronous versus asynchronous architecture for backend systems.

When to avoid DRY in Go
If you’re here for the first time, this post is part of our Business Applications in Go series. Previously, we introduced Wild Workouts, our example application built with modern tools but containing some subtle anti-patterns. We added them on purpose to show common pitfalls and how to avoid them. In this post, we begin refactoring Wild Workouts. Previous articles will give you more context, but reading them isn’t necessary to understand this one.

When using Microservices or Modular Monolith in Go can be just a detail?
Nowadays we can often hear that monolithic architecture is obsolete and responsible for all evil in IT. We often hear that microservices architecture is a silver bullet which helps to kill all this monolithic evil. But you probably know that there are almost no silver bullets in IT and every decision entails trade-offs. One of the most favored advantages of microservices architecture is good modules separation.
Series
Popular articles
- The Go libraries that never failed us: 22 libraries you need to know
- Safer Enums in Go
- Common Anti-Patterns in Go Web Applications
- How to implement Clean Architecture in Go (Golang)
- The Repository pattern in Go: a painless way to simplify your service logic
- Introduction to DDD Lite: When microservices in Go are not enough
Tags
- go
- golang
- watermill
- ddd
- events
- software-development
- domain-driven design
- event-driven
- clean-architecture
- web-applications
- anti-patterns
- architecture
- ci
- firestore
- cloudrun
- gcloud
- googlecloud
- microservices
- serverless
- testing
- advanced
- backend
- databases
- devops
- firebase
- gitlab
- reactive
- repository
- ai
- basics
- building-business-applications
- building-in-public
- cqrs
- frameworks
- kafka
- mysql
- nats
- pipelines
- scalability
- software-architecture
- transactions
- agents
- amqp
- authentication
- balance
- bounded-context
- c4
- cicd
- code-quality
- code-review
- complexity
- design-patterns
- development-process
- diagrams
- docker
- dry
- e-book
- efficiency
- enums
- event-storming
- gamedev
- generics
- google-cloud
- grpc
- htmx
- intermediate
- iteration
- javascript
- learning
- libraries
- llm
- metrics
- modular-monolith
- monolith
- open-source
- openapi
- over-engineering
- overengineering
- parallelism
- product-engineering
- productivity
- programming-languages
- prometheus
- pull-requests
- python
- rabbitmq
- retrospective
- security
- software-design
- sql
- sse
- startups
- strategic-ddd
- swagger
- terraform
- tips
- unpopular-opinions
- versioning
- work-culture