Based on nearly 20 years of working together on various projects, we discuss when it makes sense to move fast rather than aim for perfect code, and how to avoid technical debt that can kill your project.
We focus on making mindful engineering decisions instead of blindly following rules like “always do X” or “never do Y”. Different situations need different approaches to code quality.
The Distributed Monolith Trap (And How to Escape It)
Industry experts discuss the complexities of splitting software, emphasizing team organization and boundary maintenance over technology, and caution against blindly adopting microservices without considering underlying problems.
19 Dec 2025TRANSCRIPT
How to Know If your Software Is Overcomplicated or Oversimplified?
This episode explores the origins of complexity in software projects, distinguishing between essential and accidental complexity, and provides diagnostic signals for identifying unhealthy projects and matching tools to the problem.
10 Dec 2025TRANSCRIPT
DDD: A Toolbox, Not a Religion
This episode explores Domain-Driven Design as a practical toolbox for tackling domain complexity in software projects, advocating for pragmatic pattern selection to address real-world problems.
26 Nov 2025
Becoming a Product Engineer: First Steps
Industry experts explore the disparity between software project delivery speed in personal versus professional settings, emphasizing the importance of developer involvement in product decisions and collaborative techniques like Event Storming.
25 Nov 2025TRANSCRIPT
Season 2 Trailer
The podcast "No Silver Bullet" announces its return after a summer break, promising new episodes every second Wednesday.
3 Jul 2025TRANSCRIPT
AMA #1: Go and AI, Clean Architecture, Learning, Event-Driven
Industry experts discuss Go's role in AI development, clean architecture implementation, career transitions, and distributed systems, offering insights into modern software development practices in this community question and answer episode.
26 Jun 2025TRANSCRIPT
How to Create PRs That Get Merged The Same Day
Industry experts discuss strategies for achieving rapid code review cycles by creating small, manageable pull requests that facilitate quick integration and improve team knowledge sharing.
5 Jun 2025TRANSCRIPT
Event Driven Architecture: The Hard Parts
This episode explores the complexities of event-driven architecture, highlighting the importance of observability, the outbox pattern, careful event design, and avoiding over-engineering for scalable and decoupled systems.
29 May 2025TRANSCRIPT
Synchronous vs Asynchronous Architecture
This episode explores synchronous and asynchronous architectures for backend systems, weighing trade-offs between simplicity and resilience, and focusing on understanding when each approach makes sense.
15 May 2025TRANSCRIPT
Watermill: from a hobby project to 8k stars on GitHub
Episode notes: http://threedots.tech/episode/history-of-watermill/
Quick takeaways
Solve real problems first - successful open source projects start by addressing actual needs, not by looking for problems to fit a solution
Keep breaking changes minimal - Watermill stayed on v1 for 6 years with no breaking changes in the core library, building trust with users
Examples and documentation are crucial - provide real-world examples with automated tests, not just simple “hello world” demos
Promotion matters - creating a great library isn’t enough; you need to actively share it through conferences, blog posts, and communities
Be patient with growth - Watermill took 7 years to reach 8,000 stars; overnight success in open source is rare
In this episode, we share the story of how Watermill, our event-driven library for Go, grew from a side project to a popular open source library with over 8,000 GitHub stars and 100+ contributors.
We discuss the key decisions and strategies that helped make Watermill successful, from focusing on solving real problems to maintaining backward compatibility and building a community around the project.
Watermill documentation (https://watermill.io/) — our open-source event-driven architecture library for Go
Watermill repository (https://github.com/ThreeDotsLabs/watermill)
Go Event-Driven (https://threedots.tech/event-driven/) training that complements Watermill
Real World Examples (https://github.com/ThreeDotsLabs/watermill/tree/master/_examples/real-world-examples)
1 May 2025TRANSCRIPT
Unpopular opinions about Go
Full episode notes: https://threedots.tech/episode/unpopular-opinions-about-go/ (https://threedots.tech/episode/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.
Struct-based configuration is better than the “optional pattern” - structs are easier to document, discover, and maintain than the popular With-options approach.
There’s no one best project structure - starting small and evolving your structure as needed is better than following a dogmatic approach like the unofficial “Go project layout.”
Writing stubs by hand is better than using mocking libraries - manually written stubs are easier to debug and encourage better interfaces than reflection-based mocking libraries.
Code generation is better than reflect - for ORMs or dependency injection, it gives you compile-time checks and better performance.
Generics are mostly useful for libraries, not application code - while everyone waited for them, they’re rarely needed in typical service-level code.
Channels and goroutines can be overused - they add complexity and should only be used when concurrency is actually needed, not as a default approach.
Go’s error handling is fine for most projects - explicit checks make code easier to read, though built-in stack traces would be helpful.
Memory optimizations are often premature - micro-optimizations waste time for typical API services where network latency is the bottleneck.
In this episode of No Silver Bullet, we share some of our unpopular takes on the Go programming language. After working with Go for eight years on all kinds of projects, we’ve seen many discussions about what idiomatic Go means. We talk about what worked for us, but we keep in mind that different projects have different needs. We question some common Go beliefs and share tips we’ve picked up along the way.
Links:
Wild Workouts (https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example) - Our example Go project that shows a more complex application structure
Watermill (https://github.com/ThreeDotsLabs/watermill) - Our Event-driven application library for Go
HTTP Routers we recommend: Chi (https://github.com/go-chi/chi) and Echo (https://github.com/labstack/echo)
Go in One Evening (https://threedots.tech/go-in-one-evening/) - Our hands-on Training for learning Go quickly
Clean Architecture episode (https://preview-475-podcast-5-live--priceless-kepler-1faae3.netlify.app/episode/is-clean-architecture-overengineering/) - Previous episode that goes deeper into project organization
Go Developer Survey Results (https://go.dev/blog/survey2024-h2-results) - Shows that ~75% of Go developers build API/RPC services
Google’s Go Style Guide (https://google.github.io/styleguide/go/index) - Many useful ideas, but be careful about being too dogmatic about it
17 Apr 2025TRANSCRIPT
Learning Software Skills fast: what worked for us best in the last 15 years
In this episode, we discuss how to learn effectively as a software engineer. Why some people seem to learn faster than others? What are some practical ways to speed up your learning? Instead of promising magical shortcuts to becoming a principal engineer in months, we focus on a more balanced approach that helps you build skills by mixing theory with practice.
Quick takeaways
Focus on applying what you learn - reading books or watching videos isn’t enough without practice
Build real projects that challenge you - trivial examples don’t expose you to the hidden complexities you’ll face in actual work
Expect and embrace frustration - feeling stuck often means you’re learning something valuable
Learn timeless concepts over framework-specific details - aim for universal software skills like modularization
Mix theory with practice in small chunks - read a bit and code a bit, rather than consuming large amounts of content at once
Notes
We mentioned our learning platform (https://threedots.tech/learn)
Domain-Driven Design was referenced throughout - check “Implementing Domain-Driven Design” by Vaughn Vernon
Watermill - our open-source library mentioned as an example of a project that taught us while helping others: github.com/ThreeDotsLabs/watermill (https://github.com/ThreeDotsLabs/watermill)
Event-Driven Architecture traces back to 1950s, but was formalized about 20 years ago
The Repository pattern blog post (https://threedots.tech/post/repository-pattern-in-go)
Full episode notes and transcript: http://threedots.tech/episode/learning-software-skills-fast/
3 Apr 2025TRANSCRIPT
Is Clean Architecture Overengineering?
In this episode of the No Silver Bullet podcast, we discuss Clean Architecture and whether it's overengineering or a best practice for organizing code.We talk about why the pattern is often controversial, when it makes sense to use it, and how to implement it effectively.We share our experiences using Clean Architecture across different projects and teams, including the common concerns developers have when first seeing it.
Quick takeaways:
Clean Architecture is most beneficial for complex projects with larger teams - for small teams or simple projects, it can become overengineering.
Separation of concerns is the core benefit - keeping domain logic separate from implementation details makes code more maintainable.
It's easy to go too far - using too many interfaces or too many layers without a clear reason creates unnecessary complexity.
Start simple and evolve your architecture - don't force Clean Architecture from the start if your project doesn't need it yet.
Understanding the "why" behind the pattern is crucial - blindly following it without understanding leads to poor implementations.
Notes:
Related patterns:
The Dependency Inversion Principle: one of SOLID principles.
Blog post: Introducing Clean Architecture: https://threedots.tech/post/introducing-clean-architecture/ (https://threedots.tech/post/introducing-clean-architecture/)
Blog post: Microservices test architecture: https://threedots.tech/post/microservices-test-architecture/ (https://threedots.tech/post/microservices-test-architecture/)
Blog post: Repository Pattern in Go: https://threedots.tech/post/repository-pattern-in-go/ (https://threedots.tech/post/repository-pattern-in-go/)
Blog post: Combining DDD, CQRS, and Clean Architecture in Go: https://threedots.tech/post/ddd-cqrs-clean-architecture-combined/ (https://threedots.tech/post/ddd-cqrs-clean-architecture-combined/) (Mentioned as available)
Example Go Project: Wild Workouts: https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example (https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example)
go-cleanarch Linter: https://github.com/roblaszczak/go-cleanarch (https://github.com/roblaszczak/go-cleanarch)
Full episode notes: https://threedots.tech/episode/is-clean-architecture-overengineering/
3 Apr 2025TRANSCRIPT
When you shouldn’t use frameworks in Go
Quick takeaways
Frameworks promise productivity but often lead to issues as projects get larger and more complex.
The Go community prefers small, focused libraries over frameworks due to Go's design philosophy influenced by Unix principles.
Watch out for risks using frameworks like vendor lock-in, deprecation, and costly migrations that can take months.
Explicit code is more maintainable than magic framework abstractions.
Choose your approach based on project size and maturity - frameworks might work for prototypes, while modular libraries are better for long-term projects.
Introduction
In this episode of the No Silver Bullet podcast, we discuss frameworks in Go and when they're useful or problematic.We talk about why the Go community generally avoids frameworks compared to other languages, and how small, modular libraries are often preferred in Go development.
We share our experiences with frameworks across different projects, including tradeoffs between productivity and long-term maintenance.
Notes
Model-View-Controller (MVC): Pattern first described in the 1970s for Smalltalk, still widely used today.
Unix Philosophy: https://en.wikipedia.org/wiki/Unix_philosophy (https://en.wikipedia.org/wiki/Unix_philosophy): design concept created by Ken Thompson (also a Go creator) promoting small programs that do one thing well and work together.
When to avoid DRY in Go: https://threedots.tech/post/things-to-know-about-dry/ (https://threedots.tech/post/things-to-know-about-dry/)
Watermill: https://watermill.io (https://watermill.io): Our event-driven library for Go designed to not be a framework.
Repository Pattern: https://threedots.tech/post/repository-pattern-in-go/ (https://threedots.tech/post/repository-pattern-in-go/): Our blog post that is still relevant and frequently referenced.
tdl: https://github.com/ThreeDotsLabs/cli (https://github.com/ThreeDotsLabs/cli) and pq: https://github.com/ThreeDotsLabs/watermill/tree/master/tools/pq (https://github.com/ThreeDotsLabs/watermill/tree/master/tools/pq) - the CLI tools we mentioned.
Clean Architecture: https://threedots.tech/post/introducing-clean-architecture/ (https://threedots.tech/post/introducing-clean-architecture/): The topic of our next podcast episode, a design approach that helps maintain separation of concerns.
Wild Workouts: https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example (https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example) : Our example Go codebase demonstrating clean architecture.
The Best Go framework: no framework?: https://threedots.tech/post/best-go-framework/ (https://threedots.tech/post/best-go-framework/)
Quotes
The happy path is easy enough, but the happy path is usually not the hard part of software. We often overvalue how much effort the boilerplate requires. - Miłosz
Framework knowledge tends to become out of date. You can spend days or weeks learning something about a framework, but it can be outdated. And if you switch to another programming language or company, a lot of effort that you spent to learn stuff will be just wasted. - Robert
It's more important to learn even-driven architecture because you learn the theory behind it and how it works in general - it transfers better to whatever you will do later. Focus on timeless skills like how to split modules in your application, how to make it decoupled, how to write business logic so it's easy to read and modify. - Miłosz
The Go language is heavily influenced by Unix philosophy - write programs that do one thing and do it well, write programs that work together. It's visible in Go's standard library. This is why Go promotes building independent components that you can connect together. - Robert
You need to be careful not to go too far with foundations. It's better to start with some modular libraries, have some reasonable setup in place, but don't go too crazy with it. Most of the time you'll need to refactor the project anyway, whatever you do, because it can change drastically. - Miłosz
One big decision at the beginning may cost you six months of work later. Understanding if something is tightly coupled to your application is simple - just think about how easy it would be to remove it. - Robert
Full episode notes: https://threedots.tech/episode/when-you-should-not-use-frameworks/
3 Apr 2025TRANSCRIPT
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.
Architecture decisions need more thought than other code quality factors since they're hardest to change later - ask "how hard would this be to remove?"
Balance between MVP and quality depends on your situation - for experiments, cut corners on purpose; for critical systems or enterprise products, focus on quality from the start.
Introduction
In the first episode of No Silver Bullet live podcast, we talk about the balance between writing high-quality code and taking shortcuts.
Based on nearly 20 years of working together on various projects, we discuss when it makes sense to move fast rather than aim for perfect code, and how to avoid technical debt that can kill your project.
We focus on making mindful engineering decisions instead of blindly following rules like "always do X" or "never do Y".Different situations need different approaches to code quality.
Notes
"No Silver Bullet": The classic 1986 paper by Fred Brooks that our podcast name references, discussing how there's no single development that will solve all software engineering challenges.
Our Learning Platform: /learn: The project we discussed that started as an MVP and was later refactored
Architecture Patterns:
Pareto Principle: The 80/20 rule we mentioned - often 20% of the code creates 80% of the value
Future Episodes:
Development Practices:
Quotes
Quality is not about some kind of elegance of code because it's just an artificial thing. It's not really helpful for your team if it's pretty. - Miłosz
Often you have in the code places that you don't touch often or it's not earning a lot of money... Ask what are the places that we're changing the most often? What are the places that are creating most of the value? - Robert
I remember one project when we started applying Domain-Driven Design... Everyone loved it in the team... But what I also remember is that it had no paying users and we had to shut it down. - Miłosz
If you did your dirty POC, don't miss the time when you should clean it up, because it's easy to go into a spot where it's no longer possible to do that. - Robert
After working with [legacy systems] for long enough, you might think, 'I've had enough of this, I won't allow my next project to rot like this one.' It sounds like a good idea, but it can also be a trap. - Miłosz
Sometimes it can be even the opposite. Having everything super consistent can actually be worse than having inconsistent things, because keeping this consistency requires effort... Sometimes it requires you to use an approach that is not optimal just because 'we're doing it consistently.' - Robert
A useful mental model here is to care about the useful product first, not the technical design, which of course is important, but I think it's easy to overvalue it. - Miłosz
Try to find some places where you can do refactoring in one week... Often you don't need to rewrite an entire service. You can just do some refactoring in the code and iterate on that. - Robert
Episode notes and summary: https://threedots.tech/episode/when-to-write-low-quality-code/
Inside a recent episode
The Distributed Monolith Trap (And How to Escape It)
Published 28 Jan 2026 · Transcript excerpt
[…] And it might be one cluster. And maybe there are some parts that are more supporting, more generic, and they don't need to be involved as much. So they don't need to know all the details of your domain. And very often this helps you to simplify this part. For example, it can be some e -commerce software or some accountings software you can just buy or wipe code or whatever. You don't need to build it yourself from scratch if you don't want to. So in other words, not all software in your product is equal. So some parts of software probably require a bit more of love. And the less they know of each other, the cleaner your boundaries and the simpler the software as well. […]
Pod Engine is an independent podcast discovery and analytics service and is not affiliated with or endorsed by this podcast. Artwork and show content belong to their owners. Full legal notice.
Explore this show Podcast research with Pod Engine