우리가 글을 쓸때 논리정연하게 자신의 의견을 잘 들어내며, 때로는 독자에게 보다 더 쉽고 몰입감 있게 읽힐 수 있도록 글을 깨끗하게 잘 쓸 필요가 있다.
이는 코드도 마찬가지다.
때론 보다 더 나은 성능을 위해, 때론 읽기 쉬운 코드를 위해
우린 깨끗하게 코드를 짜야한다.
그러기 위해서 몇 가지 기본적인 규칙들을 통해서 보다더 깨끗한 코드를 작성 할 수 있도록 해보자
== 대신 === 사용하기
=== 가 더 강력하다,
이렇게 써야 null 과 undefined 를 구별 할 수 있을 뿐만 아니라 타입 또한 같은지도 판별 할 수 있다.
아래 예시코드를 보자
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
}
변수의 용도와 의도를 드러내는 이름으로 짓기
변수의 이름만 봐도 용도름 짐작할 수 있고 검색이 가능하도록 단순하면 좋다
예시코드를 보자
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();
길어도 묘사가 잘 되는 이름 사용하기
줄여쓰지 말자 딱 변수명 봤을때 뭐하는 놈인지 바로 알 수 있도록 길더라도 풀네임으로 쓰자
제발
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
}
}
부정 조건(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;
}
}
ES Classes는 JavaScript의 새로운 개꿀문법이다.
진짜 코드 깔끔해진다 꼭 쓰자
prototype 과 동작원리는 비슷하다
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() {
/* ... */
}
}
클린코드를 쓸 수 밖에 없게 만들어주는 고오급 도구
처음 쓸땐 많이 불편하겠지만 익숙해지면 깨끗해지는 코드를 볼 수 있을 것이다.