I’ll highlight three approaches to organizing and structuring your Go code. Each approach introduces a different level of abstraction. Then, I’ll compare them all and cover the use cases for each one.
Our goal is to implement an HTTP server containing user information (Main DB in the figure below), where each user has a role (e.g. basic, moderator, admin), with an additional database (Configuration DB in the figure below), containing sets of permissions available for each role (e.g. read, write, edit).
Our HTTP server should implement an endpoint that returns a set of permissions for a given user ID.
That’s it! Those are the 3 levels of abstraction, the first one being the most slim, containing global state and tightly coupled logic, providing the fastest implementation and the least code to write and maintain, the second being a moderate hybrid, and the third completely decoupled and reusable but requiring the most overhead for maintenance.
Given the lack of community guidelines Go code comes in many shapes and forms, each has interesting merits. However, mixing different design patterns may cause problems. To organize this, I’ve introduced three different approaches to write and structure Go code. So when should each approach be used? I propose the following:
Approach I: The single package approach will probably be the go-to approach when working in small, well-experienced teams on small projects wanting to achieve fast results. This approach is faster and easier to kick start, although it requires much caution and coordination when maintaining due to lack of enforcement capabilities.
Approach II: The coupled packages approach is kind of a hybrid fusion of the other two, it has the advantages of being relatively fast and easy to maintain, while having most of the enforcement capabilities. It may be used for bigger projects by bigger teams, but still lacks reusability and has some overhead maintaining.
Approach III: The independent packages approach may suit projects of a more complex nature, bigger projects, projects that are probably more long term, worked on by bigger teams, or projects that contain pieces of logic that will probably be reused later on. This approach has a longer implementation time, and takes more time to maintain.