📜 ⬆️ ⬇️

Code That Cannot Be Supported (Part 2)

The continuation of this topic is the second and third chapters of the essay “Unmaintainable Code”. Somewhat echoes the first, but the methods described are no longer so obvious (and some are distinguished by truly devilish ingenuity and no less insidiousness). Oh yes, the author quietly switched to C / C ++ from the Java language declared in the prologue.

Camouflage



The art of camouflage - hiding things or masking them for others - constitutes a significant part of the art of writing unsupported code. Most of the techniques in this section are based on the fact that the compiler perceives and processes the code differently than a text editor or person. Below are selected camouflage techniques:
')
1. Write the "effective" code

In the name of efficiency, more sins are being committed than because of any other reason, including stupidity.

The safest way to hide your obfuscation code is to pretend that your main goal is to increase the effectiveness of the program. In the name of a high goal, they will forgive you all your tricks when they come up.

2. Comments pretending to be a code

Comment on the code snippets so that at first glance they seem relevant.
 for ( j=0; j<array_len; j+ =5 ) { total += array[j+0]; total += array[j+1]; /*       total += array[j+2]; */ total += array[j+3]; total += array[j+4]; } 

Without code highlighting, would you notice that the middle line is commented out?
(I can not imagine what development environment this method is designed for - even Far has a code highlighting plugin. Apparently, it is supposed to combine it with incorrect file extensions, for which / * * / is not recognized as a comment - comment.)

3. Namespaces

In C, the struct / union and typedef struct / union belong to different namespaces; therefore, the same name can (and should) be used in both. It is advisable to make them almost compatible.

typedef struct { char* pTr; int lEn; } snafu;

struct snafu { unsigned cNt; char* pTr; int lEn; } A;


4. Hidden Macros

Hide macro definitions in the thick of meaningless comments; then the maintainer will skip all comments at once and will not detect the macro. Use this macro to replace any legal language expression with something very strange:

#define a=ba=0-b

(I don’t know what the author meant; this macro in C / C ++ code generates an error if the variable a appears in the code, and is safely ignored if there is no such variable. C / C ++ is also not fools who wrote :-) - comment per.)

5. Pretend to be busy

Use macros to create fictional “functions” that absolutely do nothing.

#define fastcopy(x,y,z) /*xyz*/
:
fastcopy(array1, array2, size);


6. Override functions

Create "functions" - double standard (macros with parameters) that do something completely unexpected. (Special maniacs can thus override a dozen functions that a corrective person may want to use. For example, you can write your bulky module calculation function together with the #define abs (a) (-2 * a) macro, and use it, demonically laughing at his partner’s attempts to replace it with a normal module - comment.)

7. Transfer in variable names

Remember that C preprocessor regards the \ character at the end of a line as a line break and sticks it to the next? Fine! Creatively approach splitting long variable names into strings to make it as difficult as possible to find all references to these variables by a simple search.

8. Choose reserved words for arbitrary examples.

If in the documentation you need an arbitrary example for the file name, use “file” and not an obvious arbitrary name like “charlie.dat”. In general, choose arbitrary examples that are as close as possible to the reserved words, or these words themselves (if the compiler refuses to accept it, all the better, it’s just documentation). When used correctly, readers are hopelessly confused as to which parts of the example can be replaced with other words, and which parts cannot. If you are caught, you can innocently prove that you were only trying to help the reader understand the meaning of each variable.

9. Names in the code vs names in the interface

Make sure the variable names have nothing to do with the names in the documentation and interface. For example, the “Postal Code” field can be stored in a zip variable.

10. Say no to renames

To synchronize two pieces of code, do not rename the variables; better redefine them with #define. Create more synonyms for the same variable in different files to prevent text searching.

11. Bypass the ban on global variables.

To do this, define a static global structure containing all the variables you need and name it EverythingYoullEverNeed. In a function, pass this structure (or better, a pointer to it called handle) to create the illusion of the absence of global variables.

12. Overload operators

The remarkable property of operator overloading allows you to create your own operators +, -, /, *, completely unrelated to arithmetic. After all, if Stroustrup uses shift operators (>> and <<) for stream I / O, how are you worse?

13. #define & #ifdef

As can be seen from the preceding paragraphs, the preprocessor directives deserve a separate ode of grateful masking; hardly anything else makes it possible to bring so much confusion into the code. The #define expressions are wonderfully disguised as functions and variables. Creative use #ifdef allows you to use different versions of a function, depending on the order in which quantities and header files are included. Try to figure out what the following code does:

#ifndef DONE
#ifdef TWICE
// put stuff here to declare 3rd time around
void g(char* str);
#define DONE
#else // TWICE
#ifdef ONCE
// put stuff here to declare 2nd time around
void g(void* str);
#define TWICE
#else // ONCE
// put stuff here to declare 1st time around
void g(std::string str);
#define ONCE
#endif // ONCE
#endif // TWICE
#endif // DONE


14. Compiler Directives

Another thing that is convenient for changing the behavior of the code - this is why they were created.

15. Distracting maneuvers

Spice up your code with unused variables and undisclosed methods — just don't remove the code that has become unnecessary. The justification for this may be that this code may still be useful. Bonus for names similar to the code used - the accompanying person will mix them up.

Documentation



Any fool can tell the truth, but only an intelligent person can lie well

Compilers ignore comments and do not see the documentation, so you can do anything in them to confuse the poor fellow.

1. Lie

Well, you can not lie directly, just forget to update the comments when you update the code.

2. Document the obvious

Season the code with comments like / * increment i * /, at the same time avoid commenting on questionable places - the purpose of the method or the meaning of the actions performed.

3. “What,” not “why”

Comment only on the actions of your program, but not its purpose and purpose.

4. Avoid documenting the "obvious"

If you assume that your code will change in a certain way, in any case do not mention what you need to do. The people who came after you, there is nothing to climb to edit your code, not understanding it in every detail.

5. On the issue of documentation templates

Consider the proper use of function documentation prototypes: carefully copy templates from a function to a function, but never fill out the template fields. If you are forced to fill them in, make sure that the parameters of all functions are called the same, and their decryption has nothing to do with the actual function.

6. On the issue of project documentation

Suppose you need to implement some complex algorithm. Use the classic principle of software development: first, create a project of this algorithm. Write a very detailed (the more detailed, the better) document that would describe it step by step, in the form of a multi-level (minimum 5 levels) hierarchy of nested items with automatic numbering. Make sure that the result is at least 500 points. So, an example of one item can be

1.2.4.6.3.13 - Display all impacts for activity where selected mitigations can apply (short pseudocode omitted).

After that (yes, the focus is here) write the code, and for each such item create a separate method Act1_2_4_6_3_13 (). No, do not write comments in the code of the methods - because for this there is project documentation! Since the numbering in the original document changes automatically when editing a document, it would be difficult to keep the static naming of methods up to date. However, for you it will not be absolutely no work - after all, you do not seek to keep the document up to date. In fact, you should make every effort to destroy not only the document itself, but also all traces of its existence. However, you can leave one or two drafts carefully hidden in the closet under the old computers.

7. Units of measurement

Never document the units of measurement of variables and parameters - this is not so important in the calculations, but it is extremely important in the engineering work. Similarly, never comment on constants used in transformations, or on how to get values. A primitive, but effective way is to decorate the code with comments that indicate the wrong units. If you have a particularly dark mood, invent your own unit: name it after yourself or someone special and never define it explicitly. If you come to this, explain that you are using it to limit yourself to integer arithmetic and not to bother with fractional numbers.

8. Bugs

Never document bugs in someone else's code. If you suspect that there is a bug somewhere, keep it with you. If you have ideas on reorganizing the code, for God's sake, do not write them down. Think about what will happen if your commentator sees the author of the code, the guide, the client? Yes, you can dismiss! However, the anonymous comment “It needs to be fixed” works wonders, especially if it is not clear what it refers to.

9. Description of variables

Never - hear, never! - do not document variables when they are declared. Facts about the use of a variable, its boundaries and permissible values, accuracy, units of measure, output format, input rules, etc. should be obvious from the code. If you are obliged to write comments, infect the body of the procedures with them, but in no case do not declare variables.

10. Derogatory comments

Hack on the bud any attempts to attract employees of other companies, generously decorating your code with comments insulting their honor and dignity:

* Software Services Inc.; , ,
* 50 <math.h>


If possible, place such comments in important pieces of code, mixing them with semantic comments, so that attempts to neutralize them are as complicated as possible.

11. Comment as if it is COBOL on punched cards.

Abandon the possibilities of development environments, do not believe the rumors that the definitions of functions and variables are always in one click away from their use and rely on the code written in Visual Studio 6.0 to be accompanied by edlin or vi tools. Draconian commentary requirements are a great way to bury code.

12. Monty Python style comments.

A comment to the makeSnafucated method must consist of exactly one line: / * make snafucated * /. Never define anywhere what snafucated is - any fool knows.

13. Outdated code

Never rely on version control systems to restore obsolete code - just do not delete it. Never comment on whether the new code should replace the old one or supplement it, why the old code did not suit someone, whether it worked at all, etc. Comment on the old code as / * * / instead of // on each line - it is easier to take it as valid and waste energy on its support.

Source: https://habr.com/ru/post/99146/


All Articles