10 tips for a reusable architecture

55
10 tips for a reusable architecture Jorge D. Ortiz Fuentes @jdortiz

Upload: jorge-ortiz

Post on 02-Jul-2015

3.494 views

Category:

Mobile


0 download

DESCRIPTION

Get some hints on how to write the code of your iOS apps in a more reusable way. This will make you more efficient and happier.

TRANSCRIPT

Page 1: 10 tips for a reusable architecture

10 tips for a reusable

architectureJorge D. Ortiz Fuentes

@jdortiz

Page 2: 10 tips for a reusable architecture

A POWWAU production

Page 3: 10 tips for a reusable architecture

Agenda

★Goal

★Principles

★Tips

★Q&A

Page 4: 10 tips for a reusable architecture

Goal

Page 5: 10 tips for a reusable architecture

Write code that can be used as

many times & in as many projects as

possible.

Page 6: 10 tips for a reusable architecture

Principles

Page 7: 10 tips for a reusable architecture

SOLID

★Single Responsibility

★Open/Closed

★ Liskov Substitution

★ Interface Segregation

★Dependency Inversion

Page 8: 10 tips for a reusable architecture

Tips

Page 9: 10 tips for a reusable architecture

Forgive me, because I am going to sin

★The following are tips, not rules.

★They might not apply to your code.

★But I would, at least, think about them.

Page 10: 10 tips for a reusable architecture

1.

Page 11: 10 tips for a reusable architecture

Don’t write reusable code

Page 12: 10 tips for a reusable architecture

Don’t write start with reusable

code

Page 13: 10 tips for a reusable architecture

Don’t start with reusable code

★Start with the right idea

★But don’t need the perfect code

★You can always refactor

★Shipped is better than perfect

Page 14: 10 tips for a reusable architecture

2.

Page 15: 10 tips for a reusable architecture

But don’t commit code that is clearly not reusable

Page 16: 10 tips for a reusable architecture

Commit reusable code

★Do the Right Thing™ before committing to the development branch or any shared branches.

★Be a good boy scout: If you revisit the code and it can be improved, do so.

Page 17: 10 tips for a reusable architecture

3.

Page 18: 10 tips for a reusable architecture

Move all the business logic to

the model

Page 19: 10 tips for a reusable architecture

Move to the model★Model > Data

★Business rules

• Behaviors

• Validation

• Importing & exporting

• Migration

Page 20: 10 tips for a reusable architecture

Instead of- (IBAction) importPasteText:(id)sender { UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; if ([pasteboard containsPasteboardTypes:@[@"public.utf8-plain-text", @"public.text"]]) { NSInteger rejectedItems = 0; CheckItem *newItem = nil; [self.undoManager beginUndoGrouping]; NSString *textToImport = [pasteboard.string copy]; NSArray *items = [textToImport componentsSeparatedByString:@"\n"]; NSUInteger objectNumber = 0; if ([[self.itemsTableViewDataSource.fetchedResultsController sections] count] > 0) { id <NSFetchedResultsSectionInfo> sectionInfo = [self.itemsTableViewDataSource.fetchedResultsController sections][0]; objectNumber = [sectionInfo numberOfObjects]; } for (NSString *item in items) { NSArray *itemComponents = [item componentsSeparatedByString:@":"]; NSString *itemName = [itemComponents[0] stringByTrimmingCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]]; if ([itemName length] > 0) { …

Page 21: 10 tips for a reusable architecture

do- (IBAction) importPasteText:(id)sender { UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; if ([pasteboard containsPasteboardTypes:@[@“public.utf8-plain-text", @"public.text"]]) { [self.undoManager beginUndoGrouping]; [self.model importItemsInChecklist: self.checklist fromString:pasteboard.string]; [self.undoManager endUndoGrouping]; } }

Page 22: 10 tips for a reusable architecture

4.

Page 23: 10 tips for a reusable architecture

Don’t put presentation logic

into the model

Page 24: 10 tips for a reusable architecture

Presentation logic

★ It isn’t business logic, but “UI logic”

★ In the VC, it could be inconsistent, better “centralized”.

★ It shouldn’t be in the model.

★ It can contain UI dependent information (colors, fonts,…).

Page 25: 10 tips for a reusable architecture

Instead of

// Set label to “3 days left” - (void) displayRemainingTime { self.remainingLabel.text = [self.task remainingTime]; }

Page 26: 10 tips for a reusable architecture

do

// Set label to “3 days left” - (void) displayRemainingTime { TaskPresenter *tp = [[TaskPresenter alloc] initWithTask:self.task]; self.remainingLabel.text = [tp remainingTime]; }

Page 27: 10 tips for a reusable architecture

5.

Page 28: 10 tips for a reusable architecture

Put the network closer to the

model (instead of View Controller)

Page 29: 10 tips for a reusable architecture

Network code★The view controller is responsible for responding events:

• lifecycle

• UI generated

★Controlling networking is OK

★Doing networking is wrong

★ In the model or a category:

• Provide business logic with network functionality

• Handle concurrency

Page 30: 10 tips for a reusable architecture

6.

Page 31: 10 tips for a reusable architecture

Make classes for Data Sources &

Delegates of table views

Page 32: 10 tips for a reusable architecture

Data Source & Delegate Objects

★ It exceeds VC responsibilities

★Responsibility: View model

★They can be reused

Page 33: 10 tips for a reusable architecture

Instead of

// @interface MyVC: UITableViewController

@implementation MyVC { //implicit (in super) // self.tableView.dataSource = self; // self.tableView.delegate = self; }

Page 34: 10 tips for a reusable architecture

do// @interface MyVC: UITableViewController @interface MyVC @property (strong) MyDataSrc *myDataSrc; @end

@implementation MyVC - (void) viewDidLoad { [self assignDataSource]; }

- (void) assignDataSource { self.myDataSrc = [[MyDataSrc alloc] initWithMOC:self.moc]; self.myDataSrc.fetchedResourceController.delegate.self; self.tableView.dataSource = self; [self.myDataSource performFetch]; } @end

Page 35: 10 tips for a reusable architecture

7.

Page 36: 10 tips for a reusable architecture

But then, don’t let them take

care of the views

Page 37: 10 tips for a reusable architecture

DataSource & Delegate responsibilities

★Metadata: How many rows, sections…

★Act on data: add or delete row

★Provide views, view info and present data

★Act on selections

Page 38: 10 tips for a reusable architecture

Use a delegateMyVC MyDataSrc

numberOfSectionInTableView:tableView:numberOfRowsInSection:tableView:cellForRowAtIndexPath:

displayObj

ect:inCell

Page 39: 10 tips for a reusable architecture

TableViewViewModelDelegate

@protocol TableViewViewModelDelegate <NSObject>

- (NSString *) cellIdentifier; - (CGFloat) cellHeight; - (UITableViewCell *) displayObject:(NSManagedObject *)object inCell:(UITableViewCell *)cell; - (NSString *) headerIdentifier; - (CGFloat) headerHeight; - (UITableViewHeaderFooterView *) displayObject:(NSManagedObject *)object inHeader:(UITableViewHeaderFooterView *)header; @optional - (void) didSelectObject:(NSManagedObject *)object; - (void) didSelectAccessoryForObject:(NSManagedObject *)object;

@end

Page 40: 10 tips for a reusable architecture

8.

Page 41: 10 tips for a reusable architecture

Test your code

Page 42: 10 tips for a reusable architecture

Test

★Reusable code = code + tests

★Tests contain

• Validation

• Assumptions

• Documentation

Page 43: 10 tips for a reusable architecture

Test your Core Data model

@implementation CoreDataTestCase - (void) setUp { [super setUp]; [self createCoreDataStack]; }

- (void) createCoreDataStack { NSBundle *bundle = [NSBundle bundleForClass:[self class]]; model = [NSManagedObjectModel mergedModelFromBundles:@[bundle]]; coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; store = [coordinator addPersistentStoreWithType: NSInMemoryStoreType configuration: nil URL: nil options: nil error: NULL]; context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; context.persistentStoreCoordinator = coordinator; }

Page 44: 10 tips for a reusable architecture

Test your view controllers

- (void) setUp { [super setUp];

[self createFixture]; [self createSut]; }

- (void) createSut { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil]; sut = [storyboard instantiateViewControllerWithIdentifier:viewControllerID]; sut.data = data; }

Page 45: 10 tips for a reusable architecture

Test your view controllers (2)

- (void) testOnViewDidLoadTitleIsSetToChecklistName { [sut view];

XCTAssertTrue([sut.title isEqualToString:sut.checklist.name], @"View controller title must be set to the checklist name"); }

Page 46: 10 tips for a reusable architecture

9.

Page 47: 10 tips for a reusable architecture

Break up your Storyboards into

workflows

Page 48: 10 tips for a reusable architecture

Huge StoryboardsSomething to avoid

Page 49: 10 tips for a reusable architecture

Workflows★Huge Storyboards:

• Teams get conflicts in the Storyboards often

• Difficult to maintain

★Better Storyboards:

• One per workflow (sign in/sign up, statistics, preferences)

• Even combine with XIB (useful for cells)

Page 50: 10 tips for a reusable architecture

Load another Storyboard

- (IBAction) displayReport:(id)sender { UIViewController *reportVC = [[UIStoryboard storyboardWithName:reportStoryboard bundle:nil] instantiateInitialViewController]; [self presentViewController:reportVC animated:YES completion:nil]; }

Page 51: 10 tips for a reusable architecture

10.

Page 52: 10 tips for a reusable architecture

Create your own modules

Page 53: 10 tips for a reusable architecture

Modular code

★ iOS support

• Until iOS 8: only static libraries (no resources, separated headers)

• iOS 8: frameworks

★Cocoapods: allow to share open source code

Page 54: 10 tips for a reusable architecture

Create a pod★ Isolate the code (use pod-template)

★Create .podspec & LICENSE

★pod lib create coolpod

★ In your Podfile:

• pod ‘coolpod', :git => 'https://server/repoURL/coolpod.git'

Page 55: 10 tips for a reusable architecture

Thank you!

Images courtesy of Shutterstock