Expressive Code: People Matter

Download Report

Transcript Expressive Code: People Matter

Expressive Code:
Micro Design
Greg Vaughn
Sr. Software Technical Specialist
Landsafe, Inc.
[email protected]
Code for People
“Programs must be written for people to
read, and only incidentally for
machines to execute.” – Abelman and
Sussman Structure and Interpretation of Computer
Programs
“Any fool can write code that a computer
can understand. Good programmers
write code that humans can
understand. ” – Martin Fowler
2
Expressive Code
7/20/2015
Monkeys on Your Back
Robust
Requirements
Schedule
Easy to Read,
Easy to Change
Performance
3
Expressive Code
7/20/2015
Monkeys on Your Back
4
Expressive Code
7/20/2015
Why Most Code is Hard to Read
 Tactical vs. Strategic Forces
 Meet the Schedule…NOW!
 Match the Requirements…NOW!
 Make it Robust…Soon
 Make it Perform…Soon
 Make it Easily Maintainable…eh, who cares?
5
Expressive Code
7/20/2015
Why Should I Care?
 Code is easier to write than read
 Audience is really developers
 Not the Computer
 In a few months, you’ll be a stranger to your own
code too
 Object Oriented development is for people
not for computers
 Computer would prefer binary
 45-70% of total software cost is in
maintenance state
6
Expressive Code
7/20/2015
Expressive Design
Definitions
API = Application PROGRAMMER
Interface
Hacking = communicating with computer
Designing = communicating with
programmer
Expressive Code is a part of good
design
At the micro level
7
Expressive Code
7/20/2015
Roadmap
Naming
Formatting
Commenting
Idioms
Guiding
Principles
8
Expressive Code
7/20/2015
Naming
The name of a method is an abstraction,
the body is an implementation
9
Expressive Code
7/20/2015
Use of Names
 How we typically lookup APIs:
1. Look for appropriately named
package and class
2. Look for appropriately named
method
3. Then – maybe – read detailed
comments
 IDE code completion
10
Expressive Code
7/20/2015
Naming Goals
Clear variable and class names
Smaller, well-named methods
Smaller context helps to make
names clearer
IDE code completion
Integer.getInteger() is bad example
11
Expressive Code
7/20/2015
Worst Possible hashCode Method
private int id;
public String getID() {
return “” + id;
}
public int hashCode() {
Integer hashInteger = Integer.getInteger(getID());
if(hashInteger == null) return 0;
else return hashInteger.intValue();
}
 Method name is misleading
 Integer.getInteger(String s) mistaken for Integer.parseInt(String s)
 Actually looks for System.getProperty(s) and converts result to
an Integer
 Should have just returned the id
12
Expressive Code
7/20/2015
Java Naming Conventions
Classes capitalized
Constants all caps
Variables and methods begin with
lower-case
Personal: avoid _ or m_, etc. for
instance variables
Compensation for classes and methods
that are too long
13
Expressive Code
7/20/2015
Expected Names
 Loop counters: i, j, k
 Enumerator: enum
 Iterator: iter
 Exception: e
 Event: evt
 Context should be small and clear enough
that longer names add no value
 Expressive code is not about being verbose
14
Expressive Code
7/20/2015
Choosing Names
Don’t be afraid of a thesaurus
Use common metaphor or naming
system
Use programming vocabulary
Use business vocabulary
15
Expressive Code
7/20/2015
Rules of Thumb
 Ottinger’s Rules for Variable and Class Naming:
 http://www.objectmentor.com/publications/naming.htm
Use pronounceable names
Phone test
Avoid encodings
Clarity (don’t be too cute)
One concept, one word
Bidirectional
16
Expressive Code
7/20/2015
Parts of Speech
Classes (and some interfaces) are
 Nouns or Noun phrases
Subclasses modify superclasses
 Adjectives
Some interfaces modify implementors
 Adjectives
Methods act
 Verbs (Commands or Requests)
17
Expressive Code
7/20/2015
Naming Don’ts
Don’t rely on intuition
Use glossary if you have unique
concepts
Don’t mislead
Capital ‘O’ lower-case ‘l’
Don’t add artificial context
Every class of Joe’s Cool App begins
JCA
18
Expressive Code
7/20/2015
Useless Name Fragments
 Info
 Data
 Class
 Object
 Amount
 Variable
 Type name
 addressString, salaryFloat
 addAddress(Address addr)
19
Expressive Code
7/20/2015
Formatting
20
Expressive Code
7/20/2015
Brace Placement and Indentation
Religious war
But with technical solution
VCS’s can call custom scripts
Use pretty printer pre-checkin
Developers can then format to their
own preference on checkout
Learn your IDE/editor settings
Avoids formatting noise in diffs
Everybody’s happy!
21
Expressive Code
7/20/2015
Reading Code
We typically scan the left edge
So put important stuff there
Method declarations
Conditionals
Loops
Method Calls
Assignments
22
Expressive Code
7/20/2015
Indentation
For quickly scanning code
Learn IDE/editor settings
Expand tabs to 4 spaces
With 4 space indent (Sun’s coding
standard):
Pay a penalty for getting nested too deeply
Separate loop or conditional bodies in
other methods
23
Expressive Code
7/20/2015
Whitespace
Use it to separate “paragraphs”
Variables that will be used in following
loop
Comments to explain following line or
block
Consider whether it should be a
separate method
24
Expressive Code
7/20/2015
Commenting
/* increment i */
25
Expressive Code
7/20/2015
Target Coding Projects
 Typical “bread and butter” business
software
 Not
 Not
 Not
 Not
original CS algorithm study
heavy mathematical simulation
medical devices
space shuttle control systems
 Failure modes of software
 Loss of life
 Financial catastrophe
 Financial discomfort
26
Expressive Code
7/20/2015
Avoid Comments
 Completely self-documenting code is a Platonic
ideal
 Probably not achievable
 But worth pursuing
 Wrong (out of date) comments are worse than no
comments at all
 If you feel the need to add a comment, consider:
 Rename method
 Extract method
 Introduce predicate method (isValidFoo())
 Use explaining variable
27
Expressive Code
7/20/2015
Top Down Commenting
authenticate() {
/* Find out which authentication method to use */
/* If it's a network connection, authenticate host */
/* Prompt user for password */
/* Validate supplied password */
/* If it doesn't match, raise the alarm */
}
 In code:
authenticate() {
findAuthenticationMethod();
if(isNetworkConnection()) authenticateHost();
String password = getPasswordFromUser();
if(!validPassword(password)) {
raiseAlarm();
}
}
28
Expressive Code
7/20/2015
When You Need Comments
Not What
Why
What else you tried
Why it didn’t work
Assumptions
Limitations (to-do)
Reference to algorithm or pattern
Explain API “gotchas”
29
Expressive Code
7/20/2015
Canonical Lousy Comment
for(int i=0; i < elements.length; i++) {
process(elements[i]);
if(elements[i] == 0) {
i++; /*increment i*/
}
}
 What?
 Comment to code ratio could be a design
goal required by Professor Clueless
30
Expressive Code
7/20/2015
Slightly Better Lousy Comment
for(int i=0; i < elements.length; i++) {
process(elements[i]);
if(elements[i] == 0) {
i++; /*ignore next element */
}
}
 Better … but still “what”
31
Expressive Code
7/20/2015
Decent Comment
for(int i=0; i < elements.length; i++) {
process(elements[i]);
if(elements[i] == END_SECTION_MARKER) {
i++; /*padding element for future use*/
}
}
 Explains “why” in both code and comment
32
Expressive Code
7/20/2015
Cross Reference Comments
/* this is used by Parser.readFile() */
Tool compensation
Can get easily out of date and WRONG
It’s hard enough to just keep
comments in sync with adjacent code
– this is hopeless
Just say no
33
Expressive Code
7/20/2015
Comments vs. Tests
Let’s get extreme
Unit Tests capture and explain code
So do comments
Tests tell you when they get out of sync
with the code
Comments are easier to read
JUnit
34
Expressive Code
7/20/2015
Idioms
35
Expressive Code
7/20/2015
Different Meaning to Developers
i++
Implies increment by 1 – always
i += x
Add a number to i
Might be 1 this time, but might not next
time
i = x + y
Implies old value of i is unimportant
36
Expressive Code
7/20/2015
Returning Booleans
Don’t do:
if (boolean) {
return true;
} else {
return false;
}
37
Do:
return boolean;
Expressive Code
7/20/2015
Clean up spaghetti conditionals
DeMorgan’s Laws
!(a && b) = (!a) || (!b)
!(a || b) = (!a) && (!b)
Other useful identities
!(x > y) = (x <= y)
!(x >= y) = (x < y)
Explaining variables
Short circuiting
38
Expressive Code
7/20/2015
Example Credit Application
if(!((score > 700) || ((income >= 40000) &&
!(income > 100000) && authorized &&
(score > 500)) || (income > 100000)) {
reject();
} else {
accept();
}
 Removing some syntactic noise:
if(!(A || (B && !C && D && E) || F)) {
reject();
} else {
accept();
}
39
Expressive Code
7/20/2015
Example Credit Application
boolean lowRisk = (score > 700) || (income > 100000);
boolean marginalRisk = (score > 500) &&
(40000 <= income) && (income <= 100000);
if(lowRisk || (marginalRisk && authorized)) {
accept();
} else {
reject();
}
 Introduced explaining variables
 lowRisk was A || F
 marginalRisk was B && !C && D
 Reversed if/else clauses and removed ‘!’
40
Expressive Code
7/20/2015
Predicate Methods
Complex boolean logic in separate
methods
Well named
isAcceptableRisk()
isUserValid()
canTransitionTo(State s)
41
Expressive Code
7/20/2015
Anti-Example Predicate Method
public static final Boolean isNotRMIModuleEnabled() {
return new Boolean(
!!! isRMIModuleEnabled().booleanValue());
}
 !! = nothing
 Boolean methods should be
expressed in positive
 Don’t call new Boolean(true)
 Instead use Boolean.TRUE
 Apply these rules and the method
disappears!
42
Expressive Code
7/20/2015
Ternary Operator
if(arr.length == 1) {
label.setText(arr.length + “ result found”);
} else {
label.setText(arr.length + “ results found”);
}
Vs.
label.setText(arr.length + ((arr.length == 1) ?
“ result” : “ results”) + “ found”);
 Left edge scan looks for important parts
 label.setText(…
 if(arr.length…
43
Expressive Code
7/20/2015
Default Switch Statement
 Even if your cases cover all possible values,
add a default block so other developers don’t
waste time wondering
 Throw IllegalArgumentException if it is
impossible to reach
 Later edits won’t leave a hole in the possible
values
 Silent failure
44
Expressive Code
7/20/2015
Single Statement Ifs
 If you’re going to avoid brackets, place the
statement at the end of the same line as the
if
 if(specialCase) x += 2;
 Later edits won’t accidentally place a print
statement ahead of the body of the if
if(specialCase)
System.out.println(“special case!”);
x += 2;
Whoops!
45
Expressive Code
7/20/2015
Multiple Exit Points
Don’t fear them
Use if they make things clearer
Better than a bunch of boolean flags
Small methods alleviate concerns
Good for guard clauses
Predicate Methods
46
Expressive Code
7/20/2015
Iterator Idioms
for(Iterator iter = list.iterator(); iter.hasNext();) {
…
Instead of
Iterator iter = list.iterator();
while(iter.hasNext()) {
…
while(true)
Instead of
for(;;)
47
Expressive Code
7/20/2015
Nesting Idiom
DO
if(z.equals(a)) {
…
} else if(z.equals(b)) {
…
} else if(z.equals(c )) {
…
} else {
…
}
DON’T
 This is effectively a
switch, not
subordinate if’s
48
if(z.equals(a)) {
…
} else {
if(z.equals(b)) {
…
} else {
if(z.equals(c )) {
…
} else {
…
}
}
}
Expressive Code
7/20/2015
Error Handling Code
If complex, place in separate method
Success flows should dominate
But sometimes it is clearer to detect
errors and abort first
Guard clauses
If you can’t do anything about an
exception
Declare it in your throws clause
Or wrap it in a layered Exception
49
Expressive Code
7/20/2015
Warning Signs
Excessive Parameter List
Hard for client programmer to keep them
all straight
Probably means a new object is hiding in
there
Have you discovered a new abstraction?
Overuse of instanceof
Replace Reflection with Polymorphism
Should you make a new subclass or
interface?
50
Expressive Code
7/20/2015
Guiding Principles
51
Expressive Code
7/20/2015
Redundancy (and Repetition)
 DRY Principle (Don’t Repeat Yourself)
 “Every piece of knowledge must have a single,
unambiguous, authoritative representation
within a system.” Dave Thomas, Andy Hunt,
Pragmatic Programmer
 Once and Only Once
 Bug fixes won’t have to happen in multiple
places due to “copy and paste reuse”
 Long methods increase the chance of
redundancy
52
Expressive Code
7/20/2015
Goals
 Build classes with language primitives
 loops, threading constructs, data types, etc.
 Build applications with classes
 Create higher abstraction “language” of classes
 Read code!
 Think about why a particular piece is hard or
easy to read
 4 am test
 Would it be clear to you at 4 am?
53
Expressive Code
7/20/2015
Methods for Clarity
Typical thought:
Create methods for reuse
Instead:
Methods label/explain what block of code
does
Reuse is just a handy side effect
54
Expressive Code
7/20/2015
Writing Methods
Save your short term memory
Write sub-methods with names of each
step you need to do
Becomes your to-do list
Helps to keep them short, and well
named
New IDEs will offer to stub those
methods for you – less typing!
55
Expressive Code
7/20/2015
Inefficiencies
 Profile later
 Usually you pay for performance with clarity
 But not always – new String(“…”)
 Hotspot optimizations
 Aggressive inlining, etc.
 Moore’s law is in your favor
 Sometimes it makes more sense to spend money
on hardware
 Good developers are expensive
 Opportunity costs of new features developers
aren’t working on
56
Expressive Code
7/20/2015
Simplicity
Most software is more complex than it
needs to be
Most software is more complex than
other human endeavors
Break rules if it makes things clearer
57
Expressive Code
7/20/2015
Law of Demeter
 “Don’t talk to strangers”.
 Within a method, methods can only be
called on the following objects
1. A parameter of the method, (including this)
a. For pragmatic reasons: static methods of another
class
2. An immediate part object
a. An object returned by calling another method of this
b. An attribute of this
c. An element of a collection which is an attribute of this
3. An object created within the method
 Apply judiciously!
58
Expressive Code
7/20/2015
Minimize Scope
Declare locals just before they are
needed
We’re not writing C code
Should almost always have initializer
for(Iterator …) vs. while(iter)
Keep methods and classes small and
focused
Don’t expose more than needed
59
Expressive Code
7/20/2015
Closing Thoughts
60
Expressive Code
7/20/2015
Maintaining a Mess
Refactor first
Rename Method is one of easiest
refactorings to automate
Extract Method
Appearing in more and more IDEs
Use JRefactory standalone
You’ll have a better chance once the
existing code is clear
61
Expressive Code
7/20/2015
Obfuscated Code Example
class Div{static $1 $_;class $1{void _$(String $_){System.//
out.print($_);}$1(){_();}void _(){int _,$,_$,$$,__,ä=(1<<5),
å=100,ö=12,åö=ä*ö;å-=1<<4;while(åö>0){for($$=_$=_=__=$=(int)
å;_$>($$-(1<<2));_$(""+(char)(_$)),_$-=1<<1)for(_=$=__-9;_>(
$-6);_-=1<<1,_$(""+(char)(_$!=å?_:ä)));char S$=(char)(å+ö+1)
;_$("te"+S$+(char)(ö+(int)S$));åö--;}}}Div(){$_=new $1();}
public static void main(String []$){Div å=new Div();}}
 Or
class Div {
public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
System.out.print(“TIGERteam “);
}
}
}
62
Expressive Code
7/20/2015
Effort – Clarity Curve
 Most code fits between those extremes
 Good News?
 Not Really
Effort
 That’s the lazy solution
 Takes more work to make it clear
 And even more to truly obfuscate it
Clarity
63
Expressive Code
7/20/2015
It’s Finally Working!
 Natural reaction to put it away and move on
 Even if you don’t fully understand why it works
 Coding for machine, not for developers
 Terrible expression of intent
 Refactor
 If it breaks, better you, now, than maintenance
programmer, later
 Might be you!
 Learn something
 Explain “why” in comments
64
Expressive Code
7/20/2015
Stick it to the Maintenance Guy
http://www.dfan.org/writing/comment.html
There was this one hairy part in particular [for
Ultima Underworld AI code] …it had lots of
special cases and weird logic, and after I had
written it I couldn't put it behind me fast enough.
Six months later, I realize that I'm going to have to
muck with this code. "Man," I say to myself, "I
sure hope that I commented this code well when
I originally wrote it." So, with trepidation, I open
up the file and look at the function in question,
and there is exactly one comment in it, at the
very top, and it says:
/* HA HA HA */
65
Expressive Code
7/20/2015
Expressive Code:
Micro Design
Question and Answer
Greg Vaughn
Sr. Software Technical Specialist
Landsafe, Inc.
[email protected]