Column | chapter nine algorithm
Url | http://www.jiuzhang.com
Just as food may smell before it rots. Code smell also occurs when code has hidden problems. This is called code smell, and it exists in the overall structure and design phase of the code, indicating that there may be a deeper problem in a code block or in a common programming pattern.
Code smells are often thought of as a sign that a piece of code needs to be refactored, but that doesn’t mean the code is buggy or useless. In general, code blocks with smelly code work fine, but are often difficult to maintain and extend, which can lead to technical problems, especially in large projects.
So what are some common code odors? And how to solve it? Here we highlight the 10 most common code odors and how to deodorize them.
1. The tightly coupled
Existing problems
Tight coupling is when two objects depend on each other’s data or functions, and if you modify one of them, the other also needs to be modified. When two objects are too tightly coupled, changing the code can be a nightmare, and bugs are more likely to be introduced with each change.
Such as:
In this case, the Worker and Bike classes are tightly coupled. What if one day you want to drive to work instead of riding your bike? You must go into the Worker class and replace all code related to the Bike class with code related to the Car class. It can get messy and easy to make mistakes.
The solution
You can reduce the coupling by adding an abstraction layer. In this case, the Worker class can not only ride a bicycle, but also drive a car, drive a truck, and even ride a motorcycle. These are all vehicles, aren’t they? So you can create a vehicle interface that allows you to insert and modify different types of vehicles depending on your needs.
Such as:
2. God objects
Existing problems
A God object is a large class or module that contains too many variables and functions. Both “knowing too much” and “doing too much” can cause problems for two reasons. First, other classes or modules become overly dependent on data (tightly coupled). Second, because all the code is crammed into one place, the overall structure is cluttered.
The solution
Take a God object, separate its data and functions according to its problems, and convert these groups into objects. It might be better to break it down into many smaller objects than god objects.
For example, suppose you have a huge User class:
You can convert this to a combination of the following:
This way, the next time you need to modify the login process, you don’t have to go through the huge User class, but through the easily managed Credentials class!
3. Long functions
Existing problems
As the name implies, a long function is a function that is too long. While there is no specific number for how many lines of code are “too long” for a function, you’ll know if it’s too long when you see the function. This is almost a more serious version of the God object problem, where a long function contains too many implementations.
The solution
Long functions should be decomposed into many subfunctions, each of which is designed to handle a single task or problem. Ideally, the original long function would become a list of child function calls, making the code cleaner and easier to read.
4. Too many parameters
Existing problems
Having too many arguments in the constructor of a function or class can cause problems for two reasons. First, it makes the code harder to read and the testing harder. Second, and more importantly, this means that the function is too vague and burdened with too much functionality.
The solution
Although “too much” is subjective for argument lists, we recommend keeping an eye on and avoiding any function with more than three arguments. Of course, it is sometimes permissible for a function to have five or even six arguments, if for a reasonable reason.
In most cases, there is no better way to decompose the function into two or more distinct functions. Unlike “long functions,” this problem cannot be solved simply by replacing code with subfunctions, because it is the function itself that needs to be decomposed into separate subfunctions, each of which needs to contain its own functionality.
5. Name ambiguous identifiers
Existing problems
One or two letters of the variable name, name of the function has no obvious significance, and too much of the name of the class, use the variable type tag variable names (for example, b_isCounted Boolean variables), worst of all, the mixed in a code to use a different naming rules, all of which will cause the code difficult to read, it is difficult to understand and difficult to maintain.
The solution
Naming variables, functions, and classes is a difficult skill to learn. If you are working on an existing project, take a close look at the way identifiers are named. If there is a naming style guide, keep it in mind and stick to it. If it’s a new project, consider developing your own naming style and stick to it.
In general, variable names should be short but descriptive. Function names should usually have at least one verb, and function names should show what the function does, but not too many words. The same goes for class names.
6. The magic number
Existing problems
You’re looking through some code someone else has written, and you find some hard-coded numbers. They may be part of an if statement, or part of some unintelligible calculation that doesn’t seem to make any sense, and you need to modify the module, but you can’t understand what the numbers mean, which can be very frustrating.
The solution
These so-called “magic numbers” should be avoided at all costs when programming. Hard-coded numbers make sense when they’re written, but they quickly lose all meaning, especially if someone else is trying to maintain your code.
One solution is to leave a comment on the numbers, but a better choice is to convert magic numbers to constant variables (for calculation) or enumerations (for if statements and switch statements). By giving magic numbers a name, the code is readable at a glance and less prone to errors.
7. Deep nesting
Existing problems
There are two main types of statements that can cause deeply nested code: loops and conditional statements. Deeply nested code isn’t always bad, but it can be problematic because it’s hard to understand (especially if variables aren’t well named) and even harder to change.
The solution
If you find yourself writing a double, triple, or even quadruple for loop, your code will probably try to find data outside of its scope. So you should provide a way to request data ** via an object or module function call that contains the data. **
On the other hand, deeply nested IF statements often indicate that you are trying to deal with too many logical blocks in a single function or class. In fact, deep nesting and long functions often go hand in hand. If your code has a large number of switch statements or nested if-then-else statements, you may need to implement a state machine or policy pattern.
8. Unhandled exceptions
Existing problems
Exceptions are very powerful, but they can be easily abused. Incorrect use of throw-catch statements can lead to significantly more difficult debugging. For example, ignoring or masking caught exceptions.
The solution
Do not ignore or mask caught exceptions, but print out the exception and its invocation information so that the debugger can find the error. If your program silently fails, you may have a headache in the future! In addition, I prefer to output specific exception messages rather than all exceptions.
9. Duplicate code
Existing problems
You execute the same logical block in multiple unrelated parts of the program, and then find that you need to change the logical block, but you don’t remember all the places where the block was executed. Assuming you end up changing only five places when in fact there are eight places that need to be changed, this will result in an error.
The solution
The first choice for solving repetitive code problems is to convert to functions. Suppose you are developing a chat application and you write it like this:
Elsewhere in the code, you find that you need to perform the same “is this user online?” Check. Instead of copying and pasting the code block, place it in a function:
This way, you can use the isUserOnline () function anywhere in the code to check. If you need to modify this block of logic, just modify the method and apply it everywhere the method is called.
10. Lack of notes
Existing problems
There are no comments anywhere in the code. There are no functional comments for functions, no overview of the use of classes, no explanation of algorithms, and so on. One could argue that well-written code doesn’t need comments, but the truth is that even the best written code is not as easy to understand as comments.
The solution
An easy-to-maintain code block is one where the code is written well enough that it doesn’t need comments, but it still has comments. When writing comments, remember that your goal is to explain why the code block exists, not what the code block is doing. Comments can help you better understand your own code and others’ code and reduce your workload, so don’t ignore them.
How to write well-styled code
It is obvious that most non-standard code is the result of ignoring good programming principles and code style. If you stick to the **DRY principle (Don’t repeat Yourself) ** you can eliminate most of the code duplication, while mastering the single responsibility principle can avoid creating huge God objects.
Don’t take this lightly. If you can’t read your own code at a glance, let alone anyone else?
Welcome to follow my wechat official account: Ninechapter.
Elite programmer exchange community, regular release of interview questions, interview skills, job information, etc