JavaScript

[JavaScript] Clean Code JavaScript

반응형

3. Functions

이 게시물은 Rober C. Martin의 책 Clean Code 를 자바스크립트에 맞게 조정한 Ryan McDermott의 깃허브 리포지토리를 직접 타이핑함으로써 학습의 목적으로 작성하게 되었으며 3. Functions 의 부분에 해당합니다.


1. 함수 인자는 2개 이하가 이상적이다.

함수의 인자, 매개변수가 많아진다는 것은 그 함수에게 너무 많은 역활을 부여하고 있는 것이 아닌지 생각해 보아야 한다.
함수는 인자를 1 ~ 2 개 가지고 있는것이 가장 이상적이며 만일 3개 이상의 인자를 가져야 한다면 그러한 인자들로 구성된 하나의 객체를 함수의 인자로 넘겨주자.

함수 내부에서는 넘겨받은 객체를 ES2015/ES6 의 구조분해할당 을 통해 개별 변수에 값을 할당하여 사용할 수 있다.

이 구문은 여러가지의 장점이 존재한다.

  1. 그 함수를 보게 될 때 어떤 속성들이 사용되는지 한눈에 알 수 있다.
  2. 구조분해할당은 함수에 전달되는 객체의 기본속성을 복제하여 사이드이펙트가 일어나는 것을 방지한다.

BAD 😑

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

GOOD 😊

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

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

2. 함수는 하나의 행동만 해야한다.

함수가 1개 이상의 행동을 하게 된다면 작성, 테스트, 이해 부분에서 모두 어려워진다. 만일 하나의 함수에 하나의 역활만을 부여한다면 좀 더 고치기 쉽고 이해하기 쉬울 것이다.

BAD 😑

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

GOOD 😊

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

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

3. 함수명은 함수가 무엇을 하는지 알 수 있어야 한다.

BAD 😑

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

GOOD 😊

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

4. 함수는 단일 행동을 추상화 해야한다.

BAD 😑

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

  const statements = code.split(" ");
  const tokens = [];

  REGEXES.forEach((REGEX) => {
    statements.forEach((statement) => {
      // ...
    });
  });

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

  ast.forEach((node) => {
    // parse...
  });
}

GOOD 😊

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

5. 중복된 코드는 작성을 지양한다.

BAD 😑

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

GOOD 😊

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

    let portfolio = employee.getGithubLink();

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

    const data = {
      expectedSalary,
      experience,
      protfolio,
    };

    render(data);
  });
}

6. Object.assign을 사용하여 기본이 되는 객체를 만든다.

기본이 되는 Object를 생성하여 추가적으로 assign을 통해 targetObject를 덮어씌우는 방식으로 진행하라고 이해하였다.

BAD 😑

const menuConfig = {
  title: null,
  body: "Bar",
  buttonText: null,
  cancellable: true,
};

function createMenu(config) {
  config.title = config.title || "Foo";
  config.body = config.body || "Bar";
  config.buttonText = config.buttonText || "Baz";
  config.cancellable =
    config.cancellable !== undefined ? config.cancellable : true;
}

createMenu(menuConfig);

GOOD 😊

const menuConfig = {
  title: "Order",
  // 유저가 'body' key의 value를 정하지 않았다.
  buttonText: "Send",
  cancellable: true,
};

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

  /*
  config = {
    title: "Order",
    body: "Bar",
    buttontext: "Send",
    cancellable: true}
  */
}

createMenu(menuConfig);

7. 매개변수로 플래그를 사용하지 않는다.

플래그 변수: boolean(true, false)값을 가지는 변수
플래그를 사용한다는 것은 해당 함수가 한가지 이상의 역활을 하고 있다는 것을 뜻한다. 만일 플래그에 의해 나눠지는 코드가 존재한다면 별도의 함수로 분리하자.

BAD 😑

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

GOOD 😊

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

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

출처

clean-code-javascript / Ryan McDermott [https://github.com/ryanmcdermott/clean-code-javascript]

반응형