There are tons of articles online that discuss the articles/talks/books that you must consume to become a true programmer. I dislike this framing; it’s gatekeeping, plus software development is such a varied discipline that one person’s essential reading is entirely unnecessary for another.
Instead, I’d like to present to you my programming earworms.
An earworm is a song that gets stuck in your head and just keeps popping up at random times. Likewise, the following are articles/talks/books I consumed years ago yet somehow keep coming back to mind, over and over, because they really struck a nerve.
I’m going to list out my programming earworms and why they have been stuck in my head for so long. Will these be useful to you? I don’t know! What I can say is that they have all shaped my thinking about programming greatly.
Before I begin, some context...
- I’m listing them approximately in the frequency that they return to my head.
- I do not 100% agree with everything stated in each link - rather, there’s some aspect to each that really resonated with me.
Simple Made Easy by Rich Hickey
The foremost problem I deal with is complexity. The more complex a system is, the harder it is to do everything, from maintenance to feature work to reliability.
This talk tackles this problem in a fundamental manner that has forever shaped how I think about addressing complexity. In short, it’s key to make code as simple as possible, but beware of falling into the trap of confusing “easy” with “simple.”
(A quick simple vs. easy example: anyone can play the triangle; you just hit it. That’s simple. By contrast, it’s easy for me to play trombone because I’ve practiced for years, but most people would find it difficult.)
Integrated Tests Are A Scam by J. B. Rainsberger
The basic point of this talk is that tests that run the entire application (“integrated tests”) can’t come anywhere close to covering all your bases. Each additional variable in an app exponentially increases the tests needed to cover every possible state. Ouch!
If, instead, you architect your app such that it’s just a series of components talking to each other, then you can test the contracts between components in a sane manner without having to invoke the whole app due to transitive properties. That is, if you can test A <-> B, and test B <-> C, then you don’t need to test A <-> C.
This is one of those great ideas that pays off in multiple ways - not only are your tests better, but supporting those tests also forces your software architecture to be better, too.
(If you’ve got limited time, there’s an article instead, but I prefer the talk because it also discusses solutions.)
The Future of the Testing Role by James Bach
I’ve always worked with manual testers and I highly appreciate them because they find my mistakes before users do.
Unfortunately, not everyone feels that appreciation. For a long time, I’ve had to push back against management who wants to get rid of manual testing. They would prefer to replace it with developer-driven initiatives, like automation.
This talk makes the best case for manual testing I’ve seen. It deconstructs why testing is a unique role and how expert testers provide special skills that others don’t. It also explains why people often overlook the importance of manual testing.
(This is a long talk; you can get a lot out of this by only watching the first half, as the back half is directed towards testers themselves.)
Technical leadership and glue work by Tanya Reilly
This is a fantastic talk about a situation everyone should be aware of - people doing important glue work that no one realizes is crucial.
I keep spreading this talk around for a few reasons. It’s got good advice for people who are stuck doing underappreciated glue work. For developers who don’t realize glue work exists, it points out stuff they ought to learn to do beyond coding. And it is a warning to management not to pigeonhole people into being glue and not giving them a chance to flourish in other ways.
Underlying it all, the talk highlights how developers contribute to software in many different ways besides just coding. It continually reminds me to appreciate the many ways people are contributing to a piece of software.
(This talk is also available in blog form.)
What if the user was a function? by André Staltz
This was the talk that introduced me to unidirectional architecture, and to me is still one of the best introductions to the concept.
Instead of a complicated dance between different components (e.g. model-view-controller), instead you just have data flow in one direction: a model would be fed into a view, the user would interact with the view, then those interactions would get fed back into the model, which would update the view...
This setup instantly felt so much simpler to me than any other architecture I’d seen before. I suspect many others feel the same, as numerous popular frameworks now use unidirectional data flow.
(I want to give an honorable mention here to Christina Lee’s Borrowing the Best of the Web to Make Native Better, which really helped contextualize this idea within Android for me.)
Notes on structured concurrency by Nathaniel J. Smith
Concurrency is hard. Really hard.
Structured concurrency is the idea that you are required to keep track of all your concurrent calls by scoping them, rather than letting your asynchronous code just fly off into the wild yonder. I’ve been blindly feeling my way towards a solution like this for years (i.e. my failed library RxLifecycle), so when I read this article, it instantly struck a chord with me.
I think the idea of structured concurrency is fantastic; I’m really pleased that it’s getting a big trial run with Kotlin coroutines, which adapted it. I suspect that in time, structured concurrency will be commonplace, much like how unidirectional data flow has taken over UI frameworks.
When I was a young programmer, I assumed that all languages and frameworks were essentially good. If a lot of people were using a technology, then it had to be designed well, right?
Ever since reading it, I have kept a skeptical eye towards system design. What works well in a system and what doesn’t? How do we mitigate problems caused by unchangeable design snafus?
Nowadays, I seek out “The Good Parts” book for whatever language I’m working with. For example, the Java version of this book is Effective Java.
The mythical 10x programmer by Salvatore Sanfilippo
Is there such a thing as a 10x programmer? I don’t know, and I generally steer clear of the 10x programmer debate entirely (as it only leads to unproductive flame wars) but unfortunately for me here this article launches from the idea.
The reason I return to this article again and again is because I think it makes a fantastic point on how non-linear programming is as a discipline. From that viewpoint, there are definitely ways to exponentially speed up some work. I especially like his point about sacrificing design perfection in order to get the work done.