Time is the most valuable resource for a developer. The six methods described in this article to write maintenance code can save you time and reduce your frustration: spend one minute writing comments, it will save you an hour of effort to study the code.
I learned how to write, improve, and maintain code. Over the past 12 years, I have been writing computer games and making a living by selling online through sharing software technologies that were once booming. That is to say, I often need to code from the ground up from a blank screen. It can be sold only when the Code reaches tens of thousands of lines.
That is to say, if an error occurs, I have to solve the problem myself. When I was still searching for bugs at three o'clock in the morning, I looked at the obscure code of yunyun and asked myself, "My God, which stupid guy wrote these spam codes? ", Unfortunately, the answer to the question is "I ".
After learning good and formal coding skills, I was greatly benefited. This article includes some practices. Many experienced programmers are familiar with this content. They can repeat this article through the elegant prose introduction and review the headache of coding before adopting the clear coding concept.
But more people will, like me, intrude into the field of programming without human intervention. The content described in this article may be very basic for many people, but it is a very valuable resource for others, because no one has told him before. Therefore, if you do not want to take a detour, this article will be very suitable for you.
Example
For ease of explanation, this article will use a sample space game program called kill bad aliens. In this game, you will use a keyboard to control a spaceship, which can move horizontally forward or backward at the bottom of the screen, and can also launch bullets up.
Figure 1. Our hypothetical game
The game takes place in a period called wave. In every wave, aliens will appear at the top of the screen one by one. They are flying everywhere, and there will be bombs. Aliens will appear at regular intervals. After killing a certain number of aliens, a wave is over.
Killing an alien will give you extra points. When you finish a wave, you will receive an additional score reward based on the length of time required to complete the game.
If you are hit by a bomb, your current ship will be blown up, and another ship will appear. If it was blown up more than three times, the game would have ended. If your score is high, you will be promoted to "person". If your score is low, you cannot.
Now we can sit down and start writing this kill bad alients game in C ++. First, define several objects to represent the ship, the player's bullets, the enemy and the enemy's bullets. Then write code to draw these objects. You also need to write code to make these objects move around over time. In addition, you also need to write game logic, alien AI, and code that can perceive the user's intention to press keys.
So how can we achieve this so that after the game is compiled, the code is easy to understand, easy to maintain, and at least it will not be a mess?
Tip 1: Comment frequently
Always add comments to the code. Suppose you wrote a process but didn't annotate it. After a few months, you will try to trim it (you will definitely do it ), it will take a lot of time to study the code because you have not commented on it before. Time is your most valuable resource. The lost time will never be recovered.
However, annotations also require skills like other things. As long as you practice more, your skills in this area will be continuously improved. Comments are good or bad.
It is best not to write the comment too long. Assume that a function is annotated, and this annotation can save you 10 minutes to understand the code in the future. This is good. Now, assuming that the comment is too long, it takes five minutes to write the comment, and five minutes to read the comment. In this way, no time is actually saved. This is not a good practice.
Of course, do not write comments too short. If no comments are found in the Code on one or two pages, it is best to make the code clear and clear. Otherwise, it will take a long time to study it in the future.
In addition, the Comment method cannot be too rigid. When people are writing comments, they often have a hot mind and write the following comments:
// Now we increase Number_Aliens_on_screen by one. Number_Aliens_on_screen = Number_Aliens_on_screen + 1;
|
Obviously, there is no need to comment on such obvious things. If the code is so messy that it requires line-by-line comments, the more advantageous way is to simplify the code first. In this case, Annotations do not save time, but consume time. Because annotations take time to study, and they are distributed in different locations in the actual code on the screen, you can only view a few comments on the display at a time.
In addition, do not write comments like this:
Short get_current_score() { [insert a whole bunch of code here.]
return [some value];
// Now we're done. }
|
What is the use of comments like "We're done? Thank you for letting me know. Isn't it enough for me to note the braces below and the large white spaces followed by them to understand that this is the end of a piece of code? Similarly, you do not need to use comments like "now we return a value" before returning a statement.
So if you are writing code without instructions from your boss or company, how can you comment on it? My practice is: I will write an introduction to the Code maintained by myself. In this case, when I return a process that I wrote a long time ago, I can view its explanation. Once I understand how it works, I can easily understand the actual code. This usually involves:
- Before a process/function, write a few words to describe its functions.
- A description of the value passed to it.
- A description of the returned result of a function.
- Within a process/function, code can be decomposed into comments for shorter tasks.
- Give a brief explanation of the cause of some obscure code.
In short, we need to give a description at the beginning, and then comment on several points inside the code. This approach takes a short time, but can save a lot of time in the future.
The following is another example from the hypothetical kill bad alients game. Consider the object that represents the player bullet. You need to call the function frequently to move it up to check whether the bullet hits any target. I may write the code to implement this function as follows:
// This procedure moves the bullet upwards. It's called //NUM_BULLET_MOVES_PER_SECOND times per second. It returns TRUE if the //bullet is to be erased (because it hit a target or the top of the screen) and FALSE //otherwise. Boolean player_bullet::move_it() { Boolean is_destroyed = FALSE;
// Calculate the bullet's new position.
[Small chunk of code.]
// See if an enemy is in the new position. If so, call enemy destruction call and // set is_destroyed to TRUE
[small chunk of code]
// See if bullet hits top of screen. If so, set is_destroyed to TRUE
[Small chunk of code.]
// Change bullet's position.
[Small chunk of code.]
Return is_destroyed; }
|
If the code is clear enough, the comments shown above should be enough. For people like me who need to return this function from time to fix errors, this will save a lot of time.
Tip 2: Use more # define. Yes, it requires a lot of use.
Suppose that in our hypothetical game, players are expected to score 10 points when shooting an alien. There are two ways to achieve this. One of the worst practices is as follows:
// We shot an alien. Give_player_some_points(10);
This is the good way: In some global file, do this:
#definePOINT_VALUE_FOR_ALIEN10
|
Then, when we need to give some scores, we will naturally write this:
// We shot an alien. Give_player_some_points(POINT_VALUE_FOR_ALIEN);
|
To some extent, most programmers know how to do this, but they need to follow the rules to do it well. For example, every time you define a constant, you must consider defining it at a central position. Assume that you want to set the game area to 800*600 pixels. Do this:
#define PIXEL_WIDTH_OF_PLAY_AREA800 #define PIXEL_HEIGHT_OF_PLAY_AREA600
|
If you want to change the size of the game window on a certain date (you may need to do so), changing the value here will save you twice. This is because: First, you do not need to find all the places in the code that mention that the game window is 800 pixels wide (800! What did I think at the time ?) Second, you do not need to always fix bugs that are unavoidable due to missing references.
When I made a kill bad aliens game, I had to decide how many aliens would need to be killed, how fast a wave would end, how many aliens could be on the screen, and how fast those aliens would appear. For example, if I want the number of aliens in each wave to be the same and they all appear at the same speed, I may write the following code:
#defineNUM_Aliens_TO_KILL_TO_END_WAVE20 #defineMAX_Aliens_ON_SCREEN_AT_ONCE5 #defineSECONDS_BETWEEN_NEW_Aliens_APPEARING3
|
This code is very clear. Since then, if I think this wave is too short or the time interval for aliens to appear is too short, I can immediately adjust the corresponding value and immediately let the game take effect again.
A wonderful way to set the game value is to make changes quickly, which makes immediate control very good. For example, if you rewrite the above Code as follows:
#defineNUM_Aliens_TO_KILL_TO_END_WAVE20 #defineMAX_Aliens_ON_SCREEN_AT_ONCE100 #defineSECONDS_BETWEEN_NEW_Aliens_APPEARING1
|
Then, you will not be able to enjoy the above pleasure and excitement.
Figure 2. Kill bad aliens before processing a constant
Figure 3. Kill bad aliens after processing constants (this kind of game may not be good enough, but it is very interesting for reference)
By the way, you may have noticed that I didn't make any comments for the above values, because the variable names clearly show the meaning of these values. This is what I will discuss next.
Tip 3: Do not use a self-defeating variable name.
The general goal is simple: write code so that those who do not know what it is intended can understand it, so that those who know what it is intended can understand it as soon as possible.
The best strategy for achieving this goal is to assign explicit names to variables, processes, and so on. When others see this variable name, they will immediately understand its meaning, and you do not have to search the entire program for it.incremeter_side_blerfm
Which may save about five minutes.
Some balancing is required here. The given name should be as long and clear as possible so that you can understand its meaning, but it cannot be too long or too weird. In this way, the readability of the code will be affected.
For example, in reality, I may not name constants as shown in the previous section. I used to do this so that readers can fully understand the meaning of these constants without any context. In the context of the program itself, the comparison is as follows:
#defineMAX_Aliens_ON_SCREEN_AT_ONCE5
|
I will not hesitate to code like this:
This short name will soon give rise to doubts, and the short name will also increase the readability of the Code.
Now let's look at the code snippet that I often call to move aliens everywhere on the screen. I will not hesitate to code it like this:
// move all the Aliens for (short i = 0; I < MAX_NUM_Aliens; i++) if (Aliens[i].exists()) // this alien currently exist? Aliens[i].move_it();
|
Please note that the name of the array containing all aliens is very simple, calledAliens
. This is great. It is exactly the descriptive name I want. It is very short and I don't feel bored even if I type it thousands of times. This array is frequently used. If you name it likeall_Aliens_currently_on_screen
With such a name, the final code written will grow a lot and the code will become unclear.
Similarly, I also name the loop variable directlyi
, Without any additional instructions. If you touch the descriptive variable name concept for the first time, you may not be able to name this cyclic variable as a name like "counter. In fact, there is no need to do this. The significance of naming a variable is to enable the reader to understand the intention of the variable immediately. Everyone knows that such names as "I" and "J" are often used for cyclic variables. Therefore, it is entirely possible to name them like this without additional explanation or explanation.
Of course, pay more attention to variable naming. For example, there is something called Hungarian notation. There are many types of variables, but the basic idea is to add a flag at the beginning of the variable name to indicate its type (for example, all unsigned long variables useul
). This is much more troublesome than I want, but this concept must be understood. It may take too much time to figure out, but it is worth it.
Tip 4: Check for errors.
A program of the normal size usually has a large number of functions and processes. What's more troublesome is that each of them requires a slight error check.
When creating a process/function, you should always consider the following: "If some malicious people intentionally pass various weird values to the function or process, how can I self-protect the code I just created and protect the computer from damages?" Then, write code to check the malicious data to protect itself from the destruction of the data.
For example. Our major goal of this space game is to kill aliens and earn points, so we need a process to change scores. In addition, when adding time-sharing, we need to call a routine to achieve the star-shining effect on scores. The first process is shown as follows:
Void change_score(short num_points) { score += num_points;
make_sparkles_on_score(); }
|
So far, it is not bad. Now let's think about: what are possible errors?
First, an obvious problem is:num_points
Is negative? Can we reduce players' scores? Even if we can reduce the score, I did not mention the Score Loss in my previous descriptions about the game. Furthermore, the game should be interesting, but losing points is not an interesting thing in any case. Therefore, negative score values are considered an error and must be captured.
The above errors are relatively easy, but there is a very subtle problem (which I often want to handle in the game ). Ifnum_points
What if it is zero?
This is a very plausible situation. Remember, we will give a reward Score Based on the player's speed at the end of each wave. If a player is very slow, should we give him a zero reward score? Callchange_score
And pass the value 0, which is completely feasible.
The problem now is that we may not want the score board to flash around without changing the value displayed. Therefore, we must first capture this issue. Let's try the following code:
Void change_score(short num_points) { if (num_points < 0) { // maybe some error message return; }
score += num_points;
if (num_points > 0) make_sparkles_on_score(); }
|
Well, the situation is much better.
Note that this is a simple function. It does not use any novel pointers highly praised by new users. If you want to pass an array or pointer, it is best to be careful with the appearance of errors and bad data.
The benefits of doing so are not limited to saving the program from destruction. A good error check can make debugging faster. If you know that the data written exceeds the range of the array, you need to check the code in detail to find possible errors. If the error check in this process is ready, you do not need to spend a lot of time looking for errors.
This method saves a lot of time and can be repeated. In other words, time is our precious resource.
Tip 5: "immature optimization is the root cause of troubles"-Donald knuth
The above motto is not created by me. It can be found in Wikipedia, so it must be very wise.
Unless it is difficult to find someone else, the primary goal of code writing is simplicity. Simple code is easier to write, easier to understand, and easier to debug.
Optimization is contrary to simplicity. But sometimes optimization is required, especially in games. This issue is critical and you may not be aware of the need for optimization until you use a parser to actually test the working code. (ParserIs a program used to monitor other programs and find out the time it takes for the program to use different calls. These are all great programs. You can find one to try .)
Every time I optimize a game, it's often unexpected. The code I am very worried about is always not a problem. On the contrary, I think the foolproof code will run very slowly. Since I have no idea about the speed of running, the optimization I made before getting the actual data is a waste of time. Worse than wasting time, it also makes code a little messy.
This rule seems hard to comply. However, if the rule is easy, it cannot be called a rule. Many good programmers hate to make code that can run quickly bloated and clumsy.
But the good news is that this is the only thing you can slack off when I keep saying "this shouldn't be the case!
Please make your code as neat and effective as possible. In the subsequent Optimization phase, it may need to be completely invisible. So be careful if not necessary.
When it comes to injury, let's take a look at the final suggestion.
Tip 6: do not be knowledgeable or smart.
You may have heard of ioccc, that is, International obfuscated C code contest. As we all know, C and C ++, no matter how superior they are, will eventually lead to a nightmare of coding complexity. This competition is to show the value of concise code by selecting the most outrageous code.
Let's look at what troubles you can make when you think you have all the programming knowledge and are willing to take risks. With sufficient knowledge, you can compress ten lines of code into one line with confidence. The price is that you cannot quickly fix any bugs.
The lesson to be learned here is that if the code you write requires you to have a detailed knowledge of complex priority rules, or you have to read the chapters of some books to find out what is going on, then, when you write this code, you will be confused and clever.
Everyone has their own tolerance for the complexity of the Code. Personally, the programs I write tend to show a typical conservative style. I personally think that if a piece of C code requires you to know the difference between I ++ and ++ I, this code is too complicated.
You can think of me as a regular person. Yes, I do. However, it takes me a little time to understand my code.
Conclusion
At this point, you may think: "Wow, it's a waste of time. All these things you 've introduced are obvious and well-known. Why write such an article ?" In fact, I hope you will think so, because it means that you have made progress and become wise. This is good.
But do not mistakenly think that all this content is self-evident to everyone. This is not the case. Bad code can be seen everywhere, but it shouldn't actually be.
If you are writing a lot of code and want to leave yourself alone. So please make the code as simple as possible, so that you can save a lot of time and avoid a lot of setbacks.