Do not agree to develop what you do not understand

Original author: Jonathan Boccata
  • Transfer


Since the beginning of 2018, I have been the leader / chief / lead developer in the team - call it what you want, but the bottom line is that I am fully responsible for one of the modules and for all the developers who work on it. This position gives me a new look at the development process, as I am involved in more projects and participate more actively in decision making. Recently, thanks to these two circumstances, I suddenly realized how much a measure of understanding affects the code and the application.

The thought I want to express is that the quality of the code (and the final product) is closely related to how much the people who design and write the code are aware of what they are doing.

You may be thinking now: “Thank you, cap. Of course, it would be nice to understand what you write at all. Otherwise, with the same success, you can hire a group of monkeys to hammer on arbitrary keys, and calm down on this. " And you are absolutely right. Accordingly, I take for granted: you realize that having a general idea of ​​what you are doing is necessary. This can be called a zero level of understanding, and we will not analyze it in detail. We will analyze in detail what exactly needs to be understood and how it affects the decisions that you make every day. If I knew these things beforehand, this would save me a ton of wasted time and dubious code.

Although you will not see a single line of code below, I still think that everything said here is of great importance for writing high-quality, expressive code.

First level of understanding: Why does it not work?


Developers usually come to this level at the very early stages of their career, sometimes even without any help from others - at least, according to my observations. Imagine that you got a bug report: some function in the application does not work, you need to fix it. How will you act?

The standard scheme looks like this:

  1. Find the piece of code that causes the problem (how this is done is a separate topic, I disclose it in my book on outdated code)
  2. Make changes to this snippet
  3. Make sure that the bug is fixed and there are no regressive errors

Now let's focus on the second point - making changes to the code. There are two approaches to this process. First: to delve into what exactly is happening in the current code, identify the error and fix it. Second: move to the touch - add, say, +1 to a conditional statement or loop, see if this function worked in the right scenario, then try something else and so on ad infinitum.

The first approach is correct. As Steve McConnell explains in his Code Complete book (by the way, I highly recommend it), every time we change something in the code, we should be able to predict with certainty how this will affect the application. I quote from memory, but if the bugfix doesn’t work as you expected, it should be very cautious for you, you should question your entire plan of action.

Summarizing the above, in order to perform a solid bugfix that does not degrade the quality of the code, you need to understand the whole structure of the code and the source of a specific problem.

Second level of understanding: Why does it work?


This level is comprehended much less intuitively than the previous one. Being a novice developer, I learned it thanks to my boss, and later on I repeatedly explained the essence of the matter to beginners.

This time, let's imagine that you received two bug reports at once: the first is about scenario A, the second is about scenario B. Something is wrong in both scenarios. Accordingly, you are taken first for the first bug. Guided by the principles that we introduced for the first level of understanding, you delve into the code relevant to the problem, find out why it forces the application to behave exactly like that in scenario A, and make reasonable adjustments that give exactly the result that you expected. Everything is going fine.

Then you go to scenario B. You repeat the script in an attempt to provoke a mistake, but - a surprise! - now everything works as it should. To confirm your guess, you cancel the changes made in the process of working on the error A, and the bug B returns again. Your bug fix solved both problems. Lucky!

You didn’t count on it at all. You came up with a way to fix the mistake in scenario A and you have no idea why it worked for scenario B. At this stage, there is a great temptation to decide that both tasks have been successfully completed. This is quite logical: the point was to eliminate errors, wasn’t it? But the work is not over yet: you still have to figure out why your actions corrected the error in scenario B. Why? Then, that he may be working on the wrong principles, and then you will need to look for another way. Here are a couple of examples of such cases:

  • since the solution could not be targeted specifically for error B, taking into account all factors, you may have unknowingly broken function C.
  • it is possible that somewhere the third bug related to the same function also hid, and your bugfix makes the system work correctly in script B on it. Now everything looks good, but one fine day this third bug will be noticed and fixed. Then in scenario B, an error occurs again, and well, if only there.

All this introduces randomness into the code and someday it will fall on your head - most likely, at the most inopportune moment. You’ll have to gather your will into a fist to force yourself to spend time understanding why everything seems to work, but it's worth it.

Third Level of Understanding: Why Does It Work?


My recent insight is connected precisely with this level, and probably it would have given me the most benefits if I had come to this idea earlier.

To make it clearer, let’s take a look at an example: your module must be made compatible with function X. You are not particularly familiar with function X, but you were told that you need to use the F. framework for compatibility with it. Other modules that integrate with X work exactly with him.

Since the first day of your life, your code has not come into contact with the F framework at all, so it will not be so easy to implement it. This will have serious consequences for some components of the module. Nevertheless, you head off into development: write code for weeks, test, roll out pilot versions, get feedback, fix regression errors, find unforeseen complications, don't fit into the originally agreed time frame, write some more code, test, get the opposite connection, correct regression errors - all this in order to implement the framework F.

And at some point you suddenly realize - or maybe hear from someone - that maybe the framework F will not give you compatibility at all with fun tion X. Maybe all this time and effort has been made absolutely no to that.

Something similar happened once in the course of work on a project for which I was responsible. Why did this happen? Because I poorly understood what the essence of function X is and how it relates to the framework F. What should I do? Ask the person who sets the task for development to clearly explain how the planned action plan leads to the desired outcome, instead of simply repeating what was done for other modules, or to take the word that it is necessary for the function X to work.

The experience of this project taught me to refuse to start the development process until we have a clear understanding of why we are asked to perform certain actions. Refuse plain text. When you receive a task, the first impulse is to take up it immediately so as not to waste time in vain. But the policy of “freezing the project until we enter into all the particulars” can reduce wasted time by orders of magnitude.

Even if they try to put pressure on you, to force you to start work, although you do not understand how this is justified, resist. First, figure out the purpose for which you are assigned such a task, and decide whether this is the right path to the goal. I had to learn all this through bitter experience - I hope that for those who read this, my example will make life easier.

Fourth level of understanding: ???


There is always something to learn in programming, and I suppose I only touched on the very top layers of the topic of understanding. What other levels of understanding have you discovered over the years of working with code? What decisions were made that had a good effect on the quality of the code and the application? What decisions turned out to be wrong and taught you a valuable lesson? Share your experiences in the comments.

Also popular now: