
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.

Unpopular opinions about Go
Quick takeaways Simplicity isn’t enough for complex applications - while Go’s syntax is simple, complex applications still need proper design patterns; primitive code easily becomes spaghetti code in large projects. Reading the standard library isn’t the best way to learn Go - it’s optimized for different goals than typical applications and might be confusing for beginners. Router libraries are better than the standard HTTP package - libraries like Chi or Echo come with a nice high-level API.

When it’s worth to write low-quality code
Quick Takeaways High-quality code is mainly about keeping good iteration speed over time - can you add features without breaking what works? Not all code needs to be high quality - focus your efforts on the code that’s most important, changes often, or creates the most value. The right time to refactor is after you know your product has value, but before technical debt gets too big - make small improvements bit by bit.
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
- clean-architecture
- domain-driven design
- events
- web-applications
- anti-patterns
- event-driven
- ci
- firestore
- architecture
- cloudrun
- gcloud
- googlecloud
- serverless
- software-development
- testing
- advanced
- databases
- devops
- firebase
- gitlab
- microservices
- reactive
- repository
- backend
- basics
- building-business-applications
- building-in-public
- cqrs
- frameworks
- kafka
- mysql
- nats
- pipelines
- scalability
- software-architecture
- transactions
- amqp
- authentication
- balance
- bounded-context
- c4
- cicd
- code-quality
- design-patterns
- diagrams
- docker
- dry
- e-book
- efficiency
- enums
- event-storming
- gamedev
- generics
- google-cloud
- grpc
- htmx
- intermediate
- iteration
- javascript
- learning
- libraries
- maintainability
- metrics
- monolith
- open-source
- openapi
- over-engineering
- overengineering
- parallelism
- productivity
- programming-languages
- prometheus
- python
- rabbitmq
- retrospective
- security
- sql
- sse
- startups
- strategic-ddd
- swagger
- terraform
- tips
- unpopular-opinions
- versioning