iOS Development
Methodology
Applying Best Practices to the Xcode World
Thursday, July 25, 13
This is a “Guided Exploration...
Tom von Schwerdtner
SmartLogic
smartlogic.io
twitter.com/tvon
github.com/tvon
Thursday, July 25, 13
So you understand my p...
What you’re in for
• Xcode’s bad influences
• Organization and Separation of Concerns
• Testing, and in Isolation
Code: htt...
Xcode’s Bad Influences
Thursday, July 25, 13
Xcode’s Bad Influences
• Lack of Project Structure
• Questionable Templates
Thursday, July 25, 13
Two primary gripes.
Files...
Solutions
• Create Folders for Groups
• Strip Comments
• Avoid UITableViewController
Thursday, July 25, 13
First and forem...
Better Templates
github.com/mneorr/Alcatraz/
Alcatraz - Xcode Plugin Manager
Thursday, July 25, 13
Use Alcatraz.
We have t...
Better Templates
github.com/mneorr/Alcatraz/
Alcatraz - Xcode Plugin Manager
(or build from scratch, it’s good practice)
T...
Organization and
Separation of Concerns
Thursday, July 25, 13
What are Concerns?
• Roles within the Application
• View Controllers
• Views
• Services
• Models
• Delegates (protocol imp...
How to Separate?
• Organize into groups/folders
• Keep as isolated as possible
• Stand-alone protocol implementations
Thur...
Data Source Isolation
Thursday, July 25, 13
A DataSource can be extremely simple.
Expose NSMutableArray “items” to be setu...
Data Source Isolation
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPa...
DataSource Isolation
- (void)viewDidLoad
{
// (minor setup code)
// WidgetCellIdentifier declared in data source header
[s...
Testing, and in Isolation
Thursday, July 25, 13
Testing in isolation means testing individual components without relying o...
A Note on Tools
• BDD Tool: Kiwi
• Web Mocking: Nocilla
• (Ditch whatever Xcode gives you)
Thursday, July 25, 13
Hitting t...
A Category Test
Testing the parsing of a timestamp string to an
NSDate
Thursday, July 25, 13
This is a good first test. It ...
A Category Test
describe(@"NSDate+Timestamps", ^{
it(@"Initializes an NSDate from a timestamp string", ^{
NSString *timest...
Implementation
Thursday, July 25, 13
If we TDD this, we should first get a “no known class method with selector...” error.
Implementation
+(id)dateWithTimestamp:(NSString *)string
{
return [NSDate date];
}
Thursday, July 25, 13
Implement the bar...
Implementation
+(id)dateWithTimestamp:(NSString *)string
{
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]...
Testing a Data Source
Thursday, July 25, 13
This is where we test our stand alone data source.
By splitting out the class,...
Testing a Data Source
describe(@"WidgetsTableDataSource", ^{
it(@"Returns WidgetCell configured with correct Widget", ^{
U...
Testing a Data Source
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPa...
Exercises for the Reader
• Test WidgetCell configuration
• Isolate the Data Source Test (don’t rely on widget cell)
Thursda...
Questions?
smartlogic.io
twitter.com/smartlogic
github.com/smartlogic
facebook.com/smartlogic
Thursday, July 25, 13
So tha...
Upcoming SlideShare
Loading in …5
×

iOS Development Methodology

1,767 views

Published on

A walkthrough of iOS development methodology from SmartLogic's Tom von Schwerdtner.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,767
On SlideShare
0
From Embeds
0
Number of Embeds
29
Actions
Shares
0
Downloads
29
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

iOS Development Methodology

  1. 1. iOS Development Methodology Applying Best Practices to the Xcode World Thursday, July 25, 13 This is a “Guided Exploration”, though I will be talking a lot. Please feel free to ask questions at any time, I’d like this to be more of a discussion than a presentation. the Ruby community has been preaching test-first Agile methodologies for years, even if you don’t entirely buy into what they are saying, they are pushing the discussion forward and improving their best practices. Today I want to talk about applying some of these practices to iOS/ Objective-C development in Xcode.
  2. 2. Tom von Schwerdtner SmartLogic smartlogic.io twitter.com/tvon github.com/tvon Thursday, July 25, 13 So you understand my perspective... Developing websites for over 10 years Ruby for past 2.5 years iOS for past 1.5 years
  3. 3. What you’re in for • Xcode’s bad influences • Organization and Separation of Concerns • Testing, and in Isolation Code: https://github.com/smartlogic/ios-best-practices or http://goo.gl/skgRY Thursday, July 25, 13 This is what we’re going to talk about This talk is aimed at beginner to intermediate developers (but hopefully something for everyone) Some familiarity with the structure of iOS apps is somewhat necessary.
  4. 4. Xcode’s Bad Influences Thursday, July 25, 13
  5. 5. Xcode’s Bad Influences • Lack of Project Structure • Questionable Templates Thursday, July 25, 13 Two primary gripes. Filesystem does not match project organization Lousy for any non-xcode view of the project (github/bitbucket)
  6. 6. Solutions • Create Folders for Groups • Strip Comments • Avoid UITableViewController Thursday, July 25, 13 First and foremost you can actually create folders for groups. Ensures files added to that group will default to that folder. UItableViewController adds unecessary noise (more on that later) File comments are redundant in the world of git.
  7. 7. Better Templates github.com/mneorr/Alcatraz/ Alcatraz - Xcode Plugin Manager Thursday, July 25, 13 Use Alcatraz. We have templates that should show up there soon. Starting with an empty Xcode project is good practice. It is important to know all the steps required to get to that Master-Detail view example
  8. 8. Better Templates github.com/mneorr/Alcatraz/ Alcatraz - Xcode Plugin Manager (or build from scratch, it’s good practice) Thursday, July 25, 13 Use Alcatraz. We have templates that should show up there soon. Starting with an empty Xcode project is good practice. It is important to know all the steps required to get to that Master-Detail view example
  9. 9. Organization and Separation of Concerns Thursday, July 25, 13
  10. 10. What are Concerns? • Roles within the Application • View Controllers • Views • Services • Models • Delegates (protocol implementations) Thursday, July 25, 13 Concerns are the different components that make up your application. Controllers generally coordinate other objects (models, views, services and delegates) The other objects should essentially worry about themselves.
  11. 11. How to Separate? • Organize into groups/folders • Keep as isolated as possible • Stand-alone protocol implementations Thursday, July 25, 13 Organization is important, just put each in it’s own place Isolation may take some practice, let’s touch on that real quick.
  12. 12. Data Source Isolation Thursday, July 25, 13 A DataSource can be extremely simple. Expose NSMutableArray “items” to be setup externally Put Cell configuration code in the cell.
  13. 13. Data Source Isolation - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { WidgetCell *cell = [tableView dequeueReusableCellWithIdentifier:WidgetCellIdentifier forIndexPath:indexPath]; [cell configure:[self.items objectAtIndex:indexPath.row]]; return cell; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.items count]; } Thursday, July 25, 13 A DataSource can be extremely simple. Expose NSMutableArray “items” to be setup externally Put Cell configuration code in the cell.
  14. 14. DataSource Isolation - (void)viewDidLoad { // (minor setup code) // WidgetCellIdentifier declared in data source header [self.tableView registerClass:[WidgetCell class] forCellReuseIdentifier:WidgetCellIdentifier]; self.dataSource = [[WidgetsTableDataSource alloc] init]; self.tableView.dataSource = self.dataSource; [WidgetAPIService getWidgets:^(NSMutableArray *widgets) { self.dataSource.items = widgets; [self.tableView reloadData]; }]; } Thursday, July 25, 13 The entire UIViewController is basically the viewDidLoad method. Our service loads items based on an API call. This gives us a nicely isolated data source. This is a good lead in to testing in isolation
  15. 15. Testing, and in Isolation Thursday, July 25, 13 Testing in isolation means testing individual components without relying on external components. If you need to be sold on testing, in short it allows you to change and refactor your code and knowing that doing so doesn’t break anything (or finding it and fixing it). It reduces the
  16. 16. A Note on Tools • BDD Tool: Kiwi • Web Mocking: Nocilla • (Ditch whatever Xcode gives you) Thursday, July 25, 13 Hitting the network for every test is just a bad idea. I like to test against a dev server until tests are greeen, then stub requests.
  17. 17. A Category Test Testing the parsing of a timestamp string to an NSDate Thursday, July 25, 13 This is a good first test. It is isolated by nature (being a category). This is a legitimate test, whenever you are parsing a string to turn it into something else you should test that your parsing works.
  18. 18. A Category Test describe(@"NSDate+Timestamps", ^{ it(@"Initializes an NSDate from a timestamp string", ^{ NSString *timestamp = @"2010-02-03T04:05:06Z"; NSDate *date = [NSDate dateWithTimestamp:timestamp]; NSUInteger units = NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit| NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit; NSDateComponents *components = [[NSCalendar currentCalendar] components:units fromDate:date]; [[theValue(components.year) should] equal:theValue(2010)]; [[theValue(components.month) should] equal:theValue(2)]; [[theValue(components.day) should] equal:theValue(3)]; [[theValue(components.hour) should] equal:theValue(4)]; [[theValue(components.minute) should] equal:theValue(5)]; [[theValue(components.second) should] equal:theValue(6)]; }); }); Thursday, July 25, 13 Our test. Give it a timestamp string, expect a proper NSDate back.
  19. 19. Implementation Thursday, July 25, 13 If we TDD this, we should first get a “no known class method with selector...” error.
  20. 20. Implementation +(id)dateWithTimestamp:(NSString *)string { return [NSDate date]; } Thursday, July 25, 13 Implement the bare minimum to get past that error, and we get an NSDate but all of the values are wrong.
  21. 21. Implementation +(id)dateWithTimestamp:(NSString *)string { NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; return [dateFormatter dateFromString:string]; } Thursday, July 25, 13 At this point we implement the method and the test should pass.
  22. 22. Testing a Data Source Thursday, July 25, 13 This is where we test our stand alone data source. By splitting out the class, we can now test it without involving the view controller (and any weight that may carry)
  23. 23. Testing a Data Source describe(@"WidgetsTableDataSource", ^{ it(@"Returns WidgetCell configured with correct Widget", ^{ UITableView *tableView = [[UITableView alloc] init]; WidgetsTableDataSource *dataSource = [[WidgetsTableDataSource alloc] init]; Widget *widgetOne =[[Widget alloc] init]; widgetOne.name = @"First Widget"; Widget *widgetTwo =[[Widget alloc] init]; widgetTwo.name = @"Second Widget"; dataSource.items = [@[widgetOne, widgetTwo] mutableCopy]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; UITableViewCell *widgetCell = [tableView cellForRowAtIndexPath:indexPath]; [[((WidgetCell *)widgetCell).nameLabel.text should] equal:@"First Widget"]; }); }); Thursday, July 25, 13 Step through. We initialize a table view (data source methods require it) We initialize our data source We add two widgets to the data source items. We verify that cellForRowAtIndexPath returns the correct cell data. Note that this somewhat inadvertently tests WidgetCell, but that is not our concern so much as the verification that the right cell is returned. Why test something this simple? Well, they say that the two hardest things in computer science are cache invalidation, naming things and off-by-one errors. Besides which, your items array could be a more complex collection.
  24. 24. Testing a Data Source - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { WidgetCell *cell = [tableView dequeueReusableCellWithIdentifier:WidgetCellIdentifier forIndexPath:indexPath]; [cell configure:[self.items objectAtIndex:indexPath.row]]; return cell; } Thursday, July 25, 13 Once again, the Data Source implementation. Very simple.
  25. 25. Exercises for the Reader • Test WidgetCell configuration • Isolate the Data Source Test (don’t rely on widget cell) Thursday, July 25, 13 There are improvements that could be made here, if interested.
  26. 26. Questions? smartlogic.io twitter.com/smartlogic github.com/smartlogic facebook.com/smartlogic Thursday, July 25, 13 So that’s it. Depending on time left we can discuss testing techniques, organization or even work on a particular problem if someone has something they’d like to discuss.

×