클린 코드란 효율성이 있고,가독성이 좋은 다른 사람이 고치기 쉬운 코드를 의미합니다.
주의깊게 짠 코드로 중복 피하기, 한 기능만 수행, 제대로 표현, 작게 추상화 등이 잘 적용된 코드를 클린 코드라고 합니다.
의미 있는 이름을 사용
의도가 분명한 이름 -> 가독성 올라감
다음 두 코드를 비교해보겠습니다.
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[]> flaggedCell = new ArrayList<int[]>();
for(int[] cell : gameBoard)
if(x[0] == 4) flaggedCell.add(cell);
return flaggedCell;
}
두 코드는 변수와 함수의 이름만 다를 뿐 완벽하게 같은 구조입니다.
하지만 첫번째 코드에서는 각 요소가 뭘 의미하는지 알 수 없습니다. 반면 아래의 코드는 flag된 셀의 정보를 얻어오는 코드임을 명확하게 알 수 있습니다. 이처럼 이름만 잘 지어줘도 코드의 가독성이 올라가며 코드를 처음보는 사람도 쉽게 이해할 수 있는 코드가 됩니다.
위의 코드에서 int[] 가 의미하는 대신 간단한 클래스인 Cell을 만들어 관리한다면 정확히 어떤 일을 하는 코드인지 이해가 쉬워집니다.
public List<int[] getFlaggedCells(){
List<Cell> flaggedCell = new ArrayList<Cell>();
for(Cell cell : gameBoard)
if(cell.isFlagged()) flaggedCell.add(cell);
return flaggedCell;
}
그릇된 정보를 담으면 안된다.
ex) Map을 사용해서 회원 목록을 저장한 경우 memberList라고 쓰는 경우에 다른 사람은 List 자료형을 사용한 것으로 오해할 수 있습니다. 이런 경우 memberMap과 같은 이름을 지어줘야합니다.
또한 account, accounts 등과 같이 서로 비슷한 이름을 사용하면 가독성이 떨어지기 때문에 사용하지않도록 주의해야합니다.
XYZControllerForEfficientHandlingOfString이라는 이름을 사용하고 조금 떨어진 곳에 XYZControllerForEfficientStorageOfString이라는 이름을 사용하면 가독성이 떨어집니다.
소문자 l과 대문자 O를 조심한다. lll1l1 O0OO0 를 언뜻 봤을 때 바로 l,1 그리고 0,O를 구분해내는 것은 쉬운 일이 아니다. 오죽하면 이들이 구분이 잘되는 폰트까지 나왔을까요.
의미 있는 구분
public static void copyCharArray(char a1[],char a2[]){
for(int i = 0;i<a1.length;i++){
a2[i] = a1[i];
}
}
public static void copyCharArray(char[] source,char[] destination){
for(int i = 0;i<source.length;i++){
destination[i] = source[i];
}
}
위의 두 코드는 a1,a2를 source와 destination으로 바꾼 차이 밖에 없는 코드입니다.
이름만 바꿨을 뿐인데 어떤 내용인지 훨씬 이해하기 쉬워졌습니다.
또한 읽는 사람이 차이를 알 수 있도록 이름을 구분해줘야합니다.
ex) moneyAmount, money는 구분이 안되고, customerInfo와 customer는 구분이 안됩니다.
발음하기 쉬운 이름을 사용
생성된 날짜를 저장하는 변수를 genymdhms(generate year-month-day-hour-minute-second)라고 해놓으면 코드를 놓고서 토론이나 리뷰를 진행할 때 큰 어려움이 생깁니다.
검색하기 쉬운 이름을 사용
문자 하나를 사용하는 이름과 상수는텍스트 코드에서 쉽게 눈에 띄지않습니다. 학생당 들을 수 있는 강의 수가 최대 7개인 경우를 예시로 들어보겠습니다.
MAX_CLASSES_PER_STUDENT로 해놓는다면 눈에 잘 들어오고 이후에 코드 내에서 grep으로 찾기도 쉽습니다.
반면, 7로 해놓은 경우 코드 내에서 다른 의미로 7이 쓰인 경우가 있으면 그 경우와 구분하기도 어렵습니다.
또한 최대 강의수가 7개에서 10개로 변경되는 경우 MAX_CLASSES_PER_STUDENT을 사용하는 경우는 값을 7에서 10으로만 바꿔주면 됩니다. 하지만 7로 해놓은 경우는 해당하는 항목을 전부 찾아서 10으로 바꿔줘야합니다.
가독성 뿐만 아니라 유지보수 측면에서도 검색하기 쉬운 이름을 사용하면 큰 이점을 가져올 수 있습니다.
클래스 이름은 명사나 명사구로 메서드 이름은 동사나 동사구로
함수 설계
작게 만들어라
if문 / else문/ while문 등에 들어가는 블록은 1~2줄 정도가 적당합니다. 그 방법은 블록 안에서 함수를 호출하도록 설계하는 것이 중요합니다. 이런 방식을 사용하면 함수의 이름을 적절하게 짓는다면 코드를 이해하기도 쉬워집니다.
이 말은 중첩 구조가 생길만큼 함수가 커져서는 안된다는 의미로 들여쓰기 수준은 1단이나 2단을 넘어셔면 안됩니다.(실제 면접에서 코테 코드 리뷰를 받으면서 들었던 내용입니다.)
한 가지만 해라
“함수는 한 가지를 해야하고, 그 한 가지를 잘 해야하고, 그 한 가지만을 해야합니다.”
이 문장에서 한 가지는 과연 어떤 것을 의미할까요?
다음 예시를 먼저 확인해보겠습니다.
다음과 같은 기능을 하는 함수는 몇 가지 기능을 하는 함수일까요?
페이지가 테스트 페이지인지 판단한다.
테스트 페이지라면 설정 페이지와 해제 페이지를 넣는다.
페이지를 HTML로 렌더링한다.
세 가지라고 생각할 수 있겠지만 위의 함수는 추상화 수준이 하나입니다.
솔직히 함수가 몇 가지를 하는지 판단하는 것은 헷갈리는 일입니다. 이런 헷갈림을 최소화하기 위해서 다음 3개의 기준으로 판단하는 것이 좋습니다.
추상화 수준이 1개인지를 확인합니다. 추상화 수준에서 여러 단계로 나눠서 수행하기 위해서 하는 것이 함수를 만드는 목적 중 하나이기 때문에, 추상화 수준이 하나라면 해당 함수는 한 가지만 하는 것입니다.
함수 내에서 의미 있는 이름으로 다른 함수를 추출할 수 있다면 그 함수는 여러 작업을 하는 것입니다.
예를 들어, 2차원 배열을 탐색할 때, 배열의 범위를 벗어나는지 확인을 하는 코드가 있다면 이는 함수를 outOfBoundCheck와 같은 이름의 함수로 추출할 수 있습니다. 이렇게 함수로 추출하지않으면 2차원 배열을 탐색하는 함수는 한 가지 이상을 하는 것이됩니다.
한 함수에서 섹션이 나눠지는지 체크합니다. 여러 개로 나눠진다면 여러 작업을 한다는 증거이므로 함수 내에서 섹션이 나눠지는지를 체크해주는 것만으로도 한 가지만 하는지 확인이 가능합니다.
함수 당 추상화 수준은 하나로
한 함수 내에 추상화 수준을 섞으면 특정 표현이 근본 개념인지 세부사항인지 구분하기 어렵기 때문에 코드를 읽는 사람이 헷갈립니다.
예시를 통해서 추상화 수준에 대한 설명을 해보겠습니다.
설정 페이지와 해제 페이지를 포함하려면, 설정 페이지를 포함하고, 테스트 페이지 내용을 포함하고, 해제 페이지를 포함한다.--(1)
설정 페이지를 포함하려면, 슈아면 슈트 설정 페이지를 포함한 후 일반 설정 페이지를 포함한다.--(2)
슈트 설정 페이지를 포함하려면, 부모 계층에서 "SuiteSetUp" 페이지를 찾아 include 문과 페이지 경로를 추가한다.--(3)
부모 계층을 검색하려면...--(4)
위의 글에서 보면 위에서 아래로 읽어내려갈 수록 추상화 수준이 낮아집니다. 위와 같은 문장의 구조로 위에서 아래로 문단을 읽어내려가듯이 코드를 구현하면 추상화 수준을 일관되게 유지하기가 쉬워집니다.
서술적인 이름을 사용하라
isTestable, includesetupAndTeardownPages, countFlaggedCell과 같이 서술적인 이름을 사용해서 읽는 사람이 어떤 기능을 하는지 예측할 수 있도록 해주는 것이 중요합니다.
함수 인수
함수에서 이상적인 인수 개수는 0개 입니다. 인수가 3개를 넘어가면 인수마다 유효한 값으로 모든 조합을 구성해 테스트하기가 상당히 부담스러워지기 때문에, 함수의 인수는 3개 이하로 하는 것이 좋습니다.
부수 효과를 일으키지마라
함수에서 한 가지만을 해야하기 때문에 부수 효과를 일으키면 안됩니다. 예를 들어서 로그인을 담당하는 함수를 구현하며 다음과 코드를 작성했다고 해보겠습니다.
public class UserValidator{
private Cryptographer cryptographer;
public boolean checkPassword(String userName, String password){
User user = UserGateway.findByName(userName);
if(user != User.NULL){
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if("Valid Password".equals(phrase)){
Session.initialize();
return true;
}
}
return false;
}
}
언뜻 보기에는 별문제가 없어보이는 함수입니다.
하지만 Session.initialize() 호출이 있는 것이 문제가 됩니다. 함수의 이름에는 세션을 초기화한다는 정보를 알 수 없습니다. 그래서 함수 이름만 보고서 함수를 호출하는 사용자가 사용자를 인증하면서 기존 세션 정보를 지워버릴 가능성이 생깁니다. 이런 부수 효과는 시간적인 결합을 초래해서 세션을 초기화해도 괜찮은 경우에만 호출이 가능합니다. 특히나 이렇게 부수적인 효과로 숨겨진 경우에는 문제를 찾기가 어렵기 때문에 함수의 이름에 세션을 초기화한다는 것을 명시해주는 것이 좋습니다.
명령과 조회를 분리해라
함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야합니다. 즉, 객체의 상태를 변경하거나 객체 정보를 반환하거나 둘 중 하나만 해야합니다.
위의 코드에서 (2)번에 해당하는 코드는 username이 SSAFY로 설정되어있는지 확인하는 코드일까요? 아니면 username을 SSAFY로 설정하는 코드일까요?
(1)번을 만든 개발자는 “set”을 동사로 의도해 attributes를 value로 세팅에 성공하면 true를 리턴하게 해놓았는데, if문 안에 있으니 형용사처럼 느껴저 username이 SSAFY라면으로 생각하게됩니다. 이런 혼란을 방지하기 위해서 (3)과 같이 명령과 조회를 분류하는 방식을 사용해야합니다.
오류 코드보다 예외를 사용해라
위의 코드에서 (1)을 보면 세팅을 하는 부분에서 try-catch문을 사용했습니다. 해당 부분을 if-else를 사용해서 구현을 해도 되지만 try-catch를 분리해서 코드를 작성한다면 원래 코드에서 오류 처리 코드를 구분할 수 있기 때문에 코드가 깔끔해집니다.
try-catch문을 사용할 때, 코드 구조에 정상 동작과 오류 처리 동작이 뒤섞이는데 Try-catch 블록을 별도의 함수로 뽑아낸다면 이런 문제점을 해결할 수 있습니다. 그 이유는 오류처리도 한 가지 작업이기 때문에, 함수가 한 가지만 해야한다는 원칙을 따르기 위해서 오류처리도 별도의 함수로 뽑아내는 것이 중요합니다.
반복하지마라
특정 조건에 따라서 데이터들을 정렬을 해야하는 경우를 생각해보겠습니다.
데이터마다 정렬하는 방식을 오름차순 정렬하는 상황인데, 어느 날 고객 데이터를 분석한 결과 고객들이 내림차순 정렬된 결과를 선호한다는 소식을 들었습니다.
이 때, 알고리즘을 하나의 함수로 만들어 놓지않고, 각각의 데이터마다 구현을 해야한다면, 어느 하나의 데이터라도 구현을 빼먹는 순간 오류가 발생합니다.
그래서 반복되는 부분은 함수로 따로 빼줘서 반복을 줄여주는 것이 중요합니다.
함수를 짜는 방법
함수를 짜는 방법은 글짓기와 같습니다. 처음에는 길고 복잡하며 중복된 부분을 신경쓰지않고 코드를 작성합니다. 그 후 코드를 점점 다듬으면서 함수를 만들고, 이름을 바꾸고, 중복을 제거해줍니다. 그 과정에서 메서드의 크기를 줄이고, 순서가 바뀌기도합니다. 또한, 클래스를 쪼개기도 합니다. 이런 과정을 거쳐서 위에서 설명한 조건들을 만족하는 코드를 작성하게됩니다.
처음부터 위의 조건을 다 만족하는 코드를 짜는 것은 거의 불가능한 일이기 때문에 차근차근 고쳐나가는 연습을 하는 것이 중요합니다.
주석
주석은 나쁜 코드를 보완하지 못합니다. 코드로 의도를 표현하는 것이 중요합니다. 주석은 코드로 의사 전달이 제대로 안된 경우를 만회하기 위해서 사용한다고 생각하는 것이 중요합니다. 코드의 내용은 최대한 코드로 표현을 하고 코드로 표현하는 것이 불가능한 경우나 주석 사용이 불가피한 경우에만 유용합니다. 그 이유는 좋은 주석이 있고 나쁜 주석이 있기 때문입니다.
좋은 주석
법적인 주석
정보를 제공하는 주석
의도를 설명하는 주석
의미를 명료하게 밝히는 주석
결과를 경고하는 주석
TODO 주석
중요성을 강조하는 주석
공개 API에서 Javadocs
나쁜 주석
이해하기 어려운 주석
다른 코드를 뒤져봐야하는 주석은 코드를 읽는 사람과 제대로 소통하지 못하는 주석입니다.
같은 이야기를 중복하는 주석
오해의 여지가 있는 주석
의무적으로 다는 주석
이력을 기록하는 주석
있으나 마나한 주석
함수나 변수로 표현할 수 있는 주석
닫는 괄호에 다는 주석
주석으로 처리한 코드
HTML 주석
전역 정보
정리
검색 가능한 이름을 사용하기 (Use a searchable name.)
함수명은 반드시 동사로. (Function name should be verbs.)
함수는 동작 하나만.
함수의 인수는 3개이하 적당. 많을 경우에는 Object로 정리해서 param 사용.
함수의 파리미터에 boolean 을 둬서 액션 2개 이상을 구현하기 보다는, 함수를 2개로 구분하는 것을 추천.
클린코드
클린 코드란?
클린 코드란 효율성이 있고,가독성이 좋은 다른 사람이 고치기 쉬운 코드를 의미합니다. 주의깊게 짠 코드로 중복 피하기, 한 기능만 수행, 제대로 표현, 작게 추상화 등이 잘 적용된 코드를 클린 코드라고 합니다.
의미 있는 이름을 사용
의도가 분명한 이름 -> 가독성 올라감
다음 두 코드를 비교해보겠습니다.
두 코드는 변수와 함수의 이름만 다를 뿐 완벽하게 같은 구조입니다. 하지만 첫번째 코드에서는 각 요소가 뭘 의미하는지 알 수 없습니다. 반면 아래의 코드는 flag된 셀의 정보를 얻어오는 코드임을 명확하게 알 수 있습니다. 이처럼 이름만 잘 지어줘도 코드의 가독성이 올라가며 코드를 처음보는 사람도 쉽게 이해할 수 있는 코드가 됩니다. 위의 코드에서 int[] 가 의미하는 대신 간단한 클래스인 Cell을 만들어 관리한다면 정확히 어떤 일을 하는 코드인지 이해가 쉬워집니다.
그릇된 정보를 담으면 안된다.
ex) Map을 사용해서 회원 목록을 저장한 경우 memberList라고 쓰는 경우에 다른 사람은 List 자료형을 사용한 것으로 오해할 수 있습니다. 이런 경우 memberMap과 같은 이름을 지어줘야합니다. 또한 account, accounts 등과 같이 서로 비슷한 이름을 사용하면 가독성이 떨어지기 때문에 사용하지않도록 주의해야합니다.
XYZControllerForEfficientHandlingOfString이라는 이름을 사용하고 조금 떨어진 곳에 XYZControllerForEfficientStorageOfString이라는 이름을 사용하면 가독성이 떨어집니다.
소문자 l과 대문자 O를 조심한다. lll1l1 O0OO0 를 언뜻 봤을 때 바로 l,1 그리고 0,O를 구분해내는 것은 쉬운 일이 아니다. 오죽하면 이들이 구분이 잘되는 폰트까지 나왔을까요.
의미 있는 구분
위의 두 코드는 a1,a2를 source와 destination으로 바꾼 차이 밖에 없는 코드입니다. 이름만 바꿨을 뿐인데 어떤 내용인지 훨씬 이해하기 쉬워졌습니다.
또한 읽는 사람이 차이를 알 수 있도록 이름을 구분해줘야합니다. ex) moneyAmount, money는 구분이 안되고, customerInfo와 customer는 구분이 안됩니다.
발음하기 쉬운 이름을 사용
생성된 날짜를 저장하는 변수를 genymdhms(generate year-month-day-hour-minute-second)라고 해놓으면 코드를 놓고서 토론이나 리뷰를 진행할 때 큰 어려움이 생깁니다.
검색하기 쉬운 이름을 사용
문자 하나를 사용하는 이름과 상수는텍스트 코드에서 쉽게 눈에 띄지않습니다. 학생당 들을 수 있는 강의 수가 최대 7개인 경우를 예시로 들어보겠습니다. MAX_CLASSES_PER_STUDENT로 해놓는다면 눈에 잘 들어오고 이후에 코드 내에서 grep으로 찾기도 쉽습니다. 반면, 7로 해놓은 경우 코드 내에서 다른 의미로 7이 쓰인 경우가 있으면 그 경우와 구분하기도 어렵습니다. 또한 최대 강의수가 7개에서 10개로 변경되는 경우 MAX_CLASSES_PER_STUDENT을 사용하는 경우는 값을 7에서 10으로만 바꿔주면 됩니다. 하지만 7로 해놓은 경우는 해당하는 항목을 전부 찾아서 10으로 바꿔줘야합니다. 가독성 뿐만 아니라 유지보수 측면에서도 검색하기 쉬운 이름을 사용하면 큰 이점을 가져올 수 있습니다.
클래스 이름은 명사나 명사구로 메서드 이름은 동사나 동사구로
함수 설계
작게 만들어라
if문 / else문/ while문 등에 들어가는 블록은 1~2줄 정도가 적당합니다. 그 방법은 블록 안에서 함수를 호출하도록 설계하는 것이 중요합니다. 이런 방식을 사용하면 함수의 이름을 적절하게 짓는다면 코드를 이해하기도 쉬워집니다. 이 말은 중첩 구조가 생길만큼 함수가 커져서는 안된다는 의미로 들여쓰기 수준은 1단이나 2단을 넘어셔면 안됩니다.(실제 면접에서 코테 코드 리뷰를 받으면서 들었던 내용입니다.)
한 가지만 해라
“함수는 한 가지를 해야하고, 그 한 가지를 잘 해야하고, 그 한 가지만을 해야합니다.” 이 문장에서 한 가지는 과연 어떤 것을 의미할까요? 다음 예시를 먼저 확인해보겠습니다. 다음과 같은 기능을 하는 함수는 몇 가지 기능을 하는 함수일까요?
함수 당 추상화 수준은 하나로
한 함수 내에 추상화 수준을 섞으면 특정 표현이 근본 개념인지 세부사항인지 구분하기 어렵기 때문에 코드를 읽는 사람이 헷갈립니다. 예시를 통해서 추상화 수준에 대한 설명을 해보겠습니다.
위의 글에서 보면 위에서 아래로 읽어내려갈 수록 추상화 수준이 낮아집니다. 위와 같은 문장의 구조로 위에서 아래로 문단을 읽어내려가듯이 코드를 구현하면 추상화 수준을 일관되게 유지하기가 쉬워집니다.
서술적인 이름을 사용하라
isTestable, includesetupAndTeardownPages, countFlaggedCell과 같이 서술적인 이름을 사용해서 읽는 사람이 어떤 기능을 하는지 예측할 수 있도록 해주는 것이 중요합니다.
함수 인수
함수에서 이상적인 인수 개수는 0개 입니다. 인수가 3개를 넘어가면 인수마다 유효한 값으로 모든 조합을 구성해 테스트하기가 상당히 부담스러워지기 때문에, 함수의 인수는 3개 이하로 하는 것이 좋습니다.
부수 효과를 일으키지마라
함수에서 한 가지만을 해야하기 때문에 부수 효과를 일으키면 안됩니다. 예를 들어서 로그인을 담당하는 함수를 구현하며 다음과 코드를 작성했다고 해보겠습니다.
언뜻 보기에는 별문제가 없어보이는 함수입니다. 하지만 Session.initialize() 호출이 있는 것이 문제가 됩니다. 함수의 이름에는 세션을 초기화한다는 정보를 알 수 없습니다. 그래서 함수 이름만 보고서 함수를 호출하는 사용자가 사용자를 인증하면서 기존 세션 정보를 지워버릴 가능성이 생깁니다. 이런 부수 효과는 시간적인 결합을 초래해서 세션을 초기화해도 괜찮은 경우에만 호출이 가능합니다. 특히나 이렇게 부수적인 효과로 숨겨진 경우에는 문제를 찾기가 어렵기 때문에 함수의 이름에 세션을 초기화한다는 것을 명시해주는 것이 좋습니다.
명령과 조회를 분리해라
함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야합니다. 즉, 객체의 상태를 변경하거나 객체 정보를 반환하거나 둘 중 하나만 해야합니다.
위의 코드에서 (2)번에 해당하는 코드는 username이 SSAFY로 설정되어있는지 확인하는 코드일까요? 아니면 username을 SSAFY로 설정하는 코드일까요? (1)번을 만든 개발자는 “set”을 동사로 의도해 attributes를 value로 세팅에 성공하면 true를 리턴하게 해놓았는데, if문 안에 있으니 형용사처럼 느껴저 username이 SSAFY라면으로 생각하게됩니다. 이런 혼란을 방지하기 위해서 (3)과 같이 명령과 조회를 분류하는 방식을 사용해야합니다.
오류 코드보다 예외를 사용해라
위의 코드에서 (1)을 보면 세팅을 하는 부분에서 try-catch문을 사용했습니다. 해당 부분을 if-else를 사용해서 구현을 해도 되지만 try-catch를 분리해서 코드를 작성한다면 원래 코드에서 오류 처리 코드를 구분할 수 있기 때문에 코드가 깔끔해집니다. try-catch문을 사용할 때, 코드 구조에 정상 동작과 오류 처리 동작이 뒤섞이는데 Try-catch 블록을 별도의 함수로 뽑아낸다면 이런 문제점을 해결할 수 있습니다. 그 이유는 오류처리도 한 가지 작업이기 때문에, 함수가 한 가지만 해야한다는 원칙을 따르기 위해서 오류처리도 별도의 함수로 뽑아내는 것이 중요합니다.
반복하지마라
특정 조건에 따라서 데이터들을 정렬을 해야하는 경우를 생각해보겠습니다. 데이터마다 정렬하는 방식을 오름차순 정렬하는 상황인데, 어느 날 고객 데이터를 분석한 결과 고객들이 내림차순 정렬된 결과를 선호한다는 소식을 들었습니다. 이 때, 알고리즘을 하나의 함수로 만들어 놓지않고, 각각의 데이터마다 구현을 해야한다면, 어느 하나의 데이터라도 구현을 빼먹는 순간 오류가 발생합니다. 그래서 반복되는 부분은 함수로 따로 빼줘서 반복을 줄여주는 것이 중요합니다.
함수를 짜는 방법
함수를 짜는 방법은 글짓기와 같습니다. 처음에는 길고 복잡하며 중복된 부분을 신경쓰지않고 코드를 작성합니다. 그 후 코드를 점점 다듬으면서 함수를 만들고, 이름을 바꾸고, 중복을 제거해줍니다. 그 과정에서 메서드의 크기를 줄이고, 순서가 바뀌기도합니다. 또한, 클래스를 쪼개기도 합니다. 이런 과정을 거쳐서 위에서 설명한 조건들을 만족하는 코드를 작성하게됩니다. 처음부터 위의 조건을 다 만족하는 코드를 짜는 것은 거의 불가능한 일이기 때문에 차근차근 고쳐나가는 연습을 하는 것이 중요합니다.
주석
주석은 나쁜 코드를 보완하지 못합니다. 코드로 의도를 표현하는 것이 중요합니다. 주석은 코드로 의사 전달이 제대로 안된 경우를 만회하기 위해서 사용한다고 생각하는 것이 중요합니다. 코드의 내용은 최대한 코드로 표현을 하고 코드로 표현하는 것이 불가능한 경우나 주석 사용이 불가피한 경우에만 유용합니다. 그 이유는 좋은 주석이 있고 나쁜 주석이 있기 때문입니다.
좋은 주석
나쁜 주석
정리