Developer Blog

How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained

If you are an iOS developer using Mattt Thompson’s ‘delightful networking framework’ AFNetworking (and if you aren’t, what are you waiting for?), perhaps you have been been curious or confused about the caching mechanism employed and how you can tweak it to your advantage.

AFNetworking actually takes advantage of 2 separate caching mechanisms:

  • AFImagecache: a memory-only image cache private to AFNetworking, subclassed off of NSCache

  • NSURLCache: NSURLConnection's default URL caching mechanism, used to store NSURLResponse objects : an in-memory cache by default, configurable as an on-disk persistent cache

In order to understand how each caching system works, let’s look at how they are defined:

How AFImageCache Works

AFImageCache is a part of the UIImageView+AFNetworking category. It is a subclass of NSCache, storing UIImage objects with a URL string as its key (obtained from an input NSURLRequest object).

AFImageCache definition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@interface AFImageCache : NSCache <AFImageCache>

// singleton instantiation :

+ (id <AFImageCache>)sharedImageCache {
    static AFImageCache *_af_defaultImageCache = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _af_defaultImageCache = [[AFImageCache alloc] init];

// clears out cache on memory warning :

    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * __unused notification) {
        [_af_defaultImageCache removeAllObjects];
    }];
});

// key from [[NSURLRequest URL] absoluteString] :

static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) {
    return [[request URL] absoluteString];
}

@implementation AFImageCache

// write to cache if proper policy on NSURLRequest :

- (UIImage *)cachedImageForRequest:(NSURLRequest *)request {
    switch ([request cachePolicy]) {
        case NSURLRequestReloadIgnoringCacheData:
        case NSURLRequestReloadIgnoringLocalAndRemoteCacheData:
            return nil;
        default:
            break;
    }

    return [self objectForKey:AFImageCacheKeyFromURLRequest(request)];
}

// read from cache :

- (void)cacheImage:(UIImage *)image
        forRequest:(NSURLRequest *)request {
    if (image && request) {
        [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)];
    }
}

AFImageCache is a private implementation of NSCache. There is no customization that you can do outside of editing the implementation in the the UIImageView+AFNetworking category, directly. It stores all accessed UIImage objects into its NSCache. The NSCache controls when the UIImage objects are released. If you wish to observe when images are released, you can implement NSCacheDelegate’s cache:willEvictObject method.

Edit (03.14.14) : Mattt Thompson has gratiously informed me that as of AFNetworking 2.1, AFImageCache is configurable. There is now a public setSharedImageCache method. Here’s the full AFN 2.2.1 UIImageView+AFNetworking specification.

How NSURLCache Works

Since AFNetworking uses NSURLConnection, it takes advantage of its native caching mechanism, NSURLCache. NSURLCache caches NSURLResponse objects returned by server calls via NSURLConnection.

Enabled by Default, but Needs a Hand

An NSURLCache sharedCache is enabled by default and will be used by any NSURLConnection objects fetching URL contents for you.

Unfortunately, it has a tendency to hog memory and does not write to disk in its default configuration. To tame the beast and potentially add some persistance, you can simply declare a shared NSURLCache in your app delegate like so:

1
2
3
4
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024
                                              diskCapacity:100 * 1024 * 1024
                                              diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];

Here we declare a shared NSURLCache with 2mb of memory and 100mb of disk space

Setting the Cache Policy on NSURLRequest Objects

NSURLCache will respect the caching policy (NSURLRequestCachePolicy) of each NSURLRequest object. The policies are defined as follows :

  • NSURLRequestUseProtocolCachePolicy: specifies that the caching logic defined in the protocol implementation, if any, is used for a particular URL load request. This is the default policy for URL load requests

  • NSURLRequestReloadIgnoringLocalCacheData: ignore the local cache, reload from source

  • NSURLRequestReloadIgnoringLocalAndRemoteCacheData: ignore local & remote caches, reload from source

  • NSURLRequestReturnCacheDataElseLoad: load from cache, else go to source.

  • NSURLRequestReturnCacheDataDontLoad: offline mode, load cache data regardless of expiration, do not go to source

  • NSURLRequestReloadRevalidatingCacheData: existing cache data may be used provided the origin source confirms its validity, otherwise the URL is loaded from the origin source.

Caching to Disk with NSURLCache

Cache-Control HTTP Header

Either the Cache-Control header or the Expires header MUST be in the HTTP response header from the server in order for the client to cache it (with the existence of the Cache-Control header taking precedence over the Expires header). This is a huge gotcha to watch out for. Cache Control can have parameters defined such as max-age (how long to cache before updating response), public / private access, or no-cache (don’t cache response). Here is a good introduction to HTTP cache headers.

Subclass NSURLCache for Ultimate Control

If you would like to bypass the requirement for a Cache-Control HTTP header and want to define your own rules for writing and reading the NSURLCache given an NSURLResponse object, you can subclass NSURLCache.

Here is an example that uses a CACHE_EXPIRES value to judge how long to hold on to the cached response before going back to the source:

(Thanks to Mattt Thompson for the feedback and code edits!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@interface CustomURLCache : NSURLCache

static NSString * const CustomURLCacheExpirationKey = @"CustomURLCacheExpiration";
static NSTimeInterval const CustomURLCacheExpirationInterval = 600;

@implementation CustomURLCache

+ (instancetype)standardURLCache {
    static CustomURLCache *_standardURLCache = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _standardURLCache = [[CustomURLCache alloc]
                                 initWithMemoryCapacity:(2 * 1024 * 1024)
                                 diskCapacity:(100 * 1024 * 1024)
                                 diskPath:nil];
    }

    return _standardURLCache;
}

#pragma mark - NSURLCache

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
    NSCachedURLResponse *cachedResponse = [super cachedResponseForRequest:request];

    if (cachedResponse) {
        NSDate* cacheDate = cachedResponse.userInfo[CustomURLCacheExpirationKey];
        NSDate* cacheExpirationDate = [cacheDate dateByAddingTimeInterval:CustomURLCacheExpirationInterval];
        if ([cacheExpirationDate compare:[NSDate date]] == NSOrderedAscending) {
            [self removeCachedResponseForRequest:request];
            return nil;
        }
    }
}

    return cachedResponse;
}

- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse
                 forRequest:(NSURLRequest *)request
{
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:cachedResponse.userInfo];
    userInfo[CustomURLCacheExpirationKey] = [NSDate date];

    NSCachedURLResponse *modifiedCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];

    [super storeCachedResponse:modifiedCachedResponse forRequest:request];
}

@end

Now that you have your NSURLCache subclass, don’t forget to initialize it in your AppDelegate in order to use it :

1
2
3
4
CustomURLCache *URLCache = [[CustomURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024
                                                   diskCapacity:100 * 1024 * 1024
                                                                 diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];

Overriding the NSURLResponse before caching

The -connection:willCacheResponse delegate is a place to intercept and edit the NSURLCachedResponse object created by NSURLConnection before it is cached. In order to edit the NSURLCachedResponse, return an edited mutable copy as follows (code from NSHipster blog):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse {
    NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy];
    NSMutableData *mutableData = [[cachedResponse data] mutableCopy];
    NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly;

    // ...

    return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
                                                    data:mutableData
                                                userInfo:mutableUserInfo
                                           storagePolicy:storagePolicy];
}

// If you do not wish to cache the NSURLCachedResponse, just return nil from the delegate function:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse {
    return nil;
}

Disabling NSURLCache

Don’t want to use the NSURLCache? Not Impressed? That’s okay. To disable the NSURLCache, simply zero out memory and disk space in the shared NSURLCache definition in your appDelegate:

1
2
3
4
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0
                                              diskCapacity:0
                                              diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];

Summary

I wanted to write this blog post for the benefit of the iOS community, to summarize all of the information I found dealing with caching releated to AFNetworking. We had an internal app loading a lot of images that had some memory issues and performance problems. I was tasked with trying to diagnose the caching behavior of the app. During this exercise, I discovered the information on this post through scouring the web and doing plenty of debugging and logging. It is my hope that this post summarizes my findings and provides an opportunity for others with AFNetworking experience to add additional information. I hope that you have found this helpful.

One Simple Trick to Level Up Your Code

As software developers we can’t stop bad code but we can make it better. There are a number of ways we try to make better code. We try to follow best practices like TDD. We’ve all read a number of books on design patterns, code standards, rules, and guidelines. It is a fact though, that the real world gets in the way. Deadlines are tight. Projects get rushed. Code is written quickly and sloppily. None of these things are going away but there is one simple thing we can do no matter how tight the deadline.

When you write a piece of code, take a brief pause and look at what you just wrote. Ask yourself:

Can I make this code better?

Chances are you’ll see at least one thing that could be changed. A large method that could be broken up. A convoluted logic expression. Or any number of small things. If you take just a moment to change that one thing before moving on, all of your code will be cleaner, easier to maintain, and in general much higher quality.

Scrap Your Cake Pattern Boilerplate: Dependency Injection Using the Reader Monad

There are a number of ways to do dependency injection in Scala without adding a framework. The cake pattern is probably the most popular approach and is used in the Scala compiler itself. Using implicit parameters is less popular and is used in the Scala concurrency libraries.

An approach that doesn’t get as much mention in the blogosphere but gets much love from those who have tried it is dependency injection via the Reader Monad.

To illustrate the differences between the Reader Monad approach and the more popular approaches, let’s look at examples of using each to solve the same dependency problem. These examples will all be injecting a dependency for getting User objects from a repository:

1
2
3
4
trait UserRepository {
  def get(id: Int): User
  def find(username: String): User
}

The Cake Pattern

In the cake pattern we represent the dependency as a component trait. We put the thing that is depended on into the trait along with an abstract method to return an instance.

1
2
3
4
5
6
7
8
9
trait UserRepositoryComponent {

  def userRepository: UserRepository

  trait UserRepository {
    def get(id: Int): User
    def find(username: String): User
  }
}

Then we declare the dependency in abstract classes using self-type declarations.

1
2
3
4
5
6
7
8
9
10
11
trait Users {
  this: UserRepositoryComponent =>

  def getUser(id: Int): User = {
    userRepository.get(id)
  }

  def findUser(username: String): User = {
    userRepository.find(username)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
trait UserInfo extends Users {
  this: UserRepositoryComponent =>

  def userEmail(id: Int): String = {
    getUser(id).email
  }

  def userInfo(username: String): Map[String, String] = {
    val user = findUser(username)
    val boss = getUser(user.supervisorId)
    Map(
      "fullName" -> s"${user.firstName} ${user.lastName}",
      "email" -> s"${user.email}",
      "boss" -> s"${boss.firstName} ${boss.lastName}"
    )
  }
}

We extend the component trait to provide concrete implementations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
trait UserRepositoryComponentImpl extends UserRepositoryComponent {

  def userRepository = new UserRepositoryImpl

  class UserRepositoryImpl extends UserRepository {

    def get(id: Int) = {
      ...
    }

    def find(username: String) = {
      ...
    }
  }
}

Finally we can create an instance of our class with the dependency by mixing in a concrete implementation.

1
2
3
object UserInfoImpl extends
  UserInfo with
  UserRepositoryComponentImpl

For testing we can create a test instance of our class and mix in a mock implementation.

1
2
3
4
5
6
object TestUserInfo extends
  UserInfo with
  UserRepositoryComponent {

  lazy val userRepository = mock[UserRepository]
}

Implicits

The cake pattern works really well but tends to require a lot of boilerplate. Another approach is to add implicit parameters to the methods that require the dependency.

1
2
3
4
5
6
7
8
9
10
trait Users {

  def getUser(id)(implicit userRepository: UserRepository) = {
    userRepository.get(id)
  }

  def findUser(username)(implicit userRepository: UserRepository) = {
    userRepository.find(username)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object UserInfo extends Users {

  def userEmail(id: Int)(implicit userRepository: UserRepository) = {
    getUser(id).email
  }

  def userInfo(username: String)(implicit userRepository: UserRepository) = {
    val user = findUser(username)
    val boss = getUser(user.supervisorId)
    Map(
      "fullName" -> s"${user.firstName} ${user.lastName}",
      "email" -> s"${user.email}",
      "boss" -> s"${boss.firstName} ${boss.lastName}"
    )
  }
}

This is a lot less code and has the advantage of allowing us to substitute a different UserRepository at any point either by defining our own implicit value or by passing it as an explicit argument.

A downside of this approach is that it clutters up the method signatures. Every method that depends on a UserRepository (userEmail and userInfo in this example) has to declare that implicit parameter.

The Reader Monad

In Scala, a unary function (a function with one parameter) is an object of type Function1. For example, we can define a function triple that takes an Int and triples it:

1
2
3
val triple = (i: Int) => i * 3

triple(3)   // => 9

The type of triple is Int => Int, which is just a fancy way of saying Function1[Int, Int].

Function1 lets us create new functions from existing ones using andThen:

1
2
3
val thricePlus2 = triple andThen (i => i + 2)

thricePlus2(3)  // => 11

The andThen method combines two unary functions into a third function that applies the first function, then applies the second function to the result. The parameter type of the second function has to match the result type of the first function, but the result type of the second function can be anything:

1
2
3
val f = thricePlus2 andThen (i => i.toString)

f(3)  // => "11"

The type of f here is Int => String. Using andThen we can change the result type as much as we want but the parameter type is always the same as in the initial function.

The Reader Monad is a monad defined for unary functions, using andThen as the map operation. A Reader, then, is just a Function1. We can wrap the function in a scalaz.Reader to get the map and flatMap methods:

1
2
3
4
5
6
7
8
9
import scalaz.Reader

val triple = Reader((i: Int) => i * 3)

triple(3)   // => 9

val thricePlus2 = triple map (i => i + 2)

thricePlus2(3)  // => 11

The map and flatMap methods let us use for comprehensions to define new Readers:

1
2
3
val f = for (i <- thricePlus2) yield i.toString

f(3)  // => "11"

If the above example looks strange, remember that it’s just a fancy way of writing:

1
2
3
val f = thricePlus2 map (i => i.toString)

f(3)  // => "11"

Dependency Injection with the Reader Monad

To use the Reader Monad for dependency injection we just need to define functions with a UserRepository parameter. We can wrap each of these functions in a scalaz.Reader to get the full monady goodness.

We define a “primitive” Reader for each operation defined in the UserRepository trait:

1
2
3
4
5
6
7
8
9
10
11
trait Users {
  import scalaz.Reader

  def getUser(id: Int) = Reader((userRepository: UserRepository) =>
    userRepository.get(id)
  )

  def findUser(username: String) = Reader((userRepository: UserRepository) =>
    userRepository.find(username)
  )
}

Note that these primitives return Reader[UserRepository, User] and not User. It’s a decorated UserRepository => User that you can use with for comprehensions. It’s a function that will eventually return a User when given a UserRepository. The actual injection of the dependency is deferred.

We can now define all the other operations (as Readers) in terms of the primitive Readers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object UserInfo extends Users {

  def userEmail(id: Int) = {
    getUser(id) map (_.email)
  }

  def userInfo(username: String) =
    for {
      user <- findUser(username)
      boss <- getUser(user.supervisorId)
    } yield Map(
      "fullName" -> s"${user.firstName} ${user.lastName}",
      "email" -> s"${user.email}",
      "boss" -> s"${boss.firstName} ${boss.lastName}"
    )
}

Because these methods use map and flatMap on the primitives (for comprehensions use map and flatMap), the methods return new higher-level Readers. The userEmail method in this example returns Reader[UserRepository, String]. All of the higher-level methods dealing with users return higher-level Readers built directly or indirectly from the primitives.

Unlike in the implicits example, we don’t have UserRepository anywhere in the signatures of userEmail and userInfo. We don’t have to mention UserRepository anywhere other than our primitives. If we gain additional dependencies we can encapsulate them all in a single Config object and we only have to change the primitives.

For example, say we needed to add a mail service:

1
2
3
4
trait Config {
  def userRepository: UserRepository
  def mailService: MailService
}

We would only have to change our primitives to take Config instead of UserRepository:

1
2
3
4
5
6
7
8
9
10
11
trait Users {
  import scalaz.Reader

  def getUser(id: Int) = Reader((config: Config) =>
    config.userRepository.get(id)
  )

  def findUser(username: String) = Reader((config: Config) =>
    config.userRepository.find(username)
  )
}

Our UserInfo object doesn’t need to change. This may seem like a small win in this example but it’s a huge win in a large application that has many times more higher-level Readers than primitives.

Injecting the dependency

So where does the actual UserRepository get injected? All of these methods return Readers that can get User-related stuff out of a UserRepository. The actual dependency injection keeps getting deferred up to higher layers.

At some point we need to apply one of these Readers to a concrete UserRepository to actually get the stuff. Normally this would be at the outer edges of our application. In the case of a web application, this would be the controller actions.

Assuming we have a concrete implementation of UserRepository as an object called UserRepositoryImpl, we might define a controller like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object Application extends Application(UserRepositoryImpl)

class Application(userRepository: UserRepository) extends Controller with Users {

  def userEmail(id: Int) = Action {
    Ok(run(UserInfo.userEmail(id)))
  }

  def userInfo(username: String) = Action {
    Ok(run(UserInfo.userInfo(username)))
  }

  private def run[A](reader: Reader[UserRepository, A]): JsValue = {
    Json.toJson(reader(userRepository))
  }
}

The object Application uses the default concrete implementation, and we can instantiate a test version using the class Application with a mock repository for testing. In this example we’ve also defined a convenience method run that injects the UserRepository into a Reader and converts the result to JSON.

But I can’t choose!

There’s no rule that says we have to use just one dependency injection strategy. Why not use the Reader Monad throughout our application’s core, and the cake pattern at the outer edge?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
object Application extends Application with UserRepositoryComponentImpl

trait Application extends Controller with Users {
  this: UserRepositoryComponent =>

  def userEmail(id: Int) = Action {
    Ok(run(UserInfo.userEmail(id)))
  }

  def userInfo(username: String) = Action {
    Ok(run(UserInfo.userInfo(username)))
  }

  private def run[A](reader: Reader[UserRepository, A]): JsValue = {
    Json.toJson(reader(userRepository))
  }
}

This way we get the benefit of the cake pattern but we only have to apply it to our controllers. The Reader Monad lets us push the injection out to the edges of our application where it belongs.

Answers to Common Questions in Cocoa Development

I recently created my first Cocoa app, and it was a real pain. I wanted to add a bunch of common features I see in every app, and hunting down the right answers on stack overflow proved to be very difficult. The following is a list of answers to common problems I ran into.

Note that Apple’s new rules about app sandboxing makes some of these features unavailable, and I think that’s garbage. Also note that these are quick and dirty solutions, and in now way represent best practices. All of this was done in Xcode 5 with a target of 10.7.

Adding an Icon to the System Tray

Winning solution: Creating a Standalone StatusItem Menu

I’m not going to replicate the whole article, so you’ll have to go there to see how to rig up things in Interface Builder, but here are the relevant bits of code to insert:

1
2
3
4
5
6
7
// MyAppDelegate.h
@interface MyAppDelegate : NSObject <NSApplicationDelegate> {
    IBOutlet NSMenu *statusMenu;
    NSStatusItem *statusItem;
    NSImage *statusImage;
    NSImage *statusHighlightedImage;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// MyAppDelegate.m
- (void) applicationDidFinishLaunching: (NSNotification *) aNotification {
  // Create the NSStatusBar and set its length
  statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength];

  // Allocates and loads the images into the application which will be used for our NSStatusItem
  NSBundle *appBundle = [NSBundle mainBundle];
  statusImage = [appBundle imageForResource:@"icon.grey"];
  statusHighlightedImage = [appBundle imageForResource:@"icon.highlighted"];

  // Sets the images in our NSStatusItem
  [statusItem setImage:statusImage];
  [statusItem setAlternateImage:statusHighlightedImage];

  // Tells the NSStatusItem what menu to load
  [statusItem setMenu:statusMenu];
  // Sets the tooptip for our item
  [statusItem setToolTip:@"My Custom Menu Item"];
  // Enables highlighting
  [statusItem setHighlightMode:YES];
}

Note that getting the sizing of the images right was obnoxious, and I couldn’t find any solid information about it in Apple branded documentation. I can at least point out that the retina image assets seem to work the way you would expect, so adding a icon.png and an icon@2x.png does the right thing. I had to mess with the sizes a bunch though, and found that a non-retina icon that is 21x21 pixels works. Continuing to mess with things… it seems like the retina version of the icon had to be 41x41 pixels (not exactly double… “it just works!”).

For more info, this is the best resource I found NSStatusItem – What Size Should Your Icon Be?.

Registering a Global Hotkey to Bring Your App Into Focus

From what I read, it seems like the way you do this in Cocoa is to use the Carbon api. Regardless, after enough digging, I finally found this: DDHotKey. It makes things incredibly easy:

1
2
3
4
5
6
7
8
9
10
11
12
13
// MyAppDelegate.m
#import "DDHotKeyCenter.h"

- (void) applicationDidFinishLaunching: (NSNotification *) aNotification {
  // register hotkey
  DDHotKeyCenter *c = [[DDHotKeyCenter alloc] init];
  if ([c registerHotKeyWithKeyCode:34 modifierFlags:(NSCommandKeyMask | NSShiftKeyMask) target:self action:@selector(hotkeyAction:withObject:) object:nil]) {
      NSLog(@"registered");
  }
  else {
      NSLog(@"not registered");
  }
}

This example will register command + shift + i as your hotkey. To ensure that your app pops up to the front, you can do:

1
2
3
4
5
- (void) hotkeyAction: (NSEvent *)hotKeyEvent withObject:(id)anObject {
  NSApplication *myApp = [NSApplication sharedApplication];
  [myApp activateIgnoringOtherApps:YES];
  [self.window orderFrontRegardless];
 }

Make App Hide When Losing Focus

1
2
3
4
// MyAppDelegate.m
- (void) applicationDidResignActive: (NSNotification *) notification {
    [[NSApplication sharedApplication] hide:self];
}

Prevent App From Showing In Dock/Alt+Tab

This one requires you to edit your MyApp-Info.plist file (usually under “Supporting Files” in the project). Add a new key for “Application is agent (UIElement)” and set it to YES.

Start App at Login

Winning solution: Stack Overflow – How do you make your app open at login (with a few changes for Xcode 5)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// MyAppDelegate.m
+ (BOOL) willStartAtLogin: (NSURL *) itemURL {
  Boolean foundIt=false;
  LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
  if (loginItems) {
    UInt32 seed = 0U;
    NSArray *currentLoginItems = (__bridge NSArray *)(LSSharedFileListCopySnapshot(loginItems, &seed));
    for (id itemObject in currentLoginItems) {
      LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;

      UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
      CFURLRef URL = NULL;
            OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL);
      if (err == noErr) {
        foundIt = CFEqual(URL, (__bridge CFTypeRef)(itemURL));
        CFRelease(URL);

        if (foundIt)
          break;
      }
    }
    CFRelease(loginItems);
  }
  return (BOOL)foundIt;
}

+ (void) setStartAtLogin: (NSURL *) itemURL enabled: (BOOL) enabled {
  OSStatus status;
  LSSharedFileListItemRef existingItem = NULL;

  LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
  if (loginItems) {
    UInt32 seed = 0U;
    NSArray *currentLoginItems = (__bridge NSArray *)(LSSharedFileListCopySnapshot(loginItems, &seed));
    for (id itemObject in currentLoginItems) {
      LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;

      UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
      CFURLRef URL = NULL;
            OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL);
      if (err == noErr) {
        Boolean foundIt = CFEqual(URL, (__bridge CFTypeRef)(itemURL));
        CFRelease(URL);

        if (foundIt) {
          existingItem = item;
          break;
        }
      }
    }

    if (enabled && (existingItem == NULL)) {
      LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst,
        NULL, NULL, (__bridge CFURLRef)itemURL, NULL, NULL);

    } else if (!enabled && (existingItem != NULL))
    LSSharedFileListItemRemove(loginItems, existingItem);

    CFRelease(loginItems);
  }
}

If you’d like a checkbox that is bound to your app’s “start at login” state, you can create a property:

1
2
// MyAppDelegate.h
@property BOOL startAtLogin;

then use Interface Builder to bind a checkbox to this property, and implement the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// MyAppDelegate.m
- (NSURL *) appURL {
  return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
}

- (BOOL) startAtLogin {
  return [ISPAppDelegate willStartAtLogin:[self appURL]];
}

- (void) setStartAtLogin: (BOOL) enabled {
  [self willChangeValueForKey:@"startAtLogin"];
  [ISPAppDelegate setStartAtLogin:[self appURL] enabled:enabled];
  [self didChangeValueForKey:@"startAtLogin"];
}

Conclusion

Now you have the basics of an app that can do whatever you’d like without having to figure out the boilerplate. If there’s some interest, I’d be willing to roll all of this up into a public github repo that people can check out and use as a starting place for utility apps. For those who are curious, the reason I had to figure all of this out was to build Insert Pic.

Using Play Framework’s in Memory Database to Improve Test Speed

I’ve been working with Play Framework 2.x in scala for the last few months and overall I’m pretty happy. One big issue I ran into recently was that if you want to use a real database, it becomes hard to convince Play Framework to run your tests against H2 (for the order of magnitude speed increase).

The Secret Sauce

The trick that finally made it work was found by digging through the Play source. You can tell your app to use a specific data source while running in test mode. The easiest way to set this up is to give yourself a trait that you will extend classes and objects with:

1
2
3
4
5
6
7
8
9
trait DatabaseClient {
  private def dbName = if (Mode.Test == current.mode) "test" else "default"

  def db = Database.forDataSource(DB.getDataSource(dbName))

  def withSession[A](f: => A): A = db.withSession(f)

  def withTransaction[A](f: => A): A = db.withTransaction(f)
}

This allows you to run a different DB config while in test mode.

Getting The Test Environment To Work

While the Play documentation tells you that you can just add multiple datasources to your application.conf file, what they fail to mention is that your app will try to use all specified DBs in all environments. Instead of placing the config for your test database in your config file, I inject it directly into the FakeApplication that I instantiate for my tests:

1
2
3
4
5
6
7
trait TestHelpers { self: Specification =>

  def fakeApplication = FakeApplication(additionalConfiguration = inMemoryDatabase("test") + (
    "applyEvolutions.test" -> "true"
  ))

}

It’s useful to have this in its own trait because you will likely want to use fakeApplication in a few instances (we have to reference it in our model tests as well as our controller tests). Now that you have a configuration for your “test” database, and due to the change above, when your tests run, they will use H2.

Note that if you are using Typesafe Slick, you’ll want to inject a "slick.test" -> "models.*" in there.

Providing your FakeApplication for your tests

In order to get my tests to run in the context of an H2 database, I use a trait that can wrap my specs for me:

1
2
3
4
5
6
7
8
9
trait TestSupport { self: Specification =>

  trait WithApplication extends Around {
    def around[T : AsResult](t: => T) = running(fakeApplication) {
      AsResult(t)
    }
  }

}

then in my spec:

1
2
3
4
5
6
7
8
9
10
11
class ModelSpec extends Specification with TestSupport {

  "Model" should {

    "be creatable" in new WithApplication {
      Model.create() must beSome[Model]
    }

  }

}

The nice thing about this setup is that it’s flexible to meet the demands of most apps. Adding changes to the config is always a black box, it’s hard to reason about how the framework will react to those changes. Moving this to actual code makes it more obvious what is actually happening, and lets you go even further, if, for example, you wanted to have your model tests run against MySql, but controller tests use H2 (not sure why you would want this…).

Caveat

As far as I can tell, Play will try to maintain a connection to your database regardless of whether or not you deliberately try to connect to it (if it’s in the config, it tries to connect). This means the tests ran fine on my machine, but were failing on our CI (circleci.com). The fix is to make sure that your connection to the database is still valid, so all I had to do was update the user/pass/dbname in my CI config and I was all set. It feels a bit sloppy that Play connects to a database you aren’t even using, so if anyone has any suggestions on how to prevent this behavior, let me know and I’ll update this post.

Modifying the iOS Settings.bundle Using Build Phases

Most iOS apps today communicate with a server to send and receive data. During development you may have several servers (QA, Staging, Prod) and oftentimes find that you need to distribute copies of your app pointing to each server.

A common approach here is to create a temporary “debug” page where you can configure which server you want your app to use.

This is a good solution but a more elegant one exists. The idea is to create a settings page in the iOS settings app, where you can select between servers or enter your own custom URL. This solution keeps debug code down to a minimum and is less disruptive not requiring an entire debug page created in the app.

Settings.bundle

In order to add an app setting page to the iOS settings app, you must create a Settings.bundle file.

Below is a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<dict>
  <key>PreferenceSpecifiers</key>
  <array>
      <dict>
          <key>Title</key>
          <string>Restart app after making changes</string>
          <key>Type</key>
          <string>PSGroupSpecifier</string>
      </dict>
      <dict>
          <key>DefaultValue</key>
          <false/>
          <key>Key</key>
          <string>use_dev</string>
          <key>Title</key>
          <string>ON-Dev OFF-Staging</string>
          <key>Type</key>
          <string>PSToggleSwitchSpecifier</string>
      </dict>
      <dict>
          <key>AutocapitalizationType</key>
          <string>None</string>
          <key>AutocorrectionType</key>
          <string>No</string>
          <key>DefaultValue</key>
          <string></string>
          <key>IsSecure</key>
          <false/>
          <key>Key</key>
          <string>custom_URL</string>
          <key>KeyboardType</key>
          <string>Alphabet</string>
          <key>Title</key>
          <string>Other (i.e. ab.com)</string>
          <key>Type</key>
          <string>PSTextFieldSpecifier</string>
      </dict>
  </array>
  <key>StringsTable</key>
  <string>Root</string>
</dict>
</plist>

And the resulting settings page:

Alt text

Build Phase Run Script

The problem with the above solution is that you must remember to remove the Settings.bundle file when archiving your app for the store.

Taking our solution to the next level, during an App Store build, the build phases run script can be used to zap this settings page and replace it with something useful. For the purpose of this blog, we will replace the page with the version number of the app.

Below is an example build phase run script that deletes the current settings when building for the App Store and creates new elements for displaying the app version number:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if [ "$CONFIGURATION" == "AppStore" ] ; then

APPVERSION="`/usr/libexec/PlistBuddy -c \"Print :CFBundleVersion\" \"$CODESIGNING_FOLDER_PATH/Info.plist\"`"
SETTINGSBUNDLEPATH="$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist"

/usr/libexec/PlistBuddy -c "Delete :PreferenceSpecifiers" "$SETTINGSBUNDLEPATH"

/usr/libexec/PlistBuddy -c "Add :StringsTable string 'Root'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers array" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:0 dict" "$SETTINGSBUNDLEPATH"

/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:0:Type string 'PSGroupSpecifier'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:0:Title string 'Version Information'" "$SETTINGSBUNDLEPATH"

/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:Type string 'PSTitleValueSpecifier'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:Title string 'Release:'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:Key string 'appVersion'" "$SETTINGSBUNDLEPATH"
/usr/libexec/PlistBuddy -c "Add :PreferenceSpecifiers:1:DefaultValue string '$APPVERSION'" "$SETTINGSBUNDLEPATH"

fi

And the resulting settings page:

Alt text

Note that as an added benefit, using the Settings.bundle (even if it is just displaying your app version) is a good way to widen the footprint and exposure of your app since it will be listed in the main settings page.

Apple Sprite Kit Demo

With Xcode 5 Apple is releasing Sprite Kit, a great new tool for making 2D games that abstracts away a lot of boilerplate.

I threw together a quick demo using the Apple Adventure game as a reference. The code referenced in this blog post can be found here: https://github.com/asail77/OLTTSpriteDemo

As you scan through the code, you will notice that most of it is located in OLMyScene.h. With 541 lines of code, you are able to get a big bang for your buck! This is because Sprite Kit does most of the work for you. All you have to concentrate on is the logic of your game and the graphics.

Atlas Folders

One of the interesting features of Sprite Kit is the .atlas folder. Place a group of photos (i.e. a series of graphics for an action like “Goblin_Walk”) in the folder and Xcode will automatically create an atlas file when the application is packaged. You can see this by going to the package contents and opening one of the atlas folders. You will notice that all of the images are combined into a single image with some corresponding xml used to reference the original images.

The images are packed together and arranged in a way that results in less disk usage. Additionally, with less files to load from disk, you have better performance.

Note that -(void)loadWorldData is used initially to load all atlas and particle files before the demo begins. When these files are needed later, they are copied from memory rather than reloaded from disk:

1
SKEmitterNode *archerProjectile = [_archerProjectile copy];

This helps to ensure you are maintaing a good frame rate.

Partical Files

Another cool feature of Sprite Kit is the ability to create particle files and completely customize them. In Xcode, open up the Particle Files folder under Resources and view the .sks files to see this in action.

Note that for the ArcherProjectile particle file, I found that the particle would not travel nicely through the world (i.e. create a long trail) when “fired” by the Hero. This was solved by setting the target node to the world:

1
2
3
-(void)fireAtAntagonist {
  ...
  archerProjectile.targetNode = _world;

Action Chaining

One of my favorite features of Sprite Kit is the ability to chain actions together and attach them to an SKSpriteNode.

For example, when launching the spaceship, I want a few events to happen:

  1. I want the spaceship to follow a path that I calculate based on the position of all Antagonists in view, but I want this path to start on the left side of the screen and end on the right with a total time of 4 seconds.

  2. At the same time, when the spaceship is half way through its path (2 seconds in), I want all antagonists to be “killed” making it appear as if the spaceship has blown them up.

  3. After 4 seconds, when the spaceship has exited the screen, I want it to be removed from the world and released.

All of this can be achieved with the following:

1
2
3
4
5
6
  // Launch spaceship
  [_spaceship runAction:[SKAction group:@[[SKAction followPath:path asOffset:false orientToPath:YES duration:4],
                                          [SKAction sequence:@[[SKAction waitForDuration: 2],
                                                               [SKAction runBlock:^{[self killAllAntagonists];}],
                                                               [SKAction waitForDuration: 2],
                                                               [SKAction removeFromParent]]]]]];

Physics

Most of the code is self explanatory, with the update loop being used continuously to update the Hero and Antagonists. The physics callback of the render loop is not used here, but it is worth noting that I am using physics to prevent the characters from overlapping and to detect collisions:

1
2
3
4
5
6
7
8
9
- (void)createMoreAntagonists {
  ...
  // Set collision physics
  antagonist.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:50];
  antagonist.physicsBody.categoryBitMask = ColliderTypeAntagonist;
  antagonist.physicsBody.collisionBitMask = ColliderTypeProjectile | ColliderTypeAntagonist | ColliderTypeHero;
  antagonist.physicsBody.contactTestBitMask = ColliderTypeProjectile;
  ...
}

Defining the physical boundary of an object, setting the types of objects it can collide with, and deciding when to trigger collision events are all one liners. You can respond to collision events by implementing the didBeginContact method:

1
2
3
4
5
6
7
8
9
10
- (void)didBeginContact:(SKPhysicsContact *)contact {
  SKNode *bodyA = contact.bodyA.node;
  SKNode *bodyB = contact.bodyB.node;

  // Check for Hero projectile to Antagonist collision.  If found, blow up Antagonist
  if ([bodyA isKindOfClass:[SKEmitterNode class]] && [bodyB isKindOfClass:[OLAntagonist class]])
    [self blowUpAntagonist:(OLAntagonist *)bodyB];
  else if ([bodyB isKindOfClass:[SKEmitterNode class]] && [bodyA isKindOfClass:[OLAntagonist class]])
    [self blowUpAntagonist:(OLAntagonist *)bodyA];
}

End Result

Below is a screenshot of what to expect!

Alt text

Improving Abstraction and Testability by Removing Activerecord Callbacks

ActiveRecord gives software developers a way to hook behavior into a model during persistence related activities. This can come in handy, however, everything that can be done in a callback can be done in a better, cleaner way.

An example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class User < ActiveRecord::Base

  has_and_belongs_to_many :badges

  before_save  :downcase_sensitive_fields
  after_create :send_welcome_email, :award_sign_up_badge
  after_save   :award_earned_badges

  private
  def downcase_sensitive_fields
    self.email = email.to_s.downcase
  end

  def send_welcome_email
    UserMailer.welcome_email(self).deliver
  end

  def award_sign_up_badge
    badge = Badge.find_by_name('Sign Up')
    self.badges << badge
  end

  def award_earned_badges
    badge = Badge.find_by_name('One Year')
    if created_at < 1.year.ago && !badges.include?(badge)
      self.badges << badge
    end
  end

end

We can improve this by moving each of the various callbacks to a more appropriate place and in the process simplifying our User model. This will allow the User model to focus on what it does best.

First, let’s look at the different types of actions that are happening. Our first callback is forcing our email to lower case, which is a data manipulation action to normalize the input into something we desire. Hooks that manipulate data can be replaced with overridden setters:

1
2
3
4
5
6
7
8
9
class User

  has_and_belongs_to_many :badges

  def email=(val)
    write_attribute(:email, val.to_s.downcase)
  end

end

Next, we see the other callbacks are things we want to happen either when a User is created or when it is saved. Lumping these actions into callbacks makes testing harder, as you often get unwanted side effects in your tests. As we see with the badges, it also means we have a strong reliance on Badge. You see this type of callback most often when someone has diligently followed the Skinny Controller/Fat Model paradigm. They know this code shouldn’t be in the controller, so they put it in the model and since it is related to saving the trend is to use callbacks.

We can improve this situation by creating a new class that will be in charge of knowing how to handle persistence related side effects. We’ll call it a UserService.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class UserService

  attr_accessor :user, :mail_service, :badge_service

  def initialize(opts)
    @user = opts[:user] || User.new
    @mail_service = opts[:mail_service] || UserMailer
    @badge_service = opts[:badge_service] || BadgeService.new
  end

  def create(params)
    user.attributes = params
    user.valid? && create_user
  end

  def update(params)
    user.attributes = params
    user.valid? && update_user
  end

  private

  def create_user
    if (success = user.save)
      mail_service.welcome_email(user).deliver
      badge_service.award_badges(user, new: true)
    end
    success
  end

  def update_user
    if (success = user.save)
      badge_service.award_badges(user)
    end
    success
  end

end

class BadgeService

  def award_badges(user, opts)
    sign_up_badge(user, opts)
    one_year_badge(user, opts)
  end

  private
  def sign_up_badge(user, opts)
    if opts[:new]
      badge = Badge.fetch(:sign_up)
      user.badges << badge unless user.badges.include?(badge)
    end
  end

  def one_year_badge(user, opts)
    if user.created_at < 1.year.ago
      badge = Badge.fetch(:one_year)
      user.badges << badge unless user.badges.include?(badge)
    end
  end

end

This also gives us an opportunity to easily change how badges are awarded. We can see that there might be further areas we could improve. For example, we can shift the rules for badges to a BadgeRule class or into the Badge itself instead of the BadgeService knowing the logic for each badge. Since we are still directly using an ActionMailer for the welcome email it makes stubbing the mail_service clumsier, so we may want to further abstract that as well.

Now, our set of classes are much easier to test and it is clear what each class is responsible for. All of the business logic of what needs to happen when a user is created and saved can now be tested without a real user, real mailer, or real badges. This means no database hits and much faster tests.

Deploying Rails 4 to Heroku

Heroku is an excellent option for deploying your Rails 4 application and the following setup will allow you to get maximum performance for a minimal cost.

Application Design Choices

Choosing the right services and architecture can go a long way to maximizing performance on Heroku.

Application Server

You have a number of choices for application servers, however you will see your biggest performance gains using clustered Puma. This acts like Unicorn by utilizing several different processes (workers) but still has the mutli-threading provided by Puma. Since your rails app is going to be I/O blocked the vast majority of the time, you will benefit from this setup even on MRI. Add the puma gem to your Gemfile and add the following line to your Procfile:

web: bin/puma -C config/puma.rb -p $PORT

Then in config/puma.rb put:

1
2
3
4
5
6
7
8
9
workers 4
threads 16,16
preload_app!

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

Background Jobs

You should be sending any non-trivial processing to a background job. The best way to maximize the use of your worker dynos is to use sidekiq for your job queue solution. Add the gem to your Gemfile and add the following line to your Procfile:

worker: bin/sidekiq

Optionally you can adjust the number of threads it uses. If most of your jobs are I/O bound try increasing the number of worker threads from the default 25. You can do this with the -c 50 option.

Database

Heroku can support a number of different database options through the Heroku Addons, however the default is Postgres. Postgres has a number of features that give it a great deal of flexibility including support for Hash and Array fields. I highly recommend you use Postgres locally for development as well instead of sqlite. Just add the pg gem to your Gemfile.

Unless you tell Heroku otherwise, you will have a development database which has a number of restrictions. The database has no caching, a limited connection pool, and a limitation on the number of rows you can have in your tables.

Any production application should be using Crane or better which can be added using the web interface or the command line. This will give you a base level of caching, no limitation on the number of rows, and a large 500 connections limit. Depending on your database size and usage you may wish to choose a larger database option which increases your cache.

Amazon S3

If you do any processing of images in your application, I recommend using Carrierwave and storing the images on S3. Furthermore, to reduce any chance of time-outs on uploads, I suggest having your forms upload direct to Amazon S3 and placing a job in Sidekiq to pull the image, process it, and place the processed images back on S3.

Also, rather than having your application serve assets (doesn’t it have something better to do??), look at adding the asset_sync gem to your project. This will allow you to hook into the asset precompile step and ship all of your assets to Amazon S3. Then just set your asset_host to your S3 bucket.

Heroku Rails 4 Support

Heroku treats logs as streams. If you add the following to your Gemfile, your app will handle logging as you expect and will be set to serve assets as well.

gem 'rails_12factor', group: :production

Heroku Ruby 2.0 Support

You should tell Heroku what version of Ruby to use. You can do this in your Gemfile by placing the following line:

ruby '2.0.0'

Heroku Addon Recommendations

Heroku has a large number of very useful Addons, many of which have free options.

PG Backups

Heroku will back up your database but you have to ask them to! Make sure you add on PG Backups. It’s free and you are silly not to. I recommend the “Auto – One Month Retention” option.

Redis (Pick One)

If you added Sidekiq to your application as I have suggested, you need a Redis Addon. There are a number to choose from and some have free tiers which provide plenty of space for your Sidekiq job queue. If you use Redis in other places in your application or expect a large queue depth, then select a larger package as necessary. I’ll leave it up to you to compare price and service.

Memcachier

You can use Redis as your cache store for Rails, but if you use memcache, you can get more cache for your cash using Memcachier, including 25MB in their free tier.

Logs

Heroku logs are not great. That’s probably an understatement. I highly recommend adding in a logging Addon such as Papertrail or Loggly.

Mandrill

Despite the horrible name, if you want to send email from your app, you should look at Mandrill. It is the transactional email service offered by Mailchimp. It works great just as an smtp server but has excellent bonus features like success tracking, open tracking, and you can use your Mailchimp templates.

New Relic

You get the basic version for free, but again you have to tell Heroku you want it. Just add the addon, include the gem in your app and optionally modify the config file. You then get excellent stats of your application performance.

Extra bonus, you can use New Relic’s availability monitoring to keep a single dyno application alive. Just set up availability monitoring and give New Relic and url on your app to ping. I highly suggest creating a specific ping end point that does nothing so it is the lightest load on your application as possible.

Additional Monitoring

I suggest adding some additional monitoring and/or error reporting. Services like Airbrake and Honeybadger both have Heroku Addons that make managing your application errors easy.

Others

There are of course a large number of other Addons which may enhance your application or make your life easier. I suggest browsing through them all and looking for things that will specifically help your particular application.

Wrap Up

So let’s talk about price as that always seems to come up when Heroku is brought up as an option. Let’s first layout what the minimum actually looks like for a true production grade application:

  • Web Dynos (1): Free (See New Relic Tip)
  • Worker Dynos (1): $35
  • Database (Crane): $50
  • PG Backups: Free
  • Redis (Redis Cloud 25MB): Free
  • Memcachier (25MB): Free
  • Papertrail (10MB w/2-Day Search): Free
  • Mandrill (12K Emails/Month): Free
  • New Relic: Free
  • Airbrake (Dev): $9

Total: $94/month

But that’s just the minimum so let’s be realistic and look at what a production application that gets any real amount of traffic actually needs:

  • Web Dynos (2): $35 (1 is Free)
  • Worker Dynos (1): $35
  • Database (Kappa): $100
  • PG Backups: Free
  • Redis (Redis Cloud 25MB): Free
  • Memcachier (250MB): $25
  • Papertrail (100MB w/7-Day Search): $15
  • Mandrill (40K Emails/Month): $5.95
  • New Relic: Free
  • Airbrake (Production): $25

Total: $341.95/month

There are surely cheaper hosting options out there that will give you the same or better performance for less money, however you have to ask yourself as a small start up the following question:

Do I want to spend my time developing my application or maintaining it?

If I don’t spend all the time setting up servers and services, and performing regular maintenance, backups, and worse fixing things when they break, I need to hire someone to do this for me. The best case scenario is you may be able to find an admin to handle all of this on a part-time basis, but even at part time you are probably spending at least $500/month.

So, find out what cheaper hosting solution you would like to use, factor in any of the services provided by Addons that you are not going to set up yourself on this platform. Whatever that total is, take the delta from your Heroku bill. If this difference is less than you can hire someone to do the work for you, then you can start considering options other than Heroku. Until then, reduce your stress and just git push heroku.