티스토리 뷰

반응형


| 12. 창발성(創發性)


-


|| 창발적 설계로 깔끔한 코드를 구현하자



대다수는 Kent Beck이 제시한 "단순한 설계 규칙" 네 가지가 소프트웨어 설계 품질을 크게 높여준다고 믿는다..

- 다음 규칙을 따르면 설계는 '단순하다'고 말할 수 있다. - Kent Beck

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

2. 중복을 없앤다.

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

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



|| 단순한 설계 규칙 1: 모든 테스트를 실행하라


- 철저한 테스트로 모든 테스트 케이스를 항상 통과하는 시스템은 '테스트가 가능한 시스템'이다.

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

  (하나만 수행하는 클래스, SRP 준수 클래스)

- 테스트 케이스 작성이 쉬워지려면 DIP 원칙 적용, DI, 인터페이스, 추상화 등과 같은 도구를 사용해 결합도를 낮춰야 한다.



|| 단순한 설계 규칙 2~4: 리펙터링


- 리펙터링 단계에서는 소프트웨어 설계 품질을 높이는 기법을 무엇이든 적용해보자.

- 응집도 높이기

- 결합도 낮추기

- 관심사 분리하기

- 시스템 관심사를 모듈로 나누기

- 함수와 클래스 크기 줄이기

- 더 나은 이름 선택하기

..



|| 중복을 없애라


"중복은 커다란 적이다."

- 깔끔한 시스템을 만들려면 단 몇 줄이라도 중복을 제거하겠다는 의지가 필요하다 !


> Before

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void scaleToOneDimension(float desiredDimension, float imageDimension) {
  if (Math.abs(desiredDimension - imageDimension) < errorThreshold)
    return;
  float scalingFactor = desiredDimension / imageDimension;
  scalingFactor = (float)(Math.floor(scalingFactor * 100* 0.01f);
  
  RenderedOpnewImage = ImageUtilities.getScaledImage(image, scalingFactor, scalingFactor);
  image.dispose();
  System.gc();
  image = newImage;
}
 
public synchronized void rotate(int degrees) {
  RenderedOpnewImage = ImageUtilities.getRotatedImage(image, degrees);
  image.dispose();
  System.gc();
  image = newImage;
}
cs


> After

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void scaleToOneDimension(float desiredDimension, float imageDimension) {
  if (Math.abs(desiredDimension - imageDimension) < errorThreshold)
    return;
  float scalingFactor = desiredDimension / imageDimension;
  scalingFactor = (float) Math.floor(scalingFactor * 10* 0.01f);
  replaceImage(ImageUtilities.getScaledImage(image, scalingFactor, scalingFactor));
}
 
public synchronized void rotate(int degrees) {
  replaceImage(ImageUtilities.getRotatedImage(image, degrees));
}
 
private void replaceImage(RenderedOpnewImage) {
  image.dispose();
  System.gc();
  image = newImage;
}
cs


- 클래스가 SRP(단일 책임 원칙)를 위반한다면?

- 다른 클래스로 옮겨도 좋다. (가시성을 높이기 위해)

- 새 메서드를 더 추상화해 다른 맥락에서 재사용할 기회를 포착할 수 있다.

- 소규모 재사용 -> 시스템 복잡도 극적 하강!


||| TEMPLATE METHOD PATTERN


- 고차원 중복 제거


> Before

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class VacationPolicy {
  public void accrueUSDDivisionVacation() {
    // 지금까지 근무한 시간을 바탕으로 휴가 일수를 계산하는 코드
    // ...
    // 휴가 일수가 미국 최소 법정 일수를 만족하는지 확인하는 코드
    // ...
    // 휴가 일수를 급여 대장에 적용하는 코드
    // ...
  }
  
  public void accrueEUDivisionVacation() {
    // 지금까지 근무한 시간을 바탕으로 휴가 일수를 계산하는 코드
    // ...
    // 휴가 일수가 유럽연합 최소 법정 일수를 만족하는지 확인하는 코드
    // ...
    // 휴가 일수를 급여 대장에 적용하는 코드
    // ...
  }
}
cs


> After

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
abstract public class VacationPolicy {
  public void accrueVacation() {
    caculateBseVacationHours();
    alterForLegalMinimums();
    applyToPayroll();
  }
  
  private void calculateBaseVacationHours() { /* ... */ };
  abstract protected void alterForLegalMinimums();
  private void applyToPayroll() { /* ... */ };
}
 
public class USVacationPolicy extends VacationPolicy {
  @Override protected void alterForLegalMinimums() {
    // 미국 최소 법정 일수를 사용한다.
  }
}
 
public class EUVacationPolicy extends VacationPolicy {
  @Override protected void alterForLegalMinimums() {
    // 유럽연합 최소 법정 일수를 사용한다.
  }
}
cs

- 하위 클래스는 중복되지 않는 정보만 제공



|| 표현하라


-

- 코드는 개발자의의도를 분명히 표현해야 한다! (결함과 유지보수 비용을 줄이기 위해)


1. 좋은 이름을 선택

2. 함수와 클래스 크기를 가능한 줄이자

3. 표준 명칭을 사용

4. 단위 테스트 케이스를 꼼꼼히 작성

- 테스트 케이스는 소위 '예제로 보여주는 문서'


* 표현력을 높이는 가장 중요한 방법은 "노력" 




출처 : 클린 코드 (Robert C. Martin)





반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday