forked from benhamill/railsconf_2011
-
Notifications
You must be signed in to change notification settings - Fork 0
/
confident_code.txt
100 lines (67 loc) · 2.09 KB
/
confident_code.txt
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
Confident Code
Avdi Grimm
slides: http://avdi.org/talks/confident-code-railsconf-2011/
Look at Code Complete book.
um.
Narrative Structure:
1. Gather Input
2. Perform Work
3. Deliver Results
4. Handle Failure
Fewer branches and easier to understand, but NOT SHORTER. You know? That's okay.
GATHER INPUT
Must be sure of your inputs.
Switching (case) on the type of an object is a code smell (nil checks and
try() count).
With uncertain nput: coerce, reject or ignore.
Coerce:
to_s, to_i, to_sym, Array(), to_your_mom, etc.
Look:
Array([1, 2, 3]) #=> [1, 2, 3]
Array("foo") #=> ["foo"]
Array(nil) #=> []
# woah!
No consistent interface? Grab the Decorator pattern.
Reject:
Define an assert method that raises Exception.
github.com/avdi/failfast
Ignore:
guard clause: return '' if input.nil?
Special case? Make an object about it.
def check_shit(status=$?)
status ||= OpenScruct.new(:exitstatus => 0)
unless [0, 172].include?(status.exitstatus)
raise ArgumentError, "Command exited with status #{status.exitstatus}"
end
end
Null Object: Returns self for any method call.
Maybe(foo).bar.baz + buz # if foo.nil? this returns nil
class Nothing
def method_missing(*)
self
end
def nil?; true; end
end
Maybe(value)
value.nil? Nothing : value
end
use collection.fetch(key) { fallback_action }
PERFORM WORK
Don't get distracted.
Code what you mean.
Conditionals raise cognative complexity; relegate them to business logic.
Single object operations are inherantly 1-or-fail.
Collection object operations are inherently 0-or-more.
DELIVER RESULTS
Help your callers be confident (return NothingObject or special case object)
HANDLE FAILURE
Put optimal path first; error handling at the end.
bouncer method:
def check_child_exit_status
result = yield
status = ? ... look for slides?
end
checked method:
def checked_popen(command, mode, fail_action)
check_child_ex... look for slides?
end