What is a Package
You may already know that a package in Go is defined as a collection of files in the same directory that are compiled together. A file contains variables, constants, types, and functions, and they're visible in other files within the package. Visibility of a symbol outside of the package is controlled by the first character in the name: a capital letter makes a symbol exported, and a lowercase letter marks it as unexported. A package in Go provides a way to accomplish a set of tasks.
While sounding simple, this definition gives us all that we need to lay out the foundation for a good software design. Having thought about what it really means, and how to employ it, you realise that the package paradigm in Go is meant to embrace and support many of the good practices in software engineering. The responsible engineer knowns and applies the SOLID design principles.
So how does exactly the package system help us with software design? This is what packages help us to do:
- provide namespace and set the context
- group code by responsibilities, roles and functionality, and keep them clear (SRI), i.e. encapsulate what varies
- facilitate extension over modification (OCP)
- build and maintain proper abstractions (LSR)
- keep interfaces and public API narrow (ISP), i.e. hide implementation details and decoupling
- maintain healthy dependencies between objects (DIP)
- distribute and reuse code (DRY)
- keep it simple, testable and atomic (KISS)
- and so on.
What a Go package is not? The most important thing to remember is that packages are not means of/for implementing a hierarchy. The hierarchy of libraries in Go is flat. Bear this fact in mind. Each time when you encounter net/http, it does not mean that http is a descendant of net, or a sub-package. This is done simply as a matter of namespacing and setting the context, and no more than that. The net package is completely independent, and can be used on its own, so the net/http package is (although it does use net internally). In spite of being inside net, there is no hierarchical or inheritance relation between the two. The http package is just located within the net package's folder.
Building a firm understanding of the packages' nature and purpose is one of the keys to designing changeable and maintainable software. Without this understanding, anything you do, even if it seems to be right, will eventually fall apart. It does not matter how well a house is built, if it stands on a weak and shaky foundation.
One of the most often mistakes is creating a package, not knowing when to and when not to do so. On one extreme, a project may have too much code, with too different roles mixed in a single package. On the opposite, a project may abuse the use of packages so that there is way too many of them. Neither of these situations helps in building great software.
You need to find balance, and knowing when it's a good time for creating a package is helpful.