Don't Run In Circles • The Applied Go Weekly Newsletter 2025-04-13
Your weekly source of Go news, tips, and projects
Don't Run In Circles
Hi ,
Do you know that feeling when you have a task to solve but seem to run in circles, getting nowhere? This is how a compiler must feel if a language allows import cycles. Sure, compilers can detect the cycle and stop circling around, but this requires effort and makes the compiler slow.
The Go compiler doesn't allow import cycles, but not everyone seems to be happy about this decision. "Why can't I use cyclic imports? My architecture has this structure for a reason!" Well, there are good reasons to avoid this, and several not-too-difficult ways of resolving an import cycle.
More on this in the Spotlights section.
But first, let's look behind the scenes of writing a (quite popular!) Go book, dive deep into memory leak troubleshooting, and examine the footguns of limiting available CPUs inside a Kubernetes pod.
Have an awesome week!
–Christoph
Featured articles
So, I Wrote a Book: The Story Behind 100 Go Mistakes
It all started with a blog post: How Teiva Hasanyl came about to write a book about 100 mistakes a developer can make in Go.
A Trip Down Memory Lane: How We Resolved a Memory Leak When pprof Failed Us - WarpStream
How do you track down a memory leak if even pprof
can't help? Take a dump! (A core dump, that is.)
Golang Performance Penalty in Kubernetes
Seasoned Kubernetes devops may know this caveat already, but Mansoor's article goes into great depth to uncover all aspects of the problem of a wrong GOMAXPROCS setting inside a k8s pod.
Podcast corner
Cup o' Go: Don't give me that line feed! 🖶
Catching up on Cup o' Go (which releases new episodes usually shortly after I sent my newsletter issue to the printing press, unfortunately).
APIs: Design Imperfectly, Improve Relentlessly
How to create high-quality APIs? The Fallthrough panel discusses learnings and tips. Including a look behind the scenes of creating Fallthrough episodes.
Spotlight: Go doesn't like import cycles
I find it hard to tell you, 'cause I find it hard to take
When people run in circles
It's a very, very
Mad world
–Tears for Fears, Mad World
Imagine this: You are about to build an account
package and a transaction
package as part of an e-commerce app. While you work out the details of these packages, you notice that both packages seem to depend on each other: An account needs to manage its transactions, and a transaction needs account details to, for example, validate funds.
Now you have an import cycle between the two packages, also known as a circular dependency.
I have an import cycle... yeah, so what?
From the perspective of code logic, an import cycle might seem entirely valid, maybe even desirable. But from a dependency management perspective, the opposite is true. It's harder for the compiler to find out what to compile, and it's harder for the developer to maintain such import cycles. In Go, cyclic imports won't even compile. Go intentionally disallow import cycles.
Citing Rob Pike:
The lack of import cycles in Go forces programmers to think more about their dependencies and keep the dependency graph clean and builds fast. Conversely, allowing cycles enables laziness, poor dependency management, and slow builds. Eventually one ends up with a single cyclical blob enclosing the entire dependency graph and forcing it into a single build object. This is very bad for build performance and dependency resolution. These blobs also take much more work to detangle than is required to keep the graph a proper DAG in the first place.
This is one area where up-front simplicity is worthwhile.
Import cycles can be convenient but their cost can be catastrophic.
TL;DR: The two main problems with import cycles are:
- Long compile times
- Increased maintenance burden and mental load
The first one should be a no-brainer for everyone. We all love the crazy fast Go compiler, don't we?
The second one is equally important. Creating import cycles is easy if you're lazy with building your app's architecture. But you won't be able to manage those import cycles later with the same laziness used to creating them. The tech debt would hit hard.
Obviously, the better approach is to avoid import cycles, or detangle them the moment they occur.
But how?
Breaking the cycles
Here are a few approaches to fixing an import cycle:
- Don't let a package import itself. This one may sound trivial, but it's easy to accidentally write
foo.Bar()
inside packagefoo
, and if the formatter happily auto-adds the package to the import list, you have unconsciously created a single-package import cycle. (At least, none of the Go formatters I tested auto-adds a self-import.) - Use dependency injection to reverse the dependency relationship between two packages. Instead of directly accessing a package function or type, use an interface and have the constructor (the
New()
orNewX...()
function) accept this interface. Now the clients of the package can do the wiring without causing an import cycle. - Move common code to an extra package. Identify code used by all packages involved in the import cycle and move it to a new package that the existing packages can import.
- Merge the packages. An import cycle between two packages can be a sign that the code is tightly coupled and should better live in the same package.
The next time you encounter an import cycle not allowed
error, step back and restructure. Your future self will thank you.
Quote of the Week: Like our cities
We build our computer systems the way we build our cities: over time, without a plan, on top of ruins.
More articles, videos, talks
So, Why does Go’s Composition Feel So Speedy? 💻 | by Aryan | Apr, 2025 | Cubed
Go has no inheritance for good reasons. The obvious one is less code complexity. The not-so-obvious one? Runtime speed.
Cutting 70% of Infra Costs with Go: A benchmark between Go, NextJS, Java and GraalVM | by Lucas Borsatto | Medium
All performance comparisons have to be taken with a grain of salt. Usually, too many moving parts are involved: language, frameworks, OS, network, etc. But detailed performance tests like this one can provide an initial orientation.
Don't Overload Your Brain: Write Simple Go | Jakub Jarosz
About unnecessary condition blocks, logic indirections, and optimal reading flow.
Why Go Should Be Your Best First Step into Backend Development | by Aryan | Apr, 2025 | Cubed
Nothing against a bit language advocacy from time to time! Especially if the points are vaild.
Announcing Mockery v3 - Top of Mind
Mockery v3 got faster and offers a universal template framework. In this article, the author explains some of the reasons for the changes in v3.
My pessimism about changes to error handling in Go (but they'll happen)
An appeal for leaving Go's error handling as it is now.
Is Golang Still Growing? Go Language Popularity Trends in 2024
A Go market study by JetBrains.
Accepted proposals: store test artifacts, and add WaitGroup.Go
Two proposals have been accepted that seem worth noting:
testing: store test artifacts · Issue #71287 · golang/go: Tests may generate files that are stored only temporarily. The -outputdir
flag, currently used for setting the storage of pprof
output, shall be extended to also set the storage location of test artifacts.
sync: add WaitGroup.Go · Issue #63796 · golang/go: WaitGroup's rituals of Add(1)
and defer wg.Done()
are error-prone and confusing for beginners .("Is 1 a magic number?") A new Go() method shall make using WaitGroups substantially easier.
Final comment: "By a stroke of good fortune / carelessness, the implementation is already complete."
Projects
Libraries
GitHub - metafates/schema: 📐 Type-safe schema guarded types for Go. No field tags or map[string]any schemas, pure types!
Schema validation usually relies on either struct tags or duplicated types, both of which is prone to typos and cumbersome to refactor.metafates/schema
avoids these drawbacks by using types for validation. The overhead induced by reflection can be eliminated through code generation.
GitHub - blindlobstar/go-interview-problems: Go live coding interview problems
An upcoming job interview is not a strict requirement for tackling these nice little programming problems.
GitHub - Synoptiq/go-fluxus: 🧬 Fluxus is a modern, type-safe pipeline orchestration library for Go that makes complex data processing elegant and efficient
An in-process pipeline library.
Tools and applications
GitHub - rasadov/EcommerceAPI: Modular e-commerce backend with a GraphQL gateway and gRPC microservices for accounts, products, orders, and recommendations.
This project is in a proof-of-concept stage with some requirements to still be addressed, but maybe worth following if you plan to implement open source e-commerce apps.
GitHub - github/github-mcp-server: GitHub's official MCP Server
GitHub and Anthropic joined forces to rewrite the GitHub MCP server in Go. (It was written in TypeScript before.)
Go Docs Syntax Highlighter - Chrome Web Store
Don't tell Rob Pike, but here is a Chrome extension that brings colors to Go docs. (No source code available, unfortunately.)
timeline · tangled
Tangled wants to eliminate the need to log in to someone else's git platform (GitHub, GitLab, Codeberg,...) in order to collaborate on a project. Instead, Tangled connects git servers called "knot" via Bluesky's AT protocol. It's currently in alpha state (and visibly so); read more in this announcement.
Hireblades by Iskander (quasilyte)
A round-based top-down game made with Ebitengine.
GitHub - odlemon/podium
If Kubernetes is overkill for your requirements, try Podium. According to the author, it's like Docker Compose with health checks and auto-recovery. Optimized for single-node deployments.
Multiplayer Pacman
A multiplayer Pacman game built with Go and Flutter. Source code here.
Organizrr
A local-first PDF labelling & splitting tool. Despite being built with Go, it runs entirely in the browser (thanks to WASM). Source code here.
GitHub - Vistahm/ewc: ewc (easy wifi connection) helps you to control your wifi network on Linux with less pain!
Switch wifi access points or turn wifi on or off from your terminal.
Completely unrelated to Go
Typing using my keyboard (the other kind)
What keyboard do you use? The one built into the laptop, a retro-style IBM keyboard with extra loud keyclicks, or an ergonomic split keyboard?
Nicole Tietz-Sokolskaya decided to try out "the other kind": A piano-style keyboard. And it works, but don't ask how!
Celebrate 50 years of Microsoft with the company’s original source code
Bill Gates looks back to the very beginnings of Microsoft, when Paul Allen and he wrote the first Microsoft product on a PDP-10.
Warning: The page is heavy on animated graphics and effects that even brings my MacBook M2 Pro to turn up the fans. (via)
Reimagining Democracy
What if we landed on some alien planet and had to form new governmental structures from scratch?
An interesting idea that Bruce Schneier, renowned security expert, unrolls in his article. It's not just his thoughts, though. The article is a distillate from three years of annual workshops with subject-matter experts from various disciplines.
"Personally, I was most interested, at each of the three workshops, in how political systems fail. As a security technologist, I study how complex systems are subverted—hacked, in my parlance—for the benefit of a few at the expense of the many."

Happy coding! ʕ◔ϖ◔ʔ
Questions or feedback? Drop me a line. I'd love to hear from you.
Best from Munich, Christoph
Not a subscriber yet?
If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding.
Find the subscription form at the end of this page.
How I can help
If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):
On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.
Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff.
My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.
Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.
Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany