An encouraging thing happened to me last year. I was faced with a mystery involving how a bit of application code was interacting with ActiveRecord. It seemed like we were calling ActiveRecord properly, but the query wasn’t coming out quite right. In years past, this would have likely stymied me; productivity lost! But this time, I had the gumption to dive into the mystery and the tooling to help me navigate the murky waters of an object-relational mapper’s internals. Armed with a little bit of confidence, the ability to click on a method call to jump into its definition, and a little bit of experimenting in a Rails console, I figured out the problem. Success!
Now, when I’m faced with a weird situation, I tell myself “these are computers, I know this!”1 and dive in.
This feeling is due to a few ways I leveled up my skills over the past few years. A little improvement in my tooling helped me acquire the “quickly jump to the definition of this function/method/etc.” skill. The big level up was the confidence that I could figure this mystery out, that there was likely an easy explanation lurking just behind the curtain, and that if I had the gumption to pursue it, I could figure all this out.
I feel like any developer of any background and experience can level up these skills!
I. Finding courage in cartoon foxes and stick figures
Over the past few years, I have been able to dive into more curious bugs, behaviors, and domain logic because I was encouraged by off-the-wall, esoteric forms of technical discourse. It probably started off years ago with the silly carton foxes of Why’s Poignant Guide to Ruby. Check it out if you haven’t!
Fifteen years ago (yikes!), when Ruby was gaining momentum and Rails was, to most people, a demo screencast, this approach to teaching a language was controversial. “Programming is serious!”, some would say. They claim there’s no room for flippant catchphrases like “chunky bacon,” sketchy cartoons, or programs not meant for “production-fortified commercial codebases”. Turns out, they are wrong — some folks find playful texts are a much easier way to learn deep topics like Haskell, Erlang, or even economics.
Fast forward to now, and folks like Julia Evans, the Base CS podcast, and illustrated.dev are once again chipping away at the notion that computers are all serious business that require a stiff lip and stereotypically masculine dedication to mathematical rigidity. I have learned more about datacenter networking and containerized deployment from Evans’ stick figures than any manual page, reference doc, or even the classic textbooks of W. Richard Stevens.
In other words: These are computers. I know this. And from there, I can figure out almost anything.
II. Knowing I’ve solved bigger mysteries than this
Allow me to get self-involved for a moment.
I recharge my batteries not with side hustles or open source projects2 but by tinkering with side projects and learning new technologies. I’ve long had a growth mindset. I’ve benefitted a lot by turning that energy and curiosity into something I could apply when I get stuck on less esoteric work mysteries like legacy-to-me code and framework code.
I was fortunate to study computer science in university, and a little lucky that the program at my university was very average. My courses pushed me to figure out topics I would have otherwise skipped or found too intimidating like discrete math, computer architecture, or compiler construction. I came out with the ability to self-teach myself the topics I found interesting and immediately practical like Linux, programming languages, and how to actually build software.
In my twenties, when I was still full of energy and some margin time to pursue interesting ideas, I took more time to self-learn things which challenged or intrigued me. I learned how Ruby works, the basics of Haskell, and went deeper into databases and distributed systems than many developers outside of mega corporations have the necessity to do.
By my early thirties, I could look at a wide spectrum of technologies and feel confident (perhaps unearned) I could “figure it out” if necessary in a professional context. Out of order computer architectures, database index and query strategies, distributed consensus, managed runtime trade offs, or implementing binary addition from first principles all felt like a big challenge, but something I could participate in a discussion of, if not attempt to implement of on my own. A growth mindset in my twenties, learning tricky talks on my own, and a few of the courses I didn’t think I’d use in college paid off!
Having these topics “under my belt” makes tackling many (but not all) challenges feel achievable. I feel like this is down to the curiosity to learn a bunch of topics on my own and the optimism that I’ve learned plenty of tricky topics and can learn more. Of all the things I would encourage a younger-me to continue doing, challenging myself to figure out big, audacious mysteries is amongst the most important.
III. Believing there are no evil spirits
In code, there are no boogeymen or little demons conspiring to confuse me. The vast majority of the logic and behavior of any computer, program, or system thereof is explainable. While it’s tempting and enjoyable to ascribe personalities, stories, motivations, and drama to inanimate systems, they do not actually exist.
Most systems are linear, predictable, and some kind of deterministic. Things don’t happen magically, they only happen for reasons I don’t yet understand. There are no evil demons or spirits, only processes or circumstances which my mental model does not yet accommodate.
The corollary to this is that there are very few mysteries I can’t solve with sufficient time and determination. The solution might be weird, completely different from what I first thought, not what I’d hoped to learn, or involve inputs outside what I considered the domain of the problem. But the answer exists!
It’s tempting to say “this job just dies overnight and we restart it” as though that were nature and we have no agency over the process. But, I totally do have control over the process and can look into why it’s dying overnight! The only thing stopping me is me, and finding some time to learn. Given necessity and a time box3, I can figure it out or eliminate variables that aren’t the answer.
It’s also tempting to think “well I call this method and then the framework does some magic? and I get the value I want back, most of the time”. Like I said before: there is no magic, only things I don’t yet know about. When I find myself uttering this, I know it’s time to roll up some courage, gumption, and sleeves then dive into the framework to figure out how it makes the magic happen.
Some unpredictable or surprising behavior is very deep. Not every mystery is worth my time to resolve. That’s what time boxes are for! When this happens, my goal is to remove as many “suspicious spirit” stories as possible. The more logic and facts I bring to explaining this behavior, the better equipped I am to actually figuring it out next time I look into it.
These are computers and software; I know this.
IV. Enhancing my thinking with tools
I eschewed integrated development environments for a long time; they were slower and less capable than more focused text editors with smaller, Unix-style language integrations. But, computers are faster, designers of IDEs are more tasteful, and we now live in a world where language runtimes are just as influential as linters, test runners, and build tools. Perhaps now is the time for a smarter, integrated development environment.
It’s essential, to me, that whatever I’m using to write and edit the code is fast enough to keep up with my thinking. Beyond my own ability to type and make up names, the important criteria are all about enhancing my ability to think. TextMate first did this with vastly improved file navigation and language-specific snippets and expansions that helped me hold less syntax and boilerplate in my head. Vim, then Atom, helped me lay source files out side-by-side, like I would with sheets of paper, so I could think about related things in a limited-but-helpful spatial ordering.
Now, the tool that is enhancing my thinking is RubyMine. Its ability to “take me to the definition of the method/variable/class/etc.” under my cursor is now much easier to use than setting up equivalent tools that integration with Emacs, Vim, etc. So in the moment of perplexing code, I’m able to jump into the code at the center of the mystery and figure out what was going on.
In this case: these are computers, they know me. ;)
V. Mystery. Learn. Repeat.
Pulling it all together: I’m often faced with mysteries in the course of development work. It often takes courage and the confidence I’ve tackled deep topics before to go down the rabbit hole. Once I’m down the rabbit hole, it’s important to remind myself that most systems are linear and have logical inputs and outputs; no philosophical daemons mischievously manipulating results to confuse me. Automated tools for navigating source code are a huge boon throughout the process. All together, I stand a pretty good chance of tackling mysteries.
The common link between Ms. Evans and Mr. Stiff, makers of cartoon-y programming literature, is broad curiosity about the craft of programming and optimism that no topic is “off limits”, “too deep”, or “requires credentials” for us to learn. That’s a great mindset we can all benefit from!
Thanks to Marie Chatfield, Kelsey Huse, and Brian Ray for giving me tremendous feedback on this draft.
- There’s a scene in the original Jurassic Park where a young heroine saves the day by doing some computer stuff. In a crucial moment with dinosaurs about to eat the whole cast, she sits down in front of the computer system which can save them, recognizes it, utters “This is Unix, I know this!”, and proceeds to save the day. ↩
- Though I wish I could do that too! ↩
- Time boxing is working on a task for a fixed time, e.g. 30 minutes. Either you finish it, decide not to keep going, or have a better idea of how to break it down so you can finish it. ↩