100 Go Mistakes 10-16

Here we go through the rest of Chapter 2

 10 - Not being aware of the possible problems with type embedding

Go allows you to not only include types as fields in structs, but also to embed them.

Essentially this makes the fields of the embedded/base type part of the "containers" interface.

Harsanyi points out that this can lead to exposing more than you might want to, since all of the base type's fields and behaviors are exposed as part of the container.

If there is reason to hide the base struct's details, rather simply include it as an unexported field and write accessors.

11 - Not using the functional options pattern


I'll admit that I hadn't heard about, or consciously noticed, this pattern before now, but it's quite brilliant.
An issue with positional arguments in complex functions is that having tons of arguments that are either null, or unused along certain paths, etc. is a real PITA.
My own preference, when factoring out the functionality into multiple functions is actually to pass through an options structure (like, in JS, maybe just some structured object with conventional fields).

This is doable in golang, but there are a few gotchas around things like differentiating between something being unused and it just having its default value (with ints, 0 versus "I didn't set it").

The functional options pattern is a quite brilliant approach that mixes anonymous functions and veriadic arguments to pretty much nail the issues we have with config.

This blog post by Soham Kamani gives a good overview.


12 - Project misorganization


Gives a quick overview of project structure and package organization in golang projects.


With regards to package organization
  • Golang has no notion of subpackages, so parent/child package relationships are more organizational than functional (there is no privileged access to internals of package X from package X/Y)
  • Avoid premature packaging, we might cause overcomplication.
  • Granularity is important to consider, we don't want hundreds of small packages (although an exception is made for those with highly cohesive functionality)
  • Name with care - we should name packages after what they provide rather than what they contain.
  • Export as little as possible. We can always export more later if necessary - this potentially reduces coupling.

13 - Creating utility packages

This is really just an argument against badly named, arbitrary "util" type packages. 

14 - Ignoring package name collisions


It's possible to introduce variable collisions and overriding for both package names and built-in functions. We should either rename our variables or (in the case of packages) alias the package name.

15 - Missing code documentation


All exported elements should be documented.

With structs, vars, functions, the convention is to "add comments, starting with the name of the exported element".
These comments should focus on what the function or variable does, not how it does it (the latter is irrelevant from the client's perspective - since it is implementation details).

Packages are also to be commented - convention is "// package NAME" followed by comments.
This could appear anywhere in the package, but if you have many files, you could add a "docs.go" file to the package.

16 - Not using linters


Use a linter. 

Comments

Popular posts from this blog

JCE's Gifted and Talented Center

100 Go Mistakes: 1-9