Developing Anxiety

May 23, 2016

After two and a half years of decline, including a couple of emergency room visits, I finally sought treatment for my anxiety this spring.

I know many software developers who stuggle with anxiety. Perhaps software development attracts anxious people. We can mediate social interactions through the safety of a chat window. We spend our days in abstactions, so we can control the virtual environment—the code—in which we work. That sense of control can be comforting.

Or maybe the act of software development promotes anxiety. Our daily lives are cycles of facing failures big and small: syntax errors, logic mistakes, crashers, threading bugs, and, god forbid, provisioning problems. When we do succeed at solving a problem, there’s always another one waiting in the issue tracker. And because all code has bugs, the sense of control that appealed to us initially gives way to shipping software we know isn’t as good as it could be.

* * *

My struggle started in the fall of 2013. That summer we lost a friend and co-worker at Omni, Joel Reuter, to his battle with mental illness. The development team also worked multiple weeks without a day off through August and into September as we fought to update all our apps for Apple’s radically redesigned iOS 7.

That Labor Day weekend I had my first panic attack at the office, leading to my first ER visit. After blood tests, a chest x-ray, and lots of questions, the doctor told me to see my primary care doctor about acid reflux and sent me home. Instead of calling my doctor, I went back to the office the next day. We had apps to ship.

After shipping, we revisited work-life balance issues at Omni and haven’t pushed quite that hard since, but my anxiety issues continued. Another panic attack sent me back to the ER in November. It was the same routine, but I followed up this time, getting treatment for acid reflux. I also told my primary care doc about my anxiety. He prescribed Ativan to take the edge off and help me sleep and left it at that.

Ativan has a high addiction risk, so I was afraid to take it unless I was in really bad shape. It also made me drowzy enough that taking it at work wasn’t an option.

The panic attacks continued to get worse. Every month or so, I’d freeze trying to solve programming problems at work. Anxious thoughts would fill my head, taking up the headspace needed for programming. These thoughts tend to build on themselves. “I’m stuck on this problem. … What if I can’t solve this problem at all? … What if we fail to ship because of me? … What if I’m losing the ability to program altogether?” These spirals would spin into full-blown panic attacks.

Panic attacks lead to heart palpitations, dizziness, and shortness of breath. However, the worst part is the inner dialog that insists that you’re having a heart attack or losing your mind. After losing Joel, the latter thought was particularly terrifying. If you haven’t experienced a panic attack, it can be easy to think, “Just suck it up. You know there’s nothing to be afraid of.” You might as well tell someone five drinks into their bottle of scotch, “Just suck it up. You’re not really drunk.”

In December of last year, I had my first attack in a social situation. I’d spent the week sleeping too little preparing my Xcoders talk on OAAppearance. The talk had gone well. After the exposure of teaching for six years, public speaking doesn’t provoke my anxiety. While socializing after the talk, the boozy milkshake and fries triggered a serious bout of heartburn. That spun into a bad enough panic attack that I passed out. My friends were very supportive and saw that I got home safely. Unwilling to admit to the problem, I told them that it was exhaustion or a bad cold.

In February, I lost consciousness again during an attack. This time I was at home and the attack spun out of control so fast that I didn’t have time to react. I went from the bedroom to the kitchen to find an Ativan. Before I reached the cupboard, I went from standing to prone, bouncing my head off the floor on the way down. This episode, and my wife’s reaction to it, was enough to finally prompt me to seek help.

I found a new primary care doctor and scheduled an appointment to talk specifically about anxiety and panic attacks. Unlike my previous doctor, my new doctor treated the problem seriously. A couple of stories that ended with me on the floor probably gave my symptoms a bit more punch, but I think largely it was a matter of finding a doctor who took mental health issues seriously.

Since then I’ve started taking Celexa, a selective serotonin reüptake inhibitor (SSRI). SSRIs are the most common class of anti-depressants. This might be a temporary thing while I get my head right again. Some people just need short-term treatment while they heal. It might also be a lifetime thing. We’ll reëvaluate in the fall and see how things are going.

I know some people fear that anti-depressants mask the real you. My experience has been one of uncovering the real me. Peeling away the anxiety has let me experience the contentment again that had been missing. I’m not wildly happy or giddy all the time. I’m just more able to appreciate the good people and things around me.

I’ve also been seeing a therapist. He’s helped me learn some techniques for coping with anxiety and for diverting or riding out panic attacks. We’ve also talked through past episodes, a process called exposure therapy, which has been helpful in reducing meta-anxiety—anxiety about anxiety.

Finally, I’ve been practicing mindfulness meditation. I’m at 68 days in a row. It’s not easy to sit still—I don’t idle well—but there’s a reason it’s called a meditation practice. I’ve gotten better at it. The Headspace iPhone app has been great for this.

It’s been three months since I’ve had a panic attack, and several weeks since I’ve had any anxiety at all beyond the normal everyday worries of life. I feel like I’ve turned a corner and wanted to share my story to remind others that they aren’t alone. Things can get better.

* * *

If you’re struggling with anxiety, there are many things you can do.

Self Care

Be careful with hydration and nutrition. As developers, we can often focus to a fault. If the kitchen staff at Omni didn’t announce when lunch was ready, I’d forget to eat. The Due app has been great to remind me to take a break and have a snack in the afternoon. I always have a glass of water on my desk.

Practice good sleep hygiene. The most important thing here, counterintuitively to me, is getting up at the same time everyday. No sleeping in on weekends. If you go to bed and can’t sleep, get up again. Train your brain that the bedroom is for sleeping. You might get less sleep initially, but the fifteen minute power nap is your friend.

Exercise. You don’t have to become a marathoner. Simply taking a brisk 20 minute walk everyday is enough. It’s also a great way to solve tricky programming problems. I’ve done some of my best coding walking around Green Lake.


Start a meditation practice. There is ample evidence that mindfulness boosts happiness and life satisfaction. As developers, we do our work in our minds. Meditation helps us leave that office inside our heads. Headspace has been super helpful for me, particularly the series on stress and on anxiety.

Professional Help

See if your employee benefits include an Employee Assistance Program. These programs often include initial mental health consultations at no cost without having to get a referal. Most programs include a contact phone number to seek help. Many also provide email or web contact options if you find the phone intimidating.

Find an understanding primary care doctor. If your anxiety is interfering with your work or your personal life, it’s serious enough that you should seek professional help. If your current doctor doesn’t take your concerns seriously, find one who will. Mental health is as important as physical health. They’re really all part of the same thing, your health.

If your doctor recommends medication, ask about side effects and follow up. A challenge with medication for mental illness is that individuals respond very differently to different drugs. You and your doctor may have to try a variety of things to find what works. Your doctor should be clear about this and willing to schedule appropriate follow-up visits to work through the options.

Seek therapy. The combination of medication and cognitive behavioral therapy is more effective than either alone. The allure of a cure-all pill is strong, maybe even stronger than the idea that we can go it alone. However, the hard work of talking through your issues with another human being, one with professional training and experience, can be key to developing effective coping strategies.


Anxiety seems to be common with software developers. Three articles helped spur me to write this post.

From Andy Culp:

Yesterday I was approached by a developer, apprentice, friend, and sometimes mentor, who was having some personal issues. … During the conversation it was revealed how they’re experiencing huge anxiety, complete with panic attacks, and are even consulting a physician who prescribed medication for it. As this person spoke I could see the anxiety levels grow within through their body language , and witnessed the “deer caught in headlights” look as they wrestled on the precipice of going into another panic attack. “Developer Anxiety, we’re not alone”, by Andy Culp

From Greg Hurrell:

I was aware of all of these [perfectionism, procastination, and paralysis], but it is only recently that I identified the root cause that lies at the heart of all of them. It is a very simple emotion: fear. All of these can be reduced to fear. Fear of failing in the eyes of others and of myself, fear of not being good enough, fear of saying something stupid, fear of building the wrong abstraction, fear of repeating a past mistake, fear of being misunderstood or misjudged, fear of treading on somebody’s toes… “Conquering my demons”, by Greg Hurrell

From Kent Beck, who is confronting my single greatest fear:

When I was about 10 I read Flowers for Algernon, the story of a mentally challenged man who is subjected to an IQ-increasing treatment that only works temporarily. The story is written as a diary, with spelling and vocabulary tracking his changing mental abilities. As a child, the story was exciting because I could see how much smarter I was going to be and I could see all the new ways I could think and the worlds that would open up.

When I re-read Flowers for Algernon recently I was just sad. The second half of the story, where his mind is going away, is brutal. He can remember how smart he was but knows it’s gone for good.

I’m living through something eerily similar. “Me an’ Algernon”, by Kent Beck

Finally, I owe a debt to my friend and co-worker Rachael for her openness about her own battle. That’s been instrumental in my journey. Thank you, Rachael.

Network Activity Indicator

May 22, 2016

Anthony Mattox nerd sniped me on Jonathan Wight’s Swift Slack the other day.

Does anyone have any suggestions for the best way to manage the system network activity indicator? In previous projects I’ve implemented a simple singleton class with ‘begin task’ and ‘end task’ functions which just modify an internal counter. This works fine, but it’s easy to make mistakes.

I put together a little manager class that includes the begin/end task methods, but it also uses weak references to make ending automatic. Besides being something you can drop into your own projects, it’s a nice example of using weak references in Swift.

The full source of the class, with comments, is available in this gist. I’ll walk through the pieces here.

The class is a singleton, and I don’t feel bad about that. There’s only one network activity indicator on your iPhone after all. We use a fairly standard Swiftism for vending the singleton instance:

public class NetworkIndicatorManager {
    public static var sharedManager = NetworkIndicatorManager()

Beyond getting the shared instance, there’s only one method that clients need to use, beganNetworkTask(withToken token: AnyObject). Before diving into the implementation, let’s look at how client code would use the API.

let task = NSBlockOperation() {
    /* do some network work here */
NetworkIndicatorManager.sharedManager.beganNetworkTask(withToken: task)

This code creates an NSOperation instance, task, to do some async work. It then gets the shared NetworkIndicatorManager and begins a network task passing the operation instance as the token. Then the code enqueues the task operation on a background queue and we’re done.

The queue will retain task until it finishes executing. The NetworkIndicatorManager just holds a weak reference to task. It notices when that weak reference becomes nil, and if no other network tasks are active, hides the indicator. We don’t have to remember to end the task. We just have to avoid leaking a reference to it, which we would need to do anyway. Easy peasy.

So how do we implement that? Let’s look at beganNetworkTask(withToken token: AnyObject) first:

    public func beganNetworkTask(withToken token: AnyObject) {
        let wrappedToken = WeakWrapper(wrapping: token)

    private var keepAliveTokens: [WeakWrapper<AnyObject>] = []

Notice that token has to be an object type so that we can store a weak reference to it. Then to store token in a Swift array, we need to wrap it in another class. Swift arrays can’t (yet?) hold weak references directly. After wrapping the token, we store it in the keepAliveTokens array. Then we call a helper method to update the activity indicator.

Before looking at that helper method, here’s WeakWrapper:

private class WeakWrapper<Wrapped: AnyObject> {
    weak var wrapped: Wrapped?

    /// Becomes true when `wrapped` is deallocated.
    var isCleared: Bool {
        return wrapped == nil

    init(wrapping: Wrapped) {
        self.wrapped = wrapping

This generic class stores a weak reference to a single object. Since it’s weak, the wrapped property has to have an optional type. Unlike many such properties, this one starts out with a value; the initializer has a non-optional argument. The property type has to be optional because it can become nil later, when all strong references to the wrapped object are released.

For convenience in implementing our updateIndicator() function, we give WeakWrapper a computed property, isCleared, that lets us check if the wrapped object has been deallocated.

Turning to updateIndicator() we’ll find the meat of the implementation:

    private func updateIndicator() {
        keepAliveTokens = keepAliveTokens.filter { wrappedToken in
        let shouldShowActivity = !keepAliveTokens.isEmpty
        UIApplication.sharedApplication().networkActivityIndicatorVisible = shouldShowActivity

First we filter the array of wrapped tokens to remove wrappers whose tokens have been cleared. There’s no mechanism in Swift (or Objective-C) to get a notification when the target of a weak reference goes away. The only way to check is to dereference and see if we get nil back. (See this excellent Mike Ash post for the gory details.) The isCleared computed property handles this check.

As this point, keepAliveTokens only contains wrappers for live objects, so if the array is not empty, we should show the activity indicator.

If we don’t get a notification when the tokens go away, how do we know to update the indicator? The rest of the updateIndicator() method handles this:

        if !isPollingConfigured && shouldShowActivity {
            pollingTimer = NSTimer.scheduledTimerWithTimeInterval(completionCheckInterval, target: self, selector: #selector(timerFired(_:)), userInfo: nil, repeats: true)
        } else if isPollingConfigured && !shouldShowActivity {
            pollingTimer = nil

    private var pollingTimer: NSTimer? = nil
    private var isPollingConfigured: Bool { return pollingTimer != nil }

    public var completionCheckInterval: NSTimeInterval = 1.0

We need to use a timer to periodically update the indicator. The if statement ensures the this pollingTimer is configured if there is any activity and is torn down when all activity ends.

I chose to expose completionCheckInterval as a public property so the client app can adjust it if necessary. One second seems like a reasonable choice though. The indicator will always spin long enough for the user to notice it, but we won’t spend too much time processing the keepAliveTokens array. I suppose if your use case had thousands of active network tasks, this processing might get expensive, but you should probably be rethinking your life choices at that point anyway.

The pollingTimer is configured to call a timerFired(_:) method. That’s dead simple:

    private dynamic func timerFired(timer: NSTimer) {

The dynamic modifier marks the method as dispatching through the Objective-C runtime so that the NSTimer instance can call it via performSelector(). It might be nice to have the timer invoke updateIndicator() directly, but NSTimer expects a specific type signature for the target method.

That’s the essence of the class, though the full version in the gist has just a few other wrinkles. There’s a no-arg beganNetworkTask() method that returns an opaque token object. That’s useful if you don’t have any natural token object like an NSOperation in your code. You can just hang on to a reference to the returned opaque token to keep the operation alive. There’s also a finishedNetworkTask(forToken:) method if you need to explicitly signal the end of a task. Finally, there are some guard statements that I omitted above for clarity. It’s useful to look at one of these.

The full implementations of beganNetworkTask(withToken:), updateIndicator(), and finishedNetworkTask(forToken:) take pains to do their work on the main queue. They do this using a guard statement like so:

    public func beganNetworkTask(withToken token: AnyObject) {
        // Redispatch async to main queue so access to `keepAliveTokens` is single threaded
        guard NSThread.isMainThread() else {
            NSOperationQueue.mainQueue().addOperationWithBlock {
                self.beganNetworkTask(withToken: token)
        let wrappedToken = WeakWrapper(wrapping: token)

The guard ensures that the method was invoked on the main thread. If not it re-dispatches asynchronously to the main queue, calling the same method again. This ensures that access to the keepAliveTokens array is single-threaded, so we don’t have any race conditions. The similar guard in updateIndicator() also keeps our pollingTimer scheduled on the main run loop.

I didn’t bother creating a micro-framework for NetworkIndicatorManager. I’m unlikely to maintain it, but please feel free to copy and paste any or all of it that you find useful.

Share and enjoy!

CocoaConf Seattle 2016

May 6, 2016

It was a pleasure to speak at CocoaConf Seattle this year. Here’s the abstract for my talk:

Let’s Build a Reactive Programming Library

Functional reactive programming is a much promoted technique for building apps structured around data flow, asynchronous events, and value types.

There are several popular frameworks for reactive programming in the Apple ecosystem, including Reactive Cocoa, RxSwift, and Bond. These powerful tools can be intimidating when first trying to learn the concepts.

In this talk I’ll implement a simple reactive programming library “from scratch”, live coding the interesting bits, and using them in a small demonstration app. The talk is intended for people new to reactive programming and should help demystify the concepts so you can approach one of the more powerful frameworks with confidence.

The code that we developed in the talk, along with the other code using that library, is up on GitHub now.

I’ve also posted the slides from my talk, though most of the information was in the form of animations that don’t translate well. Still, if you attended the talk, I hope these will be useful.

Complete and Await Reply Script, Version 1.0.2

January 26, 2016

Via email, Peter Sacréas, pointed out that my Complete and Await Reply script loses links in the notes of the tasks you apply it to. The script was making a new note by getting the text of an existing note, manipulating it, and then setting the note property of the duplicated task. Applescript is notoriously bad at handling rich text. By round-tripping the entire note through Applescript, I was losing the link.

In practice, the script just needs to insert some new text at the beginning of the note. So, instead of replacing the full text on the note, I switched to using an incantation that inserts plain text before the existing note, leaving the rich text unchanged:

set textToInsert to notePrefix & ((current date) as text) & return
insert textToInsert at before first character of note of theDupe

Bug fixed! You can grab the updated version here.

Share and enjoy!

Swift Framework Patch Proposal Pitch

January 17, 2016

After raising a ruckus about the thread on swift-evolution discussing making methods final by default, I was extremely pleased to see this proposal pitch shared by Joe Groff.

A lot of the discussion around the final/sealed-by-default issue focused on the ability in ObjC to extend frameworks or fix bugs in unforeseen ways. Framework developers aren’t perfect, and being able to patch a broken framework method can be the difference between shipping and not. On the other hand, these patches become compatibility liabilities for libraries, which have to contend not only with preserving their own designed interface but all the undesigned interactions with shipping apps based on those libraries. The Objective-C model of monkey-patchable-everything has problems, but so does the buttoned-down everything-is-static C++ world many of us rightly fear. However, with the work we’re putting into Swift for resilience and strong versioning support, I think we’re in a good position to try to find a reasonable compromise.

The essence of the idea is to provide specific, language-level support for declaring a patch to framework code from client code. Joe also sketches a corresponding mechanism for assisting framework authors in evolving their code while still supporting apps that rely on previous, buggy framework behavior.

There are lots of details that would need to be worked out, but mostly I’m gratified that Joe so clearly articulates the concerns that many of us in the app development community share.

Thanks, Joe!