forked from ryanmcdermott/clean-code-javascript
-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathREADME.md
More file actions
2646 lines (1926 loc) · 87.9 KB
/
README.md
File metadata and controls
2646 lines (1926 loc) · 87.9 KB
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# clean-code-javascript
clean code JavaScript(日本語訳)
## Table of Contents
1. [Introduction](#introduction)
2. [Variables](#variables)
3. [Functions](#functions)
4. [Objects and Data Structures](#objects-and-data-structures)
5. [Classes](#classes)
6. [SOLID](#solid)
7. [Testing](#testing)
8. [Concurrency](#concurrency)
9. [Error Handling](#error-handling)
10. [Formatting](#formatting)
11. [Comments](#comments)
12. [Translation](#translation)
## Introduction
## はじめに

Software engineering principles, from Robert C. Martin's book
[_Clean Code_](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882), adapted for JavaScript.
This is not a style guide. It’s a guide to producing [readable, reusable, and refactorable](https://github.com/ryanmcdermott/3rs-of-software-architecture) JavaScript software.
Robert C. Martin の著書 [_Clean Code_](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) に記載されたソフトウェアエンジニアリングの原則を、JavaScript 向けに適用したものです。
これはスタイルガイドではありません。[可読性が高く、再利用でき、リファクタリングしやすい](https://github.com/ryanmcdermott/3rs-of-software-architecture) JavaScript を書くためのガイドです。
Not every principle herein has to be strictly followed, and even fewer will be universally agreed upon.
These are guidelines—codified over many years of collective experience.
ここに書かれた原則すべてに厳密に従う必要はありませんし、すべてが普遍的に合意されているわけでもありません。
これはガイドラインであり、長年の経験からまとめられた知見です。
Software engineering is only about 50 years old—we are still learning.
Perhaps in the future we’ll have harder rules, but for now let these guidelines serve as a touchstone for your team’s JavaScript quality.
ソフトウェアエンジニアリングはまだ 50 年ほどの歴史しかなく、私たちは常に学び続けています。
いつか厳格なルールが確立されるかもしれませんが、今のところは _あなたとあなたのチームが JavaScript の品質を判断するための指針_ として役立ててください。
One more thing: knowing these won’t instantly make you a better developer.
Every piece of code starts as a first draft—like wet clay that will be shaped later.
Don’t beat yourself up for imperfect drafts. Beat up the code instead!
もう 1 つ大切なことがあります。
これらの知識を覚えたからといって、すぐに優れた開発者になれるわけではありません。
すべてのコードは最初は「未完成のたたき台」です。
改善が必要な初稿に対して自分を責めないでください。責めるべきはコードそのものです!
## **Variables**
### Use meaningful and pronounceable variable names
### 意味があり、発音しやすい変数名を使うこと
**Bad:**
```javascript
const yyyymmdstr = moment().format("YYYY/MM/DD");
```
**Good:**
```javascript
const currentDate = moment().format("YYYY/MM/DD");
```
**[⬆ back to top](#table-of-contents)**
### Use the same vocabulary for the same type of variable
### 同じ種類の変数には同じ語彙を使うこと
**Bad:**
```javascript
getUserInfo();
getClientData();
getCustomerRecord();
```
**Good:**
```javascript
getUser();
```
**[⬆ back to top](#table-of-contents)**
### Use searchable names
### 検索可能な名前を使うこと
We will read more code than we will ever write. It's important that the code we do write is readable and searchable. By not naming variables that end up being meaningful for understanding our program, we hurt our readers. Make your names searchable. Tools like [buddy.js](https://github.com/danielstjules/buddy.js) and [ESLint](https://github.com/eslint/eslint/blob/660e0918933e6e7fede26bc675a0763a6b357c94/docs/rules/no-magic-numbers.md) can help identify unnamed constants.
私たちはコードを書くよりも、読むほうがずっと多いです。
そのため、書くコードが読みやすく、検索しやすいことは非常に重要です。
プログラムの理解にとって意味を持つ変数に名前を付けないと、読者を苦しめることになります。
名前は検索可能にしてください。
[buddy.js](https://github.com/danielstjules/buddy.js) や [ESLint](https://github.com/eslint/eslint/blob/660e0918933e6e7fede26bc675a0763a6b357c94/docs/rules/no-magic-numbers.md) といったツールは、名前が付いていない定数を検出するのに役立ちます。
**Bad:**
```javascript
// What the heck is 86400000 for?
// 一体、なんのための86400000なんだい?
setTimeout(blastOff, 86400000);
```
**Good:**
```javascript
// Declare them as capitalized named constants.
// それらを大文字の名前付き定数として宣言してください。
const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000;
setTimeout(blastOff, MILLISECONDS_PER_DAY);
```
**[⬆ back to top](#table-of-contents)**
### Use explanatory variables
### 説明的な変数を利用すること
**Bad:**
```javascript
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(
address.match(cityZipCodeRegex)[1],
address.match(cityZipCodeRegex)[2]
);
```
**Good:**
```javascript
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);
```
**[⬆ back to top](#table-of-contents)**
### Avoid Mental Mapping
### メンタルマップ(暗黙的な読み替え)を避ける
Explicit is better than implicit.
明示は暗黙より優れている。
**Bad:**
```javascript
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach((l) => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
// Wait, what is `l` for again?
// ちょっと待って、もう一度`l`ってなんだっけ?
dispatch(l);
});
```
**Good:**
```javascript
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach((location) => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
dispatch(location);
});
```
**[⬆ back to top](#table-of-contents)**
### Don't add unneeded context
### 不必要なコンテキストを追加しない
If your class/object name tells you something, don't repeat that in your
variable name.
もしクラス名やオブジェクト名がすでに何かを表しているのであれば、変数名の中で同じ情報を繰り返してはいけません。
**Bad:**
```javascript
const Car = {
carMake: "Honda",
carModel: "Accord",
carColor: "Blue",
};
function paintCar(car, color) {
car.carColor = color;
}
```
**Good:**
```javascript
const Car = {
make: "Honda",
model: "Accord",
color: "Blue",
};
function paintCar(car, color) {
car.color = color;
}
```
**[⬆ back to top](#table-of-contents)**
### Use default parameters instead of short circuiting or conditionals
### 短絡評価や条件分岐の代わりにデフォルト引数を使う
Default parameters are often cleaner than short circuiting. Be aware that if you use them, your function will only provide default values for `undefined` arguments. Other "falsy" values such as `''`, `""`, `false`, `null`, `0`, and `NaN`, will not be replaced by a default value.
デフォルト引数のほうが、コードがより明確で読みやすくなります。
ただし注意点として、デフォルト引数が適用されるのは `undefined` の場合だけ です。
`''`、`""`、`false`、`null`、`0`、`NaN` といった “falsy” な値は、デフォルト値では置き換えられません。
**Bad:**
```javascript
function createMicrobrewery(name) {
const breweryName = name || "Hipster Brew Co.";
// ...
}
```
**Good:**
```javascript
function createMicrobrewery(name = "Hipster Brew Co.") {
// ...
}
```
**[⬆ back to top](#table-of-contents)**
## **Functions**
### Function arguments (2 or fewer ideally)
### 関数の引数(理想は 2 つ以下)
Limiting the amount of function parameters is incredibly important because it makes testing your function easier. Having more than three leads to a combinatorial explosion where you have to test tons of different cases with each separate argument.
関数の引数の数を制限することは非常に重要です。引数が少なければ、関数をテストしやすくなるからです。
引数が 3 つを超えると、組み合わせが爆発し、それぞれの引数について膨大なケースをテストしなければならなくなります。
One or two arguments is the ideal case, and three should be avoided if possible. Anything more than that should be consolidated. Usually, if you have more than two arguments then your function is trying to do too much. In cases where it's not, most of the time a higher-level object will suffice as an argument.
理想的なのは 1〜2 個の引数 であり、可能であれば 3 個も避けるべき です。
それ以上の引数が必要になる場合は、まとめられるか検討してください。
一般的には、引数が 2 個を超える関数は「やりすぎ」ていることが多いです。
そうでない場合でも、たいていはより高レベルのオブジェクトを引数として渡すことで十分です。
Since JavaScript allows you to make objects on the fly, without a lot of class boilerplate, you can use an object if you are finding yourself needing a lot of arguments.
JavaScript ではクラスのような面倒な準備なしにその場でオブジェクトを作れるため、引数が多くなりそうなときはオブジェクトを使うのが有効です。
To make it obvious what properties the function expects, you can use the ES2015/ES6 destructuring syntax. This has a few advantages:
1. When someone looks at the function signature, it's immediately clear what properties are being used.
1. It can be used to simulate named parameters.
1. Destructuring also clones the specified primitive values of the argument object passed into the function. This can help prevent side effects. Note: objects and arrays that are destructured from the argument object are NOT cloned.
1. Linters can warn you about unused properties, which would be impossible without destructuring.
関数がどのプロパティを期待しているか明確にするために、ES2015/ES6 の分割代入(destructuring)構文 を使うとよいでしょう。
これには次のメリットがあります:
1. 関数シグネチャを見るだけで、どのプロパティが使われているかすぐに分かる。
1. 名前付きパラメータのように使える。
1. 分割代入された プリミティブ値 は複製されるため、副作用を防ぐ助けになる。※ただし、分割代入された オブジェクトや配列は複製されない 点に注意。
1. Linter による「未使用プロパティ」の警告が効くようになる。分割代入しなければこれは不可能。
**Bad:**
```javascript
function createMenu(title, body, buttonText, cancellable) {
// ...
}
createMenu("Foo", "Bar", "Baz", true);
```
**Good:**
```javascript
function createMenu({ title, body, buttonText, cancellable }) {
// ...
}
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true,
});
```
**[⬆ back to top](#table-of-contents)**
### Functions should do one thing
### 関数は 1 つのことだけを行うべき
This is by far the most important rule in software engineering. When functions do more than one thing, they are harder to compose, test, and reason about. When you can isolate a function to just one action, it can be refactored easily and your code will read much cleaner. If you take nothing else away from this guide other than this, you'll be ahead of many developers.
これはソフトウェアエンジニアリングにおけるもっとも重要なルールです。
関数が複数のことを行うと、構成しにくくなり、テストもしにくくなり、理解もしづらくなります。
関数を 1 つの動作に切り分けることができれば、リファクタリングが格段に容易になり、コードの読みやすさも大きく向上します。
このガイドから他のことを何も覚えなくても、このルールだけを守れれば、多くの開発者より一歩先に進めます。
**Bad:**
```javascript
function emailClients(clients) {
clients.forEach((client) => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
```
**Good:**
```javascript
function emailActiveClients(clients) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
```
**[⬆ back to top](#table-of-contents)**
### Function names should say what they do
### 関数名はその関数が何をするのかを明確に表すべき
**Bad:**
```javascript
function addToDate(date, month) {
// ...
}
const date = new Date();
// It's hard to tell from the function name what is added
// 関数名からは何が追加されているのか分かりにくい。
addToDate(date, 1);
```
**Good:**
```javascript
function addMonthToDate(month, date) {
// ...
}
const date = new Date();
addMonthToDate(1, date);
```
**[⬆ back to top](#table-of-contents)**
### Functions should only be one level of abstraction
### 関数は 1 つの抽象レベルだけを扱うべき
When you have more than one level of abstraction your function is usually doing too much. Splitting up functions leads to reusability and easier testing.
複数の抽象レベルを 1 つの関数に混在させてしまうと、その関数はたいてい「やりすぎている」状態になります。
関数を適切に分割すれば、再利用しやすくなり、テストもしやすくなります。
**Bad:**
```javascript
function parseBetterJSAlternative(code) {
const REGEXES = [
// ...
];
const statements = code.split(" ");
const tokens = [];
REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...
});
});
const ast = [];
tokens.forEach((token) => {
// lex...
});
ast.forEach((node) => {
// parse...
});
}
```
**Good:**
```javascript
function parseBetterJSAlternative(code) {
const tokens = tokenize(code);
const syntaxTree = parse(tokens);
syntaxTree.forEach((node) => {
// parse...
});
}
function tokenize(code) {
const REGEXES = [
// ...
];
const statements = code.split(" ");
const tokens = [];
REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
tokens.push(/* ... */);
});
});
return tokens;
}
function parse(tokens) {
const syntaxTree = [];
tokens.forEach((token) => {
syntaxTree.push(/* ... */);
});
return syntaxTree;
}
```
**[⬆ back to top](#table-of-contents)**
### Remove duplicate code
### 重複したコードを取り除くこと
Do your absolute best to avoid duplicate code. Duplicate code is bad because it means that there's more than one place to alter something if you need to change some logic.
重複コードは必ず避けるようにしましょう。
重複があるということは、あるロジックを変更したいときに 複数の場所を修正しなければならない ということであり、非常に悪い状態です。
Imagine if you run a restaurant and you keep track of your inventory: all your tomatoes, onions, garlic, spices, etc. If you have multiple lists that you keep this on, then all have to be updated when you serve a dish with tomatoes in them. If you only have one list, there's only one place to update!
たとえば、あなたがレストランを経営していて、トマト・玉ねぎ・にんにく・スパイスなどの在庫を管理しているとします。
もし在庫を記録したリストが複数あれば、トマトを使った料理を出すたびに すべてのリストを更新しなければならなくなります。
しかしリストが 1 つだけなら、更新すべき場所も 1 つだけで済みます。
Oftentimes you have duplicate code because you have two or more slightly different things, that share a lot in common, but their differences force you to have two or more separate functions that do much of the same things. Removing duplicate code means creating an abstraction that can handle this set of different things with just one function/module/class.
重複コードが生まれる典型的な理由は、「とてもよく似ているが、少しだけ違う」処理が複数存在するために、似たような関数を複数つくってしまう からです。
重複コードをなくすということは、こうした「少し違うだけの複数の処理」を 1 つの関数・モジュール・クラスに抽象化する ということです。
Getting the abstraction right is critical, that's why you should follow the SOLID principles laid out in the Classes section. Bad abstractions can be worse than duplicate code, so be careful! Having said this, if you can make a good abstraction, do it! Don't repeat yourself, otherwise you'll find yourself updating multiple places anytime you want to change one thing.
ただし、この「抽象化」を正しく行うことは非常に重要です。
これが難しい理由でもあり、Classes セクションで説明した SOLID 原則 に従うべき理由でもあります。
悪い抽象化は重複コードよりも悪影響を及ぼすので注意してください。
しかし、もし 良い抽象化 がつくれるなら、迷わずそうすべきです。
「同じことを繰り返さない(Don't repeat yourself)」を徹底しないと、あなたは 1 箇所の変更を行うために 複数箇所を更新し続ける未来 に直面することになります。
**Bad:**
```javascript
function showDeveloperList(developers) {
developers.forEach((developer) => {
const expectedSalary = developer.calculateExpectedSalary();
const experience = developer.getExperience();
const githubLink = developer.getGithubLink();
const data = {
expectedSalary,
experience,
githubLink,
};
render(data);
});
}
function showManagerList(managers) {
managers.forEach((manager) => {
const expectedSalary = manager.calculateExpectedSalary();
const experience = manager.getExperience();
const portfolio = manager.getMBAProjects();
const data = {
expectedSalary,
experience,
portfolio,
};
render(data);
});
}
```
**Good:**
```javascript
function showEmployeeList(employees) {
employees.forEach((employee) => {
const expectedSalary = employee.calculateExpectedSalary();
const experience = employee.getExperience();
const data = {
expectedSalary,
experience,
};
switch (employee.type) {
case "manager":
data.portfolio = employee.getMBAProjects();
break;
case "developer":
data.githubLink = employee.getGithubLink();
break;
}
render(data);
});
}
```
**[⬆ back to top](#table-of-contents)**
### Set default objects with Object.assign
### Object.assign を使ってデフォルトのオブジェクトを設定する
**Bad:**
```javascript
const menuConfig = {
title: null,
body: "Bar",
buttonText: null,
cancellable: true,
};
function createMenu(config) {
config.title = config.title || "Foo";
config.body = config.body || "Bar";
config.buttonText = config.buttonText || "Baz";
config.cancellable =
config.cancellable !== undefined ? config.cancellable : true;
}
createMenu(menuConfig);
```
**Good:**
```javascript
const menuConfig = {
title: "Order",
// User did not include 'body' key
// ユーザーは body キーを含めていない
buttonText: "Send",
cancellable: true,
};
function createMenu(config) {
let finalConfig = Object.assign(
{
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true,
},
config
);
return finalConfig;
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// config は次のようになります:{ title: "Order", body: "Bar", buttonText: "Send", cancellable: true }
// ...
}
createMenu(menuConfig);
```
**[⬆ back to top](#table-of-contents)**
### Don't use flags as function parameters
### フラグ(真偽値)を関数の引数として使わない
Flags tell your user that this function does more than one thing. Functions should do one thing. Split out your functions if they are following different code paths based on a boolean.
フラグが必要になるということは、その関数が複数のことをしているというサインです。
関数は 1 つのことだけを行うべきです。
もし真偽値によって処理が分岐するのであれば、関数を分割してそれぞれ別の処理として定義してください。
**Bad:**
```javascript
function createFile(name, temp) {
if (temp) {
fs.create(`./temp/${name}`);
} else {
fs.create(name);
}
}
```
**Good:**
```javascript
function createFile(name) {
fs.create(name);
}
function createTempFile(name) {
createFile(`./temp/${name}`);
}
```
**[⬆ back to top](#table-of-contents)**
### Avoid Side Effects (part 1)
### 副作用を避ける(part 1)
A function produces a side effect if it does anything other than take a value in and return another value or values. A side effect could be writing to a file, modifying some global variable, or accidentally wiring all your money to a stranger.
関数は、値を受け取って別の値を返す以外のことを行うと、その時点で副作用を持ちます。
副作用には、ファイルへの書き込み、グローバル変数の変更、あるいは誤って全財産を知らない人に送金する、といったものが含まれます。
Now, you do need to have side effects in a program on occasion. Like the previous example, you might need to write to a file. What you want to do is to centralize where you are doing this. Don't have several functions and classes that write to a particular file. Have one service that does it. One and only one.
重要なのは、副作用の発生場所を 1 つに集中させること です。
特定のファイルに書き込む処理を、複数の関数やクラスに散在させてはいけません。
その役割を担う 単一のサービスを 1 つだけ用意してください。
The main point is to avoid common pitfalls like sharing state between objects without any structure, using mutable data types that can be written to by anything, and not centralizing where your side effects occur. If you can do this, you will be happier than the vast majority of other programmers.
ポイントは、構造もなくオブジェクト間で状態を共有したり、どこからでも書き換え可能な可変データ型を使ったり、副作用を発生させる場所を分散させたりする、といった典型的な落とし穴を避けることです。
これができるようになれば、あなたは大多数のプログラマーよりもずっと快適にコードを書けるようになるでしょう。
**Bad:**
```javascript
// Global variable referenced by following function.
// If we had another function that used this name, now it'd be an array and it could break it.
// グローバル変数がこのあとに続く関数から参照されている。
// もし同じ名前を別の関数でも使っていた場合、今やこの値は配列になってしまい、動作が壊れる可能性がある。
let name = "Ryan McDermott";
function splitIntoFirstAndLastName() {
name = name.split(" ");
}
splitIntoFirstAndLastName();
console.log(name); // ['Ryan', 'McDermott'];
```
**Good:**
```javascript
function splitIntoFirstAndLastName(name) {
return name.split(" ");
}
const name = "Ryan McDermott";
const newName = splitIntoFirstAndLastName(name);
console.log(name); // 'Ryan McDermott';
console.log(newName); // ['Ryan', 'McDermott'];
```
**[⬆ back to top](#table-of-contents)**
### Avoid Side Effects (part 2)
### 副作用を避ける(part 2)
In JavaScript, some values are unchangeable (immutable) and some are changeable (mutable). Objects and arrays are two kinds of mutable values so it's important to handle them carefully when they're passed as parameters to a function. A JavaScript function can change an object's properties or alter the contents of an array which could easily cause bugs elsewhere.
JavaScript では、変更できない値(immutable)と変更できる値(mutable)があります。
オブジェクトと配列は mutable な値 に分類されるため、関数に渡す際には特に注意が必要です。
JavaScript の関数は、オブジェクトのプロパティを変更したり、配列の内容を変更したりすることができ、その結果、思わぬ箇所でバグを引き起こす可能性があります。
Suppose there's a function that accepts an array parameter representing a shopping cart. If the function makes a change in that shopping cart array - by adding an item to purchase, for example - then any other function that uses that same `cart` array will be affected by this addition. That may be great, however it could also be bad. Let's imagine a bad situation:
たとえば、ショッピングカートを表す配列を受け取る関数があるとします。
もしその関数がカートの配列を変更(購入予定の商品を追加する、など)すると、同じ配列を使っている別の関数にもその変更が影響します。
これが望ましい場合もありますが、悪影響になるケースもあります。
悪いケースを想像してみましょう。
The user clicks the "Purchase" button which calls a `purchase` function that spawns a network request and sends the `cart` array to the server. Because of a bad network connection, the `purchase` function has to keep retrying the request. Now, what if in the meantime the user accidentally clicks an "Add to Cart" button on an item they don't actually want before the network request begins? If that happens and the network request begins, then that purchase function will send the accidentally added item because the `cart` array was modified.
ユーザーが「購入」ボタンを押すと、purchase 関数が呼ばれ、ネットワークリクエストを発行してカートの配列をサーバーに送信します。
しかしネットワークが不安定で、このリクエストが繰り返し再試行されるとします。
その間に、ユーザーが誤って「カートに追加」ボタンを押し、本当は購入したくない商品を追加してしまうかもしれません。
もしそのタイミングでリクエストが再試行されると、`purchase` 関数は誤って追加された商品まで送信してしまいます。
これは、カート配列が変更されてしまったために起こります。
A great solution would be for the `addItemToCart` function to always clone the `cart`, edit it, and return the clone. This would ensure that functions that are still using the old shopping cart wouldn't be affected by the changes.
この問題の優れた解決策は、`addItemToCart` 関数が 常にカートを clone(複製)し、複製を編集して返すことです。
Two caveats to mention to this approach:
1. There might be cases where you actually want to modify the input object, but when you adopt this programming practice you will find that those cases are pretty rare. Most things can be refactored to have no side effects!
1. Cloning big objects can be very expensive in terms of performance. Luckily, this isn't a big issue in practice because there are [great libraries](https://facebook.github.io/immutable-js/) that allow this kind of programming approach to be fast and not as memory intensive as it would be for you to manually clone objects and arrays.
このアプローチには 2 つの注意点があります:
1. 入力オブジェクトを実際に変更したいケースもまれにあるが、この手法を採用すると、そのようなケースは非常に少ないことに気づくでしょう。多くの処理は、副作用なしにリファクタリングできます。
1. 大きなオブジェクトを複製するのは、パフォーマンス面で高コストです。ただし現実的にはあまり問題になりません。なぜなら、手動で複製するより高速でメモリ効率も良い[優れたライブラリ](https://facebook.github.io/immutable-js/)が存在するからです。
**Bad:**
```javascript
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
```
**Good:**
```javascript
const addItemToCart = (cart, item) => {
return [...cart, { item, date: Date.now() }];
};
```
**[⬆ back to top](#table-of-contents)**
### Don't write to global functions
### グローバル関数に書き込まない
Polluting globals is a bad practice in JavaScript because you could clash with another library and the user of your API would be none-the-wiser until they get an exception in production. Let's think about an example: what if you wanted to extend JavaScript's native Array method to have a `diff` method that could show the difference between two arrays? You could write your new function to the `Array.prototype`, but it could clash with another library that tried to do the same thing. What if that other library was just using `diff` to find the difference between the first and last elements of an array? This is why it would be much better to just use ES2015/ES6 classes and simply extend the `Array` global.
グローバルを汚染することは、JavaScript における悪いプラクティスです。
なぜなら、他のライブラリと衝突する可能性があり、あなたの API の利用者は本番環境で例外が発生するまでその問題に気づけないからです。
例を考えてみましょう。
JavaScript のネイティブな Array に `diff` メソッドを追加して、2 つの配列の差分を取得できるようにしたいとします。
`Array.prototype` に新しいメソッドを書き込むことはできますが、同じ名前の `diff` を追加しようとしている他のライブラリと衝突する可能性 があります。
もしその別のライブラリが `diff` を「配列の最初と最後の要素の差分を求める関数」として実装していたらどうなるでしょうか?
互いの実装が上書きされ、どちらかが正常に動作しなくなる可能性があります。
このような理由から、Array.prototype を汚染するのではなく、ES2015/ES6 のクラス構文を使って `Array` を拡張するほうがずっと安全です。
**Bad:**
```javascript
Array.prototype.diff = function diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter((elem) => !hash.has(elem));
};
```
**Good:**
```javascript
class SuperArray extends Array {
diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter((elem) => !hash.has(elem));
}
}
```
**[⬆ back to top](#table-of-contents)**
### Favor functional programming over imperative programming
### 手続き型プログラミングより、関数型プログラミングを優先する
JavaScript isn't a functional language in the way that Haskell is, but it has a functional flavor to it. Functional languages can be cleaner and easier to test. Favor this style of programming when you can.
JavaScript は Haskell のような純粋な関数型言語ではありませんが、関数型の特徴をある程度備えています。
関数型言語は、よりクリーンでテストしやすい傾向があります。
可能な場面では、このスタイルのプログラミングを優先しましょう。
**Bad:**
```javascript
const programmerOutput = [
{
name: "Uncle Bobby",
linesOfCode: 500,
},
{
name: "Suzie Q",
linesOfCode: 1500,
},
{
name: "Jimmy Gosling",
linesOfCode: 150,
},
{
name: "Gracie Hopper",
linesOfCode: 1000,
},
];
let totalOutput = 0;
for (let i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
```
**Good:**
```javascript
const programmerOutput = [
{
name: "Uncle Bobby",
linesOfCode: 500,
},
{
name: "Suzie Q",
linesOfCode: 1500,
},
{
name: "Jimmy Gosling",
linesOfCode: 150,
},
{
name: "Gracie Hopper",
linesOfCode: 1000,
},
];
const totalOutput = programmerOutput.reduce(
(totalLines, output) => totalLines + output.linesOfCode,
0
);
```
**[⬆ back to top](#table-of-contents)**
### Encapsulate conditionals
### 条件式をカプセル化する
**Bad:**
```javascript
if (fsm.state === "fetching" && isEmpty(listNode)) {
// ...
}
```
**Good:**
```javascript
function shouldShowSpinner(fsm, listNode) {
return fsm.state === "fetching" && isEmpty(listNode);
}
if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}
```
**[⬆ back to top](#table-of-contents)**
### Avoid negative conditionals
### 否定形の条件式を避ける
**Bad:**
```javascript
function isDOMNodeNotPresent(node) {
// ...
}
if (!isDOMNodeNotPresent(node)) {
// ...
}
```
**Good:**
```javascript
function isDOMNodePresent(node) {
// ...
}
if (isDOMNodePresent(node)) {
// ...
}
```
**[⬆ back to top](#table-of-contents)**
### Avoid conditionals
### 条件文を避ける
This seems like an impossible task. Upon first hearing this, most people say, "how am I supposed to do anything without an `if` statement?" The answer is that you can use polymorphism to achieve the same task in many cases. The second question is usually, "well that's great but why would I want to do that?" The answer is a previous clean code concept we learned: a function should only do one thing. When you have classes and functions that have `if` statements, you are telling your user that your function does more than one thing. Remember, just do one thing.
これは一見、不可能なことのように思えるかもしれません。
この話を聞くと、多くの人は「`if` 文なしでどうやって処理を書くの?」と言います。
答えは、多くの場合、ポリモーフィズム(多態性)を使うことで同じことが実現できる ということです。
次によく出てくる質問は「それは良さそうだけど、なぜわざわざそうする必要があるの?」というものです。
その答えは、以前出てきたクリーンコードの基本原則、“関数は 1 つのことだけを行うべき” にあります。
クラスや関数の中に `if` 文があるということは、その関数が 複数のことを行っている ことを意味します。
常に思い出してください。
関数は 1 つのことだけを行うべきです。
**Bad:**
```javascript
class Airplane {
// ...
getCruisingAltitude() {
switch (this.type) {
case "777":
return this.getMaxAltitude() - this.getPassengerCount();
case "Air Force One":
return this.getMaxAltitude();
case "Cessna":
return this.getMaxAltitude() - this.getFuelExpenditure();
}
}
}
```
**Good:**
```javascript
class Airplane {
// ...
}
class Boeing777 extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude() - this.getPassengerCount();
}
}
class AirForceOne extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude();
}
}
class Cessna extends Airplane {
// ...
getCruisingAltitude() {