[JavaScript] Clean Code - 가독성 높이기

Seob·2020년 10월 3일
6

TIL

목록 보기
35/36
post-thumbnail

Introduction

A professional developer will write the code for the future self and for the “other guy” not just for the machine

위의 글을 보면, 클린 코드는 주석 없이도 스스로 설명이 되고 사람에 의해 쉽게 이해될 수 있는 코드일것이고, 확장하거나 수정하기에도 쉬운 코드를 말할 것이다.

Even bad code can function, but if the code isn’t clean, it can bring a development organization to its knees.

1. Strong type checks

==대신 === 사용하기

0 == false // true
0 === false // false
2 == "2" // true
2 === "2" // false

// example
const val = "123";

if (val === 123) {
  console.log(val);
  // it cannot not be reached
}

if (val === "123") {
  console.log(val);
  // it can be reached
}

2. Variables

변수의 용도와 의도를 드러내는 이름으로 짓기

변수의 이름만 봐도 용도름 짐작할 수 있고 검색이 가능하도록 단순하면 좋다 🤓

Bad 👎🏻

let daysSLV = 10;

let y = new Date().getFullYear();

let ok;

if (user.age > 30) {
  ok = true;
}

good 👍🏻

const MAX_AGE = 30;

let daysSinceLastVisit = 10;

let currentYear = new Date().getFullYear();

...

const isUserOlderThanAllowed = user.age > MAX_AGE;

불필요한 단어 추가하지 않기

Bad 👎🏻

let nameValue;
let theProduct;

good 👍🏻

let name;
let product;

변수의 의미를 외우거나 유추하도록 하지 않게 하기

Bad 👎🏻

const products = ["T-Shirt", "Shoes", "Watches", "Bags"];

products.forEach(p => {
  doSomething();
  doSomethingElse();
  // ...
  // ...
  // ...
  // ...
  // What is `p` for?
  register(p);
});

good 👍🏻

const products = ["T-Shirt", "Shoes", "Watches", "Bags"];

products.forEach(product => {
  doSomething();
  doSomethingElse();
  // ...
  // ...
  // ...
  register(product);
});

같은 타입의 변수에는 같은 단어 쓰기

Bad 👎🏻

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

good 👍🏻

getProduct();

3. Functions

길어도 묘사가 잘 되는 이름 사용하기

함수의 이름과 함수가 받는 인자(arguments)는 동사이거나 해당 함수의 의도와 쓰임을 잘 나타낼 수 있는 것이 좋다.

Their name should say what they do!

Bad 👎🏻

function email(user) {
  // implementation
}

good 👍🏻

function sendEmailUser(emailAddress) {
  // implementation
}

많은 수의 인자를 넣는것은 피하자
이상적으로, 한 함수에서 최대 2개까지 사용하는 것이 좋다. 인자가 적을수록, 함수를 테스트 하기도 쉬워진다.

Bad 👎🏻

function getProducts(fields, fromDate, toDate) {
  // implementation
}

good 👍🏻

function getProducts({ fields, fromDate, toDate }) {
  // implementation
}

getProducts({
  fields: ['id', 'name', 'price', 'units],
  fromDate: '2020-07-01',
  toDate: '2020-07-22'
});

conditionals 대신 default arguments 사용하기

Bad 👎🏻

function createShape(type) {
  const shapeType = type || "circle";
  // ...
}

good 👍🏻

function createShape(type = "circle") {
  // ...
}

한 함수에서 여러가지 동작 피하기

Bad 👎🏻

function notifyUsers(users) {
  users.forEach(user => {
    const userRecord = database.lookup(user);
    if (userRecord.isVerified()) {
      notify(user);
    }
  });
}

good 👍🏻

function notifyVerifiedUsers(users) {
  users.filter(isUserVerified).forEach(notify);
}

function isUserVerified(user) {
  const userRecord = database.lookup(user);
  return userRecord.isVerified();
}

default objects 지정할 때 Object.assign 사용하기

Bad 👎🏻

const shapeConfig = {
  type: "circle",
  width: 150,
  height: null
};

function createShape(config) {
  config.type = config.type || "circle";
  config.width = config.width || 300;
  config.height = config.height || 300;
}

createShape(shapeConfig);

good 👍🏻

const shapeConfig = {
  type: "circle",
  width: 150
  // Exclude the 'height' key
};

function createShape(config) {
  config = Object.assign(
    {
      type: "circle",
      width: 300,
      height: 300
    },
    config
  );
  ...
}
  
createShape(shapeConfig);

파라미터로 flags 쓰지 않기
flags를 파라미터로 사용하는 것은 함수가 해야할 일 보다 더 하고 있다는 의미!

Bad 👎🏻

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

good 👍🏻

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

function createPublicFile(name) {
  createFile(`./public/${name}`);
}

Globals 오염시키지 않기

이미 존재하는 객체를 extend해야 한다면 ES Classes와 상송성을 이용하고 native 객체의 prototy chain에 함수를 만드는걸 지양하자

Bad 👎🏻

Array.prototype.myFunction = function myFunction() {
  // implementation
};

good 👍🏻

class SuperArray extends Array {
  myFunc() {
    // implementation
  }
}

4. Conditionals

부정 조건(negative conditionals) 지양하기

Bad 👎🏻

function isPostNotPublished(post) {
  // implementation
}
if (!isPostNotPublished(post)) {
  // implementation
}

good 👍🏻

function isPostPublished(user) {
  // implementation
}
if (isPostPublished(user)) {
  // implementation
}

conditional shorthand 사용하기
사소해 보일지 모르지만, 짚고 넘어갈만 하다.

값이 boolean이거나 undefined 혹은 null값이 아니라고 확신할 때 쓰는게 좋다.

Bad 👎🏻

if (isValid === true) {
  // do something...
}
if (isValid === false) {
  // do something...
}

good 👍🏻

if (isValid) {
  // do something...
}
if (!isValid) {
  // do something...
}

꼭 필요한 상황이 아니면 조건은 지양하기
다형성(polymorphism)과 상속성(inheritance)을 이용하자 👀

Bad 👎🏻

class Dog {
  // ...
  getBreed() {
    switch (this.type) {
      case "GermanShepherd":
        return this.getStandardSize("GermanShepherd");
      case "JackRussellTerrier":
        return this.getStandardSize("JackRussellTerrier");
      case "ShibaInu":
        return this.getStandardSize("ShibaInu");
    }
  }
}

good 👍🏻

class Dog {
  // ...
}

class GermanShepherd extends Dog {
  // ...
  getStandardSize() {
    return this.standardSize;
  }
}

class JackRussellTerrier extends Dog {
  // ...
  getSize() {
    return this.standardSize;
  }
}

class ShibaInu extends Dog {
  // ...
  getSize() {
    return this.standardSize;
  }
}

5. ES Classes

ES Classes는 JavaScript의 새로운 개꿀문법이다.

이 전에 prototype과 함께 동작하던 것과 같지만 겉모습만 다르고 낡은 ES5 plain 함수보다 이것을 이용하자.

Bad 👎🏻

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

Product.prototype.getSize = function getSize() { /**/ };

const Tshirt = function(name, color) {
  if (!(this instanceof Tshirt)) {
    throw new Error("Instantiate Tshirt with `new` keyword");
  }
  Product.call(this, name);
  this.color = color;
};

Tshirt.prototype = Object.create(Product.prototype);
Tshirt.prototype.constructor = Tshirt;
Tshirt.prototype.printColor = function printColor() { /**/ };

good 👍🏻

class Product {
  
  constructor(name) {
    this.name = name;
  }
  
  getDiscount() {
    /* ... */
  }
}

class Tshirt extends Product {
  
  constructor(name, color) {
    super(name);
    this.color = color;
  }
  
  getSize() {
    /* ... */
  }
}

6. Eval 지양하기

The Eval function allows us to pass a string to the JavaScript compiler and have it execute as JavaScript

간단히 말해서, runtime에 전달되는 모든 것은 마치 design time에 추가된 것처럼 실행된다.

eval("alert('Hi');");

"Hi"라는 메세지가 든 alert창을 띄운다.

Eval function should be avoided because it’s not safe and it opens a potential threat vector for malicious programmers to exploit.

7. Lint 사용하기

JavaScript의 ES Lint는 흔하게 저지르는 실수를 바로잡아주는

8. 평소에 피해야할 것들

  • 반복적인 코드 작성하지 않기
  • 사용되지 않는 함수나 죽은 코드 남겨두지 않기

반복적인 코드는 React에서 컴포넌트로 분리해서 관리하면 좋다.
개발 도중 사용하지 않기로한 코드나 함수는 즉시 지워버리도록 하자! 🤓

참고&번역 🎈

profile
Hello, world!

0개의 댓글