I’m not saying I don’t find enjoyment in coding. I do.

The high when you’ve deciphered new APIs and manipulated them into making your device do something it couldn’t before is intoxicating.

You feel as a God amongst mortals, able to bend the universe to your will. All things are possible.

It’s just that until that moment, my emotional state hovers somewhere in the spectrum between white-hot rage and tear-inducing frustration.

Frustration is one our most common shared experiences

Though we engineers don’t often often talk about it with non-engineers. The animation below shows my face after 20 minutes of debugging a problem.

Twenty minutes of debugging later, it turns out I’d forgotten to call .show() after creating a Toast.

I spoke with a colleague recently — an experienced engineer new to Android — who wanted to write an app to automatically turn on his Internet-connected lights when he got close to his house. He’d done a course on Android, so he was familiar with Android fundamentals.

He talked a lot about his frustrations.

I figured it should take me about an hour to go from nothing to the app he described. Rather than sit down next to him and pair program, I figured I’d record myself writing the code (and cut out the (really) boring bits.)

This screencast shows the easiest, fastest, and wrongest way to build this app. It’s 16 minutes represents about two hours of real-time coding and debugging, and implements everything within a single Activity. There’s a thousand ways in which this implementation is wrong — and I spend some time at the end of the video explaining why everything should be done differently.

Developing real apps for mobile is complicated

A lot of people — myself included — spend a lot of time crafting the perfect code samples, walkthroughs, tutorials, and training, so when new developers are ready to write their first app, they’ve got all the tools they need to architect it correctly, and implement it efficiently.

But if you’re trying to get a feel for Android and figure out if an idea is possible, is it worth figuring out and implementing Fragments, Services, and Intent Receivers? Understanding the subtleties of the Activity and app lifecycles?

If you want to write a high quality app that users will love and VCs will want to shower money on — eventually, the answer will be a resounding yes. BUT, that doesn’t mean you have to learn all that stuff up front.

If you go into it knowing you’re going to start again, it can be fun to write something hacky and kludgy just to have some fun and prove your idea can be done. I think of it as an incentive to learn the hard stuff.

As a result of this throw-away work, learn something very valuable — it’s possible to do what we want: automatically turn on our Internet-connected lights when we get close to home.

Which. Let’s face it. Is pretty damn cool.

When I want to learn how to code using a new platform, API, or framework, I’ll start by experimenting, trying, and failing, until I make headway or get bored.

On Day One, I just want to download the SDK, fire-up an IDE, and experiment.

I’ll invest a few hours getting a feel for how things work without worrying much about the right way to do it. That’ll produce something ugly, buggy, poorly architected, and totally unscalable — but workable as a prototype.

Note that the getting started experience is critical here. If I spend those first few hours installing and configuring my development environment I may stop before I even start.

I’ll start by seeing what’s possible using my intuition — the same way I learn how to use new electronics. And I’ll use Stack Overflow, because, I mean, seriously, let’s be real.

Of course, much like with my new electronics, eventually I may read a manual or a book, do a course, watch a video, or review a sample — but that’s never where I start (which is more than a little ironic given how much time I spend creating those things for other developers.)

There’s an art to building apps that delight users

But when it comes to just making something work, it feels like coding should be predictable. A mobile app, at its root, is just manipulating transistors that let you create AND, OR, and NOT gates, that in turn can be used to create more complex logic — we’re really just dealing with logic circuits, which when you boil it down, is just a series of trues and falses.

These basic building blocks are used to construct increasingly complex APIs, frameworks, and platforms — which are in turn used to create increasingly feature-rich apps for users. Each step along this path effectively encapsulates best-practice implementation details, so we we don’t have to start every project defining an object, creating a linked list, and writing a quicksort algorithm.

We can conceptually translate incredibly complex systems into simple state machines

I can take a video on my phone with a few swipes and touches, and start watching it on my TV with a few more. When you stop to think about the number of interacting systems it requires (electricity, power distribution, digital-analog conversion, video recording, video broadcasting, LCD display, Chromecast, …) — let alone how each of those systems works down to the physical layer (not to mention the complex decision process by which I decided on which video to watch, and the intricate and protracted negotiations with my wife to determine a mutually agreed-upon selection), it quickly becomes a fractal of complexity and intimidation.

As engineers, the difficulty, frustration, and ultimately the thrill of victory comes from unraveling the complications caused by multiple layers of abstraction within our code, the interaction between those components, and the way those systems are experienced by the end user.

To effectively write and (especially) debug code, you need to keep significant parts — if not all — of the system in your head. That means everything from the high-level architecture of how the pieces fit together, to how each of those pieces works — at times, all the way down to the physical layer.

The frustration comes from being pulled down the stack

We’re constantly switching contexts between “big picture” conceptualizations of how the system as a whole should work, and the excruciating detail of how each of its parts are implemented.

Typical flowchart of debugging code that really should already work

Say you’re incorporating Wi-Fi and Bluetooth signals into a self-learning system to trigger a geofence more efficiently. When it doesn’t work, the problem could be anything from a misunderstanding of how the Bluetooth APIs work, to mis-reading your Bluetooth signals, or forgetting to call .show() on the toast you’re using to test if it’s working.

Minimize the depth and complexity of your problem stack

To lower my frustration — and maximize my enjoyment — I try to keep the scope of what I’m working on at any given time as small as possible. Once that’s working, I’ll take a step back and add more complexity, iterating quickly so that there’s a tight loop between solving a difficult problem and having a better version of my working app

In practice, that looks a little like this.