Preface |
|
xii | |
Acknowledgments |
|
xiii | |
About this book |
|
xiv | |
About the author |
|
xvii | |
About the cover illustration |
|
xviii | |
|
1 Go: Simple to learn but hard to master |
|
|
1 | (6) |
|
|
2 | (1) |
|
1.2 Simple doesn't mean easy |
|
|
3 | (1) |
|
|
4 | (3) |
|
|
4 | (1) |
|
|
5 | (1) |
|
|
5 | (1) |
|
Suboptimal or unidiomatic organization |
|
|
5 | (1) |
|
|
6 | (1) |
|
|
6 | (1) |
|
|
6 | (1) |
|
2 Code and project organization |
|
|
7 | (49) |
|
2.1 #1: Unintended variable shadowing |
|
|
7 | (2) |
|
2.2 #2: Unnecessary nested code |
|
|
9 | (3) |
|
2.3 #3: Misusing init functions |
|
|
12 | (13) |
|
|
12 | (3) |
|
When to use in it functions |
|
|
15 | (2) |
|
2.4 #4: Overusing getters and setters |
|
|
17 | (1) |
|
2.5 #5: Interface pollution |
|
|
18 | (1) |
|
|
18 | (3) |
|
|
21 | (3) |
|
|
24 | (1) |
|
2.6 #6: Interface on the producer side |
|
|
25 | (2) |
|
2.7 #7: Returning interfaces |
|
|
27 | (1) |
|
|
28 | (3) |
|
2.9 #9: Being confused about when to use generics |
|
|
31 | (5) |
|
|
31 | (3) |
|
|
34 | (2) |
|
2.10 #10: Not being aware of the possible problems with type embedding |
|
|
36 | (4) |
|
2.11 #11: Not using the functional options pattern |
|
|
40 | (6) |
|
|
41 | (1) |
|
|
42 | (2) |
|
Functional options pattern |
|
|
44 | (2) |
|
2.12 #12: Project misorganization |
|
|
46 | (2) |
|
|
46 | (1) |
|
|
47 | (1) |
|
2.13 #13: Creating utility packages |
|
|
48 | (2) |
|
2.14 #14: Ignoring package name collisions |
|
|
50 | (1) |
|
2.15 #15: Missing code documentation |
|
|
51 | (2) |
|
2.16 #16: Not using linters |
|
|
53 | (3) |
|
|
56 | (39) |
|
3.1 #17: Creating confusion with octal literals |
|
|
56 | (1) |
|
3.2 #18: Neglecting integer overflows |
|
|
57 | (4) |
|
|
58 | (1) |
|
Detecting integer overflow when incrementing |
|
|
59 | (1) |
|
Detecting integer overflows during addition |
|
|
60 | (1) |
|
Detecting an integer overflow during multiplication |
|
|
60 | (1) |
|
3.3 #19: Not understanding floating points |
|
|
61 | (3) |
|
3.4 #20: Not understanding slice length and capacity |
|
|
64 | (4) |
|
3.5 #21: Inefficient slice initialization |
|
|
68 | (3) |
|
3.6 #22: Being confused about nil vs. empty slices |
|
|
71 | (3) |
|
3.7 #23: Not properly checking if a slice is empty |
|
|
74 | (2) |
|
3.8 #24: Not making slice copies correctly |
|
|
76 | (1) |
|
3.9 #25: Unexpected side effects using slice append |
|
|
77 | (3) |
|
3.10 #26: Slices and memory leaks |
|
|
80 | (4) |
|
|
80 | (1) |
|
|
81 | (3) |
|
3.11 #27: Inefficient map initialization |
|
|
84 | (3) |
|
|
84 | (2) |
|
|
86 | (1) |
|
3.12 #28: Maps and memory leaks |
|
|
87 | (3) |
|
3.13 #29: Comparing values incorrecdy |
|
|
90 | (5) |
|
|
95 | (18) |
|
4.1 #30: Ignoring the fact that elements are copied in range loops |
|
|
95 | (3) |
|
|
96 | (1) |
|
|
96 | (2) |
|
4.2 #31: Ignoring how arguments are evaluated in range loops |
|
|
98 | (4) |
|
|
100 | (1) |
|
|
100 | (2) |
|
4.3 #32: Ignoring the impact of using pointer elements in range loops |
|
|
102 | (3) |
|
4.4 #33: Making wrong assumptions during map iterations |
|
|
105 | (3) |
|
|
105 | (2) |
|
Map insert during iteration |
|
|
107 | (1) |
|
4.5 #34: Ignoring how the break statement works |
|
|
108 | (2) |
|
4.6 #35: Using defer inside a loop |
|
|
110 | (3) |
|
|
113 | (13) |
|
5.1 #36: Not understanding the concept of a rune |
|
|
114 | (1) |
|
5.2 #37: Inaccurate string iteration |
|
|
115 | (3) |
|
5.3 #38: Misusing trim functions |
|
|
118 | (1) |
|
5.4 #39: Under-optimized string concatenation |
|
|
119 | (2) |
|
5.5 #40: Useless string conversions |
|
|
121 | (2) |
|
5.6 #41: Substrings and memory leaks |
|
|
123 | (3) |
|
|
126 | (17) |
|
6.1 #42: Not knowing which type of receiver to use |
|
|
127 | (2) |
|
6.2 #43: Never using named result parameters |
|
|
129 | (3) |
|
6.3 #44: Unintended side effects with named result parameters |
|
|
132 | (1) |
|
6.4 #45: Returning a nil receiver |
|
|
133 | (3) |
|
6.5 #46: Using a filename as a function input |
|
|
136 | (2) |
|
6.6 #47: Ignoring how defer arguments and receivers are evaluated |
|
|
138 | (5) |
|
|
138 | (3) |
|
Pointer and value receivers |
|
|
141 | (2) |
|
|
143 | (19) |
|
|
143 | (3) |
|
7.2 #49: Ignoring when to wrap an error |
|
|
146 | (3) |
|
7.3 #50: Checking an error type inaccurately |
|
|
149 | (3) |
|
7.4 #51: Checking an error value inaccurately |
|
|
152 | (2) |
|
7.5 #52: Handling an error twice |
|
|
154 | (2) |
|
7.6 #53: Not handling an error |
|
|
156 | (2) |
|
7.7 #54: Not handling defer errors |
|
|
158 | (4) |
|
8 Concurrency: Foundations |
|
|
162 | (31) |
|
8.1 #55: Mixing up concurrency and parallelism |
|
|
163 | (3) |
|
8.2 #56: Thinking concurrency is always faster |
|
|
166 | (7) |
|
|
166 | (3) |
|
|
169 | (4) |
|
8.3 #57: Being puzzled about when to use channels or mutexes |
|
|
173 | (1) |
|
8.4 #58: Not understanding race problems |
|
|
174 | (1) |
|
Data races vs. race conditions |
|
|
174 | (5) |
|
|
179 | (2) |
|
8.5 #59: Not understanding the concurrency impacts of a workload type |
|
|
181 | (5) |
|
8.6 #60: Misunderstanding Go contexts |
|
|
186 | (7) |
|
|
186 | (1) |
|
|
187 | (1) |
|
|
188 | (2) |
|
Catching a context cancellation |
|
|
190 | (3) |
|
|
193 | (41) |
|
9.1 #61: Propagating an inappropriate context |
|
|
193 | (3) |
|
9.2 #62: Starting a goroutine without knowing when to stop it |
|
|
196 | (2) |
|
9.3 #63: Not being careful with goroutines and loop variables |
|
|
198 | (2) |
|
9.4 #64: Expecting deterministic behavior using select and channels |
|
|
200 | (4) |
|
9.5 #65: Not using notification channels |
|
|
204 | (1) |
|
9.6 #66: Not using nil channels |
|
|
205 | (6) |
|
9.7 #67: Being puzzled about channel size |
|
|
211 | (2) |
|
9.8 #68: Forgetting about possible side effects with string formatting |
|
|
213 | (3) |
|
|
213 | (1) |
|
|
214 | (2) |
|
9.9 #69: Creating data races with append |
|
|
216 | (2) |
|
9.10 #70: Using mutexes inaccurately with slices and maps |
|
|
218 | (3) |
|
9.11 #71: Misusing sync.WaitGroup |
|
|
221 | (2) |
|
9.12 #72: Forgetting about sync.Cond |
|
|
223 | (5) |
|
9.13 #73: Not using errgroup |
|
|
228 | (3) |
|
9.14 #74: Copying a sync type |
|
|
231 | (3) |
|
|
234 | (28) |
|
10.1 #75: Providing a wrong time duration |
|
|
235 | (1) |
|
10.2 #76: Time, After and memory leaks |
|
|
235 | (3) |
|
10.3 #77: Common JSON-handling mistakes |
|
|
238 | (6) |
|
Unexpected behavior due to type embedding |
|
|
238 | (2) |
|
JSON and the monotonic clock |
|
|
240 | (3) |
|
|
243 | (1) |
|
10.4 #78: Common SQL mistakes |
|
|
244 | (5) |
|
Forgetting that sql. Open doesn't necessarily establish connections to a database |
|
|
244 | (1) |
|
Forgetting about connections pooling |
|
|
245 | (1) |
|
Not using prepared statements |
|
|
246 | (1) |
|
|
247 | (1) |
|
Not handling row iteration errors |
|
|
248 | (1) |
|
10.5 #79: Not closing transient resources |
|
|
249 | (6) |
|
|
250 | (2) |
|
|
252 | (1) |
|
|
253 | (2) |
|
10.6 #80: Forgetting the return statement after replying to an HTTP request |
|
|
255 | (1) |
|
10.7 #81: Using the default HTTP client and server |
|
|
256 | (6) |
|
|
256 | (3) |
|
|
259 | (3) |
|
|
262 | (37) |
|
11.1 #82: Not categorizing tests |
|
|
262 | (4) |
|
|
263 | (1) |
|
|
264 | (1) |
|
|
265 | (1) |
|
11.2 #83: Not enabling the -race flag |
|
|
266 | (2) |
|
11.3 #84: Not using test execution modes |
|
|
268 | (3) |
|
|
269 | (1) |
|
|
270 | (1) |
|
11.4 #85: Not using table-driven tests |
|
|
271 | (3) |
|
11.5 #86: Sleeping in unit tests |
|
|
274 | (4) |
|
11.6 #87: Not dealing with the time API efficiently |
|
|
278 | (3) |
|
11.7 #88: Not using testing utility packages |
|
|
281 | (4) |
|
|
281 | (2) |
|
|
283 | (2) |
|
11.8 #89: Writing inaccurate benchmarks |
|
|
285 | (9) |
|
Not resetting or pausing the timer |
|
|
286 | (1) |
|
Making wrong assumptions about micro-benchmarks |
|
|
287 | (2) |
|
Not being careful about compiler optimizations |
|
|
289 | (2) |
|
Being fooled by the observer effect |
|
|
291 | (3) |
|
11.9 #90: Not exploring all the Go testing features |
|
|
294 | (5) |
|
|
294 | (1) |
|
Testing from a different package |
|
|
295 | (1) |
|
|
295 | (1) |
|
|
296 | (3) |
|
|
299 | (58) |
|
12.1 #91: Not understanding CPU caches |
|
|
300 | (12) |
|
|
300 | (1) |
|
|
301 | (3) |
|
Slice of structs vs. struct of slices |
|
|
304 | (1) |
|
|
305 | (2) |
|
|
307 | (5) |
|
12.2 #92: Writing concurrent code that leads to false sharing |
|
|
312 | (3) |
|
12.3 #93: Not taking into account instruction-level parallelism |
|
|
315 | (6) |
|
12.4 #94: Not being aware of data alignment |
|
|
321 | (3) |
|
12.5 #95: Not understanding stack vs. heap |
|
|
324 | (7) |
|
|
324 | (5) |
|
|
329 | (2) |
|
12.6 #96: Not knowing how to reduce allocations |
|
|
331 | (3) |
|
|
331 | (1) |
|
|
332 | (1) |
|
|
332 | (2) |
|
12.7 #97: Not relying on inlining |
|
|
334 | (3) |
|
12.8 #98: Not using Go diagnostics tooling |
|
|
337 | (10) |
|
|
337 | (7) |
|
|
344 | (3) |
|
12.9 #99: Not understanding how the GC works |
|
|
347 | (5) |
|
|
347 | (2) |
|
|
349 | (3) |
|
12.10 #100: Not understanding the impacts of running Go in Docker and Kubernetes |
|
|
352 | (5) |
|
|
355 | (2) |
Index |
|
357 | |