Upload
oursky
View
42
Download
1
Embed Size (px)
Citation preview
Clean Code⇧⌘KEdwin Kwok
Monday, 11 March, 13
Clean CodeTitle: Clean Code: A Handbook of Agile Software Craftsmanship
Author: Robert C. Martin (Uncle Bob)
Monday, 11 March, 13
Why Clean Code?
Monday, 11 March, 13
Why Clean Code?
0
10
20
30
40
50
60
70
80
90
100
0 500 1000 2000 2500 3000 3500 4000
Productivity Ratio vs Time
Monday, 11 March, 13
Smart vs ProfessionalSmart
Great Coding Skill
Write advanced code
String r; // lowercase url
Monday, 11 March, 13
Smart vs ProfessionalSmart
Great Coding Skill
Write advanced code
String r; // lowercase url
Professional
Readable code
Maintainable code
String lowercaseUrl;
Monday, 11 March, 13
NameChoose your names thoughtfully
If a name requires a comment, the name does not reveal its intent
Monday, 11 March, 13
NameChoose your names thoughtfully
If a name requires a comment, the name does not reveal its intent
int d;
What does it mean? Days? Diameter?
Monday, 11 March, 13
NameChoose your names thoughtfully
If a name requires a comment, the name does not reveal its intent
int d;
What does it mean? Days? Diameter?
int d; //elapsed time in days
Is this any better?
Monday, 11 March, 13
NameChoose your names thoughtfully
If a name requires a comment, the name does not reveal its intent
int d;
What does it mean? Days? Diameter?
int elapsedTimeInDays;
What about this?
int d; //elapsed time in days
Is this any better?
Monday, 11 March, 13
NameChoose part of speech well
method / function => verb
class / object => noun
def authentication # ...end
def authenticate # ...end
Monday, 11 March, 13
Nameuse Pronounceable Names
class DtaRcrd102 { private Date genymdhms; private Date modymdhms; private final String pszqint = “102”;}
class Customer { private Date generationTimestamp; private Date modificationTimestamp; private final String recordId = “102”;}
Monday, 11 March, 13
Names...Avoid encodings
public class Part { private String mName; void setName(String name) { mName = name; }}
public class Part { private String name; void setName(String name) { this.name = name; }}
Hungarian notation
bBusy: booleanchInitial: charcApples: count of itemsfpPrice: floating-pointdbPi: double (Systems)pFoo: pointer
Monday, 11 March, 13
Discussion:Android vs IOS
ListView listView = new ListView(context);listView.setAdapter(anAdapter);
UITableView tableView = [[UITableView alloc] initWithFrame:aFrame style:UITableViewStylePlain];tableView.datasource = aDataSource;
Android:
IOS:
Which one is better?
Monday, 11 March, 13
AdapterThe adapter pattern is adapting between classes and objects, like a bridge between two objects.
e.g.
SimpleCursorAdapter
ArrayAdapterMonday, 11 March, 13
AdapterTitle: Design Patterns: Elements of Reusable Object-Oriented Software
Author:
John Vlissides
Richard Helm
Ralph Johnson
Erich Gamma
Monday, 11 March, 13
Use Case (Philips)UITabBarController
Adapter
UITableViewController
Monday, 11 March, 13
Use design pattern as name
Use Solution Domain Names, e.g.
AccountVisitor
JobQueue
LabelObserver
SimpleCursorAdapter
Monday, 11 March, 13
Singleton
https://www.youtube.com/watch?v=-FRm3VPhseI
Monday, 11 March, 13
Singleton
https://www.youtube.com/watch?v=-FRm3VPhseI
v.s.Global Object
Monday, 11 March, 13
Deceptive APItestCharge() { CreditCard cc; cc = new CreditCard(“1234567890121234”); cc.charge(100);}
java.lang.NullPointerExceptionat talk.CreditCard.charge(CreditCard.java:49)
Monday, 11 March, 13
Deceptive APItestCharge() { CreditCardProcessor.init(...); CreditCard cc; cc = new CreditCard(“1234567890121234”); cc.charge(100);}
java.lang.NullPointerExceptionat talk.CreditCardProcessor.init(CreditCardProcessor.java:146)
Monday, 11 March, 13
Deceptive APItestCharge() { OffineQueue.start(); CreditCardProcessor.init(...); CreditCard cc; cc = new CreditCard(“1234567890121234”); cc.charge(100);}
java.lang.NullPointerExceptionat talk.OfflineQueue.start (OfflineQueue.java:16)
Monday, 11 March, 13
Deceptive APItestCharge() { Database.connect(...); OffineQueue.start(); CreditCardProcessor.init(...); CreditCard cc; cc = new CreditCard(“1234567890121234”); cc.charge(100);}
CreditCard API lies
It pretends to not need the CreditCardProcessor
The API doesn’t tell the exact order of the initialization
Monday, 11 March, 13
Deceptive APItestCharge() { database = new Database(...); queue = new OfflineQueue(database); creditCardProcessor = new CreditCardProcessor(queue); CreditCard cc; cc = new CreditCard(“1234567890121234”, creditCardProcessor); cc.charge(100);}
Dependency injection enforces the order of initialization at compile time.
Monday, 11 March, 13
Discussion:Object passing in Android?
How to pass objects to another Activity?
Monday, 11 March, 13
Comment
Monday, 11 March, 13
Comment
//* no Comments *//
Monday, 11 March, 13
Comment
Comment doesn’t make your code becomes good code
//* no Comments *//
Monday, 11 March, 13
Good CommentsInformative Comments
// format matched kk:mm:ss EEE, MMM dd, yyyyPattern timePattern = Pattern.compile( “\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*”);
Todo Comments/* TODO: All calls to getPage should actually come here, and be relative to the current page, not the parent page. It was a gross error to have the whole wiki know that references were relative to the parent instead of the page. */
Pubic API documentation
Monday, 11 March, 13
Bad Comments
Redundant Comments
/** * The processor delay for this component. */protected int backgroundProcessorDelay = -1;
/** * The container event listeners for this Container. */protected ArrayList listeners = new ArrayList();
Monday, 11 March, 13
Bad CommentsAttribution Comments/* Added by Gary */Big Banner Comments// **********************// * Instance Variables *// *********************private int myVariable;
// ***********************// * Default Constructor *// ***********************public MyClass() {}
Monday, 11 March, 13
Mumbling
/* For bug FS-13005, we had to add this. The bug was that the Now Playing screen was somehow being launched, in that viewDidAppear was being called, but the view was not being shown on the screen. The Now Playing screen then when on to do all it's stuff and the user was left looking at an incomplete Mode screen. So the "fix" is to kill off any residual Now Playing screen that is under the Mode tab whenever we start a new connection to a radio. */
What is FS-13005?
Sorry! I have no idea what you are talking about.
Monday, 11 March, 13
Horizontal Alignment@interface Tape : NSObject {! NSString *_brushName;! NSString *_headImageNamed;! NSString *_bodyImageNamed;! NSString *_tailImageNamed;! CGFloat _opacity;! BOOL! _includeShadow;! NSString *_text;! NSString *_fontName;! CGFloat! _fontSize;! NSString *_colorHex;! NSDictionary *_all;}
@interface Tape : NSObject {! NSString *_brushName;! NSString *_headImageNamed;! NSString *_bodyImageNamed;! NSString *_tailImageNamed;! CGFloat _opacity;! BOOL! _includeShadow;! NSString *_text;! NSString *_fontName;! CGFloat! _fontSize;! NSString *_colorHex;! NSDictionary *_all;}
Monday, 11 March, 13
Function
should be Small
does one thing
the ideal number of arguments for a function is .... 0
the less arguments, the better
try not to more than 3 arguments
Monday, 11 March, 13
Function
No Side effects
// do something or answer something, but not bothpublic boolean set(String attribute, String value);
if (attributeExists(“username”)) { setAttribute(“username”, “Ben”);}
Monday, 11 March, 13
Class
Avoid God Class
In OO, God Class is a class that does lots of things
example: UITableViewController
Monday, 11 March, 13
Data Structure and Objectpublic class Square { public Point topLeft; public double side;}
public class Geometry { public double calculateArea(Object shape) throws noSuchShapeException { if (shape instanceof Square) { Square square = (Square)shape; return square.side * square.side; } else if (shape instanceof Rectangle) { Rectangle rectangle = (Rectangle)shape; return rectangle.height * rectangle.width; } throw new NoSuchShapeException(); }}
public class Rectangle { public Point topLeft; public double height; public double width;}
Monday, 11 March, 13
Data Structure and Objectpublic class Square implements Shape { public Point topLeft; public double side; public double area() { return side*side; }}
public class Rectangle implements Shape{ public Point topLeft; public double height; public double width; public double area() { return height * width; }}
Monday, 11 March, 13
Data Structure and ObjectProcedural Code (code using data structure)
Pros: easy to add new functions without changing existing data structure
Cons: hard to add new data structure all the functions must change
OO code
Pros: easy to add new classes without changing existing function
Cons: hard to a new function as all classes must change
Monday, 11 March, 13
Data Structure and ObjectProcedural Code (code using data structure)
Pros: easy to add new functions without changing existing data structure
Cons: hard to add new data structure all the functions must change
OO code
Pros: easy to add new classes without changing existing function
Cons: hard to a new function as all classes must change
Avoid Hybrids
Monday, 11 March, 13
How About ActiveRecord?
Monday, 11 March, 13
Error HandlingPrefer exceptions to returning error codes
if (deletePage(page) == E_OK) { if (registry.deleteReference(page.name) == E_OK) { if (configKeys.deleteKey(page.name.makeKey() == E_OK) { logger.log(“page deleted”); } else { logger.log(“configKey not deleted”); } } else { logger.log(“deleteReference from registry failed”); }} else { logger.log(“delete failed”); return E_ERROR;}
Monday, 11 March, 13
Error Handlingprefer exceptions to returning error codes
try { deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey());} catch (Exception e) { logger.log(e.getMessage());}
easier to find the normal path
avoid nested conditions
Monday, 11 March, 13
Error Handling
Don’t Return Null
List<Employee> employees = getEmployees();if (employees != null) { for (Employee e : employees) { totalPay += e.getPay(); }}
Monday, 11 March, 13
Error Handling
Don’t Return Null
List<Employee> employees = getEmployees();for (Employee e : employees) { totalPay += e.getPay();}
public List<Employee> getEmployees() { if (/* there are no employees */) { return Collections.emptyList(); }}
Monday, 11 March, 13
SOLID
Single Responsibility Principle
Open Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency inversion Principle
Monday, 11 March, 13
Single Responsibility PrincipleLabelBox Cloud Labels
Monday, 11 March, 13
Architecture
Monday, 11 March, 13
Monday, 11 March, 13
Architecture
The Lost Years
http://www.youtube.com/watch?v=WpkDN78P884
The Web (Rails) is a Delivery Mechanism!
Monday, 11 March, 13
Test - a real scenario
...
client server
workerss3
1. upload a video
2. store in s33. start worker and
send request to worker
4. dedicated worker pulls the file from s3 and do transcoding
Monday, 11 March, 13
TestRemove FEAR during Development
You know you break something during testing.
For example:
Rugby - ~178 tests
Refer to Ben’s presentation
https://speakerdeck.com/oursky/testing
Monday, 11 March, 13
Test
FIRST
Fast
Independent
Repeatable
Self-validating
Timely
Monday, 11 March, 13
RefactorTitle:Refactoring: Improving the Design of Existing Code
Author:
Martin Fowler
Kent Beck
John Brant
William Opdyke
Don RobertsMonday, 11 March, 13
Familiar With your Tools
try to familiar with your tools before coding, don’t create messy stuffs by your first impression
do testing before adopting to the real code
read the API, doc and Google
ask others ...
Monday, 11 March, 13
Quiz (javascript)The expected output of the following javascript is alert count down from 5 to 0. Explain why it doesn’t work and fix the bug.
function count (num) { for (var i = 0; i <= num; i += 1) { setTimeout(function () { alert(num - i); }, i * 1000); }}count(5);
Monday, 11 March, 13
Quiz (javascript)function count (num) { for (var i = 0; i <= num; i += 1) { (function (time) { setTimeout(function () { alert(num - time); }, time * 1000); }(i)); }}count(5);
Monday, 11 March, 13
Quiz (javascript) cont.
function changeAnchorsToLightBox(anchors) { var length = anchors.length; for (var i = 0; i < length; i++) { anchors[i].onclick = function () { lightBox.open(anchors[i]); return false; }; }}
Monday, 11 March, 13
Quiz (javascript) cont.function changeAnchorsToLightBox(anchors) { var length = anchors.length; for (var i = 0; i < length; i++) { (function (anchor) { anchor.onclick = function () { lightBox.open(anchor); return false; }; }(anchors[i])); }}
Monday, 11 March, 13
Quiz (javascript) cont.function changeAnchorsToLightBox(anchors) { var length = anchors.length; for (var i = 0; i < length; i++) { (function (anchor) { anchor.onclick = function () { lightBox.open(anchor); return false; }; }(anchors[i])); }}
Monday, 11 March, 13
Reference
Clean Code: A Handbook of Agile Software Craftsmanship
http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
The Clean Code Talks - "Global State and Singletons"
https://www.youtube.com/watch?v=-FRm3VPhseI
Monday, 11 March, 13
Q & A and ...
“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
Martin Fowler:
Monday, 11 March, 13