-
Notifications
You must be signed in to change notification settings - Fork 160
/
DEVGUIDE
63 lines (48 loc) · 1.27 KB
/
DEVGUIDE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
▒ Compiling without optimizations and inlining:
-gcflags "-N -l"
▒ Very slow memory leaks, not reflected in the memory profile, are goroutine leaks!
▒ Iterator variables are overwritten. Not correct:
for i := 0; i < N; i++ {
go func() {
println(i)
}()
}
▒ Never use sync.Cond
▒ defer recover() does not have any effect. Use
defer func() {
recover()
}()
READABILITY
===========
▒ Use anonymous structs to group together fields protected by the same lock, e.g.
type tx struct {
r struct {
sync.Mutex
ch <-chan UnlockFunc
unlk UnlockFunc
}
s struct {
sync.Mutex
s chan<- UnlockFunc
}
}
BUG BLINDNESS
=============
Sometimes you run into a bug the source of which you cannot recover, specifically
because your
▒ Receiver is a value by mistake
func (...) Close() error {
x.Lock()
defer x.Unlock()
if x.closed {
return io.ErrUnexpectedEOF
}
close(x.channel) // PANIC: closing a closed channel
x.closed = true
return nil
}
This panic seems implausible, staring at the code.
The bug is gleaned by looking at the receiver and checking
whether you have (x Type) or (x *Type).
CRUX: It is hard to catch because the natural line of reasoning, which
follows the stack trace does not prompt you to look at the receiver.