Today, we’re introducing Prefer – a platform for the future of independent work that we’ve been working on since 2015. I won’t rehash our launch post, which explains what we’re doing and why (and for even more, please read what my colleagues Scott and Andrew also had to say), but I want to add some additional color to how we’re approaching our mission from an engineering perspective.
Software to power the future of work
Having spent the first part of my career primarily working with great product thinkers, engineers, and designers, I’m excited to now add operators, strategists, and community builders to that list. At Prefer, great code and beautiful designs are necessary but insufficient factors to our long-term success; important as they are, they won’t make a difference if we’re not actually solving an acute need that we deeply understand as a company.
Suffice to say, we have our work cut out for us. We're building both a user-facing product, but also whatever technology is needed to power our community-building operations. The latter may end up being more important than the former. The software we build will be the primary way that our customers interface with Prefer, but will also be crucial in diagnosing which approaches we should be taking and when, and then sprinting towards them.
Distributed from the start
Unconventionally for a team of our size, Prefer has offices in both New York and San Francisco, with engineers on the ground in both locations. Building a distributed team from day one has its challenges, but also provides us with a few unique advantages (notably, hiring the best developers that we can in either location).
To account for the inherent overhead, we take measures like grouping meetings together on specific days to provide for as much uninterrupted development time as possible. As we’re regularly working across cities and timezones, I think our documentation, communication, and collaboration processes are advanced beyond what one would expect from a company as nascent as we are, and provide us more flexibility when it comes to travel, remote work, and general quality of life. We leverage great tools like Clubhouse and Quip to stay productive and in touch without letting the work around the work become a distraction. And we get both Mission-style 🌯 and New York City 🍕 (we make a point to spend lots of time together in person, and not simply spend it working).
Inspired by ourfriends at Artsy and Kickstarter, we hope to make open source a big part of how we approach day-to-day software development at Prefer. One of our core values as a company is to provide individuals with empowerment, and sharing what we build with the broader development community is one of the best ways I can think of for us to do exactly that.
I’m making this proclamation despite not having done anything towards this end yet, because that’s how strongly I feel about it.
Come join us
Including myself, there are only five developers working on Prefer, but we have grand ambitions for scaling our codebase as well as the team itself (did I mention that we’re hiring?). We approach the technical challenges ahead with collective excitement for software engineering as a craft, but more importantly, in service of the mission that our whole company has feverishly rallied behind.
With all of that said, I think it’s time to get back to work.
View hierarchies in iOS applications have only gotten more complex over the years, particularly as view controller containment has gained traction as a nice way to compose parts of your application together without succumbing to inheritance (and as such, tighter coupling than you probably want). One downside of this is that displaying something on top of the currently displayed view can potentially involve quite a bit of hierarchy traversal and understanding of how your UI’s pieces all fit together.
When attempting to overlay something on top of your entire view hierarchy – common examples include a notification banner or a heads-up display – it’s helpful to move up a level beyond regular views or even view controllers, and start thinking in the context of windows. While one could reach for UIApplication.shared.keyWindow, or employ some private API to find e.g. the window that’s currently hosting the status bar or an alert dialog, a far simpler and cleaner approach is to simply create a new window of your own. This is far from a new technique, but I only recently learned how easy it actually is in practice.
UIWindow inherits from UIView, meaning you can simply create a new instance by providing it with a frame: let window = UIWindow(frame: frame). Magically, you don’t actually have to explicitly add your new window to the view hierarchy. Simply initializing it and setting its isHidden property to false1 will cause it to be shown on screen, with its stack order dictated by its windowLevel property. UIWindowLevelStatusBar allows your window to sit atop everything else.
Keep a strong reference to your newly created window and add whatever subviews you want to it. When finished, simply removing the reference will cause the window (and as such, its subviews) to be removed from the view hierarchy (and subsequently, from memory).
There’s a little bit of work involved in making sure that your new window doesn’t unintentionally impact the status bar style, so I’ve provided some sample code below that shows how to specify exactly how you want it to behave (if you’re not using view controller-based status bar appearance, you can ignore this and continue driving the style however you do currently).
extensionUIWindowfinalclassStatusBarPreferringViewController:UIViewController// MARK: - InputsprivateletstatusBarStyle:UIStatusBarStyle// MARK: - Initializationinit(statusBarStyle:UIStatusBarStyle)self.statusBarStyle=statusBarStylesuper.init(nibName:nil,bundle:nil)}requiredinit?(coderaDecoder:NSCoder)fatalError("init(coder:) has not been implemented")}// MARK: - UIViewControlleroverridevarprefersStatusBarHidden:Boolreturnfalse}overridevarpreferredStatusBarStyle:UIStatusBarStylereturnstatusBarStyle}}staticfuncnewWindow(level:UIWindowLevel=UIWindowLevelStatusBar,statusBarStyle:UIStatusBarStyle)->UIWindowguardletkeyWindow=UIApplication.shared.keyWindowelsefatalError("Must have a key window")letwindow=UIWindow(frame:keyWindow.bounds)window.windowLevel=levelwindow.isHidden=falsewindow.rootViewController=StatusBarPreferringViewController(statusBarStyle:statusBarStyle)returnwindow}}
We’d all like to be more productive, but it’s far easier to stick with a daily habit like reading for at least five minutes than, say, training to run a marathon sometime in the next year. I’ve personally found these types of small, repetitive goals really easy to gamify, and if your brain is anything like mine, a few strategic dopamine deployments can really go a long way. Drinking eight glasses of water a day isn’t hard to begin with, but it’s certainly a lot easier if you’re constantly being reminded about it. And if you’re made aware that you’re actually at risk of breaking a 15 day streak, you’re even more likely to get off the couch for a refill. Obviously these streaks don’t really matter, but brains work in mysterious ways. Or at least mine does.
It’s really easy to go overboard here. In a perfect world, I’d of course like to read about current events and practice the guitar every day, but the quickest way to make sure you don’t drink those eight glasses of water is to lump them alongside a bunch of other goals that you weren’t realistically going to hit anyway. Take something like hitting a daily stand goal1; I can usually accomplish this without really thinking much about it, and on the days when I don’t, I’m usually only an hour or two short. But since missing a day isn’t particularly crucial, there’s no compelling reason for me to explicitly check how I’m doing. Going from pull (“Let me proactively see how many hours I’ve stood for today”) to push (“Hey, you need three more hours or you’re going to lose your 20 day streak”) provides enough of an impetus to do the task that was easy to begin with as long as you didn’t forget.
Like weather or to-do list applications, there are a lot of different habit trackers, which shouldn’t be surprising given that everyone responds to subtly different types of motivation. Most are pretty similar, however. Before diving in too deep, let’s take a look at a couple that aren’t really full-featured habit trackers, but interesting entries nonetheless.
Sessions and Activity++
Sessions is unique amongst the applications listed here, as it’s entirely built around setting timers for habits. If your goal is to read for five minutes each day, it’ll kick off a timer and increase your streak once it’s completed. It’s very nicely designed, and there are certainly plenty of cases in which timers are useful when performing daily habits2, but it’s not flexible enough to be a general purpose streak tracker.
Activity++ has a narrow focus; it tracks streaks and provides gorgeous visualizations for the three metrics highlighted by Apple’s Activity app – Move (active calories burned), Stand (hours in which you’ve stood and moved for at least a minute), and Exercise (minutes of “brisk activity”) – and does so automatically by integrating with HealthKit. Given the small feature set, Activity++ is a very nice application, but it frustratingly doesn’t notify you if you’re at risk of breaking a streak. There is an Apple Watch complication, but it oddly doesn’t include any streak data. I’d like to see a simple Today widget with streak information added as well.
Next, a group of apps that I found to all be pretty comparable to one another.
Habit List, Momentum, and Strides
These are all nice, and all pretty standard as far as streak tracking goes. They each provide a bevy of flexibility options (multiple times per day or week, every 2-3 days, only on Tuesdays, etc.), so depending on your needs, the specific configuration that one provides might be reason alone to use it. Habit List has my favorite design of the bunch, but Momentum has a Today widget which may give it a slight edge. I don’t personally need a desktop component, but if you do, Momentum has a Mac app and iCloud sync, while Strides (my least favorite of the three) is also available on the web.
With a few slight tweaks, either Habit List or Momentum could be sufficient, but they’re each missing at least one of the two features that I’ve since come to rely on from…
Productive and Streaks
Productive is similar to the apps outlined above, feature-wise, and sports an incredibly custom UI that I really enjoy using. But the ingenious difference is that it lets you specify when in the day you plan to perform each of your habits: in the morning/afternoon/evening, or anytime. It also let’s you indicate which specific hours your morning, afternoon, and evening are comprised of3.
Why? If you only perform a certain habit (e.g. flossing) at night, there’s no need for your homescreen to show a badge all day indicating that you haven’t done it yet. I’m pretty conservative about app icon badges – I think important ones should be noticeable and jarring, which means not letting unimportant ones dilute their prominence. Productive lets me do exactly this, which makes up for the fact that it doesn’t offer a Today widget or a Watch complication.
The easiest habits to track are the ones that get automatically tracked for you. While Streaks allows you to enter custom habits as well, it’s main draw is a wide variety of built-in presets for automatically tracking based on your HealthKit data: sleeping, drinking water, weighing yourself, exercising, etc. For this reason alone, tracking your health-based habits with Streaks is a no brainer. It even has a Today widget, a Watch complication, and really nice custom Watch notifications.
The biggest problem with Streaks is that it supports a maximum of only six habits. This, combined with the aforementioned smarter badging solution that Productive employs, has me using both in conjunction with one another: Streaks for habits that can be automatically tracked via HealthKit, and Productive for everything else. And it’s working really well for me.
I don’t realistically expect Productive to add HealthKit support, or Streaks to drop its habit limit and ape Productive’s badging implementation, but if one or the other did, I’d happily consolidate.
Productivity is all about finding a system that works for you, and importantly, not trying to do too much. In my case, the combination of reminders and streak tracking helps keep me motivated and prevents me from forgetting, making it easy to keep up with simple habits that I know would otherwise lapse. As our smartphones and watches learn more and more about ourselves, the opportunities to employ systems4 that help us be better versions of ourselves is only going to increase.