Making a decision is like a workout for your brain. You can do only so much in a day. If you overexert yourself, you can even mentally injure yourself (cause mental fatigue). Exercising your decision-making powers while psychologically fatigued will only bring more fatigue. Prolonged mental fatigue will lead to more stress. Moreover, that will lead to burnouts and depression Sleeping and resting allow you to restore your decision-making stamina.
Programmers are constantly faced with making decisions on the job. That can become exhausting. For example, the other day I had a pair-programming interview with a candidate in the afternoon. I had very split feelings about their performance. It was a hard decision if they should pass or fail the interview. Usually, I would be able to make this decision without much of a problem. That day, our team had a design meeting where many decisions were made. I could feel my mental energy being toasted. So I waited until the next day to make the decision about the interview. The decision was much easier to make.
Decision-making stamina is called willpower. Will (or volition in psychology) is the cognitive process by which you decide on and commit to a particular course of action. The concept of draining willpower is called ego depletion.
Every decision you make as a software developer drains your willpower. For example, deciding if you should eat that sweet cake or a healthy fruit will drain your willpower and you will have more trouble making decisions at work after that. Also, spending too much time while deciding on the name of the variable will inhibit your further decisions. While this article applies to any decision you make, we will focus more on the decisions you, as a software developer, need to make at work.
You will learn how to decrease the cost of decisions, detect when you are low on willpower, and how to restore your willpower.
How Making Decisions Builds up Stress
Decisions can be inherently simple or complex. More complex decisions are harder to make. The harder it is to make a decision, the more it will cost your willpower.
When you do not have enough willpower, it is still possible to make simple decisions, but it will be much harder to do. Also, if you have a choice between a better way to do something against the easier way to do something, you will default to the easier one, since its willpower cost is much smaller.
Whenever you make a decision in such a state, you build up your stress. That happens because of mental fatigue. Over time, that stress buildup can lead to burnout and depression. When stressed out, you will be much worse at doing your job. As more stress builds up, you will stop caring about the work you are doing. That could lead to very poor quality and detrimental decisions. Additionally, it will affect your career and your personal life negatively.
To prevent such stress buildup, you need to be able to detect that you do not have enough willpower. It is relatively straightforward to do. You are low on willpower when you feel that a simple decision is harder to make than usual. For example, it is harder to give a name to a variable than usual. Alternatively, it is more difficult to go and talk to your product person about that edge case that you are not sure how to handle. Another indicator: you fall back on your bad habits much more often. That is a side effect of ego depletion—loss of self-control.
What Increases Decision Complexity?
Every decision has an inherent complexity. Some decisions are naturally simple. Some are complex.
In a real-world context, it is not enough to count only the inherent complexity of a decision. A few things increase the complexity of a decision by a large margin.
The less information you have, the harder it is to make a decision. When you know that you lack certain information, you will hesitate to make that decision.
As you get more context on the problem at hand, it will become increasingly easier to make a decision. On the contrary, indefinitely waiting for all the information is not practical. In the software development world, many decisions are made when there is not enough information available.
The obvious solution for that problem would be to wait until sufficient information is available. On the other hand, deferring a decision for a long time also consumes a good chunk of your willpower. That’s especially so when you had to make that decision yesterday.
Another important factor in decision-making is the cost of a mistake. More precisely, how much do you fear to fail? If the cost of failure is very high, the decision’s complexity will skyrocket. If the expense of a mistake is tiny, the decision might become almost trivial.
Imagine that one decision depends on the outcome of the other one, which depends on the results of the third decision, and so on. Let’s call that a decision chain.
Now you have to make a new decision in such a chain. You know that all the previous decisions in the chain were correct. Making that new decision is as hard, and as easy, as making it without the chain.
Unfortunately, this happy path is not what you observe in the real world. Usually, a few of the previous decisions in the chain are still of unknown status. You do not know if they were correct or incorrect. Moreover, now you have to make another decision today.
How much harder do you think that decision will be to make?
A great deal harder.
You simply can’t have all the information to make that decision. Within such decision chains, you have to operate in a constant state of uncertainty. Such uncertainty increases the cost of decision-making. On top of that, continued uncertainty contributes to stress buildup.
The information you need to make a new decision is produced from the effect of the previous decisions. In systems theory, that is called a feedback loop. The time it takes for an effect to become apparent is called delay.
You want these feedback loop delays to be as small as possible. That will reduce the complexity of your average decision by a huge margin.
You have to recognize these various feedback loops and shorten their delays. Let me give you a few examples of how I have reduced feedback loops in software development teams in the past.
Business Impacts of Features you Develop
After developing a certain feature, do you know how much more revenue your product is generating? Alternatively, how much more are users engaged with your iPhone app?
Business impact is an effective change in any important characteristic of your business. In traditional business, it could be your sales revenue. In charity, it could be a count of saved lives. If you are developing a feature for a couple of months and it does not produce that impact, then you have wasted your time.
Very often, software developers do not have access to that kind of information. That is why for the developer, it is very hard to make any tradeoff in the area of business impact. Going back to the concept of feedback loops—they do not exist here. You need to create them.
Software developers are natural problem solvers. Every day, they deal with complexity in the code that is on par with levels of business and economic complexity. It’s no wonder that when developers know an actual goal behind a feature or task, they can find a better, easier, and faster way to reach it.
Businesses should trust software developers to make business-level decisions and give them problems to solve instead of complete solutions. For that to work, software developers need to know well the current state of the business goals—preferably in real time as measurable metrics. When that is done, software developers will optimize their decision-making for these metrics. Here is how that could work:
In the past, I was working on a project in which we were developing a website where fans could buy songs of their favorite bands.
One day, a project manager came and asked us to create an iPhone app. Obviously, it was a lot of work. Moreover, it was very frustrating because we did not know why we needed that app to be available. Also, it was not clear what features we should implement and how we should implement them.
Apparently, the business wanted to sell more merchandise via our product. In addition, some bogus research had shown that it was best done via an iPhone app.
I described this problem to my former colleague, and they pointed me towards the impact mapping technique. The method was mind-blowing. We asked a few questions of our stakeholders and understood why they needed an iPhone app.
Using the impact mapping technique, we came up with a multitude of possible solutions that were much simpler and made more sense in our context. We chose to sell merchandise in bundles.
Then I was interested in those business impacts, so I added merchandise sales to our monitoring system. On top of that, I made a graph that was very visible on our big display near the team tables. That did wonders. Developers started to discuss all the tradeoffs and decisions from the angle of merchandise revenue.
I created a new feedback loop for every single developer in the room. As they deployed a new version of the software, they could see what kind of business impact they produced. That short feedback loop allowed us to turn hard decisions about what features to develop into quick experiments. We would deploy a new version and look at the monitor. If merchandise sales went up and stayed up over time, it was a successful experiment. Otherwise, we would revert the change and cut that feature out of the scope.
Eventually, we reached our merchandise sales goals. We even slightly overdid it.
You can see more feedback loops here.
First, the information on why a business makes certain decisions. Now that you know a business’s goals, you can propose better solutions to a problem. As a software developer, you are a natural problem solver, so the chance that you can come up with something better is quite possible. After this success, the business was willing to tell us their goals.
Second, exposing the business impact as a prominent graph in your team’s operations monitor helps the whole team to focus on what matters most. Give developers a game, and they will play it.
Code-Level Decisions
Let me tell you a story about how short feedback loops can improve decision-making at the code-level:
Once, I was on a team where we would code one feature for a week or two. Then we would resolve all the merge conflicts and push our changes to the master branch. One or two months later, we would get a few bug reports. These bugs would be hard to fix because we would not remember the code anymore. Of course, the code was a terrible mess and debugging took much time.
That is quite a long feedback loop. After a small change in the code, we would know if it was correct or not after only a few months. All the decisions that we made in code we had to do very carefully. Extracting one method from another method was potentially a dangerous operation. Changing a conditional statement always left us feeling that we forgot to change another one somewhere in the code base. That should have been an obvious change on the code level, but ended up being a nightmare.
Then we tried hard not to make any mistakes. How?
By developing features even slower and testing them manually, and more rigorously. By doing so, we made our feedback loop for our code decisions even longer. That only led to more merge conflicts, even messier code base, and scarier decision-making. The bug rate also kept increasing.
At this point, my friend and I had read about automated testing: unit testing and acceptance testing. Outside of our daily jobs, we tried to develop a full-blown application for a few months using these techniques. We liked it. The bug rate decreased by a huge margin. Also, we tried code review in the form of merge requests from feature branches.
These techniques gave us tremendously tight feedback loops. If we made even the smallest change in the code, we could see within five to 10 seconds what other components of the system the change affected. That is all thanks to the unit tests and acceptance tests. Code review helped us to give each other feedback on micro design decisions that we were making in the code. For example, readability of a name, whether or not we should split a class in two, too large functions, and so on.
During my daily job, we had a new product just starting. I proposed that the team try out these automated testing and code review techniques for two weeks. We decided to give it a try.
As I already had a somewhat successful experience with these techniques, the team succeeded in applying them. We saw much fewer bugs. None of them was a show-stopper from releasing a product. Our code base was more readable than everything we had seen before. It took only a few days to develop an average feature, and merge it back to the master.
Eventually, we were automatically deploying every such merge to our staging environment for the business and customers to test. That gave us another short feedback loop on the correctness of the code that we were writing. Moreover, that gave us confidence in making the decisions in the code, such as bigger refactoring, cleanup, and application of the campsite rule. We were not afraid of making decisions in the code. That made these decisions much simpler.
Slowly, other teams started to notice what we were doing. They began adopting some of our techniques. Some started writing unit tests for new code. Others switched to feature branches and code review.
You can see multiple feedback loops at work here.
First, feedback on code-level decisions concerning correctness. Imagine you have spotted a duplication. Your first thought is to extract that duplication into a single function. Now you need one month to know if your refactoring did not produce bugs. You will hesitate to do it. It will be a hard decision to do that refactoring.
Now, imagine you could have pressed one button to run the test suite that you trust. The test suite is so fast that you will know if you introduced any bugs within five to 10 seconds. What is the cost of making the decision to refactor? Practically nothing. Refactor, run tests, and undo if needed. With modern tooling, the whole cycle can take up to 20 to 30 seconds.
Having any testing is nice. Automated testing is much more useful, as it shortens the feedback loop to seconds for your single decision in the code. Test-driven development reduces that feedback loop for each decision in the decision chain even more. That removes a lot of risk and uncertainty while implementing any functionality.
Second, feedback on code-level decisions regarding readability. You could’ve decided on a certain code structure and naming, and see if your colleagues could understand what that code did. Without any code review, you would get feedback on these decisions within anywhere from one week to one year, or never.
Peer code review is shortening the feedback on how good your system is to days or even hours. Pair programming makes this feedback instantaneous.
How to Restore Willpower
The most efficient way to restore willpower is to get enough sleep. Taking a short nap in the afternoon may help you get through the most intense days. One full night of sleep restores full reserves of your willpower. I use these tips to get a better sleep every night.
Eating food is another effective way to restore your willpower. Be careful not to overeat. If you overeat, then you will be sleepy for a couple of hours and will not be able to make decisions properly.
Another way to restore bits of willpower is to take breaks at work regularly and often. These breaks should be part of your work time, i.e., you should not work more hours because you took these breaks. That is critical for you as a software developer. Not only does it restore willpower, but it allows your brain to process all the information it just received. That lets you have new insights and come up with solutions you otherwise would not be able to. Moreover, it allows you to step back and see a bigger picture. When coding, software developers are focused on a very narrow part of the picture. What makes sense in such a narrowly focused environment might not make sense from a big-picture standpoint.
There is one good technique for taking breaks often: the Pomodoro technique. In essence, you will take regular short breaks between focused work intervals. Thanks to this technique, I don’t feel tired at the end of the day, and I maintain enough willpower to make decisions throughout the day, even in the evening.
Another effective way to restore your willpower is to take physically active breaks. If you had a 15-minute break somewhere around 11 a.m. and 3 p.m., you could do a little exercise or a workout. That would energize your brain and refresh your thoughts before going back to work. For example, I use these 15-minute breaks to play table tennis (aka ping-pong) with my colleagues.
While these methods are good at restoring willpower, they do not heal you from stress. It takes much more time to relieve stress. So it is best to avoid building it up in the first place.
Bottom Line
Making decisions expends your willpower. As willpower is depleted, decisions made count towards your mental fatigue.
Being in a constant state of mental fatigue leads to stress buildup. Stress itself causes mental fatigue. That is a vicious loop, which leads to burnout and depression. That in itself will affect your career and personal life negatively.
If you want to be a successful software developer, you will need to fight back against these issues. So as soon as you feel low on willpower, you need to defer important decisions until the next day. You will need a good night’s sleep and a short nap on the most decision-heavy days. Also, you will need to take regular and active breaks and eat just enough food to restore your willpower. In our trade, healthy sleep and regular breaks are extremely important.
The nastiest of all are decision chains. As software development is very complex, we work with these chains all the time.
The most efficient way to deal with decision chains is to shorten their feedback loops. Our trade is full of techniques that exist for a sole purpose—tighten that feedback loop using test-driven development, automated testing, continuous integration and delivery, pair programming, code review, impact mapping, agile retrospective, and so on.
Learn and master these tools. They will help you avoid stress, feel better, and be more successful as a software developer.