“클린코드는 코드를 처음 보는 사람도 동작을 직관적으로 파악할 수 있도록 하는 것을 목표로 합니다. 여기서 코드를 처음 보는 사람은 우리 팀원들, 유지 보수를 할 후임자들, 오픈소스나 API 사용자, 그리고 3달 뒤의 자기 자신이 있습니다.
우리는 코드를 읽는 것이 아니라, 해석합니다. 가독성 확보는 코드 해석에 드는 비용을 줄이는 작업입니다.
심지어 우리는 코드를 몇 번이나 반복해서 읽습니다. 클린코드에서는 코드를 짜는 것과 읽는 것의 비중이 1:10 정도라고 이야기합니다. 조금 과장하자면 가독성 확보는 전체 코딩 업무의 90%에 대한 효율화 작업이라고 할 수 있겠습니다.”
[출처] [네이버클라우드 개발자 스토리] 좋은 코드란 무엇일까?🤔 #클린코드 이야기|작성자 NAVER Cloud Platform
현업에서 개발을 하다보면 "시간에 쫒겨서" "기획이 자주 바뀌어서" "기능이 추가돼서"
"동료가 내 코드를 건드려서" 등등 많은 이유로 코드가 더티해 지기 마련입니다,
저 또한 그렇습니다.
처음 코드를 작성할 때의 마음은 어디가고 "바빠 죽겠는데 나중에 리팩토링 해야지"하고 넘기는 경우도 더러 있습니다.
사실 바쁘다는 핑계일 뿐이고 클린코드 작성이 아직 습관화 되지 못한 탓이겠죠.
우리가 작성하는 클린 코드는 가독성을 높여주고 유지보수를 유연하게 해주며
작은 실수로 생기는 오류들을 최소화 시켜줍니다.
미래의 나를 위해서, 옆자리 동료를 위해서, 훌륭한 커뮤니케이션을 위해서 클린코드 작성을 시작해 봅시다!!
Bad 👎🏻
const yyyymmdstr = moment().format('YYYY/MM/DD');
good 👍🏻
const currentDate = moment().format('YYYY/MM/DD');
Bad 👎🏻
let nameValue;
let clientData;
good 👍🏻
let name;
let client;
Bad 👎🏻
Array.forEach( p => {
doSomting1();
doSomting2();
});
good 👍🏻
Array.forEach( product => {
doSomting1();
doSomting2();
});
Bad 👎🏻
setTimeout(function, 86400000);
good 👍🏻
const MILLISECONDS_IN_A_DAY = 86400000;
setTimeout(function, MILLISECONDS_IN_A_DAY);
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();
}
Bad 👎🏻
function createMenu(title, body, buttonText, cancellable) {
///
}
good 👍🏻
function createMenu({ title,body, buttonText, cancellable }) {
///
}
createMenu({
title: 'userInfomation',
body: 'Bar',
buttonText: 'submit',
cancellable: true,
})
Bad 👎🏻
function AddToDate(date, month) {
// ...
}
const date = new Date();
// 뭘 추가하는 건지 이름만 보고 알아내기 힘듭니다.
AddToDate(date, 1);
good 👍🏻
function AddMonthToDate(date, month) {
// ...
}
const date = new Date();
AddMonthToDate(date, 1);
Bad 👎🏻
function drawDeveloperList(developers) {
const data = new Object();
users.forEach( developer => {
const expectedSalary = developer.calculateExpectedSalary();
const experience = developer.getExperience();
const githubLink = developer.getGithubLink();
const data = {
expectedSalary,
experience,
};
});
return data;
}
function drawManagerList(managers) {
const data = new Object();
users.forEach( manager => {
const expectedSalary = manager.calculateExpectedSalary();
const experience = manager.getExperience();
const portfolio = manager.getMBAProjects();
const data = {
expectedSalary,
experience,
};
});
return data;
}
good 👍🏻
function drawEmployeeList(employees) {
const data = new Object();
users.forEach( employees => {
const expectedSalary = employees .calculateExpectedSalary();
const experience = employees .getExperience();
//다른 부분만 찾아서 로직을 나눠줍니다.
let portfolio = employee.getGithubLink();
if (employee.type === 'manager') {
portfolio = employee.getMBAProjects();
}
const data = {
expectedSalary,
experience,
};
});
return data;
}
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}`);
}
Bad 👎🏻
let name = 'Didier Drogba';
function splitIntoFirstAndLastName() {
name = name.split(' ');
}
//전역 변수를 참조했기 때문에 이제 name은 배열이 됩니다.
//name을 사용하는 또 다른 함수가 있다면 프로그램이 망가집니다.
splitIntoFirstAndLastName();
console.log(name); //['Didier', 'Drogba']
good 👍🏻
function splitIntoFirstAndLastName(name) {
return name.split(' ');
}
//전역 변수는 변경시키지 않고
const name = 'Didier Drogba';
//새로운 변수에 값을 참조합니다.
const newName = splitIntoFirstAndLastName(name);
console.log(name); // 'Didier Drogba';
console.log(newName); // ['Didier', 'Drogba'];
Bad 👎🏻
let user = { name: 'Drogba', age: 32 };
function increaseAge(user) {
user.age = user.age + 1;
return user;
}
good 👍🏻
let user = { name: 'Drogba', age: 32 };
function increaseAge(user) {
//Spread Operater 새로운 객체로 결과 값을 반환
return {...user, age: user.age + 1};
}
Bad 👎🏻
//오래된 브라우저의 경우 캐시되지 않은 `list.length`를 통한
//반복문은 높은 코스트를 가졌습니다.
//그 이유는 `list.length`를 매번 계산해야만 했기 때문인데,
//최신 브라우저에서는 이것이 최적화 되었습니다.
for (let i = 0, len = list.length; i < len; i++) {
// ...
}
good 👍🏻
for (let i = 0; i < list.length; i++) {
// ...
}
Bad 👎🏻
function oldRequestModule(url) {
// ...
}
function newRequestModule(url) {
// ...
}
//const req = oldRequestModule;
const req = newRequestModule;
good 👍🏻
function newRequestModule(url) {
// ...
}
const req = newRequestModule;
Bad 👎🏻
function updateUser(user) {
if(user.point > 30) {
//Do Something
}
}
good 👍🏻
function updateUser(user) {
//조건이 맞지 않으면 빠르게 리턴
if(user.point <= 30) {
return;
}
//Do Something Here!
}
Bad 👎🏻
function isDOMNodeNotPresent(node) {
// ...
}
if (!isDOMNodeNotPresent(node)) {
// ...
}
good 👍🏻
function isDOMNodePresent(node) {
// ...
}
if (isDOMNodePresent(node)) {
// ...
}
Bad 👎🏻
if (fsm.state === 'fetching' && isEmpty(listNode)) {
// ...
}
good 👍🏻
function shouldShowSpinner(fsm, listNode) {
return fsm.state === 'fetching' && isEmpty(listNode);
}
if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}
Bad 👎🏻
let col = "score"
if (col === "score" || col === "age" || col === "mobile" || col === "email") {
// 조건에 따른 로직
}
good 👍🏻
if (["score", "age", "mobile", "email"].include(col)) {
// 조건에 따른 로직
}
Bad 👎🏻
let color = "";
if (score > 90) {
color = "blue";
} else {
color = "yellow";
}
good 👍🏻
// 삼항연산자를 사용해서 축약
let color = (score > 90) ? "blue" : "yellow"
Bad 👎🏻
if (member !== null || member !== undefined || member !== "") {
let student = member;
}
good 👍🏻
let student = member || "";