Don't settle for developing what you don't understand

Don't settle for developing what you don't understand

Since the beginning of 2018, I have been the lead/head/lead developer in the team - call it what you want, but the point 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 perspective on the development process, as I am involved in more projects and more actively involved 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 point I'm trying to make is that the quality of the code (and the end product) is closely related to how aware the people who design and write the code are of what they're doing.

You might be thinking right now, “Thanks, Cap. Of course, it would be nice to understand what you write in general. Otherwise, with the same success, you can hire a group of monkeys to thrash on arbitrary keys, and calm down on this. And you are absolutely right. Accordingly, I take it for granted that you realize that it is necessary to have a general idea of ​​what you are doing. This can be called the zero level of understanding, and we will not analyze it in detail. In detail, we will analyze what exactly you need to understand and how this affects the decisions you make every day. If I knew these things ahead of time, it would save me a lot of wasted time and dubious code.

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

First level of understanding: Why doesn't it work?

Developers usually reach this level very early in their careers, sometimes even without any help from others - at least in my experience. Imagine that you have received a bug report: some function in the application does not work, it needs to be fixed. How will you act?

The default schema looks like this:

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

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

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

Summarizing what has been said, in order to implement a solid bugfix that does not worsen the quality of the code, you need to understand both the entire structure of the code and the source of a particular problem.

Second level of understanding: Why does it work?

This level is perceived much less intuitively than the previous one. I, being still a novice developer, learned it thanks to my boss, and subsequently I myself explained the essence of the matter to beginners more than once.

This time, let's imagine that you received two bug reports at once: the first one is about scenario A, the second one is about scenario B. In both scenarios, something is wrong. Accordingly, you are taken first for the first bug. Based on the principles we developed for the first level of understanding, you delve deeply into the code that is relevant to the problem, figure out why it causes the application to behave the way it does in Scenario A, and make intelligent adjustments that produce exactly the result you want. expected. Everything is going great.

Then you move on to scenario B. You repeat the scenario in an attempt to provoke an error, but - surprise! - now everything works as it should. To confirm your guess, you undo the changes you made while working on bug A, and bug B reappears. Your bugfix solved both problems. Lucky!

You didn't count on it at all. You've come up with a way to fix a bug in Scenario A, and you have no idea why it worked for Scenario B as well. At this point, it's very tempting to assume that both tasks were successfully completed. This is quite logical: the point was to eliminate errors, wasn't it? But the work is not over yet: you have yet to figure out why your actions fixed the error in scenario B. Why? Then, that it may work on the wrong principles, and then you will need to look for another way out. Here are a couple of examples of such cases:

  • since the solution was not chosen specifically for error B, taking into account all factors, you may have broken function C without knowing it.
  • it is possible that a third bug related to the same function is lurking somewhere, and your bug fix ties the correct operation of the system in script B on it. Now everything looks good, but one day this third bug will be noticed and fixed. Then script B will again have an error, and it's good if only there.

All this introduces chaos into the code and will someday fall on your head - most likely, at the most inopportune moment. You'll have to muster the will to force yourself to take the time to understand why everything seems to work, but it's worth it.

Third level of understanding: Why does it work?

This level is exactly what I had a recent insight into, and it is probably the level that would have given me the most benefits if I had come to this idea earlier.

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

Your code hasn't touched the F framework at all since day one, so it won't be easy to implement it. This will have serious consequences for some components of the module. However, you are headlong into development: writing code for weeks, testing, rolling out pilot versions, getting feedback, fixing regression bugs, discovering unforeseen complications, not meeting the originally agreed deadlines, writing some more code, testing, getting feedback. communication, fixing regression errors - all this in order to implement the F framework.

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

Something similar happened once while working on a project I was responsible for. Why did it happen? Because I didn't really understand what the X function is and how it relates to the F framework. What should I have done? Ask the person setting the development task to clearly explain how the intended course of action leads to the desired outcome, instead of simply repeating what has been done for other modules, or taking the word that it is necessary for 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 being asked to perform certain actions. Refuse directly. When you receive a task, the first impulse is to take it on immediately so as not to waste time in vain. But the policy of “freezing the project until we get into all the details” can reduce wasted time by orders of magnitude.

Even if they try to put pressure on you, to force you to start working, although you don’t understand why this is justified, resist. First, figure out for what purpose you are given such a task, and decide whether this is the right path to the goal. I had to learn all this the hard way - I hope those who read this, my example will make life easier.

The fourth level of understanding: ???

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

Source: habr.com

Add a comment