All Projects β†’ qkraudghgh β†’ clean-code-javascript-ko

qkraudghgh / clean-code-javascript-ko

Licence: other
πŸ› Clean Code concepts adapted for JavaScript - ν•œκΈ€ λ²ˆμ—­νŒ πŸ‡°πŸ‡·

Projects that are alternatives of or similar to clean-code-javascript-ko

Clean Code Dotnet
πŸ› Clean Code concepts and tools adapted for .NET
Stars: ✭ 4,425 (+150.42%)
Mutual labels:  clean-code, composition, inheritance, clean-architecture, principles
Clean Code Javascript
πŸ› Clean Code concepts adapted for JavaScript
Stars: ✭ 62,912 (+3460.38%)
Mutual labels:  clean-code, composition, inheritance, clean-architecture, principles
Clean Code Javascript
πŸ› Clean Code cho Javascript: mα»™t sα»‘ lời khuyΓͺn để giα»― cho code js của bαΊ‘n luΓ΄n sαΊ‘ch sαΊ½ thΖ‘m tho πŸ’ͺ πŸ’ͺ πŸ’ͺ
Stars: ✭ 166 (-90.61%)
Mutual labels:  clean-code, composition, clean-architecture, principles
Clean Code Javascript Tr
JavaScript için Uyarlanmış Temiz Kod Kavramları
Stars: ✭ 232 (-86.87%)
Mutual labels:  clean-code, composition, clean-architecture, principles
Write Readable Javascript Code
πŸ“– All about writing maintainable JavaScript
Stars: ✭ 244 (-86.19%)
Mutual labels:  clean-code, clean-architecture, principles
Android Clean Architecture
Showcasing a Clean Architecture approach from our Android applications framework!
Stars: ✭ 160 (-90.95%)
Mutual labels:  clean-code, clean-architecture
Coroutines Flows Modularised
Clean Architecture Modular Project: MVVM + Coroutines+ Flows + Dagger2 + LiveData + UnitTests + UITests + MockWebServer
Stars: ✭ 166 (-90.61%)
Mutual labels:  clean-code, clean-architecture
Architecture
.NET 6, ASP.NET Core 6, Entity Framework Core 6, C# 10, Angular 13, Clean Code, SOLID, DDD.
Stars: ✭ 2,285 (+29.32%)
Mutual labels:  clean-code, clean-architecture
clean architecture typescript example
This repository provides an implementation (or at least an attempt) of Uncle Bob's Clean Architecture with Typescript.
Stars: ✭ 78 (-95.59%)
Mutual labels:  clean-code, clean-architecture
Android Clean Architecture Mvvm Dagger Rx
Implemented by Clean Architecture, Dagger2, MVVM, LiveData, RX, Retrofit2, Room, Anko
Stars: ✭ 138 (-92.19%)
Mutual labels:  clean-code, clean-architecture
Typescript Clean Architecture
It is my attempt to create Clean Architecture based application in Typescript
Stars: ✭ 225 (-87.27%)
Mutual labels:  clean-code, clean-architecture
Dotnet New Caju
Learn Clean Architecture with .NET Core 3.0 πŸ”₯
Stars: ✭ 228 (-87.1%)
Mutual labels:  clean-code, clean-architecture
Clean Code Java
Clean Code concepts adapted for Java. Based on @ryanmcdermott repository.
Stars: ✭ 155 (-91.23%)
Mutual labels:  clean-code, clean-architecture
Cleanarchitecture.workerservice
A solution template using Clean Architecture for building a .NET Core Worker Service.
Stars: ✭ 142 (-91.96%)
Mutual labels:  clean-code, clean-architecture
Android Modular Architecture
πŸ“š Sample Android Components Architecture on a modular word focused on the scalability, testability and maintainability written in Kotlin, following best practices using Jetpack.
Stars: ✭ 2,048 (+15.9%)
Mutual labels:  clean-code, clean-architecture
Run Aspnetcore
A starter kit for your next ASP.NET Core web application. Boilerplate for ASP.NET Core reference application, demonstrating a layered application architecture with applying Clean Architecture and DDD best practices. Download 100+ page eBook PDF from here ->
Stars: ✭ 227 (-87.15%)
Mutual labels:  clean-code, clean-architecture
Baking App Kotlin
Android architecture sample with dynamic feature modularisation, clean architecture with MVI (Uni-directional data flow), dagger hilt, DFM Navigation, kotlin coroutines with StateFlow and Exo player.
Stars: ✭ 239 (-86.47%)
Mutual labels:  clean-code, clean-architecture
Clean Architecture Manga
πŸŒ€ Clean Architecture with .NET6, C#10 and React+Redux. Use cases as central organizing structure, completely testable, decoupled from frameworks
Stars: ✭ 3,104 (+75.66%)
Mutual labels:  clean-code, clean-architecture
Go Clean Architecture
πŸ‘¨β€πŸ’» REST API example, built by following Uncle Bob’s clean architecture principles
Stars: ✭ 133 (-92.47%)
Mutual labels:  clean-code, clean-architecture
Php Programming Best Practices
Referencia para los desarrolladores de Tiendanube y para la comunidad de PHP.
Stars: ✭ 138 (-92.19%)
Mutual labels:  clean-code, clean-architecture

clean-code-javascript

  • Updated date 2020.01.09
  • ν˜„μž¬ μ›λ¬Έμ˜ 1c0b20a κΉŒμ§€ λ°˜μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

λͺ©μ°¨

  1. μ†Œκ°œ(Introduction)
  2. λ³€μˆ˜(Variables)
  3. ν•¨μˆ˜(Functions)
  4. 객체와 자료ꡬ쑰(Objects and Data Structures)
  5. 클래슀(Classes)
  6. SOLID
  7. ν…ŒμŠ€νŠΈ(Testing)
  8. λ™μ‹œμ„±(Concurrency)
  9. μ—λŸ¬ 처리(Error Handling)
  10. ν¬λ§·νŒ…(Formatting)
  11. 주석(Comments)
  12. λ²ˆμ—­(Translation)

μ†Œκ°œ(Introduction)

μ½”λ“œλ₯Ό 읽을 λ•Œ μ†Œλ¦¬ 지λ₯΄λŠ” 숫자둜 μ†Œν”„νŠΈμ›¨μ–΄ ν’ˆμ§ˆμ„ μΆ”μ •ν•˜λŠ” 유머 사진

이 글은 μ†Œν”„νŠΈμ›¨μ–΄ 방법둠에 κ΄€ν•œ μ±…λ“€ 쀑 Robert C. Martin's의 책인 Clean Code에 μžˆλŠ” λ‚΄μš©μ„ JavaScript 언어에 μ μš©μ‹œμΌœ 적은 κΈ€ μž…λ‹ˆλ‹€. 이 글은 λ‹¨μˆœνžˆ Style Guideκ°€ μ•„λ‹ˆλΌ JavaScript둜 μ½”λ“œλ₯Ό μž‘μ„±ν• λ•Œ 읽기 쉽고, μž¬μ‚¬μš© κ°€λŠ₯ν•˜λ©° λ¦¬νŒ©ν† λ§ κ°€λŠ₯ν•˜κ²Œλ” μž‘μ„±ν•˜λ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

μ—¬κΈ° μžˆλŠ” λͺ¨λ“  원칙이 μ—„κ²©νžˆ μ§€μΌœμ Έμ•Όν•˜λŠ” 것은 μ•„λ‹ˆλ©°, 보편적으둜 ν†΅μš©λ˜λŠ” 원칙은 μ•„λ‹™λ‹ˆλ‹€. 이것듀은 지침일 뿐이며 Clean Code의 μ €μžκ°€ μˆ˜λ…„κ°„ κ²½ν—˜ν•œ λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ μ •λ¦¬ν•œ κ²ƒμž…λ‹ˆλ‹€.

μ†Œν”„νŠΈμ›¨μ–΄ μ—”μ§€λ‹ˆμ–΄λ§ μ—­μ‚¬λŠ” 50년을 쑰금 λ„˜κ²Όμ§€λ§Œ μš°λ¦¬λŠ” 아직도 λ§Žμ€ 것듀을 배우고 μžˆμŠ΅λ‹ˆλ‹€. 그리고 μ†Œν”„νŠΈμ›¨μ–΄ 아킀텍쳐가 건좕섀계 λ§ŒνΌμ΄λ‚˜ μ˜€λž˜λ˜μ—ˆμ„ λ•Œ μš°λ¦¬λŠ” μ•„λž˜ κ·œμΉ™λ“€λ³΄λ‹€ 더 μ—„κ²©ν•œ κ·œμΉ™λ“€μ„ 따라야 할지도 λͺ¨λ¦…λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ§€κΈˆ λ‹Ήμž₯은 이 κ°€μ΄λ“œ 라인을 λ‹Ήμ‹ κ³Ό λ‹Ήμ‹  νŒ€μ΄ μž‘μ„±ν•˜λŠ” JavaScript μ½”λ“œμ˜ ν’ˆμ§ˆμ„ ν‰κ°€ν•˜λŠ” κΈ°μ€€μœΌλ‘œ μ‚ΌμœΌμ„Έμš”.

ν•œκ°€μ§€ 더 λ§λΆ™μ΄μžλ©΄, 이 원칙듀을 μ•Œκ²Œλœλ‹€ν•΄μ„œ λ‹Ήμž₯ 더 λ‚˜μ€ κ°œλ°œμžκ°€ λ˜λŠ” 것은 μ•„λ‹ˆλ©° μ½”λ“œλ₯Ό μž‘μ„±ν•  λ•Œ μ‹€μˆ˜λ₯Ό ν•˜μ§€ μ•Šκ²Œ ν•΄μ£ΌλŠ” 것은 μ•„λ‹™λ‹ˆλ‹€. ν›Œλ₯­ν•œ λ„μžκΈ°λ“€μ΄ μ²˜μŒμ—” λ§λž‘ν•œ 점토뢀터 μ‹œμž‘ν•˜λ“―μ΄ λͺ¨λ“  μ½”λ“œλ“€μ€ μ²˜μŒλΆ€ν„° μ™„λ²½ν•  수 μ—†μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 당신은 νŒ€μ›λ“€κ³Ό 같이 μ½”λ“œλ₯Ό λ¦¬λ·°ν•˜λ©° 점점 μ™„λ²½ν•˜κ²Œ λ§Œλ“€μ–΄κ°€μ•Ό ν•©λ‹ˆλ‹€. 당신이 처음 μž‘μ„±ν•œ μ½”λ“œλ₯Ό κ³ μΉ  λ•Œ μ ˆλŒ€λ‘œ μžμ‹ μ„ μ§ˆνƒ€ν•˜μ§€ λ§ˆμ„Έμš”. λŒ€μ‹  μ½”λ“œλ₯Ό λΆ€μˆ˜κ³  더 λ‚˜μ€ μ½”λ“œλ₯Ό λ§Œλ“œμ„Έμš”!

λ³€μˆ˜(Variables)

의미있고 λ°œμŒν•˜κΈ° μ‰¬μš΄ λ³€μˆ˜ 이름을 μ‚¬μš©ν•˜μ„Έμš”

μ•ˆμ’‹μ€ 예:

const yyyymmdstr = moment().format('YYYY/MM/DD');

쒋은 예:

const currentDate = moment().format('YYYY/MM/DD');

⬆ μƒλ‹¨μœΌλ‘œ

λ™μΌν•œ μœ ν˜•μ˜ λ³€μˆ˜μ— λ™μΌν•œ μ–΄νœ˜λ₯Ό μ‚¬μš©ν•˜μ„Έμš”

μ•ˆμ’‹μ€ 예:

getUserInfo();
getClientData();
getCustomerRecord();

쒋은 예:

getUser();

⬆ μƒλ‹¨μœΌλ‘œ

검색가λŠ₯ν•œ 이름을 μ‚¬μš©ν•˜μ„Έμš”

μš°λ¦¬λŠ” μž‘μ„±ν•  μ½”λ“œλ³΄λ‹€ 읽을 μ½”λ“œκ°€ 더 λ§ŽμŠ΅λ‹ˆλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μ½”λ“œλ₯Ό 읽기 쉽고 검색 κ°€λŠ₯ν•˜κ²Œ μž‘μ„±ν•΄μ•Ό ν•©λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ μ—¬λŸ¬λΆ„μ˜ μ½”λ“œλ₯Ό μ΄ν•΄ν•˜λ €κ³  ν•˜λŠ” μ‚¬λžŒλ“€μ—κ²Œ 큰 어렀움을 μ€λ‹ˆλ‹€. 검색가λŠ₯ν•œ μ΄λ¦„μœΌλ‘œ λ§Œλ“œμ„Έμš”. buddy.js 그리고 ESLint 와 같은 도ꡬ듀이 이름이 μ •ν•΄μ Έμžˆμ§€ μ•Šμ€ μƒμˆ˜λ“€μ„ λ°œκ²¬ν•˜κ³  κ³ μΉ  수 있게 λ„μ™€μ€λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

// λŒ€μ²΄ 86400000 무엇을 μ˜λ―Έν•˜λŠ” κ±ΈκΉŒμš”?
setTimeout(blastOff, 86400000);

쒋은 예

// λŒ€λ¬Έμžλ‘œ `const` μ „μ—­ λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜μ„Έμš”
const MILLISECONDS_IN_A_DAY = 86400000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);

⬆ μƒλ‹¨μœΌλ‘œ

μ˜λ„λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ³€μˆ˜λ“€μ„ μ‚¬μš©ν•˜μ„Έμš”

μ•ˆμ’‹μ€ 예:

const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);

쒋은 예:

const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);

⬆ μƒλ‹¨μœΌλ‘œ

μžμ‹ λ§Œ μ•Œμ•„λ³Ό 수 μžˆλŠ” μž‘λͺ…을 ν”Όν•˜μ„Έμš”

λͺ…μ‹œμ μΈ 것이 μ•”μ‹œμ μΈ 것보닀 μ’‹μŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

const locations = ['μ„œμšΈ', '인천', 'μˆ˜μ›'];
locations.forEach(l => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  // 잠깐, `l`은 또 λ­˜κΉŒμš”?
  dispatch(l);
});

쒋은 예:

const locations = ['μ„œμšΈ', '인천', 'μˆ˜μ›'];
locations.forEach(location => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  dispatch(location);
});

⬆ μƒλ‹¨μœΌλ‘œ

λ¬Έλ§₯상 ν•„μš”μ—†λŠ” 것듀을 쓰지 λ§ˆμ„Έμš”

μ•ˆμ’‹μ€ 예:

const Car = {
  carMake: 'BMW',
  carModel: 'M3',
  carColor: 'νŒŒλž€μƒ‰'
};

function paintCar(car) {
  car.carColor = '빨간색';
}

쒋은 예:

const Car = {
  make: 'BMW',
  model: 'M3',
  color: 'νŒŒλž€μƒ‰'
};

function paintCar(car) {
  car.color = '빨간색';
}

⬆ μƒλ‹¨μœΌλ‘œ

κΈ°λ³Έ λ§€κ°œλ³€μˆ˜κ°€ short circuiting νŠΈλ¦­μ΄λ‚˜ 쑰건문 보닀 κΉ”λ”ν•©λ‹ˆλ‹€

κΈ°λ³Έ λ§€κ°œλ³€μˆ˜λŠ” μ’…μ’… short circuiting νŠΈλ¦­λ³΄λ‹€ κΉ”λ”ν•©λ‹ˆλ‹€. κΈ°λ³Έ λ§€κ°œλ³€μˆ˜λŠ” λ§€κ°œλ³€μˆ˜κ°€ undefinedμΌλ•Œλ§Œ μ μš©λ©λ‹ˆλ‹€. '', "", false, null, 0, NaN 같은 falsyν•œ 값듀은 κΈ°λ³Έ λ§€κ°œλ³€μˆ˜κ°€ μ μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function createMicrobrewery(name) {
  const breweryName = name || 'Hipster Brew Co.';
  // ...
}

쒋은 예:

function createMicrobrewery(name = 'Hipster Brew Co.') {
  // ...
}

⬆ μƒλ‹¨μœΌλ‘œ

ν•¨μˆ˜(Functions)

ν•¨μˆ˜ μΈμžλŠ” 2개 μ΄ν•˜κ°€ μ΄μƒμ μž…λ‹ˆλ‹€

λ§€κ°œλ³€μˆ˜μ˜ 개수λ₯Ό μ œν•œ ν•˜λŠ” 것은 ν•¨μˆ˜ ν…ŒμŠ€νŒ…μ„ μ‰½κ²Œ λ§Œλ“€μ–΄ μ£ΌκΈ° λ•Œλ¬Έμ— μ€‘μš”ν•©λ‹ˆλ‹€. λ§Œμ•½ λ§€κ°œλ³€μˆ˜κ°€ 3개 이상일 κ²½μš°μ—” ν…ŒμŠ€νŠΈ ν•΄μ•Όν•˜λŠ” 경우의 μˆ˜κ°€ λ§Žμ•„μ§€κ³  각기 λ‹€λ₯Έ μΈμˆ˜λ“€λ‘œ μ—¬λŸ¬ 사둀듀을 ν…ŒμŠ€νŠΈ ν•΄μ•Όν•©λ‹ˆλ‹€.

1κ°œλ‚˜ 2개의 인자λ₯Ό 가지고 μžˆλŠ” 것이 κ°€μž₯ 이상적인 μΌ€μ΄μŠ€μž…λ‹ˆλ‹€. 그리고 3개의 μΈμžλŠ” κ°€λŠ₯ν•œ ν”Όν•΄μ•Όν•©λ‹ˆλ‹€. 그것보닀 더 λ§Žλ‹€λ©΄ ν†΅ν•©λ˜μ–΄μ•Όν•©λ‹ˆλ‹€. λ§Œμ•½ 당신이 2개 μ΄μƒμ˜ 인자λ₯Ό 가진 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ κ·Έ ν•¨μˆ˜μ—κ²Œ λ„ˆλ¬΄ λ§Žμ€ 역할을 ν•˜κ²Œ λ§Œλ“  κ²ƒμž…λ‹ˆλ‹€. 그렇지 μ•Šμ€ 경우라면 λŒ€λΆ€λΆ„μ˜ 경우 μƒμœ„ κ°μ²΄λŠ” 1개의 인자만으둜 μΆ©λΆ„ν•©λ‹ˆλ‹€.

JavaScriptλ₯Ό μ‚¬μš©ν•  λ•Œ λ§Žμ€ λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈ 없이 λ°”λ‘œ 객체λ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ 당신이 λ§Œμ•½ λ§Žμ€ μΈμžλ“€μ„ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€λ©΄ 객체λ₯Ό μ΄μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν•¨μˆ˜κ°€ κΈ°λŒ€ν•˜λŠ” 속성을 쒀더 λͺ…ν™•νžˆ ν•˜κΈ° μœ„ν•΄μ„œ es6의 비ꡬ쑰화(destructuring) ꡬ문을 μ‚¬μš©ν•  수 있고 이 κ΅¬λ¬Έμ—λŠ” λͺ‡κ°€μ§€ μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.

  1. μ–΄λ–€ μ‚¬λžŒμ΄ κ·Έ ν•¨μˆ˜μ˜ μ‹œκ·Έλ‹ˆμ³(인자의 νƒ€μž…, λ°˜ν™˜λ˜λŠ” κ°’μ˜ νƒ€μž… λ“±)λ₯Ό λ³Ό λ•Œ μ–΄λ–€ 속성이 μ‚¬μš©λ˜λŠ”μ§€ μ¦‰μ‹œ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
  2. λ˜ν•œ λΉ„κ΅¬μ‘°ν™”λŠ” ν•¨μˆ˜μ— μ „λ‹¬λœ 인수 객체의 μ§€μ •λœ κΈ°λ³Ένƒ€μž… 값을 λ³΅μ œν•˜λ©° μ΄λŠ” μ‚¬μ΄λ“œμ΄νŽ™νŠΈκ°€ μΌμ–΄λ‚˜λŠ” 것을 λ°©μ§€ν•©λ‹ˆλ‹€. 참고둜 인수 κ°μ²΄λ‘œλΆ€ν„° λΉ„κ΅¬μ‘°ν™”λœ 객체와 배열은 λ³΅μ œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  3. Linterλ₯Ό μ‚¬μš©ν•˜λ©΄ μ‚¬μš©ν•˜μ§€μ•ŠλŠ” μΈμžμ— λŒ€ν•΄ κ²½κ³ ν•΄μ£Όκ±°λ‚˜ 비ꡬ쑰화 없이 μ½”λ“œλ₯Ό 지 수 μ—†κ²Œ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function createMenu(title, body, buttonText, cancellable) {
  // ...
}

쒋은 예:

function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}

createMenu({
  title: 'Foo',
  body: 'Bar',
  buttonText: 'Baz',
  cancellable: true
});

⬆ μƒλ‹¨μœΌλ‘œ

ν•¨μˆ˜λŠ” ν•˜λ‚˜μ˜ ν–‰λ™λ§Œ ν•΄μ•Όν•©λ‹ˆλ‹€

이것은 μ†Œν”„νŠΈμ›¨μ–΄ μ—”μ§€λ‹ˆμ–΄λ§μ—μ„œ κ°€μž₯ μ€‘μš”ν•œ κ·œμΉ™μž…λ‹ˆλ‹€. ν•¨μˆ˜κ°€ 1개 μ΄μƒμ˜ 행동을 ν•œλ‹€λ©΄ μž‘μ„±ν•˜λŠ” 것도, ν…ŒμŠ€νŠΈν•˜λŠ” 것도, μ΄ν•΄ν•˜λŠ” 것도 μ–΄λ €μ›Œμ§‘λ‹ˆλ‹€. 당신이 ν•˜λ‚˜μ˜ ν•¨μˆ˜μ— ν•˜λ‚˜μ˜ 행동을 μ •μ˜ν•˜λŠ” 것이 κ°€λŠ₯해진닀면 ν•¨μˆ˜λŠ” μ’€ 더 고치기 μ‰¬μ›Œμ§€κ³  μ½”λ“œλ“€μ€ 읽기 μ‰¬μ›Œμ§ˆ κ²ƒμž…λ‹ˆλ‹€. λ§Žμ€ 원칙듀 쀑 μ΄κ²ƒλ§Œ μ•Œμ•„κ°„λ‹€ ν•˜λ”λΌλ„ 당신은 λ§Žμ€ κ°œλ°œμžλ“€μ„ μ•žμ„€ 수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function emailClients(clients) {
  clients.forEach(client => {
    const clientRecord = database.lookup(client);
    if (clientRecord.isActive()) {
      email(client);
    }
  });
}

쒋은 예:

function emailClients(clients) {
  clients
    .filter(isClientActive)
    .forEach(email);
}

function isClientActive(client) {
  const clientRecord = database.lookup(client);
  return clientRecord.isActive();
}

⬆ μƒλ‹¨μœΌλ‘œ

ν•¨μˆ˜λͺ…은 ν•¨μˆ˜κ°€ 무엇을 ν•˜λŠ”μ§€ μ•Œ 수 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€

μ•ˆμ’‹μ€ 예:

function AddToDate(date, month) {
  // ...
}

const date = new Date();

// 뭘 μΆ”κ°€ν•˜λŠ” 건지 μ΄λ¦„λ§Œ 보고 μ•Œμ•„λ‚΄κΈ° νž˜λ“­λ‹ˆλ‹€.
AddToDate(date, 1);

쒋은 예:

function AddMonthToDate(date, month) {
  // ...
}

const date = new Date();
AddMonthToDate(date, 1);

⬆ μƒλ‹¨μœΌλ‘œ

ν•¨μˆ˜λŠ” 단일 행동을 좔상화 ν•΄μ•Όν•©λ‹ˆλ‹€

μΆ”μƒν™”λœ 이름이 μ—¬λŸ¬ 의미λ₯Ό λ‚΄ν¬ν•˜κ³  μžˆλ‹€λ©΄ κ·Έ ν•¨μˆ˜λŠ” λ„ˆλ¬΄ λ§Žμ€ 일을 ν•˜κ²Œλ” μ„€κ³„λœ κ²ƒμž…λ‹ˆλ‹€. ν•¨μˆ˜λ“€μ„ λ‚˜λˆ„μ–΄μ„œ μž¬μ‚¬μš©κ°€λŠ₯ν•˜κ³  ν…ŒμŠ€νŠΈν•˜κΈ° μ‰½κ²Œ λ§Œλ“œμ„Έμš”.

μ•ˆμ’‹μ€ 예:

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...
  });
}

쒋은 예:

function tokenize(code) {
  const REGEXES = [
    // ...
  ];

  const statements = code.split(' ');
  const tokens = [];
  REGEXES.forEach(REGEX => {
    statements.forEach(statement => {
      tokens.push( /* ... */ );
    });
  });

  return tokens;
}

function lexer(tokens) {
  const ast = [];
  tokens.forEach(token => {
    ast.push( /* ... */ );
  });

  return ast;
}

function parseBetterJSAlternative(code) {
  const tokens = tokenize(code);
  const ast = lexer(tokens);
  ast.forEach(node => {
    // parse...
  });
}

⬆ μƒλ‹¨μœΌλ‘œ

μ€‘λ³΅λœ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ λ§ˆμ„Έμš”

μ€‘λ³΅λœ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ μ•ŠκΈ°μœ„ν•΄ μ΅œμ„ μ„ λ‹€ν•˜μ„Έμš”. μ€‘λ³΅λœ μ½”λ“œκ°€ μžˆλ‹€λŠ” 것은 μ–΄λ–€ λ‘œμ§μ„ μˆ˜μ •ν•΄μ•Ό ν•  일이 생겼을 λ•Œ μˆ˜μ • ν•΄μ•Όν•  μ½”λ“œκ°€ ν•œ κ³³ μ΄μƒμ΄λΌλŠ” 것을 λœ»ν•©λ‹ˆλ‹€.

λ§Œμ•½ 당신이 λ ˆμŠ€ν† λž‘μ„ μš΄μ˜ν•˜λ©΄μ„œ ν† λ§ˆν† λ‚˜ μ–‘νŒŒ, 마늘, 고좔같은 κ²ƒλ“€μ˜ μž¬κ³ κ΄€λ¦¬λ₯Ό ν•΄μ•Όν•œλ‹€κ³  μƒκ°ν•΄λ³΄μ„Έμš”. μž¬κ³ κ°€ μ ν˜€μžˆλŠ” 쒅이가 μ—¬λŸ¬μž₯ μžˆλ‹€λ©΄ ν† λ§ˆν† λ‚˜ μ–‘νŒŒμ˜ μž¬κ³ κ°€ λ³€λ™λ˜μ—ˆμ„ λ•Œ μž¬κ³ κ°€ μ ν˜€μžˆλŠ” λͺ¨λ“  쒅이λ₯Ό μˆ˜μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. λ§Œμ•½ 재고λ₯Ό κ΄€λ¦¬ν•˜λŠ” 쒅이가 ν•œ μž₯μ΄μ—ˆλ‹€λ©΄ ν•œ μž₯의 재고 λͺ©λ‘λ§Œ μˆ˜μ •ν•˜λ©΄ 됐겠죠!

μ’…μ’… μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ μ‚¬μ†Œν•œ λͺ‡λͺ‡μ˜ 차이점 λ•Œλ¬Έμ— μ€‘λ³΅λœ μ½”λ“œλ₯Ό μž‘μ„±ν•œ κ²½μš°κ°€ 있고 이런 차이점듀은 λŒ€λΆ€λΆ„ λ˜‘κ°™μ€ 일을 ν•˜λŠ” λΆ„λ¦¬λœ ν•¨μˆ˜λ“€μ„ 갖도둝 κ°•μš”ν•©λ‹ˆλ‹€. 즉 쀑볡 μ½”λ“œλ₯Ό μ œκ±°ν•œλ‹€λŠ” 것은 ν•˜λ‚˜μ˜ ν•¨μˆ˜ / λͺ¨λ“ˆ / 클래슀λ₯Ό μ‚¬μš©ν•˜μ—¬ 이 μ—¬λŸ¬ 가지 μ‚¬μ†Œν•œ 차이점을 처리 ν•  수 μžˆλŠ” 좔상화λ₯Ό λ§Œλ“œλŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.

그리고 좔상화 ν•  뢀뢄이 λ‚¨μ•„μžˆλŠ” 것은 μœ„ν—˜ν•˜κΈ°λ•Œλ¬Έμ— 클래슀 μ„Ήμ…˜μ— μ œμ‹œλœ μ—¬λŸ¬ 원칙듀을 따라야 ν•©λ‹ˆλ‹€. 잘 좔상화 ν•˜μ§€ λͺ»ν•œ μ½”λ“œλŠ” μ€‘λ³΅λœ μ½”λ“œλ³΄λ‹€ λ‚˜μ  수 μžˆμœΌλ―€λ‘œ μ‘°μ‹¬ν•˜μ„Έμš”. 즉 좔상화λ₯Ό 잘 ν•  수 μžˆλ‹€λ©΄ κ·Έλ ‡κ²Œ ν•˜λΌλŠ” λ§μž…λ‹ˆλ‹€. μ½”λ“œμ˜ 쀑볡을 ν”Όν•œλ‹€λ©΄ μ—¬λŸ¬λΆ„μ΄ 원할 λ•Œ μ–Έμ œλ“  ν•œ 곳만 μˆ˜μ •ν•΄λ„ λ‹€λ₯Έ λͺ¨λ“  μ½”λ“œμ— 반영되게 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function showDeveloperList(developers) {
  developers.forEach(developers => {
    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);
  });
}

쒋은 예:

function showEmployeeList(employees) {
  employees.forEach((employee) => {
    const expectedSalary = employee.calculateExpectedSalary();
    const experience = employee.getExperience();

    let portfolio = employee.getGithubLink();

    if (employee.type === 'manager') {
      portfolio = employee.getMBAProjects();
    }

    const data = {
      expectedSalary,
      experience,
      portfolio
    };

    render(data);
  });
}

⬆ μƒλ‹¨μœΌλ‘œ

Object.assign을 μ‚¬μš©ν•΄ κΈ°λ³Έ 객체λ₯Ό λ§Œλ“œμ„Έμš”

μ•ˆμ’‹μ€ 예:

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);

쒋은 예:

const menuConfig = {
  title: 'Order',
  // μœ μ €κ°€ 'body' key의 valueλ₯Ό μ •ν•˜μ§€ μ•Šμ•˜λ‹€.
  buttonText: 'Send',
  cancellable: true
};

function createMenu(config) {
  config = Object.assign({
    title: 'Foo',
    body: 'Bar',
    buttonText: 'Baz',
    cancellable: true
  }, config);

  // configλŠ” 이제 λ‹€μŒκ³Ό λ™μΌν•©λ‹ˆλ‹€: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
  // ...
}

createMenu(menuConfig);

⬆ μƒλ‹¨μœΌλ‘œ

λ§€κ°œλ³€μˆ˜λ‘œ ν”Œλž˜κ·Έλ₯Ό μ‚¬μš©ν•˜μ§€ λ§ˆμ„Έμš”

ν”Œλž˜κ·Έλ₯Ό μ‚¬μš©ν•˜λŠ” 것 μžμ²΄κ°€ κ·Έ ν•¨μˆ˜κ°€ ν•œκ°€μ§€ μ΄μƒμ˜ 역할을 ν•˜κ³  μžˆλ‹€λŠ” 것을 λœ»ν•©λ‹ˆλ‹€. boolean 기반으둜 ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜λŠ” μ½”λ“œκ°€ λ‚˜λ‰œλ‹€λ©΄ ν•¨μˆ˜λ₯Ό λΆ„λ¦¬ν•˜μ„Έμš”.

μ•ˆμ’‹μ€ 예:

function createFile(name, temp) {
  if (temp) {
    fs.create(`./temp/${name}`);
  } else {
    fs.create(name);
  }
}

쒋은 예:

function createFile(name) {
  fs.create(name);
}

function createTempFile(name) {
  createFile(`./temp/${name}`);
}

⬆ μƒλ‹¨μœΌλ‘œ

μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλ₯Ό ν”Όν•˜μ„Έμš” (part 1)

ν•¨μˆ˜λŠ” 값을 λ°›μ•„μ„œ μ–΄λ–€ 일을 ν•˜κ±°λ‚˜ 값을 리턴할 λ•Œ μ‚¬μ΄λ“œ 이팩트λ₯Ό λ§Œλ“€μ–΄λƒ…λ‹ˆλ‹€. μ‚¬μ΄λ“œ μ΄νŒ©νŠΈλŠ” νŒŒμΌμ— μ“°μ—¬μ§ˆ μˆ˜λ„ 있고, μ „μ—­ λ³€μˆ˜λ₯Ό μˆ˜μ •ν•  수 있으며, μ‹€μˆ˜λ‘œ λͺ¨λ“  λˆμ„ λ‹€λ₯Έ μ‚¬λžŒμ—κ²Œ 보낼 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

당신은 λ•Œλ•Œλ‘œ ν”„λ‘œκ·Έλž¨μ—μ„œ μ‚¬μ΄λ“œ 이팩트λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•  λ•Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. μ•„κΉŒ λ“€μ—ˆλ˜ μ˜ˆλ“€ 쀑 ν•˜λ‚˜μΈ νŒŒμΌμž‘μ„±μ„ ν•  λ•Œμ™€ 같이 말이죠. 이 λ•Œ μ—¬λŸ¬λΆ„μ΄ ν•΄μ•Όν•  일은 파일 μž‘μ„±μ„ ν•˜λŠ” ν•œ 개의 ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” 일 μž…λ‹ˆλ‹€. νŒŒμΌμ„ μž‘μ„±ν•˜λŠ” ν•¨μˆ˜λ‚˜ ν΄λž˜μŠ€κ°€ μ—¬λŸ¬κ°œ μ‘΄μž¬ν•˜λ©΄ μ•ˆλ©λ‹ˆλ‹€. λ°˜λ“œμ‹œ ν•˜λ‚˜λ§Œ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

즉, μ–΄λ– ν•œ ꡬ쑰체도 없이 객체 μ‚¬μ΄μ˜ μƒνƒœλ₯Ό κ³΅μœ ν•˜κ±°λ‚˜, 무엇이든 μ“Έ 수 μžˆλŠ” λ³€κ²½ κ°€λŠ₯ν•œ 데이터 μœ ν˜•μ„ μ‚¬μš©ν•˜κ±°λ‚˜, 같은 μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλ₯Ό λ§Œλ“€μ–΄λ‚΄λŠ” 것을 μ—¬λŸ¬κ°œ λ§Œλ“€κ±°λ‚˜ν•˜λ©΄ μ•ˆλ©λ‹ˆλ‹€. μ—¬λŸ¬λΆ„λ“€μ΄ μ΄λŸ¬ν•œ 것듀을 지킀며 μ½”λ“œλ₯Ό μž‘μ„±ν•œλ‹€λ©΄ λŒ€λΆ€λΆ„μ˜ λ‹€λ₯Έ κ°œλ°œμžλ“€λ³΄λ‹€ 행볡할 수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

// μ•„λž˜ ν•¨μˆ˜μ— μ˜ν•΄ μ°Έμ‘°λ˜λŠ” μ „μ—­ λ³€μˆ˜μž…λ‹ˆλ‹€.
// 이 μ „μ—­ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 또 ν•˜λ‚˜μ˜ ν•¨μˆ˜κ°€ μžˆλ‹€κ³  μƒκ°ν•΄λ³΄μ„Έμš”. 이제 이 λ³€μˆ˜λŠ” 배열이 될 것이고, ν”„λ‘œκ·Έλž¨μ„ λ§κ°€λœ¨λ¦¬κ² μ£ .
let name = 'Ryan McDermott';

function splitIntoFirstAndLastName() {
  name = name.split(' ');
}

splitIntoFirstAndLastName();

console.log(name); // ['Ryan', 'McDermott'];

쒋은 예:

function splitIntoFirstAndLastName(name) {
  return name.split(' ');
}

const name = 'Ryan McDermott';
const newName = splitIntoFirstAndLastName(name);

console.log(name); // 'Ryan McDermott';
console.log(newName); // ['Ryan', 'McDermott'];

⬆ μƒλ‹¨μœΌλ‘œ

μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλ₯Ό ν”Όν•˜μ„Έμš” (part 2)

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” κΈ°λ³Ένƒ€μž… μžλ£Œν˜•μ€ 값을 μ „λ‹¬ν•˜κ³  객체와 배열은 μ°Έμ‘°λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€. 객체와 배열인 경우λ₯Ό ν•œλ²ˆ μ‚΄νŽ΄λ΄…μ‹œλ‹€. μš°λ¦¬κ°€ λ§Œλ“  ν•¨μˆ˜λŠ” μž₯λ°”κ΅¬λ‹ˆ 배열에 λ³€ν™”λ₯Ό μ£Όλ©° 이 λ³€ν™”λŠ” ꡬ맀λͺ©λ‘μ— μ–΄λ–€ μƒν’ˆμ„ μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯ 같은 것을 λ§ν•©λ‹ˆλ‹€. λ§Œμ•½ μž₯λ°”κ΅¬λ‹ˆ 배열을 μ‚¬μš©ν•˜λŠ” μ–΄λŠ λ‹€λ₯Έ ν•¨μˆ˜κ°€ μžˆλ‹€λ©΄ μ΄λŸ¬ν•œ 좔가에 영ν–₯을 λ°›μŠ΅λ‹ˆλ‹€. 이것은 쒋을 μˆ˜λ„ μžˆμ§€λ§Œ, μ•ˆμ’‹μ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ•ˆμ’‹μ€ 예λ₯Ό ν•œλ²ˆ μƒμƒν•΄λ΄…μ‹œλ‹€.

μœ μ €κ°€ κ΅¬λ§€ν•˜κΈ° λ²„νŠΌμ„ 눌러 ꡬ맀 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€. μ΄λŠ” λ„€νŠΈμ›Œν¬ μš”μ²­μ„ μƒμ„±ν•˜κ³  μ„œλ²„μ— μž₯λ°”κ΅¬λ‹ˆ 배열을 λ³΄λƒ…λ‹ˆλ‹€. ν•˜μ§€λ§Œ λ„€νŠΈμ›Œν¬ 연결이 μ’‹μ§€μ•Šμ•„μ„œ ꡬ맀 ν•¨μˆ˜λŠ” λ‹€μ‹œν•œλ²ˆ λ„€νŠΈμ›Œν¬ μš”μ²­μ„ 보내야 ν•˜λŠ” 상황이 μƒκ²ΌμŠ΅λ‹ˆλ‹€. μ΄λ•Œ, μ‚¬μš©μžκ°€ λ„€νŠΈμ›Œν¬ μš”μ²­μ΄ μ‹œμž‘λ˜κΈ° 전에 μ‹€μˆ˜λ‘œ μ›ν•˜μ§€ μ•ŠλŠ” μƒν’ˆμ˜ "μž₯λ°”κ΅¬λ‹ˆμ— μΆ”κ°€" λ²„νŠΌμ„ μ‹€μˆ˜λ‘œ ν΄λ¦­ν•˜λ©΄ μ–΄λ–»κ²Œλ κΉŒμš”? μ‹€μˆ˜κ°€ μžˆκ³ λ‚œ λ’€, λ„€νŠΈμ›Œν¬ μš”μ²­μ΄ μ‹œμž‘λ˜λ©΄ μž₯λ°”κ΅¬λ‹ˆμ— μΆ”κ°€ ν•¨μˆ˜ λ•Œλ¬Έμ— μ‹€μˆ˜λ‘œ λ³€κ²½λœ μž₯λ°”κ΅¬λ‹ˆ 배열을 μ„œλ²„μ— λ³΄λ‚΄κ²Œ λ©λ‹ˆλ‹€.

κ°€μž₯ 쒋은 방법은 μž₯λ°”κ΅¬λ‹ˆμ— μΆ”κ°€λŠ” 항상 μž₯λ°”κ΅¬λ‹ˆ 배열을 λ³΅μ œν•˜μ—¬ μˆ˜μ •ν•˜κ³  λ³΅μ œλ³Έμ„ λ°˜ν™˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μ΄λ ‡κ²Œν•˜λ©΄ μž₯λ°”κ΅¬λ‹ˆ μ°Έμ‘°λ₯Ό λ³΄μœ ν•˜κ³ μžˆλŠ” λ‹€λ₯Έ ν•¨μˆ˜κ°€ λ‹€λ₯Έ λ³€κ²½ μ‚¬ν•­μ˜ 영ν–₯을 받지 μ•Šκ²Œλ©λ‹ˆλ‹€.

이 μ ‘κ·Όλ²•μ—λŒ€ν•΄ λ§ν•˜κ³  싢은 것이 두가지 μžˆμŠ΅λ‹ˆλ‹€.

  1. μ‹€μ œλ‘œ μž…λ ₯된 객체λ₯Ό μˆ˜μ •ν•˜κ³  싢은 κ²½μš°κ°€ μžˆμ„ 수 μžˆμ§€λ§Œ μ΄λŸ¬ν•œ 예제λ₯Ό 생각해보고 μ μš©ν•΄λ³΄λ©΄ 그런 κ²½μš°λŠ” 거의 μ—†λ‹€λŠ” 것을 깨달을 수 μžˆμŠ΅λ‹ˆλ‹€. 그리고 λŒ€λΆ€λΆ„μ˜ 것듀이 μ‚¬μ΄λ“œ μ΄νŽ™νŠΈ 없이 λ¦¬νŒ©ν† λ§ 될 수 μžˆμŠ΅λ‹ˆλ‹€.
  2. 큰 객체λ₯Ό λ³΅μ œν•˜λŠ” 것은 μ„±λŠ₯ μΈ‘λ©΄μ—μ„œ 값이 맀우 λΉ„μŒ‰λ‹ˆλ‹€. μš΄μ’‹κ²Œλ„ 이런게 큰 λ¬Έμ œκ°€ λ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ μ΄λŸ¬ν•œ ν”„λ‘œκ·Έλž˜λ° 접근법을 κ°€λŠ₯ν•˜κ²Œν•΄μ€„ 쒋은 λΌμ΄λΈŒλŸ¬λ¦¬κ°€ 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. μ΄λŠ” 객체와 배열을 μˆ˜λ™μœΌλ‘œ λ³΅μ œν•˜λŠ” κ²ƒμ²˜λŸΌ λ©”λͺ¨λ¦¬ 집약적이지 μ•Šκ²Œ ν•΄μ£Όκ³  λΉ λ₯΄κ²Œ λ³΅μ œν•΄μ€λ‹ˆλ‹€.

Bad:

const addItemToCart = (cart, item) => {
  cart.push({ item, date: Date.now() });
};

Good:

const addItemToCart = (cart, item) => {
  return [...cart, { item, date : Date.now() }];
};

⬆ μƒλ‹¨μœΌλ‘œ

μ „μ—­ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ§€ λ§ˆμ„Έμš”

μ „μ—­ ν™˜κ²½μ„ μ‚¬μš©ν•˜λŠ” 것은 JavaScriptμ—μ„œ λ‚˜μœ κ΄€ν–‰μž…λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ λ‹€λ₯Έ λΌμ΄λΈŒλŸ¬λ¦¬λ“€κ³Όμ˜ 좩돌이 일어날 수 있고, λ‹Ήμ‹ μ˜ APIλ₯Ό μ“°λŠ” μœ μ €λ“€μ€ μš΄μ˜ν™˜κ²½μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜κΈ° μ „κΉŒμ§€λŠ” 문제λ₯Ό μΈμ§€ν•˜μ§€ λͺ»ν•  것이기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 예제λ₯Ό ν•˜λ‚˜ μƒκ°ν•΄λ΄…μ‹œλ‹€. JavaScript의 λ„€μ΄ν‹°λΈŒ Array λ©”μ†Œλ“œλ₯Ό ν™•μž₯ν•˜μ—¬ 두 λ°°μ—΄ κ°„μ˜ 차이λ₯Ό 보여쀄 μˆ˜μžˆλŠ” diff λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Όν• κΉŒμš”? μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό Array.prototype에 μ“Έ μˆ˜λ„ μžˆμ§€λ§Œ, λ˜‘κ°™μ€ 일을 μ‹œλ„ν•œ λ‹€λ₯Έ λΌμ΄λΈŒλŸ¬λ¦¬μ™€ 좩돌 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€λ₯Έ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ diff λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 첫번째 μš”μ†Œμ™€ λ§ˆμ§€λ§‰ μš”μ†Œμ˜ 차이점을 찾으면 μ–΄λ–»κ²Œ λ κΉŒμš”? 이것이 κ·Έλƒ₯ ES2015/ES6의 classesλ₯Ό μ‚¬μš©ν•΄μ„œ μ „μ—­ Arrayλ₯Ό μƒμ†ν•΄λ²„λ¦¬λŠ” 것이 훨씬 더 λ‚˜μ€ μ΄μœ μž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};

쒋은 예:

class SuperArray extends Array {
  diff(comparisonArray) {
    const hash = new Set(comparisonArray);
    return this.filter(elem => !hash.has(elem));
  }
}

⬆ μƒλ‹¨μœΌλ‘œ

λͺ…λ Ήν˜• ν”„λ‘œκ·Έλž˜λ°λ³΄λ‹€ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ 지ν–₯ν•˜μ„Έμš”

JavaScriptλŠ” Haskell처럼 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λŠ” μ•„λ‹ˆμ§€λ§Œ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ²˜λŸΌ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜ν˜• μ–Έμ–΄λŠ” 더 κΉ”λ”ν•˜κ³  ν…ŒμŠ€νŠΈν•˜κΈ° μ‰½μŠ΅λ‹ˆλ‹€. κ°€λŠ₯ν•˜λ©΄ 이 방식을 μ‚¬μš©ν•˜λ„λ‘ ν•΄λ³΄μ„Έμš”.

μ•ˆμ’‹μ€ 예:

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;
}

쒋은 예:

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
  .map(programmer => programmer.linesOfCode)
  .reduce((acc, linesOfCode) => acc + linesOfCode, INITIAL_VALUE);

⬆ μƒλ‹¨μœΌλ‘œ

쑰건문을 μΊ‘μŠν™” ν•˜μ„Έμš”

μ•ˆμ’‹μ€ 예:

if (fsm.state === 'fetching' && isEmpty(listNode)) {
  // ...
}

쒋은 예:

function shouldShowSpinner(fsm, listNode) {
  return fsm.state === 'fetching' && isEmpty(listNode);
}

if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
  // ...
}

⬆ μƒλ‹¨μœΌλ‘œ

뢀정쑰건문을 μ‚¬μš©ν•˜μ§€ λ§ˆμ„Έμš”

μ•ˆμ’‹μ€ 예:

function isDOMNodeNotPresent(node) {
  // ...
}

if (!isDOMNodeNotPresent(node)) {
  // ...
}

쒋은 예:

function isDOMNodePresent(node) {
  // ...
}

if (isDOMNodePresent(node)) {
  // ...
}

⬆ μƒλ‹¨μœΌλ‘œ

쑰건문 μž‘μ„±μ„ ν”Όν•˜μ„Έμš”

쑰건문 μž‘μ„±μ„ ν”Όν•˜λΌλŠ” 것은 맀우 λΆˆκ°€λŠ₯ν•œ 일둜 λ³΄μž…λ‹ˆλ‹€. 이 μ–˜κΈ°λ₯Ό 처음 λ“£λŠ” μ‚¬λžŒλ“€μ€ λŒ€λΆ€λΆ„ "Ifλ¬Έ 없이 μ–΄λ–»κ²Œ μ½”λ“œλ₯Ό μ§œλ‚˜μš”?"라고 λ§ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ λ‹€ν˜•μ„±μ„ μ΄μš©ν•œλ‹€λ©΄ λ™μΌν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‘λ²ˆμ§Έ μ§ˆλ¬Έμ€ 보톡 "λ„€ μ’‹λ„€μš” 근데 λ‚΄κ°€ μ™œ κ·Έλ ‡κ²Œ ν•΄μ•Όν•˜λ‚˜μš”?"이죠. 그에 λŒ€ν•œ λŒ€λ‹΅μ€, μ•žμ„œ μš°λ¦¬κ°€ κ³΅λΆ€ν–ˆλ˜ clean code 컨셉에 μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜λŠ” 단 ν•˜λ‚˜μ˜ 일만 μˆ˜ν–‰ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€. 당신이 ν•¨μˆ˜λ‚˜ ν΄λž˜μŠ€μ— if문을 μ“΄λ‹€λ©΄ 그것은 κ·Έ ν•¨μˆ˜λ‚˜ ν΄λž˜μŠ€κ°€ ν•œκ°€μ§€ μ΄μƒμ˜ 일을 μˆ˜ν–‰ν•˜κ³  μžˆλ‹€κ³  λ§ν•˜λŠ” 것과 κ°™μŠ΅λ‹ˆλ‹€. κΈ°μ–΅ν•˜μ„Έμš”, ν•˜λ‚˜μ˜ ν•¨μˆ˜λŠ” λ”± ν•˜λ‚˜μ˜ 일만 ν•΄μ•Όν•©λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

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();
    }
  }
}

쒋은 예:

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() {
    return this.getMaxAltitude() - this.getFuelExpenditure();
  }
}

⬆ μƒλ‹¨μœΌλ‘œ

νƒ€μž…-체킹을 ν”Όν•˜μ„Έμš” (part 1)

JavaScriptλŠ” νƒ€μž…μ΄ μ •ν•΄μ Έμžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ΄λŠ” λ‹Ήμ‹ μ˜ ν•¨μˆ˜κ°€ μ–΄λ–€ νƒ€μž…μ˜ μΈμžλ“  받을 수 μžˆλ‹€λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. 이런 JavaScript의 μžμœ λ‘œμ›€ λ•Œλ¬Έμ— μ—¬λŸ¬ 버그가 λ°œμƒν–ˆμ—ˆκ³  이 λ•Œλ¬Έμ— λ‹Ήμ‹ μ˜ ν•¨μˆ˜μ— νƒ€μž…-체킹을 μ‹œλ„ ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ νƒ€μž…-체킹 말고도 μ΄λŸ¬ν•œ ν™”λ₯Ό ν”Όν•  λ§Žμ€ 방법듀이 μ‘΄μž¬ν•©λ‹ˆλ‹€. 첫번째 방법은 일관성 μžˆλŠ” APIλ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function travelToTexas(vehicle) {
  if (vehicle instanceof Bicycle) {
    vehicle.pedal(this.currentLocation, new Location('texas'));
  } else if (vehicle instanceof Car) {
    vehicle.drive(this.currentLocation, new Location('texas'));
  }
}

쒋은 예:

function travelToTexas(vehicle) {
  vehicle.move(this.currentLocation, new Location('texas'));
}

⬆ μƒλ‹¨μœΌλ‘œ

νƒ€μž…-체킹을 ν”Όν•˜μ„Έμš” (part 2)

당신이 λ¬Έμžμ—΄, μ •μˆ˜, λ°°μ—΄λ“± κΈ°λ³Έ μžλ£Œν˜•μ„ μ‚¬μš©ν•˜κ³  λ‹€ν˜•μ„±μ„ μ‚¬μš©ν•  수 없을 λ•Œ μ—¬μ „νžˆ νƒ€μž…-체킹이 ν•„μš”ν•˜λ‹€κ³  λŠκ»΄μ§„λ‹€λ©΄ TypeScriptλ₯Ό λ„μž…ν•˜λŠ” 것을 κ³ λ €ν•΄λ³΄λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. TypeScriptλŠ” ν‘œμ€€ JavaScript ꡬ문에 정적 νƒ€μž…μ„ μ œκ³΅ν•˜λ―€λ‘œ 일반 JavaScript의 λŒ€μ•ˆμœΌλ‘œ μ‚¬μš©ν•˜κΈ°μ— μ’‹μŠ΅λ‹ˆλ‹€. JavaScriptμ—μ„œ νƒ€μž…-체킹을 ν•  λ•Œ λ¬Έμ œμ μ€ κ°€μ§œ type-safety λ₯Ό μ–»κΈ°μœ„ν•΄ μž‘μ„±λœ μ½”λ“œλ₯Ό μ„€λͺ…ν•˜κΈ° μœ„ν•΄μ„œ λ§Žμ€ 주석을 λ‹¬μ•„μ•Όν•œλ‹€λŠ” μ μž…λ‹ˆλ‹€. JavaScript둜 μ½”λ“œλ₯Ό μž‘μ„±ν• λ• κΉ”λ”ν•˜κ²Œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ³ , 쒋은 ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μ§œμ•Όν•˜λ©° 쒋은 μ½”λ“œ 리뷰λ₯Ό ν•΄μ•Όν•©λ‹ˆλ‹€. 그러기 μ‹«λ‹€λ©΄ κ·Έλƒ₯ TypeScript(이건 μ œκ°€ λ§ν–ˆλ“―μ΄, 쒋은 λŒ€μ²΄μž¬μž…λ‹ˆλ‹€!)λ₯Ό μ“°μ„Έμš”.

μ•ˆμ’‹μ€ 예:

function combine(val1, val2) {
  if (typeof val1 === 'number' && typeof val2 === 'number' ||
      typeof val1 === 'string' && typeof val2 === 'string') {
    return val1 + val2;
  }
  
  throw new Error('Must be of type String or Number');
}

쒋은 예:

function combine(val1, val2) {
  return val1 + val2;
}

⬆ μƒλ‹¨μœΌλ‘œ

κ³Όλ„ν•œ μ΅œμ ν™”λ₯Ό μ§€μ–‘ν•˜μ„Έμš”

μ΅œμ‹  λΈŒλΌμš°μ €λ“€μ€ λŸ°νƒ€μž„μ— λ§Žμ€ μ΅œμ ν™” μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. λŒ€λΆ€λΆ„ 당신이 μ½”λ“œλ₯Ό μ΅œμ ν™” ν•˜λŠ” 것은 μ‹œκ°„λ‚­λΉ„μΌ κ°€λŠ₯성이 λ§ŽμŠ΅λ‹ˆλ‹€. μ΅œμ ν™”κ°€ λΆ€μ‘±ν•œ 곳이 μ–΄λ”˜μ§€λ₯Ό μ•Œλ €μ£ΌλŠ” 쒋은 μžλ£Œκ°€ μ—¬κΈ° μžˆμŠ΅λ‹ˆλ‹€. 이것을 μ°Έμ‘°ν•˜μ—¬ μ΅œμ‹  λΈŒλΌμš°μ €λ“€μ΄ μ΅œμ ν™” 해주지 μ•ŠλŠ” λΆ€λΆ„λ§Œ μ΅œμ ν™”λ₯Ό ν•΄μ£ΌλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

// 였래된 λΈŒλΌμš°μ €μ˜ 경우 μΊμ‹œλ˜μ§€ μ•Šμ€ `list.length`λ₯Ό ν†΅ν•œ λ°˜λ³΅λ¬Έμ€ 높은 μ½”μŠ€νŠΈλ₯Ό κ°€μ‘ŒμŠ΅λ‹ˆλ‹€.
// κ·Έ μ΄μœ λŠ” `list.length`λ₯Ό 맀번 κ³„μ‚°ν•΄μ•Όλ§Œ ν–ˆκΈ° λ•Œλ¬ΈμΈλ°, μ΅œμ‹  λΈŒλΌμš°μ €μ—μ„œλŠ” 이것이 μ΅œμ ν™” λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
for (let i = 0, len = list.length; i < len; i++) {
  // ...
}

쒋은 예:

for (let i = 0; i < list.length; i++) {
  // ...
}

⬆ μƒλ‹¨μœΌλ‘œ

죽은 μ½”λ“œλ₯Ό μ§€μš°μ„Έμš”

죽은 μ½”λ“œλŠ” μ€‘λ³΅λœ μ½”λ“œ λ§ŒνΌμ΄λ‚˜ 쒋지 μ•ŠμŠ΅λ‹ˆλ‹€. 죽은 μ½”λ“œλŠ” λ‹Ήμ‹ μ˜ μ½”λ“œμ— λ‚¨μ•„μžˆμ„ μ–΄λ– ν•œ μ΄μœ λ„ μ—†μŠ΅λ‹ˆλ‹€. ν˜ΈμΆœλ˜μ§€ μ•ŠλŠ” μ½”λ“œκ°€ μžˆλ‹€λ©΄ κ·Έ μ½”λ“œλŠ” μ§€μš°μ„Έμš”! κ·Έ μ½”λ“œκ°€ μ—¬μ „νžˆ ν•„μš”ν•΄λ„ κ·Έ μ½”λ“œλŠ” 버전 νžˆμŠ€ν† λ¦¬μ— μ•ˆμ „ν•˜κ²Œ λ‚¨μ•„μžˆμ„ κ²ƒμž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function oldRequestModule(url) {
  // ...
}

function newRequestModule(url) {
  // ...
}

const req = newRequestModule;
inventoryTracker('apples', req, 'www.inventory-awesome.io');

쒋은 예:

function newRequestModule(url) {
  // ...
}

const req = newRequestModule;
inventoryTracker('apples', req, 'www.inventory-awesome.io');

⬆ μƒλ‹¨μœΌλ‘œ

객체와 자료ꡬ쑰(Objects and Data Structures)

getter와 setterλ₯Ό μ‚¬μš©ν•˜μ„Έμš”

JavaScriptλŠ” μΈν„°νŽ˜μ΄μŠ€μ™€ νƒ€μž…μ„ κ°€μ§€κ³ μžˆμ§€ μ•Šκ³  μ΄λŸ¬ν•œ νŒ¨ν„΄μ„ μ μš©ν•˜κΈ°κ°€ νž˜λ“­λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ publicμ΄λ‚˜ private같은 ν‚€μ›Œλ“œκ°€ μ—†κΈ° λ•Œλ¬Έμ΄μ£ . κ·Έλ ‡κΈ° λ•Œλ¬Έμ— getter 및 setterλ₯Ό μ‚¬μš©ν•˜μ—¬ 객체의 데이터에 μ ‘κ·Όν•˜λŠ” 것이 객체의 속성을 μ°ΎλŠ” 것보닀 훨씬 λ‚«μŠ΅λ‹ˆλ‹€. "μ™œμš”?"라고 λ¬ΌμœΌμ‹€ μˆ˜λ„ μžˆκ² μŠ΅λ‹ˆλ‹€. μ™œ κ·ΈλŸ°μ§€μ— λŒ€ν•΄μ„œ λͺ‡ 가지 이유λ₯Ό λ‘μ„œμ—†μ΄ μ μ–΄λ΄€μŠ΅λ‹ˆλ‹€.

  • 객체의 속성을 μ–»λŠ” 것 μ΄μƒμ˜ λ§Žμ€ 것을 ν•˜κ³ μ‹Άμ„ λ•Œ, μ½”λ“œμ—μ„œ λͺ¨λ“  μ ‘κ·Όμžλ₯Ό μ°Ύμ•„ λ°”κΎΈκ³  ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.
  • setν• λ•Œ κ²€μ¦λ‘œμ§μ„ μΆ”κ°€ν•˜λŠ” 것이 μ½”λ“œλ₯Ό 더 κ°„λ‹¨ν•˜κ²Œ λ§Œλ“­λ‹ˆλ‹€.
  • λ‚΄λΆ€μš© APIλ₯Ό μΊ‘μŠν™” ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • gettingκ³Ό settingν•  λ•Œ 둜그λ₯Ό μ°Ύκ±°λ‚˜ μ—λŸ¬μ²˜λ¦¬λ₯Ό ν•˜κΈ° μ‰½μŠ΅λ‹ˆλ‹€.
  • μ„œλ²„μ—μ„œ 객체 속성을 λ°›μ•„μ˜¬ λ•Œ lazy load ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function makeBankAccount() {
  // ...

  return {
    // ...
    balance: 0
  };
}

const account = makeBankAccount();
account.balance = 100;

쒋은 예:

function makeBankAccount() {
  // private으둜 μ„ μ–Έλœ λ³€μˆ˜
  let balance = 0;

  // μ•„λž˜ return을 톡해 public으둜 μ„ μ–Έλœ "getter"
  function getBalance() {
    return balance;
  }

  // μ•„λž˜ return을 톡해 public으둜 μ„ μ–Έλœ "setter"
  function setBalance(amount) {
    // ... balanceλ₯Ό μ—…λ°μ΄νŠΈν•˜κΈ° μ „ κ²€μ¦λ‘œμ§
    balance = amount;
  }

  return {
    // ...
    getBalance,
    setBalance
  };
}

const account = makeBankAccount();
account.setBalance(100);

⬆ μƒλ‹¨μœΌλ‘œ

객체에 λΉ„κ³΅κ°œ 멀버λ₯Ό λ§Œλ“œμ„Έμš”

클둜져λ₯Ό μ΄μš©ν•˜λ©΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. (ES5 μ΄ν•˜μ—μ„œλ„)

μ•ˆμ’‹μ€ 예:

const Employee = function(name) {
  this.name = name;
};

Employee.prototype.getName = function getName() {
  return this.name;
};

const employee = new Employee('John Doe');
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined

쒋은 예:

function makeEmployee(name) {
  return {
    getName() {
      return name;
    },
  };
}

const employee = makeEmployee('John Doe');
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe

⬆ μƒλ‹¨μœΌλ‘œ

클래슀(Classes)

ES5의 ν•¨μˆ˜λ³΄λ‹€ ES2015/ES6의 클래슀λ₯Ό μ‚¬μš©ν•˜μ„Έμš”

κΈ°μ‘΄ ES5의 ν΄λž˜μŠ€μ—μ„œ μ΄ν•΄ν•˜κΈ° μ‰¬μš΄ 상속, ꡬ성 및 λ©”μ†Œλ“œ μ •μ˜λ₯Ό ν•˜λŠ” 건 맀우 μ–΄λ ΅μŠ΅λ‹ˆλ‹€. 맀번 κ·ΈλŸ°κ²ƒμ€ μ•„λ‹ˆμ§€λ§Œ 상속이 ν•„μš”ν•œ 경우라면 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 당신이 크고 더 λ³΅μž‘ν•œ 객체가 ν•„μš”ν•œ κ²½μš°κ°€ μ•„λ‹ˆλΌλ©΄ ν΄λž˜μŠ€λ³΄λ‹€ μž‘μ€ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ„Έμš”.

μ•ˆμ’‹μ€ 예:

const Animal = function(age) {
  if (!(this instanceof Animal)) {
    throw new Error("Instantiate Animal with `new`");
  }
    
  this.age = age;
};

Animal.prototype.move = function() {};

const Mammal = function(age, furColor) {
  if (!(this instanceof Mammal)) {
    throw new Error("Instantiate Mammal with `new`");
  }

  Animal.call(this, age);
  this.furColor = furColor;
};

Mammal.prototype = Object.create(Animal.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.liveBirth = function liveBirth() {};

const Human = function(age, furColor, languageSpoken) {
  if (!(this instanceof Human)) {
    throw new Error("Instantiate Human with `new`");
  }

  Mammal.call(this, age, furColor);
  this.languageSpoken = languageSpoken;
};

Human.prototype = Object.create(Mammal.prototype);
Human.prototype.constructor = Human;
Human.prototype.speak = function speak() {};

쒋은 예:

class Animal {
  constructor(age) {
    this.age = age;
  }

  move() { /* ... */ }
}

class Mammal extends Animal {
  constructor(age, furColor) {
    super(age);
    this.furColor = furColor;
  }

  liveBirth() { /* ... */ }
}

class Human extends Mammal {
  constructor(age, furColor, languageSpoken) {
    super(age, furColor);
    this.languageSpoken = languageSpoken;
  }

  speak() { /* ... */ }
}

⬆ μƒλ‹¨μœΌλ‘œ

λ©”μ†Œλ“œ 체이닝을 μ‚¬μš©ν•˜μ„Έμš”

JavaScriptμ—μ„œ λ©”μ†Œλ“œ 체이닝은 맀우 μœ μš©ν•œ νŒ¨ν„΄μ΄λ©° jQueryλ‚˜ Lodash같은 λ§Žμ€ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ 이 νŒ¨ν„΄μ„ μ°Ύμ•„λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” μ½”λ“œλ₯Ό κ°„κ²°ν•˜κ³  μ΄ν•΄ν•˜κΈ° μ‰½κ²Œ λ§Œλ“€μ–΄μ€λ‹ˆλ‹€. 이런 μ΄μœ λ“€λ‘œ λ©”μ†Œλ“œ 체이닝을 μ“°λŠ” 것을 κΆŒν•˜κ³ , μ‚¬μš©ν•΄λ³Έλ’€ μ–Όλ§ˆλ‚˜ μ½”λ“œκ°€ κΉ”λ”ν•΄μ‘ŒλŠ”μ§€ κΌ­ 확인 해보길 λ°”λžλ‹ˆλ‹€. 클래슀 ν•¨μˆ˜μ—μ„œ λ‹¨μˆœνžˆ λͺ¨λ“  ν•¨μˆ˜μ˜ 끝에 'this'λ₯Ό λ¦¬ν„΄ν•΄μ£ΌλŠ” κ²ƒμœΌλ‘œ 클래슀 λ©”μ†Œλ“œλ₯Ό μΆ”κ°€λ‘œ μ—°κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class Car {
  constructor() {
    this.make = 'Honda';
    this.model = 'Accord';
    this.color = 'white';
  }

  setMake(make) {
    this.make = make;
  }

  setModel(model) {
    this.model = model;
  }

  setColor(color) {
    this.color = color;
  }

  save() {
    console.log(this.make, this.model, this.color);
  }
}

const car = new Car();
car.setColor('pink');
car.setMake('Ford');
car.setModel('F-150');
car.save();

쒋은 예:

class Car {
  constructor() {
    this.make = 'Honda';
    this.model = 'Accord';
    this.color = 'white';
  }

  setMake(make) {
    this.make = make;
    // λ©”λͺ¨: 체이닝을 μœ„ν•΄ thisλ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.
    return this;
  }

  setModel(model) {
    this.model = model;
    // λ©”λͺ¨: 체이닝을 μœ„ν•΄ thisλ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.
    return this;
  }

  setColor(color) {
    this.color = color;
    // λ©”λͺ¨: 체이닝을 μœ„ν•΄ thisλ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.
    return this;
  }

  save() {
    console.log(this.make, this.model, this.color);
    // λ©”λͺ¨: 체이닝을 μœ„ν•΄ thisλ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.
    return this;
  }
}

const car = new Car()
  .setColor('pink')
  .setMake('Ford')
  .setModel('F-150')
  .save();

⬆ μƒλ‹¨μœΌλ‘œ

상속보단 μ‘°ν•©(composition)을 μ‚¬μš©ν•˜μ„Έμš”

Gang of four의 Design Patternsμ—μ„œ 유λͺ…ν•œ μ „λž΅μœΌλ‘œ 당신은 κ°€λŠ₯ν•˜λ‹€λ©΄ μƒμ†λ³΄λ‹€λŠ” 쑰합을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. 상속을 μ‚¬μš©ν–ˆμ„ λ•Œ 얻을 수 μžˆλŠ” 이득보닀 쑰합을 μ‚¬μš©ν–ˆμ„ λ•Œ 얻을 수 μžˆλŠ” 이득이 많기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 이 μ›μΉ™μ˜ μš”μ μ€ 당신이 계속 상속을 μ‚¬μš©ν•΄μ„œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ³ μž ν•  λ•Œ, λ§Œμ•½ 쑰합을 μ΄μš©ν•˜λ©΄ 더 μ½”λ“œλ₯Ό 잘 지 수 μžˆμ§€ μ•Šμ„κΉŒ μƒκ°ν•΄λ³΄λΌλŠ” 것에 μžˆμŠ΅λ‹ˆλ‹€. λ•Œλ•Œλ‘œλŠ” 이것이 λ§žλŠ” μ „λž΅μ΄κΈ° λ•Œλ¬Έμ΄μ£ .

"그럼 λŒ€μ²΄ 상속을 μ–Έμ œ μ‚¬μš©ν•΄μ•Ό λ˜λŠ” κ±΄κ°€μš”?"라고 λ¬Όμ–΄ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. 이건 당신이 μ§λ©΄ν•œ 문제 상황에 λ‹¬λ €μžˆμ§€λ§Œ 쑰합보닀 상속을 μ“°λŠ”κ²Œ 더 쒋을 λ§Œν•œ μ˜ˆμ‹œλ₯Ό λͺ‡ 개 λ“€μ–΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

  1. λ‹Ήμ‹ μ˜ 상속관계가 "has-a" 관계가 μ•„λ‹ˆλΌ "is-a" 관계일 λ•Œ (μ‚¬λžŒ->동물 vs. μœ μ €->μœ μ €μ •λ³΄)
  2. 기반 클래슀의 μ½”λ“œλ₯Ό λ‹€μ‹œ μ‚¬μš©ν•  수 μžˆμ„ λ•Œ (인간은 λͺ¨λ“  λ™λ¬Όμ²˜λŸΌ 움직일 수 μžˆμŠ΅λ‹ˆλ‹€.)
  3. 기반 클래슀λ₯Ό μˆ˜μ •ν•˜μ—¬ νŒŒμƒλœ 클래슀 λͺ¨λ‘λ₯Ό μˆ˜μ •ν•˜κ³  싢을 λ•Œ (μ΄λ™μ‹œ λͺ¨λ“  동물이 μ†ŒλΉ„ν•˜λŠ” 칼둜리λ₯Ό λ³€κ²½ν•˜κ³  싢을 λ•Œ)

μ•ˆμ’‹μ€ 예:

class Employee {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  // ...
}

// 이 μ½”λ“œκ°€ μ•ˆμ’‹μ€ μ΄μœ λŠ” Employeesκ°€ tax dataλ₯Ό "가지고" 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.
// EmployeeTaxDataλŠ” Employee νƒ€μž…μ΄ μ•„λ‹™λ‹ˆλ‹€.
class EmployeeTaxData extends Employee {
  constructor(ssn, salary) {
    super();
    this.ssn = ssn;
    this.salary = salary;
  }

  // ...
}

쒋은 예:

class EmployeeTaxData {
  constructor(ssn, salary) {
    this.ssn = ssn;
    this.salary = salary;
  }
  
  // ...
}

class Employee {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  setTaxData(ssn, salary) {
    this.taxData = new EmployeeTaxData(ssn, salary);
  }
  // ...
}

⬆ μƒλ‹¨μœΌλ‘œ

SOLID

단일 μ±…μž„ 원칙 (Single Responsibility Principle, SRP)

Clean Codeμ—μ„œ λ§ν•˜κΈΈ "클래슀λ₯Ό μˆ˜μ • ν•  λ•ŒλŠ” μˆ˜μ • ν•΄μ•Όν•˜λŠ” μ΄μœ κ°€ 2개 이상 있으면 μ•ˆλ©λ‹ˆλ‹€". 이것은 ν•˜λ‚˜μ˜ ν΄λž˜μŠ€μ— λ§Žμ€ κΈ°λŠ₯을 μ‘€μ…”λ„£λŠ” κ²ƒμ΄λ‚˜ 닀름 μ—†μŠ΅λ‹ˆλ‹€. 마치 λΉ„ν–‰κΈ°λ₯Ό νƒˆλ•Œ 가방을 1개만 가지고 νƒˆ 수 μžˆμ„ λ•Œ 처럼 말이죠. 이 λ¬Έμ œλŠ” λ‹Ήμ‹ μ˜ ν΄λž˜μŠ€κ°€ κ°œλ…μ μœΌλ‘œ μ‘μ§‘λ˜μ–΄ μžˆμ§€ μ•Šλ‹€λŠ” 것이고, 클래슀λ₯Ό λ°”κΏ”μ•Όν•  λ§Žμ€ μ΄μœ κ°€ λ©λ‹ˆλ‹€. 클래슀λ₯Ό μˆ˜μ •ν•˜λŠ”λ° λ“€μ΄λŠ” μ‹œκ°„μ„ μ€„μ΄λŠ” 것은 μ€‘μš”ν•©λ‹ˆλ‹€. μ™œλƒλ©΄ ν•˜λ‚˜μ˜ ν΄λž˜μŠ€μ— λ„ˆλ¬΄ λ§Žμ€ κΈ°λŠ₯듀이 있고 당신이 이 μž‘μ€ κΈ°λŠ₯듀을 μˆ˜μ •ν•  λ•Œ 이 μ½”λ“œκ°€ λ‹€λ₯Έ λͺ¨λ“ˆλ“€μ— μ–΄λ– ν•œ 영ν–₯을 λΌμΉ˜λŠ”μ§€ μ΄ν•΄ν•˜κΈ° μ–΄λ €μšΈ 수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class UserSettings {
  constructor(user) {
    this.user = user;
  }

  changeSettings(settings) {
    if (this.verifyCredentials()) {
      // ...
    }
  }

  verifyCredentials() {
    // ...
  }
}

쒋은 예:

class UserAuth {
  constructor(user) {
    this.user = user;
  }

  verifyCredentials() {
    // ...
  }
}


class UserSettings {
  constructor(user) {
    this.user = user;
    this.auth = new UserAuth(user);
  }

  changeSettings(settings) {
    if (this.auth.verifyCredentials()) {
      // ...
    }
  }
}

⬆ μƒλ‹¨μœΌλ‘œ

개방/폐쇄 원칙 (Open/Closed Principle, OCP)

Bertrand Meyer에 말에 μ˜ν•˜λ©΄ "μ†Œν”„νŠΈμ›¨μ–΄ 개체(클래슀, λͺ¨λ“ˆ, ν•¨μˆ˜ λ“±)λŠ” ν™•μž₯을 μœ„ν•΄ κ°œλ°©μ μ΄μ–΄μ•Ό ν•˜λ©° μˆ˜μ •μ‹œμ—” 폐쇄적이어야 ν•©λ‹ˆλ‹€." 이것에 μ˜λ―ΈλŠ” λ¬΄μ—‡μΌκΉŒμš”? 이 μ›λ¦¬λŠ” 기본적으둜 μ‚¬μš©μžκ°€ .js μ†ŒμŠ€ μ½”λ“œ νŒŒμΌμ„ μ—΄μ–΄ μˆ˜λ™μœΌλ‘œ μ‘°μž‘ν•˜μ§€ μ•Šκ³ λ„ λͺ¨λ“ˆμ˜ κΈ°λŠ₯을 ν™•μž₯ν•˜λ„λ‘ ν—ˆμš©ν•΄μ•Όν•œλ‹€κ³  λ§ν•©λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class AjaxAdapter extends Adapter {
  constructor() {
    super();
    this.name = 'ajaxAdapter';
  }
}

class NodeAdapter extends Adapter {
  constructor() {
    super();
    this.name = 'nodeAdapter';
  }
}

class HttpRequester {
  constructor(adapter) {
    this.adapter = adapter;
  }

  fetch(url) {
    if (this.adapter.name === 'ajaxAdapter') {
      return makeAjaxCall(url).then((response) => {
        // transform response and return
      });
    } else if (this.adapter.name === 'httpNodeAdapter') {
      return makeHttpCall(url).then((response) => {
        // transform response and return
      });
    }
  }
}

function makeAjaxCall(url) {
  // request and return promise
}

function makeHttpCall(url) {
  // request and return promise
}

쒋은 예:

class AjaxAdapter extends Adapter {
  constructor() {
    super();
    this.name = 'ajaxAdapter';
  }

  request(url) {
    // request and return promise
  }
}

class NodeAdapter extends Adapter {
  constructor() {
    super();
    this.name = 'nodeAdapter';
  }

  request(url) {
    // request and return promise
  }
}

class HttpRequester {
  constructor(adapter) {
    this.adapter = adapter;
  }

  fetch(url) {
    return this.adapter.request(url).then((response) => {
      // transform response and return
    });
  }
}

⬆ μƒλ‹¨μœΌλ‘œ

λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙 (Liskov Substitution Principle, LSP)

이것은 맀우 κ°„λ‹¨ν•˜μ§€λ§Œ κ°•λ ₯ν•œ μ›μΉ™μž…λ‹ˆλ‹€. λ¦¬μŠ€μ½”ν”„ μ›μΉ™μ΄λž€ μžλ£Œν˜• Sκ°€ μžλ£Œν˜• T의 ν•˜μœ„ν˜•μ΄λΌλ©΄, ν”„λ‘œκ·Έλž¨μ΄ κ°–μΆ”μ–΄μ•Ό ν•  속성듀(μ •ν™•μ„±, μˆ˜ν–‰λ˜λŠ” μž‘μ—… λ“±)의 변경사항 없이, μžλ£Œν˜• T의 객체λ₯Ό μžλ£Œν˜• S의 객체둜 ꡐ체(μΉ˜ν™˜)ν•  수 μžˆμ–΄μ•Ό ν•œλ‹€λŠ” μ›μΉ™μž…λ‹ˆλ‹€.

이 원칙을 예λ₯Ό λ“€μ–΄ μ„€λͺ…ν•˜μžλ©΄ 당신이 λΆ€λͺ¨ ν΄λž˜μŠ€μ™€ μžμ‹ 클래슀λ₯Ό 가지고 μžˆμ„ λ•Œ 베이슀 ν΄λž˜μŠ€μ™€ ν•˜μœ„ 클래슀λ₯Ό 잘λͺ»λœ κ²°κ³Ό 없이 μ„œλ‘œ κ΅ν™˜ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ—¬μ „νžˆ 이해가 μ•ˆκ°„λ‹€λ©΄ μ •μ‚¬κ°ν˜•-μ§μ‚¬κ°ν˜• 예제λ₯Ό λ΄…μ‹œλ‹€. μˆ˜ν•™μ μœΌλ‘œ μ •μ‚¬κ°ν˜•μ€ μ§μ‚¬κ°ν˜•μ΄μ§€λ§Œ 상속을 톡해 "is-a" 관계λ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λΈλ§ν•œλ‹€λ©΄ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class Rectangle {
  constructor() {
    this.width = 0;
    this.height = 0;
  }

  setColor(color) {
    // ...
  }

  render(area) {
    // ...
  }

  setWidth(width) {
    this.width = width;
  }

  setHeight(height) {
    this.height = height;
  }

  getArea() {
    return this.width * this.height;
  }
}

class Square extends Rectangle {
  setWidth(width) {
    this.width = width;
    this.height = width;
  }

  setHeight(height) {
    this.width = height;
    this.height = height;
  }
}

function renderLargeRectangles(rectangles) {
  rectangles.forEach((rectangle) => {
    rectangle.setWidth(4);
    rectangle.setHeight(5);
    const area = rectangle.getArea(); // μ •μ‚¬κ°ν˜•μΌλ•Œ 25λ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 20이어야 ν•˜λŠ”κ²Œ λ§žμŠ΅λ‹ˆλ‹€.
    rectangle.render(area);
  });
}

const rectangles = [new Rectangle(), new Rectangle(), new Square()];
renderLargeRectangles(rectangles);

쒋은 예:

class Shape {
  setColor(color) {
    // ...
  }

  render(area) {
    // ...
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }

  getArea() {
    return this.width * this.height;
  }
}

class Square extends Shape {
  constructor(length) {
    super();
    this.length = length;
  }

  getArea() {
    return this.length * this.length;
  }
}

function renderLargeShapes(shapes) {
  shapes.forEach((shape) => {
      const area = shape.getArea();
      shape.render(area);
    });
  }

const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];
renderLargeShapes(shapes);

⬆ μƒλ‹¨μœΌλ‘œ

μΈν„°νŽ˜μ΄μŠ€ 뢄리 원칙 (Interface Segregation Principle, ISP)

JavaScriptλŠ” μΈν„°νŽ˜μ΄μŠ€κ°€ μ—†κΈ° λ•Œλ¬Έμ— λ‹€λ₯Έ μ›μΉ™λ“€μ²˜λŸΌ λ”± 맞게 μ μš©ν•  μˆ˜λŠ” μ—†μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜, JavaScript에 νƒ€μž… μ‹œμŠ€ν…œμ΄ μ—†λ‹€ ν•˜λ”λΌλ„ μ€‘μš”ν•˜κ³  κ΄€κ³„μžˆλŠ” μ›μΉ™μž…λ‹ˆλ‹€.

ISP에 μ˜ν•˜λ©΄ "ν΄λΌμ΄μ–ΈνŠΈλŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μΈν„°νŽ˜μ΄μŠ€μ— μ˜μ‘΄ν•˜λ„λ‘ κ°•μš” λ°›μœΌλ©΄ μ•ˆλ©λ‹ˆλ‹€." 덕 타이핑 λ•Œλ¬Έμ— μΈν„°νŽ˜μ΄μŠ€λŠ” JavaScriptμ—μ„œλŠ” μ•”μ‹œμ μΈ 계약일 λΏμž…λ‹ˆλ‹€.

JavaScriptμ—μ„œ 이것을 λ³΄μ—¬μ£ΌλŠ” κ°€μž₯ 쒋은 μ˜ˆλŠ” λ°©λŒ€ν•œ μ–‘μ˜ μ„€μ • 객체가 ν•„μš”ν•œ ν΄λž˜μŠ€μž…λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈκ°€ λ°©λŒ€ν•œ μ–‘μ˜ μ˜΅μ…˜μ„ μ„€μ •ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ λŒ€λΆ€λΆ„μ˜ 경우 섀정듀이 μ „λΆ€ λ‹€ ν•„μš”ν•œ 건 μ•„λ‹ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 섀정을 μ„ νƒμ μœΌλ‘œ ν•  수 μžˆλ‹€λ©΄ "무거운 μΈν„°νŽ˜μ΄μŠ€(fat interface)"λ₯Ό λ§Œλ“œλŠ” 것을 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class DOMTraverser {
  constructor(settings) {
    this.settings = settings;
    this.setup();
  }

  setup() {
    this.rootNode = this.settings.rootNode;
    this.animationModule.setup();
  }

  traverse() {
    // ...
  }
}

const $ = new DOMTraverser({
  rootNode: document.getElementsByTagName('body'),
  animationModule() {} // μš°λ¦¬λŠ” λŒ€λΆ€λΆ„μ˜ 경우 DOM을 탐색할 λ•Œ μ• λ‹ˆλ©”μ΄μ…˜μ΄ ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  // ...
});

쒋은 예:

class DOMTraverser {
  constructor(settings) {
    this.settings = settings;
    this.options = settings.options;
    this.setup();
  }

  setup() {
    this.rootNode = this.settings.rootNode;
    this.setupOptions();
  }

  setupOptions() {
    if (this.options.animationModule) {
      // ...
    }
  }

  traverse() {
    // ...
  }
}

const $ = new DOMTraverser({
  rootNode: document.getElementsByTagName('body'),
  options: {
    animationModule() {}
  }
});

⬆ μƒλ‹¨μœΌλ‘œ

μ˜μ‘΄μ„± μ—­μ „ 원칙 (Dependency Inversion Principle, DIP)

이 원칙은 두가지 μ€‘μš”ν•œ μš”μ†Œλ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€.

  1. μƒμœ„ λͺ¨λ“ˆμ€ ν•˜μœ„ λͺ¨λ“ˆμ— μ’…μ†λ˜μ–΄μ„œλŠ” μ•ˆλ©λ‹ˆλ‹€. λ‘˜ λ‹€ 좔상화에 μ˜μ‘΄ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  2. μΆ”μƒν™”λŠ” 세뢀사항에 μ˜μ‘΄ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 세뢀사항은 좔상화에 μ˜ν•΄ 달라져야 ν•©λ‹ˆλ‹€.

μ²˜μŒμ—λŠ” 이것을 μ΄ν•΄ν•˜λŠ”λ° μ–΄λ €μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ λ§Œμ•½ Angular.js둜 μž‘μ—…ν•΄λ³Έμ μ΄ μžˆλ‹€λ©΄ μ˜μ‘΄μ„± μ£Όμž…(Dependency Injection) ν˜•νƒœλ‘œ 이 원리λ₯Ό κ΅¬ν˜„ν•œ 것을 λ³΄μ•˜μ„ κ²ƒμž…λ‹ˆλ‹€. DIPλŠ” λ™μΌν•œ κ°œλ…μ€ μ•„λ‹ˆμ§€λ§Œ μƒμœ„ λͺ¨λ“ˆμ΄ ν•˜μœ„ λͺ¨λ“ˆμ˜ 세뢀사항을 μ•Œμ§€ λͺ»ν•˜κ²Œ ν•©λ‹ˆλ‹€. μ΄λŠ” μ˜μ‘΄μ„± μ£Όμž…μ„ 톡해 달성할 수 μžˆμŠ΅λ‹ˆλ‹€. DI의 μž₯점은 λͺ¨λ“ˆ κ°„μ˜ μ˜μ‘΄μ„±μ„ κ°μ†Œμ‹œν‚€λŠ” 데에 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“ˆκ°„μ˜ μ˜μ‘΄μ„±μ΄ λ†’μ„μˆ˜λ‘ μ½”λ“œλ₯Ό λ¦¬νŒ©ν† λ§ ν•˜λŠ”λ° μ–΄λ €μ›Œμ§€κ³  이것은 맀우 λ‚˜μœ 개발 νŒ¨ν„΄λ“€ 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€.

μ•žμ—μ„œ μ„€λͺ…ν•œ κ²ƒμ²˜λŸΌ JavaScriptμ—λŠ” μΈν„°νŽ˜μ΄μŠ€κ°€ μ—†μœΌλ―€λ‘œ 좔상화에 μ˜μ‘΄ν•˜λŠ” 것은 μ•”μ‹œμ μΈ μ•½μ†μž…λ‹ˆλ‹€. μ΄λ§μΈμ¦‰μŠ¨, λ‹€λ₯Έ κ°μ²΄λ‚˜ ν΄λž˜μŠ€μ— λ…ΈμΆœλ˜λŠ” λ©”μ†Œλ“œμ™€ 속성이 λ°”λ‘œ μ•”μ‹œμ μΈ 약속(좔상화)κ°€ λœλ‹€λŠ” 것이죠. μ•„λž˜ μ˜ˆμ œμ—μ„œ μ•”μ‹œμ μΈ 약속은 InventoryTrackerμ—λŒ€ν•œ λͺ¨λ“  μš”μ²­ λͺ¨λ“ˆμ΄ requestItems λ©”μ†Œλ“œλ₯Ό κ°€μ§ˆ κ²ƒμ΄λΌλŠ” μ μž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class InventoryRequester {
  constructor() {
    this.REQ_METHODS = ['HTTP'];
  }

  requestItem(item) {
    // ...
  }
}

class InventoryTracker {
  constructor(items) {
    this.items = items;

    // μ•ˆμ’‹μ€ 이유: νŠΉμ • μš”μ²­λ°©λ²• κ΅¬ν˜„μ— λŒ€ν•œ μ˜μ‘΄μ„±μ„ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
    // requestItemsλŠ” ν•œκ°€μ§€ μš”μ²­λ°©λ²•μ„ ν•„μš”λ‘œ ν•©λ‹ˆλ‹€.
    this.requester = new InventoryRequester();
  }

  requestItems() {
    this.items.forEach(item => {
      this.requester.requestItem(item);
    });
  }
}

const inventoryTracker = new InventoryTracker(['apples', 'bananas']);
inventoryTracker.requestItems();

쒋은 예:

class InventoryTracker {
  constructor(items, requester) {
    this.items = items;
    this.requester = requester;
  }

  requestItems() {
    this.items.forEach(item => {
      this.requester.requestItem(item);
    });
  }
}

class InventoryRequesterV1 {
  constructor() {
    this.REQ_METHODS = ['HTTP'];
  }

  requestItem(item) {
    // ...
  }
}

class InventoryRequesterV2 {
  constructor() {
    this.REQ_METHODS = ['WS'];
  }

  requestItem(item) {
    // ...
  }
}

// μ˜μ‘΄μ„±μ„ μ™ΈλΆ€μ—μ„œ λ§Œλ“€μ–΄ μ£Όμž…ν•΄μ€ŒμœΌλ‘œμ¨,
// μš”μ²­ λͺ¨λ“ˆμ„ μƒˆλ‘­κ²Œ λ§Œλ“  μ›Ήμ†ŒμΌ“ μ‚¬μš© λͺ¨λ“ˆλ‘œ μ‰½κ²Œ λ°”κΏ” 끼울 수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
const inventoryTracker = new InventoryTracker(['apples', 'bananas'], new InventoryRequesterV2());
inventoryTracker.requestItems();

⬆ μƒλ‹¨μœΌλ‘œ

ν…ŒμŠ€νŠΈ(Testing)

ν…ŒμŠ€νŠΈλŠ” λ°°ν¬ν•˜λŠ” 것보닀 μ€‘μš”ν•©λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ 없이 λ°°ν¬ν•œλ‹€λŠ” 것은 당신이 μ§œλ†“μ€ μ½”λ“œκ°€ μ–Έμ œλ“  μ˜€μž‘λ™ν•΄λ„ μ΄μƒν•˜μ§€ μ•Šλ‹€λŠ” μ–˜κΈ°μ™€ κ°™μŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈμ— μ–Όλ§ˆλ‚˜ μ‹œκ°„μ„ νˆ¬μžν• μ§€λŠ” 당신이 ν•¨κ»˜ μΌν•˜λŠ” νŒ€μ— λ‹¬λ €μžˆμ§€λ§Œ Coverageκ°€ 100%λΌλŠ” 것은 κ°œλ°œμžλ“€μ—κ²Œ 높은 μžμ‹ κ°κ³Ό μ•ˆλ„κ°μ„ μ€λ‹ˆλ‹€. 이 말은 ν›Œλ₯­ν•œ ν…ŒμŠ€νŠΈ 도ꡬλ₯Ό λ³΄μœ ν•΄μ•Ό ν•˜λŠ” 것 뿐만 μ•„λ‹ˆλΌ ν›Œλ₯­ν•œ Coverage 도ꡬλ₯Ό μ‚¬μš©ν•΄μ•Όν•œλ‹€λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것은 κ·Έ 무엇도 λ³€λͺ…이 될 수 μ—†μŠ΅λ‹ˆλ‹€. μ—¬κΈ° ν›Œλ₯­ν•˜κ³  λ§Žμ€ JavaScript ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬λ“€ 이 μžˆμŠ΅λ‹ˆλ‹€. λ‹Ήμ‹ μ˜ νŒ€μ˜ κΈ°ν˜Έμ— λ§žλŠ” ν”„λ ˆμž„μ›Œν¬λ₯Ό κ³ λ₯΄κΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬λ₯Ό κ³¨λžλ‹€λ©΄ μ΄μ œλΆ€ν„°λŠ” νŒ€μ˜ λͺ©ν‘œλ₯Ό λͺ¨λ“  μƒˆλ‘œμš΄ κΈ°λŠ₯/λͺ¨λ“ˆμ„ 지 λ•Œ ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” κ²ƒμœΌλ‘œ ν•˜μ„Έμš”. λ§Œμ•½ ν…ŒμŠ€νŠΈ 주도 개발 방법둠(Test Driven Development, TDD)이 λ‹Ήμ‹ μ—κ²Œ λ§žλŠ” 방법이라면 그건 ν›Œλ₯­ν•œ 개발 방법이 될 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ€‘μš”ν•œ 것은 당신이 μ–΄λ– ν•œ κΈ°λŠ₯을 κ°œλ°œν•˜κ±°λ‚˜ μ½”λ“œλ₯Ό λ¦¬νŒ©ν† λ§ ν•  λ•Œ 당신이 μ •ν•œ Coverage λͺ©ν‘œλ₯Ό λ‹¬μ„±ν•˜λŠ” 것에 μžˆμŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈ 컨셉

μ•ˆμ’‹μ€ 예:

const assert = require('assert');

describe('MakeMomentJSGreatAgain', () => {
  it('handles date boundaries', () => {
    let date;

    date = new MakeMomentJSGreatAgain('1/1/2015');
    date.addDays(30);
    assert.equal('1/31/2015', date);

    date = new MakeMomentJSGreatAgain('2/1/2016');
    date.addDays(28);
    assert.equal('02/29/2016', date);

    date = new MakeMomentJSGreatAgain('2/1/2015');
    date.addDays(28);
    assert.equal('03/01/2015', date);
  });
});

쒋은 예:

const assert = require('assert');

describe('MakeMomentJSGreatAgain', () => {
  it('handles 30-day months', () => {
    const date = new MakeMomentJSGreatAgain('1/1/2015');
    date.addDays(30);
    assert.equal('1/31/2015', date);
  });

  it('handles leap year', () => {
    const date = new MakeMomentJSGreatAgain('2/1/2016');
    date.addDays(28);
    assert.equal('02/29/2016', date);
  });

  it('handles non-leap year', () => {
    const date = new MakeMomentJSGreatAgain('2/1/2015');
    date.addDays(28);
    assert.equal('03/01/2015', date);
  });
});

⬆ μƒλ‹¨μœΌλ‘œ

λ™μ‹œμ„±(Concurrency)

Callback λŒ€μ‹  Promiseλ₯Ό μ‚¬μš©ν•˜μ„Έμš”

Callback은 κΉ”λ”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 그리고 μ—„μ²­λ‚˜κ²Œ λ§Žμ€ μ€‘κ΄„ν˜Έ 쀑첩을 λ§Œλ“€μ–΄ λƒ…λ‹ˆλ‹€. ES2015/ES6에선 Promiseκ°€ λ‚΄μž₯λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 이걸 μ“°μ„Έμš”!

μ•ˆμ’‹μ€ 예:

require('request').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', (requestErr, response) => {
  if (requestErr) {
    console.error(requestErr);
  } else {
    require('fs').writeFile('article.html', response.body, (writeErr) => {
      if (writeErr) {
        console.error(writeErr);
      } else {
        console.log('File written');
      }
    });
  }
});

쒋은 예:

require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
  .then((response) => {
    return require('fs-promise').writeFile('article.html', response);
  })
  .then(() => {
    console.log('File written');
  })
  .catch((err) => {
    console.error(err);
  });

⬆ μƒλ‹¨μœΌλ‘œ

Async/Await은 Promise보닀 λ”μš± κΉ”λ”ν•©λ‹ˆλ‹€

Promise도 Callback에 λΉ„ν•΄ 정말 κΉ”λ”ν•˜μ§€λ§Œ ES2017/ES8에선 async와 await이 μžˆμŠ΅λ‹ˆλ‹€. 이듀은 Callbackμ—λŒ€ν•œ λ”μš± κΉ”λ”ν•œ 해결책을 μ€λ‹ˆλ‹€. 였직 ν•„μš”ν•œ 것은 ν•¨μˆ˜μ•žμ— asyncλ₯Ό λΆ™μ΄λŠ” 것 λΏμž…λ‹ˆλ‹€. 그러면 ν•¨μˆ˜λ₯Ό λ…Όλ¦¬μ μœΌλ‘œ μ—°κ²°ν•˜κΈ°μœ„ν•΄ 더이상 then을 쓰지 μ•Šμ•„λ„ λ©λ‹ˆλ‹€. λ§Œμ•½ 당신이 ES2017/ES8 μ‚¬μš©ν•  수 μžˆλ‹€λ©΄ 이것을 μ‚¬μš©ν•˜μ„Έμš”!

μ•ˆμ’‹μ€ 예:

require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
  .then(response => {
    return require('fs-promise').writeFile('article.html', response);
  })
  .then(() => {
    console.log('File written');
  })
  .catch(err => {
    console.error(err);
  })

쒋은 예:

async function getCleanCodeArticle() {
  try {
    const response = await require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
    await require('fs-promise').writeFile('article.html', response);
    console.log('File written');
  } catch(err) {
    console.error(err);
  }
}

⬆ μƒλ‹¨μœΌλ‘œ

μ—λŸ¬ 처리(Error Handling)

μ—λŸ¬λ₯Ό λ±‰λŠ”λ‹€λŠ” 것은 쒋은 κ²ƒμž…λ‹ˆλ‹€! 즉, ν”„λ‘œκ·Έλž¨μ—μ„œ 무언가가 잘λͺ»λ˜μ—ˆμ„ λ•Œ λŸ°νƒ€μž„μ—μ„œ μ„±κ³΅μ μœΌλ‘œ ν™•μΈλ˜λ©΄ ν˜„μž¬ μŠ€νƒμ—μ„œ ν•¨μˆ˜ 싀행을 μ€‘λ‹¨ν•˜κ³  (λ…Έλ“œμ—μ„œ) ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œν•˜κ³  μŠ€νƒ μΆ”μ μœΌλ‘œ μ½˜μ†”μ—μ„œ μ‚¬μš©μžμ—κ²Œ κ·Έ 이유λ₯Ό μ•Œλ €μ€λ‹ˆλ‹€.

λ‹¨μˆœνžˆ μ—λŸ¬λ₯Ό ν™•μΈλ§Œ ν•˜μ§€λ§ˆμ„Έμš”

λ‹¨μˆœνžˆ μ—λŸ¬λ₯Ό ν™•μΈν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œ κ·Έ μ—λŸ¬κ°€ ν•΄κ²°λ˜κ±°λ‚˜ λŒ€μ‘ ν•  수 있게 λ˜λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€. console.logλ₯Ό 톡해 μ½˜μ†”μ— 둜그λ₯Ό κΈ°λ‘ν•˜λŠ” 것은 μ—λŸ¬ 둜그λ₯Ό μžƒμ–΄λ²„λ¦¬κΈ° 쉽기 λ•Œλ¬Έμ— 쒋은 방법이 μ•„λ‹™λ‹ˆλ‹€. λ§Œμ•½μ— try/catch둜 μ–΄λ–€ μ½”λ“œλ₯Ό κ°μŒŒλ‹€λ©΄ 그건 당신이 κ·Έ μ½”λ“œμ— μ–΄λ–€ μ—λŸ¬κ°€ 날지도 λͺ¨λ₯΄κΈ° λ•Œλ¬Έμ— 감싼 κ²ƒμ΄λ―€λ‘œ κ·Έμ—λŒ€ν•œ κ³„νšμ΄ μžˆκ±°λ‚˜ μ–΄λ– ν•œ μž₯치λ₯Ό ν•΄μ•Όν•©λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

try {
  functionThatMightThrow();
} catch (error) {
  console.log(error);
}

쒋은 예:

try {
  functionThatMightThrow();
} catch (error) {
  // 첫번째 방법은 console.errorλ₯Ό μ΄μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 이건 console.log보닀 쑰금 더 μ•Œμ•„μ±„κΈ° μ‰½μŠ΅λ‹ˆλ‹€.
  console.error(error);
  // λ‹€λ₯Έ 방법은 μœ μ €μ—κ²Œ μ•Œλ¦¬λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
  notifyUserOfError(error);
  // 또 λ‹€λ₯Έ 방법은 μ„œλΉ„μŠ€ μžμ²΄μ— μ—λŸ¬λ₯Ό κΈ°λ‘ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
  reportErrorToService(error);
  // ν˜Ήμ€ κ·Έ μ–΄λ–€ 방법이 될 수 μžˆμŠ΅λ‹ˆλ‹€.
}

⬆ μƒλ‹¨μœΌλ‘œ

Promiseκ°€ μ‹€νŒ¨λœ 것을 λ¬΄μ‹œν•˜μ§€ λ§ˆμ„Έμš”

μœ„μ˜ 원칙과 같은 μ΄μœ μž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

getdata()
.then(data => {
  functionThatMightThrow(data);
})
.catch(error => {
  console.log(error);
});

쒋은 예:

getdata()
.then(data => {
  functionThatMightThrow(data);
})
.catch(error => {
  // 첫번째 방법은 console.errorλ₯Ό μ΄μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 이건 console.log보닀 쑰금 더 μ•Œμ•„μ±„κΈ° μ‰½μŠ΅λ‹ˆλ‹€.
  console.error(error);
  // λ‹€λ₯Έ 방법은 μœ μ €μ—κ²Œ μ•Œλ¦¬λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
  notifyUserOfError(error);
  // 또 λ‹€λ₯Έ 방법은 μ„œλΉ„μŠ€ μžμ²΄μ— μ—λŸ¬λ₯Ό κΈ°λ‘ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
  reportErrorToService(error);
  // ν˜Ήμ€ κ·Έ μ–΄λ–€ 방법이 될 수 μžˆμŠ΅λ‹ˆλ‹€.
});

⬆ μƒλ‹¨μœΌλ‘œ

ν¬λ§·νŒ…(Formatting)

ν¬λ§·νŒ…μ€ μ£Όκ΄€μ μž…λ‹ˆλ‹€. 여기에 μžˆλŠ” λ§Žμ€ κ·œμΉ™κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ λ”°λ₯΄κΈ° μ‰¬μš΄ κ·œμΉ™λ“€μ΄ μžˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œ μ•Œμ•„μ•Ό ν•  것은 ν¬λ§·νŒ…μ— λŒ€ν•΄ κ³Όλ„ν•˜κ²Œ μ‹ κ²½μ“°λŠ” 것은 μ˜λ―Έμ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. ν¬λ§·νŒ… 체크λ₯Ό μžλ™μœΌλ‘œ ν•΄μ£ΌλŠ” λ§Žμ€ 도ꡬ듀이 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 이쀑 ν•˜λ‚˜λ₯Ό 골라 μ‚¬μš©ν•˜μ„Έμš”. κ°œλ°œμžλ“€λΌλ¦¬ ν¬λ§·νŒ…μ—λŒ€ν•΄ λ…ΌμŸν•˜λŠ” κ²ƒλ§ŒνΌ μ‹œκ°„κ³Ό λˆμ„ λ‚­λΉ„ν•˜λŠ” 것이 μ—†μŠ΅λ‹ˆλ‹€.

μžλ™μœΌλ‘œ μ„œμ‹μ„ κ΅μ •ν•΄μ£ΌλŠ” 것(λ“€μ—¬μ“°κΈ°, 탭이냐 μŠ€νŽ˜μ΄μŠ€λƒ, μž‘μ€ λ”°μ˜΄ν‘œλƒ ν°λ”°μ˜΄ν‘œλƒ)에 ν•΄λ‹Ήν•˜μ§€ μ•ŠλŠ” 사항에 λŒ€ν•΄μ„œλŠ” λͺ‡κ°€μ§€ 지침을 λ”°λ₯΄λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

μΌκ΄€λœ λŒ€μ†Œλ¬Έμžλ₯Ό μ‚¬μš©ν•˜μ„Έμš”

JavaScriptμ—λŠ” 정해진 νƒ€μž…μ΄ μ—†κΈ° λ•Œλ¬Έμ— λŒ€μ†Œλ¬Έμžλ₯Ό κ΅¬λΆ„ν•˜λŠ” κ²ƒμœΌλ‘œ λ‹Ήμ‹ μ˜ λ³€μˆ˜λ‚˜ ν•¨μˆ˜λͺ… λ“±μ—μ„œ λ§Žμ€ 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. 이 κ·œμΉ™ λ˜ν•œ 주관적이기 λ•Œλ¬Έμ— 당신이 νŒ€μ΄ μ„ νƒν•œ κ·œμΉ™λ“€μ„ λ”°λ₯΄μ„Έμš” μ€‘μš”ν•œκ±΄ 항상 일관성 있게 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

const DAYS_IN_WEEK = 7;
const daysInMonth = 30;

const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];

function eraseDatabase() {}
function restore_database() {}

class animal {}
class Alpaca {}

쒋은 예:

const DAYS_IN_WEEK = 7;
const DAYS_IN_MONTH = 30;

const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];

function eraseDatabase() {}
function restoreDatabase() {}

class Animal {}
class Alpaca {}

⬆ μƒλ‹¨μœΌλ‘œ

ν•¨μˆ˜ ν˜ΈμΆœμžμ™€ ν•¨μˆ˜ ν”Όν˜ΈμΆœμžλŠ” κ°€κΉκ²Œ μœ„μΉ˜μ‹œν‚€μ„Έμš”

μ–΄λ–€ ν•¨μˆ˜κ°€ λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ κ·Έ ν•¨μˆ˜λ“€μ€ μ†ŒμŠ€ 파일 μ•ˆμ—μ„œ μ„œλ‘œ 수직으둜 κ·Όμ ‘ν•΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. μ΄μƒμ μœΌλ‘œλŠ” ν•¨μˆ˜ 호좜자λ₯Ό ν•¨μˆ˜ ν”Όν˜ΈμΆœμž λ°”λ‘œ μœ„μ— μœ„μΉ˜μ‹œμΌœμ•Ό ν•©λ‹ˆλ‹€. μš°λ¦¬λŠ” μ½”λ“œλ₯Ό μ½μ„λ•Œ 신문을 읽듯 μœ„μ—μ„œ μ•„λž˜λ‘œ 읽기 λ•Œλ¬Έμ— μ½”λ“œλ₯Ό μž‘μ„± ν•  λ•Œλ„ 읽을 λ•Œλ₯Ό κ³ λ €ν•˜μ—¬ μž‘μ„± ν•΄μ•Όν•©λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

class PerformanceReview {
  constructor(employee) {
    this.employee = employee;
  }

  lookupPeers() {
    return db.lookup(this.employee, 'peers');
  }

  lookupManager() {
    return db.lookup(this.employee, 'manager');
  }

  getPeerReviews() {
    const peers = this.lookupPeers();
    // ...
  }

  perfReview() {
    this.getPeerReviews();
    this.getManagerReview();
    this.getSelfReview();
  }

  getManagerReview() {
    const manager = this.lookupManager();
  }

  getSelfReview() {
    // ...
  }
}

const review = new PerformanceReview(user);
review.perfReview();

쒋은 예:

class PerformanceReview {
  constructor(employee) {
    this.employee = employee;
  }

  perfReview() {
    this.getPeerReviews();
    this.getManagerReview();
    this.getSelfReview();
  }

  getPeerReviews() {
    const peers = this.lookupPeers();
    // ...
  }

  lookupPeers() {
    return db.lookup(this.employee, 'peers');
  }

  getManagerReview() {
    const manager = this.lookupManager();
  }

  lookupManager() {
    return db.lookup(this.employee, 'manager');
  }

  getSelfReview() {
    // ...
  }
}

const review = new PerformanceReview(employee);
review.perfReview();

⬆ μƒλ‹¨μœΌλ‘œ

주석(Comments)

λΉ„μ¦ˆλ‹ˆμŠ€ 둜직이 λ³΅μž‘ν•œ κ²½μš°μ—λ§Œ 주석을 λ‹€μ„Έμš”

주석을 λ‹€λŠ”κ²ƒμ€ 사과해야할 일이며 ν•„μˆ˜μ μΈ 것이 μ•„λ‹™λ‹ˆλ‹€. 쒋은 μ½”λ“œλŠ” μ½”λ“œ 자체둜 λ§ν•©λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

function hashIt(data) {
  // 이건 ν•΄μ‰¬μž…λ‹ˆλ‹€.
  let hash = 0;

  // lenghλŠ” data의 κΈΈμ΄μž…λ‹ˆλ‹€.
  const length = data.length;

  // λ°μ΄ν„°μ˜ λ¬Έμžμ—΄ 개수만큼 λ°˜λ³΅λ¬Έμ„ μ‹€ν–‰ν•©λ‹ˆλ‹€.
  for (let i = 0; i < length; i++) {
    // λ¬Έμžμ—΄ μ½”λ“œλ₯Ό μ–»μŠ΅λ‹ˆλ‹€.
    const char = data.charCodeAt(i);
    // 해쉬λ₯Ό λ§Œλ“­λ‹ˆλ‹€.
    hash = ((hash << 5) - hash) + char;
    // 32-bit μ •μˆ˜λ‘œ λ°”κΏ‰λ‹ˆλ‹€.
    hash &= hash;
  }
}

쒋은 예:

function hashIt(data) {
  let hash = 0;
  const length = data.length;

  for (let i = 0; i < length; i++) {
    const char = data.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;

    // 32-bit μ •μˆ˜λ‘œ λ°”κΏ‰λ‹ˆλ‹€.
    hash &= hash;
  }
}

⬆ μƒλ‹¨μœΌλ‘œ

μ£Όμ„μœΌλ‘œ 된 μ½”λ“œλ₯Ό 남기지 λ§ˆμ„Έμš”

버전 관리 도ꡬ가 μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— μ½”λ“œλ₯Ό μ£Όμ„μœΌλ‘œ 남길 μ΄μœ κ°€ μ—†μŠ΅λ‹ˆλ‹€.

μ•ˆμ’‹μ€ 예:

doStuff();
// doOtherStuff();
// doSomeMoreStuff();
// doSoMuchStuff();

쒋은 예:

doStuff();

⬆ μƒλ‹¨μœΌλ‘œ

μ½”λ“œ 기둝을 μ£Όμ„μœΌλ‘œ 남기지 λ§ˆμ„Έμš”

버전 관리 도ꡬλ₯Ό μ΄μš©ν•΄μ•Όν•˜λŠ” 것을 κΌ­ κΈ°μ–΅ν•˜μ„Έμš”. 죽은 μ½”λ“œλ„ λΆˆν•„μš”ν•œ μ„€λͺ…도 특히 μ½”λ“œμ˜ 기둝에 λŒ€ν•œ 주석도 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ½”λ“œμ˜ 기둝에 λŒ€ν•΄ 보고 μ‹Άλ‹€λ©΄ git logλ₯Ό μ‚¬μš©ν•˜μ„Έμš”!

μ•ˆμ’‹μ€ 예:

/**
 * 2016-12-20: λͺ¨λ‚˜λ“œ μ œκ±°ν–ˆμŒ, μ΄ν•΄λŠ” λ˜μ§€ μ•ŠμŒ (RM)
 * 2016-10-01: λͺ¨λ‚˜λ“œ μ“°λŠ” 둜직 κ°œμ„  (JP)
 * 2016-02-03: νƒ€μž…μ²΄ν‚Ή ν•˜λŠ”λΆ€λΆ„ 제거 (LI)
 * 2015-03-14: 버그 μˆ˜μ • (JR)
 */
function combine(a, b) {
  return a + b;
}

쒋은 예:

function combine(a, b) {
  return a + b;
}

⬆ μƒλ‹¨μœΌλ‘œ

μ½”λ“œμ˜ μœ„μΉ˜λ₯Ό μ„€λͺ…ν•˜μ§€ λ§ˆμ„Έμš”

이건 정말 쓸데 μ—†μŠ΅λ‹ˆλ‹€. μ μ ˆν•œ 듀여쓰기와 ν¬λ§·νŒ…μ„ ν•˜κ³  ν•¨μˆ˜μ™€ λ³€μˆ˜μ˜ 이름에 의미λ₯Ό λΆ€μ—¬ν•˜μ„Έμš”.

μ•ˆμ’‹μ€ 예:

////////////////////////////////////////////////////////////////////////////////
// μŠ€μ½”ν”„ λͺ¨λΈ μ •μ˜
////////////////////////////////////////////////////////////////////////////////
$scope.model = {
  menu: 'foo',
  nav: 'bar'
};

////////////////////////////////////////////////////////////////////////////////
// actions μ„€μ •
////////////////////////////////////////////////////////////////////////////////
const actions = function() {
  // ...
};

쒋은 예:

$scope.model = {
  menu: 'foo',
  nav: 'bar'
};

const actions = function() {
  // ...
};

⬆ μƒλ‹¨μœΌλ‘œ

λ²ˆμ—­(Translation)

λ‹€λ₯Έ μ–Έμ–΄λ‘œλ„ 읽을 수 μžˆμŠ΅λ‹ˆλ‹€:

⬆ μƒλ‹¨μœΌλ‘œ

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].