100 Go Common Mistakes

Interface Pollution (#5)
The main use cases for us to use interfaces in Go.
- Common behavior
- Decoupling
- Restricting behavior (counter intuitive)
Abstractions should be discovered, not created.
--> We shouldn't start creating abstractions in our code if there is no immediate reason to do so.
Don't design with interfaces, discover them.
If it's unclear how an interface makes the code better, we should probably consider removing it to make our code simpler.

Interface on the producer side (#6)
Interfaces are satisfied implicitly in Go(that's why this mechanism is called duck typing),which tends to be a gamechanger compared to other languages with an explicit implementation.
It's better that it's up to client side to decide whether it needs some form of abstraction and then determine the best abstraction level for its needs.

Being confused about when to use generics (#9)
For instance, functions working with slices, maps, and channels of any type.
A function to merge to channels would work with any channel type.
Hence, we could use type parameters to factor out the channel type:
func merge[T any](ch1, ch2 <-chan T) <- chan T {
// ...
}

Project misorganization (project structure and package organization) (#12)
To help clients understand a Go project, we should name our packages after what they provice, not what they contain.
A package name should be short, concise, expressive, and, by convention, a single lowercase word.
In 2023, the Go team has published an official guideline for organizing / structuring a Go project: https://go.dev/doc/modules/layout

Missing code documentation (#15)
Documentation is an important aspect of coding.
First, every exported element must be documented, whether it's a structure, an interface, a function, or something else, if it's exported, it must be documented.
--> It was suprising for me because many exported components on my team's Go project don't have documentation..
When it comes to documenting a variable or a constant, we might be interested in conveying two aspects.
- purpose: should live as code documentation to be useful for external clients
- its content: shouldn't necessarily be public
To help clients and maintainers understand a package's scope, we should also document each package.
The convention is to start the comment with // Package
followed by the package name.
The first line of a package comment should be concise. That's because it will appear in the package.
Then, we can provide all the information we need in the following lines.

Creating confution with octal literals (#17)
- Binary - Uses a
0b
or0B
prefix (for example,0b100
is equal to 4 in base 10) - Octal - Uses an
0o
or0O
prefix (for example,0o10
is equal to 8 in base 10) - Hexadecimal - Uses an
0x
or0X
prefix (for example0xF
is equal to 15 in base 10) - Imaginary - Uses an i suffix (for example,
3i
)

Not understanding slice length and capacity (#20)

Not properly checking if a slice is empty (#23)
Slice's length checking works regardless of whether the slice is nil or empty.
This principle is the same with maps.

Not making slice copies correctly (#24)
src := []int{0, 1, 2}
var dst []int
copy(dst, src)
fmt.Println(dst) // []

break
statement works (#34)
Ingnoring how the One essential rule to keep in mind is that a break
statement terminates the innermost for
, which
or select
statement. In the previous example, it terminates only the switch
statement.

Not understainding the concurrency impact of a workload type(#59)
In programming, the execution time of workload is limited by one of the following:
- The Speed of the CPU
- For example, runnning a merge sort algorithm. This kind of workload is called CPU-bound.
- The Speed of I/O
- For example, making a REST call or a database query.The workload is called I/O-bound.
- The Amount of Available Memory
- The workload is called memory-bound.

Creating data reces with append(#69)
We should remember that using append on a shared slice in concurrent applications can lead to a data race. Hence, it should be avoided.