클린 코드 Chapter 12. 창발성

Jeongmin Yeo (Ethan)·2021년 3월 13일
3

Clean Code

목록 보기
12/14
post-thumbnail

클린 코드 Chapter 12. 창발성에 대해 정리합니다.

학습할 내용은 다음과 같습니다.

  • Principle 1. 모든 테스트를 실행하라
  • Principle 2. 리팩토링
  • Principle 3. 표현하라

Reference


Intro

착실하게 따르기만 하면 우수한 설계가 나오는 규칙이 있다.

이 규칙을 따르기만 하면 코드 구조와 설계를 파악하기 쉽다.

다음은 켄트 벡이 제시한 단순한 설계 규칙 네 가지가 있다.

  • 모든 테스트를 실행한다.

  • 중복을 없앤다.

  • 프로그래머 의도를 표현한다.

  • 클래스와 메소드 수를 최소로 줄인다.


Principle 1. 모든 테스트를 실행하라

무엇보다 먼저 설계는 의도한 대로 돌아가는 시스템을 내놓아야 한다.

문서로는 시스템을 완벽하게 설계했지만 시스템이 의도한대로 돌아가지 않는다면 그 가치는 인정받기 힘들다.

테스트가 불가능한 시스템은 검증도 불가능하고 절대 출시하면 안된다.

다행스럽게도 테스트가 가능한 시스템을 만들려고 애쓰면 설계 ㅍ품질이 더불어 높아진다.

크기가 작고 목적 하나만 수행하는 클래스가 나온다.

철저한 테스트가 가능한 시스템을 만들면 더 낭느 설계가 얻어진다.

결합도가 높은 클래스가 있어서 테스트하기 어렵다면 DIP와 같은 원칙을 적용하고 의존성 주입을 이용해 결합도를 낮춰서 테스트를 적요할 수 있다.


Principle 2. 리팩토링

테스트 케이스를 모두 적용했다면 이제 코드와 클래스를 정리하자.

코드를 정리하면서 시스템이 깨질까 걱정할 필요는 없다 테스트 케이스가 있으니까.

리팩토링 단계에서는 소프트웨어 설계 품질을 높이는 기법이라면 무엇이든 적용해도 좋다.

응집도를 높이고 결합도를 낮추고 관심사를 분리하고 함수와 클래스 크기를 줄이고 더 나은 이름을 선택하고 다양한 기법을 사용해도 좋다.

이 원칙은 중복을 제거하고 프로그래머 의도를 표현하고 클래스와 메소드를 최소로 줄이는 원칙이다.

중복을 없애라

우수한 설계에서 중복은 커다란 적이다.

중복은 추가 작업, 추가 위험, 복잡도를 말한다.

중복은 여러가지 형태가 있다. 똑같은 코드는 당연히 중복이고 비슷한 코드도 중복이다. 이를 리팩토링을 통해서 해결할 수 있다.

구현 코드도 중복의 한 형태다.

예를 들어 다음과 같은 메소드가 있다고 보자.

int size () {}

boolean isEmpty () {}

isEmpty와 size 메소드는 유사하다 그러므로 중복을 줄일 수 있다. 다음고 ㅏ같이

boolean isEmpty(){
  return 0 == size(); 
}

그리고 클래스에서 여러 중복된 코드가 있다면 뽑아서 새로운 메소드로 만들 수 있다.

이때 새로운 메소드로 뽑고보니 클래스가 SRP를 위반한다면 다른 클래스에 옮기는 작업을 해도 좋다. 이렇게 하면 시스템 복잡도를 끅적으로 줄여준다.

소규모 재사용을 제대로 익혀야 대규모 재사용이 가능해진다.

TEMPLATE METHOD 패턴을 통해 고차원 중복을 제거할 수 있다. 다음 예를 보자.

public class VacationPolicy{
  public void accrueUsDivisionVacation(){
    // 지금까지 근무한 시간을 바탕으로 휴가 일수를 계산하는 코드
    
    ...
    
    // 휴가 일수가 미국 최소 법정 일수를 만족하는지 확인하는 코드
    
    ...
   
    // 휴가 일수를 급여 대장에 적용하는 코드
  }
}


public class VacationPolicy{
  public void accrueEUDivisionVacation(){
    // 지금까지 근무한 시간을 바탕으로 휴가 일수를 계산하는 코드
    
    ...
    
    // 휴가 일수가 유럽연합 최소 법정 일수를 만족하는지 확인하는 코드
    
    ...
   
    // 휴가 일수를 급여 대장에 적용하는 코드
  }
}

최소 법정 일수를 계산하는 코드만 제외하면 두 메소드는 동일하다.

여기에 TEMPLATE METHOD 패턴을 사용해 중복을 제거할 수 있다.

abstract public class VacationPolicy{
  public void accrueVacation(){
    calculateBaseVacationHours();
    alterForLegelMinimums();
    applyToPayroll(); 
  }
  
  private void calculateBaseVacationHours(){
     ... 
  }
  
  abstract protected void alterForLegalMinimums(); 
  
  private void applyToPayroll(){
     ... 
  }
}


public class USVactionPolicty extends VacationPolicy{
  @Override protected void alterForLegamMinimums(){
  
  }
}

public class EUVactionPolicty extends VacationPolicy{
  @Override protected void alterForLegamMinimums(){
  
  }
}

하위 클래스는 중복되지 않는 정보만 제공해 알고리즘에서 빠진 구멍을 채울 수 있다.


Principle 3. 표현하라

아마 우리 대다수는 엉망인 코드를 접한 경험이 있고 그렇게 개발한 경험도 있다.

자신이 이해하는 코드는 짜기 쉽다. 코드를 짜는 동안에는 구석구석 이해하니까.

하지만 나중에 코드를 유지보수할 사람을 생각해서 코드를 짜야한다.

소프트웨어 프로젝트 비용 중 대다수는 장기 유지보수 비용에 들어간다.

코드를 변경하면서 버그의 싹을 심지 않으려면 유지보수 개발자가 시스템을 제대로 이해해야한다.

유지보수 개발자가 시스템을 제대로 이해하기 위해서는 개발자의 의도를 분명히 표현해야 한다.

개발자가 코드를 명백하게 짤수록 이해하기 쉽고 오해가 적어진다.

이릉 위한 규칙은 다음과 같다.

우선 좋은 이름을 선택한다. 이름과 기능이 완전히 딴판인 클래스나 함수는 이해하기 어렵다.

둘째, 함수와 클래스 크기를 가능한 줄인다. 작은 클래스와 작은 함수가 이해하기 쉽다.

셋째, 표준 명칭을 사용한다. 에를 들어 디자인 패턴은 의사소통과 표현력 강화가 주 목적이다.

디자인 패턴을 사용했으면 그 이름을 붙여주자.

넷째, 단위 테스트 케이스를 꼼꼼히 작성한다. 테스트 케이스는 소위 예제로 보여주는 문서다.

잘 만든 테스트 케이스를 읽으면 클래스 기능이 보인다.

profile
좋은 습관을 가지고 싶은 평범한 개발자입니다.

0개의 댓글