[1] DRY(Don't Repeat Yourself) - 반복하지마라
[2] KISS(Keep It Simple, Stupid) - 심플하고, 멍청하게 유지하자
■ Code : 10줄 짜리 코드를 1줄로 줄이기 위해 화려한 테크닉을 이용해서 가독성을 떨어뜨리기 보다는 누구나 이해할 수 있도록 심플하고 간결하게 작성하는 것이 좋다.
■ Function : 별도의 주석을 달지 않더라도 함수의 이름, 매개변수 그리고 구현된 사항의 코드를 읽었을 때 한 번에 이해할 수 있도록 한 가지의 기능을 수행하는 코드를 작성하는 것이 좋다.
■ Class : 한 가지의 챔임만 담당하는 클래스를 심플하게 만드는 것이 좋다.
■ View : 사용자에게 보여지는 UI를 담당하는 컴포넌트에는 별도의 비즈니스 로직을 포함하지 않고 최대한 심플하고 멍청하게 UI에 관련된 로직들만 담당하고 있어야 한다.
■ Service : 여러 가지 기능을 복합적으로 담당하는 하나의 큰 서비스를 만들기보다는 단 하나의 기능을 담당하는 개별적인 심플한 서비스를 만드는 것이 좋다.
[3] YAGNI(You Ain't Gonna Need It) - 너 그거 필요 없어
[4] 식별자에 의미를 부여하라.
■ 식별자 이름을 줄여쓰지 말아라.
■ boolean 타입의 변수는 접두사(prefix)를 사용해라. "isLoggedIn", hasFollowers" etc...
■ 함수는 동사를 넣어 사용해라."get, set, reset, fetch, add, remove, update, delete, etc...
[5] 기본 매개변수(default parameter)를 사용해라.
[6] 인수/인자를 3개로 제한해라. 만약 더 필요하다면 객체에 담아라.
[7] 함수의 매개변수로 boolean 타입을 사용하지 마라. 함수의 기능을 쪼개어 따로 관리해라.
[8] 조건문을 캡슐화해 함수로 사용하라.
KISS Examples
// dirty
function getFirst(array, isEven){
return array.find(x => (isEven ? x % 2 === 0 : x % 2 !== 0));
}
// refactor case#1
function getFirst(){
if(isEven){
return array.find(x => x % 2 === 0);
}else{
return array.find(x => x % 2 !== 0);
}
};
// refactor case#2
function getFirstOdd(){
return array.find(x => x % 2 === 0);
}
function getFirstEven(){
return array.find(x => x % 2 !== 0);
}
■ 3항연산자를 풀고, boolean 타입의 매개변수에 따라 true에 대한 로직, false에 대한 로직으로 분리했다.
// dirty
function updateAndPrint(rawData){
// logic#1
db.update(rowData);
// logic#2
printer.print(data);
}
// refactor case#1
function update(rawData){
db.update(rawData);
return data;
}
function print(data){
printer.print(data);
};
■ 두 가지의 기능이 있던 updateAndPrint 함수를 분리하였다.
// dirty
class UserOrderService {
userDb;
orderDb;
paymentClient;
processUserOrder(userId, orderId){
// logic#1
const user = userDb.select(/* db query */);
if(!user){
throw Error("...");
}
// logic#2
const order = orderDb.select(/* db query */);
if(!order){
throw Error("...");
}
// logic#3
paymentClient
.connect(/* url */)
.then(/* process payment */)
.catch(/* retry */);
orderDb.updateOrder(order, PAID);
}
}
// refactor case#1
class UserService {
userDb;
getUser = () => userDb.select(/* db query */);
}
class OrderService {
orderDb;
createOrder = (user, product) => {};
getOrder = (orderId) => orderDb.select(/* db query */);
updateOrder = (order) => {
orderDb.updateOrder(order, PAID);
}
}
class PaymentsService {
paymentClient;
processPayment(orderRequest){
return paymentClient
.connect(/* url */)
.then(/* process payment */)
.catch(/* retry */);
}
}
■ userOrderService 클래스를 기능별로 3개의 클래스로 분리하였다.
// dirty
class LoginViwe {
display(){
// display view..
}
onLoginButtonClick(){
fetch(/* url */)
.then(data => data.json())
.then(data => {
if(data.token){
localStorage.setItem("TOKEN", data.token);
// update UI elements
}else{
// ...
}
})
.catch(error => {
if(error.statusCode === 500){
// retry fetch?
}else if(error.statusCode === 400){
// handle an error
}
// show error message
});
}
}
// refactor case#1
class LoginView {
constructor(userPresenter){
this.userPresenter = userPresenter;
}
display(){
// display view..
}
onLoginButtonClick(){
this.userPresenter
.login()
.then(result => {
// update text UI element
// update button UI element
});
}
}
class UserPresenter {
userService;
login(){
this.userService
.login()
.then(result => {
if(result.success){
localStorage.setItem("TOKEN", result.token);
return {
displayMessage: result.message,
buttonText: "Go Home",
}
}else{
return {
displayMessage: "Unable to login",
buttonText: "Ok",
}
}
})
.catch(error => {
// Something..
});
}
}
const userPresenter = new UserPresenter();
const login = new LoginView(userPresenter);
■ View와 관련된 class에서 비즈니스 로직부분을 분리해 따로 새로운 class를 만들었다.
'클린코드 샘플(JavaScript)' 카테고리의 다른 글
비동기 처리에 대한 클린 코드 예제 (0) | 2022.11.21 |
---|---|
[1] 클린코드 Rule (0) | 2022.11.17 |
Redux - reducer(switch문) 리팩토링 (0) | 2022.11.15 |
if else, switch (feat. 객체 + 함수) (0) | 2022.11.15 |
함수형 프로그래밍, 상속 (커링, Currying) (0) | 2022.11.01 |
댓글