모르지 않다는 것은 아는것과 다르다.

Books

클린코드 1장, 2장

채마스 2022. 4. 17. 21:30

1장 깨끗한 코드

C++ 창시자이자 C++ Programming Language 저자 Bjarne Stroustrup

  • 나는 우아하고 효율적인 코드를 좋아한다.
  • 논리가 간단해야 버그가 숨어들지 못한다.
  • 의존성을 최대한 줄여야 유지보수가 쉬워진다.
  • 오류는 명백한 전략에 의거해 철저히 처리한다.
  • 성능을 최적으로 유지해야 사람들이 원칙 없는 최적화로 코드를 망치려는 유혹에 빠지지 않는다.
  • 깨끗한 코드는 한 가지를 제대로 한다.

 

Object Oriented Analysis and Design with Application 저자 Grady Booch

  • 깨끗한 코드는 단순하고 직접적이다.
  • 깨끗한 코드는 결코 설계자의 의도를 숨기지 않는다.
  • 오히려 명백한 추상화와 단순한 제어문으로 가득하다.

 

OTI 창립자이자 이클립스 전략의 대부 Dave Thomas

  • 깨끗한 코드는 작성자가 아닌 사람도 읽기 쉽고 고치기 쉽다.
  • 단위 테스트 케이스와 인수 테스트 케이스가 존재한다.
  • 깨끗한 코드에는 의미있는 이름이 붙는다.
  • 특정 목정을 달성하는 방법은 하나만 제공한다.
  • API 는 명확하며 최소로 줄였다.
  • 언어에 따라 필요한 모든 정보를 코드만으로 명확히 표현할 수 없기에 코드는 문학적으로 표현해야 마땅하다.

 

Working Effectively with Lagacy Code 저자 Michael Feathers

  • 깨끗한 코드의 특징은 많지만 그 중에서도 모두를 아우르는 특징이 하나 있다.
  • 깨끗한 코드는 언제나 누군가 주의 깊게 짰다는 느낌을 준다.
  • 작성자가 이미 모든 사항을 고려했으므로, 고칠 궁리를 하다보면 언제나 제자리로 돌아온다.
  • 그리고는 누군가 남겨준 코드, 누군가 주의 깊게 짜놓은 작품에 감사를 느낀다.

 

Extreme Programming Installed 와 Extreme Programming Adventure in C# 저자 Ron Jeffries

  • 최근 들어 나는 컨트 벡이 제안한 코드 규칙으로 구현을 시작한다.
  • 중요한 순으로 나열하자면 간단한 코드는 '모든 테스트를 통과한다.'
  • '중복이 없다', '시스템 내 모든 설계 아이디어를 표현한다.'
  • '클래스, 메서드, 함수 등을 최대한 줄인다'

 

위키 장시자, 익스트림 프로그래밍 공동창시자 Ward Cunningham

  • 코드를 읽으면서 짐작했던 기능을 각 루팅이 그대로 수행한다면 깨끗한 코드라 불러도 되겠다.
  • 코드가 그 문제를 풀기 위한 언어처럼 보인다면 아름다운 코드라 불러도 되겠다.

 

 

2장 의미있는 이름

의도를 분명히 밝혀라

  • 의도가 분명한 이름은 정말로 중요하다.
  • 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많다.
  • 의도를 전달하는 이름이 무엇일까?
int d; // 경과 시간
  • d 라는 변수는 의도를 주석으로 나태내고 있다. 그렇다면 d 가 쓰이는 모든 부분에 주석으로 의도를 명시할 것인가? -> 옳지 않다.
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModeification;
int fileAgeInDays;
  • 위와 같이 의도를 표한할 수 있는 변수명을 사용하는 것이 바람직하다.
  • 아래와 같은 코드의 문제점은 무엇일까?
public List<int[]> getThem(){
  List<int[]> list1 = new ArrayList<int[]>();
  for (int[] x : theList)
    if (x[0] == 4)
      list1.add(x);
  return list1;
}
  • 위의 코드를 보면 아래와 같은 의문이 생긴다.
    • theList에 무엇을 포함하고 있지?
    • 0번째값을 왜 찾아야하지?
    • 값이 4는 무슨 의미지?
    • 함수가 반환하는 리스트 list1는 어떻게 사용하지?
  • 위의 코드를 아래와 같이 리팩토링 할 수 있다.
public List<Cell> getFlaggedCells(){
  List<Cell> flaggedCells = new ArrayList<Cell>();
  for (Cell cell : gameBoard)
    if (cell[STATUS_VALUE] == FLAGGED)
      flaggedCells.add(cell);
  return flaggedCells;
}
  • 위와 같이 의미있는 변수명을 부여하고, 매직 넘버를 제거했을 뿐인데, 코드의 의도가 명확해졌다.

 

의미 있게 구분하라

  • 이름을 의미 있게 구분하는 것도 중요하다.
public static void copyChars(char a1[], char a2[]) {
  for (int i = 0; i< a1.length; i++) {
    a2[i] = a1[i];
  }
}
  • 위의 코드에서 a1, a2 는 숫자 1,2 로 구분을 했으나, 역시 의도를 파악할 수 없다.
public static void copyChars(char source[], char destination[]) {
  for (int i = 0; i< source.length; i++) {
    destination[i] = source[i];
  }
}
  • 위와 같이 source, destination 으로 의도를 전달하는 것이 바람직 하다.

 

클래스 이름

  • 클래스 이름과 객체 이름은 명사나 명사구가 적합하다.
  • Customer, WikiPage, Account, AddressParser 등은 좋은 예다.
  • Manager, Processor, Date, Info와 같은 단어는 피하는 것이 좋다. -> 너무 범용적이다.
  • 동사는 사용하지 않는다.

 

메서드 이름

  • 메서드 이름은 동사나 동사구가 적합하다.
  • postPayment, deletePage, save 등이 좋은 예다.
  • 접근자, 변경자, 조건자는 javabean 표준에 따라 값 앞에 get, set, is를 붙인다.
  • 생성자를 중복정의할 때는 정적 팩토리 메서드를 사용한다.
    • Complex fulcrumPoint = Complex.FromRealNumber(23.0);

 

검색하기 쉬운 이름을 사용해라

  • 여기서 검색은 구글링이 아닌, IDE 툴에서의 검색을 의미한다.
private static final MAX_CLASSES_PER_STUDENT = "7";
  • 문자 "7" 만 사용하는 것 보단 상수를 사용해서 눈에 잘 띄게 구분하는 것이 좋다.

 

한 개념에 한 단어만 사용하라

  • 추상적인 개념 하나에 단어 하나를 선택해 이를 고수한다.
  • 똑같은 메서드를 클래스마다 fetch, retrieve, get으로 제각각 부르면 혼란스럽다.
  • 그렇기 때문에 일관성 단어를 선택하는 것이 바람직하다.

 

의미있는 맥락을 추가해라

  • 이름에 의미를 부여하기 위해서 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다.
  • 하지만, 때때로 위의 방법이 실패할 때가 있다.
  • 그럴때에 마지막 수단으로 접두어를 붙인다.
  • firstName, lastName, street, houseNumber, city, state, zipcode 라는 변수가 있다고 해보자.
  • 저 변수들이 모여있으면 주소와 관련된 변수라고 인식할 수 있지만, firstName, lastName, state 만 놓고 보면, 주소와 관련된 변수라고 인식하기 어렵다.
  • 그렇기 때문에 addrFirstName, addrLastName, addrState 와 같이 addr 이라는 접두어를 추가해서 맥락을 분명히 할 수 있다.

 

클래스를 통한 맥락 추가

  • 때때로 맥락이 불분명한 메서드에 경우 클래스로 정의해서 맥락을 추가할 수 있다.
  • 아래와 같은 메소드가 있다고 해보자.
private void printGuessStatistics(char candidate, int count) {
  String number;
  String verb;
  String pluralModifier;
  if (count == 0) {
    number = "no";
    verb = "are";
    pluralModifier = "s";
  } else if (count == 1) {
    number = "1";
    verb = "is";
    pluralModifier = "";
  } else {
    number = Integer.toString(count);
    verb = "are";
    pluralModifier = "s";
  }
  String guessMessage = String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
}
  • number, verb, pluralModifier 는 메서드의 전반에 걸쳐 사용된다.
  • 하지만, number, verb, pluralModifier 는 함수를 끝까지 읽어봐야 의미가 파악된다.
  • 이런경우 클래스를 추출해서 맥락을 부여할 수 있다.
public class GuessStatisticsMessage {
  private String number;
  private String verb;
  private String pluralModifier;

  public String make(char candidate, int count) {
    createPluralDependentMessageParts(count);
    return String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
  }

  private void createPluralDependentMessageParts(int count) {
    if (count == 0) {
      thereAreNoLetters();
    } else if (count == 1) {
      thereIsOneLetter();
    } else {
      thereAreManyLetters(count);
    }
  }

  private void thereAreManyLetters(int count) {
    number = Integer.toString(count);
    verb = "are";
    pluralModifier = "s";
  }

  private void thereIsOneLetter(){
    number = "1";
    verb = "is";
    pluralModifier = "";
  }

  private void thereAreNoLetter(){
    number = "no";
    verb = "are";
    pluralModifier = "s";
  }

}

 

불필요한 맥락을 없애라

  • Gas Station Deluxe 라는 애플리케이션을 짠다고해서, 모든 클래스 이름을 GSD 로 시작하는 것은 바람직하지 않다.
  • 일반적으로 짧은 이름이 긴 이름보다 좋다. 단, 의미가 분명한 경우에 한해서다. 이름에 불필요한 맥락을 추가하지 않도록 주의해야 한다.

 

이외에 좋은 습관들

  • 그릇된 정보를 피하라
  • 발음하기 쉬운 이름을 사용하라
  • 검색하기 쉬운 이름을 사용하라
  • 인코딩을 피하라
  • 자신의 기억력을 자랑하지 마라
  • 기발한 이름은 피하라
  • 말장난을 하지 마라
  • 해법 영역에서 가져온 이름을 사용하라
  • 문제 영역에서 가져온 이름을 사용하라

 

TDD 법칙 세 가지

  • 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
  • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
  • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

 

TDD 원칙

  • FIRST
    • Fast 빠르게
    • Independent 독립적으로
    • Repeatable 반복가능하게
    • Self-Validating 자가 검정하는
    • Timly 적시에




REFERENCES

  • 클린코드 1, 2장