Date post: | 22-Dec-2015 |
Category: |
Documents |
View: | 214 times |
Download: | 0 times |
1
Style-Oriented Approaches
2
<spartan.programming>
3
Before Spartanization (1/2) public int compare(Object o1, Object o2) {
if (!(o1 instanceof Cookie)) { throw new ClassCastException(o1.getClass().getName()); } if (!(o2 instanceof Cookie)) { throw new ClassCastException(o2.getClass().getName()); } Cookie c1 = (Cookie) o1; Cookie c2 = (Cookie) o2;
// Continues on next slide...
4
Before Spartanization (2/2) if (c1.getPath() == null && c2.getPath() == null) { return 0; } else if (c1.getPath() == null) { // null is assumed to be "/" if (c2.getPath().equals(CookieSpec.PATH_DELIM)) { return 0; } else { return -1; } } else if (c2.getPath() == null) { // null is assumed to be "/" if (c1.getPath().equals(CookieSpec.PATH_DELIM)) { return 0; } else { return 1; } } else { return c1.getPath().compareTo(c2.getPath()); } }
5
After Spartanization
public int compare(Object o1, Object o2) {
String p1 = ((Cookie) o1).getPath();
String p2 = ((Cookie) o2).getPath();
if (p1 == null && p2 == null)
return 0;
if (p2 == null)
return p1.equals(CookieSpec.PATH_DELIM) ? 0 : 1;
if (p1 == null)
return p2.equals(CookieSpec.PATH_DELIM) ? 0 : -1;
return p1.compareTo(p2);
}
6
Approach: Spartan Programming• Philosophy:
• Bugs are due to inability to see all the code at once• Static simplicity => Dynamic simplicity• Methods are the groundwork of programs• 7 +/- 2 Rule
Values• Understandability• Loose Coupling• Strong Cohesion• Continuity• Compos-ability
• Principles• Eliminate duplications• Minimization of: #lines, #columns, #tokens, #characters, #variables, #branches
• Practices• Frugal use of Variables• Small Interfaces• Minimal use of Control• Careful use of Screen Space
“Minimalism isn't always the right choice, but it's rarely the wrong choice”
7
Frugal use of Variables
Minimize:• Number• Scope• Accessibility • Variability • Name length• Life time• The use of arrays
8
Small Interfaces
• Minimize the number of parameters• Minimize side-affecting parameters
• Parameter kind priority• Input parameters• Output parameters• Input-output parameters• Pass by name
9
Minimal use of Control
• Avoid conditionals • Ternary operator (cond ? a : b)• Polymorphic messages• Encapsulation of logic inside classes
• Compact blocks• Early exits• Short branch first• Avoid deep nesting
• Avoid looping - functional style
10
Careful use of Screen Space
• K&R Style• Eliminate unnecessary parenthesis/braces• Refactor code into helper methods
• Shortens the primary method
• “Hand rule”: Width, Height
11
A Recipe for an Ideal Class
•Prefixed with a 1-2 lines javadoc comment•Less than 4 instance fields – preferably final•Priority: no accessors, getter only, getter + setter•Final fields can be public•3-4 public methods•Less than 100 LOC•Methods are less than 10 lines•enable(), disable() rather than setEnabled(boolean b)•Must override toString() •All fields initialized by constructor•Short variable names: $, m, o, etc.•Order: Fields, constructors, toString(), equals(), hash(), public
methods, private methods
•Most warnings turned on (in particular, “un-used XXX”)
12
An Even Stricter Approach
•One level of indentation per method•The “else” keyword is forbidden•Wrap all primitives and strings•One dot per line•Don’t abbreviate names•class < 50 LOC, package < 10 classes•Less than three instance fields•A collection field precludes other fields•No getters/setters
Jeff Bay, “Object Calisthenics”The ThoughtWorks Anthology
13
</spartan.programming>
14
<cohesion>
15
Low Cohesion
// class DatePanel
public void processKey(KeyEvent e) { ... if ((keycode == KeyEvent.VK_LEFT) || (keycode == 226))
update(Calendar.DAY_OF_YEAR, -1); if ((keycode == KeyEvent.VK_RIGHT) || (keycode == 227)) update(Calendar.DAY_OF_YEAR, 1); if ((keycode == KeyEvent.VK_PAGE_UP)) update(Calendar.MONTH, -1); ... if ((!e.isControlDown()) && (!e.isShiftDown())) { model.clearSelection(); if (e.isShiftDown()) model.addSelection(model.getDate()); ...
16
High Cohesion // class DatePanel public void processKey(KeyEvent e) {
boolean changed = updateCalendar(e.getKeyCode()); if (changed) updateModel(e); fireKeyListenerKeyPressed(e); }
private boolean updateCalendar(int keycode) { if ((keycode == KeyEvent.VK_LEFT) || (keycode == 226)) update(Calendar.DAY_OF_YEAR, -1); else if ((keycode == ...) update(...) else return false; return true; }
private void updateModel(KeyEvent e) { if ((!e.isControlDown()) ...
17
</cohesion>
18
<coupling>
19
Coupling w/ ResultSet private List<String> names = new ArrayList<String>();
public void collectNames(ResultSet rs, int n) { for(int i = 0; i < n; ++i) { if(!rs.next()) return; names.add(rs.getString(0));
} }
20
Coupling w/ Iterator
private List<String> names = new ArrayList<String>();
public void collectNames(Iterator<String> iter, int n) { for(int i = 0; i < n; ++i) { if(!iter.hasNext()) return; names.add(iter.next()); } }
21
Even Less Coupling
public interface Processor { public void process(String s); }
public void setProcessor(Processor arg) { p = arg; }
private Processor p;
public void collectNames(Iterator<String> iter, int n) { for(int i = 0; i < n; ++i) { if(!iter.hasNext()) return; p.process(iter.next()); } }
// => More Versatility, but less easy to use
22
</coupling>
23
<naming>
24
General• Highly important
• Understandability without delving into details
• Avoid hiding of fields with variables
• A good metaphor may help: Figure, Page
• Classes – Nouns• File• Account• SymbolTable
• Methods – Verbs• open()• withdraw()• lookup()
25
Types •Nouns: Figure, Account
• Sometimes –er suffix: Formatter, Loader
•Popularity => Simple name• Frequent usage: typing a variable• Frequent usage: superclass
•Communicate similarities & differences• Add a prefix to the superclass
class TextFormatter extends Formatter { ... }
•Avoid “Object” in class names
•Single form for enum typesenum Pet { CAT, DOG }
26
Interfaces vs .Classes
•Interfaces will usually be a popular type
class ColoredFigure implements Figure { ... }
•-able is a common suffix for interfaces• Denotes a mixin-like protocol unit
•If both interface & concrete class are popular
abstract class AbstractFigure implements IFigure { ... }
class Figure extends AbstractFigure { ... }
27
Common Naming Schemes
InterfaceSuperclassRoot ClassSub Classes
FigureAbstractFigureDefaultFigure
FigureAbstractFigureConcreteFigure
FigureColoredFigureResizableColoredFigureFixedColoredFigure
IFigureAbstractFigureFigure
ResizableFigureResizableFigure
28
Methods
•Verbs: paint(), remove()
•boolean setters/getters• isVisible()• setVisible(boolean)• show(), hide() // More explicit
•Getters• getX()• x()
•Setters• setX(int)• x(int)
29
Variables•result•results•count, n•curr, each•i, j•arg•List<Message> messages•Map<String,String> addressFromName •that•lhs, rhs•iconA, iconB•Event event; Painter painter;•Event e; Painter p;•isEmpty; // Better than: if(!notEmpty) ...
30
<hungarian.notation>
31
Hungarian Notation is Bad
•Prefix specifies the type/stroage of the variable
•C• ulDistance = Unsigned Long• bEnabled = Boolean • paulData = Pointer to Array of Unsigned Long• szName = Zero terminated String
•Java• pX = Parameter• fY = Field (sometimes “m” for Member)• sfZ = Static Field
•Considered outdated (or even evil)• Overly verbose• Obviated by: smart IDEs, short methods/classes
32
Hungarian Notation is Great
•Prefix specifies “pseudo subtype”
•Pseudo subtypes examples:• Integers: Row vs. Column• Integers: Dollars vs. Cents• Strings: text vs. HTML
33
Is Address HTML-ed?
String str = person.getDetails(“address”);...
String adr = str;
...
record.setField(“location", adr);
...
String address = record.getField(“location"); ...
out.println(“Send to: <i>” + address + “</i>”); // Did we remember to call htmlEncode() ??
34
Hungarian Notation to the Rescue
Let’s apply this convention
•Strings coming from the user are considered text• Must be stored in variables prefixed with “t”• The same goes for database columns
•htmlEncode() translates a “t” prefix to “h”• Strings returned from htmlEncode() are considered HTML• Must be stored in a variable prefixed with “h”
•Assignments allowed only if prefixes match
35
Is tAddress HTML-ed? String tStr = person.getDetails(“address”);
...
String tAdr = tStr;
...
record.setField(“tLocation", tAdr);
...
String tAddress = record.getField(“tLocation");
...
out.println(“Send to: <i>” + tAddress + “</i>”); // Clearly, tAddress was not htmlEnocde-d
36
Rename: tAddress => hAddress String tStr = getOrderDetails(“address”);
...
String tAdr = tStr;
...
record.setField(“tLocation", tAdr);
...
String hAddress = record.getField(“tLocation"); // violation of our convention !!
...
out.println(“Send to: <i>” + hAddress + “</i>”);
37
Correct Code – All Prefixes Match String tStr = getOrderDetails(“address”);
...
String tAdr = tStr;
...
record.setField(“tLocation", tAdr);
...
String hAddress = htmlEncode(record.getField(“tLocation"));
...
out.println(“Send to: <i>” + hAddress + “</i>”);
38
</hungarian.notation>
39
</naming>
40
Eyetracking
41
Benefits of Narrow Code
•We don’t read stuff on the right-hand side•Stacktrace•Debugability of if statements•Debugability of return values•Explaining variables
•=> Prefer tall, narrow code• Over short, wide
42
Fix it in the language
“For example, I want the next C grammar to define that a space comes between any keyword and an opening parenthesis. "if (foo)" would be legal, but "if(foo)" would not. Not a warning, not optionally checked, but actually forbidden by the language parser. Flat out illegal. Can't compile.
... There is not now, nor will there ever be, a programming style whose benefit
is significantly greater than any of the common styles. Get real. Discovering a style that improves your productivity by more than a few percent over the common styles is about as likely as discovering a new position for sex.”
Ken Arnold, “Style is Substance”www.artima.com