Address: luopq.com/2016/02/21/… , please specify
Function is the most basic unit to realize the function of the program, and every program is composed of one of the most basic functions. Writing a function well is the most critical step to improve the quality of program code. This article on the preparation of the function, from the function naming, code distribution, skills and other aspects, talk about how to write a readable, easy maintenance, easy to test the function.
named
Let’s start with naming, which is the first step to readability. Naming variables and functions has always been a sore point for developers, especially for non-English speakers. Here are some thoughts and feelings about how to name functions:
Adopt uniform naming rules
Before we talk about how to give functions accurate and elegant names, it is important to have a common naming convention. This is the most basic rule for improving code readability. PASCAL and hump nomenclature are two of the most popular conventions of the moment. They may vary from language to language, but one thing to remember is to keep your team and individual styles consistent. PASCAL nomenclature is simply: when more than one word forms a name, capitalize the first letter of each word. Such as:
public void SendMessage ();
public void CalculatePrice ();
Copy the code
In C#, this naming is commonly used for classes, attributes, functions, etc. In JS, constructors are also recommended to be named this way.
Camelback nomenclature is similar to PASCAL nomenclature. When multiple words form a name, the first word is all lowercase and the first letter of each word is capitalized. Such as:
var sendMessage = function () {};
var calculatePrice = function () {};
Copy the code
Hump nomenclature is used for fields, local variables, function parameters, and so on. In JS, functions are also commonly named in this way.
The naming convention is not absolute. The most important thing is to follow team conventions and language conventions.
Describe everything the function does as completely as possible
Some developers may find short function names to be cleaner and more comfortable to look at than long ones. But in general, the shorter the function name, the more abstract the description. Function users’ first impression of a function is its name, and hence its function. We should try to describe everything the function does to prevent potential errors caused by ignorance or misunderstanding. For example, suppose we make a function to add comments, and then return the total number of comments. What is the appropriate name?
Var count = function addComment() {}; Var count = function addCommentAndReturnCount() {};Copy the code
This is just a simple example, and we may encounter more complex situations in actual development. The single responsibility principle is the principle that we should follow when developing functions, but when it is not possible to achieve a single responsibility for a function, remember that the function name should describe everything as possible. When you can’t name a function, you should analyze whether the function is written scientifically and how to optimize it.
Use accurate descriptive verbs
This is a difficult point for non-Native English language developers, and the most important thing to improve your ability in this area is to improve your vocabulary and read good code to gain experience. Here are a few of my own thoughts: 1. Don’t use generic words. Many developers use generic verbs to name functions. We often get data in various ways during development, but using GET in each way is a bit abstract. Specific how to name, to specific analysis: (1) simple return data
Person.prototype.getFullName = function() {
return this.firstName = this.lastName;
}Copy the code
(2) Remote data acquisition
var fetchPersons = function () {
...
$.ajax({
})
}Copy the code
(3) Load data from local storage
var loadPersons = function () {};
Copy the code
(4) Obtain data through calculation
var calculateTotal = function () {};
Copy the code
(5) Find data from array
var findSth = function (arr) {};
Copy the code
(6) Generated or obtained from some data
var createSth = function (data) {};
var buildSth = function (data) {};
var parseSth = function(data) {};Copy the code
This is a simple example, we usually encountered in the development of the situation will be much more complex, the key is to rely on the accumulation of words, read more excellent source code
The following is the arrangement of some common antithesis words, we can refer to use
add/remove increment/decrement open/close
begin/end insert/delete show/hide
create/destory lock/unlock source/target
first/last min/max star/stop
get/put next/previous up/down
get/set old/newCopy the code
Make naming rules for different projects and requirements
This is also important, especially in teamwork, where different projects and requirements may result in different naming conventions. For example, we usually use the verb-object structure, that is, the verb before the noun after the disaster. But on some projects, such as data interface, some teams use the name first and the verb second, for example:
public static Product[] ProductsGet(){};
public static Product[] ProductsDel(){};
public static Customer[] CustomerDel(){};
public static Customer[] CustomerDel(){};
Copy the code
The advantage of this is that when you look at the front noun, such as ProductsGet, you will quickly know that this is a product-specific data interface. Of course, this is not absolute, but the key is to work together and follow the same set of naming rules.
Function parameters
When calling a function, users must strictly follow the parameters defined by the function, which is crucial for the ease of use and testability of the function. Let me give you some ideas on how to optimize function parameters from several aspects.
The number of arguments
There is no doubt that the more arguments a function has, the worse the usability of the function is, because the user has to enter the arguments in strict order of the argument list, and if one parameter is mistyped, the result will be unexpected. But is it always better to have as few arguments as possible? Let’s look at the following example:
var count = 0; Var unitPrice = 1.5; . . var calculatePrice = function () { return count * unitPrice; }Copy the code
In this example, we calculate the price through the function calculatePrice, which takes no parameters and calculates directly through the two global variables unitPrice and count. The definition of this function is very convenient for the user, and can be called directly without entering any parameters. But there are potential bugs: global variables can be changed to other values elsewhere, difficult to unit test, and so on. So, this function can pass in quantity and price information:
var calculatePrice = function(count, unitPrice) {
return count * unitPrice;
}Copy the code
In this way, function users pass in parameters to call when using, avoiding the possible problems of global variables. It also reduces coupling and improves testability, so you don’t have to rely on global variables when testing.
Of course, as long as the function does not depend on global variables and testability, it is better to have fewer arguments. As a reference, the Code Book limits functions to seven parameters. Sometimes, it is inevitable to use more than 10 functions. In this case, we can consider constructing a class with similar parameters. Let’s look at a typical example. I believe you must have done such a function at ordinary times, list filtering, which involves various conditions of filtering, sorting, paging and other functions, if the parameters are listed one by one must be very long, for example:
var filterHotel = function (city, checkIn, checkOut, price, star, position, wifi, meal, sort, pageIndex) {}
Copy the code
This is a function that filters hotels, with parameters such as city, check-in and check-out times, price, star rating, location, wifi, breakfast, sort, page number, etc. The actual situation may be much more. In the case of a large number of parameters, we can consider extracting some similar parameters into classes:
function DatePlace (city, checkIn, checkOut){
this.city = city;
this.checkIn = checkIn;
this.checkOut = checkOut
}
function HotelFeature (price, star, position, wifi, meal){
this.price = price;
this.star = star;
this.position = position;
this.wifi = wifi;
this.meal = meal;
}
var filterHotel = function (datePlce, hotelFeature, sort, pageIndex) {};
Copy the code
Multiple parameters are extracted into objects. Although there are more objects, function parameters are clearer and easier to call.
Try not to use bool as a parameter
Sometimes, we write cases where bool is used as a parameter, for example:
Var getProduct = function(finished) {if(finished){} else{}};Copy the code
Without the comment, the user would see code like getProduct(true) and have no idea what true means, and would have to look at the function definition to see how it is used. This means that the function is not clear enough and should be optimized. There are usually two ways to optimize it: (1) split the function into two functions getFinishedProduct and getUnFinishedProduct (2) convert bool to a meaningful enumeration getProduct(ProductStatus)
Do not modify input parameters
If the input parameters are modified within a function, this can be potentially buggy, and the user is unaware that the function parameters are being modified after the call. The correct way to use input parameters is to pass them in only for function calls. If changes are unavoidable, be sure to mention them in the comments.
Try not to use output parameters
Using output parameters shows that this function does more than one thing, and that it can be confusing to use. The right way to do it is to break up the function so that it only does one thing.
Writing a function body
Function body is the whole logic of function function, is the most critical place of a function. Here are some personal thoughts about functional coding.
Related operations are put together
Sometimes we perform a series of operations within a function to accomplish a function, such as:
var calculateTotalPrice = function() {
var roomCount = getRoomCount();
var mealCount = getMealCount();
var roomPrice = getRoomPrice(roomCount);
var mealPrice = getMealPrice(mealCount);
return roomPrice + mealPrice;
}Copy the code
This code calculates the room rate and breakfast rate, and then adds the two together to return the total price. At first glance, this code looks fine, but when we analyze the code, we first get the number of rooms and the number of breakfasts, and then calculate the price of each by the number of rooms and the number of breakfasts. In this case, the number of rooms and the code for calculating room prices are split in two places, as is the calculation of breakfast prices. That is, two pieces of code that are related are scattered all over the place, so that the code doesn’t read logically and is not well organized. We should keep related statements and actions together to make it easier to refactor the code. We modify as follows:
var calculateTotalPrice = function() {
var roomCount = getRoomCount();
var roomPrice = getRoomPrice(roomCount);
var mealCount = getMealCount();
var mealPrice = getMealPrice(mealCount);
return roomPrice + mealPrice;
}Copy the code
We put the related operations together so that the code looks cleaner and is easier to refactor.
Minimize code nesting
It’s common to write if, switch, or for statements, and we’ve certainly written multiple nested if or for statements. If you have more than three nested statements in your code, it becomes very difficult to read. We should avoid nesting multiple layers of code, preferably no more than two. Here are some of the techniques or methods I use to reduce nesting.
If statement nesting problem
Multi-layer if statement nesting is common. What’s a good way to reduce nesting? If there is a condition under which it is possible to terminate a function directly, that condition should be the first. Let’s look at the following example.
if(condition1) {
if(condition2){
if(condition3){
}
else{
return;
}
}
else{
return;
}
}
else {
return;
}Copy the code
This code has three layers of nested if statements, which seems very complicated. We can extract the last return to the first.
if(! condition1){ return; } if(! condition2){ return; } if(! condition3){ return; } //doSthCopy the code
Condition1 = false condition1 = false condition1 = false condition1 = false condition1 = false condition1
Note: Normally, we write if statements with the condition true in front of them, which is more consistent with our thinking habits. In the case of multiple levels of nesting, reducing the nesting of if statements should be a priority
Conditional statements are generally unavoidable. Sometimes, if we want to judge a lot of conditions, we will write a lot of if-elseif statements, nested, more trouble. If we ever add a new requirement, we have to add an if branch statement, which is not only difficult to modify, but also prone to error. The table driven approach proposed in The Code Book can effectively solve the problem caused by the if statement. Let’s look at this example:
If (condition == "case1"){return 1; } elseif(condition == "case2"){return 2; } elseif(condition == "case3"){return 3; } elseIf (condition == "case4"){return 4; }Copy the code
If we add another case, we need to add another if branch, which may cause potential problems. How to optimize this code? We can use a Map or Dictionary to Map each case to the corresponding value.
var map = {
"case1":1,
"case2":2,
"case3":3,
"case4":4
}
return map[condition];
Copy the code
With map optimization, the entire code is not only more concise, but also easier to modify and error-resistant. Of course, many times our conditional statements are not so simple and may involve complex logical operations. You can refer to Chapter 18 of the Code Book for a detailed description.
When calling multiple layers of nesting for a function, we can also extract the inner nesting into a new function and then call that function, so that the code is clearer.
For loop nesting optimization
Nested for loop compared to the if is more complex nested, would be more trouble to read, tell me about what time to pay attention to things: 1, the maximum of two layer 2, extracting the inner for loop nested loops in the new function 3, multi-layer loop, not simple status index variable named I, j, k, etc., easy to cause confusion, to have specific meaning
Extract complex logic and semantically
Sometimes, we will write some complicated logic, the reader may not know what to do, in this case, should extract the complex logic code.
if (age > 18 && gender == "man") {
//doSth
}Copy the code
This code indicates that if you are older than 18 and male, you can doSth, but it is still not clear enough to extract it
var canDoSth = function (age, gender){ return age > 18 && gender == "man"; }... . . if(canDoSth(age, gender)){ //doSth }Copy the code
There is an extra function, but the code is cleaner and more semantic.
conclusion
This article from function naming, function parameters and function code writing three aspects about how to write a good feeling and ideas of a function. There are a lot of specific situations mentioned in the article. Of course, there will be more complicated situations in daily coding, which MAY not have occurred to me at the moment. I simply summed up: 1 and accurately on the variable, function name, don’t have to repeat logic code 3, 2 functions don’t more than 20 lines, the number of rows 20 lines here is just a probably, is not necessarily the number 4, the decrease of nesting I believe you will be a lot about this aspect of experience, welcome to communicate and jointly improve code quality.