64
Clean Code ⇧⌘K Edwin Kwok Monday, 11 March, 13

How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

  • Upload
    oursky

  • View
    42

  • Download
    1

Embed Size (px)

Citation preview

Page 1: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Clean Code⇧⌘KEdwin Kwok

Monday, 11 March, 13

Provided to you by
Open source development kit for mobile, web & IoT apps
Skygear.io
Skygear.io
Page 2: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Clean CodeTitle: Clean Code: A Handbook of Agile Software Craftsmanship

Author: Robert C. Martin (Uncle Bob)

Monday, 11 March, 13

Skygear.io
Page 3: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Why Clean Code?

Monday, 11 March, 13

Skygear.io
Page 4: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 5: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Smart vs ProfessionalSmart

Great Coding Skill

Write advanced code

String r; // lowercase url

Monday, 11 March, 13

Skygear.io
Page 6: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Smart vs ProfessionalSmart

Great Coding Skill

Write advanced code

String r; // lowercase url

Professional

Readable code

Maintainable code

String lowercaseUrl;

Monday, 11 March, 13

Skygear.io
Page 7: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

NameChoose your names thoughtfully

If a name requires a comment, the name does not reveal its intent

Monday, 11 March, 13

Skygear.io
Page 8: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 9: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 10: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 11: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

NameChoose part of speech well

method / function => verb

class / object => noun

def authentication # ...end

def authenticate # ...end

Monday, 11 March, 13

Skygear.io
Page 12: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 14: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 15: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

AdapterThe adapter pattern is adapting between classes and objects, like a bridge between two objects.

e.g.

SimpleCursorAdapter

ArrayAdapterMonday, 11 March, 13

Skygear.io
Page 16: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

AdapterTitle: Design Patterns: Elements of Reusable Object-Oriented Software

Author:

John Vlissides

Richard Helm

Ralph Johnson

Erich Gamma

Monday, 11 March, 13

Skygear.io
Page 17: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Use Case (Philips)UITabBarController

Adapter

UITableViewController

Monday, 11 March, 13

Skygear.io
Page 18: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Use design pattern as name

Use Solution Domain Names, e.g.

AccountVisitor

JobQueue

LabelObserver

SimpleCursorAdapter

Monday, 11 March, 13

Skygear.io
Page 19: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Singleton

https://www.youtube.com/watch?v=-FRm3VPhseI

Monday, 11 March, 13

Skygear.io
Page 20: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Singleton

https://www.youtube.com/watch?v=-FRm3VPhseI

v.s.Global Object

Monday, 11 March, 13

Skygear.io
Page 21: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Deceptive APItestCharge() { CreditCard cc; cc = new CreditCard(“1234567890121234”); cc.charge(100);}

java.lang.NullPointerExceptionat talk.CreditCard.charge(CreditCard.java:49)

Monday, 11 March, 13

Skygear.io
Page 22: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 23: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 24: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 25: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 26: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Discussion:Object passing in Android?

How to pass objects to another Activity?

Monday, 11 March, 13

Skygear.io
Page 27: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Comment

Monday, 11 March, 13

Skygear.io
Page 28: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Comment

//* no Comments *//

Monday, 11 March, 13

Skygear.io
Page 29: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Comment

Comment doesn’t make your code becomes good code

//* no Comments *//

Monday, 11 March, 13

Skygear.io
Page 30: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 31: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 32: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Bad CommentsAttribution Comments/* Added by Gary */Big Banner Comments// **********************// * Instance Variables *// *********************private int myVariable;

// ***********************// * Default Constructor *// ***********************public MyClass() {}

Monday, 11 March, 13

Skygear.io
Page 33: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 34: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 35: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 36: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 37: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Class

Avoid God Class

In OO, God Class is a class that does lots of things

example: UITableViewController

Monday, 11 March, 13

Skygear.io
Page 38: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 39: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 40: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 41: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 42: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

How About ActiveRecord?

Monday, 11 March, 13

Page 43: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 44: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 45: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Error Handling

Don’t Return Null

List<Employee> employees = getEmployees();if (employees != null) { for (Employee e : employees) { totalPay += e.getPay(); }}

Monday, 11 March, 13

Skygear.io
Page 46: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 47: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

SOLID

Single Responsibility Principle

Open Closed Principle

Liskov Substitution Principle

Interface Segregation Principle

Dependency inversion Principle

Monday, 11 March, 13

Skygear.io
Page 48: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Single Responsibility PrincipleLabelBox Cloud Labels

Monday, 11 March, 13

Skygear.io
Page 49: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Architecture

Monday, 11 March, 13

Skygear.io
Page 50: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Monday, 11 March, 13

Skygear.io
Page 51: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Architecture

The Lost Years

http://www.youtube.com/watch?v=WpkDN78P884

The Web (Rails) is a Delivery Mechanism!

Monday, 11 March, 13

Skygear.io
Page 52: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 53: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 54: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Test

FIRST

Fast

Independent

Repeatable

Self-validating

Timely

Monday, 11 March, 13

Skygear.io
Page 55: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

RefactorTitle:Refactoring: Improving the Design of Existing Code

Author:

Martin Fowler

Kent Beck

John Brant

William Opdyke

Don RobertsMonday, 11 March, 13

Skygear.io
Page 56: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 57: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 58: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Skygear.io
Page 59: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 60: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 61: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 62: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 63: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

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

Skygear.io
Page 64: How to write better code: in-depth best practices for writing readable, simple, extendable and efficient code (Part I)

Brought to you by Oursky

Build your mobile app fast skygear.io (open source)