Skip to content

Commit ad4a7aa

Browse files
author
myoungho.Pak
committed
[ac6a51d] update
1 parent 2a66254 commit ad4a7aa

File tree

1 file changed

+101
-56
lines changed

1 file changed

+101
-56
lines changed

README.md

Lines changed: 101 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# clean-code-javascript
22

3-
* Updated date 2017.1.16
4-
* 현재 원문의 [00a5068](https://github.com/ryanmcdermott/clean-code-javascript/commit/00a50681b1c0a24e9c8c08d8872fee9c76da17d5)
3+
* Updated date 2017.1.31
4+
* 현재 원문의 [ac6a51d](https://github.com/ryanmcdermott/clean-code-javascript/commit/ac6a51d640064ec4ac6cada7af477df8967dd193)
55
까지 반영되어 있습니다.
66

77
## 읽기에 앞서
@@ -24,9 +24,10 @@
2424
5. [클래스(Classes)](#클래스classes)
2525
6. [테스트(Testing)](#테스트testing)
2626
7. [동시성(Concurrency)](#동시성concurrency)
27-
8. [에러 처리(Error Handling)](#에러-처리error-Handling)
27+
8. [에러 처리(Error Handling)](#에러-처리error-handling)
2828
9. [포맷팅(Formatting)](#포맷팅formatting)
2929
10. [주석(Comments)](#주석comments)
30+
11. [번역(Translation)](#번역translation)
3031

3132
## 소개(Introduction)
3233
![코드를 읽을 때 소리 지르는 숫자로 소프트웨어 품질을 추정하는 유머 사진](http://www.osnews.com/images/comics/wtfm.jpg)
@@ -107,7 +108,7 @@ saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeReg
107108
```javascript
108109
const address = 'One Infinite Loop, Cupertino 95014';
109110
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
110-
const [, city, zipCode] = address.match(cityZipCodeRegex);
111+
const [, city, zipCode] = address.match(cityZipCodeRegex) || [];
111112
saveCityZipCode(city, zipCode);
112113
```
113114
**[⬆ 상단으로](#목차)**
@@ -173,6 +174,8 @@ function paintCar(car) {
173174
**[⬆ 상단으로](#목차)**
174175

175176
### 기본 매개변수가 short circuiting 트릭이나 조건문 보다 깔끔합니다
177+
기본 매개변수는 종종 short circuiting 트릭보다 깔끔합니다. 기본 매개변수는 매개변수가 `undefined`일때만
178+
적용됩니다. `''`, `""`, `false`, `null`, `0`, `NaN` 같은 `falsy`한 값들은 기본 매개변수가 적용되지 않습니다.
176179

177180
**안좋은 예:**
178181
```javascript
@@ -195,14 +198,25 @@ function createMicrobrewery(name = 'Hipster Brew Co.') {
195198
매개변수의 개수를 제한 하는 것은 함수 테스팅을 쉽게 만들어 주기 때문에 중요합니다. 만약 매개변수가 3개 이상일 경우엔
196199
테스트 해야하는 경우의 수가 많아지고 각기 다른 인수들로 여러 사례들을 테스트 해야합니다.
197200

198-
인자가 한 개도 없는 것이 이상적인 케이스이고 1개나 2개 정도의 인자는 괜찮습니다.
199-
하지만 3개는 피해야하고 그 이상이라면 줄이는 것이 좋습니다.
201+
1개나 2개의 인자를 가지고 있는 것이 가장 이상적인 케이스입니다.
202+
그리고 3개의 인자는 가능한 피해야합니다. 그것보다 더 많다면 통합되어야합니다.
200203
만약 당신이 2개 이상의 인자를 가진 함수를 사용한다면 그 함수에게 너무 많은 역할을 하게 만든 것입니다.
201204
그렇지 않은 경우라면 대부분의 경우 상위 객체는 1개의 인자만으로 충분합니다.
202205

203206
JavaScript를 사용할 때 많은 보일러플레이트 없이 바로 객체를 만들 수 있습니다.
204207
그러므로 당신이 만약 많은 인자들을 사용해야 한다면 객체를 이용할 수 있습니다.
205208

209+
함수가 기대하는 속성을 좀더 명확히 하기 위해서 es6의 비구조화(destructuring) 구문을 사용할 수 있고
210+
이 구문에는 몇가지 장점이 있습니다.
211+
212+
1. 어떤 사람이 그 함수의 시그니쳐(인자의 타입, 반환되는 값의 타입 등)를 볼 때 어떤 속성이 사용되는지
213+
즉시 알 수 있습니다.
214+
2. 또한 비구조화는 함수에 전달된 인수 객체의 지정된 기본타입 값을 복제하며 이는 사이드이펙트가
215+
일어나는 것을 방지합니다. 참고로 인수 객체로부터 비구조화된 객체와 배열은 복제되지 않습니다.
216+
3. Linter를 사용하면 사용하지않는 인자에 대해 경고해주거나 비구조화 없이 코드를 짤 수 없게 할 수 있습니다.
217+
218+
219+
206220
**안좋은 예:**
207221
```javascript
208222
function createMenu(title, body, buttonText, cancellable) {
@@ -212,17 +226,16 @@ function createMenu(title, body, buttonText, cancellable) {
212226

213227
**좋은 예:**
214228
```javascript
215-
const menuConfig = {
229+
function createMenu({ title, body, buttonText, cancellable }) {
230+
// ...
231+
}
232+
233+
createMenu({
216234
title: 'Foo',
217235
body: 'Bar',
218236
buttonText: 'Baz',
219237
cancellable: true
220-
};
221-
222-
function createMenu(config) {
223-
...
224-
}
225-
238+
});
226239
```
227240
**[⬆ 상단으로](#목차)**
228241

@@ -403,8 +416,8 @@ function showManagerList(managers) {
403416

404417
**좋은 예:**
405418
```javascript
406-
function showList(employees) {
407-
employees.forEach(employee => {
419+
function showEmployeeList(employees) {
420+
employees.forEach((employee) => {
408421
const expectedSalary = employee.calculateExpectedSalary();
409422
const experience = employee.getExperience();
410423

@@ -500,7 +513,7 @@ function createTempFile(name) {
500513
```
501514
**[⬆ 상단으로](#목차)**
502515

503-
### 사이드 이펙트를 피하세요
516+
### 사이드 이펙트를 피하세요 (part 1)
504517
함수는 값을 받아서 어떤 일을 하거나 값을 리턴할때 사이드 이팩트를 만들어냅니다.
505518
사이드 이팩트는 파일에 쓰여질 수도 있고, 전역 변수를 수정할 수 있으며, 실수로 모든 돈을 다른 사람에게 보낼 수도 있습니다.
506519

@@ -541,6 +554,44 @@ console.log(newName); // ['Ryan', 'McDermott'];
541554
```
542555
**[⬆ 상단으로](#목차)**
543556

557+
### 사이드 이펙트를 피하세요 (part 2)
558+
자바스크립트에서는 기본타입 자료형은 값을 전달하고 객체와 배열은 참조를 전달합니다.
559+
객체와 배열인 경우를 한번 살펴봅시다. 우리가 만든 함수는 쇼핑카트 배열에 변화를 주며
560+
이 변화는 구매목록에 어떤 상품을 추가하는 기능 같은 것을 말합니다.
561+
만약 `장바구니` 배열을 사용하는 어느 다른 함수가 있다면 이러한 추가에 영향을 받습니다.
562+
이것은 좋을 수도 있지만, 안좋을 수도 있습니다. 안좋은 예를 한번 상상해봅시다.
563+
564+
유저가 구매하기 버튼을 눌러 `구매` 함수를 호출합니다. 이는 네트워크 요청을 생성하고 서버에 `장바구니` 배열을 보냅니다.
565+
하지만 네트워크 연결이 좋지않아서 `구매` 함수는 다시한번 네트워크 요청을 보내야 하는 상황이 생겼습니다.
566+
이때, 사용자가 네트워크 요청이 시작되기 전에 실수로 원하지 않는 상품의 "장바구니에 추가" 버튼을 실수로 클릭하면 어떻게됩니까?
567+
이런 일이 발생하고 네트워크 요청이 시작되면 `장바구니에 추가`함수 때문에 실수로 변경된 `장바구니` 배열을 서버에 보내게 됩니다.
568+
569+
가장 좋은 방법은 `장바구니에 추가`는 항상 `장바구니` 배열을 복제하여 수정하고 복제본을 반환하는 것입니다.
570+
이렇게하면 장바구니 참조를 보유하고있는 다른 함수가 다른 변경 사항의 영향을 받지 않게됩니다.
571+
572+
이 접근법에대해 말하고 싶은 것이 두가지 있습니다.
573+
574+
1. 실제로 입력된 객체를 수정하고 싶은 경우가 있을 수 있지만 이러한 예제를 생각해보고 적용해보면 그런 경우는
575+
거의 없다는 것을 깨달을 수 있습니다. 그리고 대부분의 것들이 사이드 이펙트 없이 리팩토링 될 수 있습니다.
576+
2. 큰 객체를 복제하는 것은 성능 측면에서 값이 매우 비쌉니다. 운좋게도 이런게 큰 문제가 되지는 않습니다.
577+
왜냐하면 이러한 프로그래밍 접근법을 가능하게해줄 [좋은 라이브러리](https://facebook.github.io/immutable-js/)가 있기 때문입니다.
578+
이는 객체와 배열을 수동으로 복제하는 것처럼 메모리 집약적이지 않게 해주고 빠르게 복제해줍니다.
579+
580+
**Bad:**
581+
```javascript
582+
const addItemToCart = (cart, item) => {
583+
cart.push({ item, date: Date.now() });
584+
};
585+
```
586+
587+
**Good:**
588+
```javascript
589+
const addItemToCart = (cart, item) => {
590+
return [...cart, { item, date : Date.now() }];
591+
};
592+
```
593+
**[⬆ 상단으로](#목차)**
594+
544595
### 전역 함수를 사용하지 마세요
545596
전역 환경을 사용하는 것은 JavaScript에서 나쁜 관행입니다. 왜냐하면 다른 라이브러리들과의 충돌이 일어날 수 있고,
546597
당신의 API를 쓰는 유저들은 운영환경에서 예외가 발생하기 전까지는 문제를 인지하지 못할 것이기 때문입니다. 예제를 하나 생각해봅시다.
@@ -617,7 +668,7 @@ const programmerOutput = [
617668

618669
const totalOutput = programmerOutput
619670
.map(programmer => programmer.linesOfCode)
620-
.reduce((acc, linesOfCode) => acc + linesOfCode, 0);
671+
.reduce((acc, linesOfCode) => acc + linesOfCode, INITIAL_VALUE);
621672
```
622673
**[⬆ 상단으로](#목차)**
623674

@@ -729,7 +780,7 @@ JavaScript는 타입이 정해져있지 않습니다. 이는 당신의 함수가
729780
```javascript
730781
function travelToTexas(vehicle) {
731782
if (vehicle instanceof Bicycle) {
732-
vehicle.peddle(this.currentLocation, new Location('texas'));
783+
vehicle.pedal(this.currentLocation, new Location('texas'));
733784
} else if (vehicle instanceof Car) {
734785
vehicle.drive(this.currentLocation, new Location('texas'));
735786
}
@@ -863,7 +914,7 @@ class BankAccount {
863914

864915
// getter/setter를 정의할 때 `get`, `set` 같은 접두사가 필요하지 않습니다.
865916
set balance(amount) {
866-
if (verifyIfAmountCanBeSetted(amount)) {
917+
if (this.verifyIfAmountCanBeSetted(amount)) {
867918
this._balance = amount;
868919
}
869920
}
@@ -899,7 +950,7 @@ const Employee = function(name) {
899950

900951
Employee.prototype.getName = function getName() {
901952
return this.name;
902-
}
953+
};
903954

904955
const employee = new Employee('John Doe');
905956
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
@@ -909,13 +960,15 @@ console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined
909960

910961
**좋은 예:**
911962
```javascript
912-
const Employee = function (name) {
913-
this.getName = function getName() {
914-
return name;
963+
function makeEmployee(name) {
964+
return {
965+
getName() {
966+
return name;
967+
},
915968
};
916-
};
969+
}
917970

918-
const employee = new Employee('John Doe');
971+
const employee = makeEmployee('John Doe');
919972
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
920973
delete employee.name;
921974
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
@@ -1139,17 +1192,9 @@ class Shape {
11391192
}
11401193

11411194
class Rectangle extends Shape {
1142-
constructor() {
1195+
constructor(width, height) {
11431196
super();
1144-
this.width = 0;
1145-
this.height = 0;
1146-
}
1147-
1148-
setWidth(width) {
11491197
this.width = width;
1150-
}
1151-
1152-
setHeight(height) {
11531198
this.height = height;
11541199
}
11551200

@@ -1159,12 +1204,8 @@ class Rectangle extends Shape {
11591204
}
11601205

11611206
class Square extends Shape {
1162-
constructor() {
1207+
constructor(length) {
11631208
super();
1164-
this.length = 0;
1165-
}
1166-
1167-
setLength(length) {
11681209
this.length = length;
11691210
}
11701211

@@ -1175,21 +1216,12 @@ class Square extends Shape {
11751216

11761217
function renderLargeShapes(shapes) {
11771218
shapes.forEach((shape) => {
1178-
switch (shape.constructor.name) {
1179-
case 'Square':
1180-
shape.setLength(5);
1181-
break;
1182-
case 'Rectangle':
1183-
shape.setWidth(4);
1184-
shape.setHeight(5);
1185-
}
1186-
1187-
const area = shape.getArea();
1188-
shape.render(area);
1189-
});
1190-
}
1219+
const area = shape.getArea();
1220+
shape.render(area);
1221+
});
1222+
}
11911223

1192-
const shapes = [new Rectangle(), new Rectangle(), new Square()];
1224+
const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];
11931225
renderLargeShapes(shapes);
11941226
```
11951227
**[⬆ 상단으로](#목차)**
@@ -1520,7 +1552,7 @@ Gang of four의 [*Design Patterns*](https://en.wikipedia.org/wiki/Design_Pattern
15201552
"그럼 대체 상속을 언제 사용해야 되는 건가요?"라고 물어 볼 수 있습니다. 이건 당신이 직면한 문제 상황에 달려있지만
15211553
조합보다 상속을 쓰는게 더 좋을 만한 예시를 몇 개 들어 보겠습니다.
15221554

1523-
1. 당신의 상속관계가 "is-a" 관계가 아니라 "has-a" 관계일 때 (동물->사람 vs. 유저->유저정보)
1555+
1. 당신의 상속관계가 "is-a" 관계가 아니라 "has-a" 관계일 때 (사람->동물 vs. 유저->유저정보)
15241556
2. 기반 클래스의 코드를 다시 사용할 수 있을 때 (인간은 모든 동물처럼 움직일 수 있습니다.)
15251557
3. 기반 클래스를 수정하여 파생된 클래스 모두를 수정하고 싶을 때 (이동시 모든 동물이 소비하는 칼로리를 변경하고 싶을 때)
15261558

@@ -1596,7 +1628,7 @@ describe('MakeMomentJSGreatAgain', () => {
15961628

15971629
date = new MakeMomentJSGreatAgain('1/1/2015');
15981630
date.addDays(30);
1599-
date.shouldEqual('1/31/2015');
1631+
assert.equal('1/31/2015', date);
16001632

16011633
date = new MakeMomentJSGreatAgain('2/1/2016');
16021634
date.addDays(28);
@@ -1617,7 +1649,7 @@ describe('MakeMomentJSGreatAgain', () => {
16171649
it('handles 30-day months', () => {
16181650
const date = new MakeMomentJSGreatAgain('1/1/2015');
16191651
date.addDays(30);
1620-
date.shouldEqual('1/31/2015');
1652+
assert.equal('1/31/2015', date);
16211653
});
16221654

16231655
it('handles leap year', () => {
@@ -2027,3 +2059,16 @@ const actions = function() {
20272059
};
20282060
```
20292061
**[⬆ 상단으로](#목차)**
2062+
2063+
## 번역(Translation)
2064+
2065+
다른 언어로도 읽을 수 있습니다:
2066+
2067+
- ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [fesnt/clean-code-javascript](https://github.com/fesnt/clean-code-javascript)
2068+
- ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese**: [alivebao/clean-code-js](https://github.com/alivebao/clean-code-js)
2069+
- ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [marcbruederlin/clean-code-javascript](https://github.com/marcbruederlin/clean-code-javascript)
2070+
- ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [qkraudghgh/clean-code-javascript-ko](https://github.com/qkraudghgh/clean-code-javascript-ko)
2071+
- ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [BoryaMogila/clean-code-javascript-ru/](https://github.com/BoryaMogila/clean-code-javascript-ru/)
2072+
2073+
**[⬆ 상단으로](#목차)**
2074+

0 commit comments

Comments
 (0)