Learning how to structure an application in Go is hard. Not only are there a million different approaches out there, but everyone will tell you why you shouldn’t do X while rarely offering a better approach.
In reality, everything comes down to context. How big is your application? How are you deploying? How big is your team? Is your project open source? Do you have any conventions that your team prefers? How important are tests, and what coverage do you need? All of these factors and more will shape how you structure your application, because there truly isn’t a single “correct” way to structure an application. It depends entirely on your context.
Unfortunately knowing that context matters doesn’t always help. It still leaves the new Gopher wondering, “What structure is best for my context?”
The goal of this series is to explore application structure in Go. We will mostly be exploring this from a web application perspective, but most, if not all, of the information we cover will be useful regardless of what type of applications you are building.
We will start by examining why it is so hard for everyone to just agree on a universal structure, and then dive into a few various options for structuring your application and discuss when and why they can be useful. We will also discuss some pitfalls each has and why you may hear people telling you to avoid some of them (even though they are entirely feasible for many applications).
By the end I hope to leave you with enough information that you can start building with the confidence that you can learn and adapt as your project and team grows without feeling the need to start with a structure too complicated for your current needs.
The first thing we need to discuss is why it feels like this problem is solved in other languages and/or frameworks (eg Ruby on Rails uses MVC), but in Go this is still an unsolved problem. (Hint: It isn’t really as solved in other languages as you might believe.)
In this article we will discuss context, how other languages approach the application design problem, why they might take the approach they do, and what we can learn from it as we design our applications in Go.
A flat application structure is basically exactly what it sounds like. Rather than creating directories with packages in them, we instead opt to just put all of our code in a single package.
This is almost certainly the least hip way to layout your code, but I have found it to be insanely refreshing for many projects. It is reminiscent of my PHP days when I was just learning to code and I cared more about making the damn website work rather than how I was supposed to be coding.
It probably goes without saying, but a flat app structure won’t work forever. At some point your application is going to outgrow it. That said, it likely works much longer than you think, and this is typically one of the easiest structures to let evolve naturally as your application grows in complexity.
MVC has been around for a LOOONG time, but it is often discouraged in Go. It is my belief that MVC is actually a pretty good fit for Go, but it requires you to drop some preconceived notions about what MVC is and how it should be implemented.
In this article we not only look at what MVC is, but how to implement it effectively in Go. We will even look at package naming, mistakes to avoid, and by the end you will hopefully be ready to try out an MVC application in Go.
Domain driven design sounds great in theory, but how is it applied in Go?
Rather than looking at DDD from an abstract view, this article attempts to take a more practical approach. We start off with some code that is tightly coupled and look at how it evolves as requirements evolve. By the end we decouple the code, but at the cost of a great deal of extra code. We then explore how a more domain-oriented design can help alleviate much of the pains we had, while being much easier to utilize.
Finally, we take some time to discuss the pros and cons of starting out with domain driven design. Does it make more sense to let your code evolve, or to dive right into designing domain models before writing a line of code?
If we ultimately decide to use DDD in our Go code, there are a few ways we can improve the effectiveness of our code. One of those is to write interface test suites - tests that are implementation agnostic and can be used to test ANY implementation of an interface we define at the domain level.
Not only will interface tests help ensure that you are testing behavior (rather than implementation details), but it also means any new implementations of a domain interface have tests to work with out of the box and we can swap implementations with confidence that our application will continue to work.
This series is actively being composed, but my schedule is wonky and future posts get delayed all the time 😦. I’ll try to keep pushing updates, but I can’t make any promises on when they will be published.
Sign up for my mailing list and I'll send you a FREE sample from my course - Web Development with Go. The sample includes 19 screencasts and the first few chapters from the book.
You will also receive emails from me about Go coding techniques, upcoming courses (including FREE ones), and course discounts.
Jon Calhoun is a full stack web developer who teaches about Go, web development, algorithms, and anything programming. If you haven't already, you should totally check out his Go courses.
Previously, Jon worked at several statups including co-founding EasyPost, a shipping API used by several fortune 500 companies. Prior to that Jon worked at Google, competed at world finals in programming competitions, and has been programming since he was a child.
Spread the word
Did you find this page helpful? Let others know about it!
Sharing helps me continue to create both free and premium Go resources.
Want to discuss the article?
See something that is wrong, think this article could be improved, or just want to say thanks? I'd love to hear what you have to say!
You can reach me via email or via twitter.
©2024 Jonathan Calhoun. All rights reserved.