As a programmer you are likely to experience frustration from time to time. In the last few months I am sure you can recall at least a couple of occasions when you have sat at your desk, faced with a problem of some description, and felt at least a small degree of frustration. Or maybe you experience this unpleasant feeling on a daily basis. Maybe it has become part and parcel of your working life. If this is indeed the case, then something needs to change. Too much frustration is likely to lead to stress, which in turn can of course lead to a whole range of physical and mental problems. So how can programmers keep a lid on frustration in the workplace? What can we do to minimize its effects? And why do we ever feel frustrated by our work in the first place?
The Wikipedia page on frustration, in its first two sentences, provides a nice definition:
“In psychology, frustration is a common emotional response to opposition. Related to anger and disappointment, it arises from the perceived resistance to the fulfillment of individual will. The greater the obstruction, and the greater the will, the more the frustration is likely to be.”
In more simple terms, frustration happens like this: we want something (will), but we can’t get it (obstruction). And the greater the obstruction and will, the more intensely frustration is felt.
If we were to look at frustrated programmers at work, we would find that the thing they want, their individual will, is probably the satisfactory completion of whatever they are working on. If you are trying to fix a bug, you want it to be fixed. If you are working on a new feature, you want to finish its implementation. And if you are working towards a deadline, you want to achieve completion on time.
But something gets in the way. The unanticipated obstruction. You thought you could achieve completion by performing tasks a, b and c. However, halfway through task b, you realise that there are actually a couple of other tasks that need doing – tasks which you hadn’t planned for. Suddenly, the thing that you want – satisfactory completion – has slipped further out of reach. Worse still, your original estimate has become unrealistic.
The result? Frustration.
If all this wasn’t bad enough, you may even find yourself stuck in a vicious cycle of ever-increasing frustration, which looks something like this:
You have a problem, you try a solution, it doesn’t work.
Or maybe this:
You have a problem, you try a solution, and it works, but you find one or more new problems along the way.
What we need to do as programmers is figure out ways to avoid getting stuck in these cycles of frustration. Because the more frustrated we feel, the less sharp our thinking will become. And the less sharply we can think, the less likely we are to come up with good solutions to the problems we face.
How can we do this? How can we fight off the perils of frustration?
To a certain degree, I don’t think we can. We are only human, and we are never going to be clever enough to fully predict how a system is going to behave. Software systems are just too complex for that. In Code Complete, Steve McConnell states that managing complexity is the most important technical topic in software development. In other words, the whole purpose of programming languages, operating systems, design principles and patterns, is to help us flawed humans better understand what is going on inside a computer. Without these things, you would be working directly with bits and bytes, and you clearly wouldn’t get very far in trying to develop a useful application. Our brains are not capable of perfectly predicting how exactly a line of code is going to impact every other part of a system. There will always be times when we are caught up in that cycle of unpredictability, when a 3 day task becomes a 3 week task.
What we can do is improve, reduce the likelihood of frustration, even if we can’t eliminate it completely. The best way to do this is to continuously acknowledge our limitations, and the fact that we are not capable of perfectly predicting a complex system’s behaviour. It is almost a kind of humility. If we can learn to accept that we aren’t as clever as we think we are, then we will begin to take measures to compensate for our limitations. The opposite of this would be to be so confident in our ability that we would just ruthlessly plough into our code, refusing to admit that we’re not actually sure we’re doing the right thing.
The measures you take to compensate for your limitations will depend on your individual circumstances. Test-driven development is interesting as it fundamentally changes the low-level dynamic of how we code. Rather than waiting for a problem to show itself, the developer creates a problem (code which doesn’t compile or a failing test) and then fixes it. However, TDD is no silver bullet. You can still find yourself underestimating the complexity of a task, which will of course lead to frustration. Improving our estimating skills can also reduce the likelihood of frustration, along with finding the courage to provide an estimate which may not be well received. My own practice of religiously taking regular breaks stems partly from an acknowledgement that we are limited in how long we are able to concentrate on a task in an effective manner. Careful planning of a project or task is also a reflection of our inability to ‘wing it’ and still achieve good results. Defining what ‘done done’ looks like ahead of time may also help us to gain control.
It sometimes takes a crisis to force us to accept that we are vulnerable and imperfect. We need to choose not to wait for that wake-up call, and instead make the right low-level decisions, minute by minute, in acknowledgement of our limitations. A lot has been said about positive visualisation and its merits, however we should also consider the potential value of a little negative visualisation from time to time. What if things don’t go according to plan? How likely is it that we will sail through this task without entering a cycle of unpredictable system behaviour, and how can we mitigate that risk?