The Eleventh Principle: An idiom should only implement the functionality needed.

This is a continuation of the blog post 12 Principles of Good Software Design.

11. An idiom should only implement the functionality needed.

One of the coolest things about writing software is that we are creating something out of virtually nothing but our imagination and our ability to design something that works. And so it allows us to test our pet theories about architectural design, about the best way to solve problems with designs that are extensible and which can be generalized to solve even larger problems.

The temptation to do this exists on all projects. Even though we are warned constantly about premature optimization, we still do the equivalent when it comes to solving the immediate problems we have in front of us by extending them to more generalized solutions which we expect will help us in the future. But they almost never do: instead of providing us an easily extensible architecture which can solve future problems, we instead create something too complicated to maintain. And the new problems we face don’t fit into the solution we previously built.

Years ago I wrote an essay on how not to write Factorial in Java.

Another example of solving problems we don’t have yet, only to make things confusing: suppose we have a table view which only shows a subset of the items in the table depending on a bit of business logic. This business logic essentially filters out the results of the table according to a function which takes an object from our database and determines if it should be visible or not.

In the process we decide that what we really need here is considerable flexibility in determining if rows are visible or not.

So we decide to use the Specification Pattern, which provides us nearly unlimited flexibility in assembling simple conditional statements into complex logic classes. We build our specification protocol:

@class ModelObject;

@protocol Specification <NSObject>
- (BOOL)isVisible:(ModelObject *)obj;
@end

and we build our classes which handle the various boolean operations:

#import "Specification.h"

@interface AndSpecification : NSObject <Specification>
- (id)initWithLeft:(id<Specification>)left right:(id<Specification>)right;
@end

@interface OrSpecification : NSObject <Specification>
- (id)initWithLeft:(id<Specification>)left right:(id<Specification>)right;
@end

@interface NotSpecification : NSObject <Specification>
- (id)initWithSpecification:(id<Specification>)spec;
@end

And of course comes our test classes which test potential propositions:

@interface HasNameSpecification : NSObject<Specification>
- (BOOL)isVisible:(ModelObject *)obj;
@end

@interface HasAddressSpecification : NSObject<Specification>
- (BOOL)isVisible:(ModelObject *)obj;
@end

Our View Controller class then runs our filter as we refresh the contents:

@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (strong, nonatomic) id<Specification> filter;
@property (strong, nonatomic) NSMutableArray<ModelObject *> *allObjects;
@property (strong, nonatomic) NSMutableArray<ModelObject *> *filtered;
... (other fields) ...
@end

...

- (void)refreshContents
{
	[self.filtered removeAllObjects];
	for (ModelObject *obj in self.allObjects) {
		if ([self.filter isVisible:obj]) {
			[self.filtered addObject:obj];
		}
	}
	[self.tableView reloadData];
}

For now, of course, we only have one filter–so we construct that by hand in the viewDidLoad method:

- (void)viewDidLoad {
	[super viewDidLoad];
	...
	self.filter = [[AndSpecification alloc] initWithLeft:[[HasNameSpecification alloc] init] right:[[HasAddressSpecification alloc] init]];
	...
}

Nearly a half-dozen classes, a hundred lines of glue code or so, but we are now prepared for that future request we know that is coming, of a server which may send over an arbitrary filter specification to our client which alters the behavior of what items we show on the table view.

This design model is conceptually relatively easy, too: if we have other predicates we may filter against, such as if the zip code is well formed or if the phone number is present, we simply create new classes for each test–then assemble them into a tree hierarchy for evaluation.

And when the back end sends us a promised XML file which contains the new filter specification, such as:

<or>
    <filter name="HasName"/>
    <filter name="HasAddress"/>
</or>

we can easily parse that using our specification classes and reload the filter used in our code.


A beautiful architectural generality to solve the present problem of filtering items if they have a name and address against a general purpose structure that can form any filter we can imagine from an arbitrary specification.

But will we ever use this generalized solution?


Well, in order to support this filter method, the back end needs to send an XML specification for the new filter. The XML needs to be authored–which implies a back-end page which administrators can go to in order to create new filters. The page needs to be created and maintained; the database entries need to be built and tested, the end-user administrators need to be trained, and the new filters need to be validated before they are deployed.

That’s a lot of back-end work.

Instead of sending this XML, it would be far easier to simply send a single keyword or index: “filterNameAddress” for our present filter, or “filterNameOrAddress” for an Or operation. Or even better, that could be represented by a magic number.

Dozens of lines of code in our application, and in the end, this is how we’d wind up using our classes:

- (void)viewDidLoad {
	[super viewDidLoad];
	...
	switch (self.filterIndex) {
		default:
		case FILTER_NAME_ADDRESS:
			self.filter = [[AndSpecification alloc] initWithLeft:[[HasNameSpecification alloc] init] right:[[HasAddressSpecification alloc] init]];
			break;
		case FILTER_NAME_OR_ADDRESS:
			self.filter = [[OrSpecification alloc] initWithLeft:[[HasNameSpecification alloc] init] right:[[HasAddressSpecification alloc] init]];
			break;
	}
	...
}

Meanwhile we could have eliminated the nearly half dozen classes with two methods and a switch statement instead:

- (void)refreshContents
{
	[self.filtered removeAllObjects];
	for (ModelObject *obj in self.allObjects) {
		BOOL addFlag;
		switch (self.filterIndex) {
			default:
			case FILTER_NAME_ADDRESS:
				addFlag = [self testNameAddress:obj];
				break;
			case FILTER_NAME_OR_ADDRESS:
				addFlag = [self testNameOrAddress:obj];
				break;
		}
		if (addFlag) {
			[self.filtered addObject:obj];
		}
	}
	[self.tableView reloadData];
}

Worse, this is how our code would evolve. In the present, we haven’t reached that point. Our present problem is to filter against one pre-existing filter, so why couldn’t have we written this instead?

- (void)refreshContents
{
	[self.filtered removeAllObjects];
	for (ModelObject *obj in self.allObjects) {
		if (obj.name && obj.address) {
			[self.filtered addObject:obj];
		}
	}
	[self.tableView reloadData];
}

Dozens of lines of specification code scattered across 5 separate classes against a protocol interface which is hard for a programmer to understand–literally replaced by one line of code:

if (obj.name && obj.address) ...

And that’s nearly a half-dozen classes and dozens of lines of code we now have to maintain, explain, and explain why we’re doing things the hard way–for a future that never came.


Life is hard enough as a software developer for us to solve problems we don’t currently have.

The Tenth Principle: An idiom should not require extraordinary steps to compile or break the existing development tool set.

This is a continuation of the blog post 12 Principles of Good Software Design.

10. An idiom should not require extraordinary steps to compile or break the existing development tool set.

I guarantee this will be my most controversial comment, given how common it is for developers to want to customize their build processes to supposedly make things easier for them. And when we work by ourselves, it’s enticing to do things our own ways, to customize our environments to add new and time saving processes.

But when we work with a team, or when we work on products for a larger organization, those custom tools can create more problems than they solve. One person’s time saving plugin is another person’s confusing plugin, one person’s custom method to build a product is another person’s tool breaking dependency.

As an example, suppose you wish to integrate Maven with Xcode to automatically handle checking out and building a product. According to this article on Stack Overflow, you would need to downgrade to an earlier version of Maven. Yet when we downgrade Maven on a computer, we potentially create other dependency issues if–for example–we’re building Java on the same computer.

We also see similar integration problems with CocoaPods, as features in Xcode represent a moving target that CocoaPods sometimes fails to keep up with.

It’s not to suggest there is a problem with either of these projects. But because they are not part of the standard tool chain, sometimes the standard tool chain can break, creating problems for the development team. And those breaks must be weighed against the benefit provided by these tools. For example, project requirements may force the use of CocoaPods for third party library integration, and you just have to deal with the occasional problems that arise.

But if you are integrating just one library, the extra machinery introduced by CocoaPods may not be worth the trouble of simply downloading the library and linking directly to it.


Other problems can arise when a team doesn’t know or doesn’t use the tool chains for a particular language in a standard way.

For example, it is possible to build a Java application which is built using make, using tools such as emacs to edit the code. One could build an Android application this way, using the command-line tools in the Android application. One can–with the application of the right command line arguments–even ignore the standard hierarchical directory structure that usually accompanies a Java application.

For example, suppose we have a very simple Java program which prints “Hello World”:

package com.chaosinmotion.testbuild;

public class Main
{
	public static void main(String[] args)
	{
		System.out.println("Hello world.");
	}
}

and we wish to build a jar file which can be executed using java -jar test.jar.

So we create our manifest file:

Main-Class: com.chaosinmotion.testbuild.Main

And we build our Makefile:

com/chaosinmotion/testbuild/%.class: %.java
	javac $< -d .

test.jar: com/chaosinmotion/testbuild/Main.class
	jar cmf manifest test.jar com/chaosinmotion/testbuild/Main.class

Our file directory looks like:

src/
    Main.java
    Makefile
    manifest

And when we run make on the command line we get the jar file we want.


Did I just offend all the experienced Java programmers here? 😈


Yes, you can build Java applications this way. You can even build Android applications this way: all of the steps in the Android build process ultimately triggers command-line tools that can just as easily be fired from a Makefile.

But you wouldn’t want to, because it subverts the common Java development paradigms used by most Java development tools.

By not maintaining the source kit directory structure that most Java development kits expect, you cannot move your code to Android Studio or Eclipse. You can’t even easily move your code to using ant. (This was a simple one-source file example. Suppose, however, you had hundreds of java files scattered across multiple directories, directories which do not reflect the package structure declared in the source kit.)

And by not being able to use the standard tools, you miss out on a variety of features these tools bring to the table which can help accelerate your development process. For example, that make file that builds hundreds of sources means you don’t get the benefits of an incremental build and debug process you’d get in Eclipse or Android Studio. It means you wind up spending a considerably longer time to wait for a build. It means you may not even be able to leverage a source debugger tool, leaving you to using “print” statements to debug your code.


The problem with abusing development tools, especially in a large group project, is that you create all sorts of obstacles to efficiency. Now some of the plugins or additional tools we really need to use: as I noted, the occasional cost of a broken Xcode build process may outweigh the necessity of coordinating a dozen or more plugins provided and managed by CocoaPods. But think carefully before wandering away from a development environment’s “happy path”, because you may create more problems than you solve.

The Ninth Principle: An idiom should be debuggable.

This is a continuation of the blog post 12 Principles of Good Software Design.

9. An idiom should be debuggable.

As software developers sometimes we become distracted by shiny bobbles and design patterns that represent a theoretical ideal that we think will help solve our problems. But in the process we don’t consider the fundamental process of writing software, we break our tools and we inadvertently create inefficiencies in the name of that ideal. Some developers even go so far as to think that if the tools are broken in order to fulfill their ideal, that it’s the tools fault–not considering that regardless of fault, they now have to write software with one hand tied behind their back.

The fundamental process of writing software is the Edit-Compile-Test cycle: we write code. We compile code. We test, find bugs and fix them by editing the code. And the faster we can perform this cycle, the more productive we can be.

Now a considerable amount of attention has been paid to the edit part of our process: IDEs, code refactoring, autocompletion; they all help us create and change code faster. We also have spent considerable amount of time on the compile process, even going so far as to advocate computer languages (such as Javascript or Ruby) which skip the compile step entirely. But we seem to take testing for granted, outside of unit testing–which is such a small subset of the entire “test” cycle above it’s almost not worth mentioning here.

And by disregarding testing (except for “unit tests”), we make our lives considerably more difficult.


For example, let’s assume we have a model class which we wish to provide a mock of, for testing purposes. The model class itself contains a lot of sophisticated logic, but it’s not ready yet, so we wish to use a mock object to test our user interface. Our standard mechanism for constructing our model is a ModelFactory:

@class Model;

@interface ModelFactory : NSObject

+ (ModelFactory *)shared;
- (Model *)create;

@end

In order to allow us to create our mock object, we use the NSProxy object, which takes all method calls to it and encapsulates them as an invocation which can then be forwarded to the appropriate object for execution.

So we create our protocol to define the procedures used by our model:

@protocol ModelProtocol <NSObject>

- (NSInteger)getItemCount;
- (NSDictionary *)getItemForIndex:(NSInteger)index;

@end

And we then define our proxy with the protocol:

#import "ModelProtocol.h"

@interface Model : NSProxy <ModelProtocol>

- (id)initWithObject:(id)object;

@end

For this example, our proxy simply wraps an object which provides the implementation, though in practice this could be considerably more complex:

@interface Model ()
@property (strong, nonatomic) NSObject <ModelProtocol> *forward;

@end

@implementation Model

- (id)initWithObject:(id)object
{
	self.forward = object;
	return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
	return [self.forward methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
	[invocation invokeWithTarget:self.forward];
}

@end

Our mock object, of course, is relatively simple:

#import "ModelMock.h"

@implementation ModelMock

- (NSInteger)getItemCount
{
	return 3;
}

- (NSDictionary *)getItemForIndex:(NSInteger)index
{
	return @{ @"Index": @(index) };
}

@end

Now we have the machinery in place to allow us to create a Model object, and since we’re building our Model from a factory singleton, we have a single place where we can produce our model (or Mock model) quite easily.


At this point we can obtain an instance of our proxy through the model factory, and execute methods in our proxy, switching between our mock object and our production project in our factory.

So, in our View Controller:

@interface ViewController ()
@property (strong, nonatomic) Model *model;
@end

@implementation ViewController

- (void)viewDidLoad {
	[super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.

	self.model = [[ModelFactory shared] create];
	NSInteger index = [self.model getItemCount]; // Test our call
	NSLog(@"%d",(int)index);

	(other initialization here)
}

We create our model from the model factory, and we can invoke a method within our proxy which then is forwarded to our mock object.


So now we need to debug this. And so we set a breakpoint on the line where our method call is made to our proxy:

NewImage

And we step into our method. Or rather, we try to step into our method. Result?

NewImage

We don’t step into the method.

The current version of Xcode (Version 3.7.1 (7D1014) as of this writing) cannot step into a proxy. That’s because the process wraps the proxy into an invocation and then calls the invocation elsewhere.

Now for our simple mock object, it may not matter–but if we need to step into the actual model code, we’re screwed.

We cannot debug our code anymore.


And it didn’t have to be this way if we didn’t fall victim to the shiny bobbles. We already have the pieces in place to allow us an easier implementation–one which doesn’t have all the shiny coolness of NSProxy, but a more pedestrian implementation which we can actually debug.

Step 1: Get rid of the Model object entirely. We don’t need it.

Step 2: Change our ModelFactory to return the protocol representation of our object:

@protocol ModelProtocol;

@interface ModelFactory : NSObject

+ (ModelFactory *)shared;
- (id)create;

@end

Our ModelFactory then directly returns the raw mock model object or the regular model object.

Our View Controller also needs to change:

@interface ViewController ()
@property (strong, nonatomic) id model;
@end

@implementation ViewController

- (void)viewDidLoad {
	[super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.

	self.model = [[ModelFactory shared] create];
	NSInteger index = [self.model getItemCount];
	NSLog(@"%d",(int)index);
}

But the changes are not significant; just the actual declaration of the model property.

Now we set our breakpoint as before:

NewImage

And we step in, and amazingly enough, we actually manage to step into our mock object:

NewImage


There are so many patterns out there that seem cool and interesting, but which make debugging our code significantly harder. We saw this in a previous post where we examined a method swizzling technique on a category of UITableView, where a bug in our endless scrolling code could potentially break every single UITableView and not just the ones that use endless scrolling–and without leaving us a clue as to how things went wrong.

Proxies and delayed invocation objects are also quite nice and can be used to solve very specific problems–but in general there are often other methods which don’t require more esoteric expressions which a modern debugger cannot handle.

An idiom should be debuggable, because if it is not, we’re left being lost, forced to do our job with one arm tied behind our back.

The Eighth Principle: An idiom should keep related functionality together in the same place.

This is a continuation of the blog post 12 Principles of Good Software Design.

8. An idiom should keep related functionality together in the same place.

In a 1968 edition of The Communications of the ACM, Edsger Dijkstra published a paper A Case against the GO TO Statement, where he made the argument that the GO TO (or GOTO) statement popular in many programming languages at the time was harmful.

The unbridled use of the go to statement has an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress.

That is, the GOTO statement allows us to construct “spaghetti code”, it is impossible to know by examining a small segment of code how that chunk of code would be executed, when it would be executed or under what conditions it would be executed. Worse, a chunk of code towards the end of a function may be logically related to the code at the start of a function–but we have no way to understand this by casual inspection.

To give a concrete example of what this means, suppose we have the following code in BASIC:

SUB printlist
    LET x = 0
    LET len = 10
10: IF x >= len GOTO 20
    PRINT x
    x = x + 1
    GOTO 10
20: END SUB

Compare and contrast to the following written in C:

int len = 10;
for (int x = 0; x < len; ++x) {
	print(x);
}

Both of these do the exact same thing: we iterate x from 0 to 10, printing x each time through the loop.

In C our for loop keeps the related functionality (iterating through the loop) together in a single line, which makes the intent of our code obvious.

Our BASIC example using GOTO statements, however, scatters the code which implements our loop.

Coloring the elements of our C statement to show our index being initialized, updated and tested against the limit, we see:

int len = 10;
for (int x = 0; x < len; ++x) {
	print(x);
}

Now look at where the corresponding elements are in our BASIC statement:

SUB printlist
    LET x = 0
    LET len = 10
10: IF x >= len GOTO 20
    PRINT x
    x = x + 1
    GOTO 10
20: END SUB

Now this is a trivial case, but imagine if you have two embedded for loops combined with a rather complex inner loop. It would be nearly impossible using GOTO to understand what is going on–because we have violated the principle of keeping related functionality together in the same place.


The idea that GOTOs are considered dangerous stems from the idea that it makes it harder for us to read the software we’ve written. Of course GOTO statements do not necessarily lead to spaghetti code, but unfortunately it makes it incredibly easy, and that obfuscation makes code maintenance and fixing bugs difficult to impossible.

It’s not just GOTO statements which can lead to spaghetti code. In fact, it is poor code hygiene which causes the code for a given feature to be scattered across multiple locations in our code–and even across multiple classes or modules as well as in multiple disparate places in the same source module. GOTO may make good code hygiene more difficult, but simply ignoring GOTO statements without understanding code hygiene is just as harmful.


There are many ways in which functionality expresses itself in code, and many way where we can practice good code hygiene by keeping related functionality together.

Functionality can be related by side effect or by operation; for example, a component may need to initialize a number of other subcomponents, and it would be desirable (as much as possible) to show each component being completely initialized before the next component, rather than mixing initialization code in a jumble.

A previous example demonstrated one of these. Suppose we have a view controller which is initializing multiple buttons by setting their appearance:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Set up the appearance of our interface
	 */

	self.firstButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.secondButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.firstButton.layer.borderWidth = 1;
	self.secondButton.layer.borderWidth = 1;
	self.thirdButton.layer.borderWidth = 2;
	self.thirdButton.layer.borderColor = [UIColor darkGrayColor].CGColor;
	self.firstButton.layer.cornerRadius = 6;
	self.secondButton.layer.cornerRadius = 6;
	self.thirdButton.layer.cornerRadius = 6;
}

Notice the spaghetti of our initialization code; it’s unclear which button is being initialized in what way. By simply reordering the statements by related functionality we can understand better what is going on:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Set up the appearance of our interface
	 */

	self.firstButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.firstButton.layer.borderWidth = 1;
	self.firstButton.layer.cornerRadius = 6;

	self.secondButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.secondButton.layer.borderWidth = 1;
	self.secondButton.layer.cornerRadius = 6;

	self.thirdButton.layer.borderColor = [UIColor darkGrayColor].CGColor;
	self.thirdButton.layer.borderWidth = 2;
	self.thirdButton.layer.cornerRadius = 6;
}

Readability is enhanced by keeping related functionality together.


Functionality can be related by feature: a custom view with drawing code would be easier to understand if all of the drawing code were kept together and perhaps ordered from the most specific to the most general.

For example, suppose we have a custom UIView which draws a series of four buttons, and send a message if one of the buttons is tapped on by the user.

The functionality of our custom UIView can be broken down into three general bits of functionality:

  1. Calculate the location of each of the buttons.
  2. Draw the individual buttons.
  3. Handle tap events by calling our callback.
    1. With these features in mind we can build our custom view.

      First, we need to calculate the location of our four buttons. We assume our buttons are all 44×44 pixels in size, laid side by side. The intrinsic size of our view is then 44 pixels tall by 44 * 4 = 176 pixels wide.

      - (CGSize)intrinsicContentSize
      {
      	return CGSizeMake(176, 44);
      }
      
      - (CGRect)calcButtonAtIndex:(NSInteger)index
      {
      	return CGRectMake(44*index,0,44,44);
      }

      The first returns our intrinsic size. The second calculates the rectangle for each “button” we’re drawing in our custom view.

      The second feature involves drawing the contents. We need to draw each button in the rectangle we obtain from the -calcButtonAtIndex: method:

      // From PaintCode file.
      - (void)drawCanvas1WithFrame: (CGRect)frame label: (NSString*)label
      {
          //// General Declarations
          CGContextRef context = UIGraphicsGetCurrentContext();
      
          //// Rectangle Drawing
          CGRect rectangleRect = CGRectMake(CGRectGetMinX(frame) + 2.5, CGRectGetMinY(frame) + 4.5, CGRectGetWidth(frame) - 5, CGRectGetHeight(frame) - 9);
          UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRoundedRect: rectangleRect cornerRadius: 6];
          [UIColor.lightGrayColor setStroke];
          rectanglePath.lineWidth = 1;
          [rectanglePath stroke];
          NSMutableParagraphStyle* rectangleStyle = [NSMutableParagraphStyle new];
          rectangleStyle.alignment = NSTextAlignmentCenter;
      
          NSDictionary* rectangleFontAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize: UIFont.buttonFontSize], NSForegroundColorAttributeName: UIColor.blackColor, NSParagraphStyleAttributeName: rectangleStyle};
      
          CGFloat rectangleTextHeight = [label boundingRectWithSize: CGSizeMake(rectangleRect.size.width, INFINITY)  options: NSStringDrawingUsesLineFragmentOrigin attributes: rectangleFontAttributes context: nil].size.height;
          CGContextSaveGState(context);
          CGContextClipToRect(context, rectangleRect);
          [label drawInRect: CGRectMake(CGRectGetMinX(rectangleRect), CGRectGetMinY(rectangleRect) + (CGRectGetHeight(rectangleRect) - rectangleTextHeight) / 2, CGRectGetWidth(rectangleRect), rectangleTextHeight) withAttributes: rectangleFontAttributes];
          CGContextRestoreGState(context);
      }
      
      - (void)drawRect:(CGRect)rect
      {
      	for (NSInteger i = 0; i < 4; ++i) {
      		NSString *label = [NSString stringWithFormat:@"%d",(int)i];
      		CGRect r = [self calcButtonAtIndex:i];
      		[self drawButtonWithFrame:r label:label];
      	}
      }

      Note the button drawing itself was created using the PaintCode app, which is one of those powerful tools you really need if you are creating iOS software. It can automate the creation of custom drawing code incredibly simple. But because the style of the code doesn’t match the style of the software we’ve built elsewhere, it’s worth noting where the code came from.

      The third feature involves testing for tap events. Because we’re calculating the rectangle in a separate routine, our hit detection code becomes very simple:

      - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
      {
      }
      
      - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
      {
      }
      
      - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
      {
      }
      
      - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
      {
      	UITouch *touch = [touches anyObject];
      	CGPoint where = [touch locationInView:self];
      
      	for (NSInteger i = 0; i < 4; ++i) {
      		CGRect r = [self calcButtonAtIndex:i];
      		if (CGRectContainsPoint(r, where)) {
      			if (self.tapCallback) {
      				self.tapCallback(i);
      			}
      		}
      	}
      }

      Note: if you need to declare one of the tap methods you should declare all four. The iOS tap hit detection mechanism appears to get confused if you only declare one of these methods.

      Putting together these three bits of functionality together in a single class, we get our class declaration:

      #import <UIKit/UIKit.h>
      
      @interface CustomButtons : UIView
      @property (copy) void (^tapCallback)(NSInteger i);
      @end

      And our custom view class:

      #import "CustomButtons.h"
      
      @implementation CustomButtons
      
      #pragma mark - Layout calculation
      
      - (CGSize)intrinsicContentSize
      {
      	return CGSizeMake(176, 44);
      }
      
      - (CGRect)calcButtonAtIndex:(NSInteger)index
      {
      	return CGRectMake(44*index,0,44,44);
      }
      
      #pragma mark - Drawing Support
      
      - (void)drawButtonWithFrame: (CGRect)frame label: (NSString*)label
      {
      	//// General Declarations
      	CGContextRef context = UIGraphicsGetCurrentContext();
      
      	//// Rectangle Drawing
      	CGRect rectangleRect = CGRectMake(CGRectGetMinX(frame) + 0.5, CGRectGetMinY(frame) + 0.5, CGRectGetWidth(frame) - 1, CGRectGetHeight(frame) - 1);
      	UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: rectangleRect];
      	[UIColor.lightGrayColor setStroke];
      	rectanglePath.lineWidth = 1;
      	[rectanglePath stroke];
      	NSMutableParagraphStyle* rectangleStyle = [NSMutableParagraphStyle new];
      	rectangleStyle.alignment = NSTextAlignmentCenter;
      
      	NSDictionary* rectangleFontAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize: UIFont.buttonFontSize], NSForegroundColorAttributeName: UIColor.blackColor, NSParagraphStyleAttributeName: rectangleStyle};
      
      	CGFloat rectangleTextHeight = [label boundingRectWithSize: CGSizeMake(rectangleRect.size.width, INFINITY)  options: NSStringDrawingUsesLineFragmentOrigin attributes: rectangleFontAttributes context: nil].size.height;
      	CGContextSaveGState(context);
      	CGContextClipToRect(context, rectangleRect);
      	[label drawInRect: CGRectMake(CGRectGetMinX(rectangleRect), CGRectGetMinY(rectangleRect) + (CGRectGetHeight(rectangleRect) - rectangleTextHeight) / 2, CGRectGetWidth(rectangleRect), rectangleTextHeight) withAttributes: rectangleFontAttributes];
      	CGContextRestoreGState(context);
      }
      
      - (void)drawRect:(CGRect)rect
      {
      	for (NSInteger i = 0; i < 4; ++i) {
      		NSString *label = [NSString stringWithFormat:@"%d",(int)i];
      		CGRect r = [self calcButtonAtIndex:i];
      		[self drawButtonWithFrame:r label:label];
      	}
      }
      
      #pragma mark - Touch Events
      
      - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
      {
      }
      
      - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
      {
      }
      
      - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
      {
      }
      
      - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
      {
      	UITouch *touch = [touches anyObject];
      	CGPoint where = [touch locationInView:self];
      
      	for (NSInteger i = 0; i < 4; ++i) {
      		CGRect r = [self calcButtonAtIndex:i];
      		if (CGRectContainsPoint(r, where)) {
      			if (self.tapCallback) {
      				self.tapCallback(i);
      			}
      		}
      	}
      }
      
      @end

      Because we’ve successfully grouped the functionality of our component, we can use the #pragma mark directive to help document the functionality of our component, allowing future developers to understand the pieces that make our component work.


      Functionality may be related by collections of objects implementing an application feature: all of the components used to implement a language parser should be kept together. Java has the concept of a “package” which represents a collection of classes that implement a single feature, but we can achieve the same effect in Xcode for Objective C by organizing our project source kit into groups.

      For example, suppose we need to build a parser which parses strings containing simple arithmetic equations, returning an abstract syntax tree that can be used later to evaluate the equations.

      For our algorithm we could use the Shunting-yard algorithm, which allows us to properly group equations according to operator precedence. First, however, we need to group characters and letters into symbols, and for that we will use a Lexical analysis tool. Our lexical analysis tool could have the following declaration, taking an input string and providing functions for extracting the next token (either a variable, a number or an operator or parenthesis) for parsing.

      #define LEX_VARIABLE	65536
      #define LEX_NUMERIC	65537
      
      @interface LexicalParser : NSObject
      - (id)initWithString:(NSString *)str;
      
      - (NSInteger)nextToken;
      - (NSString *)lastToken;
      - (void)pushBackToken;
      @end

      Our methods allow us to get the next token–either a character (such as ‘+’ or ‘*’), or a token, a collection of characters representing a variable name or a number. If we returned a token, -lastToken returns a string representing the token. And -pushBackToken allows us to set a flag which effectively pushes back a single token.

      On top of this class we would implement the parser, the shunting yard algorithm which allows us to convert the tokens from our lexical analysis parser into an abstract tree:

      @interface EquationParser : NSObject
      - (id)initWithLexicalParser:(LexicalParser *)lex;
      - (AbstractSyntaxNode *)parse;
      @end

      The abstract syntax tree is represented by a collection of nodes, with the format:

      @interface AbstractSyntaxNode: NSObject
      @property (nonatomic, assign) BOOL leaf;	// value
      
      // if leaf is true
      @property (nonatomic, copy) NSString *value;
      
      // if leaf is false
      @property (nonatomic, assign) NSInteger op;
      @property (nonatomic, strong) AbstractSyntaxNode *left;
      @property (nonatomic, strong) AbstractSyntaxNode *right;
      @end

      After going through all this work to build these three interrelated classes used to implement a single feature, it’d be a shame if we were to organize our project as follows:

      NewImage

      Why?

      Because we have no way as we browse the project to understand that we have an equation parser that is built using three interrelated classes.

      However, if we were to organize our project as follows:

      NewImage

      Now we have a clue how our equation parser may work.


      Functionality may be related by the sequence of execution statements; by using anonymous classes in Java or blocks in Objective C we can keep the code executed as a result of an asynchronous statement next to the code which triggers the asynchronous operation.

      From a previous example, we can use blocks with an asynchronous operation in order to keep the code which triggers an operation together with the code that is called as a result of that operation.

      So our API which makes a request to a remote server and returns a result has the following declaration:

      @interface Server : NSObject
      
      + (Server *)shared;
      
      - (void)requestWithEndpoint:(NSString *)endpoint
      				 parameters:(NSDictionary *)params
      		  completionHandler:(void (^)(NSDictionary *data, NSURLResponse *response, NSError *error))callback;
      
      @end

      This allows us to write our request as follows:

      - (void)doOperation
      {
      	int value1 = (do something here);
      	NSDictionary *d = @{ @"arg1": @( value1 ) };
      
      	[[Server shared] requestWithEndpoint:@"apicall" parameters:d completionHandler:^(NSDictionary *data, NSURLResponse *response, NSError *error) {
      		NSInteger retVal = [data[@"result"] integerValue];
      
      		(handle our result here)
      	}];
      }

      Notice that not only is our code here concise; it is obviously making an API call to the endpoint “apicall” with a single parameter with an argument named “arg1”, but we can see immediately following it in the code how we handle our result.

      Had we written our declaration differently, say with a response object passed in to our request:

      @protocol ServerResponse 
      - (void)completionWithData:(NSDictionary *)data 
      			response:(NSURLResponse *)response 
      			userData:(NSDictionary *)userData;
      @end
      
      @interface Server : NSObject
      + (Server *)shared;
      - (void)requestWithEndpoint:(NSString *)endpoint
      			parameters:(NSDictionary *)params
      			userData:(NSDictionary *)userData
      			response:(id)response;
      @end

      Then our call may seem simpler:

      - (void)doOperation
      {
      	int value1 = (do something here);
      	NSDictionary *d = @{ @"arg1": @( value1 ) };
      
      	[[Server shared] requestWithEndpoint:@"apicall" parameters:d userData:nil response:self];
      }

      But our call does not reveal to us what action is taken when we get a response. Worse, we don’t even have an obvious way of knowing where the response will arrive in our class.


      Good code hygiene requires far more of us than simply not using GOTO statements. It requires us to consider how our code holds together at each level of the implementation, from individual statements to collections of classes, and how we handle responses to asynchronous messages.

      GOTO statements are bad because it makes it easy to write spaghetti code; it makes it too easy for us to scatter related functions all throughout the source kit, without any clue as to where the code lives for a given set of features. But bad code hygiene–failing to keep functionality related by feature, by function or by code execution–can lead to spaghetti code even without the use of a single GOTO statement, even in a computer language otherwise designed to help make code better organized.

The Seventh Principle: An idiom should stick to language features which make code obvious.

This is a continuation of the blog post 12 Principles of Good Software Design.

7. An idiom should stick to language features which make code obvious.

The Objective C language has a number of interesting features which allow us to add new functionality to our code. Features such as KVO allow us to trigger an event when a field changes. Categories allow us to extend an existing class. Method swizzling allows us to replace the functionality of a method with another for all objects of a given class.

Java has a number of interesting features as well. The ability to customize our class loader allows us to modify the way we load executable code. Java has a rich set of introspection primitives as well as reflection support to allow us to dynamically examine classes and code. Java even includes an annotation mechanism that can help us guide our introspection to associate semantic meaning to methods and fields.

Do not use them unless you absolutely must.

When you use these features you can make the functionality of your code impossible to follow for someone new to a project. These features can make it impossible for someone to discover if functionality is built in or added, impossible for someone to follow the flow of execution, impossible to discover how to fix bugs or extend functionality.

And some of the tools at your disposal are downright dangerous, in the sense that if you screw something up you can make the application unstable. Certain techniques, such as method swizzling, can introduce bugs that are nearly impossible to debug.

So many times we use features such as this, when it is not necessary; similar functionality could be achieved more simply through easier to understand and easier to maintain techniques, such as class inheritance.


Suppose you have the following application which displays a table of items in iOS. The model declaration is simple: given a start row and a number of rows, this loads an array of the objects and asynchronously returns the loaded list of items.

#import <Foundation/Foundation.h>

@interface Model : NSObject

+ (Model *)shared;

- (void)loadStarting:(NSInteger)startRow length:(NSInteger)length callback:(void (^)(NSArray *))callback;

@end

The view controller and table cell should be familiar; they are from our previous example.

Our view controller:

#import "ViewController.h"
#import "TableViewCell.h"
#import "Model.h"

@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSMutableArray *data;
@end

static const void *ImageNameKey = &ImageNameKey;

@implementation ViewController

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Create and bind our view model
	 */

	self.data = [[NSMutableArray alloc] init];
	[[Model shared] loadStarting:0 length:20 callback:^(NSArray *a) {
		[self.data addObjectsFromArray:a];
		[self.tableView reloadData];
	}];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	NSDictionary *d = self.data[indexPath.row];
	[cell setData:d];

	return cell;
}

@end

Our table cell simply takes the contents and displays them; our view controller only needs to know the number of rows loaded.

Our assignment: add endless scrolling. That is, as we scroll in our table view, as we reach the bottom we should dynamically load more items until we reach the end.


For our example we will create a new category on UITableView which sends us a message when scrolling is close to the bottom, so we can then trigger loading more rows.

Our final category looks like the following:

@protocol UITableViewEndlessDelegate <UITableViewDelegate>
- (BOOL)appendMoreDataToTableView:(UITableView *)tableView;
@end

@interface UITableView (EndlessScroll)

- (void)setEndlessScrollingEnabled:(BOOL)flag;
- (BOOL)endlessScrollingEnabled;

- (void)finishedAppendingData;

@end

The essence of our endless scrolling code involves looking at the current offset of the content, and if it is close enough to the bottom, trigger a callback to ask our view controller to load more rows. If we have no more rows to load, then we disable endless scrolling for that table view. We also keep track if the table view is in the loading state; if it is, we don’t trigger multiple callbacks to load more data. (We can use that state to extend our table view to maintain some loading UI, such as a spinner at the bottom of our content area.)

The code which handles that is below:

/*
 *	Endless scrolling logic. This is simple; all we do is test if the
 *	y position is at max, and if it is, trigger our event.
 */

- (CGFloat)es_triggerOffset
{
	CGFloat h = self.contentSize.height;
	UIEdgeInsets insets = self.contentInset;
	h -= self.bounds.size.height - insets.top - insets.bottom;
	if (h < 0) h = 0;
	return h;
}

- (void)es_testBounds
{
	if (self.es_state.loading) return;	// we're loading

	CGFloat ypos = self.contentOffset.y;
	if (ypos >= self.es_triggerOffset - 44) {	// We're close to bottom
		self.es_state.loading = YES;
		BOOL flag = [(id<UITableViewEndlessDelegate>)self.delegate appendMoreDataToTableView:self];
		if (!flag) self.endlessScrollingEnabled = NO;
	}
}

It’s fairly straight forward. The first method calculates the offset which would be the “maximum scroll”; that is, the maximum amount our content can scroll. The second method determines if we are loading, and if we are not, then determines if we are at the bottom of the scroll area. If so, we note that we’re loading, and call our callback.

Because this is a category we cannot simply extend our class. We must instead use an association to store our data:

- (InternalState *)es_state
{
	return objc_getAssociatedObject(self, InternalStateKey);
}

Our internal state simply tracks if endless scrolling is initialized, and if we are in the loading state. Additional items, such as spinners, would also be tacked on here.

/*
 *	Declare internal state record that we track for our endless scrolling
 *	mechanism
 */

@interface InternalState: NSObject
@property (assign) BOOL initialized;
@property (assign) BOOL loading;
@end

@implementation InternalState
@end

Note that we also extend the UITableViewDelegate with an additional method. From our header declaration:

@protocol UITableViewEndlessDelegate <UITableViewDelegate>
- (BOOL)appendMoreDataToTableView:(UITableView *)tableView;
@end

This additional callback in our delegate allows our view controller to detect if we need to load more items and take the appropriate action. Once we’re done loading (as loading is an asynchronous process), we call the -finishedAppendingData; category method. If there are no more rows we disable endless scrolling by calling -setEndlessScrollingEnabled: with NO.

Now at the heart of our endless scrolling, we require callbacks as the contents move. Currently on iOS, when the contents move, the method setContentOffset: is invoked. As the contents resize, setContentSize: is invoked. In order to intercept calls to these methods we must use method swizzling. We basically replace the pointer to the function that is invoked by the selectors setContentOffset and setContentSize with pointers to our own functions. Our functions then invoke the previous selectors, then detect if we hit the bottom by calling our -es_TestBounds methods.

/*
 *	Swizzle swap
 */

static void SwizzleMethods(Class c, SEL original, SEL alternate)
{
	Method origMethod = class_getInstanceMethod(c, original);
	Method altMethod = class_getInstanceMethod(c, alternate);

	if (class_addMethod(c, original, method_getImplementation(altMethod), method_getTypeEncoding(altMethod))) {
		class_replaceMethod(c, alternate, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
	} else {
		method_exchangeImplementations(origMethod, altMethod);
	}
}

+ (void)load
{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		SwizzleMethods(self, @selector(setContentOffset:), @selector(es_SetContentOffset:));
		SwizzleMethods(self, @selector(setContentSize:), @selector(es_SetContentSize:));
	});
}

The load method is special; it is invoked as our category is loaded. This means our methods are swizzled the moment any code refers to our category.

And our swizzled methods are:

/*
 *	The swizzled methods
 */

- (void)es_SetContentOffset:(CGPoint)contentOffset
{
	[self es_SetContentOffset:contentOffset];

	if (self.es_state.initialized) {
		[self es_testBounds];
	}
}

- (void)es_SetContentSize:(CGSize)contentSize
{
	[self es_SetContentSize:contentSize];

	if (self.es_state.initialized) {
		[self es_testBounds];
	}
}

Notice the oddity that the methods look like they’re calling themselves. They’re not. As we swizzle the methods, what’s old becomes new again–and what appears to be a method calling itself in fact is the new method calling the original method.

Our complete category declaration is thus:

#import "UITableView+EndlessScroll.h"
#import <objc/runtime.h>

static const void *InternalStateKey = &InternalStateKey;

/*
 *	Declare internal state record that we track for our endless scrolling
 *	mechanism
 */

@interface InternalState: NSObject
@property (assign) BOOL initialized;
@property (assign) BOOL loading;
@end

@implementation InternalState
@end

/*
 *	Swizzle swap
 */

static void SwizzleMethods(Class c, SEL original, SEL alternate)
{
	Method origMethod = class_getInstanceMethod(c, original);
	Method altMethod = class_getInstanceMethod(c, alternate);

	if (class_addMethod(c, original, method_getImplementation(altMethod), method_getTypeEncoding(altMethod))) {
		class_replaceMethod(c, alternate, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
	} else {
		method_exchangeImplementations(origMethod, altMethod);
	}
}

@implementation UITableView (EndlessScroll)

+ (void)load
{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		SwizzleMethods(self, @selector(setContentOffset:), @selector(es_SetContentOffset:));
		SwizzleMethods(self, @selector(setContentSize:), @selector(es_SetContentSize:));
	});
}

- (InternalState *)es_state
{
	return objc_getAssociatedObject(self, InternalStateKey);
}

- (BOOL)endlessScrollingEnabled
{
	InternalState *state = self.es_state;
	if (state == nil) return NO;
	return state.initialized;
}

- (void)setEndlessScrollingEnabled:(BOOL)flag
{
	if (!self.endlessScrollingEnabled && flag) {
		// Internal state not set, so set one up and enable
		InternalState *state = [[InternalState alloc] init];
		state.initialized = YES;
		objc_setAssociatedObject(self, InternalStateKey, state, OBJC_ASSOCIATION_RETAIN);
	} else {
		InternalState *state = objc_getAssociatedObject(self, InternalStateKey);
		state.initialized = flag;
	}
}

- (void)finishedAppendingData
{
	self.es_state.loading = NO;
	[self es_testBounds];
}

/*
 *	The swizzled methods
 */

- (void)es_SetContentOffset:(CGPoint)contentOffset
{
	[self es_SetContentOffset:contentOffset];

	if (self.es_state.initialized) {
		[self es_testBounds];
	}
}

- (void)es_SetContentSize:(CGSize)contentSize
{
	[self es_SetContentSize:contentSize];

	if (self.es_state.initialized) {
		[self es_testBounds];
	}
}

/*
 *	Endless scrolling logic. This is simple; all we do is test if the
 *	y position is at max, and if it is, trigger our event.
 */

- (CGFloat)es_triggerOffset
{
	CGFloat h = self.contentSize.height;
	UIEdgeInsets insets = self.contentInset;
	h -= self.bounds.size.height - insets.top - insets.bottom;
	if (h < 0) h = 0;
	return h;
}

- (void)es_testBounds
{
	if (self.es_state.loading) return;	// we're loading

	CGFloat ypos = self.contentOffset.y;
	if (ypos >= self.es_triggerOffset - 44) {	// We're close to bottom
		self.es_state.loading = YES;
		BOOL flag = [(id<UITableViewEndlessDelegate>)self.delegate appendMoreDataToTableView:self];
		if (!flag) self.endlessScrollingEnabled = NO;
	}
}

@end

And with all this machinery in place, we can finally update our View Controller to handle append events.

#import "ViewController.h"
#import "TableViewCell.h"
#import "Model.h"
#import "UITableView+EndlessScroll.h"

@interface ViewController () <UITableViewEndlessDelegate, UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSMutableArray *data;
@end

static const void *ImageNameKey = &ImageNameKey;

@implementation ViewController

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Create and bind our view model
	 */

	self.data = [[NSMutableArray alloc] init];
	[[Model shared] loadStarting:0 length:20 callback:^(NSArray *a) {
		[self.data addObjectsFromArray:a];
		[self.tableView reloadData];

		self.tableView.endlessScrollingEnabled = YES;
	}];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	NSDictionary *d = self.data[indexPath.row];
	[cell setData:d];

	return cell;
}

- (BOOL)appendMoreDataToTableView:(UITableView *)tableView
{
	[[Model shared] loadStarting:self.data.count length:20 callback:^(NSArray *a) {
		NSInteger count = a.count;
		if (count == 0) {
			// No more data. Turn off endless scrolling
			self.tableView.endlessScrollingEnabled = NO;

		} else {
			// Create array of indexes we're inserting
			NSMutableArray *indexes = [[NSMutableArray alloc] init];
			NSInteger last = self.data.count;
			for (NSInteger i = 0; i < count; ++i) {
				[indexes addObject:[NSIndexPath indexPathForRow:i+last inSection:0]];
			}

			// Insert the data
			[self.data addObjectsFromArray:a];

			// Update the table
			[self.tableView beginUpdates];
			[self.tableView insertRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationAutomatic];
			[self.tableView endUpdates];
		}
		[self.tableView finishedAppendingData];
	}];
	return YES;
}

@end

The notable elements are in blue. Our delegate method -appendMoreDataToTableView: handles the operation of appending more data; if more data is not available, endless scrolling ends.


Problem solved, right? And in such a clever way.

Well, not quite.

First, because we used a category and method swizzling, a casual user who has never seen this code before would not know how endless scrolling was hooked into our system. It’s not readily apparent, for example, that our category has added endless scrolling to all UITableViews and not just the one we’ve enabled, by virtue of the +load method. Worse, if you have an application with two or three dozen table views, only one of which implements endless scrolling, it may be nearly impossible for a new user to realize your category even exists.

This is important, because second: our method swizzling takes place on startup, and because all tables are affected (and not just the ones with endless scrolling) any bugs in our endless scrolling code will break all table views (and not just the ones we’ve added our functionality to). This means that a bug in a chunk of code that is entirely invisible to the user who is maintaining your code (because the <UITableView+EndlessScroll> category still affects a table view even though the header wasn’t loaded) will wind up with an exceedingly hard to understand crash, thanks to swizzling. What should be an easy to understand issue may wind up looking like an internal iOS bug.

Third, supporting the swizzling operation makes our code considerably longer and more complicated than it needs to be.


Suppose instead of adding a category we created a child class of our UITableView. This would have the nice property that only tables with endless scrolling would be affected by any bugs in our code. And it eliminates our need for swizzling and for tracking internal state using an association.

Our declaration for our child class is very similar to the category:

#import <UIKit/UIKit.h>

@protocol UITableViewEndlessDelegate <UITableViewDelegate>
- (BOOL)appendMoreDataToTableView:(UITableView *)tableView;
@end

@interface ESTableView : UITableView

- (void)setEndlessScrollingEnabled:(BOOL)flag;
- (BOOL)endlessScrollingEnabled;

- (void)finishedAppendingData;

@end

However, our class becomes considerably more concise, and more easily understood.

Instead of maintaining a property we can use class properties:

@interface ESTableView ()
@property (assign) BOOL initialized;
@property (assign) BOOL loading;
@end

Our methods for starting and stopping endless scrolling becomes considerably simpler as well:

- (BOOL)endlessScrollingEnabled
{
	return self.initialized;
}

- (void)setEndlessScrollingEnabled:(BOOL)flag
{
	self.initialized = flag;
}

Instead of swizzling we do a method override:

- (void)setContentOffset:(CGPoint)contentOffset
{
	[super setContentOffset:contentOffset];

	if (self.initialized) {
		[self es_testBounds];
	}
}

- (void)setContentSize:(CGSize)contentSize
{
	[super setContentSize:contentSize];

	if (self.initialized) {
		[self es_testBounds];
	}
}

And the rest remains more or less the same. Our complete ESTableView class becomes:

#import "ESTableView.h"

@interface ESTableView ()
@property (assign) BOOL initialized;
@property (assign) BOOL loading;
@end

@implementation ESTableView

- (void)setContentOffset:(CGPoint)contentOffset
{
	[super setContentOffset:contentOffset];

	if (self.initialized) {
		[self es_testBounds];
	}
}

- (void)setContentSize:(CGSize)contentSize
{
	[super setContentSize:contentSize];

	if (self.initialized) {
		[self es_testBounds];
	}
}

- (BOOL)endlessScrollingEnabled
{
	return self.initialized;
}

- (void)setEndlessScrollingEnabled:(BOOL)flag
{
	self.initialized = flag;
}

- (void)finishedAppendingData
{
	self.loading = NO;
	[self es_testBounds];
}

/*
 *	Endless scrolling logic. This is simple; all we do is test if the
 *	y position is at max, and if it is, trigger our event.
 */

- (CGFloat)es_triggerOffset
{
	CGFloat h = self.contentSize.height;
	UIEdgeInsets insets = self.contentInset;
	h -= self.bounds.size.height - insets.top - insets.bottom;
	if (h < 0) h = 0;
	return h;
}

- (void)es_testBounds
{
	if (self.loading) return;	// we're loading

	CGFloat ypos = self.contentOffset.y;
	if (ypos >= self.es_triggerOffset - 44) {	// We're close to bottom
		self.loading = YES;
		BOOL flag = [(id<UITableViewEndlessDelegate>)self.delegate appendMoreDataToTableView:self];
		if (!flag) self.endlessScrollingEnabled = NO;
	}
}

@end

Of course this requires a minor change in our view controller: we need to replace our UITableView with an ESTableView. But the rest of the View Controller logic is absolutely identical.


Now we’ve replaced our Objective-C specific category, swizzle and property-based solution with a more traditional child object and object inheritance solution, we’ve now done a few things:

First, we have isolated any bugs in our endless scrolling code to just the table views which have endless scrolling. This is great because it means if there is a defect in your endless scrolling code, it won’t present itself in some odd location elsewhere in the application as if it were a bug in the iOS operating system.

Second, and more importantly, because we now have to switch the UITableView to an ESTableView for endless scrolling, we signal in the code those places were we are using the enhanced functionality. This allows someone new to the code to understand that new functionality was added, and to allow them some insight as to where to find the new functionality (in the ESTableView class).

In other words, it has become exceedingly obvious that a class with new functionality has been added, while avoiding potentially dangerous constructs such as swizzling.


Of course there are times when using swizzling and attaching properties dynamically to a table helps solve a deep problem. However, most of the time there is no reason why creating a child class wouldn’t give the same results, and in the process isolate any problems while making it blinding obvious to a new developer what is going on.

And if it is blindingly obvious you have extended the functionality by creating a child class, then you will have to answer fewer questions from any new developers who take over your code.

Which means you can get home to your life sooner, while maintaining your level of productivity.

The Sixth Principle: An idiom should help isolate functionality into well defined components.

This is a continuation of the blog post 12 Principles of Good Software Design.

6. An idiom should help isolate functionality into well defined components.

Object-oriented software development is a fantastic way to build applications, especially user interface applications designed to run on a mobile device. You can isolate functionality into well defined views, attach them to well-defined models where the internal representation is hidden behind a well-defined interface, and coordinate their behavior with well defined view controllers and the like. Events can be handled in a variety of well-defined ways, with singletons processing global messages and dispatching them to registered notifiers, or passed up through a well defined command chain. And each object, built with a well-defined interface, handling one thing, and being capable of being modified without causing the entire application to fall like a house of cards.

It’s a fantastic dream, one we routinely violate every. single. day.


Here’s a common way a lot of table views are assembled in iOS. Suppose we have a list of data represented as a collection of NSDictionary objects stored in an NSArray, which is to be displayed in a table. So we build the following code to populate the table cells:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	NSDictionary *d = self.data[indexPath.row];
	NSString *title = d[@"title"];

	NSString *addr = [NSString stringWithFormat:@"%@, %@",d[@"city"],d[@"state"]];
	NSString *subtitle = addr;

	cell.textLabel.text = title;
	cell.detailTextLabel.text = subtitle;

	return cell;
}

Now it happens that having our view controller code parse the contents of the array and calculating how the contents are to be presented works okay in the simple case. But now suppose we need to extend the functionality of this table by displaying an image associated with each record. The image itself is a file name, which is pulled from a known server location.

So we add code to download the image to our view controller, which caches images in an NSCache object in the view controller, and uses a NSURLSession object, also initialized by the view controller:

- (void)downloadImage:(NSString *)path withCallback:(void (^)(UIImage *image))callback
{
	UIImage *image = [self.cache valueForKey:path];
	if (image) {
		callback(image);
		return;
	}

	void (^copyCallback)(UIImage *image) = [callback copy];
	NSString *urlPath = [NSString stringWithFormat:@"http://myserver.com/image/%@",path];
	NSURL *url = [NSURL URLWithString:urlPath];
	NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
	[self.session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError * error) {
		// We should check for errors here.

		UIImage *img = [UIImage imageWithData:data];
		dispatch_async(dispatch_get_main_queue(), ^{
			[self.cache setValue:img forKey:path];
			copyCallback(img);
		});
	}];
}

And we add our image to the code which loads the image cells:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	NSDictionary *d = self.data[indexPath.row];
	NSString *title = d[@"title"];

	NSString *addr = [NSString stringWithFormat:@"%@, %@",d[@"city"],d[@"state"]];
	NSString *subtitle = addr;

	cell.textLabel.text = title;
	cell.detailTextLabel.text = subtitle;

	// Load the image
	cell.imageView.image = [UIImage imageNamed:@"missing"];
	[self downloadImage:d[@"image"] withCallback:^(UIImage *image) {
		cell.imageView.image = image;
	}];

	return cell;
}

But, as it turns out, this has a bug; cells in our table view are reused, and it is possible if we are scrolling fast enough that an image is dynamically loaded from our cache for a particular table cell after the cell has been repurposed for another use.

So we attach a property to the table cell so we know which image the cell should be displaying, and we verify after the image is loaded the image path hasn’t changed:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	NSDictionary *d = self.data[indexPath.row];
	NSString *title = d[@"title"];

	NSString *addr = [NSString stringWithFormat:@"%@, %@",d[@"city"],d[@"state"]];
	NSString *subtitle = addr;

	cell.textLabel.text = title;
	cell.detailTextLabel.text = subtitle;

	// Load the image
	NSString *path = d[@"image"];
	objc_setAssociatedObject(cell,ImageNameKey,path,OBJC_ASSOCIATION_COPY);
	cell.imageView.image = [UIImage imageNamed:@"missing"];
	[self downloadImage:d[@"image"] withCallback:^(UIImage *image) {
		NSString *curPath = objc_getAssociatedObject(cell, ImageNameKey);
		if ([curPath isEqualToString:path]) {
			cell.imageView.image = image;
		}
	}];

	return cell;
}

Notice that this sort of code is not atypical of a lot of iOS applications. The model is little more than a chunk of data, the view is little more than a dumb holder, and the view controller winds up doing everything: network calls, caching, formatting table cells, validating images are correctly loaded.

Worse, suppose now we had to alter the functionality of our table view to add other fields, to customize the fields, and to alter the height of the different table views depending on the size of the content being provided?


The flaw here is that, due to a misapprehension as to the roles of models, views and view controllers, we have violated the essence of partitioning our code into well-defined components, where each component does one thing and does one thing well, without significantly overloading a single object with too much functionality.

The key here is that in the original Model-View-Controller papers, there are no requirements on the complexity of the views or the models, nor are there any requirements on having to roll in every single bit of functionality into a single monolithic controller. (Feel free to browse the papers linked here; I’ll wait.)

In fact, the perfect example of a view which contains complex functionality is the UITextField object; it is responsible for taking in text, presenting a keyboard, editing the text, interacting with the clipboard, and handling bidirectional text when internationalized. Hardly a “light weight” object–though we think of it as such, because it has well-defined functionality and a simple interface.


So what is our current View Controller doing, exactly, beyond coordinating messages between the views and the model?

  1. Loading images from a remote server.
  2. Formatting the data displayed in a table view.
  3. Dynamically loading images to the table view cells.

In fact, one could argue that we have no model–just an array of data objects, and so our view controller also contains some of the business logic that we should be putting in the model.

So let’s reorganize our code to refactor everything into their own well-defined components.

First, the image loading mechanism that we created above properly belongs in its own class. That’s because it is quite possible we would be reusing the code elsewhere as well. Further, if we find bugs or if we decide to migrate to a third party library, we only have one interface to change, rather than countless view controllers, each of which were responsible for loading images.

This gives us the following ImageLoader class:

#import <UIKit/UIKit.h>

@interface ImageLoader : NSObject

+ (ImageLoader *)shared;

- (void)downloadImage:(NSString *)path
		 withCallback:(void (^)(NSString *path, UIImage *image))callback;

@end

and the following implementation:

#import "ImageLoader.h"

@interface ImageLoader()
@property (strong, nonatomic) NSURLSession *session;
@property (strong, nonatomic) NSCache *cache;
@end

@implementation ImageLoader

- (id)init
{
	if (nil != (self = [super init])) {
		self.cache = [[NSCache alloc] init];

		NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
		self.session = [NSURLSession sessionWithConfiguration:config];
	}
	return self;
}

+ (ImageLoader *)shared
{
	static ImageLoader *singleton;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		singleton = [[ImageLoader alloc] init];
	});
	return singleton;
}

- (void)downloadImage:(NSString *)path
		 withCallback:(void (^)(NSString *path, UIImage *image))callback
{
	UIImage *image = [self.cache valueForKey:path];
	if (image) {
		callback(path,image);
		return;
	}

	void (^copyCallback)(NSString *path, UIImage *image) = [callback copy];
	NSString *urlPath = [NSString stringWithFormat:@"http://myserver.com/image/%@",path];
	NSURL *url = [NSURL URLWithString:urlPath];
	NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
	[self.session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError * error) {
		// We should check for errors here.

		UIImage *img = [UIImage imageWithData:data];
		dispatch_async(dispatch_get_main_queue(), ^{
			[self.cache setValue:img forKey:path];
			copyCallback(path,img);
		});
	}];
}

@end

Notice the advantage of this class: it does exactly one thing and one thing only. It loads images from our server. That’s it.

And because it only does one thing and does it simply, it is easy for us to incorporate into our code, and it is easy for us to fix problems if we discover our image loading process seems broken somehow.

The second thing we can remove from the View Controller is the functionality of parsing and loading the contents of the Table Cell. This refactoring is important in that it makes the view object (in this case, our UITableViewCell object) responsible for its presentation, rather than placing responsibility for presentation inside the view controller.

By doing this, we make the Table Cell responsible for its own presentation. This refactoring of code so that a Table Cell handles itself will be instrumental in the third step we plan to perform–and can’t be done without this second step.

(Yes, I know this is a point of contention amongst programmers who believe views should be dumb and views that are smart. The point of contention is the belief that views should not talk to models or know anything about models. However, this notion of a Model-View-Presenter pattern is not “Model-View-Controller”; views in our paradigm do not need to be completely passive. I would argue that Model-View-Presenter is appropriate only if you are architecturally constrained by a UI which does not allow you to build a more intelligent views that are able to participate in their own lifecycle or constructed to understand the context in which they are used.)

So refactoring our table view cell into it’s own class, we get a new class TableViewCell:

#import <UIKit/UIKit.h>

@interface TableViewCell : UITableViewCell

- (void)setData:(NSDictionary *)data;

@end

Notice the simplicity of the interface; as the view cell is responsible for parsing and understanding the contents at a given row, we only need to pass the row into the cell.

The implementation is also straight forward:

#import "TableViewCell.h"
#import "ImageLoader.h"

@interface TableViewCell ()
@property (copy, nonatomic) NSString *pathImage;
@end

@implementation TableViewCell

- (void)setData:(NSDictionary *)d
{
	NSString *title = d[@"title"];

	NSString *addr = [NSString stringWithFormat:@"%@, %@",d[@"city"],d[@"state"]];
	NSString *subtitle = addr;

	self.textLabel.text = title;
	self.detailTextLabel.text = subtitle;

	// Load the image
	NSString *loadPath = d[@"image"];
	self.pathImage = loadPath;
	self.imageView.image = [UIImage imageNamed:@"missing"];
	[[ImageLoader shared] downloadImage:loadPath withCallback:^(NSString *path, UIImage *image) {
		if ([self.pathImage isEqualToString:path]) {
			self.imageView.image = image;
		}
	}];
}

@end

Notice the advantage of this class: it does exactly one thing and one thing only. It loads the table view cell with the contents of our data. That’s it.

And because it only does one thing and does it simply, it is easy for us to incorporate into other table views, and it is easy for us to fix problems if we discover problems with how we’re parsing the data for presentation.

Also notice a side effect: the table view cell has become responsible for loading the image that is being displayed in itself. Our view controller now reduces to something far simpler to maintain:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	[cell setData:self.data[indexPath.row]];

	return cell;
}

Our view controller is no longer responsible for loading the image, so it no longer has to maintain a cache or even understand that some images are being loaded in the background.

We can even take this one step further, and rather than have our table view cell be responsible for handling loading of the image, we could create a separate image class which handles loading the image itself.

So here’s a simple implementation of our image loading class, which extends the UIImageView class:

#import <UIKit/UIKit.h>

@interface ImageView : UIImageView

- (void)imageFromPath:(NSString *)path;

@end

and our implementation:

#import "ImageView.h"
#import "ImageLoader.h"

@interface ImageView ()
@property (copy) NSString *path;
@end

@implementation ImageView

- (void)imageFromPath:(NSString *)loadPath
{
	self.image = [UIImage imageNamed:@"missing"];

	self.path = loadPath;
	[[ImageLoader shared] downloadImage:loadPath withCallback:^(NSString *path, UIImage *image) {
		if ([self.path isEqualToString:path]) {
			self.image = image;
		}
	}];
}

@end

Notice the advantage of this class: it does exactly one thing and one thing only. It load the image and displays it given the path of the image to display. That’s it.

And because it only does one thing and does it simply, it is easy for us to use throughout our application. Further, because it is only one class, if we decide to incorporate some more fancy features (such as a loading animation which fades the downloaded image from a black screen), we could add that by updating the code only in one place–and see the functionality throughout or application.

We inherit from the UIImageView class so we get all of the benefits of that class as well. This allows us to greatly simplify our table view cell’s initialization code (after we’ve changed the image view to our custom implementation):

- (void)setData:(NSDictionary *)d
{
	NSString *title = d[@"title"];

	NSString *addr = [NSString stringWithFormat:@"%@, %@",d[@"city"],d[@"state"]];
	NSString *subtitle = addr;

	self.textLabel.text = title;
	self.detailTextLabel.text = subtitle;
	[self.imageView imageFromPath:d[@"image"]];
}

@end

Of course sometimes you can take this to the point of absurdity. But the advantage of constructing our application using reusable components is that we can reuse them–and reuse depends on us isolating functionality into well-defined components, and having each component do its one thing well.

Besides, our applications never become simpler; product managers and business managers and program managers almost never ask us to remove features or to remove the presentation of things on our applications. They are forever pushing new functionality and new features onto our applications.

I guarantee you if you start with a very simple image loader class, eventually new requirements will expand the size of that class. Table view cells eventually contain more information, or contain tappable regions which expand to present more information. Image view loaders become more slick, with dynamic animating components and wait cursors and broken image displays.

So if your table view cell implementation starts at 10 lines, it won’t stay 10 lines for long–even if you keep to the mantra of keeping your components behavior simple and well defined, doing only one thing and doing that one thing well.


It is worth noting there is an anti-pattern to this idiom, which is rather common in the field and should be avoided at all costs.

Let’s take our current example. Suppose we have a view controller and our table cell which handles presenting the contents of a row to a view table. Suppose, however, we haven’t added loading images into our table cell yet. So our TableViewCell class’s setData function looks like the following:

- (void)setData:(NSDictionary *)d
{
	NSString *title = d[@"title"];

	NSString *addr = [NSString stringWithFormat:@"%@, %@",d[@"city"],d[@"state"]];
	NSString *subtitle = addr;

	self.textLabel.text = title;
	self.detailTextLabel.text = subtitle;
}

@end

And our View Controller’s table delegates look like the following:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	[cell setData:self.data[indexPath.row]];

	return cell;
}

Now we’ve been assigned to load images from a path location into our table cells. Rather than allow the table cell code to do what it does best (manage the presentation of the data in the table cell), instead, we add the code to handle loading the image in the background into our view controller:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

	NSDictionary *d = self.data[indexPath.row];
	[cell setData:d];

	// Load the image
	NSString *loadPath = d[@"image"];
	objc_setAssociatedObject(cell,ImageNameKey,loadPath,OBJC_ASSOCIATION_COPY);
	cell.imageView.image = [UIImage imageNamed:@"missing"];
	[[ImageLoader shared] downloadImage:loadPath withCallback:^(NSString *path, UIImage *image) {
		NSString *curPath = objc_getAssociatedObject(cell, ImageNameKey);
		if ([curPath isEqualToString:path]) {
			cell.imageView.image = image;
		}
	}];

	return cell;
}

Now look at the mess we’ve made.

We’ve violated the contract of the TableViewCell class by taking part of its responsibility for presentation, and moved it into the view controller.

“So what?” you may say.

Well, the problems with this anti-pattern are:

First, because you have violated the contract of allowing the table cell view to handle presentation of the data object, you now have made it more difficult to manage that class. Changes in the data model are now scattered between the table cell class and various view controllers which use that class.

Because of this, second, bug are harder to fix, as the responsibility for presentation is not only scattered across several possible view controllers, but it is also split between view controllers and an incomplete table view cell. This means a change to the software will require spelunking through the source code, rather than going to the one location where the functionality is handled.


Life is too short and too complicated as it is to set ourselves up for failure.

The Fifth Principle: An idiom should be unobtrusive and not clever.

This is a continuation of the blog post 12 Principles of Good Software Design.

5. An idiom should be unobtrusive and not clever.

As software developers we love to solve hard problems. The best software developers out there started with a desire to solve interesting and complicated puzzles or with the desire to make things. We enjoy the mental struggle of figuring out how to put something together, to make something appear on the screen, to wire up a bit of functionality–and when finally that button appears, the transaction is received from a remote server, the LED lights up on our embedded board–its like winning a small jackpot. Our hard work and effort allowed us to do something cool, something futuristic, something that may impact the world.

And it’s hard not to get caught up in the latest and greatest, solving problems using all the tools at our disposal. There are a lot of clever things we can do to make our code seem simpler, to make our code seem more compact, to streamline the process of writing new features. We even share those hacks with others, promulgating open source libraries which helped us solve our problem in a particularly clever way, using obscure tricks and particularly interesting ways to handle things to make our code seem “automagic”.

In some ways we’re crying out “see how clever I am?” rather than solving real problems.

I admit, I’ve done it myself.


The problem with clever solutions is that they often leverage relatively obscure language features in order to hide functionality which makes it harder for another developer to understand what is going on.

For example, here’s a particularly clever way to handle binding data fields to their associated views using KVO and some degree of introspection during the loading phase of a view controller. From our previous example, we build a binding class which allows changes in our model data to be automatically detected and used to populate the field which displays its value. This class had the following declaration:

@interface Binder : NSObject
- (void)bindKeyPath:(NSString *)path ofObject:(NSObject *)object withCallback:(void (^)(void))callback;
@end

And to use it in our ViewController, we explicitly watch for changes in our model in order to update its contents:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Load the contents from our server
	 */

	self.balance.text = @"";
	self.change.text = @"";
	self.viewModel = [[ViewModel alloc] init];
	
	self.binder = [[Binder alloc] init];
	[self.binder bindKeyPath:@"balance" ofObject:self.viewModel withCallback:^{
		double val = self.viewModel.balance;
		self.balance.text = [NSString stringWithFormat:@"%.2f",val];
	}];
}

But as we noted in the previous example, this does not reduce the amount of code that exists in our ViewController. We still have to populate the contents of our view when we detect changes in the model.

We can update our binder, to make the binding automatic. By associating values with our views within a view controller, we could recursively iterate through all of the views within a view controller, tying the view model fields in our view controller against those views.

In this example, I will go one step further and tie the edit field of our original view controller to a two-way association: if the value inside the model changes, our text field updates. But if we type in the text field, we also update the view model contents as well; removing the responsibility from the view controller from dealing with extracting and parsing the contents of the text field.

To do this we first want to alter the signature of our binder class:

@interface Binder : NSObject
- (void)bindToViewController:(UIViewController *)vc;
@end

This allows us to rewrite our view controller as follows, removing any mention of the views within it (as the binding are automagically handled for us):

#import "ViewController.h"
#import "ViewModel.h"
#import "Binder.h"

@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) ViewModel *viewModel;
@property (strong, nonatomic) Binder *binder;

@end

@implementation ViewController

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Create and bind our view model
	 */

	self.viewModel = [[ViewModel alloc] init];
	self.binder = [[Binder alloc] init];
	[self.binder bindToViewController:self];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
	/*
	 *	Check to make sure our balance has been properly adjusted
	 */

	NSInteger err = [self.viewModel updateBalance];
	if (err == UPDATEERROR_ILLEGAL) {
		/*
		 *	This would draw to zero. Alert the user rather than make the
		 *	round trip to the server
		 */

		UIAlertController *c = [UIAlertController alertControllerWithTitle:@"Illegal value" message:@"You may not reset the balance below zero" preferredStyle:UIAlertControllerStyleAlert];

		UIAlertAction *action = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
		[c addAction:action];

		[self presentViewController:c animated:YES completion:nil];
	}

	return NO;
}

@end

Notice that we have completely divorced the content of our view controller from behaviors handled by our view controller; binding is now being handled within our Binder class.

In order to indicate which fields for our views are associated with our model, we need to create a category which allows us to set the user defined runtime attributes associated with our views. We do that with a category which makes use of the Objective C runtime routine objc_setAssociatedObject:

#import <UIKit/UIKit.h>

@interface UIView (MVVMParams)

- (NSString *)modelField;
- (void)setModelField:(NSString *)modelField;

- (NSString *)modelType;
- (void)setModelType:(NSString *)modelType;

- (NSObject *)model;
- (void)setModel:(NSObject *)model;

@end

The implementation of this category is relatively trivial:

#import "UIView+MVVMParams.h"
#import <objc/runtime.h>

/*
 *	This category uses associations to store our parameters to tie in this
 *	view to the model field and how to handle model changes
 */

static const void *ModelFieldKey = &ModelFieldKey;
static const void *ModelTypeKey = &ModelTypeKey;
static const void *ModelKey = &ModelKey;

@implementation UIView (MVVMParams)

- (NSString *)modelField
{
	return objc_getAssociatedObject(self,ModelFieldKey);
}

- (void)setModelField:(NSString *)modelField
{
	objc_setAssociatedObject(self, ModelFieldKey, modelField, OBJC_ASSOCIATION_COPY);
}

- (NSString *)modelType
{
	return objc_getAssociatedObject(self,ModelTypeKey);
}

- (void)setModelType:(NSString *)modelType
{
	objc_setAssociatedObject(self, ModelTypeKey, modelType, OBJC_ASSOCIATION_COPY);
}

- (NSObject *)model
{
	return objc_getAssociatedObject(self,ModelKey);
}

- (void)setModel:(NSObject *)model
{
	objc_setAssociatedObject(self, ModelKey, model, OBJC_ASSOCIATION_RETAIN);
}


@end

Note that each of the parameters we set (two from within the NIB editor and one which is used by our Binder) simply store the value with an association object.

What this allows us to do is to indicate the model field and model type in our NIB file. So, for example, with our UILabel, within Xcode, we can do the following:

Bind1

The category will be invoked as the view is loaded, tying the key path to the stored object. This now allows us to tie our label to the model field ‘balance’, and we specify the type as ‘fpint’. (Really, ‘fpint’ could have been anything; it’s used by our Binder code to determine how to handle the field as we will see below.)

We can now expand our ViewModel as such:

#import <Foundation/Foundation.h>

// Possible updateBalance return codes
#define UPDATEERROR_OK		0
#define UPDATEERROR_ILLEGAL	1

@interface ViewModel : NSObject
@property (nonatomic, assign) double balance;
@property (nonatomic, assign) double change;

- (void)reload;			// Reload balance
- (NSInteger)updateBalance;
@end

Notice we now have a new field, change, which will be tied via our binder to the change text field in our example. And notice that because of this, we no longer pass in a change amount to the updateBalance method; change dynamically updates as we type; updateBalance is simply triggered when it’s time to update our balance.

Our binder class has become far more complex, of course, but it is written only once. The class needs to handle binding our view model to the views inside our view controller:

// Scans all views in the view controller, constructing appropriate binding
// actions according to the parameters associated with the view.
- (void)bindToViewController:(UIViewController *)vc
{
	// First, make sure we can obtain the model
	if (![vc respondsToSelector:@selector(viewModel)]) {
		NSLog(@"Error: view controller must store the view model as viewModel");
		return;
	}

	// Now recurse through all views to tie to VM
	NSObject *vm = [(id<VCModel>)vc viewModel];
	[self bindViewToModel:vc.view model:vm];
}

Note that we expect our view model to be stored in a field in the view controller called ‘viewModel’, and we determine if we can obtain the view model by examining if our view controller class implements the ‘viewModel’ selector. If it does, we obtain the view model (and we quiet compiler errors by implementing a couple of protocols), and then we bind by recursing through all the views.

(The syntax sugar we use to shut the compiler up is:

@protocol VCModel <NSObject>
- (NSObject *)viewModel;
@end

@protocol VText <NSObject>
- (NSString *)text;
- (void)setText:(NSString *)text;
@end

The first allows us to obtain the viewModel field, the second allows us access to the text and setText fields of UILabel and UITextField.)

Our binder then recurses through all the views in the view controller, determining if any of them have an associated modelField and modelType. If they do, we then create the appropriate blocks to handle copying data in and out of the views to their respective model fields:

- (void)bindViewToModel:(UIView *)view model:(NSObject *)model
{
	// If we set the model field, tie to our model
	if (nil != (view.modelField)) {
		/*
		 *	Determine how we tie based on the model type and the type of
		 *	the class. For now we only handle UILabels and UITextFields.
		 */

		NSString *modelField = view.modelField;
		NSString *modelType = view.modelType;

		if ([view isKindOfClass:[UILabel class]]) {
			// The association is only one-way.
			[self bindKeyPath:modelField ofObject:model withCallback:^{
				[self transferToView:(UIView<VText> *)view model:model field:modelField type:modelType];
			}];
		} else if ([view isKindOfClass:[UITextField class]]) {
			// Association is two way. First tie from model to view
			[self bindKeyPath:modelField ofObject:model withCallback:^{
				[self transferToView:(UIView<VText> *)view model:model field:modelField type:modelType];
			}];

			// Now tie from view to model. Because we can't use KVO to observe
			// changes in the text, we hook up a notification
			view.model = model;
			[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateModelFromKey:) name:UITextFieldTextDidChangeNotification object:view];
		}
	}

	// recurse down the rest of the views
	NSArray *children = view.subviews;
	for (UIView *v in children) {
		[self bindViewToModel:v model:model];
	}
}

Our method to transfer data from the changed model into the view is simple:

// Actually pulls the data out of the model and transforms to text by type
- (void)transferToView:(UIView<VText> *)view model:(NSObject *)model field:(NSString *)field type:(NSString *)type
{
	if ([view isFirstResponder]) return;	// if we have the focus, don't update
	if ([type isEqualToString:@"fpint"]) {
		// Extract the field by calling the appropriate object send
		NSNumber *v = [model valueForKey:field];
		view.text = [NSString stringWithFormat:@"%.2f",v.doubleValue];
	}
	// TODO: Other types here.
}

Note in our example we only handle the ‘fpint’ model type. Other types would simply extend this method.

And transfering data from our view as it is updated is equally straight forward, and equally would need to change if we added other field types:

- (void)transferFromView:(UIView<VText> *)view model:(NSObject *)model field:(NSString *)field type:(NSString *)type
{
	if ([type isEqualToString:@"fpint"]) {
		// Convert floating point value
		NSString *str = view.text;
		NSNumber *val = [NSNumber numberWithDouble:str.doubleValue];
		[model setValue:val forKey:field];
	}
}

Because we are unable to get events when the text field of a UITextField, we instead look for field change notifications. We handle those notifications here:

- (void)updateModelFromKey:(NSNotification *)n
{
	UITextField *textField = n.object;
	NSString *modelField = textField.modelField;
	NSString *modelType = textField.modelType;
	NSObject *model = textField.model;

	if (model != nil) {
		[self transferFromView:(UIView *)textField model:model field:modelField type:modelType];
	}
}

This now allows us to monitor text field changes and update our model as it does.

Our complete binder class now looks like the following:

//
//  Binder.m
//  TestPrinciples
//
//  Created by William Woody on 7/26/16.
//  Copyright © 2016 Glenview Software. All rights reserved.
//

#import "Binder.h"
#import "BinderKey.h"
#import "UIView+MVVMParams.h"
#import <objc/runtime.h>

// Syntax sugar to allow us to obtain the view model from a view controller
@protocol VCModel <NSObject>
- (NSObject *)viewModel;
@end

@protocol VText <NSObject>
- (NSString *)text;
- (void)setText:(NSString *)text;
@end

// Simple binder utility aids in KVO observation

@interface Binder ()
@property (strong, nonatomic) NSMutableDictionary *map;
@end

@implementation Binder

- (id)init
{
	if (nil != (self = [super init])) {
		self.map = [[NSMutableDictionary alloc] init];
	}
	return self;
}

- (void)dealloc
{
	NSArray *a = [self.map allKeys];
	for (BinderKey *b in a) {
		[b.object removeObserver:self forKeyPath:b.keyPath];
	}

	[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)bindKeyPath:(NSString *)path ofObject:(NSObject *)object withCallback:(void (^)(void))callback;
{
	BinderKey *k = [[BinderKey alloc] initWithObject:object keyPath:path];
	void (^copyCallback)(void) = [callback copy];
	self.map[k] = copyCallback;

	[object addObserver:self forKeyPath:path options:NSKeyValueObservingOptionNew context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
	BinderKey *k = [[BinderKey alloc] initWithObject:object keyPath:keyPath];
	void (^callback)(void) = self.map[k];
	if (callback) callback();
}

// Actually pulls the data out of the model and transforms to text by type
- (void)transferToView:(UIView<VText> *)view model:(NSObject *)model field:(NSString *)field type:(NSString *)type
{
	if ([view isFirstResponder]) return;	// if we have the focus, don't update
	if ([type isEqualToString:@"fpint"]) {
		// Extract the field by calling the appropriate object send
		NSNumber *v = [model valueForKey:field];
		view.text = [NSString stringWithFormat:@"%.2f",v.doubleValue];
	}
	// TODO: Other types here.
}

- (void)transferFromView:(UIView<VText> *)view model:(NSObject *)model field:(NSString *)field type:(NSString *)type
{
	if ([type isEqualToString:@"fpint"]) {
		// Convert floating point value
		NSString *str = view.text;
		NSNumber *val = [NSNumber numberWithDouble:str.doubleValue];
		[model setValue:val forKey:field];
	}
}

- (void)updateModelFromKey:(NSNotification *)n
{
	UITextField *textField = n.object;
	NSString *modelField = textField.modelField;
	NSString *modelType = textField.modelType;
	NSObject *model = textField.model;

	if (model != nil) {
		[self transferFromView:(UIView<VText> *)textField model:model field:modelField type:modelType];
	}
}

// Recurses through views to make appropriate ties to view model
- (void)bindViewToModel:(UIView *)view model:(NSObject *)model
{
	// If we set the model field, tie to our model
	if (nil != (view.modelField)) {
		/*
		 *	Determine how we tie based on the model type and the type of
		 *	the class. For now we only handle UILabels and UITextFields.
		 */

		NSString *modelField = view.modelField;
		NSString *modelType = view.modelType;

		if ([view isKindOfClass:[UILabel class]]) {
			// The association is only one-way.
			[self bindKeyPath:modelField ofObject:model withCallback:^{
				[self transferToView:(UIView<VText> *)view model:model field:modelField type:modelType];
			}];
		} else if ([view isKindOfClass:[UITextField class]]) {
			// Association is two way. First tie from model to view
			[self bindKeyPath:modelField ofObject:model withCallback:^{
				[self transferToView:(UIView<VText> *)view model:model field:modelField type:modelType];
			}];

			// Now tie from view to model. Because we can't use KVO to observe
			// changes in the text, we hook up a notification
			view.model = model;
			[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateModelFromKey:) name:UITextFieldTextDidChangeNotification object:view];
		}
	}

	// recurse down the rest of the views
	NSArray<UIView *> *children = view.subviews;
	for (UIView *v in children) {
		[self bindViewToModel:v model:model];
	}
}

// Scans all views in the view controller, constructing appropriate binding
// actions according to the parameters associated with the view.
- (void)bindToViewController:(UIViewController *)vc
{
	// First, make sure we can obtain the model
	if (![vc respondsToSelector:@selector(viewModel)]) {
		NSLog(@"Error: view controller must store the view model as viewModel");
		return;
	}

	// Now recurse through all views to tie to VM
	NSObject *vm = [(id<VCModel>)vc viewModel];
	[self bindViewToModel:vc.view model:vm];
}

@end

Our solution is extraordinarily clever, in that we’ve completely removed the responsibility for binding the views within our view controller to the view model. And notice the apparent elegance of our view controller:

#import "ViewController.h"
#import "ViewModel.h"
#import "Binder.h"

@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) ViewModel *viewModel;
@property (strong, nonatomic) Binder *binder;

@end

@implementation ViewController

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Create and bind our view model
	 */

	self.viewModel = [[ViewModel alloc] init];
	self.binder = [[Binder alloc] init];
	[self.binder bindToViewController:self];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
	/*
	 *	Check to make sure our balance has been properly adjusted
	 */

	NSInteger err = [self.viewModel updateBalance];
	if (err == UPDATEERROR_ILLEGAL) {
		/*
		 *	This would draw to zero. Alert the user rather than make the
		 *	round trip to the server
		 */

		UIAlertController *c = [UIAlertController alertControllerWithTitle:@"Illegal value" message:@"You may not reset the balance below zero" preferredStyle:UIAlertControllerStyleAlert];

		UIAlertAction *action = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
		[c addAction:action];

		[self presentViewController:c animated:YES completion:nil];
	}

	return NO;
}

@end

So what is wrong with being clever?

First, imagine you are a new developer to the project, and you are not familiar with the source kit, or with the way Objective C allows you to do introspection.

And you see an application that presents a screen like the one below:

Screen1

Then you look at the view controller above.

If you are familiar with the MVVM model, you see the ViewModel object being used, and you look at that class:

@interface ViewModel : NSObject
@property (nonatomic, assign) double balance;
@property (nonatomic, assign) double change;

- (void)reload;			// Reload balance
- (NSInteger)updateBalance;
@end

And what is the first thing you are going to ask?

Where are the properties in the View Controller which access the views?

There is no code that seems to populate the balance. There is no code that appears to update the balance. There is no code that appears to obtain the text field contents when the return button is pressed.

And the ViewModel class is only slightly helpful: sure, you see the logic to get the balance from the server, and you see the code to update the balance and perform run-time error checking.

But the rest is hidden behind this black box called Binder.

And worse, who ever thinks to look at the User Defined Runtime Attributes area for a particular view within the NIB editor? Even if you look there, what does “modelField” and “modelType” even mean?


And notice the problems with the code.

It’s fragile.

If the name of the fields within the ViewModel class change, you must hunt down where the fields are used within the view controller layout within the NIB to determine the associations.

It’s opaque

How would you know–without extensive documentation–that a ViewController must implement the ‘viewModel’ method in order to allow the binder to obtain the contents of the view model for binding?

There is no way you could know that the following is a fatal problem:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Create and bind our view model
	 */

	self.binder = [[Binder alloc] init];
	[self.binder bindToViewController:self];
	self.viewModel = [[ViewModel alloc] init];
}

That’s because the binder class requires the viewModel field to be initialized prior to the call to -bindToViewController:, and there is no way to know this simply by examining the initialization code.

And if you do make this mistake, what is the error you get?

*** Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[<ViewController 0x7b11c540> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key change.’

Very descriptive. </sarcasm>

In being clever we introduce a variety of opportunities for bugs.

What prevents a simple typo buried deeply in the NIB from breaking the whole scheme? What if on the UILabel we accidentally misspelled “balance” as “balances”? Or use “fbInt” instead of “fbint”? We can only catch these obscure issues via a through exercise of the entire user interface–and many teams simply do not have time to do this.

It’s not “future-proof.”

What happens to the helper category if Apple introduces a new version of the operating system which adds the ‘model’ property to certain subviews, for example?


The problem with this code is that it is not obvious. It is unclear. It’s clever to the point of intruding on how we think about view controllers. And it makes use of some fragile declarations which could easily break in a future version of the iPhone operating system.

The meaning of the code has been hidden from us behind a clever but fragile construct, making it nearly impossible for another developer to maintain.

And for what? Removing a dozen lines of code from a View Controller out of some architectural deal, solving a problem that didn’t really exist in the first place?


Do you know what terrifies me about this post? Someone will think my Binder class is so cool they will flesh it out (the complete code can be found in this post and an earlier one), and post it to Github, crediting me for such a cool and clever tool.

(Shakes head)

The Fourth Principle: An idiom should make your code easier to read.

This is a continuation of the blog post 12 Principles of Good Software Design.

4. An idiom should make your code easier to read

When you write code, you actually have two audiences, two “readers” who will be reading your software.

The first audience is the environment of compiler tools, preprocessing tools, analysis tools and other components of your development system which convert your code into a working application. That first audience is impartial, and only cares about the results of your authorship: does the compiled program run, does it meet the requirements, can testers break your code, does QA validate your code’s correctness.

For many of us, the reason why we got into software development was to write code for that impartial first audience. That audience knows no political values, is entirely emotionless. It allows us to solve difficult puzzles and tells us if our answers are right or wrong without any judgement beyond correctness. And for many of us, the fact that software development is one of the last professions which gives you a nearly guaranteed ticket to the upper-middle class is just a side benefit; it allows us to live in some degree of comfort as we solve increasingly interesting puzzles.

But there is a second audience for our code, one which many of us neglect.

Our fellow programmers.

And in many ways, writing code is very similar to writing an essay. You have related blocks of thought which are designed to hammer a single conclusion. You have varying ideas that are brought together into a single idea. You have unrelated topics that you may bounce around that eventually come together to tell a story.

All of this contributing to clarity and to communicating an idea.


Thus far, in the previous three essays covering making code simpler, making code concise and making code clear, we’ve incidentally also contributed to making code more readable. For this essay I’d like to concentrate on smaller idioms; on ways we can make code more readable that doesn’t necessarily employ using design patterns or on the choice of idioms as we refactor code.

One way we can make code more clear is in our choice of variable names.

It’s such a small thing, a variable name. But it can have a serious impact on our understanding of the code.

Now, compilers don’t care about variable names; only that you use those variables consistently. That’s how code obfuscation works with languages such as Javascript; the code remains the same, but the variables are renamed to obscure meaning to a human reader. As far as a compiler is concerned the declarations below:

#define __A long
struct __a {
	__A __b;
	__A __c;
	__A __d;
	__A __e;
};

is identical to the following declaration:

#define Integer long
struct Rect {
	Integer left;
	Integer top;
	Integer width;
	Integer height;
};

And if we were to write code that manipulates rectangles, either declaration would be fine, as far as the compiler is concerned.

Other readers of our code, however, may become puzzled when they see us manipulate rectangles using the __a declaration.

There are many naming conventions out there for variables, and many theories about why you should name variables using those different conventions. I don’t wish to come down on any side in those arguments, except to note three things.

First, a number of older conventions arose because of compiler limitations. For example, earlier C compiler linkers had limits on the maximum number of characters in a variable name that was stored. Some early C compilers only kept track of the first 6 characters or the first 32 characters of a variable name; thus, they could not tell the difference between aPointInTime and aPointOnTheLine, as compilers only storing the first 6 characters for a variable name would store aPoint for both variables.

(This is why in some early programs you see variable names like a11PointInTime or a12PointOnTheLine.)

I don’t believe any of these early tool chains exist anymore, so naming conventions which attempt to make the first N characters of a variable name (for some number N) no longer are relevant.

Hungarian Notation also arose from compiler limitations; in this case, from limitations in the type system of earlier compilers which could not distinguish between different variable types. However, again, earlier compilers have been replaced by compiles with a stronger type system, and variable naming conventions such as these place an additional burden on the author of the code (and by extension, on the reader) that is no longer quite as important.

Second, there are limits on the ability for a reader to read long variable names. There is a reason why Einstein’s famous equation is not written:

NewImage

but rather, in the more compact form:

NewImage

This, despite the fact that the former representation is arguably more informative.

Book layout editors and newspaper authors both know that the human eye can only see so much, can only scan so much distance across a line of text and successfully return to the next line, can only see so much text in a single word. Words like “antidisestablishmentarianism” exist mostly as curiosities in an essay such as mine where the average word length is less than 6 characters.

It’s not to suggest that we should go to the other extreme, that we should go to a FORTRAN-style naming convention or a naming convention from early forms of BASIC where all variable names were kept to two characters or less. But it is to suggest that a concise variable name may be easier for someone to follow–assuming the name is descriptive enough to describe what the variable holds.

In some places, I personally use short variable names. I grew up in an era where integer loop variables were i, j or k; sometimes I abbreviate temporary variables holding the length of a thing len, or a variable holding a single character as ch. But these are immediate temporary variables used only within local scope, and by using such short variable names I hope to distinguish between them and class-scope variables such as submitButton or cachedLength.

But this is my style, just as my essay writing style incorporates run-on sentences, sometimes punctuated with short sentences to drive a point home. There is a place for personal style.

So long as we convey the idea we wish to convey in a clear and concise manner, we’ve accomplished our purpose.

Third, consistent naming conventions help with understanding. You can see this all throughout Apple’s development libraries. From the earliest days of Inside Macintosh, Apple used standard naming conventions for their toolbox functions: open balances with close, new balances with dispose, create balances with delete, begin balances with end.

In more recent versions of MacOS X and iOS prior to ARC, method names starting with alloc, new, or containing copy would pass ownership to the caller and would need to be released either using the release or autorelease methods. This naming convention is enforced by ARC and is also enforced by Apple’s Xcode analysis tools.

Naming conventions are important, because they enforce consistency and help developers maintaining your code remember what are the correct methods to call when extending your code. It’s not necessary to use Apple’s naming conventions; what is important is to stick to a naming convention in a consistent fashion throughout your code.

If you use a naming convention such as the one used in Java, where routines that start with ‘get’ get the contents of a variable name (without side effects), and ‘set’ sets the value of a variable name (without meaningful side effects), then stick to that naming convention. Don’t suddenly create a new class like the following:

public class MyThing
{
	private int __value;
	
	public int value()
	{
		return __value;
	}
	
	public void updateValue(int v)
	{
		__value = v;
	}
}

Also, it’s important to be aware of any naming conventions in the environment you are using. For example, while Java uses ‘get’ as the getter for a variable held by a class, Objective C simply uses the name of the variable:

@implmentation MyThing
- (void)setValue:(int)v
{
	self.internalValue = v;
}
- (int)value
{
	return self.internalValue;
}
@end

If you are creating a class which manages resources, you may wish to use a consistent naming convention throughout. So, for example, like in the Macintosh System Toolbox, creating a window is done using ‘newWindow’; releasing is done with ‘disposeWindow’. Creating a new resource is done using ‘newResource’; releasing with ‘disposeResource’. And this consistency allows a new developer who sees a chunk of code creating a new scratch database with the method ‘newScratchDatabase’ can know with some degree of certainty the release call will be ‘disposeScratchDatabase.’


Beyond just naming conventions there are other ways you can aid with readability of your code. Like this essay, code has “sections”, “paragraphs” (which group functionality), and “sentences” or statements which describe an idea. Your choice of how you organize your sentences within a paragraph can aid in readability, even if you do not choose to refactor your code into separate functions or by using a design pattern. White space can be a powerful tool in comprehension.

For example, take the following code from a previous essay:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Set up the appearance of our interface
	 */

	self.firstButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.secondButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.firstButton.layer.borderWidth = 1;
	self.secondButton.layer.borderWidth = 1;
	self.thirdButton.layer.borderWidth = 2;
	self.thirdButton.layer.borderColor = [UIColor darkGrayColor].CGColor;
	self.firstButton.layer.cornerRadius = 6;
	self.secondButton.layer.cornerRadius = 6;
	self.thirdButton.layer.cornerRadius = 6;
}

The clump of code at the bottom initializes three buttons, one representing a “default” button. Our previous solution involved refactoring the code by removing common functionality into a separate method call.

But we can make our code above more readable simply by reordering our statements and adding some white space:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Set up the appearance of our interface
	 */

	self.firstButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.firstButton.layer.borderWidth = 1;
	self.firstButton.layer.cornerRadius = 6;

	self.secondButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.secondButton.layer.borderWidth = 1;
	self.secondButton.layer.cornerRadius = 6;

	self.thirdButton.layer.borderColor = [UIColor darkGrayColor].CGColor;
	self.thirdButton.layer.borderWidth = 2;
	self.thirdButton.layer.cornerRadius = 6;
}

This is far more readable than the previous example, and all we did was clump calls which affected buttons into their own block of code, reordering the statements so that they match, and adding white space to help visually separate clumps of code.

In fact, this should be the first step in refactoring our code into a separate method call.


Run-on statements can similarly be broken down in order to aid with understanding. With earlier compilers, run-on statements helped the compiler optimize for performance, but today’s optimizing compilers do not require collapsing statements into more compact forms in order to optimize the code. In fact, certain statement representations may hinder code optimization, and rewriting run-on statements can help the compiler by reducing statement complexity.

Take, for example, the following statement which draws text within a rectangle:

- (void)draw
{
	[UIColor.blackColor setStroke];
	[[UIBezierPath bezierPathWithRect: CGRectMake(39, 31, 88, 30)] stroke];
	[@"This is a test." drawInRect: CGRectMake(39, 31, 88, 30) withAttributes: @{ NSFontAttributeName: [UIFont fontWithName: @"HelveticaNeue" size: 12], NSForegroundColorAttributeName: UIColor.blackColor }];
}

While compact, this code is hard to follow, and has the problem of repeating code which initializes the rectangle we are drawing into. We can aid in the readability of this code by expanding the run-on statements:

- (void)draw
{
	CGRect rect = CGRectMake(39, 31, 88, 30);

	[UIColor.blackColor setStroke];
	UIBezierPath *path = [UIBezierPath bezierPathWithRect: rect];
	[path stroke];

	UIFont *font = [UIFont fontWithName: @"HelveticaNeue" size: 12];
	UIColor *color = UIColor.blackColor;
	NSDictionary *attrs = @{ NSFontAttributeName: font,
							 NSForegroundColorAttributeName: color };
	[@"This is a test." drawInRect: rect withAttributes: attrs];
}

While taking more lines, we can now see where we are creating our rectangle path, where we are creating our font, our color for our text, and we can now understand all the side effects of our code. We even collapsed the two rectangle creation statements into one, thereby reducing the potential for error.

From the latter representation we now have a better understanding–and we can contemplate further refactoring steps, such as passing in the text or rectangle as parameters, or manipulating the location of the text to be centered in the rectangle. We could also obtain the text attributes from a separate function call (so we consistently use the same text attributes in other places in our code).

Sometimes smaller isn’t better.


In the end it doesn’t matter the naming conventions you use. What is important is that the convention is used with consistency; consistency aids with readability.

And as long as you remember that you are writing for an audience of fellow programmers, and write your code in such a way as to make your code easier to read, then you can help your audience in their understanding as they take over your source kit to maintain it in the future.

The Third Principle: An idiom should make the intent of your code clear.

This is a continuation of the blog post 12 Principles of Good Software Design.

3. An idiom should make the intent of your code clear

I’ve seen in a number of places a number of rules for writing good code. Many of the rules revolve around having a class method do only one thing, or making sure functions have no side effects or that classes can be described with an “elevator pitch”; described in 10 seconds or less to someone who hasn’t a clue.

All of these ideas work because they help make clear the intent of your code.

Clarifying the intent of your code is important for a variety of reasons. By clarifying the intent of your code you make the intended functionality clear to yourself and to others who may work on your software. Clarifying the intent helps you organize your code in such a way so that it can be more easily maintained. And in striving for clear code you keep unnecessary complexity from creeping in.

There are a number of other ways to clarify the intent of your code.


Here’s a simple example. We have three buttons on iOS. In our -viewDidLoad: method we set up the user interface. One button stands out as the default button, the other two have lighter borders.

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Set up the appearance of our interface
	 */

	self.firstButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.secondButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
	self.firstButton.layer.borderWidth = 1;
	self.secondButton.layer.borderWidth = 1;
	self.thirdButton.layer.borderWidth = 2;
	self.thirdButton.layer.borderColor = [UIColor darkGrayColor].CGColor;
	self.firstButton.layer.cornerRadius = 6;
	self.secondButton.layer.cornerRadius = 6;
	self.thirdButton.layer.cornerRadius = 6;
}

Sure, the purpose of the -viewDidLoad: method is to initialize the user interface. But notice we’re doing more or less the same thing for each of the buttons. If we were to take the initialization and roll it into a separate method we can make the intent of our setup code a lot more clear.

First, refactor our common startup in a separate method:

+ (void)setupButton:(UIButton *)button asDefault:(BOOL)defFlag
{
	button.layer.borderColor = defFlag ? [UIColor darkGrayColor].CGColor : [UIColor lightGrayColor].CGColor;
	button.layer.borderWidth = defFlag ? 2 : 1;
	button.layer.cornerRadius = 6;
}

Now our startup code in -viewDidLoad: becomes far more apparent:

- (void)viewDidLoad
{
	[super viewDidLoad];

	/*
	 *	Set up the apperance of our interface
	 */

	[ViewController setupButton:self.firstButton  asDefault:NO];
	[ViewController setupButton:self.secondButton asDefault:NO];
	[ViewController setupButton:self.thirdButton  asDefault:YES];
}

We can readily see the intent of our 9 lines of initialization code.

And the advantage of expressing our intent in this way is that, in the future, if our requirements for the appearance of our buttons change, we only need to change the +setupButton:asDefault: method, as we’ve separated the semantics of how the button is used (asDefault:YES verses NO) from the actual appearance.


We can find another example from older versions of iOS. The UIAlertView class has a method for a delegate to receive a callback if the user dismisses the alert using a particular button. This allows you to prompt a user, and take action if they select “OK” from the alert.

For example, suppose we have a method which prompts the user to save data:

- (void)shouldSave
{
	UIAlertView *v = [[UIAlertView alloc] initWithTitle:@"Save?" 
			message:@"Should this file be saved?" 
			delegate:self 
			cancelButtonTitle:@"Cancel" 
			otherButtonTitles:@"Save", nil];
	[v show];
}

The problem is that we only show half of the intent of our code. Meaning the real intent of our code is to prompt the user, then to take action if the user responds in a particular way. Yet we only see half the intent; the other half is a few lines or a few hundred lines away:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
	if (buttonIndex == alertView.firstOtherButtonIndex) {
		( Do save operation )
	}
}

It gets worse if we have multiple alert views within a single controller; if we use our view controller as the single delegate for multiple alerts, we have to set some parameter in the alert, then create a switch statement to figure out which alert we were displaying.

Awkward.

Yet a simple helper class to allow us to get a call back in an Objective C block when an alert button is pressed can help us keep the code together–making the intent of our code more obvious.

Our AlertView class extends the UIAlertView with a new method:

@interface AlertView : UIAlertView<UIAlertViewDelegate>
- (void)showWithCallback:(void (^)(NSInteger btn))callback;
@end

The implementation is straight forward: the alert uses itself as the delegate, and passes the click button to the block provided:

#import "AlertView.h"

@interface AlertView ()
@property (copy) void (^callback)(NSInteger btn);
@end

@implementation AlertView

- (void)showWithCallback:(void (^)(NSInteger btn))cb
{
	self.callback = cb;
	self.delegate = self;
	[self show];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
	self.callback(buttonIndex);
}

@end

Now we can make the intent of our alert code more clear:

- (void)shouldSave
{
	AlertView *v = [[AlertView alloc] 
			initWithTitle:@"Save?" 
			message:@"Should this file be saved?" 
			delegate:nil
			cancelButtonTitle:@"Cancel" 
			otherButtonTitles:@"Save", nil];
	[v showWithCallback:^(NSInteger buttonIndex) {
		if (buttonIndex == v.firstOtherButtonIndex) {
			// Do save operation
		}
	}];
}

The intent is far clearer because the action of displaying the alert, and the code which handles the results of the alert, are now all together in one place.


Sometimes the intent of your code can be hard to convey because it implements a complex algorithm or does something unusual. But most of the applications we are asked to write are relatively simple: a screen is presented and the contents loaded from some source. You alter the contents of the data represented on the screen. The contents are then saved, and any errors along the way are displayed to the user.

Simple.

And by keeping the intent clear of each component we create, from setting up our user interface to saving the contents of our screen, you make it easier to maintain your code.

The Second Principle: An idiom should make your code concise.

This is a continuation of the blog post 12 Principles of Good Software Design.

2. An idiom should make your code concise

Suppose you have the task of creating an API for your application which can communicate with a back end server. For each API call you need to signal a wait spinner, assemble a request to the back end server, send the request, wait for the response, and parse the response in JSON, signaling a library if there is a server error so it can present the user an error message.

Suppose that our server takes its arguments as JSON as part of a POST payload. Thus, our requests look like this:

POST http://api.server.co/api/1/endpointname
{ "arg1": value_1,
  "arg2": value_2 ... }

Our endpoint “endpointname” requires two arguments, “arg1” and “arg2”, which pass in integer values.

The result, for our example, looks like this:

{ "result": result }

As a first pass, we could build a class Server which creates the NSURLSession object on iOS which allows us to make a network request and get a response. The declaration looks like this:

@interface Server : NSObject

+ (Server *)shared;

- (NSURLSession *)session;

@end

The class itself simply creates a session and returns it:

#import "Server.h"

@interface Server ()
@property (strong, nonatomic) NSURLSession *session;
@end

@implementation Server

- (id)init
{
	if (nil != (self = [super init])) {
		NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
		self.session = [NSURLSession sessionWithConfiguration:config];
	}
	return self;
}

+ (Server *)shared
{
	static Server *singleton;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		singleton = [[Server alloc] init];
	});
	return singleton;
}

@end

In order to make a request, we would then need to handle each of the steps above: start the wait spinner, assemble the request, send the request, and parse the response. For the example below we’ll ignore error codes and simply concentrate on the code which handles parsing the response.

Notice all the work we have to do in order to make our request:

- (void)doOperationWithCallback:(void (^)(NSInteger res))callback;
{
	void (^copyCallback)(NSInteger val) = [callback copy];

	int value1 = (do something here);
	int value2 = (do something here);

	// Start the wait spinner
	[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

	// Assemble the request
	NSString *endpoint = @"endpointname";
	NSString *reqString = [NSString stringWithFormat:@"%@%@",SERVERPREFIX,endpoint];
	NSURL *url = [NSURL URLWithString:reqString];

	NSMutableURLRequest *req;
	req = [[NSMutableURLRequest alloc] initWithURL:url];
	[req setHTTPMethod:@"POST"];

	NSDictionary *d = @{ @"arg1": @( value1 ),
						 @"arg2": @( value2 ) };
	NSData *jsonReq = [NSJSONSerialization dataWithJSONObject:d options:NSJSONWritingPrettyPrinted error:nil];
	[req setHTTPBody:jsonReq];
	[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

	// Now send the request and wait for the response
	[[Server shared].session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
		// Process the response. Note not handling errors for now.
		NSDictionary *respData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
		NSInteger retVal = [respData[@"result"] integerValue];

		// Dispatch back in main thread. (Our callback was in a separate
		// thread.)
		dispatch_async(dispatch_get_main_queue(), ^{
			[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
			copyCallback(retVal);
		});
	}];
}

At every point in our code where we call the back end we have to write the same 38 lines of code. We have to keep track of the callback block. We have to start and stop the spinner. We have to create the request. We have to parse the response from JSON to something we can use. We have to put the response back on the main UI thread.

And notice the bugs: if we have two network requests at the same time we may inadvertently turn off the network activity spinner before network activity is complete. We aren’t handling errors.

This is most certainly not concise. There are things we can do to help reduce the line count.

The simplest is to observe that we are starting and stopping the network activity spinner every time we make a network request. So we can extend our Server class to incorporate managing the network activity spinner.

So we change our server class declaration by hiding the session object and exposing a method call instead:

@interface Server : NSObject

+ (Server *)shared;

- (void)request:(NSURLRequest *)req completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))callback;

@end

Next, we create our request wrapper:

- (void)request:(NSURLRequest *)req completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))callback
{
	void (^copyCallback)(NSData *data, NSURLResponse *response, NSError *error) = [callback copy];

	// Start the wait spinner
	[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

	// Run the request
	[self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

		// Stop the wait spinner. Do this on the main thread
		dispatch_async(dispatch_get_main_queue(), ^{
			[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
		});

		// Call our callback
		copyCallback(data,response,error);
	}];
}

And now we can rewrite our operation call by eliminating the wait spinner.

- (void)doOperationWithCallback:(void (^)(NSInteger res))callback;
{
	void (^copyCallback)(NSInteger val) = [callback copy];

	int value1 = (do something here);
	int value2 = (do something here);

	// Assemble the request
	NSString *endpoint = @"endpointname";
	NSString *reqString = [NSString stringWithFormat:@"%@%@",SERVERPREFIX,endpoint];
	NSURL *url = [NSURL URLWithString:reqString];

	NSMutableURLRequest *req;
	req = [[NSMutableURLRequest alloc] initWithURL:url];
	[req setHTTPMethod:@"POST"];

	NSDictionary *d = @{ @"arg1": @( value1 ),
						 @"arg2": @( value2 ) };
	NSData *jsonReq = [NSJSONSerialization dataWithJSONObject:d options:NSJSONWritingPrettyPrinted error:nil];
	[req setHTTPBody:jsonReq];
	[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

	// Now send the request and wait for the response
	[[Server shared].session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
		// Process the response. Note not handling errors for now.
		NSDictionary *respData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
		NSInteger retVal = [respData[@"result"] integerValue];

		// Dispatch back in main thread. (Our callback was in a separate
		// thread.)
		dispatch_async(dispatch_get_main_queue(), ^{
			copyCallback(retVal);
		});
	}];
}

The code is shorter, but concise? Hardly.

There is an advantage to this code, by the way. Because our wait spinner code is now in one location rather than scattered everywhere where we make a request, we can easily update our wait spinner code to fix the bug of hiding the wait spinner prematurely when two network requests are made at the same time, by wrapping our code in a counter and hiding the spinner only when the count reaches zero.

Notice a couple of things about our server requests, however. First, our server example above always takes POST requests. Second, it always takes and returns JSON requests. Additionally we assume only the endpointname changes; the rest of the URL remains the same.

So why are we doing all this duplicate work?

Let’s move the functionality into our Server class.

First, we know we always take an endpoint name and an (optional) dictionary of parameters. And we know the return result will always be a JSON response, so instead of returning raw data we return our parsed data. So our server class looks like this:

@interface Server : NSObject

+ (Server *)shared;

- (void)requestWithEndpoint:(NSString *)endpoint
				 parameters:(NSDictionary *)params
		  completionHandler:(void (^)(NSDictionary *data, NSURLResponse *response, NSError *error))callback;

@end

Our server should now handle all the common work we scattered throughout our code:

#define SERVERPREFIX	@"http://api.server.co/api/1/"

- (void)requestWithEndpoint:(NSString *)endpoint parameters:(NSDictionary *)params completionHandler:(void (^)(NSDictionary *data, NSURLResponse *response, NSError *error))callback
{
	void (^copyCallback)(NSDictionary *data, NSURLResponse *response, NSError *error) = [callback copy];

	// Start the wait spinner
	[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

	// Assemble the request
	NSString *reqString = [NSString stringWithFormat:@"%@%@",SERVERPREFIX,endpoint];
	NSURL *url = [NSURL URLWithString:reqString];

	NSMutableURLRequest *req;
	req = [[NSMutableURLRequest alloc] initWithURL:url];
	[req setHTTPMethod:@"POST"];

	if (params) {
		NSData *jsonReq = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
		[req setHTTPBody:jsonReq];
		[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
	}

	// Now send the request and wait for the response
	[[Server shared].session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
		// Process the response. Note not handling errors for now.
		NSDictionary *respData = nil;
		if (data) {
			respData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
		}

		// Dispatch back in main thread. (Our callback was in a separate
		// thread.)
		dispatch_async(dispatch_get_main_queue(), ^{
			[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
			copyCallback(respData,response,error);
		});
	}];
}

Note that our single entrypoint is handling most of the common work that would otherwise be scattered throughout our code.

And our doOperationWithCallback method?

- (void)doOperationWithCallback:(void (^)(NSInteger res))callback;
{
	void (^copyCallback)(NSInteger val) = [callback copy];

	int value1 = (do something here);
	int value2 = (do something here);

	NSDictionary *d = @{ @"arg1": @( value1 ),
						 @"arg2": @( value2 ) };

	[[Server shared] requestWithEndpoint:@"endpointname" parameters:d completionHandler:^(NSDictionary *data, NSURLResponse *response, NSError *error) {
		NSInteger retVal = [data[@"result"] integerValue];
		copyCallback(retVal);
	}];
}

We’ve made our code concise.

What we’re doing has become extremely apparent, because all the duplicate bookkeeping work is now handled elsewhere in a common location.

We don’t have to worry about wait spinners or about constructing the request object–all we have to worry about is which endpoint are we calling, and what parameters are we passing, and what results we’re expecting.


An idiom should make your code concise.

Because by making your code concise you implicitly do a few things. First, you move repetitive code to another common location, where bugs (such as our wait spinner bug) can be easily fixed in one place. Second, you reveal the purpose of your function call by eliminating all the repetitive bookkeeping that distracts from the purpose of the code. And third, you reduce the probability of error.

For example, can you spot what is wrong with the following code?

- (void)doOperationWithCallback:(void (^)(NSInteger res))callback;
{
	void (^copyCallback)(NSInteger val) = [callback copy];

	int value1 = (do something here);
	int value2 = (do something here);

	// Start the wait spinner
	[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

	// Assemble the request
	NSString *endpoint = @"endpointname";
	NSString *reqString = [NSString stringWithFormat:@"%@%@",SERVERPREFIX,endpoint];
	NSURL *url = [NSURL URLWithString:reqString];

	NSMutableURLRequest *req;
	req = [[NSMutableURLRequest alloc] initWithURL:url];
	[req setHTTPMethod:@"POST"];

	NSDictionary *d = @{ @"arg1": @( value1 ) };
	NSData *jsonReq = [NSJSONSerialization dataWithJSONObject:d options:NSJSONWritingPrettyPrinted error:nil];
	[req setHTTPBody:jsonReq];
	[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

	// Now send the request and wait for the response
	[[Server shared].session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
		// Process the response. Note not handling errors for now.
		NSDictionary *respData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
		NSInteger retVal = [respData[@"result"] integerValue];

		// Dispatch back in main thread. (Our callback was in a separate
		// thread.)
		dispatch_async(dispatch_get_main_queue(), ^{
			[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
			copyCallback(retVal);
		});
	}];
}

Did you spot the error?

Think about the requirements we stated above, where our endpoint requires two arguments.

How about now? Can you spot the error now?

- (void)doOperationWithCallback:(void (^)(NSInteger res))callback;
{
	void (^copyCallback)(NSInteger val) = [callback copy];

	int value1 = (do something here);
	int value2 = (do something here);

	NSDictionary *d = @{ @"arg1": @( value1 ) };

	[[Server shared] requestWithEndpoint:@"endpointname" parameters:d completionHandler:^(NSDictionary *data, NSURLResponse *response, NSError *error) {
		NSInteger retVal = [data[@"result"] integerValue];
		copyCallback(retVal);
	}];
}

Yep, we forgot a parameter to our endpoint.

And it is easier to spot the error in 15 lines of code which reduce the process to its essentials, than in 38 lines of code full of extraneous bookkeeping code.