Top Banner
Writing clean code Mobiquity - Ángel García (Mobile developer)
42

Writing clean code

Jul 15, 2015

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Writing clean code

Writing clean codeMobiquity - Ángel García (Mobile developer)

Page 2: Writing clean code

What is all this about?

Page 3: Writing clean code

Table of contents• What is clean code? • Why is readability important? • Code style

• Code formatting • Naming conventions • Code comments

• Code structure • Control sentences • Functions and methods • Classes

• Architecture level • Modules • Software patterns • Programming paradigms

• Tools

Page 4: Writing clean code

Before we startA bit of context

Page 5: Writing clean code

• No universal definition !

• Difference between clean code, working code and good code • Clean code: readable, maintainable, extensible • Working code: does what it is supposed to do • Good code: combination of clean and working code

What is clean code?

Working code

Clean code

Good code

Page 6: Writing clean code

Why is readability important?• The process of changing code:

1. Find component 2. Find affected lines 3. Write 4. Test !

• Reading —> 80/20 !

• Readability: • Save your time • Improve maintenance • Increase extensibility

Page 7: Writing clean code

Code formattingReAD Ing iS nO t Al Wa iS aS E as Y As IT cO uLd bE

Page 8: Writing clean code

Code formatting{"id":10,"childs":[{"id":1,"title":"A"},{"id":2,"title":"B"}],"active": true,"title": "Hello World”}

{ "id": 10, "childs": [ { "id": 1, "title": "A" }, { "id": 2, "title": "B" } ], "active": true, "title": "Hello World" }

Page 9: Writing clean code

Code formatting• Brain is good on recognising patterns

• Vertical space • Horizontal space • Expressions • Casing !

• Text search along project !

• Follow language styles !

• Be consistent

Page 10: Writing clean code

Naming conventionsWhat the hell does this mean?

Page 11: Writing clean code

Naming conventions• The importance of naming. What does this code do? !func doMyStuff(param1: Bool, param2: Bool, param3:Int) -> Int { if param3 > 0 { var a = 0 if param3 % 2 == 0 && param2 { a = param3 } else if param3 % 2 == 1 && param1 { a = param3 } return a + doMyStuff(param1, param2, param3 - 1) } else { return 0 } } !doMyStuff(true, true, 4)

Page 12: Writing clean code

Naming conventions• The importance of naming. What does this code do? !func summation(fromNumber:Int, includeEven: Bool = true, includeOdd: Bool = true) -> Int { if fromNumber > 0 { var currentSum = 0 if fromNumber % 2 == 0 && includeOdd { currentSum = fromNumber } else if fromNumber % 2 == 1 && includeEven { currentSum = fromNumber } return currentSum + summation(fromNumber - 1, includeEven: includeEven, includeOdd: includeOdd) } else { return 0 } } !summation(4)

Page 13: Writing clean code

Naming conventions• Names should be explicit and clear temp.active = YES; product.active = YES; !

!• Provide context inactiveProducts.count; !!

• Avoid shortcuts !

• Avoid Business/Technical names when possible !

• Follow language conventions (ivars, setters/getters, casing,…) !

• Be consistent (remove/delete, create/insert,…)

Page 14: Writing clean code

Code comments“Now hiring now. Right now we are hiring now”

Page 15: Writing clean code

Code comments• Issues

• Can be outdated (misleading) • Require language switch

!• Types

• Redundant //Start reachability notifications [[Reachability reachabilityForInternetConnection] startNotifier]; !!

• Separate blocks with different responsibilities - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)index { //Create cell UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier]; … //Configure cell … return cell; } !

• Commented-out code

Page 16: Writing clean code

Code comments• Code is not self-explanatory • Code has side effects

//Careful! setting delegate reloads table content self.tableView.delegate = self; !

• Domain specific (complex math, business rules,…) • Public APIs in libs

/** Loads Purchase history and returns MOReceipts @param block Block executed when the history is loaded. Contains parsed MOReceipts @param errorBlock Block executed when an error occurs */ - (void)updateReceiptsOnSuccess:(MOResponseArrayBlock)block error:(MOErrorBlock)errorBlock;

!

• In general, avoid comments

Page 17: Writing clean code

Control sentencesWhere the linear flow ends

Page 18: Writing clean code

Control sentences• Format • Conditionals:

• Simple expressions —> variables if (price - price * discountPercentage + discountAmount < minimumPrice) { println("Difficult clause") } !let amountToPay = price - price * discountPercentage + discountAmount if (amountToPay < minimumPrice) {} !

• Do not use more than 3 or 4 expressions • Prefer positive clauses

var notForbidden = false if !notForbidden {}

! !• Do not use assignments or side effects

if ((x = y * 2) != 0) {} if (self = [super init]) {} if (condition && [self destroyObject]) {}

Page 19: Writing clean code

Control sentences• Avoid Spaghetti code (nested depth < 3)

if (condition1) { if (condition2) { for(i = 0; i < 10; i++) { if (condition4) { if (condition5) { } return; } } } } ! !

• Collapse when possible if (condition1) { if (condition2) { } } !if (condition1 && condition2) { } !

• Do not use goto, break, continue

Page 20: Writing clean code

Control sentences• “if” statements

• Avoid empty cases • Avoid obvious “else if” clauses

if flag { } else if !flag { println("Difficult to read") }

• “for” loops • Do not abuse

for (;condition;) { /*...*/ } • Do not modify the conditional variable inside

for (i = 0; i < 10; i++) { i *= 2; } !

• Ternary operators • Only use for assignments

condition? [self method1] : [self method2]; name = user.name? : @"Anonymous"; !

• Must be extremely simple

Page 21: Writing clean code

Functions and methodsYour code in small steps

Page 22: Writing clean code

Functions and methods• Clear naming

summation(4) !

• 1 Level of abstraction let dates = downloadAndParse(“http://myrurl.com”)

!• Single Responsibility Principle (SRP)

“Every context should have a single responsibility, and that responsibility should be entirely encapsulated by the context” - Wikipedia !

• No side effects !

• Explicit error handling - (BOOL)writeToURL:(NSURL *)aURL options:(NSDataWritingOptions)mask error:(NSError **)errorPtr;

Page 23: Writing clean code

Functions and methods• Parameters

• Prefer over instance variables (or globals/statics) • Avoid output • Reduce amount (<4) [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0] !

• 1 point of exit !

• Remove empty methods or only calling super !

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { } return self; }

Page 24: Writing clean code

ClassesYour building blocks

Page 25: Writing clean code

Classes• SRP. Check yourself:

• Name should describe responsibility • Describe functionality without “and”, “or”, “but”, “if” • Do you have flags? !

• Open-Close principle “Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification” - Wikipedia !• Hide all implementation details • Simplify public headers/methods/properties !

• Explicit dependencies !

• Sort you methods and properties (public/private)

Page 26: Writing clean code

Classes• Avoid statics

!

• Use polymorphism if (a.isKindOfClass(MyClass)) { !

!• Take advantage of categories

MyProjectUtils.convertToUrlEncoding("hello") StringUtils.convertToUrlEncoding(“hello") “hello".convertToUrlEncoding() !"hello".drawInRect(rect:rect, withAttributes: attributes) !

• Sort your toolbox!

Page 27: Writing clean code

ModulesIntegrating all the pieces

Page 28: Writing clean code

Modules• SoC

“Design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program”. Wikipedia !

• Explicit • API • Callbacks (protocols, blocks,…) • Threads !

• Split by functionality vs type !

• Hide internals !

• Structure your data - (NSDictionary *)findNearestPersonToLocation:(NSArray *)coordinates; - (Person *)findNearestPersonToLocation:(CLLocationCoordinate2D)coordinate;

Page 29: Writing clean code

Modules• Dependencies

• Law of Demeter “LoD can be succinctly summarized in one of the following ways: • Each unit should have only limited knowledge about other units: only units "closely" related to the current unit. • Each unit should only talk to its friends; don't talk to strangers. • Only talk to your immediate friends.”. Wikipedia

!aVar.getB().getC() !

!• Avoid cycles

!

• Prefer Interfaces vs concrete classes !

• Isolate lifecycle !

• Make proper use of Software patterns

A B C

Page 30: Writing clean code

Software patternsEverybody can ride a bike

Page 31: Writing clean code

Software patterns• Robust, flexible and well known solutions

!

• Reduce cognitive load “Among psychologists it is widely acknowledged that, compared to "cold" learning, people learn more effectively when they can build on what they already understand”. Wikipedia. !

• Some of most interesting: • MVC / MVVM • Inheritance / Composition • Inversion Of Control / Dependency Injection • Delegate/Observer • Factory • Chain Of Responsibility • ….

Page 32: Writing clean code

MVC• Model

• Contains information in Plain objects • Connects to endpoints, DB,.…

• View • Draws the screen • Receives/passes events to/from controllers

• Controller • Connects the View and the Model layers !

• Most common pitfalls in iOS • Massive controllers (DataSources, components,…) • Controllers doing Model/View work • View & Controller coupling

!

• Alternative: MVVM (Model-View-ViewModel)

Page 33: Writing clean code

Inheritance vs Composition

• Inheritance is good for “is-a” relations • Use composition as default

Inheritance Composition

Difficult to keep SRP Easy to keep SRP

Details from base class to subclasses Close components

Massive base classes Small components

Behaviour on compilation time Behaviour on runtime

Page 34: Writing clean code

Inversion of Control / Dependency Injection• Increase reusability of modules • Lifecycle controlled on system level • IoC

• Invert relation code-3rd party • Generic API definitions • Dependencies are provided

• DI • Dependencies are injected (constructors, setters)

!class TextEditor { var checker = SpellCheckerES() //TextEditor coupled with ES checker } !class TextEditor { var checker: SpellChecker init(checker: SpellChecker) { self.checker = checker //Implementation of checker decided by DI controller } }

Page 35: Writing clean code

Programming paradigmsLearning from others

Page 36: Writing clean code

Aspect Oriented Programming• Ideal for cross-cutting concerns

!

• Hooks code before/after methods !

• Aspects (https://github.com/steipete/Aspects) [UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo, BOOL animated) { NSLog(@"View Controller will appear"); } error:nil];

Page 37: Writing clean code

Reactive programming• Ideal for event-driven datasources

!

• Automatic propagation of changes !

• Reduces/hides state • Time independent code

!

• Reactive Cocoa (https://github.com/ReactiveCocoa/ReactiveCocoa) RAC(self.logInButton, enabled) = [RACSignal

combineLatest:@[ self.usernameTextField.rac_textSignal, self.passwordTextField.rac_textSignal, RACObserve(LoginManager.sharedManager, loggingIn) ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn) { return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue); }];

Page 38: Writing clean code

Functional programming• Mimic mathematical functions

!

• Avoids state !

• Outputs only dependent on inputs • No side effects • Parallelizable • Predictable (race conditions) !

• Chainable operations !

let evenSum = Array(1...10) .filter { (number) in number % 2 == 0 } .reduce(0) { (total, number) in total + number }

Page 39: Writing clean code

ToolsComputers can also help you

Page 40: Writing clean code

Tools• Uncrustify (http://uncrustify.sourceforge.net/)

!

• OCLint (http://oclint.org/) !

• Sonar for Objective-C (https://github.com/octo-technology) !

• Objc-dependency-visualizer (https://github.com/PaulTaykalo/objc-dependency-visualizer)

Page 41: Writing clean code

References• Clean code: A handbook of Agile Software Craftsmanship

!

!

!

!

!

!

!

!

!

!

• Objc.io (http://www.objc.io/)

Page 42: Writing clean code

Thank you!Q&A