Decaf Sucks 2: A New Old Design

The iOS 7 betas are coming thick and fast. If we want to finish the rebuild of Decaf Sucks and ship it close to the iOS 7 launch, we need to be pragmatic with our design changes. We’ll look to change as little as possible, but we still don't want to release the same old app with a slightly different skin. We want to do a little more thinking than this and give people something to make the upgrade worthwhile.

We'll achieve this by focusing on one of the core principles of the new iOS 7 design: deference to content, through a user interface that highlights the content instead of competing with it.

Right now we don't do so well by this measure, even at our very first screen:

The empty Decaf Sucks first screen

Unless our users want to stop and admire our search field and big green button, we can do a lot better than this. This isn't content. It's functionality, and it should be as invisible as possible. A much better idea would be to jump straight to the list of cafes, around the user's current location:

A list of Decaf Sucks cafes in Berlin

When people open Decaf Sucks, it’s usually because they want to find coffee now. The alternative action, looking for a different location, is much less frequent and can be hidden behind a button in the toolbar. It doesn't need prime real estate on the first screen of the app. So what we can do is completely remove the first screen and start showing useful content right away.

This is a good start, but we can do better still, by thinking more deeply about what our “content” really is. It's not just a list of cafes, it's the user's context, their location relative to the cafes around them. It's not enough just to crave a macchiato and see some text saying a café is 200m away; you should also know where that café is and what path you might take to get there. This is where the map view shines. We've had a map right from the app's first release and for all these reasons it's one of the most useful ways to find cafes. But it's still hidden behind a button press. There's no quick way to get an immediate, at-a-glance understanding of the caffeine landscape that surrounds you.

We can solve this by combining the map and list views:

A preview of the Decaf Sucks 2 combined list and map screen

After this, when the user launches the app, not only will it be already primed for their current location, they'll also see the nearby cafes both in a map and a list, and can choose to interact with whichever representation is most useful to them.

These are the main design changes we'll make for Decaf Sucks 2. We'll condense three screens into one and present useful content as early as we can. If this takes you to a suitably excellent coffee a few seconds earlier, then our mission will be accomplished!

Decaf Sucks 2: Starting Over

Decaf Sucks 2: New Xcode Project

They say to avoid the big rewrite. Luckily, Decaf Sucks isn't that big.

Importantly, one of the app's key reasons for being is to give ourselves an opportunity to build something great for iOS. When it comes to great, a lot has changed since the middle of 2011, when we released the app for iOS 4. This includes the development tools, which have grown to include:

  • ARC (Automatic reference counting)
  • Modern Objective-C (literals, object subscripting, automatic synthesizing of properties, no need for private method header declarations, etc.)
  • Storyboards
  • Auto Layout
  • Collection views
  • OS-integrated Twitter & Facebook support
  • Cocoapods
  • And the much improved editing environment in Xcode 5

Getting our hands onto these will make the app more fun to develop and improve our ability to add great new features further down the track. Decaf Sucks was also our first major iOS app. We've learnt a lot since then and there's plenty we can tidy up.

The mobile app development world is moving fast; the list above proves it. For a small app like Decaf Sucks, it makes sense for us to build with the best and latest available tools, and not to handicap ourselves for the sake of the broadest user base (especially when new iOS adoption is so fast). So Decaf Sucks 2 will be built from scratch, and for iOS 7 only. Apple is taking their mobile user experience to a significant new place, and we want to do everything we can to arrive there too.

Check back for the next post, where I'll share some thoughts on our design approach!

Decaf Sucks 2 Is Coming, 2 Hours at a Time

If you know me even a little, you'll know I love drinking coffee. This is why we built Decaf Sucks, as a place to record and share our café experiences. It's turned out that it also offers a great way to travel: finding coffee is usually an interesting axis along which to explore a city. It takes you away from the tourist traps, to interesting neighborhoods, and injects you into the regular lives of the locals. This is how I've explored Bacolod, Tokyo, Hong Kong, and most lately, San Francisco.

It was also in San Francisco that I was lucky enough to attend Apple's WWDC event for 2013. It left me enthused for all the opportunities that iOS 7 affords to developers, and with Decaf Sucks being our biggest stake in the iOS marketplace, I really wanted to take the chance to ship something new.

It so happens that I've just started a 2-week holiday, the first real time away from work in this year's travels. But if you're anything like me, and your work is something you love, then it's unlikely you completely switch off anyway. So I've decided to make the most of this and spend a little time each day on developing Decaf Sucks for iOS 7. It'll start in the mornings: I've been waking up early lately, giving me a whole 2 hours or more before the day really begins. This is how I'll be developing Decaf Sucks: 2 hours at a time. It'll be an exercise of doing a lot with a little, of the bootstrapped side-project.

In the spirit of my last Decaf Sucks development sprint, I'll document my progress here, before slipping my iPhone into my pocket and setting off each day (likely in search of the morning's first coffee). Watch this space!

Sneaking Into the Everyday

Standing in cold, pre-dawn WWDC keynote line, I met a couple of the friendly Mac & iOS engineers from 6wunderkinder, makers of the beautiful Wunderlist apps. I'd tried Wunderlist in the past, but some weeks later, I thought I'd give it another go. Turns out, it's been great! Just the mix of power and simplicity that I need to stay focused on my tasks.

This change made me realise that quite a lot of my most-used tools are also things I'd picked up only in the last year or so. On the Mac, they are:

And on iOS:

All this has happened without any particular conscious effort. Apps come to my attention, and if I like them, there's a good chance they stick around. Granted, as a software developer I may be more curious than most, but I still take this as a heartening thing: no matter when you launch, if you offer something better or compellingly different, you stand a real chance of finding your way into people's everyday.

objc.io

objc.io is a "periodical about best practices and advanced techniques in Objective-C." Its first issue has a series of articles all about lighter view controllers. I subscribed right away; this looks like it has to potential to set alongside NSHipster and iOS Dev Weekly as valuable and regularly-updated resources for Cocoa developers.

Levelling Up With AngularJS: Building a Reusable Click to Edit Directive

In my last article about AngularJS, I shared how easy it was to build a simple "click to edit" field, and along the way introduced some of Angular's core concepts: controllers, expressions & two-way bindings between your markup and the controller's scope. This was a nice introduction, but the resulting code has a shortfall: it's not easily reusable. For something that behaves as a form field, you want the ability to sprinkle it across your pages wherever you like. This is where directives come in. Spurred on by Max's recent foray into data-backed directives, I'll now take the next steps and turn this click to edit example into a reusable Angular directive.

If you've sprinkled Angular into your apps at all, you've already worked with its built-in directives, things like ng-model, ng-repeat and even ng-controller and ng-app. With a directive you can add hooks into the HTML markup for injecting your own custom markup and logic. As the AngularJS documentation puts it, "directives are a way to teach HTML new tricks." They help you keep your markup declarative and intention-revealing, and your implementation packaged away in a self-contained, reusable components.

Here's how we'd want a click to edit directive to look in practice:

<div click-to-edit="someModelName"></div>

We want the click-to-edit attribute to bind to a model in the current scope (just like ng-model does) and have that entire <div> replaced with the markup needed to show the field. Here's the directive to do it:

app = angular.module("formDemo", []);

app.directive("clickToEdit", function() {
    var editorTemplate = '<div class="click-to-edit">' +
        '<div ng-hide="view.editorEnabled">' +
            '{{value}} ' +
            '<a ng-click="enableEditor()">Edit</a>' +
        '</div>' +
        '<div ng-show="view.editorEnabled">' +
            '<input ng-model="view.editableValue">' +
            '<a href="#" ng-click="save()">Save</a>' +
            ' or ' +
            '<a ng-click="disableEditor()">cancel</a>.' +
        '</div>' +
    '</div>';

    return {
        restrict: "A",
        replace: true,
        template: editorTemplate,
        scope: {
            value: "=clickToEdit",
        },
        controller: function($scope) {
            $scope.view = {
                editableValue: $scope.value,
                editorEnabled: false
            };

            $scope.enableEditor = function() {
                $scope.view.editorEnabled = true;
                $scope.view.editableValue = $scope.value;
            };

            $scope.disableEditor = function() {
                $scope.view.editorEnabled = false;
            };

            $scope.save = function() {
                $scope.value = $scope.view.editableValue;
                $scope.disableEditor();
            };
        }
    };
});

Let's break this down a little. Right at the top we have its name: "clickToEdit." Angular directives use camelCase names in the JavaScript, which are matched to their name-with-dashes equivalent in HTML. Next, you'll see we've provided an HTML template string for the editor. It can use all of the same Angular-provided facilities that you'd otherwise use in your own page templates.

The directive function must return an object that specifies its behaviour and configuration. In our case, we use restrict: "A" to specify that the directive will only match HTML attributes, and replace: true to have the directive's template entirely replacing any elements that it matches.

We also specify a custom scope for the directive. You'll want to at least provide an empty object here if you want your directives to have their own independent scope, but you can also use this scope object to create a mapping from the HTML element's attributes to varaibles in the directive's scope. In our case, value: =clickToEdit sets up a bi-directional binding between the value in the directive's scope and the value of the click-to-edit attribute in the parent scope.

The last thing we provide in the directive configuration is a controller that provides logic to back the directive's template. This packaging of a template and its behaviour is what can turn a directive into a truly reusable component. The controller here is just a direct copy of all the code from my earlier post, but because it's packaged along with the directive, we've now made it reusable.

How would it look in practice? We might have something like a LocationFormCtrl controller that manages the editable form for a "location" record:

app.controller("LocationFormCtrl", function($scope) {
    $scope.location = {
        state: "California",
        city: "San Francisco",
        neighbourhood: "Alamo Square"
    };
});

And if we wanted to make each of these attributes have a "click to edit" field, it's now as simple as this:

<div ng-controller="LocationFormCtrl">
    <h2>Editors</h2>
    <div class="field">
        <strong>State:</strong>
        <div click-to-edit="location.state"></div>
    </div>
    <div class="field">
        <strong>City:</strong>
        <div click-to-edit="location.city"></div>
    </div>
    <div class="field">
        <strong>Neighbourhood:</strong>
        <div click-to-edit="location.neighbourhood"></div>
    </div>
</div>

Straightforward, declarative, no-cruft. This is how Angular can transform your apps, and directives play a big part in that.

To give you something to play with, here's a working demo. Below the editable fields, we also directly print the LocationFormCtrl scope's location attributes, so you can see how changes of the attributes in the fields propogate back up to the parent controller's scope.

Of course, there's even more we could do. Right now, this directive only deals with straightforward <input type="text"> fields. What about if you wanted <input type="date"> or even a <select>? This is where you could add some extra attribute names to the directive's scope, like fieldType, and then change some elements in the template based on that value. Or for full customisation, you could even turn off replace: true and add a compile function that wraps the necessary click to edit markup around any existing content in the page. I'll leave both of these as exercises to the reader, for when it's time to level up yet again!