요즘 계속해서 클린 코드에 대해 고민하고 있다.
깨끗한 코드와 깨끗하지 않은 코드의 차이점이 무엇인지, 어떤 코드가 깨끗한 코드인지, 깨끗한 코드를 구현하려면 어떻게 해야 하는지 등을 계속 생각하다가 이를 확립하기 위해 CleanCode 책을 구매했다.
CleanCode를 읽고 보기에 주요한 내용을 간단히 정리하고 개인적인 생각을 작성할 계획이다.
1장. 깨끗한 코드
Cleancode의 1장. 깨끗한 코드에선 좋은 코드를 작성해야 하는 이유, 나쁜 코드를 작성했을 때 문제점, 깨끗한 코드의 정의 등을 다룬다.
나쁜 코드
나쁜 코드란 무엇일까?
CleanCode에선 나쁜 코드를 여러 비유에 빗대는데, 그중 가장 인상 깊었던 것은 '돌아가는 쓰레기'다.
나중에 정리하겠다고 다짐하지만 그 나중은 오지 않는다는 말(르블랑의 법칙)과 함께 처음 코드를 구현할 때 깨끗한 코드를 작성하라고 이야기한다.
나쁜 코드를 작성할 경우 시간이 지남에 따라 걷잡을 수 없이 생산성이 떨어지게 되는데, 그럼에도 나쁜 코드를 작성할 수밖에 없는 악순환의 굴레에 빠져 생산성이 0에 수렴하게 된다는 내용과 함께 깨끗한 코드의 이점을 이야기한다.
여기서 말하는 깨끗한 코드의 이점은 구현에 필요한 비용을 절감하는 방법이며 전문가로서 살아남을 수 있다는 것이다.
프로그래머의 태도
깨끗한 코드를 유지하는 것은 필수이기에 이를 위해 프로그래머가 노력해야 함을 이야기한다.
기존의 좋은 코드가 시간이 촉박하다는 이유, 요구사항 방향이 변했다는 이유 등으로 결국 나쁜 코드로 변했다면 그것은 다른 부서의 잘못이 아니라 프로그래머의 잘못이라는 것이다.
코드를 구현하고 관리하는 것은 프로그래머의 역할이므로 이를 다른 부서에게 책임을 넘기지 말아야 하며, 좋은 코드를 사수할 수 있도록 노력해야 한다고 주장한다.
기한을 맞추기 위해 나쁜 코드를 만들 수밖에 없는 상황에 대해 '그들은 빨리 가려고 시간을 들이지 않는다.'라고 이야기한다. 즉, 나쁜 코드를 만드는 것은 기한을 맞추는 방법이 아니라는 것으로 오히려 속도가 낮아지며, 빨리 가는 방법은 언제나 코드를 깨끗하게 유지하는 습관이라고 주장한다.
깨끗한 코드
깨끗한 코드의 명확한 정의가 없기에 여러 노련한 프로그래머의 의견을 말한다.
효율적인 코드
우아한 코드
단순한 코드
직접적인 코드
읽기 쉬운 코드
중복이 없는 코드
짐작한 대로 기능하는 코드
코드는 다른 사람에게 보여주는 것이며 이때 '소통'을 잘하기 위해 책임감을 가져야 한다는 것을 강조한다.
보이스카우트 규칙
보이스카우트 규칙은 다음과 같다.
'캠프장은 처음 왔을 때보다 더 깨끗하게 해 놓고 떠나라'
코드에 빗대어 보면 기존 코드를 읽는 일이 잦으므로 그때마다 해당 코드를 조금이나마 개선하라는 것이다.
이 활동을 한다면 시간이 지남에 따라 코드는 점차 깨끗해진다.
느낀 점
1장을 읽음으로써 가장 크게 와닿은 것은 '나쁜 코드의 문제점'이다.
내가 팀원의 일원으로서 나쁜 코드를 만들고 있었다면 이는 고스란히 팀원에게 피해를 끼치는 것이며 이후의 다른 사람들에게도 악영향을 미친다는 것을 확실히 알 수 있었다.
한편 깨끗한 코드에 대해 나름대로 생각을 정리할 수 있었는데, 결국 가장 중요한 점은 다른 사람이 보았을 때 동작이 명확히 보여야 한다는 것이다. 그러기 위해 코드는 단순하고 직접적이어야 하며 더 이상 손을 댈 필요가 없어야 한다.
깨끗한 코드를 만들어야 하는 이유, 필요성을 느꼈으니 이후의 내용을 학습하면서 깨끗한 코드를 구현하기 위해 노력하겠다.
2장. 의미 있는 이름
Cleancode의 2장. 의미 있는 이름에선 코드를 구현하면서 짓는 수많은 이름을 잘 짓기 위해 지켜야 할 규칙을 설명한다.
의도를 분명하게 밝혀라
좋은 이름을 지을 때 소모되는 시간이 있지만, 이보다 좋은 이름을 지음으로써 절약하는 시간이 훨씬 길다고 주장한다.
해당 변수(혹은 메서드, 클래스 등)의 존재 이유, 수행 기능, 사용 방법을 드러내는 이름을 부여한다면 의도를 분명히 밝힐 수 있으며 숫자 상수나 보편적인 이름 활용을 지양하고 맥락을 명시적으로 알 수 있는 이름을 활용해야 한다고 이야기한다.
아래는 책에 나온 코드로, 동일한 동작을 하더라도 이름에 따라 명확성이 달라진다는 것을 증명한다.
// 기능이 불명확한 코드
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for(int[] x : theList)
if(x[0] == 4)
list1.add(x);
return list1;
}
//기능이 명확한 코드
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
for(int[] cell : gameBoard)
if(cell[STATUS_VALUE == FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
}
//기능이 더욱 명확한 코드
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for(Cell cell : gameBoard)
if(cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
그릇된 정보를 피하라
잘못된 정보 전달을 야기할 수 있는 이름 활용을 피하라는 의미이다.
소문자 l, 대문자 O로 인해 확실한 구분이 되지 않는 것을 간단한 예로 들었다.
의미 있게 구분하라
의미 없는 숫자(ex- a1, a2, ...)나 불용어를 활용하는 것을 피하고 정확한 의미를 가지고 있는 단어를 사용하라는 의미이다. 다른 예로 Info, Data 등의 사용도 지양하기를 권하는데, customerInfo - customer, ProductData - Product와 같이 읽는 사람이 차이를 알 수 없기 때문이다.
발음하기 쉬운 이름을 사용하라
아래는 책에 나온 코드이다. 무엇을 말하고자 하는 것인지 바로 알 수 있다.
//발음하기 어려운 이름
class DataRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
}
//발음하기 쉬운 이름
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId = "102";
}
검색하기 쉬운 이름을 사용하라
한 문자만 사용하는 경우, 상수를 사용하는 경우는 눈에 잘 들어오지 않고 역할을 제대로 알 수 없기에 검색할 수 있을 만큼 명확한 이름을 사용하라는 의미이다.
아래는 책에 나온 코드이다.
//검색하기 어려운 이름
for (int j=0; j<34; j++) {
s += (t[j]*4)/5;
}
//검색하기 쉬운 이름
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j=0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
인코딩을 피하라
헝가리안 표기법, 변수 접두어 등을 사용하지 말라는 의미로, 이러한 방식은 발음도 더 어려워지고 오타 가능성이 있으며 개발자에게 부담이 되기 때문이라고 주장한다.
물론 Interface와 같이 인코딩이 필요할 때가 있는데, 정보를 과하게 제공하지는 않는지, 주의를 흩트리지는 않는지를 생각해야 한다고 한다.
ex- ShapeFactoryImp가 IShapeFactory보다 좋다.
자신의 기억력을 자랑하지 마라
독자가 코드를 읽을 때 이름을 자신이 아는 이름으로 변환해야 한다면 바람직하지 못한 이름이라고 말한다.
클래스 & 객체 이름은 명사 / 명사구, 메서드 이름은 동사 / 동사구가 적합하며 정적 팩토리 메서르 사용을 권장한다.
기발한 이름은 피하라
유머, 농담보다 명료한 이름을 선택하라는 의미이다.
한 개념에 한 단어를 사용하라
get, fetch 등 유사한 의미를 가지고 있는 단어를 혼용하지 말고 한 개념에 한 단어를 사용하라는 것이다.
ex- controller, manage, driver
말장난을 하지 마라
한 단어를 두 목적으로 사용하지 말라는 주장으로, 위와 같이 한 개념에 한 단어를 사용하라는 것이다.
예를 들어 서로 다른 피연산자를 더할 때와 배열에 새로운 값을 추가할 때 둘 다 add를 사용하는 것은 잘못된 것이다.
둘 다 더한다는 말은 같으나, 기능이 다르기 때문이다.
해법 영역에서 가져온 이름을 사용하라
코드를 읽는 사람도 프로그래머이므로 알고리즘 이름, 전산 용어 등을 사용하라는 의미이다.
문제 영역에서 가져온 이름을 사용하라
적절한 용어가 없다면 문제 영역에서 사용되는 이름을 그대로 사용하라는 의미이다.
코드를 읽는 프로그래머는 그 단어를 해당 분야 전문가에게 질문할 것이라는 주장이다.
의미 있는 맥락을 추가하라
만약 이름이 의미를 전달하는 데 명확하지 않다면 맥락을 추가해 분명하게 하라는 의미이다.
독자가 맥락을 유추하지 않고 곧바로 알 수 있도록 하는 것이 중요하다.
불필요한 맥락을 없애라
굳이 없어도 되는 맥락은 의미 없이 긴 이름을 야기하므로 이를 없애라는 의미이다.
긴 이름보다 짧은 이름이 일반적으로 더 좋다.
느낀 점
클린 코드에 대해 고민하기 시작하면서 이름을 줄여 쓰지 않고 역할에 맞게 작성하도록 노력했다. 이번 장을 통해 개선 방향을 잡았고 이 틀에서 벗어나지 않도록 노력해야겠다.
추가로 영어의 중요성을 느꼈는데, 확실한 의미를 담은 이름을 위해 다양한 영단어를 알고 있어야겠다고 생각했다. 확실히 프로그래밍에 대해 공부할수록 점점 영어의 중요성이 부각되는 듯하다.
'OOP & CleanCode' 카테고리의 다른 글
CleanCode - 6. 객체와 자료 구조 (1) | 2024.11.30 |
---|---|
CleanCode - 5. 형식 맞추기 (1) | 2024.01.11 |
CleanCode - 4. 주석 (1) | 2024.01.02 |
CleanCode - 3. 함수 (1) | 2023.12.23 |