티스토리 뷰



[프로그래밍 언어론] 켄트벡(Kent beck)이 제시한 단순한 소프트웨어 설계 규칙



이 글은 Clean Code 책의 내용을 정리한 것입니다.


착실하게 따르기만 한다면 우수한 설계가 나오는 간단한 규칙 4가지가 있다면? 이 규칙을 통해서 코드 구조와 설계가 파악하기 쉬워지고, SRP, DIP와 같은 원칙 적용이 쉬워진다면 어떻게 하시겠습니까?


켄트 벡(Kent Beck)은 다음 규칙을 따르면 설계는 '단순해진다'라고 말하고 있습니다. 그럼 이러한 규칙은 무엇이 있을까요? 켄트벡이 제시한 규칙은 아래와 같습니다. 


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

2) 중복을 없앤다.

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

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


위의 목록은 중요도 순이며, 이에 대한 상세내역을 살펴볼 까 합니다.


단순한 설계규칙1. 모든 테스트를 실행한다.


무엇보다 먼저, 설계는 의도한 대로 돌아가는 시스템을 개발해야 합니다. 이를 위해서는 테스트를 철저히 거쳐 모든 테스트 케이스를 통과하는 시스템을 만들어야 합니다. 테스트가 가능한 시스템을 만들려고 힘쓰게 되면, 자연스레 설계 품질도 더불어 높아집니다. 


결합도가 높으면 테스트 프로그램을 작성하기 어렵습니다. 테스트 케이스를 많이 작성하게 하면 할수록 DIP 원칙은 물론, 의존성 주입, 인터페이스, 추상화과 같은 도구를 사용하여 결합도를 낮추게 됩니다. 


의존성 주입이란?


의존성 주입(Dependency Injection, DI)은 프로그래밍에서 구성요소간의 종속성을 소스코드에서 설정하지 않고 외부의 설정파일 등을 통해 주입하도록 하는 디자인 패턴 중의 하나이다.


마틴 파울러는 다음과 같은 세 가지의 의존성 주입 패턴을 제시하였다. [1]


생성자 주입 : 필요한 의존성을 모두 포함하는 클래스의 생성자를 만들고 그 생성자를 통해 의존성을 주입한다.

세터(Setter)를 통한 주입 : 의존성을 입력받는 세터(Setter) 메소드를 만들고 이를 통해 의존성을 주입한다.

인터페이스(Interface)를 통한 주입 : 의존성을 주입하는 함수를 포함한 인터페이스를 작성하고 이 인터페이스를 구현하도록 함으로써 실행시에 이를 통하여 의존성을 주입한다.


<참조 : 위키피디아>


단순한 설계규칙2. 중복을 없애라


우수한 설계에서 중복은 복잡도를 뜻하기 때문에 커다란 문제가 될 수 있습니다. 똑 같은 코드는 물론 비슷한 코드도 리팩토링을 통해서 해결할 수가 있습니다. 공통적인 코드를 새로운 메소드로 뽑거나, 이를 통해서 SRP가 위반이 된다면 새로운 메소드를 새로운 클래스로 위임할 수 있습니다. 


Template Method 패턴은 고차원적인 중복을 제거할 목적으로 자주 사용됩니다. Template Method 패턴의 전반적인 구현은 상위클래스에서 담당하고 부분적인 곳의 구체적인 구현은 하위클래스가 담당합니다. 예를 살펴보면 아래와 같습니다. 아래의 첫번째 VacationPolicy 클래스를 보면 두개의 함수에서 동일한 행위를 하는 것을 알 수 있습니다. 동일한 행위는 상위 클래스로 다른 행위를 하위 클래스로 둔다면 SRP, DIP를 만족하는 설계가 가능합니다. 


public class VacationPolicy

{

public void accrueUSDDivisionVacation()

{

// 지금까지 근무 시간 바탕으로 휴가 일수 계산

// ...

// 휴가 일수가 미국 최소 법정 일수에 만족하는지 계산 

// ...

// 휴가 일수를 급여 대장에 적용하는 코드

}

public void accrueEUDDivisionVacation()

{

// 지금까지 근무 시간 바탕으로 휴가 일수 계산

// ...

// 휴가 일수가 유럽 최소 법정 일수에 만족하는지 계산 

// ...

// 휴가 일수를 급여 대장에 적용하는 코드

}

}


public class VacationPolicy

{

public void accrueVactaion()

{

calclateBaseVacationHour();

alterForLegalMinimums();

applyToPayRoll();

}

private void calclateBaseVacationHour() { /** ... **/ };

abstract protected void alterForLegalMinimums()

private void applyToPayRoll() { /** ... **/ };

}


public class USVacationPolity extends VacationPolicy

{

@override protected void alterForLegalMinimums()

{

// 미국 최소 법정 일수 사용

}

}


public class EUacationPolity extends VacationPolicy

{

@override protected void alterForLegalMinimums()

{

// 유럽 최소 법정 일수 사용

}

}


Template Pattern에 대한 클래스 다이어그램은 아래와 같습니다. 참고하시기 바랍니다.




단순한 설계규칙3. 프로그래머의 의도를 표현하라.


자신이 짠 코드를 이해하기는 쉽지만, 차후 유지보수하는 개발자가 코드를 이해하기는 쉽지 않습니다. 이러한 이유로 소프트웨어의 유지보수 비용은 소프트웨어 프로젝트 비용의 대다수를 차지하게 됩니다. 


따라서 코드에 대한 개발자의 의도를 분명히 표현을 해야 합니다. 개발자가 코드를 명백하게 짤수록 유지보수시에도 혼란이 없습니다. 이를 위해서는 다음과 같은 절차를 따르도록 합시다.


  • 좋은 이름을 선택하라
  • 함수와 클래스 크기를 가능한 줄여라
  • 표준 명칭을 사용하라
  • 단위 테스트 케이스를 꼼꼼히 작성하라


단순한 설계규칙4. 클래스와 메소드 수를 최소로 줄여라


중복을 제거하고, 의도를 표현하고, SRP를 준수하라는 기본적 개념을 극단적으로 따르게 되면 득보다는 실이 많아지게 됩니다. 함수와 클래스 크기를 작게 유지하면서 동시에 시스템 크기도 작게 유지해야 합니다. 


하지만 이 규칙은 우선순위가 다른 3개에 비해 월등히 낮기 때문에 위의 작업을 우선적으로 하되, 줄일 수 있을 정도로 줄이면 된다고 생각하면 됩니다.


이 글이 도움이 되셨나요?

그렇다면 아래의 그림을 클릭해주세요.



댓글