๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ‘‹/์„œ์  ๐Ÿ“š

[Refactoring] Chapter 01. Refactoring : A first_example (๋ฆฌํŒฉํ„ฐ๋ง: ์ฒซ ๋ฒˆ์งธ ์˜ˆ์‹œ)

๋งˆํ‹ด ํŒŒ์šธ๋Ÿฌ(Martin Fowler)์˜ ์ €์„œ "๋ฆฌํŒฉํ† ๋ง 2ํŒ: ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ฐœ์„ ํ•˜์—ฌ ํšจ์œจ์ ์ธ ๋ฆฌํŒฉํ„ฐ๋ง ๊ตฌํ˜„ํ•˜๊ธฐ"๋ฅผ ์ฝ๊ณ  ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. (์ฑ…์— ๋‚˜์˜จ javascript ์˜ˆ์‹œ๋ฅผ typescript๋กœ ๋ณ€ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.)

Chapter 01 ๋ฆฌํŒฉํ„ฐ๋ง: ์ฒซ ๋ฒˆ์งธ ์˜ˆ์‹œ

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

[์š”์•ฝ]

  1. ๋ฐ˜๋ณต๋ฌธ ์ชผ๊ฐœ๊ธฐ : ๋ณ€์ˆ˜ ๊ฐ’์„ ๋ˆ„์ ์‹œํ‚ค๋Š” ๋ถ€๋ถ„์„ ๋ถ„๋ฆฌํ•œ๋‹ค.
  2. ๋ฌธ์žฅ ์Šฌ๋ผ์ด๋“œ ํ•˜๊ธฐ : ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™” ๋ฌธ์žฅ์„ ๋ณ€์ˆ˜ ๊ฐ’ ๋ˆ„์  ์ฝ”๋“œ ๋ฐ”๋กœ ์•ž์œผ๋กœ ์˜ฎ๊ธด๋‹ค.
  3. ํ•จ์ˆ˜ ์ถ”์ถœํ•˜๊ธฐ : ์ ๋ฆฝ ํฌ์ธํŠธ ๊ณ„์‚ฐ ๋ถ€๋ถ„์„ ๋ณ„๋„ ํ•จ์ˆ˜๋กœ ์ถ”์ถœํ•œ๋‹ค.
  4. ๋ณ€์ˆ˜ ์ธ๋ผ์ธํ•˜๊ธฐ : ์ถ”์ถœํ•œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.

[๋ฆฌํŒฉํ† ๋ง ์ „]

import { I_PLAYS } from "../../interfaces/play";
import { I_INVOICES } from "../../interfaces/invoice";

function Statement(invoice: I_INVOICES, plays: I_PLAYS): string {
  let totalAmount: number = 0;
  let volumeCredits: number = 0;
  let result: string = `์ฒญ๊ตฌ ๋‚ด์—ญ (๊ณ ๊ฐ๋ช…: ${invoice.customer})\n`;
  const format = new Intl.NumberFormat("es-US", {
    style: "currency",
    currency: "USD",
    minimumFractionDigits: 2,
  }).format;

  for (let perf of invoice.performances) {
    const play = plays[perf.playID];
    let thisAmount = 0;

    switch (play.type) {
      case "tragedy": // ๋น„๊ทน
        thisAmount = 40000;
        if (perf.audience > 30) {
          thisAmount += 1000 * (perf.audience - 30);
        }
        break;
      case "comedy": // ํฌ๊ทน
        thisAmount = 30000;
        if (perf.audience > 20) {
          thisAmount += 10000 + 500 * (perf.audience - 20);
        }
        thisAmount += 300 * perf.audience;
        break;
      default:
        throw new Error(`์•Œ ์ˆ˜ ์—†๋Š” ์žฅ๋ฅด : ${play.type}`);
    }

    //ํฌ์ธํŠธ๋ฅผ ์ ๋ฆฝํ•œ๋‹ค.
    volumeCredits += Math.max(perf.audience - 30, 0);
    if (play.type === "comedy") volumeCredits += Math.floor(perf.audience / 5);

    //์ฒญ๊ตฌ ๋‚ด์—ญ์„ ์ถœ๋ ฅํ•œ๋‹ค.
    result += `  ${play.name} : ${format(thisAmount / 100)} (${
      perf.audience
    }์„)\n`;
    totalAmount += thisAmount;
  }
  result += `์ด์•ก : ${format(totalAmount / 100)}\n`;
  result += `์ ๋ฆฝ ํฌ์ธํŠธ : ${volumeCredits}์ \n`;
  return result;
}

export { Statement };

[๋ฆฌํŒฉํ† ๋ง ํ›„]

import { I_PLAY, I_PLAYS } from "../../interfaces/play";
import { I_INVOICE_PLAY, I_INVOICES } from "../../interfaces/invoice";

function Statement(invoice: I_INVOICES, plays: I_PLAYS): string {
  function AmountFor(perf: I_INVOICE_PLAY, play: I_PLAY): number {
    // ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๋ณ€์ˆ˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ
    let thisAmount = 0; // ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ์ฝ”๋“œ

    switch (play.type) {
      case "tragedy": // ๋น„๊ทน
        thisAmount = 40000;
        if (perf.audience > 30) {
          thisAmount += 1000 * (perf.audience - 30);
        }
        break;
      case "comedy": // ํฌ๊ทน
        thisAmount = 30000;
        if (perf.audience > 20) {
          thisAmount += 10000 + 500 * (perf.audience - 20);
        }
        thisAmount += 300 * perf.audience;
        break;
      default:
        throw new Error(`์•Œ ์ˆ˜ ์—†๋Š” ์žฅ๋ฅด : ${play.type}`);
    }

    return thisAmount; // ํ•จ์ˆ˜ ์•ˆ์—์„œ ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” ๋ณ€์ˆ˜ ๋ฐ˜ํ™˜
  }

  let totalAmount: number = 0;
  let volumeCredits: number = 0;
  let result: string = `์ฒญ๊ตฌ ๋‚ด์—ญ (๊ณ ๊ฐ๋ช…: ${invoice.customer})\n`;
  const format = new Intl.NumberFormat("es-US", {
    style: "currency",
    currency: "USD",
    minimumFractionDigits: 2,
  }).format;

  for (let perf of invoice.performances) {
    const play: I_PLAY = plays[perf.playID];
    let thisAmount: number = AmountFor(perf, play);

    volumeCredits += Math.max(perf.audience - 30, 0);
    if (play.type === "comedy") volumeCredits += Math.floor(perf.audience / 5);

    result += `  ${play.name} : ${format(thisAmount / 100)} (${
      perf.audience
    }์„)\n`;
    totalAmount += thisAmount;
  }
  result += `์ด์•ก : ${format(totalAmount / 100)}\n`;
  result += `์ ๋ฆฝ ํฌ์ธํŠธ : ${volumeCredits}์ \n`;
  return result;
}

export { Statement };
LIST