/clean-code-javascript-kr

๐Ÿ› ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์œ„ํ•œ ํด๋ฆฐ์ฝ”๋“œ : ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ

Primary LanguageJavaScriptMIT LicenseMIT

ํด๋ฆฐ์ฝ”๋“œ : ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ (ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ)

์›๋ฌธ ๋งํฌ
ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ @sbyeol3

๋ชฉ์ฐจ

  1. ๋„์ž…๋ถ€
  2. ๋ณ€์ˆ˜
  3. ํ•จ์ˆ˜
  4. ๊ฐ์ฒด์™€ ์ž๋ฃŒ๊ตฌ์กฐ
  5. ํด๋ž˜์Šค
  6. SOLID
  7. ํ…Œ์ŠคํŠธ
  8. ๋™์‹œ์„ฑ
  9. ์—๋Ÿฌ ์ฒ˜๋ฆฌ
  10. ํฌ๋งทํŒ…
  11. ์ฃผ์„
  12. ๋ฒˆ์—ญ

๋„์ž…๋ถ€

Humorous image of software quality estimation as a count of how many expletives you shout when reading code

์†Œํ”„ํŠธ์›จ์–ด ์—”์ง€๋‹ˆ์–ด๋ง ์›๋ฆฌ์— ๋Œ€ํ•ด ๋กœ๋ฒ„ํŠธ C. ๋งˆํ‹ด์ด ์ €์ˆ ํ•œ ํด๋ฆฐ์ฝ”๋“œ๋ฅผ JavaScript์— ์ ์šฉ์‹œํ‚จ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์€ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ JavaScript๋กœ ๊ฐ€๋…์„ฑ ์žˆ๊ณ , ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๋ฆฌํŒฉํ† ๋ง ๊ฐ€๋Šฅํ•œ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค.

์ด ๊ธ€์— ๋‚˜์™€ ์žˆ๋Š” ์›์น™์„ ๋ชจ๋‘ ์—„๊ฒฉํ•˜๊ฒŒ ์ค€์ˆ˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, ๋” ์ ์€ ์ˆ˜์˜ ์›์น™๋“ค์ด ๋ณดํŽธ์ ์œผ๋กœ ํ•ฉ์˜๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์€ ์ง€์นจ์„œ ๊ทธ ์ด์ƒ์€ ์•„๋‹ˆ์ง€๋งŒ ํด๋ฆฐ ์ฝ”๋“œ ์ €์ž๋“ค์˜ ๋‹ค๋…„๊ฐ„์˜ ์ง‘๋‹จ์ ์ธ ๊ฒฝํ—˜์— ๊ฑธ์ณ ์„ฑ๋ฌธํ™”๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ์†Œํ”„ํŠธ์›จ์–ด ๊ณตํ•™ ๊ธฐ์ˆ ์€ ์ด์ œ ๋ง‰ 50๋…„์ด ์กฐ๊ธˆ ๋„˜์—ˆ์„ ๋ฟ์ด๊ณ , ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ๋งŽ์€ ๊ฒƒ๋“ค์„ ๋ฐฐ์šฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์•„ํ‚คํ…์ฒ˜ ์ž์ œ๋งŒํผ ์˜ค๋ž˜๋œ ๊ฒฝ์šฐ ์•„๋งˆ๋„ ๋” ๊นŒ๋‹ค๋กœ์šด ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ์ด๋Ÿฐ ์ง€์นจ๋“ค์ด ์—ฌ๋Ÿฌ๋ถ„๊ณผ ์—ฌ๋Ÿฌ๋ถ„์˜ ํŒ€์ด ๋งŒ๋“œ๋Š” JavaScript ์ฝ”๋“œ์˜ ํ€„๋ฆฌํ‹ฐ๋ฅผ ํ‰๊ฐ€ํ•˜๋Š” ์‹œ๊ธˆ์„์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ๋”! : ์ด ๊ธ€์„ ์ฝ๋Š”๋‹ค๊ณ  ๋ฐ”๋กœ ๋” ๋‚˜์€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, ์˜ค๋žœ ๊ธฐ๊ฐ„ ํŒ€์œผ๋กœ ์ผ์„ ํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ์—ฌ๋Ÿฌ๋ถ„์ด ์‹ค์ˆ˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ –์€ ์ ํ† ๊ฐ€ ์ ์ฐจ ์ตœ์ข…์ ์ธ ํ˜•ํƒœ๋กœ ๋ณ€ํ•ด๊ฐ€๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋ชจ๋“  ์ฝ”๋“œ ์กฐ๊ฐ๋“ค์€ ์ดˆ์•ˆ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ, ์šฐ๋ฆฌ๋Š” ๋™๋ฃŒ๋“ค๊ณผ ํ•จ๊ป˜ ์ฝ”๋“œ๋ฅผ ๊ฒ€ํ† ํ•  ๋•Œ ๊ฒฐํ•จ๋“ค์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์ฃ . ๊ฐœ์„ ์ด ํ•„์š”ํ•œ ์ดˆ์•ˆ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์ž์ฑ…ํ•˜์ง€ ๋งˆ์„ธ์š”. ๋Œ€์‹  ์ฝ”๋“œ๋ฅผ ๋‘๋“ค๊ฒจ ์™„์„ฑํ•ฉ์‹œ๋‹ค!

๋ณ€์ˆ˜

์˜๋ฏธ ์žˆ๊ณ  ๋ฐœ์Œ ๊ฐ€๋Šฅํ•œ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ผ

๋‚˜์œ ์˜ˆ:

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 MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; //86400000;

setTimeout(blastOff, MILLISECONDS_PER_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 = ["Austin", "New York", "San Francisco"];
locations.forEach(l => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  // ์ž ๊น, 'l'์ด ๋ญ์˜€๋”๋ผ?
  dispatch(l);
});

์ข‹์€ ์˜ˆ:

const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(location => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  dispatch(location);
});

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๋ถˆํ•„์š”ํ•œ ๋งฅ๋ฝ์„ ์ถ”๊ฐ€ํ•˜์ง€ ๋งˆ๋ผ

์—ฌ๋Ÿฌ๋ถ„์˜ ํด๋ž˜์Šค๋‚˜ ๊ฐ์ฒด๊ฐ€ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋งํ•ด์ฃผ๊ณ  ์žˆ๋‹ค๋ฉด, ๋ณ€์ˆ˜ ์ด๋ฆ„์—์„œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋˜ ๋งํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

const Car = {
  carMake: "Honda",
  carModel: "Accord",
  carColor: "Blue"
};

function paintCar(car, color) {
  car.carColor = color;
}

์ข‹์€ ์˜ˆ:

const Car = {
  make: "Honda",
  model: "Accord",
  color: "Blue"
};

function paintCar(car, color) {
  car.color = color;
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์งง์€ ์ฝ”๋“œ๋‚˜ ์กฐ๊ฑด๋ฌธ ๋Œ€์‹ ์— ์ธ์ž์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ผ

์ธ์ž์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์ฃผ๋Š” ๊ฒƒ์ด ๋ณดํ†ต์€ ์ฝ”๋“œ ํ•œ ์ค„์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋ช…๋ฃŒํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์„ค์ •ํ•˜๊ฒŒ ๋˜๋ฉด ํ•จ์ˆ˜๋Š” undefined ๊ฐ’์„ ๊ฐ€์ง€๋Š” ์ธ์ž์˜ ๊ฒฝ์šฐ์—๋งŒ ๊ธฐ๋ณธ๊ฐ’์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ '', "", false, null, 0, NaN์™€ ๊ฐ™์ด "falsy"ํ•œ ๊ฐ’๋“ค์—๋Š” ๊ธฐ๋ณธ๊ฐ’์ด ์ฃผ์–ด์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ˆ์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํ•จ์ˆ˜

ํ•จ์ˆ˜์˜ ์ธ์ž๋Š” 2๊ฐœ ์ดํ•˜์ธ ๊ฒƒ์ด ์ด์ƒ์ ์ด๋‹ค

ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ํ•จ์ˆ˜๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ์‰ฌ์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . 3๊ฐœ ์ด์ƒ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฒƒ์€ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํ•ฉ ๊ฐ„์˜ ํญ๋ฐœ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค. ์กฐํ•ฉ์ด ๋งŽ์•„์งˆ ์ˆ˜๋ก ๊ฐ๊ฐ์˜ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•  ๊ฒƒ์ด ๋งŽ์•„์ง‘๋‹ˆ๋‹ค.

1๊ฐœ ๋˜๋Š” 2๊ฐœ์˜ ์ธ์ž๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ์ด์ƒ์ ์ด๋ฉฐ, 3๊ฐœ๋Š” ๊ฐ€๋Šฅํ•œ ํ”ผํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. 3๊ฐœ๋ณด๋‹ค ๋งŽ์€ ๊ฒฝ์šฐ๋Š” ์ธ์ž๋ฅผ ํ•ฉ์น˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ธ์ˆ˜๋ฅผ 3๊ฐœ ์ด์ƒ ๊ฐ–๋Š” ํ•จ์ˆ˜๋ผ๋ฉด ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ๋Œ€๋ถ€๋ถ„ ์ƒ์œ„ ์ˆ˜์ค€์˜ ๊ฐ์ฒด๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งŽ์€ ํด๋ž˜์Šค ์—†์ด๋„ ๋ฐ”๋กœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋งŽ์€ ์ธ์ˆ˜๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋Š” ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ช…์‹œํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ๋ถ„์€ ES2015/ES6์˜ ๋น„๊ตฌ์กฐํ™” ํ• ๋‹น ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ช‡ ๊ฐ€์ง€ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ํ•จ์ˆ˜๋ฅผ ๋ดค์„ ๋•Œ ๊ทธ ํ•จ์ˆ˜์— ์–ด๋–ค ์†์„ฑ์ด ์‚ฌ์šฉ๋˜๋Š”์ง€ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๋ช…๋ช…๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ๋น„๊ตฌ์กฐํ™”๋Š” ๋˜ํ•œ ํ•จ์ˆ˜์— ์ „๋‹ฌ๋˜๋Š” ์ธ์ˆ˜ ๊ฐ์ฒด์˜ ์›์‹œ๊ฐ’๋“ค๋„ ๋ณต์ œํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. (์ฐธ๊ณ  ๐Ÿ“ ์ธ์ˆ˜ ๊ฐ์ฒด์—์„œ ๋น„๊ตฌ์กฐํ™”๋œ ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด๋“ค์€ ๋ณต์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค)
  4. Linter๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•ด ๊ฒฝ๊ณ ํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๊ตฌ์กฐํ™”ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ถˆ๊ฐ€๋Šฅํ•˜์ฃ .

๋‚˜์œ ์˜ˆ:

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

createMenu("Foo", "Bar", "Baz", true);

์ข‹์€ ์˜ˆ:

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

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํ•จ์ˆ˜๋Š” ํ•œ ๊ฐ€์ง€ ์ผ์„ ํ•ด์•ผ ํ•œ๋‹ค

์ด ๋ฃฐ์€ ์†Œํ”„ํŠธ์›จ์–ด ๊ณตํ•™์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ํ•œ ๊ฐ€์ง€ ์ผ๋ณด๋‹ค ๋” ๋งŽ์€ ์ผ์„ ํ•  ๋•Œ, ํž˜์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ณ  ์ถ”๋ก ํ•˜๋Š” ๊ฒƒ์ด ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ํ•จ์ˆ˜๊ฐ€ ํ•œ ๊ฐ€์ง€ ์ผ์„ ํ•˜๋„๋ก ๋ถ„๋ฆฌ์‹œํ‚ฌ ๋•Œ ๊ทธ ํ•จ์ˆ˜๋Š” ๋ฆฌํŒฉํ† ๋ง ํ•˜๊ธฐ๊ฐ€ ์‰ฌ์›Œ์ง€๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋„ ๋” ๋ช…๋ฃŒํ•ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒƒ๋“ค๋ณด๋‹ค ์ด ์ง€์นจ๋งŒ์„ ์ž˜ ๋”ฐ๋ฅธ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋ฅผ ์•ž์„ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

function emailActiveClients(clients) {
  clients.filter(isActiveClient).forEach(email);
}

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํ•จ์ˆ˜์˜ ์ด๋ฆ„์ด ํ•˜๋Š” ์ผ์„ ๋งํ•˜๋„๋ก ํ•˜๋ผ

๋‚˜์œ ์˜ˆ:

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

const date = new Date();

// ํ•จ์ˆ˜ ์ด๋ฆ„๋งŒ ๋ณด๋ฉด ๋ฌด์—‡์ด ๋”ํ•ด์ง€๋Š” ์ง€ ์•Œ๊ธฐ ์–ด๋ ต๊ตฐ์š” ๐Ÿฅฒ
addToDate(date, 1);

์ข‹์€ ์˜ˆ:

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

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํ•จ์ˆ˜๋Š” ์ถ”์ƒํ™”์˜ ํ•˜๋‚˜์˜ ๋ ˆ๋ฒจ์ด์–ด์•ผ ํ•œ๋‹ค

์—ฌ๋Ÿฌ๋ถ„์˜ ํ•จ์ˆ˜๊ฐ€ ๋‘˜ ์ด์ƒ์˜ ์ถ”์ƒํ™”๋ฅผ ๊ฐ€์งˆ ๋•Œ, ๊ทธ ํ•จ์ˆ˜๋Š” ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์„ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์ชผ๊ฐœ๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์—ฌ์ฃผ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๋ผ

์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๋„๋ก ์ตœ์„ ์„ ๋‹คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ง์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ๋•Œ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ์œ„์น˜๊ฐ€ ๋‘ ๊ฐœ ์ด์ƒ์ด ๋˜๋ฏ€๋กœ ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋Š” ๋‚˜์ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ์‹๋‹น์„ ์šด์˜ํ•˜๊ณ  ์žˆ๋Š”๋ฐ ํ† ๋งˆํ† , ์–‘ํŒŒ, ๋งˆ๋Š˜, ํ–ฅ์‹ ๋ฃŒ ๋“ฑ์ด ์žˆ๋Š” ์žฌ๊ณ ๋ฅผ ์ถ”์ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์„ธ์š”. ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๋ชฉ๋ก์ด ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด, ํ† ๋งˆํ† ๊ฐ€ ๋“ค์–ด๊ฐ„ ์š”๋ฆฌ๋ฅผ ์†๋‹˜์—๊ฒŒ ์ฃผ์—ˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ ๋ชฉ๋ก์ด ๋ชจ๋‘ ์—…๋ฐ์ดํŠธ ๋˜์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์žฌ๊ณ  ๋ชฉ๋ก์ด ํ•œ ๊ฐœ๋ฟ์ด๋ผ๋ฉด ๊ทธ ๋ชฉ๋ก ํ•˜๋‚˜๋งŒ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ๋˜๊ณ ์š”!

์ข…์ข… ์—ฌ๋Ÿฌ๋ถ„์€ ๊ณตํ†ต๋˜๋Š” ๋ถ€๋ถ„์ด ๋งŽ์ง€๋งŒ ๋‘ ๊ฐœ ์ด์ƒ์˜ ์•ฝ๊ฐ„์€ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด ์žˆ๊ธฐ์— ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ๊ฐ–๊ณ  ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ์ฐจ์ด๋กœ ์ธํ•ด ๊ฑฐ์˜ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฐœ๋ณ„์ ์ธ ํ•จ์ˆ˜๋“ค์ด ํ•„์š”ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์€ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜/๋ชจ๋“ˆ/ํด๋ž˜์Šค ๋งŒ์œผ๋กœ๋„ ์ด๋Ÿฌํ•œ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฒƒ๋“ค์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ถ”์ƒํ™”๋ฅผ ๋งŒ๋“ฆ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ถ”์ƒํ™”๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ๋ถ„์€ ํด๋ž˜์Šค ์žฅ์—์„œ ์ œ์‹œ๋˜๋Š” SOLID ์›์น™์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์œ ์ถ”์ƒํ™”๋Š” ์ค‘๋ณต ์ฝ”๋“œ๋ณด๋‹ค ๋” ์ข‹์ง€ ์•Š์œผ๋‹ˆ ์ฃผ์˜ํ•˜์„ธ์š”! ์ด๋ ‡๊ฒŒ ๋งํ•˜๊ธฐ๋Š” ํ–ˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ๋ถ„์ด ์ถ”์ƒํ™”๋ฅผ ์ž˜ ํ•˜์‹ ๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•˜์„ธ์š”! ๋ฐ˜๋ณตํ•  ์ˆ˜๋ก ์—ฌ๋Ÿฌ๋ถ„์€ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด ์ƒ๊ธธ ๋•Œ๋งˆ๋‹ค ์—ฌ๋Ÿฌ ๊ณณ์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

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",
  // User did not include 'body' key
  buttonText: "Send",
  cancellable: true
};

function createMenu(config) {
  let finalConfig = Object.assign(
    {
      title: "Foo",
      body: "Bar",
      buttonText: "Baz",
      cancellable: true
    },
    config
  );
  return finalConfig
  // 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}`);
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์‚ฌ์ดํŠธ ์ดํŽ™ํŠธ๋ฅผ ํ”ผํ•˜๋ผ 1

ํ•จ์ˆ˜๊ฐ€ ๊ฐ’์„ ๋ฐ›์•„ ๋‹ค๋ฅธ ๊ฐ’(๋“ค)์„ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ƒ…๋‹ˆ๋‹ค. ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋Š” ํŒŒ์ผ์— ์“ฐ๊ฑฐ๋‚˜, ์–ด๋–ค ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜, ์–ด์ฉŒ๋ฉด ์‹ค์ˆ˜๋กœ ๋‹น์‹ ์˜ ๋ชจ๋“  ๋ˆ์„ ๋‚ฏ์„  ์ด์—๊ฒŒ ์†ก๊ธˆํ•ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด ๋  ์ˆ˜๋„ ์žˆ์ฃ .

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์€ ๊ฐ€๋” ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๊ฐ€์งˆ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ์—ฌ๋Ÿฌ๋ถ„์€ ํŒŒ์ผ์— write ์ž‘์—…์ด ํ•„์š”ํ•  ์ˆ˜๋„ ์žˆ์ฃ . ์—ฌ๋Ÿฌ๋ถ„์ด ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ๋“ค์„ ์ค‘์•™ํ™” ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํŠน์ • ํŒŒ์ผ์— ์“ฐ๋Š” ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๊ฐ€์ง€์ง€ ๋งˆ์„ธ์š”. ๊ทธ๊ฒƒ์„ ํ•˜๋Š” ๋‹จ ํ•˜๋‚˜๋ฅผ ๊ฐ€์ง€์„ธ์š”.

ํ•ต์‹ฌ์€ ์–ด๋– ํ•œ ๊ตฌ์กฐ ์—†์ด ๊ฐ์ฒด๋“ค ๊ฐ„์— ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜, ๋ฌด์—‡์œผ๋กœ๋“  ์จ์งˆ ์ˆ˜ ์žˆ๋Š” mutableํ•œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ณณ์„ ์ค‘์•™ํ™” ํ•˜์ง€ ์•Š๋Š” ์ผ๋ฐ˜์ ์ธ ํ•จ์ •์„ ํ”ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ํ•จ์ •๋“ค์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ๋Œ€๋ถ€๋ถ„์˜ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค๋ณด๋‹ค ๋” ํ–‰๋ณตํ•ด์งˆ ๊ฒ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

// ๋‹ค์Œ ํ•จ์ˆ˜์— ์˜ํ•ด ์ฐธ์กฐ๋˜๋Š” ์ „์—ญ ๋ณ€์ˆ˜
// name์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋ฉด, ๋ฐฐ์—ด์ด ๋˜์–ด ๊นจ์ ธ๋ฒ„๋ฆด์ง€๋„ ๋ชฐ๋ผ์š”.
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'];

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ํ”ผํ•˜๋ผ 2

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์–ด๋–ค ๊ฐ’๋“ค์€ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅ(๋ถˆ๋ณ€, immutable)ํ•˜๊ณ  ์–ด๋–ค ๊ฐ’๋“ค์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๊ฐ€๋ณ€, mutable). ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ฐ’๋“ค์˜ ๋‘ ์ข…๋ฅ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฐ’๋“ค์€ ํ•จ์ˆ˜์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•  ๋•Œ ์กฐ์‹ฌํžˆ ๋‹ค๋ฃฐ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์—ด์˜ ์š”์†Œ๋“ค์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‰ฝ๊ฒŒ ๋ฒ„๊ทธ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

์žฅ๋ฐ”๊ตฌ๋‹ˆ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฐ์—ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„๋“ค์ด๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์„ธ์š”. ๋งŒ์•ฝ ํ•จ์ˆ˜๊ฐ€ ๊ตฌ๋งคํ•  ์•„์ดํ…œ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐฐ์—ด์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋งŒ๋“ ๋‹ค๋ฉด ๋™์ผํ•œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๋“ค๋„ ์•„์ดํ…œ ์ถ”๊ฐ€์— ์˜ํ•ด ์˜ํ–ฅ์„ ๋ฐ›๊ฒŒ ๋  ๊ฒ๋‹ˆ๋‹ค. ์ข‹์•„์š”, ํ•˜์ง€๋งŒ ์•ˆ ์ข‹์„ ์ˆ˜๋„ ์žˆ์–ด์š”. ์ข‹์ง€ ์•Š์€ ์ƒํ™ฉ์„ ์ƒ์ƒํ•ด๋ด…์‹œ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ "๊ตฌ๋งค" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ƒ์„ฑํ•˜์—ฌ ์„œ๋ฒ„์— cart ๋ฐฐ์—ด์„ ๋ณด๋‚ด๋Š” purchase ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ๋ถˆ๋Ÿ‰์œผ๋กœ purchase ํ•จ์ˆ˜๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๊ณ„์† ์žฌ์‹œ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์‚ฌ์ด ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์‹œ์ž‘๋˜๊ธฐ ์ „์— ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ์›ํ•˜์ง€ ์•Š๋Š” ํ•ญ๋ชฉ์˜ "์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ถ”๊ฐ€" ๋ฒ„ํŠผ์„ ์‹ค์ˆ˜๋กœ ํด๋ฆญํ•œ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์‹œ์ž‘๋˜์—ˆ๋‹ค๋ฉด, purchase ํ•จ์ˆ˜๋Š” cart ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ˆ˜๋กœ ์ถ”๊ฐ€๋œ ์•„์ดํ…œ์„ ์ „์†กํ•  ๊ฒ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์€ addItemToCart ํ•จ์ˆ˜๊ฐ€ ์–ธ์ œ๋‚˜ cart๋ฅผ ๋ณต์ œํ•˜์—ฌ ์ˆ˜์ •ํ•œ ํ›„ ๋ณต์ œ๋ณธ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์—ฌ์ „ํžˆ ์ด์ „ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ธํ’‹ ๊ฐ์ฒด๋ฅผ ์‹ค์ œ๋กœ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋„ ์žˆ์ง€๋งŒ ์‹ค๋ฌด์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋‹ค๋ณด๋ฉด ์‹ค์ œ๋กœ๋Š” ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ ๋“œ๋ฌผ๋‹ค๋Š” ๊ฒƒ์„ ์•„์‹ค ๊ฒ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ํ•จ์ˆ˜๋“ค์€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์—†์–ด ๋ฆฌํŒฉํ† ๋ง์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!

  2. ๊ฑฐ๋Œ€ํ•œ ๊ฐ์ฒด๋ฅผ ๋ณต์ œํ•˜๋Š” ๊ฒƒ์€ ํผํฌ๋จผ์Šค ์ธก๋ฉด์—์„œ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ ์ง์ ‘ ๋ณต์ œํ•  ๋•Œ๋ณด๋‹ค ๋น ๋ฅด๊ณ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋œ ์“ฐ๋Š” ์ข‹์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ๋Š” ํฐ ์ด์Šˆ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ „์—ญ ํ•จ์ˆ˜์— Write ํ•˜์ง€ ๋งˆ๋ผ

์ „์—ญ ๊ฐ’๋“ค์„ ์˜ค์—ผ์‹œํ‚ค๋Š” ๊ฒƒ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋งค์šฐ ๋‚˜์œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹น์‹ ์˜ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž๋Š” ํ”„๋กœ๋•์…˜์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๊นŒ์ง€๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์˜ˆ์‹œ๋ฅผ ์ƒ๊ฐํ•ด๋ณผ๊นŒ์š”. ๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„์ด JavaScript์˜ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐฐ์—ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ™•์žฅํ•˜์—ฌ ๋‘ ๋ฐฐ์—ด์˜ ์ฐจ์ด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” diff ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ์—ฌ๋Ÿฌ๋ถ„์€ Array.prototype์— ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์“ธ ์ˆ˜ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ™์€ ์ž‘์—…์„ ํ•˜๋ ค๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์ถฉ๋Œํ•  ์ˆ˜๋„ ์žˆ์ฃ . ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฐฐ์—ด์˜ ์ฒซ ์š”์†Œ์™€ ๋งˆ์ง€๋ง‰ ์š”์†Œ์˜ ์ฐจ์ด๋ฅผ ์ฐพ๊ณ ์ž diff๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ์ด ์˜ˆ์‹œ๋Š” ES2015/ES6 ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 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));
  }
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋ณด๋‹ค ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์„ ํ˜ธํ•˜๋ผ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” 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.reduce(
  (totalLines, output) => totalLines + output.linesOfCode,
  0
);

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์กฐ๊ฑด๋ฌธ์„ ์บก์Šํ™”ํ•˜๋ผ

๋‚˜์œ ์˜ˆ:

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๋ฌธ ์—†์ด ์–ด๋–ป๊ฒŒ ๋ญ˜ ํ•˜๊ฒ ์–ด์š”?"๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‹ต์€ ๋งŽ์€ ๊ฒฝ์šฐ์—์„œ ๊ฐ™์€ ์ผ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹คํ˜•์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์งˆ๋ฌธ์€ ๋ณดํ†ต "์Œ ์ข‹๋„ค์š”, ๊ทผ๋ฐ ์™œ ์ œ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์‹ถ๊ฒ ์–ด์š”?" ์ž…๋‹ˆ๋‹ค. ์ด์ „์— ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์› ๋˜ ํด๋ฆฐ ์ฝ”๋“œ ๊ฐœ๋…์— ๋‹ต์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋Š” ์˜ค์ง ํ•œ ๊ฐ€์ง€ ์ผ๋งŒ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด์ฃ . ์—ฌ๋Ÿฌ๋ถ„์ด 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();
  }
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ”ผํ•˜๋ผ 1

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ•จ์ˆ˜๋Š” ์–ด๋–ค ํƒ€์ž…์˜ ์ธ์ž๋“  ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ์—ฌ๋Ÿฌ๋ถ„์€ ์ด๋Ÿฌํ•œ ํƒ€์ž…์œผ๋กœ๋ถ€ํ„ฐ์˜ ์ž์œ ์— ์‚ฌ๋กœ์žกํ˜€ ํ•จ์ˆ˜์—์„œ ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ•˜๊ณ ์ž ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ์ผ๊ด€๋œ 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"));
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ”ผํ•˜๋ผ 2

๋ฌธ์ž์—ด์ด๋‚˜ ์ •์ˆ˜์™€ ๊ฐ™์€ ์›์‹œ๊ฐ’์œผ๋กœ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ๋‹คํ˜•์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†๊ฒ ์ง€๋งŒ ์—ฌ์ „ํžˆ ํƒ€์ž… ์ฒดํฌ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํ‘œ์ค€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ตฌ๋ฌธ ์œ„์— ์ •์  ํƒ€์ดํ•‘ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ข‹์€ ๋Œ€์•ˆ์ด ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ "ํƒ€์ž… ์•ˆ์ •์„ฑ"์„ ๋ณด์ถฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์žฅํ™ฉํ•œ ๋ง์ด ํ•„์š”ํ•ด์ง€๋ฏ€๋กœ ๊ฐ€๋…์„ฑ์ด ์ €ํ•˜๋ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๊นจ๋—ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ , ์ข‹์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ข‹์€ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ•˜์„ธ์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š” (๋งํ–ˆ๋“ฏ์ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ข‹์€ ๋Œ€์•ˆ์ž…๋‹ˆ๋‹ค!).

๋‚˜์œ ์˜ˆ:

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`์ด ์บ์‹ฑ๋˜์ง€ ์•Š์•„ ๋‹ค์‹œ ๊ณ„์‚ฐ์„ ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
// ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์ตœ์ ํ™” ๋ฉ๋‹ˆ๋‹ค.
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");

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๊ฐ์ฒด์™€ ์ž๋ฃŒ๊ตฌ์กฐ

getter์™€ setter๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

getter์™€ setter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ฐ์ฒด์—์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐพ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚ซ์Šต๋‹ˆ๋‹ค. "์™œ?"๋ƒ๊ณ  ๋ฌผ์œผ์‹ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธ€์Ž„์š”, ์•„๋ž˜ ์ด์œ ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์—ฌ๋Ÿฌ๋ถ„์ด ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋„˜์–ด ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์—ฌ๋Ÿฌ๋ถ„์€ ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๋ชจ๋“  ์•ก์„ธ์Šค ๊ถŒํ•œ์„ ์ฐพ์•„ ๋ณ€๊ฒฝํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.
  • set์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ๊ฒ€์ฆ ๊ณผ์ •์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‚ด๋ถ€ ํ‘œํ˜„์„ ์บก์Šํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ๊น…๊ณผ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์ด ์‰ฝ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์„ ๋Š๋ฆฌ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

function makeBankAccount() {
  // ...

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

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

์ข‹์€ ์˜ˆ:

function makeBankAccount() {
  // this one is private
  let balance = 0;

  // a "getter", made public via the returned object below
  function getBalance() {
    return balance;
  }

  // a "setter", made public via the returned object below
  function setBalance(amount) {
    // ... validate before updating the 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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํด๋ž˜์Šค

ES2015/ES6 ํด๋ž˜์Šค๋ณด๋‹ค ES5 ์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ์„ ํ˜ธํ•˜๋ผ

๊ณ ์ „์ ์ธ ES5 ํด๋ž˜์Šค์˜ ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค ์ƒ์†, ๊ตฌ์„ฑ, ๋ฉ”์„œ๋“œ ์ •์˜๋ฅผ ์–ป๋Š” ๊ฒƒ์€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ƒ์†์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ES2015/ES6์˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๊ทธ๋Ÿฌ๋‚˜ ๋” ํฌ๊ณ  ๋ณต์žกํ•œ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ํด๋ž˜์Šค ๋ณด๋‹ค๋Š” ์ž‘์€ ํ•จ์ˆ˜๋ฅผ ์„ ํ˜ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

  this.age = age;
};

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

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() {
    /* ... */
  }
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์‚ฌ์šฉํ•˜๋ผ

์ด ํŒจํ„ด์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์•„์ฃผ ์œ ์šฉํ•˜๋ฉฐ jQuery๋‚˜ Loadsh์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋„ ๋ณด์ž…๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์€ ์ฝ”๋“œ์˜ ํ‘œํ˜„์„ ๋” ํ’๋ถ€ํ•˜๊ฒŒ ํ•ด์ฃผ๊ณ  ์žฅํ™ฉํ•จ์„ ์ค„์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์–ผ๋งˆ๋‚˜ ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•ด์ง€๋Š”์ง€ ์‚ดํŽด๋ณด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ํด๋ž˜์Šค ํ•จ์ˆ˜์—์„œ, ๋ชจ๋“  ํ•จ์ˆ˜์˜ ๋์—์„œ ๋‹จ์ˆœํžˆ this๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋” ๋งŽ์€ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  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("Ford", "F-150", "red");
car.setColor("pink");
car.save();

์ข‹์€ ์˜ˆ:

class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
    // NOTE: Returning this for chaining
    return this;
  }

  setModel(model) {
    this.model = model;
    // NOTE: Returning this for chaining
    return this;
  }

  setColor(color) {
    this.color = color;
    // NOTE: Returning this for chaining
    return this;
  }

  save() {
    console.log(this.make, this.model, this.color);
    // NOTE: Returning this for chaining
    return this;
  }
}

const car = new Car("Ford", "F-150", "red").setColor("pink").save();

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ƒ์†๋ณด๋‹ค ๊ตฌ์„ฑ์„ ์„ ํ˜ธํ•˜๋ผ

The Gang of Four๊ฐ€ ์ €์ˆ ํ•œ ๋””์ž์ธ ํŒจํ„ด์—์„œ ์ž˜ ์•Œ๋ ค์ง„ ๋ฐ”์™€ ๊ฐ™์ด ์—ฌ๋Ÿฌ๋ถ„์€ ๊ฐ€๋Šฅํ•œ ์ƒ์†๋ณด๋‹ค๋Š” ๊ตฌ์„ฑ์„ ๋” ์„ ํ˜ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋Š” ์ข‹์€ ์ด์œ ๋“ค์ด ์žˆ๊ณ  ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋” ์ข‹์€ ์ด์œ ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฉ์–ธ์˜ ํ•ต์‹ฌ์€ ์—ฌ๋Ÿฌ๋ถ„์ด ๋ณธ๋Šฅ์ ์œผ๋กœ ์ƒ์†์„ ์›ํ•œ๋‹ค๋ฉด ๊ตฌ์„ฑ์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ฌธ์ œ๋ฅผ ๋” ์ž˜ ๋ชจ๋ธ๋งํ•  ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์€ "์ƒ์†์„ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?"๋ผ๋Š” ๊ถ๊ธˆ์ฆ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์–ด๋–ค ๋ฌธ์ œ์ด๋ƒ์— ๋”ฐ๋ผ ๋‹ค๋ฅด์ง€๋งŒ ์•„๋ž˜ ๋ชฉ๋ก์€ ๊ตฌ์„ฑ๋ณด๋‹ค ์ƒ์†์ด ๋” ํƒ€๋‹นํ•œ ๋•Œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

  1. ์ƒ์†์ด "has-a"๊ฐ€ ์•„๋‹Œ "is-a" ๊ด€๊ณ„๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒฝ์šฐ (์‚ฌ๋žŒ->๋™๋ฌผ vs. ์‚ฌ์šฉ์ž->์‚ฌ์šฉ์ž ์ƒ์„ธ).
  2. ๋ฒ ์ด์Šค ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ (์‚ฌ๋žŒ์€ ๋‹ค๋ฅธ ๋™๋ฌผ๋“ค์ฒ˜๋Ÿผ ์›€์ง์ผ ์ˆ˜ ์žˆ์Œ).
  3. ๋ฒ ์ด์Šค ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ํŒŒ์ƒ๋œ ํด๋ž˜์Šค๋ฅผ ์ „์—ญ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๋Š” ๊ฒฝ์šฐ (๋ชจ๋“  ๋™๋ฌผ์€ ์›€์ง์ผ ๋•Œ ์นผ๋กœ๋ฆฌ ์†Œ๋น„๋Ÿ‰์ด ๋ฐ”๋€œ).

๋‚˜์œ ์˜ˆ:

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

  // ...
}

// Employee๋Š” ์„ธ๊ธˆ ๋ฐ์ดํ„ฐ๋ฅผ "๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์—" ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
// 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

๋‹จ์ผ ์ฑ…์ž„ ์›์น™ (SRP)

ํด๋ฆฐ ์ฝ”๋“œ์—์„œ ๋ช…์‹œ๋œ ๊ฒƒ๊ณผ ๊ฐ™์ด "ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ํ•œ ๊ฐ€์ง€๋ณด๋‹ค ๋” ๋งŽ์œผ๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค". ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋ฅผ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์œผ๋กœ ํฌ์žฅํ•˜๋Š” ๊ฑด ๋งค๋ ฅ์ ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ๋น„ํ–‰๊ธฐ๋ฅผ ํƒˆ ๋•Œ ํ•˜๋‚˜์˜ ์บ๋ฆฌ์–ด๋งŒ ๊ฐ€์ง€๊ณ  ํƒˆ ์ˆ˜ ์žˆ์„ ๋•Œ์ฒ˜๋Ÿผ ๋ง์ด์ฃ . ๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ํด๋ž˜์Šค๊ฐ€ ๊ฐœ๋…์ ์œผ๋กœ ์‘์ง‘๋˜์ง€ ์•Š๊ณ  ๋ณ€๊ฒฝ๋  ๋งŽ์€ ์ด์œ ๋ฅผ ์ค€๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝ์‹œ์ผœ์•ผ ํ•˜๋Š” ์‹œ๊ฐ„์„ ์ค„์ด๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๋งŽ์€ ๊ธฐ๋Šฅ์ด ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ์žˆ๊ณ  ๊ทธ ์ค‘์˜ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ณ  ์žˆ๋Š” ๋‹ค๋ฅธ ๋ชจ๋“ˆ์— ์–ด๋–ค ์˜ํ–ฅ์„ ์ค„์ง€ ์•Œ๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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()) {
      // ...
    }
  }
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๊ฐœ๋ฐฉ/ํ์‡„ ์›์น™ (OCP)

Bertrand Meyer๊ฐ€ ๋งํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ "์†Œํ”„ํŠธ์›จ์–ด ์—”ํ‹ฐํ‹ฐ(ํด๋ž˜์Šค, ๋ชจ๋“ˆ, ํ•จ์ˆ˜ ๋“ฑ)๋Š” ํ™•์žฅ์— ์—ด๋ ค ์žˆ์–ด์•ผ ํ•˜๊ณ , ๋ณ€๊ฒฝ์— ๋‹ซํ˜€ ์žˆ์–ด์•ผ" ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๊ฒŒ ๋ฌด์Šจ ๋œป์ผ๊นŒ์š”? ์ด ์›์น™์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑด ํ—ˆ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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 === "nodeAdapter") {
      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
    });
  }
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™ (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(); // ๋ฌธ์ œ: ์ •์‚ฌ๊ฐํ˜•์€ 20์ด ์•„๋‹Œ 25๋ฅผ ๋ฆฌํ„ดํ•จ
    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);

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™ (ISP)

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค์ฒ˜๋Ÿผ ์—„๊ฒฉํ•˜๊ฒŒ ์ ์šฉ๋˜๋Š” ์›์น™์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ๋ถ€์กฑ ๋•Œ๋ฌธ์— ์ค‘์š”ํ•˜๊ณ  ๊ด€๋ จ์žˆ๋Š” ์›์น™์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

ISP ์›์น™์€ "ํด๋ผ์ด์–ธํŠธ๋Š” ๊ทธ๋“ค์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๋„๋ก ๊ฐ•์ œ๋ฐ›์ง€ ์•Š๋Š”๋‹ค"๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋Š” duck ํƒ€์ดํ•‘๋•Œ๋ฌธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์•”์‹œ์ ์ธ ๊ณ„์•ฝ์ž…๋‹ˆ๋‹ค.

์—ญ : duck typing์ด๋ž€ ๋™์  ํƒ€์ดํ•‘์˜ ํ•œ ์ข…๋ฅ˜๋กœ, ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์œผ๋กœ ํƒ€์ž…์„ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ  ๋ณ€์ˆ˜์™€ ๋ฉ”์†Œ๋“œ์— ์˜ํ•ด ํƒ€์ž…์ด ๊ฒฐ์ •๋˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด ์›์น™์„ ์„ค๋ช…ํ•˜๋Š” ์ข‹์€ ์˜ˆ์‹œ๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ์„ธํŒ… ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋งค์šฐ ๋งŽ์€ ์˜ต์…˜์„ ์„ค์ •ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์€๋ฐ, ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ชจ๋“  ์„ค์ •์ด ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์„ค์ •์„ ์„ ํƒ์ ์œผ๋กœ ํ•˜๋Š” ๊ฒƒ์ด "๋šฑ๋šฑํ•œ ์ธํ„ฐํŽ˜์ด์Šค"๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

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

  traverse() {
    // ...
  }
}

const $ = new DOMTraverser({
  rootNode: document.getElementsByTagName("body"),
  animationModule() {} // Most of the time, we won't need to animate when traversing.
  // ...
});

์ข‹์€ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์˜์กด ์—ญ์ „ ์›์น™ (DIP)

์ด ์›์น™์€ ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์‚ฌ์‹ค์„ ๋งํ•ด์ค๋‹ˆ๋‹ค:

  1. ๊ณ ์ˆ˜์ค€์˜ ๋ชจ๋“ˆ์€ ์ €์ˆ˜์ค€์˜ ๋ชจ๋“ˆ์— ์˜์กด์ ์ด์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ชจ๋“ˆ์€ ์ถ”์ƒํ™”์— ์˜์กด์ ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ถ”์ƒํ™”๋Š” ์„ธ๋ถ€์‚ฌํ•ญ์— ์˜์กด์ ์ด์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์„ธ๋ถ€์‚ฌํ•ญ์€ ์ถ”์ƒํ™”์— ์˜์กด์ ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” ์ด ์›์น™์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ๋ถ„์ด AngularJS๋กœ ์ž‘์—…์„ ํ•ด๋ณด์…จ๋‹ค๋ฉด, ์˜์กด์„ฑ ์ฃผ์ž…(DI)์˜ ํ˜•ํƒœ๋กœ ์ด ์›์น™์„ ๊ตฌํ˜„ํ•ด๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€๊ฐ€ ๋™์ผํ•œ ๊ฐœ๋…์€ ์•„๋‹ˆ์ง€๋งŒ, DIP ์›์น™์€ ๊ณ ์ˆ˜์ค€ ๋ชจ๋“ˆ์ด ์ €์ˆ˜์ค€ ๋ชจ๋“ˆ์˜ ์„ธ๋ถ€์‚ฌํ•ญ์„ ์•Œ๊ณ  ์ด๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด ์›์น™์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ๋‘ ๋ชจ๋“ˆ ๊ฐ„์˜ ์˜์กด์„ฑ์„ ๋‚ฎ์ถฐ์ค€๋‹ค๋Š” ๊ฒƒ์ด์ฃ . ๋ชจ๋“ˆ ๊ฐ„์˜ ์˜์กด์„ฑ์ด ๋†’์„์ˆ˜๋ก ๋ฆฌํŒฉํ† ๋ง์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ์•„์ฃผ ๋‚˜์œ ๊ฐœ๋ฐœ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

์ด์ „์— ๋งํ–ˆ๋“ฏ์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์ถ”์ƒํ™”์— ์˜์กดํ•˜๋Š” ๊ฒƒ์€ ์•”๋ฌต์ ์ธ ์•ฝ์†์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋‹ค๋ฅธ ๊ฐ์ฒด๋‚˜ ํด๋ž˜์Šค์— ๋…ธ์ถœ๋˜๋Š” ๋ฉ”์†Œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์•”๋ฌต์ ์ธ ์•ฝ์†์ด ๋˜๋Š” ๊ฒƒ์ด์ฃ . ์•„๋ž˜ ์˜ˆ์ œ์—์„œ ์•”๋ฌต์ ์ธ ์•ฝ์†์€ InventoryTracker์— ๋Œ€ํ•œ ๋ชจ๋“  ์š”์ฒญ ๋ชจ๋“ˆ์ด requestItems ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

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

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

    // ๐Ÿ™… : ํŠน์ • ์š”์ฒญ ๊ตฌํ˜„์— ๋Œ€ํ•œ ์˜์กด์„ฑ์„ ๋งŒ๋“ค์—ˆ์œผ๋ฏ€๋กœ ์ข‹์ง€ ์•Š์•„์š”.
    // requestItems์ด request ๋ฉ”์†Œ๋“œ์— ์˜ํ•ด ๋‹ฌ๋ผ์ง€๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    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();

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ๋Š” ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฑฐ๋ผ๊ณ  ํ™•์‹ ํ•  ์ˆ˜ ์—†๋Š” ์ฝ”๋“œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์–ผ๋งˆ๋‚˜ ํ•  ๊ฒƒ์ธ์ง€๋Š” ํŒ€๋งˆ๋‹ค ๋‹ค๋ฅด์ง€๋งŒ, 100% ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค๋ฉด ๋งค์šฐ ๋†’์€ ์ฝ”๋“œ์˜ ์‹ ๋ขฐ์„ฑ๊ณผ ๊ฐœ๋ฐœ์ž์˜ ๋‚ด์  ํ‰ํ™”๋„ ํ•จ๊ป˜ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ง์€ ์ข‹์€ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋”๋ถˆ์–ด ์ข‹์€ ์ปค๋ฒ„๋ฆฌ์ง€ ํˆด์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ด์ฃ .

ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ๋ณ€๋ช…์˜ ์—ฌ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•˜๊ณ  ์ข‹์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์ด ๋งŽ์œผ๋‹ˆ ์—ฌ๋Ÿฌ๋ถ„์˜ ํŒ€์— ๋งž๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ฐพ์•„๋ณด์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ํŒ€๊ณผ ์ž˜ ๋งž๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ณจ๋ž๋‹ค๋ฉด, ๋ชจ๋“  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ/๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•  ๋•Œ ํ•ญ์ƒ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ํŒ€์ด ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•๋ก (TDD)์„ ์„ ํ˜ธํ•œ๋‹ค๋ฉด ์•„์ฃผ ์ข‹์€ ์„ ํƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋–ค ๊ธฐ๋Šฅ์— ์ฐฉ์ˆ˜ํ•˜๊ฑฐ๋‚˜ ์ด๋ฏธ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜๊ธฐ ์ „์— ์—ฌ๋Ÿฌ๋ถ„์ด ์ •ํ•œ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ๋Š” ํ•˜๋‚˜์˜ ๋ชฉํ‘œ๋ฅผ ๊ฐ€์ง€๊ฒŒ ํ•ด๋ผ

๋‚˜์œ ์˜ˆ:

import assert from "assert";

describe("MomentJS", () => {
  it("handles date boundaries", () => {
    let date;

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

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

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

์ข‹์€ ์˜ˆ:

import assert from "assert";

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

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

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๋™์‹œ์„ฑ

callback ๋Œ€์‹  Promise๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

Callback์€ ๊น”๋”ํ•˜์ง€ ์•Š๊ณ , ๋„ˆ๋ฌด ๋งŽ์€ ์ค‘์ฒฉ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ES2015/ES6๋ถ€ํ„ฐ๋Š” Promise๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์œผ๋‹ˆ ์ด๊ฑธ ์‚ฌ์šฉํ•˜์„ธ์š”!

๋‚˜์œ ์˜ˆ:

import { get } from "request";
import { writeFile } from "fs";

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

์ข‹์€ ์˜ˆ:

import { get } from "request-promise";
import { writeFile } from "fs-extra";

get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin")
  .then(body => {
    return writeFile("article.html", body);
  })
  .then(() => {
    console.log("File written");
  })
  .catch(err => {
    console.error(err);
  });

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

Async/Await์€ Promise๋ณด๋‹ค ๊น”๋”ํ•˜๋‹ค

Promise๋Š” callback์˜ ์•„์ฃผ ์ข‹์€ ๋Œ€์•ˆ์ด ๋˜์ง€๋งŒ ES2017/ES8์— ๋„์ž…๋œ async/await์€ ์ด๋ณด๋‹ค ๋” ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์ด ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์•ž์— async ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๊ณ  ํ•จ์ˆ˜์˜ then ์ฒด์ธ ๋Œ€์‹ ์— ์—ฌ๋Ÿฌ๋ถ„์˜ ๋กœ์ง๋งŒ์„ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ES2017/ES8์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด async/await์„ ์‚ฌ์šฉํ•˜์„ธ์š”!

๋‚˜์œ ์˜ˆ:

import { get } from "request-promise";
import { writeFile } from "fs-extra";

get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin")
  .then(body => {
    return writeFile("article.html", body);
  })
  .then(() => {
    console.log("File written");
  })
  .catch(err => {
    console.error(err);
  });

์ข‹์€ ์˜ˆ:

import { get } from "request-promise";
import { writeFile } from "fs-extra";

async function getCleanCodeArticle() {
  try {
    const body = await get(
      "https://en.wikipedia.org/wiki/Robert_Cecil_Martin"
    );
    await writeFile("article.html", body);
    console.log("File written");
  } catch (err) {
    console.error(err);
  }
}

getCleanCodeArticle()

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์—๋Ÿฌ ์ฒ˜๋ฆฌ

์—๋Ÿฌ๋ฅผ ๋˜์ง„๋‹ค๋Š” ๊ฒƒ์€ ์ข‹์€ ๊ฒ๋‹ˆ๋‹ค! ํ”„๋กœ๊ทธ๋žจ์ด ๋ฌด์–ธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์„ ๋•Œ ํ˜„์žฌ ์Šคํƒ์—์„œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์ค‘๋‹จํ•˜๊ณ , ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  ์Šคํƒ์„ ์ถ”์ ํ•˜์—ฌ ์ฝ˜์†”์—์„œ ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์€ ๋Ÿฐํƒ€์ž„์ด ์—๋Ÿฌ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์•Œ์•„์ฐจ๋ ธ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ฐพ์•„๋‚ธ ์—๋Ÿฌ๋ฅผ ๋ฌด์‹œํ•˜์ง€ ๋งˆ๋ผ

์ฐพ์€ ์—๋Ÿฌ๋ฅผ ๊ฐ€๋งŒํžˆ ๋‘๋Š” ๊ฒƒ์€ ์—๋Ÿฌ๋ฅผ ๊ณ ์น˜๊ฑฐ๋‚˜ ๋Œ€์‘ํ•˜๋Š” ๋Šฅ๋ ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฝ˜์†”์— ์—๋Ÿฌ๋ฅผ ์ฐ๋Š” ๊ฒƒ(console.log)์€ ์ฝ˜์†”์— ์ถœ๋ ฅ๋œ ๋งŽ์€ ๊ฒƒ๋“ค์„ ์žƒ์–ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ๋งŒํผ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์•„๋‹™๋‹ˆ๋‹ค. ํŠน์ • ์ฝ”๋“œ๋ฅผ try/catch๋กœ ๋‘˜๋Ÿฌ์‹ผ๋‹ค๋Š” ๊ฒƒ์€ ๊ทธ ๊ณณ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ๊ณ„ํš์ด๋‚˜ ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

try {
  functionThatMightThrow();
} catch (error) {
  // 1. console.error์„ ์‚ฌ์šฉํ•˜๊ธฐ (console.log๋ณด๋‹ค ์•Œ๊ธฐ ์ข‹์Œ)
  console.error(error);
  // 2. ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ ค์ฃผ๊ธฐ
  notifyUserOfError(error);
  // 3. ์„œ๋น„์Šค ์ž์ฒด์— ์—๋Ÿฌ๋ฅผ ์•Œ๋ฆฌ๊ธฐ
  reportErrorToService(error);
  // ๊ทธ ์™ธ ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค
}

reject๋œ Promise๋ฅผ ๋ฌด์‹œํ•˜์ง€ ๋งˆ๋ผ

์œ„ try/catch์—์„œ ์„ค๋ช…ํ•œ ์ด์œ ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

getdata()
  .then(data => {
    functionThatMightThrow(data);
  })
  .catch(error => {
    // One option (more noisy than console.log):
    console.error(error);
    // Another option:
    notifyUserOfError(error);
    // Another option:
    reportErrorToService(error);
    // OR do all three!
  });

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

ํฌ๋งทํŒ…

ํฌ๋งทํŒ…์€ ์ฃผ๊ด€์ ์ž…๋‹ˆ๋‹ค. ์–ด๋ ต์ง€ ์•Š๊ณ  ๋น ๋ฅด๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ทœ์น™๋“ค์ด ๋งŽ์Šต๋‹ˆ๋‹ค. ํฌ๋งทํŒ…์˜ ์ค‘์š”ํ•œ ์ ์€ ํฌ๋งทํŒ…์— ๊ณผํ•˜๊ฒŒ ์‹ ๊ฒฝ ์“ธ ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค. ์ž๋™์œผ๋กœ ํ•ด์ฃผ๋Š” ์•„์ฃผ ๋งŽ์€ ๋„๊ตฌ๋“ค์ด ์žˆ์œผ๋‹ˆ๊นŒ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”! ํฌ๋งทํŒ…์— ๊ด€ํ•ด ์—”์ง€๋‹ˆ์–ด๋“ค๋ผ๋ฆฌ ๋…ผ์Ÿํ•˜๋Š” ๊ฒƒ์€ ์‹œ๊ฐ„๊ณผ ๋ˆ์„ ์•„์ฃผ ๋‚ญ๋น„ํ•˜๊ณ  ์žˆ๋Š” ๊ฑฐ์˜ˆ์š”.

์ž๋™์œผ๋กœ ํฌ๋งทํŒ…ํ•ด์ฃผ๋Š” ๋ฒ”์œ„(๋“ค์—ฌ์“ฐ๊ธฐ, ํƒญ vs. ์ŠคํŽ˜์ด์Šค, ํฐ ๋”ฐ์˜ดํ‘œ vs. ์ž‘์€ ๋”ฐ์˜ดํ‘œ ๋“ฑ)์— ํฌํ•จ๋˜์ง€ ์•Š๋Š” ๊ฒƒ๋“ค์€ ๋ช‡ ๊ฐ€์ง€ ์ง€์นจ์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ผ๊ด€๋˜๊ฒŒ ๋Œ€๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…์ด ์ •ํ•ด์ ธ ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€์†Œ๋ฌธ์ž๋Š” ์–ด๋–ค ๊ฐ’์ด ๋ณ€์ˆ˜์ธ์ง€, ํ•จ์ˆ˜์ธ์ง€์™€ ๊ฐ™์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ทœ์น™๋“ค์€ ์ฃผ๊ด€์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ๋ถ„์˜ ํŒ€์ด ์„ ํƒํ•œ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๊ทœ์น™์„ ๋”ฐ๋ฅด๋“  ์ผ๊ด€๋˜๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ฃผ์„

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋ณต์žกํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ฃผ์„์„ ๋‚จ๊ฒจ๋ผ

์ฃผ์„์€ ๋ฐฐ๋ ค์ด์ง€, ๋ฐ˜๋“œ์‹œ ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ข‹์€ ์ฝ”๋“œ๋Š” ๋Œ€๋ถ€๋ถ„ ์ฃผ์„์ด ์—†์–ด๋„ ๊ทธ ์ž์ฒด๋กœ ์„ค๋ช…์ด ๋ฉ๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

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๋น„ํŠธ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜
    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๋น„ํŠธ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜
    hash &= hash;
  }
}

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ฝ”๋“œ ๋ฒ ์ด์Šค์—์„œ ์ฃผ์„์ด ๋œ ์ฝ”๋“œ๋Š” ์ œ๊ฑฐํ•˜๋ผ

๋ฒ„์ „ ๊ด€๋ฆฌ๊ฐ€ ์กด์žฌํ•˜๋Š” ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋ž˜๋œ ์ฝ”๋“œ๋Š” ์ง€์šฐ์„ธ์š”.

๋‚˜์œ ์˜ˆ:

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

์ข‹์€ ์˜ˆ:

doStuff();

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์ผ์ง€๋ฅผ ์ฃผ์„์œผ๋กœ ๊ธฐ๋กํ•˜์ง€ ๋งˆ๋ผ

๋ฒ„์ „ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํ•ญ์ƒ ์žŠ์ง€ ๋งˆ์„ธ์š”! ์ฃฝ์€ ์ฝ”๋“œ๋‚˜ ์ฃผ์„์ด ๋œ ์ฝ”๋“œ, ํŠนํžˆ ์ผ์ง€๋ฅผ ๊ธฐ๋กํ•˜๋Š” ์ฃผ์„์€ ์žˆ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ก์„ ํ™•์ธํ•˜๋ ค๋ฉด git log ๋ช…๋ น์–ด๋ฅผ ํ™œ์šฉํ•˜์„ธ์š”!

๋‚˜์œ ์˜ˆ:

/**
 * 2016-12-20: Removed monads, didn't understand them (RM)
 * 2016-10-01: Improved using special monads (JP)
 * 2016-02-03: Removed type-checking (LI)
 * 2015-03-14: Added combine with type-checking (JR)
 */
function combine(a, b) {
  return a + b;
}

์ข‹์€ ์˜ˆ:

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋งˆ์ปค๋ฅผ ์ง€์–‘ํ•˜๋ผ

๊ทธ๊ฒƒ๋“ค์€ ์ฝ”๋“œ๋ฅผ ์ง€์ €๋ถ„ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ ์ ˆํ•œ ๋“ค์—ฌ์“ฐ๊ธฐ์™€ ํฌ๋งทํŒ…์ด ํ•จ๊ป˜ ํ•˜๋Š” ํ•จ์ˆ˜๋‚˜ ๋ณ€์ˆ˜์ด๋ฆ„์€ ์‹œ๊ฐ์ ์œผ๋กœ ์ข‹์Šต๋‹ˆ๋‹ค.

๋‚˜์œ ์˜ˆ:

////////////////////////////////////////////////////////////////////////////////
// Scope Model Instantiation
////////////////////////////////////////////////////////////////////////////////
$scope.model = {
  menu: "foo",
  nav: "bar"
};

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

์ข‹์€ ์˜ˆ:

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

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

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™

๋ฒˆ์—ญ

๋‹ค๋ฅธ ์–ธ์–ด๋กœ๋„ ์ฝ์–ด๋ณผ ์ˆ˜ ์žˆ์–ด์š”!

โฌ† ๋ชฉ์ฐจ๋กœ ์ด๋™