Finding my way to the first post
Ahh, my first post. A daunting task for someone who has spent their entire life avoiding writing at any cost. I suppose this is a make or break moment where I decide if I can learn to enjoy writing. Lately, when my mind has the time to drift I have been mulling over what I should choose as the topic.
My first thought was something simple, personal, and harmless. I figured writing about my personal code setup (editor, shell, etc) seemed like a fine choice. Not very exciting but would get me in the groove. These types of posts are like candy; I can't say no to them but they're not what I need. But recently I reached what feels like a new milestone on my programming journey and I figured describing what happened would be much more interesting. So here it is.
Becoming an apprentice
In September 2019 I started a new job. I felt like I wasn't improving as a programmer in my previous job and I dreaded going to work every day. I love programming and working so that was a bad sign. Thankfully, I had a friend working at an interesting company and he was open to working with me. I wanted the job because the company is small. They're solving hard problems - physics simulations. Each of the three other software engineers has been programming for longer than I've been alive. And most important, they seemed willing to take time to pass on their collective knowledge to me. I had a hunch that there would be plenty to learn. Turns out that hunch was dead-on.
I work closely with the CTO, Rob Nagler. He has imparted quite a lot of wisdom so far. I'm uncertain I’m qualified to make this judgment (you'll see in this post how little I know about programming) but I have a strong suspicion Rob is a world-class programmer. I have had the pleasure of sitting 5 feet from him every day for the past six months. We talk about programming and I watch him solve problems day after day. Watching a master at work has helped me improve my skills at a faster pace than ever before. Reading works by smart people or being on a team with them is one thing. Being able to sit with a craftsman, watch them do their work, and get snippets of their thinking is so much more powerful.
It’s just code
One difference between Rob and myself is our fluency in reading code. We work on open source code and use many open source tools so there is a great deal of code to read. Before working at Radiasoft I can say (with some degree of shame from my present vantage point) that I had never really read code. If you're a professional programmer a statement like that probably makes your skin crawl. Looking in the rearview, it is somewhat amazing to me that I ever solved a problem with how little code I read.
I've worked on projects with other people and read the code they check-in. I've started new projects with existing codebases and read the absolute bare minimum of the code to do what I need to do. I've read snippets of code on Stack Overflow (duh) and blogs. I've even poked around open source projects I was thinking of using. But I've never really truly read code. I've never skipped the documentation and gone straight to the source code. I've never read another project's source code and used it to inform my approach to a similar problem. I've never encountered a bug in an open source project and fixed it myself (except for this small change). Rob does this kind of reading every day.
When I run into a problem I spend time fumbling through documentation, bug reports, mailing lists, and Stack Overflow trying to find answers. Most of the time this solution works well enough, but it can be slow, lead to awkward solutions, and sometimes just doesn't work. What I now realize is that programmers better than myself have another tool to use. Reading the source code.
In the past 6 months, there have been a few times where I have been truly stumped, tapped Rob on the shoulder to ask for help, and seen him go straight to the source code to find the answer. He's done this with the Tornado web server, the asyncssh Python library, the cPython source code, and our own codebase. All of these are large codebases with plenty of places to get lost. The first few times I saw Rob do this I was blown away. In seconds, he figured out where to look and in minutes he'd found the relevant bits of code and the answer. He knew that if he read the code, he’d find the answer. When I ask him how he does it he says, “it’s just code.”
I struggle to have this level of confidence. When I read code I tend to give up quickly, telling myself that the other person is clearly some sort of genius and my mind is too feeble to understand their masterful work. I usually start at a call site or object that I think should be relevant. I then go down long rabbit holes that are orthogonal to my problem and overly specific. For example, I’ll find myself reading through the ASGI spec and how the server implements it even though I just want to know why the incoming request connection was closed abruptly. I try to really understand every last bit of code because it is the only way I can make sense of anything (not everything, anything). This is usually the moment I get frustrated that I can’t find what I need and start to think it simply can’t be found. Rob, on the other hand, churns through other codebases. He moves along knowing that it is just code and with some time and determination he can understand it.
Now that phrase — it's just code — is a mantra for me when I read new code. Every time I read code it is slightly easier than the last time: It’s a muscle that you can build like any other.
Faith in the abstractions
In addition to reading the code (and remembering that it’s just code), Rob has taught me another trick: "Have faith in the abstractions."
Recently I added an administrative page to our website. It allows a user to see their running and pending jobs. I had just finished re-writing our entire job execution system (with a great deal of help from Rob) so I knew the back-end of the code well. I was less in tune with the front-end.
I needed to provide users with a link to each currently running job in the list. I wasn't sure how to do this so I set out in standard fashion: I hunted around the website for somewhere that provides a link to a job and tried to find the relevant source code, which I could then reuse for my purposes.
There was only one other place with a link and it was on the page of
the simulation itself so we just used $window.location.href
. Not going
to work for what I need because I need to link to jobs that are not on
the current page. So armed with "it's just code," into the code I
went.
I knew that we have a concept of local and global routes so I figured if I looked near those words I'd find something. Sure enough, we have a function called formatUrlLocal. The code calls some other code that isn't dead simple. I'd need to spend some time with it to really understand what it was doing and how I might use it. I had the sense that the code was going to need to change (which was wrong) so I felt like I really had to grok it.
What I should have done at this point is looked for other uses of the code and just used it the same way myself. Instead, I was frustrated that I couldn't find what seemed like a piece of code that had to exist. I asked Rob for guidance. Specifically, I asked, "Are there any places on the site where we have links to simulations. I'm not sure how to construct the link but it seems like something we would already have code for."
Thankfully he's patient and happy to help. As one might expect, he navigated directly to the formatUrlLocal code I was looking at and said, "Here, use this." It took him the amount of time it took his fingers to search to find code it had taken me 15 minutes to get to (and that I didn’t quite know how to use even once I found it).
I asked Rob how he got to the code so quickly and how he knew it was going to help. His answer, "I have faith in abstractions." If you're adept at reading code you may be thinking, “Duh, you can't understand everything so look for the abstractions that may be relevant, try using them, and when necessary dive in and understand them.” But if you're like I was you may be thinking, “Wow I have no clue how to use that advice.”
This is the kind of advice that makes no sense until you use it and then becomes totally obvious. Maybe it’s akin to telling someone to counter-steer when their car is sliding. It just isn't obvious how it works until you can do it. Sure enough, the code worked. It said it formatted URLs and it did just that. There was an abstraction and it worked. I didn't need to understand it top to bottom but I needed to have faith. I needed to try using it.
Now when I encounter problems I have new tools. First, I tell myself: it's just code and dive right into the source code. As I look at the code, I remind myself to have faith in the abstractions. The latter strategy is much harder. There are words and styles that are suggestive of abstractions that will lead you to the answer but it takes time and experience to discern the worthwhile ones from the irrelevant ones. And over time, you hopefully learn when the abstractions aren’t quite right. That’s when it’s time to go deeper. I can't say I really have any sense for this yet. But what I do have is the awareness that the answer is out there, in code, waiting for me to read it.
These are just the first steps of my journey towards really reading code. I hope that, as my journey progresses, I will be able to write many more posts with actionable insight on how to become more fluent. For now, the only advice I have is to reiterate Rob's insights: It’s just code and have faith in the abstractions. On top of this, I have a small piece of advice of my own: If you're not reading code, start today. It gets easier every time.