Know when to not throw in the towel

Dear new developer,

I wrote previously about when to throw in the towel. Now I want to mention when you shouldn’t.

Anything worth doing is hard. That includes software development. There are times, sure, when it feels like you’re a superhero. When the code is flowing. When you can hold the entire system in your head.

Those times are great, and, in my experience, rare.

There are also times when it’s a grind. When you look up at the end of the day and wonder “what did I actually do all day?” When you are picking up a new technology or system and it feels like you are on the last move of a game of Jenga, with all the pieces about to fall over.

This is the time when you need to stop, take a deep breath, and then keep going. That doesn’t mean you can’t pop up and ask questions or take breaks, but sometimes the only way out is through.

There’s an art to knowing the difference between a grind that you have to get through and a wall that you can beat your head against without making progress. I don’t have a simple way to differentiate, other than to say that the grind often happens at the beginning of a project (when you don’t know what you don’t know) and at the end of a project, when that last 5% that you put off because it was hard balloons to 25% (or more).

I have told teams in the past that “if we aren’t learning and making mistakes and doing new things, we aren’t doing it right”. That’s because if a software engineer knows how to do something, they’ll likely automate it (and then they won’t have to do it again).

Sometimes that learning process is joyful. Sometimes it grinds. You have to push through.

Sincerely,

Dan

Laziness, impatience, hubris

Dear new developer,

Larry Wall has created foundational software (perl, patch). He coined the three virtues of a programmer:

  1. Laziness: The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful and document what you wrote so you don’t have to answer so many questions about it.
  2. Impatience: The anger you feel when the computer is being lazy. This makes you write programs that don’t just react to your needs, but actually anticipate them. Or at least pretend to.
  3. Hubris: The quality that makes you write (and maintain) programs that other people won’t want to say bad things about.

These may seem crazy. Who wants to be seen as lazy, impatient or full of hubris?

But if you think deeply about it, Larry is saying that laziness makes you work in the short term to save effort in the long term. That impatience makes you write better code because computer time is less valuable than your time. And that hubris makes you want to develop software that you can stand proudly behind.

Makes a bit more sense, no?

Sincerely,

Dan

Learning to read code is more important than learning to write it

Dear new developer,

Coding is fun! You get to take a few words on a page, breathe life into it through your understanding, type rapidly into a text editor, and display it to our colleagues. It’s an amazing profession that is changing the world.

However.

The vast majority of code is read far more often than it is written. This is true for a few reasons:

  • Companies pay for code. Code is expensive. They want to amortize the costs of writing it across as many years as they can.
  • Business requirements change. That means that the code that supports those business actions needs to change. But before that software can change, the modifier needs to understand what is currently happening. Even if the requirements dictate a whole new feature is implemented, the developer still needs to understand how the new feature fits into the existing codebase.
  • Bugs occur, where the software is almost correct, but not quite. Again, anyone fixing the bug needs to understand what the existing code is doing.

And over the years, there will be many changes and bug fixes.

There is, to be true, the occasional piece of software that is just “set and forget” where changes are minimal over the years. I once was responsible for a piece of software that ran for five years with no changes. That’s rare enough that it sticks in my mind.

So this means, that of the time you actually spend coding, it’s likely that more of it will be spent trying to understand existing code in order to make changes to it than it will be writing new code. And of the applications you support, more of them will be already written than not. Of course, depending on what company you work for, things might be different. A startup with no existing systems will need more new code than a running business. (I wish I had numbers to support these statements, but all I have is my experience.)

What does that mean for you, new developer?

It means that spending time learning to read code is a good idea.

When I approach an existing project that is new to me and need to have an understanding of it in order to make changes, there are a few different aspects I consider.

  • Scanning. This is the high level overview. What problem does this code try to solve? What language and/or framework is it using? Is it using them in an idiomatic manner, or in a unique way? What are the big pieces of the application, and how do they fit together? This information is perfect for a document, but sometimes needs to be pulled from someone’s head or from the code (you should write down what you learn).
  • Diving down. This is where you focus on the problem at hand, and try to identify where the changes should be made. This will probably involve having multiple files open and moving between them, and trying to understand all the logic of this part of the system. You can also look for more granular patterns in the code, including different levels of abstraction, homegrown libraries or frameworks used, and coding idioms. Consistency matters, so you want to write in the style of the current codebase (which doesn’t prohibit you from noting where the current style is flawed and should be changed).
  • Use the scientific method. Write a hypothesis, make small changes and see what happens. If you can make changes in a staging system or on your local machine, that’s great.. A debugger is super helpful here, as are unit tests (or any kind of automated test). If you can’t make a local copy of the entire, you can typically still set up the language runtime locally and run various chunks of code to get a better understanding of what the system is doing.

Beware of the temptation to try to understand the entire system before making any changes. Whether you need to do so is based on how entwined the system is, how well the system is tested, and how critical the system is. Only discussions with the business and other members of your team can determine the best course forward, but an understanding of the entire system will likely only come with time.

Also, beware of the temptation to just throw away the old code and rewrite it. Especially if you don’t understand all that the code is doing. Old code is reified knowledge, and you ignore that at your peril. See obligatory link to the classic post “Things You Should Never Do, Part I”.

Reading code is more important than writing code because software systems spend the majority of their lifetimes after launch, and change happens.

Sincerely,

Dan