Upload
khanh-pham
View
214
Download
0
Embed Size (px)
Citation preview
8/12/2019 112_wrirting_easytochangecode
1/207
These are confidential sessionsplease refrain from streaming, blogging, or taking pictures
Your second-most important goal as a developer
Session 112
Ken KociendaPrincipal Engineer, iOS Apps and Frameworks
1
8/12/2019 112_wrirting_easytochangecode
2/207
This is a talk about writing code
2
8/12/2019 112_wrirting_easytochangecode
3/207
Easy to read
learn
understand
maintain
change
3
8/12/2019 112_wrirting_easytochangecode
4/207
Easy to change software
4
8/12/2019 112_wrirting_easytochangecode
5/207
Your second-most important goal
5
8/12/2019 112_wrirting_easytochangecode
6/207
What is your most important goal?
6
8/12/2019 112_wrirting_easytochangecode
7/207
Ship products!
7
8/12/2019 112_wrirting_easytochangecode
8/207
This is how we think at Apple
8
8/12/2019 112_wrirting_easytochangecode
9/207
Over 30 iOS releases since 2007
9
8/12/2019 112_wrirting_easytochangecode
10/207
Releases are complicated
Legal
Marketing
Bug fixesNew app features
Improving existing features
Changing priorities
Competition
Tight schedules
Too few people
Testing
New hardware
New OS features
Work with other companies
Too many people
App Store submission
10
8/12/2019 112_wrirting_easytochangecode
11/207
Help you make change easier
11
8/12/2019 112_wrirting_easytochangecode
12/207
You always change your software
12
8/12/2019 112_wrirting_easytochangecode
13/207
Bug fixes
Adding new features
Enhancing existing features
Changing code someone else wrote
Changing code you wrote six months ago
13
8/12/2019 112_wrirting_easytochangecode
14/207
General conventions
14
8/12/2019 112_wrirting_easytochangecode
15/207
Mac and iOS conventions
15
8/12/2019 112_wrirting_easytochangecode
16/207
8/12/2019 112_wrirting_easytochangecode
17/207
Style
Stories
Laziness
Hygiene
Notifications
Optimization
Dependencies
Mixing
Expectations
Wrap up
17
8/12/2019 112_wrirting_easytochangecode
18/207
8/12/2019 112_wrirting_easytochangecode
19/207
Coding conventions
19
8/12/2019 112_wrirting_easytochangecode
20/207
Brace style for if-else
Parenthesis Style
Leading underscores
Code indenting
CapitalizationStyle (i.e. capitalization_style)
20
8/12/2019 112_wrirting_easytochangecode
21/207
Local consistency is important
21
8/12/2019 112_wrirting_easytochangecode
22/207
The beginnings of style
22
8/12/2019 112_wrirting_easytochangecode
23/207
Style goes deeper
23
8/12/2019 112_wrirting_easytochangecode
24/207
Matthew Arnold
24
8/12/2019 112_wrirting_easytochangecode
25/207
Clarity
25
8/12/2019 112_wrirting_easytochangecode
26/207
Clear writing is easier to understand
26
8/12/2019 112_wrirting_easytochangecode
27/207
Clear code is easier to change
27
8/12/2019 112_wrirting_easytochangecode
28/207
Elements of a clear coding style?
28
8/12/2019 112_wrirting_easytochangecode
29/207
!
!
Good names
Common idioms
29
8/12/2019 112_wrirting_easytochangecode
30/207
8/12/2019 112_wrirting_easytochangecode
31/207
NSString *searchString = [self _searchString];BOOL searchStringIsNotEmpty = [searchString length] != 0;
if (searchStringIsNotEmpty) { [self _findBanner]->findString(searchString,
shouldBeep ? BeepOnFailure: DoNotBeepOnFailure);}
31
8/12/2019 112_wrirting_easytochangecode
32/207
NSString *searchString = [self _searchString];
BOOL searchStringIsNotEmpty = [searchString length] != 0;
if (searchStringIsNotEmpty) { [self _findBanner]->findString(searchString,
shouldBeep ? YES: NO);}
32
8/12/2019 112_wrirting_easytochangecode
33/207
8/12/2019 112_wrirting_easytochangecode
34/207
8/12/2019 112_wrirting_easytochangecode
35/207
Hard to know what they mean
- (void)stopMagnifying:(BOOL)animated;
35
8/12/2019 112_wrirting_easytochangecode
36/207
Hard to know what they mean
- (void)stopMagnifyingAnimated:(BOOL)animated;
36
8/12/2019 112_wrirting_easytochangecode
37/207
Good names are descriptive
37
8/12/2019 112_wrirting_easytochangecode
38/207
!
!
Good names
Common idioms
38
8/12/2019 112_wrirting_easytochangecode
39/207
!
!
Good names
Common idioms
39
8/12/2019 112_wrirting_easytochangecode
40/207
Hard to know what they mean
[_rightView setAlpha:![[_temporary text] length] ? 1.0 : 0.0];
40
8/12/2019 112_wrirting_easytochangecode
41/207
Count square brackets?
41
8/12/2019 112_wrirting_easytochangecode
42/207
Hard to know what they mean
[_rightView setAlpha:![[_temporary text] length] ? 1.0 : 0.0];
42
8/12/2019 112_wrirting_easytochangecode
43/207
Be clear!
BOOL textIsEmpty = [_temporary.text length] == 0;float alpha = textIsEmpty ? 1.0 : 0.0;[_rightView setAlpha:alpha];
43
8/12/2019 112_wrirting_easytochangecode
44/207
Read and understand quickly
44
8/12/2019 112_wrirting_easytochangecode
45/207
Design patterns
45
8/12/2019 112_wrirting_easytochangecode
46/207
8/12/2019 112_wrirting_easytochangecode
47/207
Patterns used in Apple frameworks
MVC
Target-action
Delegation
Autorelease
View controller
47
8/12/2019 112_wrirting_easytochangecode
48/207
Idioms communicate at a high level
48
8/12/2019 112_wrirting_easytochangecode
49/207
8/12/2019 112_wrirting_easytochangecode
50/207
!
!
Good names
Common idioms
50
8/12/2019 112_wrirting_easytochangecode
51/207
More than skin deep
51
8/12/2019 112_wrirting_easytochangecode
52/207
Now I understand
52
8/12/2019 112_wrirting_easytochangecode
53/207
Bug. Why?
53
8/12/2019 112_wrirting_easytochangecode
54/207
Did not anticipate
Did not understand
54
8/12/2019 112_wrirting_easytochangecode
55/207
Debug
55
8/12/2019 112_wrirting_easytochangecode
56/207
8/12/2019 112_wrirting_easytochangecode
57/207
Step 1: Debugger
57
8/12/2019 112_wrirting_easytochangecode
58/207
What are you really looking for?
58
8/12/2019 112_wrirting_easytochangecode
59/207
8/12/2019 112_wrirting_easytochangecode
60/207
How could this bug happen?
60
8/12/2019 112_wrirting_easytochangecode
61/207
Brian Kernighan
61
8/12/2019 112_wrirting_easytochangecode
62/207
Debugging is understanding
62
8/12/2019 112_wrirting_easytochangecode
63/207
Debugging is not jiggling code
63
8/12/2019 112_wrirting_easytochangecode
64/207
8/12/2019 112_wrirting_easytochangecode
65/207
Why?
[self foo];
[self bar];
65
8/12/2019 112_wrirting_easytochangecode
66/207
Each bug fix should tell a story
66
8/12/2019 112_wrirting_easytochangecode
67/207
Investigate. Eureka!
Tell someone before you code the fix
67
8/12/2019 112_wrirting_easytochangecode
68/207
8/12/2019 112_wrirting_easytochangecode
69/207
Write the story into your bug tracker
69
8/12/2019 112_wrirting_easytochangecode
70/207
Anticipate more
Understand better
70
8/12/2019 112_wrirting_easytochangecode
71/207
Now I understand
71
8/12/2019 112_wrirting_easytochangecode
72/207
Wake me when it is over
72
8/12/2019 112_wrirting_easytochangecode
73/207
Lazy initialization
73
8/12/2019 112_wrirting_easytochangecode
74/207
It is good
74
8/12/2019 112_wrirting_easytochangecode
75/207
It is not magic
75
8/12/2019 112_wrirting_easytochangecode
76/207
Lazy initialization is common
FooController *controller = [FooController sharedInstance];
76
8/12/2019 112_wrirting_easytochangecode
77/207
Lazy initialization is common
@implementation FooController
+ (FooController *)sharedInstance
{ static dispatch_once_t once; static FooController *instance; dispatch_once(&once, ^{ instance = [[FooController alloc] init]; }); return instance;}
@end
77
8/12/2019 112_wrirting_easytochangecode
78/207
8/12/2019 112_wrirting_easytochangecode
79/207
Lazy initialization is common
@implementation BarController
- (id)init
{ ... FooController*fooController = [FooController
sharedInstance];...
}
@end
79
8/12/2019 112_wrirting_easytochangecode
80/207
Init storm
80
8/12/2019 112_wrirting_easytochangecode
81/207
8/12/2019 112_wrirting_easytochangecode
82/207
Long pause
82
8/12/2019 112_wrirting_easytochangecode
83/207
Order of initialization
83
8/12/2019 112_wrirting_easytochangecode
84/207
How many do you have?
@implementation FooController
+ (FooController *)sharedInstance
{ static dispatch_once_t once; static FooController *instance; dispatch_once(&once, ^{ instance = [[FooController alloc] init]; }); return instance;}
@end
84
8/12/2019 112_wrirting_easytochangecode
85/207
How many do you have?
@implementation FooController
+ (FooController *)sharedInstance
{ static FooController *instance; if (!instance) instance = [[FooController alloc] init]; return instance;}
@end
85
8/12/2019 112_wrirting_easytochangecode
86/207
Multiple instantiation of singleton
86
8/12/2019 112_wrirting_easytochangecode
87/207
Mess
87
8/12/2019 112_wrirting_easytochangecode
88/207
Think through lazy initialization
88
8/12/2019 112_wrirting_easytochangecode
89/207
No silver bullets
89
8/12/2019 112_wrirting_easytochangecode
90/207
Lightweight alloc at program start
Better singleton decomposition
90
8/12/2019 112_wrirting_easytochangecode
91/207
Alternative accessor patterns
91
8/12/2019 112_wrirting_easytochangecode
92/207
Create or not?
@interface FooController
+ (FooController *)sharedInstance; // will create
+ (FooController *)activeInstance; // wont create+ (FooController *)sharedInstance createIfNeeded:(BOOL)createIfNeeded;
@end
92
8/12/2019 112_wrirting_easytochangecode
93/207
Wake me when it is over
93
8/12/2019 112_wrirting_easytochangecode
94/207
You make the mess you clean it up!
94
8/12/2019 112_wrirting_easytochangecode
95/207
Good hygiene takes effort
95
8/12/2019 112_wrirting_easytochangecode
96/207
E.B. White
96
8/12/2019 112_wrirting_easytochangecode
97/207
Do not throw away code
97
8/12/2019 112_wrirting_easytochangecode
98/207
Conflict?
98
8/12/2019 112_wrirting_easytochangecode
99/207
Changes are part of a process
99
8/12/2019 112_wrirting_easytochangecode
100/207
Your top priority should be to ship
100
8/12/2019 112_wrirting_easytochangecode
101/207
Do not rewrite refactor
101
8/12/2019 112_wrirting_easytochangecode
102/207
Refactoring
Keep functionality, but change form
102
8/12/2019 112_wrirting_easytochangecode
103/207
What about cruft?
103
8/12/2019 112_wrirting_easytochangecode
104/207
8/12/2019 112_wrirting_easytochangecode
105/207
What is genuine cruft?
105
8/12/2019 112_wrirting_easytochangecode
106/207
Dead code
Comments which no longer apply
There is no number three
106
8/12/2019 112_wrirting_easytochangecode
107/207
Use compiler for dead code checks
107
8/12/2019 112_wrirting_easytochangecode
108/207
Delete or check old comments
108
8/12/2019 112_wrirting_easytochangecode
109/207
8/12/2019 112_wrirting_easytochangecode
110/207
Size of change is important
110
8/12/2019 112_wrirting_easytochangecode
111/207
Small: clean up as you go
111
8/12/2019 112_wrirting_easytochangecode
112/207
8/12/2019 112_wrirting_easytochangecode
113/207
Large: need real planning
113
8/12/2019 112_wrirting_easytochangecode
114/207
8/12/2019 112_wrirting_easytochangecode
115/207
Test!
115
8/12/2019 112_wrirting_easytochangecode
116/207
You make the mess you clean it up!
116
8/12/2019 112_wrirting_easytochangecode
117/207
8/12/2019 112_wrirting_easytochangecode
118/207
goto
118
8/12/2019 112_wrirting_easytochangecode
119/207
Notifications are a glorified goto
119
8/12/2019 112_wrirting_easytochangecode
120/207
You do not even say where to go!
120
8/12/2019 112_wrirting_easytochangecode
121/207
You can go to more than one place!
121
8/12/2019 112_wrirting_easytochangecode
122/207
8/12/2019 112_wrirting_easytochangecode
123/207
Non-deterministic behavior
Callbacks are unordered
123
8/12/2019 112_wrirting_easytochangecode
124/207
Notifications can complicate change
124
8/12/2019 112_wrirting_easytochangecode
125/207
Not all bad
125
8/12/2019 112_wrirting_easytochangecode
126/207
Notifications promote loose coupling
126
8/12/2019 112_wrirting_easytochangecode
127/207
Model/View/Controller (MVC)
CoreData
127
8/12/2019 112_wrirting_easytochangecode
128/207
will/did
128
8/12/2019 112_wrirting_easytochangecode
129/207
You should know about endpoints
129
8/12/2019 112_wrirting_easytochangecode
130/207
Think twice about other uses
130
8/12/2019 112_wrirting_easytochangecode
131/207
Code can be too loosely coupled
131
8/12/2019 112_wrirting_easytochangecode
132/207
8/12/2019 112_wrirting_easytochangecode
133/207
goto NextTopic;
133
8/12/2019 112_wrirting_easytochangecode
134/207
The 3% solution
134
8/12/2019 112_wrirting_easytochangecode
135/207
8/12/2019 112_wrirting_easytochangecode
136/207
97% of the time
100% - 97% = 3%
136
8/12/2019 112_wrirting_easytochangecode
137/207
Which 3% to worry about?
137
8/12/2019 112_wrirting_easytochangecode
138/207
Memory allocation
View creation
Drawing
Questionable algorithms Questionable data structures
I/O
Blocking on information
Unnecessary work
New work you just added
138
8/12/2019 112_wrirting_easytochangecode
139/207
Optimize when you have measured
139
8/12/2019 112_wrirting_easytochangecode
140/207
8/12/2019 112_wrirting_easytochangecode
141/207
Optimize when you understand
141
8/12/2019 112_wrirting_easytochangecode
142/207
8/12/2019 112_wrirting_easytochangecode
143/207
Optimize slowestand oldest3%
143
8/12/2019 112_wrirting_easytochangecode
144/207
8/12/2019 112_wrirting_easytochangecode
145/207
8/12/2019 112_wrirting_easytochangecode
146/207
Change, test, measure, optimize
146
8/12/2019 112_wrirting_easytochangecode
147/207
The 3% solution
147
8/12/2019 112_wrirting_easytochangecode
148/207
8/12/2019 112_wrirting_easytochangecode
149/207
Implications of change
149
8/12/2019 112_wrirting_easytochangecode
150/207
8/12/2019 112_wrirting_easytochangecode
151/207
!
!
Inheritance trees
Call graphs
151
8/12/2019 112_wrirting_easytochangecode
152/207
!
!
Inheritance trees
Call graphs
152
8/12/2019 112_wrirting_easytochangecode
153/207
8/12/2019 112_wrirting_easytochangecode
154/207
Avoid layers of overridden methods
154
8/12/2019 112_wrirting_easytochangecode
155/207
Use delegation
155
8/12/2019 112_wrirting_easytochangecode
156/207
Customize by calling another object
Keeps conceptual overhead small
Vary customization at runtime as needed
156
8/12/2019 112_wrirting_easytochangecode
157/207
!
!
Inheritance trees
Call graphs
157
8/12/2019 112_wrirting_easytochangecode
158/207
Smaller is better
158
8/12/2019 112_wrirting_easytochangecode
159/207
8/12/2019 112_wrirting_easytochangecode
160/207
8/12/2019 112_wrirting_easytochangecode
161/207
Strive for unidirectional calling
161
8/12/2019 112_wrirting_easytochangecode
162/207
We are all friends here
162
8/12/2019 112_wrirting_easytochangecode
163/207
We are all friends here
163
8/12/2019 112_wrirting_easytochangecode
164/207
We are all friends here
164
8/12/2019 112_wrirting_easytochangecode
165/207
8/12/2019 112_wrirting_easytochangecode
166/207
Rethink relationship
166
8/12/2019 112_wrirting_easytochangecode
167/207
!
!
Inheritance trees
Call graphs
167
8/12/2019 112_wrirting_easytochangecode
168/207
8/12/2019 112_wrirting_easytochangecode
169/207
Purity of essence (OPE)
169
8/12/2019 112_wrirting_easytochangecode
170/207
Model/View/Controller (MVC)
170
8/12/2019 112_wrirting_easytochangecode
171/207
Do not mix model and view changes
171
8/12/2019 112_wrirting_easytochangecode
172/207
Do not mix different things
172
8/12/2019 112_wrirting_easytochangecode
173/207
8/12/2019 112_wrirting_easytochangecode
174/207
Algorithms and data sources
174
8/12/2019 112_wrirting_easytochangecode
175/207
8/12/2019 112_wrirting_easytochangecode
176/207
UX and an interface paradigm
176
8/12/2019 112_wrirting_easytochangecode
177/207
Is this mixing too much?
- (void)setEditing:(BOOL)editing animated:(BOOL)animated;
177
8/12/2019 112_wrirting_easytochangecode
178/207
Hard-code animations?
178
8/12/2019 112_wrirting_easytochangecode
179/207
Multitasking gestures
179
8/12/2019 112_wrirting_easytochangecode
180/207
We change how the system works
180
8/12/2019 112_wrirting_easytochangecode
181/207
App launch without animating hard
181
8/12/2019 112_wrirting_easytochangecode
182/207
Do not mix different things
182
8/12/2019 112_wrirting_easytochangecode
183/207
Purity of essence (OPE)
183
8/12/2019 112_wrirting_easytochangecode
184/207
How do I work this thing?
184
8/12/2019 112_wrirting_easytochangecode
185/207
Bugs are often disappointments
185
8/12/2019 112_wrirting_easytochangecode
186/207
I expected A, you did B
186
8/12/2019 112_wrirting_easytochangecode
187/207
8/12/2019 112_wrirting_easytochangecode
188/207
Hard to use wrong
188
8/12/2019 112_wrirting_easytochangecode
189/207
Method arguments
Assertions and early returns
189
8/12/2019 112_wrirting_easytochangecode
190/207
This will never work
// UIActionSheet.m
- (void)showInView:(UIView *)view{ NSParameterAssert(view != nil);
...}
190
8/12/2019 112_wrirting_easytochangecode
191/207
8/12/2019 112_wrirting_easytochangecode
192/207
What about ivars?
192
8/12/2019 112_wrirting_easytochangecode
193/207
Global variables are bad, right?
193
8/12/2019 112_wrirting_easytochangecode
194/207
Scope is too broad
194
8/12/2019 112_wrirting_easytochangecode
195/207
ivar scope also can be too broad
195
8/12/2019 112_wrirting_easytochangecode
196/207
As few as possible
Simple life-cycles
Avoid tight relationships
Avoid letting non-setter methods change ivars
196
8/12/2019 112_wrirting_easytochangecode
197/207
Hard to manage ivar state?
197
8/12/2019 112_wrirting_easytochangecode
198/207
Use a state machine
198
8/12/2019 112_wrirting_easytochangecode
199/207
UIGestureRecognizers
199
8/12/2019 112_wrirting_easytochangecode
200/207
Multitasking gestures
200
8/12/2019 112_wrirting_easytochangecode
201/207
8/12/2019 112_wrirting_easytochangecode
202/207
Hard to use wrong
202
8/12/2019 112_wrirting_easytochangecode
203/207
How do I work this thing?
203
8/12/2019 112_wrirting_easytochangecode
204/207
Ten things to think about
204
8/12/2019 112_wrirting_easytochangecode
205/207
Ten things to think about
8/12/2019 112_wrirting_easytochangecode
206/207
Ten things to think about
6. Keep new code easy to change
7. Optimize slowest and oldest code
8. Limit dependencies
9. Do not mix different things
10. Make code that is hard to use wrong
206
8/12/2019 112_wrirting_easytochangecode
207/207