Advanced Debugging with XCode and LLDB, Part 2

Reading Time: 9 minutes

A WWDC talk about debugging in XCode made me rethink some things, so I decided to write about it in three parts:

  1. An outline of the techniques demonstrated in the talk
  2. How the talk challenged my views both on XCode and on learning a new stack (this post)
  3. Additional XCode debugging features not covered in the talk

Thank you to the talk hosts, Chris Miles and Sebastian Fischer, for unwittingly enabling this tangent 😃.

Here‘s where Apple keeps the video of the talk:

apple ios debugging talk
https://developer.apple.com/videos/play/wwdc2018/412/

At that link, you can also:

  • Get a transcript of the talk
  • Download an HD version of the video (the low-resolution version embedded on the site itself makes it hard to read the text in the IDE)
  • The slides (They don’t use these in the presentation, opting instead for live demos, which I think is more clear. But, if you like, the slides are there).

The Role of a Developer’s Tools

I used a bunch of bare bones text editors during my programming education, but my first professional role demanded IntelliJ, and I have used JetBrains products ever since. There is one exception, of course, because iOS development demands XCode. Only XCode generates the inconsistently attribute-laden XML that translates to the screens on an iOS device.

I have always felt artificially limited in XCode. My key bindings for JetBrains help me change my editor settings, rename a class with a couple of keystrokes, perform systemic refactors, and even offer intentions of what I might do next. By comparison, XCode’s key bindings let me get to menus…and that’s about it. Renaming something in XCode requires right clicking, navigating to a sub-menu called “Refactor”, choosing a sub-heading called “Rename”, and then…waiting…for several seconds…while the editor mounts up a pointless (and evidently computationally expensive) animation that accordion-collapses all the code between the references to the name in question.

Truth be told, I assumed that Apple had decided not to prioritize XCode. Like a gourmet chef with a mess for a home kitchen, I assumed that iOS engineers found themselves allocated to the more public-facing aspects of the brand—like the iOS Framework, or standard iOS apps, or Swift—and had no extra time or energy for developer tools.

Before seeing this talk, I did not realize the extent of the debugging tools available in XCode. It’s clear to me now that Apple does allocate time for XCode development. The difference is that I had inherited the priorities of the JetBrains team, while the XCode team set a different slate of priorities.

Vim and Emacs are both perfectly fine editors. Use whatever editor works for you!
This image isn’t related to XCode or JetBrains, but I think about it whenever people get into editor arguments. You can purchase a tee shirt with this image: https://borjasotomayor.threadless.com/designs/vi-emacs

First Priority Difference: Refactoring

Key bindings and slick refactors in XCode are, flatly, not there. But Apple engineers are in a unique position with XCode: they’re designing an editor for a relatively rigid, convention-driven framework that makes heavy use of inheritance. For this reason, there are only so many ways you can architect an iOS app without going out of your way. This means there are certain things you sort of can’t refactor, even if you wanted to. So I get why refactoring tools would not capture the attention of Apple the way they would a team that builds editors used on more flexible frameworks.

(I maintain, however, that renaming is important, and that XCode could do with a key binding for this—and also, please just make it fast, I don’t need the animation).

Second Priority Difference: Debugging

It is here that XCode shines. Mind you, JetBrains suffices for this. It has breakpoints. It drops you into editors where you can print things out at breakpoints. You can enable and disable breakpoints, and you can see a map of all your breakpoints.

But you cannot customize breakpoints in a JetBrains editor the way you can in XCode. You cannot set conditional breakpoints, or indicate whether the code should automatically continue. You cannot ask a breakpoint to insert, remove, or change lines of code in JetBrains. You cannot set a watch point or create aliases for debugging commands.

XCode’s breakpoint features changed the way I write code in iOS. I used to ascertain what the problem might be, change some code in XCode, then rerun the app on the simulator—lamenting how long I’d have to wait for it to boot—try it out, rinse, repeat. The breakpoint tools allow me to test out changes to the code without having to rerun the app at all. I’m not sure whether that’s by design, or if the team built such fully-featured debugging tools as a workaround for long simulator boot times, but the end result allows me to maintain the tight feedback loop that I’m used to on other frameworks. This is really important to me.

Additionally, XCode’s visualization tools blow JetBrains editors out of the water. We saw “Debug View Hierarchy” in the first post of this series—I’m not aware of another tool that does that. In the next post in this series, we’ll also see how XCode shows me a memory graph of my application. This is extremely useful for tracking where my objects get created. It also happens to be useful for teaching, because it directly demonstrates view recycling for students to see. By contrast, the JetBrains editors allowed one to print a crude object graph circa 2013, if I understand correctly. That feature no longer ships with the editor.

Editor Impact on Learning a Stack

The JetBrains team and the XCode team each set priorities for their editors that reflect the technical specifications of how developers use those editors. But there is a particular mode of programming to which I believe each editor loans itself.

I think it behooves a programmer to have two modes of working. The first one is most programmers’ default: I call it progress mode. This mode allows us to move fast when we understand the code we’re working on and wish to push forward with new functionality or large refactors. This is the mode demonstrated in most programming tutorials, and it’s the one celebrated by product owners and people who write listicles about “What makes a 10x Developer.” It has a problem, though: it breaks down the moment we don’t understand the code we’re working on because we end up in vicious cycles like this one:

Debugging, Retrying things that don't work
Bigger version of image here

This is where we need the second mode: investigation mode. In this mode, we are no longer focused on pushing changes. Instead, we focus on narrowing down the problem space by testing our assumptions. “Success,” in investigation mode, is not an incrementally broader feature set. Instead, it is an incrementally tighter feedback loop in which we can experiment with the thing we don’t understand in order to gain an understanding. The gold standard here is often a failing test that replicates a problem. Any tactic with a feedback loop under 10 seconds works for me.

We are reluctant to shift into investigation mode because, unlike progress mode, it doesn’t feel fast. Nevertheless, when we’re dealing with unknowns, a precise investigation often helps us resolve issues in less time (and with much less effort) than a brute-force approach in progress mode.

As you might have guessed by now, I love JetBrains editors for progress mode. For investigation mode, though, I’m most impressed with XCode. This has some implications for learning a stack, because our mode breakdown changes as our familiarity with a stack changes.

That is, when we first learn a stack, there are a lot of unknowns. So it would make sense for us to default to investigation mode here, shifting slowly toward progress mode as we develop more intuition about the stack and start to make accurate assumptions often enough to shift our thinking from tiny “what does this line do?” increments to larger, feature-size increments.

Nowadays, when I’m learning a new stack or picking up a stack that I haven’t tried for a while, I find myself taking more care to educate myself about the debugging options and other investigation tools available to me through the framework or the editor.

When I know the investigation tools at my disposal and how to use them, I have an easier time shifting into, and staying in, investigation mode. Though it feels slower than progress mode, investigation mode accelerates my skills on a given stack faster than raw progress does.

The Upshot: Considering Editors (and any software decision) in Context

Will we ever see the fully loaded key binding set in XCode? I don’t know. Will JetBrains decide to upgrade the debugging tools? I also don’t know. But I’ve learned a lot from moving past “this is good” or “this is bad” to thinking about why a given set of software decisions might have been made, and under what circumstances that set of decisions might make the most sense, or the least sense. I hope this piece has provided a demonstration of that.

In the next post of the series, we’ll refocus on XCode and take a look at some investigative features that the aforementioned talk doesn’t cover.

If you liked this piece, you might also like:

The Leveling Up Series (a perpetual favorite for gearheads like yourself)

The Books Category, to which I’m slowly adding all the blog posts where I reflected on a book

The History of API Design Series (prepare to have your sacred cows threatened)

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.