Code is tax – have a good reason to write it

I once told software engineers on my team: “We’re not here to write code”. They were flabbergasted. But I strongly believe that our job is not to write code but to solve problems. It just so happens that for many problems, code is the best, if not the only solution.

We often get this backwards. We identify as software developers, we love writing code so we will write code whether it is needed or not.

Years of experience taught me to think about a problem before writing a single line of code. I usually try to answer two questions:

  • does this problem need to be solved now or, even at all?
  • can this problem be solved without writing code?

Surprisingly often, this exercise allows me to discover alternative ways of solving a problem that are more effective than writing code.

Not all problems need to be solved

Sometimes, assessing the importance of a problem is difficult, especially when done in isolation. The issue might seem significant, prompting us to solve it with code, only to realize after the fact (or maybe even not) that this work didn’t yield any noticeable improvement.

Consider a service making blocking I/O calls. Such a service won’t scale well. However, if it receives only a few requests per minute rewriting it to improve its throughput won’t have significant impact and is not necessary.

While many such problems will never require further attention, some might need to be revisited. If the service mentioned above needs to be integrated with a system generating many requests per second, fixing the blocking I/O calls could be a top priority. So, it is important to stay on guard and address issues that were initially punted if they resurface again.

Not all problems need to be solved with code

Many problems can be solved without writing any code.

There is an entire class of problems that can be mitigated by changing the configuration of the software. For example, if your streaming service occasionally crashes due to the Out-Of-Memory exception when processing spikes of data, reducing the maximum allowed batch the service fetches for processing could be a perfectly valid solution. Processing the spikes may take a little longer, but the overall processing time may not be affected in a noticeable way and the issue is fixed without changing the code.

Often, you can solve problems making careful design choices. Take user accounts on a website, for example. When deciding how users log in, there are two common options: using their email or letting them create a unique username. Coming up with unique user names can be challenging for applications with millions of users, so many of them suggest an available user name. Using an email as the user name is an elegant way of solving the problem of unique user names without writing any code. It also simplifies the account verification and password recovery flows.

What’s the problem with writing code anyway?

In my perspective, code should be treated like a tax. Just as taxes, once code is added, it is rarely removed. Every person on the team pays this tax day in and day out because each line of code needs maintenance and is a potential source of alerts, bugs or performance issues. This is why I believe that, as software engineers, we should opt for no-code solutions when possible, and write code only when absolutely necessary.

Accelerate your software engineering career by promptly merging your diffs

One of the things that continue to amaze me daily is developers who delay merging approved diffs.

All the hard work is done – the diff has been written, reviewed and approved. The only remaining action is to execute a few commands or just press a button. But for some reason, it’s not happening.

There are no upsides to putting off the merging of approved diffs but there are plenty of downsides. The most evident one is merge conflicts. While the diff is on hold, other diffs are getting merged, and the longer the delay, the bigger the risk of having to deal with merge conflicts. In extreme cases, like bigger refactoring, the entire change may need to be redone. This isn’t just a waste of the who made the original change. Since the new change needs to be reviewed again, it’s also a waste of time for everyone else.

Delaying the merging of diffs can lead to unnecessary drama. People, especially those who reviewed the code, may work under the assumption that the changes are already merged. When they find out it’s not the case, it forces them to alter their plans or deal with merging the diff themselves, leading to unnecessary hassle.

With many years in the industry, I’ve observed an interesting phenomenon: it is not uncommon for the same bug to be independently discovered by multiple people around the same time. Delaying the merging of a fix increases the likelihood that another person on your team encounters the same bug. Unaware that a fix has already been prepared, they may decide to fix it which will result in unnecessary duplicated effort.

Holding off on merging diffs, can lead to other sticky situations. For instance, if a release branch has been cut, the change won’t be included. This creates a dilemma – either the product will ship without the change, or the change will need to be hastily merged not giving it enough time to discover potential issues. Another scenario is when external circumstances like code freeze or going on vacation, postpone merging the change even further only amplifying all the problems mentioned earlier.

Finally, all unfinished tasks – including waiting-to-be-merged diffs – take a toll on our mental capacity (Zeigarnik effect). The brain tends to remind us of them at the most inconvenient times resulting in unnecessary stress and anxiety.

The take away is simple: avoid procrastination. Run these commands, click the green button and get your diff merged. You’ll have to do this sooner or later, otherwise why you even bothered to write and send the diff in the first place?

Accelerate your software engineering career by unblocking yourself

Every software engineer gets stuck every once in a while. What makes the difference is, how we deal with it.

Being “stuck” means not being able to make progress on the top priority work.

The bigger the company the more likely it is to get stuck due to organizational, not technical reasons. Knowing how to navigate these situations has a direct impact on your career. If you can, you should prevent getting into this state in the first place, but it’s not always possible.

One of the most effective ways to get unblocked is to talk to people. Sometimes finding the right person is difficult, but it can be done. If you don’t know this person, maybe you know a person who knows this person? You can also post your question to a company forum, Slack channel or mailing list. For technical questions, the ultimate hack is to find relevant code and see who contributed to it.

When working with multiple teams communication is crucial. Frequent sync ups help discover issues before it’s too late. To mitigate the impact of delays, you need to establish an interface both teams can work against. This way both teams can make meaningful progress independently.

Getting unblocked can be difficult and even frustrating at times, but the alternative – waiting until things get better themselves is not a winning strategy.

Read more here: https://growingdev.substack.com/p/getting-unblocked

Accelerate your software engineering career by reading code

Many developers often focus solely on writing code, neglecting the importance of being able to read code. How do I know? Because I was one of them!

The ability to read code is a crucial skill for every developer, as we often spend more time reading code than actually writing it. However, reading code is often more challenging than writing code. It requires piecing together the context from various parts and putting yourself in the shoes of the original code author. Fortunately, this skill can be learned. As a software engineer, you have plenty of opportunities to enhance this skill while performing your job:

  • Participating in code reviews
  • Debugging code that is outside of your area of ownership
  • Familiarizing yourself with the code of libraries that you depend on

And, there is also GitHub with thousands of repositories solving problems of all shapes and sizes. You are guaranteed to find something that will interest you and dive in.

Improving your ability to read code will unlock many benefits for you:

  • Getting up to speed when changing jobs or teams will be smoother and faster.
  • Code reviews will take less time.
  • Understanding bugs and fixing them correctly the first time will be easier.
  • Knowing how your dependencies work will help you come up with better designs.
  • Your debugging will be more effective, especially in cases where you can’t debug directly (e.g. missing debug symbols, decompiled code, etc.).

If you feel reading code is not your thing, think again. It might take some time to pick up this skill, but it will serve you for years.

Read more here: https://growingdev.substack.com/p/the-art-of-code-reading

Accelerate your software engineering career by writing good commit messages

“’Fixing a bug’ is a great commit message!” said no one.

Why? Because commit messages like this make our jobs frustrating.

Good commit messages on the other hand, make our jobs easier and save everyone time as they:

  • give more clarity to the diff author – if you, as the diff author, have a hard time writing a good commit message maybe your change is not ready for review?
  • help understand what the person who wrote the code was thinking which makes it much easier to grasp reasons why the code was written the way it was written and helps avoid introducing regressions
  • provide the context for code reviewers and as a result facilitate faster code reviews by lowering the barrier to entry for anyone willing to review the change
  • allow finding commits quicker

Note that this is not about making commit messages longer. Long commit messages are not necessarily good commit messages. Good commit messages are short but informative. In many cases a single line explaining what the change is about is sufficient. More complex changes, especially bug fixes, often require more context:

  • What exactly the change is about. This information is a must, and should be always included in the title.
  • Why you are making this change. What scenario it unblocks. What issue it fixes.
  • Short description of implementation details.
  • If fixing a bug, how to reproduce it.
  • How the change was tested – especially useful for any validation beyond unit tests
  • Links to related issues or tasks

You can find an expanded version of this post here: https://growingdev.substack.com/p/how-to-remove-unnecessary-friction