Misusing enums

This is a response to Matt Diephouse’s article, which is itself a response to John Sundell’s article. You should go read these first.

Matt starts off by saying:

Earlier this week, John Sundell wrote a nice article about building an enum-based analytics system in Swift. He included many fine suggestions, but I believe he’s wrong about one point: that enums are the right choice.

Therefore, I’ll start similarly:

Earlier this week, Matt Diephouse wrote a nice article about building a struct-based analytics system in Swift. He included many fine suggestions, but I believe he’s wrong about one point: that structs are the right choice.

As the examples in both articles show, analytic events can have different payloads of information that they’re going to capture. Matt uses a metadata property (a Dictionary<String, String>) to capture this, but this approach imposes a significant burden at the callsite. In order to properly fill out an AnalyticEvent struct, the callsite must know how to destructure the current model/event information and package it up inside the metadata property.

This could be fine if you’re dealing with a very small app, but given that we’re at the point where we’re putting in analytics, the chances that this app is small is pretty remote.

Additionally, it’s often not the case that analytics are defined at the application level. They’re typically brought in as part of an underlying framework. This means that the top-most levels of abstraction in your app (the app itself) have to know intimate, implementation details about how levels far below (the raw analytic communication protocol) work and expect their data to be formatted. Now, it’s possible that the metadata is a very loose bucket of “anything goes here”, but that still requires a lot of extra code at the callsite.

And when you’re putting in analytics, you want them to be as least invasive as possible, because they’re not the point of your app.

So, in my opinion, the better approach would be to define your analytics by a protocol, like this:

protocol AnalyticEvent {
    var name: String { get }
    var payload: Dictionary<String, String> { get }
}

The analytics capture mechanism would then only accept values of type AnalyticEvent (the protocol), and not define concrete types itself.

Here are some of the benefits we get by taking this approach:

Semantically appropriate event definition

Each layer of your app can define its own types (whether an enum, class, or struct) that conform to the AnalyticEvent protocol. Perhaps your Networking layer defines events that capture how often it has to hit the network versus how often it has to hit the cache. It can define those in its own custom NetworkingEvent: AnalyticEvent type.

Minimized callsites

By having each layer define its own type, it can create minimized initializers for its custom AnalyticEvent that would be impractical to do with an enum, and cumbersome with a struct. For example, if I had a UserSessionEvent: AnalyticEvent, I could create an initializer that takes a LoginFailureReason as the parameter, and then the initializer turns it in to the privately-known name and payload.

Type checking events

I could create a whole bunch of extensions on an AnalyticsEvent struct to do the custom initializer for the struct that is contextually appropriate for the callsite, but that explodes the numbers of initializers I have to sort through when creating an AnalyticsEvent. The autocomplete would show me every possible initializer for every possible event type, which is a total pain.

On the other hand, by requiring a custom type that adopts the AnalyticsEvent protocol, I can narrow my focus down to only the autocompletion results that are possible for a UserSessionEvent or a NetworkingEvent or a AwesomeCarouselWidgetInteractionEvent, etc.

With this sort of type-checking in place, refactoring these events also becomes easy. I can search the codebase for just NetworkingEvent to see every place where that type of event is getting generated.

Easy extensibility

Since AnalyticEvent is a protocol, adding a new kind of event is trivial. I don’t have to add a new case to an enum. I don’t have to litter stringly-typed event names throughout my code. I don’t have to add another extension to a struct. The protocol makes it easy to isolate concerns to their respective layers.

So, next time you reach for an enum, ask yourself whether you’re going to switch over it. If you’re not, you’re probably better off with a protocol instead.


EDITED TO ADD

It should go without saying that I really appreciate both Matt and John discussing these patterns in a public forum. In no way should my comments be construed as any sort of personal attack or judgement of Matt or John.

Level up your debugging skills

Finding the root cause of an error in your app can often feel very intimidating, whether you’re brand-new to programming or you’ve been building coding for decades. Debugging problems can be extremely time consuming. Where do you start looking? How do you know if what you think is the problem is actually the problem?

While there is no one-size-fits-all approach to debugging, there is a major guiding principle that can be extremely helpful in determining the root cause of an error, and that is to apply the scientific method to your analysis. The Scientific Method is a process we use to learn new things, analyze why things happen, and correct misconceptions. In simple terms, the steps involved are:

  1. Observe
  2. Ask questions
  3. Hypothesize
  4. Test

Observation

There are many ways to observe problems in your app. Maybe it crashed. Maybe it didn’t do something you were expecting it to. Maybe your users or QA testers observed some incorrect behavior. Maybe you saw something yourself. Regardless of how it happened, debugging always starts with an observed issue.

Ask Questions

Questions form the basis of debugging (and indeed, all learning in general). Depending on your goals, deadlines, or other constraints and circumstances, your questions may range from “why is this happening and how do I fix the root cause?” to “how do I hide the symptoms of this issue?”

There are no wrong questions here. Some questions may ultimately lead to irrelevant information, but the process of asking these questions helps train your mind to ask better questions in the future.

It’s also possible that your observations lead you to areas where you don’t have the required domain knowledge to even know what questions to ask. In situations like this, you should talk to other developers and ask “what questions should I be asking?”. Try to not ask for the answer, but instead ask for the question. Getting an answer gives you a single point of reference. But getting a question gives you a trajectory for future learning.

Hypothesize

Once you’ve formed a question, next comes a very fun part: you get to make up an answer! The answer you invent can be anything, as long as it is testable. For example, you could hypothesize that the reason your app crashes is because the Moon was exactly at its orbital apogee. This is unlikely to be the root cause of your app’s crash (unless you’re writing an astronomy app?), but the point is that your hypothesis can be entirely made up.

Over time, experience will teach you to recognize patterns. For example, experienced Objective-C developers have long recognized that an EXC_BAD_ACCESS crash is likely an error related to memory management. Swift developers know what a crash due to force-unwrapping nil looks like. The more practice you get at debugging, the easier and quicker this process will become.

Test

After you’ve formed a hypothesis, now you get to perform an experiment. In order to analyze the hypothesis, you need to devise a way to either prove or disprove your theory. Sometimes, this is really trivial: run your app again, set a breakpoint, and check to see if your variable is nil when you try to unwrap it.

Sometimes the process is a lot more complex. This is where the developer tools can be invaluable.

At the most fundamental level, we have the ability to print messages to the console. This is often referred to as “caveman debugging“, because it’s using the simplest and most fundamental tools. Sometimes this is good enough. But print() and NSLog() can be tedious tools to work with.

Fortunately, Xcode provides some really useful debugging tools beyond print() and NSLog(), like breakpoints and watchpoints. The debug gauges in the Debug Navigator can help you observe the state of your app. If you see memory usage continuously increasing, then you have Observed Something and may need to consider Asking More Questions. You also have more advanced tools available, like the LLDB console, everything in Instruments, and even hyper-specialized tools like dtrace.

These tools help you analyze the results of your experiment. The experiment you construct should ideal follow proper procedures and allow you to test your variables in isolation, as well as having a control.

Ideally, these experiments and analytic tools help you prove your hypothesis correct. If they do, then it’s time to start figuring out how to solve the problem. Often, testing proves our hypothesis false. We prove that what we thought was the issue wasn’t actually the problem. When this happens, we go back to step one: we’re still observing the problem, which means we need to ask new questions, form new hypotheses, and devise new tests to examine the theories.

And of course, these tests you devise should ideally be captured in the unit tests of your app, to help you guarantee that the problem doesn’t resurface in the future as other code changes!

Parting Thoughts

This pattern of Observe-Question-Hypothesize-Test is extremely powerful. It doesn’t always work for every kind of problem (such as problems that are inherently not reproducible), but when it’s applicable it is an excellent way to organize your thoughts and know that you’re on the right path towards solving your app’s problems and becoming a better and wiser developer.

So the next time you’re stuck on a bug and don’t know how to proceed, consider applying the scientific method.

My Rating System

Recently I’ve posted a couple of tweets rating some movies I’ve seen, and I almost always get asked about my rating system, because it’s a little unusual.

I rate things out of seven stars. This is something I learned from my dad, and while it sounds weird at first, it actually makes a whole lot of sense.

We’re all fairly used to a five-star rating system, but it ends up not being quite specific enough. For example, 3/5 stars would be an average rating (because 3 is in the middle of the 1-5 range). 5/5, being 100%, is “perfect”. But that means there’s only one gradation left between the two to express the concept of something that’s “better than average” but not “perfect”: 4/5. That’s not enough.

Thus, the 7-star scale.

With a 7-star scale, you still have a definitive middle value (4/7), but you have three values on each side of the middle to express the “low”, “medium”, and “high” values of positive and negative.

Observe:

★☆☆☆☆☆☆ – downright terrible
★★☆☆☆☆☆ – really bad
★★★☆☆☆☆ – bad
★★★★☆☆☆ – average
★★★★★☆☆ – good
★★★★★★☆ – great
★★★★★★★ – truly excellent

(I suppose there is, in theory, a 0/7 rating, but I’ve yet to come across something so bad that I would rate it that low. And no, I don’t want suggestions on what that might be. I also can’t think of many 7/7 movies I’ve seen. Wonder Woman might be close, though.)

When I talk about movies with my friends, we agree that this sort of granularity is nice. For example, in my tweets above, I can clearly indicate that The Foreigner was (in my opinion) a better movie than Blade Runner: 2049, but they were both still good, while not being on-par with Thor: Ragnarok.

This then leads to the next question: why not a 9-star scale? It has the same benefit of a definitive middle value (5/9), but you start then getting in to the existential questions of “how is 6/9 different from 7/9, or 7/9 from 8/9?”. The nice thing about the 7-star scale is you have the “Low-Medium-High” range for all parts of the scale.

So, that’s why I use a 7-star scale. And that’s also probably a whole lot more than you ever really wanted to know.

A Better MVC, Part 4: Future Directions

Part 4 in a series on “fixing” Model-View-Controller:

  1. The Problems
  2. Fixing Encapsulation
  3. Fixing Massive View Controller
  4. Future Directions

There are other ways you can apply these principles to writing more maintainable apps.

View Controller-based Cells

One that I’m really interested in and am actively researching is how to use view controllers as cell content.

Cells can be really complicated things, architecturally. If you have any sort of dynamic content in a cell, you’re often faced with weird situations where you wonder “where does this logic belong?”. Do you put image loading in your view subclass? Allow your cell to handle complex business logic? Tack on additions to the list’s delegate protocol so you can message things back out (which then just complicates your list view controller)?

Using view controllers as cells helps answer these questions. It is natural to place this sort of code in the view’s controller, and the fact that the view happens to be a cell doesn’t really make a difference to the underlying principle.

Small finite lists

It’s really easy to make a view controller a cell when you have a list of a finite size. You have your “ListViewController”, and you give it an array of view controllers. It adds them as children, and then pulls out the appropriate one when its time to show a cell, and sticks the view controller’s view inside the cell’s contentView.

You can then apply the same principles of “flow view controllers” and “mini view controllers” to the content of the cell, and use child view controllers to manage portions or variations of the cell. I used to write a Mac app where I used this approach, and I could sometimes get upwards of 15 view controllers in a single cell. Granted, the cells were pretty complicated in what they could do, but none of these view controllers was longer than 100 lines of code. It made debugging issues trivially easy.

At this level of granularity in a finite list, you also probably aren’t very worried about view lifecycle callbacks, because you can pre-allocate everything.

Huge finite lists

Once you start moving past the point where you can pre-allocate everything, you have two main approaches you can take. The first approach (“huge finite lists”) is like what the current UITableView and UICollectionView API offer: you know up-front how many items are in a section. In this case, your ListViewController would likely have a similar looking datasource API as UITableView, where it progressively asks for view controllers and then uses the underlying “willBeginDisplayingCell:” etc callbacks to notify on lifecycle.

At this level you might also want to start thinking about view controller reuse, but I would probably avoid thinking about that unless I measured and determined that view controller deallocation and initialization was a measurable bottleneck.

Infinite lists

Then there’s the problem of infinity. A great example of this is the main screen of the Reddit app. You can scroll forever, and the content will just keep loading and loading… there’s no way to know up-front how much content there is. With this, you’ll be looking at loading in “slices” of the infinite view controller sequence, or taking a page (haha) out of UIPageViewController‘s book and using the “doubly-linked list” sort of API (“what’s the view controller after A? What’s the view controller after B? etc).

You’ll still have the underlying callbacks to help manage view lifecycle, and you’ll also still have to consider view controller reuse as an option.

Boilerplate

As you get in to this style of programming, you’ll find that you end up developing a decent amount of boilerplate around embedding view controllers. That is to be expected, because the view controller containment APIs tend to offer the bare minimum to do what you need.

As you find situations where the API can be improved, please request that these improvements be made in the system frameworks.

Conclusion

There’s a lot to digest in these posts. Some people may scream in horror at the idea of “view controllers as cells”, but it’s an idea worth exploring.

So, the huge TL;DR of this is:

  • Decompose your UI using view controllers
  • Use view controllers to manage sequence
  • View controllers don’t have to fill the screen

I’d love to hear your thoughts on this topic. Hit me up on twitter or via email and let’s chat!

A Better MVC, Part 3: Fixing Massive View Controller

Part 3 in a series on “fixing” Model-View-Controller:

  1. The Problems
  2. Fixing Encapsulation
  3. Fixing Massive View Controller
  4. Future Directions

The principle behind fixing Massive View Controller is to unlearn a concept that’s inadvertently drilled in to new developers’ heads:

1 View Controller ≠ 1 screen of content

From our very first iOS apps, we’re taught the idea that 1 view controller == 1 screen of content. We see this in every simple “make a list and push a detail view” app. However, as our apps grow in complexity, so do our screens of content, and the default notion that 1 view controller == 1 screen of content quickly leads to Massive View Controller.

We can save ourselves from Massive View Controller by realizing that a view controller “controls a view” and that view doesn’t have to fill the screen.

Example: The WWDC App

Disclaimer: While I used to be the lead engineer on the WWDC app, I have not seen the code in quite some time and do not know if it is actually implemented this way. I am simply describing how I would build the screen if I were to build it today.

Here’s a screenshot of the WWDC app:

WWDC app session details page

On this one screen, there are five main pieces of content:

  1. The video
  2. The title
  3. The description
  4. The contextual actions
  5. The related content

There is a lot going on here, and if this were to be implemented as a single view controller, it would be a massive view controller.

So, let’s not do that.

Instead, we’re going to make each one of those 5 areas its own view controller, all contained within the SessionDetailsViewController. The outer details view controller will own the general layout of the screen, as represented by some empty container views. These will all be in a UIScrollView that manages its content bounds through auto layout.

The SessionVideoViewController would be in charge of loading up the appropriate poster frame for the video and responding to the user tapping the play button. When the user taps that button, the view controller will delegate out that the user intends to watch the video. The parent SessionDetailsViewController can then pass that intention up the chain until it arrives at a semantically appropriate level for that intention to be translated in to the corresponding WatchVideoOperation.

The SessionTitleViewController and SessionDescriptionViewController will be pretty simple, since all they’ll have to do is observe the model object for changes and update the labels. There’s also no interaction to delegate back out.

The SessionActionsViewController would basically be a UIStackView of buttons. The buttons would be created based on inspecting the model object, and interacting with the buttons delegates back out the corresponding intention: “toggle favorite”; “leave feedback”; “begin download”; etc.

Finally, the RelatedSessionsViewController would be a side-scrolling collection view. Tapping on a related session would delegate back out that the user wants to view the session. The SessionDetailsViewController, as we learned in the previous post, would not be the one to perform that action, but would instead relay the intention up to a more semantically appropriate level (such as the view controller that owns the UINavigationController).

At the end of this exercise, we end up with more view controllers (six instead of one), but each one is relatively small. The video view controller loads a poster frame. The title and description view controllers observe the model for changes. The actions and related content view controllers are a little more complex, but each one is focused on a very specific set of actions, and neither is onerous to understand.

Example: The Reddit App

Disclaimer: I have no idea how the Reddit app is built.

For this example, let’s take a look at the Reddit app.

The Reddit app

There are a bunch of interesting things going on here, but I want to focus on the top part of this post screen that contains the actual post. A cursory survey through the app shows that there are several different styles that this post content can take, in addition to having a title:

  • Text
  • Link
  • Animated gif
  • Static image
  • Video

It would be crazy to try and build the entire post page as a single view controller. At the very least, you’d want a “post content” view controller, and a “comments” view controller. But you can go further.

Imagine that the top post content is a PostContentViewController. You still have a large view controller as you have to handle one of these 5 different kinds of post content (showing all text vs loading a web preview vs animating a gif vs showing an image vs an inline video vs a link to an external video…).

So instead, make your PostContentViewController a “flow” view controller, and then have a different view controller for each kind of content. When you have a TextPostContentViewController, you never have to worry about dealing with loading callbacks. A LinkPostContentViewController only has to deal with loading a preview. A GIFPostViewController only ever has to load a gif. It’s easy, and you PostContentViewController just has to pick the right one, embed it, and then handle the odd delegation of user intent.

By combining both principles (view controllers as flow and small view controllers), you can easily decompose your UI in to small, manageable, testable, isolated, and grokkable chunks.

A Better MVC, Part 2: Fixing Encapsulation

Part 2 in a series on “fixing” Model-View-Controller:

  1. The Problems
  2. Fixing Encapsulation
  3. Fixing Massive View Controller
  4. Future Directions

In order to fix the encapsulation violation we saw earlier, we need to understand a pretty simple principle:

In general, a view controller should manage either sequence or UI, but not both.

A view controller that manages sequence is one that I jokingly call a “Manager View Controllers” because 1) “manager” and “controller” aren’t overloaded enough already and 2) it still has the acronym “MVC”. In reality, this is a variation on the “Coordinator” pattern that has captured some of our imagination.

The idea behind the Coordinator pattern (or flow controllers or whatever you call them) is that, in order to maintain encapsulation, you need a higher-level object to decide what comes next. It “controls the flow” in your app.

Where I tend to diverge from the “traditional” flow controller implementation is that I believe that these sorts of controllers should really just be view controllers higher up in the parent view controller chain. This saves you from having to hack a new kind of responder chain object in to UIViewController, and it means you don’t end up with a third parallel hierarchy of control to maintain in sync with the other two (the View hierarchy and the view controller hierarchy).

Using container view controllers as sequence “coordinators” makes a whole lot of things really easy. For example, consider a screen where you want to load a piece of remote content. But while it’s loading, you want a spinner to show up. If the content fails to load, you want an error screen and a “try again” button.

Implementing this as a single view controller would leave you in a place where you’re on the road to Massive View Controller. You’d have a view controller that’s probably hitting the network and then trying to rationalize which of the three different states it should be in (Error, Loading, or Success), then is responsible for making sure the right set of UI elements are visible and getting the model information into the proper set of out outlets.

Instead, abstract out the sequence from the UI. The sequence is the owner of the flow between the three states, and each of the states is its own view controller.

The ShowRemoteContentViewController (the owner of the sequence) has an empty view, and it embeds the proper content view controller depending on which state it should be in:

  • Show the ErrorViewController if your networking object reported back an error. The ErrorViewController delegates back out when the user taps on a “Try Again” button, which causes the delegate (the ShowRemoteViewController) to transition to the loading state while hitting the network
  • The LoadingViewController is an empty view controller that shows a loading indicator. It is literally zero lines of code, unless you want a simple init() method, in which case it is 4.
  • The MessageViewController is the view controller that handles the “success” state. It basically populates its UI from the injected model object, and delegates back out when the user taps a “Load Another” button.

A simple iOS project (Xcode 9.1, Swift 4) showing this in action is available here: iOS Architectures.zip.

We’ve taken something that was really complicated (a single object managing UI and state and flow) and turned it in to something eminently understandable; no view controller is longer than 100 lines of code long. Each one is isolated from everything else. A good use of delegation means that testing is trivial: we load up the UI, fake a tap on the button, and assert that the delegate method is invoked. There’s almost no cognitive load to understand any individual view controller. Even the “more complicated” ShowRemoteContentViewController is simple, because it’s just flipping back and forth between a couple of different child view controllers in reaction to some delegate method invocations or the network loading. It’s all really simple, and there are no violations of encapsulation.

The same pattern holds true when you’re dealing with more structured UI. If we imagine now a list UI, where tapping a list item brings up a detail view, we can apply this same principle.

First off, we don’t want the list knowing about the detail view controller or how to show it. So, we simply make it delegate back out to someone else what the user is intending to do. The list UI receives model objects from “the outside”, so that’s what it should send back. Therefore, in our implementation of didSelectRowAtIndexPath:, we simply translate the index path in to the corresponding model object, and then message the delegate what the user intention was: listViewController:userDidSelectModelObject: → “The user wants to look at this model object”.

So, who then is the delegate? You could argue that it might be the direct parentViewController, but in this case, the parent is likely a UINavigationController. The UINavigationController is already in charge of maintaining a stack of view controllers with its own UI (the navigation bar), so this doesn’t seem like a good candidate. Instead, let’s put the UINavigationController inside a container view controller, which we’ll call the ListFlowViewController.

The ListFlowViewController creates and embeds the plain UINavigationController in itself and gives it the root screen (the list view controller). Then, it makes itself the delegate of the list, because it’s the ListFlowViewController that created the list and (likely) knows what the model objects mean. Then when the user selects an item in the list, the ListFlowViewController receives the corresponding model object, knows how to turn it into the detail screen, and gives that screen to the UINavigationController to push. We again preserve proper encapsulation principles.

This same pattern also holds true on iPad (or regular width phones) where you deal with UISplitViewController. Having a container view controller own the split view means you have a natural place for the “master” view controller to message about the user intent, and handle how to appropriate display the detail view controller. This same container view controller could also decide to entirely eschew a split view controller if the app transitions back to a compact width size class.

The huge advantage of this approach is that system features come free. Trait collection propagation is free. View lifecycle callbacks are free. Safe area layout margins are generally free. The responder chain and preferred UI state callbacks are free. And future additions to UIViewController are also free.

In exchange, you have to suffer through cleaner code, smaller view controllers, and a few more delegate protocols, which unfortunately just make your code more isolated and testable. How on earth will you survive?? 🙃

A Better MVC, Part 1: The Problems

Part 1 in a series on “fixing” Model-View-Controller:

  1. The Problems
  2. Fixing Encapsulation
  3. Fixing Massive View Controller
  4. Future Directions

I recently ran across a great article by @radiantav called “Much ado about iOS architecture“. It addresses a topic that has been on my mind a lot. I gave a talk about it at the recent Swift by Northwest called “A Better MVC”. These blog posts attempt to capture the main points of my talk.

I apologize beforehand that there aren’t really any pictures in this. They’d definitely make the subject matter clearer, but I don’t feel like spending the time to make them. You’ll just have to use your imagination.

The “Problems” with MVC

The main reason that people decry MVC is that they tend to run afoul of two major problems when using it:

  1. MVC, as taught by Apple sample code, encourages you to violate encapsulation principles, which ends up leading to spaghetti code.
  2. Without proper discipline, your view controllers end up being huge, leading to the joke that “MVC” means “Massive View Controller”.

Violating Encapsulation

It’s pretty common to come across a UITableViewDelegate method that looks something like this:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let maybeItem = query?.object(at: indexPath)
    guard let item = maybeItem else { return }
    let detail = MyCustomDetailViewController(item: item)
    show(detail, sender: self)
}

There are two huge encapsulation violations that are occurring here.

The first is this line:

let detail = MyCustomDetailViewController(item: item)

The principles of encapsulation indicate that a thing should only really “know” about objects that it contains, and then only about one layer of abstraction down. However, this line, which constructs a subsequent screen-full of information, requires the view controller to know about the sequence of data flow in its parent abstraction.

In other words, this list isn’t just a list, but must also being aware of the context in how it’s used.

The second violation is similar to the first:

show(detail, sender: self)

Again, this violates the whole “don’t know your context” principle. And, it should be noted, these critiques hold true whether you’re manually creating and showing a detail view controller, or invoking a segue and using prepareForSegue:sender:.

Massive View Controller

It is sadly pretty common to come across a view controller that is thousands of lines long. Our view controllers quickly become cluttered with networking callbacks, delegate methods, data source methods, IBActions, trait collection reactions, model observation, and of course, our business logic. Heaven forbid if you’re doing any sort of progressive loading and want to swap in an indicator to show while things are loading… that will usually add in a couple hundred lines of code as you deal with swapping views around, managing yet another stateful property, and so on.

We end up with this situation because we don’t apply enough discipline to our view controllers. They’re convenient places to dump code. But they quickly become unmaintainable, fragile, and inherently untestable. Who wants to be the poor soul who has to debug some weird state going wrong in a 5,000+ line file?

Working around MVC

In my experience, these are pretty much the two fundamental reasons why developers find other architectural patterns so appealing. As a result, we turn to other architectural patterns to try and compensate. We reach for MVVM, or React, or MVP, or FRP, or VIPER, or insert-new-architecture-here.

To be clear, there is nothing inherently wrong with any of these patterns. They all solve problems in unique and interesting ways, and it is good to study them and learn the principles they teach. However, I’ve found that building apps based on these patterns tends to pay negative dividends in the long run.

All of these patterns tend to be “strangers” to UIKit and AppKit. Because of this difference, you end up with additional hurdles to clear when things change.

When your team members change, you have additional work to teach new developers about not just the business logic of your app, but often a whole new architectural pattern. This requires more up-front investment, and a longer lead time before team members can start being productive.

When the operating system changes, you have additional work to try and shoehorn new features in to architecturally-native concepts. You have to plumb through size classes, safe layout margins, dynamic type, localization, locale changes, preferred attributes (status bar style, etc), lifecycle events, state preservation and restoration, and who knows what else when new paradigms get inevitably added as iOS updates each year.

When your requirements change, you can sometimes be caught in the situation of having to fork someone else’s library, wait for them to catch up, or hope that they’ll accept your pull request. I won’t go in to the pros and cons of third-party dependencies here, but an architectural dependency has even more “gotchas” than a normal dependency, because of the way it can underpin your entire app.

Each step of the way, you may be celebrating that your code is clean and concise. However, you drift further and further away from what the system frameworks are providing, which means adopting new systems features requires more code to bring it to where you are.

Wouldn’t it be nice if you could just get it for free? Wouldn’t it be awesome if you could just use UIKit and AppKit and have it all “just work”? Wouldn’t it be nice to live in a world where you thought 300 lines in a view controller was excessively long?

In the next post, we’ll look at how we can fix the first problem.

Keynote’s awesome Outline Mode

So, I love Keynote.app. It’s one of my all-time favorite apps. During my time at Apple, I got to use the app a lot and was constantly amazed by how powerful and capable it is. I grew very used to its precision and elegance, and its overall ease-of-use.

One of the really cool tricks I learned about Keynote was to quickly build slides using Outline Mode, like so:

Keynote Outline Mode

Outline mode is a powerful way to build slides, because it allows you to focus on the structure and flow of your content, without getting distracted too much by the visual aspect. In the early phases of building a deck, this is really important.

However… the visual aspect is still there. There are these huge slides sitting right next to your outline and you cannot make them go away. It is really easy to get distracted from what you’re doing and start focusing on text alignment, font sizes, animations, slide styles, and so on.

This morning I had the idea of “well, what about other outline modes, like the one in Pages?”. So I popped open Pages and started writing an outline and copied it to my pasteboard:

Building an outline in Pages

With this outline in hand (er, on my pasteboard), I headed back to Keynote and tried pasting it into the Outline view:

Paste an outline in to Keynote

A couple clicks to make sure the slides had the proper style (by reapplying the master style to the slides), and I had generated an entire presentation in a matter of seconds. At this point, with an outline built, I can easily create my Keynote presentation and start polishing it and adding in all the visual fanciness.

If you build presentations but get distracted by the slides, this could make your life a whole lot easier.

iOS Feature Wish: Contact Provider Extensions

For a while now, there’s been a major feature of iOS Contacts that I’ve felt has been sorely lacking, and that’s the ability for third-parties to provide their own contact card data. Here’s what I mean…

We live in a world where we have a whole bunch of different social circles that we run in, and it seems like almost every circle has a different way of keeping track of how to communicate with those people. I’ve got Twitter, LinkedIn, Snapchat, and Facebook. I’ve got a company directory, my nextdoor.com account, and even an app for congregants of a nearby church.

None of these people show up in Contacts.app, and that really bothers me.

Sometimes I want to call someone, but I can’t just go to the phone app and start typing their name. I have to remember how I know them, go to the relevant social networking app, hope my credentials are still valid, find their info, and hope there’s a phone number in there.

Sometimes I want to text or email someone, but I can’t just go to Messages or Mail and start typing their name. I have to remember how I know them, go to the relevant social networking app, hope my credentials are still valid, find their info, and hope there’s a phone number or email address in there.

I really wish iOS offered a way for these apps (Facebook, Next Door, Twitter, LinkedIn, etc) to “donate” their contact information to the system database in a non-permanent way. (By “non-permanent” I mean “don’t just dump it in to my iCloud contacts and call it good”; deleting the app would cause that info to disappear, and the app could update it on-demand) There would need to be some pretty intelligent merging that happens, but generally it’s pretty safe to assume that an individual with a certain phone number and email address is probably the same individual as another with the same phone number and email address. You’d also have to consider how to handle apps that provide unboundedly-large data sets (like the corporate directory for a 50,000+ employee company). But, these are solvable problems.

Functionality like this would also enable what I consider to be the “holy grail” of contact services: a service where I can expose a certain subset of my contact information to specific groups of people. Facebook kind of lets you do this with your profile, but also carries a whole lot of extra baggage that a lot of people find undesirable.

In my opinion, the days of manually filling out and sharing vCards belong firmly in the past, yet that is just about the “state of the art” today. We have the technology to make far superior services, but just need a way to integrate that with the standard iOS (and macOS) experience.

Disclaimer

Despite my recently-ended employment at Apple, I have zero idea of whether they have any plans to do this.

Also, I did file a bug report about this, but I do not have the bug number anymore. Please file your own copy! 🙏
Update: it’s been verified that my original bug report about this is rdar://17750541. Go forth and dupe!

Every beginning has an end

It seems like it was only the other day when I wrote the post about leaving the Evangelism team.

But, a lot has happened in the two years since then. We bought a piece of land and built a house. The kids are both in school full-time. My wife has a job that she loves.

Working from home has enabled some hugely significant changes in our lives. It vastly simplified the process of my wife getting a job. We don’t have to wonder about after-school care for our kids. My relationship with my kids has drastically changed, too. I’m no longer the guy they see for an hour or two in the morning and an hour or two in the evening. Our family life has become radically different from how it used to be, and all for the better.

However, working from home has also had its costs. For one, Apple is not really built to accommodate employees who work from home; there’s understandably a huge amount of inertia around the “everyone in the same office” mentality. A few teams are experimenting with trying to change this, but this kind of progress takes time.

Additionally, there are other costs that come with working at Apple. I can’t put my own apps on the store. I can’t speak at conferences. I can’t be an involved, vocal member of the open source developer community. I can’t do my own stuff on the side. When you’re working in Cupertino, these restrictions aren’t so bad. When you work from home, they chafe.

So, after seven years working at the mothership, I’ve decided that it’s time for me to move on. My last day is the 16th. I’ll take a very short break, and then start a new job at Snapchat on the 23rd. They’re opening a new R&D office a couple miles down the road from me, and I’m excited to help get it off the ground.

I’m also really excited to openly participate in the dev community again. I’ve got some Swift-Evolution ideas I want to propose, and I’m also thrilled to be speaking at the Swift by Northwest conference in Seattle at the end of the month.

It’s been the experience of a lifetime working for Apple. I’ve been able to be a part of something that I barely dared to dream of as a kid and a teenager, and it’s not anything I’ll ever forget.