본문 바로가기
Javascript

Javascript Clean Code에 관하여

by F.E.D 2021. 4. 11.

자바스크립트 클린코드에 대한 관점들이 많이 있습니다.

 

다른사람들을 위한 코드를 작성하는 것이 좋고, 또 그 자체로도 본인에게도 매우 도움이 되기 때문에 어떻게 보면, 클린코드는 좋은 개발자의 덕목에 필수불가결하다고 할 수 있습니다.

 

여전히 어지럽고 난해한 코드를 작성하는 법, 아무도 알아보지 못하게 코드를 작성하는 법에 대한 책들이 있긴 하지만, 저는 그런 관점에 대해서는 자기 자신이 자신이 없기 때문이라는 생각만 듭니다.

 

이 글에서는 자바스크립트 관점에서만 다룹니다.

 

1. 강력한 타입 체크

== 대신에 ===를 사용하세요.

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

// 예시
const val = "123";

if (val === 123) {
  console.log(val);
  // 콘솔이 찍히지 않습니다.
}

if (val === "123") {
  console.log(val);
  // 콘솔이 찍힙니다.
}

2. 변수 이름

변수 이름을 잘 지으세요.

 

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();
  .
  .
  .
  // p가 뭐야?
  register(p);
});

GOOD

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

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

 

문맥을 불필요하게 추가하지마세요.

BAD

const product = {
  productId: 1,
  productName: "T-Shirt",
  productPrice: 8.99,
  productUnits: 12
};

...

product.productName;

불필요하게 product가 prefix로 모두 들어간 모습입니다.

 

 

GOOD

const product = {
  id: 1,
  name: "T-Shirt",
  price: 8.99,
  units: 12
};

...

product.name;

동일한 유형의 변수에 동일한 어휘 사용하기

BAD

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

GOOD

getProduct();

3. 함수

길고 설명이 충분히 되는 함수이름을 사용하세요.

특정 동작을 나타내는 것을 고려할 때 함수 이름은 인수의 의도뿐만 아니라 그 뒤에있는 의도를 완전히 드러내는 동사 또는 구문이어야합니다.

BAD

function email(user) {
  // 실행
}

GOOD

function sendEmailUser(emailAddress) {
  // 실행
}

긴 인수를 피하세요.

인수가 적을수록 함수를 테스트하기가 더 쉽습니다.

BAD

function getProducts(fields, fromDate, toDate) {
  // 실행
}

GOOD

function getProducts({ fields, fromDate, toDate }) {
  // 실행
}

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

브라우저 지원 여부에 따라 조건 인수 대신에 기본 타입 인수를 사용하세요.

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

 

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
  // height를 제외시켜둔 상태
};

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

플래그는 함수가해야하는 것보다 더 많은 일을하고 있음을 알려주기 때문에 매개 변수로 사용하지 마십시오.

 

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

 

기존 개체를 확장해야하는 경우 네이티브 개체의 프로토 타입 체인에 함수를 만드는 대신 ES 클래스 및 상속을 사용하십시오.

 

 

BAD

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

 

GOOD

class SuperArray extends Array {
  myFunc() {
    // 실행
  }
}

 

4. 조건문

 

부정 조건문을 피하세요.

 

BAD

function isPostNotPublished(post) {
  // 실행
}
if (!isPostNotPublished(post)) {
  // 실행
}

 

GOOD

function isPostPublished(user) {
  // 실행
}
if (isPostPublished(user)) {
  // 실행
}

 

 

단축 속성을 사용하세요.

 

BAD

if (isValid === true) {
  // 실행
}
if (isValid === false) {
  // 실행
}

 

GOOD

if (isValid) {
  // 실행
}
if (!isValid) {
  // 실행
}

 

조건문을 피하고 다형성과 상속을 사용하세요.

 

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 클래스 사용

 

이제는 조금 더 클래스 사용을 선호해야할 필요가 있습니다.

 

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

 

메소드 체이닝을 사용하세요.

코드가 덜 장황 해집니다. 클래스에서 모든 함수의 끝에 이것을 반환하고 추가 클래스 메서드를 연결할 수 있습니다.

 

BAD

class Product {
  
  constructor(name) {
    this.name = name;
  }
  
  setPrice(price) {
    this.price = price;
  }
  
  setUnits(units) {
    this.units = units;
  }
  
  save() {
    console.log(this.name, this.price, this.units);
  }
}

const product = new Product("Bag");

product.setPrice(23.99);
product.setUnits(12);
product.save();

 

GOOD

class Product {
  
  constructor(name) {
    this.name = name;
  }
  
  setName(name) {
    this.name = name;
    // 체이닝을 위해서 리턴
    return this;
  }
  
  setPrice(price) {
    this.price = price;
    // 체이닝을 위해서 리턴
    return this;
  }
  
  save() {
    console.log(this.name, this.price, this.units);
    // 체이닝을 위해서 리턴
    return this;
  }
}

const product = new Product("T-Shirt")
    .setName("Jeans")
    .setAge(31.99)
    .save();

6. Eval 사용 금지

Eval 함수를 사용하면 JavaScript 컴파일러에 문자열을 전달하고 JavaScript로 실행할 수 있습니다..

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

Eval 기능은 안전하지 않고 악의적인 프로그래머가 악용할 수있는 잠재적인 위협 벡터를 열어주므로 피해야합니다.

 

7. JS Lint를 사용하세요.

JSLint는 JavaScript 코드의 일반적인 문제를 식별하는 데 도움이되는 훌륭한 도구입니다.

예를 들어 Visual Studio Code에는 컴파일 타임 (또는 수동)에서 오류를 확인할 수있는 JSLint용 추가 기능이 있습니다.

이렇게하면 코드가 더 깔끔해지며 성가신 버그가 프로덕션에 표시되는 것을 방지하는 데 도움이됩니다.

 

8. 일반화를 피하세요.

일반적으로 반복하지 않도록 자기 자신이 최선을 다해야 합니다.

중복 코드를 최소화하고, 함수 및 데드 코드와 같은 나쁜 코드를 작성하지 않기 위해 꼼꼼하게 노력해야 할 것입니다.

주석처리하지말고 데드코드 같은경우 삭제를 해버리세요.

 

감사합니다.

 

 

출처 : javascript.plainenglish.io/javascript-clean-code-best-practices-461c24c53cae

 

 

 

 

댓글