Almost 2 years ago I wrote about our approach to building our first in-house native application. This week, we shipped version 2.0 of Basecamp for iPhone, which now shares a codebase with Basecamp for iPad. I’m proud to say this is our best iOS release yet. Give it a shot!
What’s changed? Everything. For starters, we’ve:
- Rewritten the app in Objective-C
- Banked on our hybrid architecture
- Shared a universal codebase between iPhone and iPad
- Reinforced our testing infrastructure
I’m happy to share the details on how we built and shipped the app. Let’s dig in.
Buckling down
The new iPhone app is 100% Objective-C. Why did we move away from RubyMotion? Quite honestly: we needed to buckle down and learn the platform as a team.
Basecamp for iPhone 1.x was my first iOS application, and it showed. Updating it to work on iOS8 was painful, and there’s many completely non-standard patterns used in the app. One particularly bad example: NSNotificationCenter
is used for passing data around the app almost exclusively.
None of these things are RubyMotion’s fault, but I felt that after a year of working with iOS, I didn’t know the platform. That’s not something to be proud of. Avoiding Xcode may have been a badge of honor to get started, but it’s a shame to ignore the tools and affordances it provides.
I’m still convinced I wouldn’t have gotten this far without RubyMotion, and as a learning tool its value is immeasurable. It got us started and hooked on iOS development, and has been doing that for not only us but for many others. There’s plenty of examples of the wide impact RubyMotion is having. One of my favorite games I’ve played this year, A Dark Room, was written in RubyMotion. This certainly isn’t the end of RubyMotion’s influence on the iOS or Ruby communities. Once again, huge thanks to Laurent and the entire HipByte team for making a great product.
Hybrid sweetness
Our hybrid approach to native applications with embedded web content continues with this release. We’ve taken it a step further: any interaction with todos is now native.
It’s funny to me that a good “first app” for a mobile developer is a todo app. Todos aren’t simple, especially our todos in Basecamp. There’s due dates to lock down. People to assign. Comments to complain. Dragging to prioritize. There’s a lot to worry about for our todos, and it’s important enough to do right natively.
The “sweet spot” we’ve sought out is flexible: if it makes more sense to write a feature natively, we’ll try it out. We’ve done several bake-offs at this point of native vs web features. Sometimes web wins since we might need to update content, or it’s hard to render certain types of content natively. Sometimes native wins since the feel of a native control is just so obviously better, or it’s just more natural to the platform.
If you’re still considering a hybrid approach to your app, by all means: please do! But when it makes sense, challenge your assumptions.
One codebase, two apps
After shipping Basecamp for iPad this summer, we wanted to bring the same experience to iPhone. We wrestled with the upgrade path for our users on both devices with their existing apps for months. Every time we brought it up it would kill at least an hour or two collectively of our time: what if we made one app? What if we took the existing iPhone app out of sale, and replaced it with the iPad version? I went so far as writing down 5 different plans for the upgrade and giving them codenames so we could compare them in a concrete way. Just writing them down instead of talking about the tiny details of each individual decision helped crystallize the problem.
We ended up deciding to keep the apps separate in the App Store (codenamed: Vanilla Pepsi), which allowed automatic updates to give everyone the new app without having to go download a new one. This caused more pain for us inside of Xcode, as we had to now maintain two separate targets and bundle identifiers, but it ended up being simple for our customers. The upgrade numbers prove this now: we wouldn’t have seen a 70%+ uptake rate on the app a day after releasing it if we had a separate install:
If you’re faced with a decision like this, your customers’ time is more valuable than your own. Make it easy for them.
Continuously integrating
Each member of our team (2 programmers, 1 designer, 2 QA) had Xcode running and working with the latest builds. We’d ship builds via Apple’s TestFlight fairly regularly, but it was easier to just get everyone working with the simulators and the latest codebase. Essential to this process was Xcode’s CI server. It had our backs against regressions and build failures throughout the entire shipping process. If you’re writing an iOS app, you should be running Xcode CI. Getting that feedback and seeing improvement (and fixes!) over time is not only reassuring, but inspiring.
We’re still fighting with the best way to write tests for iOS. Our approach this time was to mostly test some of the messier logic, and avoid integration testing. After trying and mostly failing to maintain a set of KIF tests for the iPad release, we gave up on having our Bots tap around the apps. Our fantastic QA team hammered away at the app and found things we’d never thought of looking for. I’m hoping to play with snapshot testing, as it seems much easier to maintain and debug than traditional integration tests.
Swiftly shipping
Our next target to learn is Swift, and we’ve already started playing with it. I just can’t get enough of optionals. Map/filter lends itself to idiomatic patterns that I wish Ruby was expressive enough to match. We’re also trying to figure out how to write things in a “Swift-like” way, and it doesn’t seem like anyone knows how yet. There’s a few styleguides out there, but so far it’s a wild west of possibilities.
Basecamp on iOS is even better now, and going forward to iOS9 (and iOS10?) we’ll be ready to adapt even faster. If you’ve used the new iPhone app or any of the great features now available on both devices, let us know how they’ve been working for you!
Mike
on 04 Dec 14Might I suggest revising the title? iOS 2.0 is quite a dated version…
Anonymous Coward
on 04 Dec 14Nick
on 04 Dec 14Not a typo: The “map { $0 + $1 }” syntax and “reduce(0, +)” among other examples in that blog post don’t have as succinct equivalents in Ruby.
Kasper Timm Hansen
on 04 Dec 14Well, that reduce example is one character away from being working Ruby: “reduce(0, :+)”. But yes, Swift has got Ruby beat here.
Jess
on 04 Dec 14I, and clearly others as well, misread the title at first glance.
“Shipping Basecamp 2.0 for iOS” would have made more sense. Otherwise, great post.
Anonymous Coward
on 04 Dec 1437signals/Basecamp as a company are behind yet again.
Why release this iOS app when Swift was made available 5 months ago (June)?
David Chen
on 05 Dec 14I’m curious that how you did it with automatic upgrade outside the App Store? By updating web content in app periodically? I have the same thought before but worried if Apple allow me to do so.
Nick
on 05 Dec 14David, the 2.0 update went through the normal Apple review process.
Occasionally we do update content or styles, fix bugs, add minor features, etc on our web views without Apple’s approval. That part is another fantastic reason to favor a hybrid approach.
Marcos
on 05 Dec 14Congrats on the upgrade! Some nice improvements & thanks as always for sharing all the great behind the scenes details. I’ll be especially interested to hear any future reflections as you play more with Swift.
I did find it ironic that you included “Basecampy working from the beach” given DHH’s previous blasting of Microsoft for a similar marketing strategy: /posts/3683-microsofts-dystopian-pitch-for-remote-work
DHH
on 05 Dec 14Marcos, you’re completely right. It’s not even ironic, but hypocritical. Promoting mobile apps as “allowing you to push more work into more leisure moments” is appealing because it’s such a visual image: Oh, wow! Work at the beach! It makes for an easy and a “fun” drawing.
It also, however, sends the completely wrong message. Using mobile shouldn’t be about work encroaching your every waken moment. Let it be about getting more work done in more places during work. We have lots of customers using Basecamp who go on client visits or work outside or any other scenario where using a desktop computer just doesn’t make sense. That’s the angle to hit.
So, apologies for our slip, here, and thanks for calling it out!
Shealagh Kate King
on 09 Dec 14I’m just checking out all you have to offer at the moment, and seriously… ? Thank you, Thank you all.
I really need one thing. I need a view of the calendar where I can see three or perhaps even 6 months in advance – perhaps with just the colour coding showing up – to give me an idea of where I am dedicating my time over longer periods at a glance. This is really essential for ++ forethought in my planning, & keeping a close eye on priorities throughout the process, while retaining as soft a structure as possible so the kid in me stays on board.
BTW, your ‘Entrepreneur’ video was truly a gift. You are cogs in the wheels of many purposeful projects I’m sure. A Nurtured Life is next up ;P
Seriously. Thank you.
Warm regards, Shealagh K
Scott J Sterling
on 09 Dec 14This is an exceptional update. It’s made me want to use Basecamp even more. Two thoughts for you: 1. Calendar on iOS is great. On Mac its a useless, illegible jumble. Help! 2. Siri. For the past couple of years I forced myself to be a dedicated user of Siri for adding reminders and events plus lots more. Now I can’t live without it. I am willing to give one of my appendages if you will implement the ability to add a To Do using Siri. My suggestion is this: have a default Inbox in Basecamp so that when I speak a reminder into Siri it automatically goes to that Inbox. Then when I have time to sort things out I’ll move that To Do where it belongs in a Project/List. Being able to just pull out my iPhone, speak a reminder and then put the phone back in my pocket is so great. Please please please let me do that for work.
Nick
on 10 Dec 14Scott, I’ve been playing with a Siri/Twilio/SMS gateway for a while now, trying to get it to do something useful. My main problem is that I can’t figure out how to get Siri to not pronounce “Basecamp” as “Basacamp”.
I think we’ll have to wait until an official API comes out for Siri.
Roman Le Négrate
on 10 Dec 14@Nick: About your comment “I wish Ruby was expressive enough to match”—I have to concur with Kasper Timm Hansen in that Ruby isn’t any less expressive than Swift on that front (map/filter/reduce), if a tiny bit more verbose. See his `reduce` example, same goes for the other kinds of operations.
Scott J Sterling
on 10 Dec 14Nick, have you looked into how OmniFocus does it? It works perfectly. You turn on Capture Reminders and tell it which Reminders List you want it to capture.
By the way, this version of Basecamp on the phone is so good I deleted OmniFocus, for real.
This discussion is closed.