The art of writing small and plain functions


曾经在实习的时候徽大大布置的任务,其中部分由徽大大翻译,部分由我翻译。


原文地址:https://rainsoft.io/the-art-of-writing-small-and-plain-functions/?utm_source=codropscollective

The complexity of software applications is growing. The code quality is important in order to make the application stable and easily extensible.

随着应用软件的复杂度的不断增长,代码的质量在增加应用的稳定性和易扩展性方面起到了至关重要的作用。

Unfortunately almost every developer, including myself, in his career faced with bad quality code. And it’s a swamp. Such code has the following harmful characteristics:

然而不幸的是,包括我自己在内的每一位开发者在其职业生涯中都要不可避免地面对一些糟糕的代码。这些代码都有如下的不好的特点:

  1. Functions are too long and do too many things
  2. Often functions have side effects that are difficult to understand or even debug
  3. Unclear naming of functions and variables
  4. Fragile code: a small modification unexpectedly breaks other application components
  5. Poor or missing code coverage

1.函数太长且实现了太多的功能

2.难以理解和调试

3.复杂多样的函数名称和变量声明

4.脆弱的代码:一个小小的修改可能会意外的导致其他组件崩溃

5.代码测试覆盖率低

It sounds very common: “I don’t understand how this code works”, “this code is a mess”,”it’s hard to modify this code” and the like.

我们可能经常会听到:“我真的不明白这个代码是如何执行的”,“这个代码真是坑”,“这个代码太难改了”诸如此类的抱怨。

Once I had a situation when my colleague quit his job because he dealt with a REST API on Ruby that was hard to maintain. He received this project from previous team of developers.

曾经有一次我的同事放弃了他的工作,只因为他要处理的一个用Ruby编写的REST API太难维护。而那个项目是由之前的开发团队手中接手的。

Fixing current bugs creates new ones, adding new features creates a new series of bugs and so on (fragile code). The client didn’t want to rebuild the application with a better design, and the developer made the correct decision to quit.

修改现有的bug会产生新的更多的bugs,添加一个新的功能会引发一连串的连锁反应,产生很多bugs等等诸如此类的情况(这也就是我们所说的fragile codes)。如果客户不想重构更好的应用设计,那么作为开发者最明智的决定就是退出。

Ok, such situations happen often and are sad. But what do to?

好吧,这个坑就是这样无处不在让人头疼,那么作为程序开发者的我们,该如何去应对或者说尽量避免这种情况的发生呢?

The first to keep in mind: simply making the application run and taking care of the code quality are different tasks.

牢记在心的一件事:代码的可运行性和注重代码质量是两件事。

On one side you implement the app requirements. But on the other side you should take time to verify if any function doesn’t have too much responsibility, write comprehensive variable and function names, avoid functions with side effects and so on.

一方面你需要完成应用开发需求,但是另一方面你要花时间去验证某个函数是否做了很多事情。命名容易理解的变量和函数名称,避免函数的耦合性等等。

The functions (including object methods) are the little gears that make the application run. First you should concentrate on their structure and composition. The current article covers best practices how to write plain, understandable and easy to test functions.

函数(包括对象方法)是保证应用运行的最小单元。首先你应该专注于他们的结构和组成。本文将通过实例很好的讲述了如何写出一个单一可读和可测试的函数。

Functions should be small. Really small 函数要小且足够的小

Big functions that have a lot of responsibility should be avoided and split into small ones. Big black box functions are difficult to understand, modify and especially test.

我们应该避免庞大的拥有很多功能的大函数,应该将其分解成相应的小函数。庞大的黑盒函数是很不可读,难以修改和不易测试的。

Suppose a scenario when a function should return the weight of an array, map or plain JavaScript object. The weight is calculated by summing the property values:

假设一个场景:当一个功能函数需要通过返回数组,map或者简单的js对象的值。而这个值是通过所有属性值的和而得到的。

  • 1 point for null or undefined
  • 2 points for a primitive type
  • 4 points for an object or function.
  • 未定义和null值表示1分
  • 一个简单对象是2分(含有零个或多个的key/value对)
  • 函数和自定义对象是4分

For example the weight of an array [null, ‘Hello World’, {}] is calculated this way: 1 (for null) + 2 (for string primitive type) + 4 (for an object) = 7.

例如一个对象集合是 [null,’hello world’,{}],计算公式是:1(for null) + 2(for string) + 4(for an object)= 7

Step 0: The initial big function 原始的庞大函数

Let’s start with the worst practice. The logic is coded within a single big function

让我们从一个反面例子开始。将所有逻辑放在一个庞大的函数里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function getCollectionWeight(collection) {  
let collectionValues;
if (collection instanceof Array) {
collectionValues = collection;
} else if (collection instanceof Map) {
collectionValues = [...collection.values()];
} else {
collectionValues = Object.keys(collection).map(function (key) {
return collection[key];
});
}
return collectionValues.reduce(function(sum, item) {
if (item == null) {
return sum + 1;
}
if (typeof item === 'object' || typeof item === 'function') {
return sum + 4;
}
return sum + 2;
}, 0);
}
let myArray = [null, { }, 15];
let myMap = new Map([ ['functionKey', function() {}] ]);
let myObject = { 'stringKey': 'Hello world' };
getCollectionWeight(myArray); // => 7 (1 + 4 + 2)
getCollectionWeight(myMap); // => 4
getCollectionWeight(myObject); // => 2

The problem is clearly visible. getCollectionWeight() function is too big and looks like a black box full of surprises.

这个问题很明确。getCollectionWeight()函数太大并且看起来像一个充满惊喜的黑洞

You probably find it difficult to understand what it does from the first sight. And imagine a bunch of such functions in an application.

当你第一眼看到他的时候你可能很难理解他到底在干嘛。想象一下在你的应用中有这样一大坨函数。

When you work with such code, you waste time and effort. On the other side the quality code doesn’t make you feel uncomfortable. Quality code with small and self-explanatory functions is a pleasure to read and easy to follow.

当你处理这种代码的时候,你会花费很多精力和时间。另外,这种质量的代码让人看起来很不爽。因为去阅读和理解易懂简小的高质量代码本身就是一种美的享受。

Step 1: Extract weight by type and drop magic numbers按照参数和类型简化代码的权重

Now the goal is to split the big function into smaller, independent and reusable ones. The first step is to extract the code that determines the weight of a value by its type. This new function will be named getWeight().

现在我们的目标是将整个大函数分割成小的独立的、可重用的函数。第一步就是分析代码将获取类型的大小值的功能分割出来,我们将整个函数命名为getWeight()

Also take a look at the magic weight numbers: 1, 2 and 4. Simply reading these numbers without knowing the whole story does not provide useful information. Fortunately ES2015 allows to declare const read-only references, so you can easily create constants with meaningful names to knockout the magic numbers.

另外我们来看一下整个功能大小的值:1,2,4.显然这些书和整个函数功能没有任何关系。正好ES2015提供了声明const的引用,因此可以轻松的创建一个常量去声明这些固定的值。

Let’s create the small function getWeightByType() and improve getCollectionWeight() accordingly:

让我们来创建一个更小的函数getWeightByType() 并优化一下getCollectionWeight() 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 // Code extracted into getWeightByType()
function getWeightByType(value) {
const WEIGHT_NULL_UNDEFINED = 1;
const WEIGHT_PRIMITIVE = 2;
const WEIGHT_OBJECT_FUNCTION = 4;
if (value == null) {
return WEIGHT_NULL_UNDEFINED;
}
if (typeof value === 'object' || typeof value === 'function') {
return WEIGHT_OBJECT_FUNCTION;
}
return WEIGHT_PRIMITIVE;
}
function getCollectionWeight(collection) {
let collectionValues;
if (collection instanceof Array) {
collectionValues = collection;
} else if (collection instanceof Map) {
collectionValues = [...collection.values()];
} else {
collectionValues = Object.keys(collection).map(function (key) {
return collection[key];
});
}
return collectionValues.reduce(function(sum, item) {
return sum + getWeightByType(item);
}, 0);
}
let myArray = [null, { }, 15];
let myMap = new Map([ ['functionKey', function() {}] ]);
let myObject = { 'stringKey': 'Hello world' };
getCollectionWeight(myArray); // => 7 (1 + 4 + 2)
getCollectionWeight(myMap); // => 4
getCollectionWeight(myObject); // => 2

Looks better, right?

看起来好一点了,对吧?

getWeightByType() function is an independent component that simply determines the weight by type. And reusable, as you can execute it in any other function.

getWeightByType() 这个函数独立成一个部件,能够计算出当前的类型,可复用,你可以在其他任何函数里面调用。

getCollectionWeight() becomes a bit lighter.

getCollectionWeight()变得轻巧了很多。

WEIGHT_NULL_UNDEFINED, WEIGHT_PRIMITIVE and WEIGHT_OBJECT_FUNCTION are selfexplanatory constants that describe the type weights. You don’t have to guess what 1,2 and 4 numbers mean.

三个常量的声明似乎描述的更语义化,你不需要去猜测这几个值的意思。

Step 2: Continue splitting and make it extensible 继续分割,让它可扩展

However the updated version still has drawbacks.

然而修改之后的版本仍有缺陷。

Imagine that you have the plan to implement the weight evaluation of a Set or even other custom collection. getCollectionWeight() will grow fast in size, because it contains the logic of collecting the values.

我们可以想象我们可能要扩展计算的值的数据类型比如set或者其他自定义的集合类型,getCollectionWeight()的体积也会变大,因此我们需要一个计算集合值的逻辑。

Let’s extract into separated functions the code that gathers values from maps getMapValues() and plain JavaScript objects getPlainObjectValues(). Take a look at the improved version:

让我们开始分割函数吧。函数getMapValues()和getPlainObjectValues()分别计算两种值。让我们看一下分割之后的版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function getWeightByType(value) {  
const WEIGHT_NULL_UNDEFINED = 1;
const WEIGHT_PRIMITIVE = 2;
const WEIGHT_OBJECT_FUNCTION = 4;
if (value == null) {
return WEIGHT_NULL_UNDEFINED;
}
if (typeof value === 'object' || typeof value === 'function') {
return WEIGHT_OBJECT_FUNCTION;
}
return WEIGHT_PRIMITIVE;
}
// Code extracted into getMapValues()
function getMapValues(map) {
return [...map.values()];
}
// Code extracted into getPlainObjectValues()
function getPlainObjectValues(object) {
return Object.keys(object).map(function (key) {
return object[key];
});
}
function getCollectionWeight(collection) {
let collectionValues;
if (collection instanceof Array) {
collectionValues = collection;
} else if (collection instanceof Map) {
collectionValues = getMapValues(collection);
} else {
collectionValues = getPlainObjectValues(collection);
}
return collectionValues.reduce(function(sum, item) {
return sum + getWeightByType(item);
}, 0);
}
let myArray = [null, { }, 15];
let myMap = new Map([ ['functionKey', function() {}] ]);
let myObject = { 'stringKey': 'Hello world' };
getCollectionWeight(myArray); // => 7 (1 + 4 + 2)
getCollectionWeight(myMap); // => 4
getCollectionWeight(myObject); // => 2

If you read getCollectionWeight() now, you find much easier figure out what it does. It looks like an interesting story.

当你现在再来阅读getCollectionWeight()这个函数的时候,你会发现你能轻而易举的发现函数到底在做什么。非常有趣的变化。

Every function is obvious and straightforward. You don’t waste time digging to realize what the code does. That’s how the clean code should be.

每一个函数都清晰直观,你不用花时间去研究他在做什么,这就是精干的代码应该有的样子。

Step 3: Never stop to improve不要停止重构

Even at this step you have a lot of space for improvement!

每一个逻辑都有优化的空间。

You can create getCollectionValues() as a separated function, which contains the if/else statements to differentiate the collection types:

你可以创建一个函数 getCollectionValues()作为独立的模块。用来通过判定语句区分不同的数据类型。

1
2
3
4
5
6
7
8
9
function getCollectionValues(collection) {  
if (collection instanceof Array) {
return collection;
}
if (collection instanceof Map) {
return getMapValues(collection);
}
return getPlainObjectValues(collection);
}

Then getCollectionWeight() would become truly plain, because the only thing it needs to do is: get the collection values getCollectionValues() and apply the sum reducer on it.

getCollectionWeight()也因为只需要做一件事情而变得真正的纯粹:获取getCollectionValues()函数返回的值,并将其累加起来

You can also create a separated reducer function:

你也可以创建一个迭代函数循环的。

1
2
3
function reduceWeightSum(sum, item) {  
return sum + getWeightByType(item);
}

Because ideally getCollectionWeight() should not define functions.

因为其实理想的getCollectionWeight()函数内是不应该去定义任何函数的。

In the end the initial big function is transformed into the following small functions:

最后我们来看,最初这个庞大的函数被我们转换成了一个个小函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function getWeightByType(value) {  
const WEIGHT_NULL_UNDEFINED = 1;
const WEIGHT_PRIMITIVE = 2;
const WEIGHT_OBJECT_FUNCTION = 4;
if (value == null) {
return WEIGHT_NULL_UNDEFINED;
}
if (typeof value === 'object' || typeof value === 'function') {
return WEIGHT_OBJECT_FUNCTION;
}
return WEIGHT_PRIMITIVE;
}
function getMapValues(map) {
return [...map.values()];
}
function getPlainObjectValues(object) {
return Object.keys(object).map(function (key) {
return object[key];
});
}
function getCollectionValues(collection) {
if (collection instanceof Array) {
return collection;
}
if (collection instanceof Map) {
return getMapValues(collection);
}
return getPlainObjectValues(collection);
}
function reduceWeightSum(sum, item) {
return sum + getWeightByType(item);
}
function getCollectionWeight(collection) {
return getCollectionValues(collection).reduce(reduceWeightSum, 0);
}
let myArray = [null, { }, 15];
let myMap = new Map([ ['functionKey', function() {}] ]);
let myObject = { 'stringKey': 'Hello world' };
getCollectionWeight(myArray); // => 7 (1 + 4 + 2)
getCollectionWeight(myMap); // => 4
getCollectionWeight(myObject); // => 2

That’s the art of writing small and plain functions!

这就是编写小而单纯的函数的艺术!

After all these code quality optimizations, you get a bunch of nice benefits:

通过以上所有的这些代码质量的优化,你可以收获很多益处:

  • The readability of getCollectionWeight() increased by self-explanatory code
  • The size of getCollectionWeight() reduced considerable getCollectionWeight() function is now protected from fast growth if you plan to implement the weight calculation of other collection types
  • The extracted functions are now decoupled and reusable components. Your colleague may ask you to import these nice functions into another project: and you can easily do that If accidentally a function generates an error, the call stack will be more precisebecause it contains the function names.
  • Almost instantly you could determine the function that makes problems The split functions are much easier to test and reach a high level of code coverage. Instead of testing one big function with all possible scenarios, you can structure your tests and verify each small function separately
  • You can benefit from CommonJS or ES2015 modules format. Create from extracted functions separated modules. This makes your project files lightweight and structured.
  • 自解释代码使函数getCollectionWeight()的可读性大大增强了
    • 函数getCollectionWeight()的体积明显减小了
    • 当你添加判定值的数量的时候,函数getCollectionWeight()保持稳定的增长的速度。
    • 分离出来的代码成为具有低耦合性和可复用性的组件。你的同事或许会请求你将这些非常棒的小组件应用到其他项目中去,这是轻而易举就可以实现的。
    • 如果一旦有代码报错,报错堆栈更清晰因为他包含了函数的具体名称。你可以轻而易举的判定出出错的部分。分割出来的代码更易测试并且可以达到一个很高的测试覆盖率,从而使代码的可测试性提高。相比于这个,测试巨大的函数是很糟糕的。你可以为每一个函数构造测试并且独立的进行验证工作。
    • 你可以按照CommonJS或者ES2015的模式去构造你的函数,将其分割成独立的小函数。这会使你的项目文件变得更加轻量和更有结构。
      These advantages help you survive in the complexity of the applications.
      这些优点将你从复杂的应用中拯救出来。

As a general rule, your functions should not be longer than 20 lines of code. Smaller - better.

通常的规则是你的函数不应该超过20行,并且越小越好。

I think now you want to ask me a reasonable question: “I don’t want to create functions for each line of code. Is there a criteria when I should stop splitting?” This is a subject of the next chapter.

我想你现在有一个情理之中的问题想要问我:“让我为每一个函数写一行代码我是极不情愿的。请问对于拆分的原则有什么标准么?”这将会是我们下一个环节要解答的问题。

2. Functions should be plain 函数功能要单一

Let’s relax a bit and think what is actually a software application?

让我们稍微放松一下然后仔细想想应用软件的实质是什么?

Every application is implementing a list of requirements. The role of developer is to divide these requirements into small executable components (namespaces, classes, functions, code blocks) that do a well determined task.

每个应用在本质上都是对一系列需求的实现,而开发者所扮演的角色就是将这些需求拆分成更小的可执行的可以更好的完成自身任务的模块(命名空间,类,函数,代码块)

A component consists of other smaller components. If you want to code a component, you need to create it from components at only one level down in abstraction.

一个组件包含了其他更小的组件们。如果你想编写编写其中一个组件,你需要将他从其他你创作的同一级别的组件中中抽象出来。

In other words, what you need is to decompose a function into smaller steps, but keep these steps at the same, one step down, level of abstraction. This is important because it makes the function plain and implies to “do one thing and do it well”.

换句话说,你需要做的就是将这些功能拆分成更小的步骤,但是需要保证这些小步骤是同样的,同一级别的,同等水平的抽象。这是非常重要的因为只有这样你才能使你的函数功能单一并且意味着你成功实现了“做一件事情并且把它做好”。

Why is this necessary? Because plain functions are obvious. Obvious means easy to read and modify.

说了这么多,为什么功能单一的代码是很重要的呢?因为清晰的代码的功能是显而易见的。而显而易见则意味着代码的易读性和易修改性。

Let’s follow an example. Suppose you want to implement a function that keeps onlyprime numbers (2, 3, 5, 7, 11, etc) in an array, removing non prime ones (1, 4, 6, 8, etc). The function is invoked this way:

让我们再来看一个例子。假设你想实现一个函数:去除数组中的合数(例如1,4,6,8等)而只保留其中的质数(例如2,3,5,7,11等等)。这个函数将会被这样调用:

getOnlyPrime([2, 3, 4, 5, 6, 8, 11]); // => [2, 3, 5, 11]

What are steps at one level down in abstraction to implement the functiongetOnlyPrime()? Let’s formulate this way:

那么函数getOnlyPrime()的实现在同一个抽象级别的步骤有多少呢?让我们一起用下面这种方式一步一步来实现;

To implement getOnlyPrime() function, filter the array of numbers using isPrime()function.

为了实现函数getOnlyPrime(),我们首先使用isPrime()函数来对数组中的数据进行过滤

Simply, just apply a filter function isPrime() over the array of numbers.

简单来说,就是创建一个过滤器函数isPrime() 对数组成员进行过滤。

Do you need to implement the details of isPrime() at this level? No, becausegetOnlyPrime() function would have steps from different level of abstractions. The function would take too much responsibility.

你需要的做的只是在这个抽象级别上实现isPrime() 的细节?不,你错了。因为getOnlyPrime()函数会有很多不同级别的抽象。这个函数包含太多的任务在身。

Having the plain idea in mind, let’s implement the body of getOnlyPrime() function:

在你的头脑中想象一下如何让这个函数变的单一。接下来让我们一起来实现getOnlyPrime()这个函数的主体部分。

1
2
3
4
function getOnlyPrime(numbers) {  
return numbers.filter(isPrime);
}
getOnlyPrime([2, 3, 4, 5, 6, 8, 11]); // => [2, 3, 5, 11]

As you can see, getOnlyPrime() is plain and simple. It contains steps from a single level of abstraction: .filter() array method and isPrime().

正如你所看到的一样,getOnlyPrime()这个函数是短小而又单一的。它包含了一个单一抽象级别的函数:.filter()数组方法isPrime()

Now is the time move one level down in abstraction.

现在是时候再降低一下函数的抽象级别了。

The array method .filter() is provided by JavaScript engine and use it as is. Of course the standard describes exactly what it does.

.filter()这个方法提供了一个原生的javascript引擎。当然标准的描述是他做了什么。

Now you can detail into how isPrime() should be implemented:

现在你可以具体研究 isPrime()应该怎样被实现:

1
2
To implement isPrime() function that checks if a number n is prime, verify if any number from 2 to Math.sqrt(n) evenly divides n.
实现isPrime()这个函数就是要检查一个数n是否是素数,依次判断从2开始到√n之间的任何一个整数能否被n整除。

Having this algorithm (yet not efficient, but used for simplicity), let’s code isPrime()function:

使用已有的算法来实现isPrime()函数(虽然效率不高,但是调用却很简单)。让我们一起来编写它的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function isPrime(number) {  
if (number === 3 || number === 2) {
return true;
}
if (number === 1) {
return false;
}
for (let divisor = 2; divisor <= Math.sqrt(number); divisor++) {
if (number % divisor === 0) {
return false;
}
}
return true;
}
function getOnlyPrime(numbers) {
return numbers.filter(isPrime);
}
getOnlyPrime([2, 3, 4, 5, 6, 8, 11]); // => [2, 3, 5, 11]

getOnlyPrime() is small and plain. It has only strictly necessary steps from one level down in abstraction.

getOnlyPrime()是小而单一的。它只有一个小于一个抽象级别的必要的步骤。

The readability of complex functions can be much improved if you follow the rule of making them plain. Having each level of abstraction coded precisely prevents the creation of big chunks of unmaintainable code.

如果你能按照这样的规则去使自己的代码的功能变得单一,那个抽象复杂的函数的可读性将会被大大的提高。对每一个抽象级别进行编码会很好的防止大的可维护性差的代码的产生。

3. Use concise function names使用简洁清晰的函数命名

Function names should be concise: no more and no less. Ideally the name suggests clearly what the function does, without the necessity to dive into the implementation details.

函数命名应该是简洁明了的:不多不少。理想的命名应该是可以清楚地告诉人们这个函数实现了怎样的功能,没有必要再将它拆分成更小的细节去实现。

For function names use camel case format that starts with a lowercase letter: addItem(),saveToStore() or getFirstName().

函数命名一般会使用驼峰命名法——以小写字母开头,例如:addItem(),saveToStore() or getFirstName().

Because functions are actions, the name should contain at least one verb. For example deletePage(), verifyCredentials(). To get or set a property, use the standard set and getprefixes: getLastName() or setLastName().

因为函数是一种功能的实现,所以命名至少应该是包含一个动词。例如deletePage(), verifyCredentials().如果是为了设置或者是获取属性值,那个可以使用标准的set和get作为前缀:getLastName() 或者setLastName().

Avoid in the production code misleading names like foo(), bar(), a(), fun(), etc. Such names have no meaning.

并且要防止使用类似 foo(), bar(), a(), fun()等等的命名将我们带入歧途。这样的命名是无意义的。

If functions are small and plain, names are concise: the code is read as a wonderful prose.
如果你的函数是小而单一并且命名简洁的,这意味着读你的代码就像是在读一篇美妙的散文一样令人赏心悦目。

4. Conclusion结论

Certainly the provided examples are quite simple. Real world applications are more complex. You may complain that writing plain functions, with only one level down in abstraction, is a tedious task. But it’s not that complicated if your practice right from the start of the project.

当然啦,上文提到的例子都是相当简单的。真实的应用都是相当复杂的。或许你会抱怨,这样将在同一个抽象级别的函数写的单一是一件很枯燥乏味的工作。但是如果你从开始你的项目的时候就正确的练习那将一点儿都不困难。

If an application already has functions with too much responsibility, you may find hard to reorganize the code. And in many cases impossible to do in a reasonable amount of time. At least start with small: extract something you can.

如果一个应用已经有了太多复杂的函数,你或许会发现去重构这个代码是很困难的。并且在很多情况下重构这些代码会花去超出预期的时间。至少,从小功能开始:拆分那些你可以拆分的。

Of course the correct solution is to implement the application correctly from the start. And dedicate time not only to implementation, but also to a correct structure of your functions: as suggested make them small and plain.

当然最好的解决方法就是你从项目最开始就正确的实现这些应用。其实你花费时间最多的不光是如何实现这些功能,还有就是你的函数有没有一个正确的结构:就像我所建议的,让你的代码短小精悍。

Measure seven times, cut once.

ES2015 implements a nice module system, that clearly suggest that small functions are a good practice.

ES2015定义了一个很棒的模块系统,其中清楚地建议我们实现小功能是一个很好的练习方式。

Just remember that clean and organized code always deserves investing time. You may find it hard to do. You may need a lot of practice. You may come back and modify a function multiple times.

你只需要记住清晰有条理的代码总是值得我们花费更多的时间。或许开始的时候你会觉得这很困难,但是或许你需要的只是多加练习。或许你会有很多次回过头来看你之前编写的代码并且重构他们的一个功能很多次。

1
2
Nothing can be worse than messy code.
没有什么能比糟糕的代码更糟糕的了。

What practice do you use to make the code organized? Feel free to write a comment bellow!

在你的日常编码过程中你是如何练习把你的代码写的调理清晰的呢?放轻松,在下面留下你的留言吧~!

文章目录
  1. 1. Functions should be small. Really small 函数要小且足够的小
  2. 2. Step 0: The initial big function 原始的庞大函数
  3. 3. Step 1: Extract weight by type and drop magic numbers按照参数和类型简化代码的权重
  4. 4. Step 2: Continue splitting and make it extensible 继续分割,让它可扩展
  5. 5. Step 3: Never stop to improve不要停止重构
  6. 6. 2. Functions should be plain 函数功能要单一
  7. 7. 3. Use concise function names使用简洁清晰的函数命名
  8. 8. 4. Conclusion结论
|