Eternity's Chit-Chat

aeternum.egloos.com



진화적인 설계-1.우리는 실패하고 있다 4부 Evolutionary Design

패턴은 진화의 방향을 제시한다

패턴을 사용하면서 부딪히게 되는 대부분의 문제는 패턴을 맹목적으로 사용할 때 발생한다. 대부분의 패턴 입문자가 빠지기 쉬운 함정은 패턴을 적용하는 컨텍스트의 적절성은 무시한 채 패턴의 구조에만 초점을 맞추는 것이다. 망치를 들면 모든 것이 못으로 보인다는 격언처럼 패턴을 익힌 후에는 모든 설계 문제를 패턴으로 해결하려고 시도하기 쉽다. Joshua Kerievsky는 이를 “패턴 만능주의”라고 부른다.

패턴을 처음 배우기 시작했을 때, 패턴은 객체지향 설계를 위한 융통성 있고 정교하며 심지어 우아하기까지 한 방법으로 보였다. … 그러나 시간이 지나면서 패턴의 강력함에 빠져 간단하게 작성할 수 있는 코드조차 괜히 복잡하게 만들게 되었다. 계산을 하는 데 두 세가지 다른 방법이 있다는 것을 알게 되면 바로 Strategy 패턴을 도입했다. 사실 간단한 조건문을 사용하면 더 쉽고 빠르게 프로그램을 작성할 수 있었을 테고, 그것만으로 충분한 해결책이 되는 경우에도 말이다.

- Joshua Kerievsky, 패턴을 활용한 리팩터링

해결하려는 문제가 아니라 구조에 중점을 두는 접근 방법은 불필요하게 복잡하고, 이해하기 난해하며, 유지보수하기 어려운 시스템을 낳게 된다. 따라서 부적절한 상황에서 부적절하게 사용된 패턴으로 인해 소프트웨어의 엔트로피가 증가하는 부작용을 낳기 쉽다. 패턴을 남용하지 않기 위해서는 다양한 트레이드오프 관계 속에서 패턴을 적용하고 사용해 본 경험이 필요하다.

GOF의 디자인 패턴에서 저자들은 초심자와 전문가의 차이점으로 어떤 문제를 해결하기 위해 과거의 경험을 활용할 수 있는 능력을 보유했는지의 여부를 들고 있다. 앞서 언급한 것처럼 패턴의 학습을 통해 초심자라도 전문가와 유사한 수준의 설계 기술을 보유할 수 있다. 그러나 전문가와 초심자의 또 다른 차이점은 전문가는 다양한 실무 경험을 통해 어떤 컨텍스트에서 어떤 패턴을 적용해야 하는지, 그리고 이 보다 더 중요한 것으로 어떤 패턴을 적용해서는 안 되는 지에 대한 감각을 익히고 있다는 점이다. 패턴을 가장 효과적으로 적용하는 방법은 패턴을 지향하거나 패턴을 목표로 리팩토링하는 것이다.  

‘리팩토링의 결과로 나온 구조’인 패턴에 많이 익숙해진 지금, 나는 패턴의 최종 결과나 그 결과의 구현이 의미하는 바를 이해하는 것보다 패턴을 목표로 한 또는 패턴을 지향한 리팩토링을 하는 이유를 이해하는 것이 훨씬 가치 있다고 생각한다.
더 훌륭한 소프트웨어 설계자가 되려면, 훌륭한 소프트웨어 설계가 어떻게 발전해왔는지 그 과정을 공부하는 것이 훌륭한 설계 자체를 공부하는 것보다 훨씬 중요하다. 그 발전 과정 속에 진짜 지혜가 숨어 있기 때문이다. 발전의 결과로 나온 구조도 도움이 되긴 하겠지만, 그 구조가 왜 그런 식의 설계로 발전했는지를 알지 못한다면, 다른 프로젝트에서 그것을 잘못 적용하거나 또는 그 구조로 과도한 설계를 할 가능성이 커진다.

- Joshua Kerievsky, 패턴을 활용한 리팩터링

Alan Shalloway는 훌륭한 설계자는 개별 클래스나 객체 수준보다 먼저 해결하고자 하는 문제 영역에 관해 고려해야 한다고 주장한다. 훌륭한 설계를 위해서는 전체적인 관점에서 문제에 관해 간단히 서술한 후 세부적인 정보를 추가해가면서 설계를 진행해야 한다. 즉, 세부적인 사항을 결정하기 전에 설계 솔루션이 위치해야 하는 적절한 컨텍스트를 먼저 고려해야 한다는 것이다. Alan Shalloway는 이를 ‘컨텍스트에 의한 설계(Design by Context)’라고 부른다. 여기에서 전체적인 컨텍스트와 세부적인 설계 솔루션 모두 패턴의 형식을 띤다.

패턴은 설계를 진행하고 있는 컨텍스트(context)에 작용하는 영향력(force)을 고려하여 선택해야 한다. 그러나 컨텍스트에 작용하는 영향력의 실체는 소프트웨어를 구축하기 전까지는 알 수 없는 경우가 대부분이다. 즉, 실제로 소프트웨어를 구현해 보기 전까지는 현재의 컨텍스트에 선택한 패턴이 적절한 지 여부를 판단할 수 없다는 것이다. 따라서 ‘컨텍스트에 의한 설계’는 패턴 중심의 ‘진화적 설계’ 방식을 따라야 한다.

진화적 설계는 패턴을 적용할 수 있는 새로운 패러다임을 제공한다. 일단 현재의 요구사항을 수용할 수 있도록 소프트웨어를 설계한다. 새로운 요구사항이 등장하거나 기존의 요구사항이 변경될 경우 코드는 스스로 자신이 가야 할 방향을 제시하기 시작한다. 코드에 귀 기울임으로써 패턴에서 이야기하는 영향력이 발생했음을 느낄 수 있게 된다. 남은 일은 영향력을 수용하며 패턴을 향해 리팩토링하는 것이다.

진화적인 설계는 패턴을 위한 문맥을 제공하고, 패턴은 진화적인 설계의 목적을 제시한다.

예제 프로그램
설계가 서서히 진화되어 가는 과정을 설명하기 위해서 간단한 예제 프로그램을 가지고 진행할 것이다. 예제 프로그램은 핸드폰 요금을 계산하는 간단한 소프트웨어로, 다양한 요금제의 지원과 요금제의 변경에 유연하게 대처하는 것을 주요 설계 목적으로 한다.

핸드폰 과금 시스템의 구현은 리팩토링에 의해 점진적으로 설계를 개선시켜 나가는 ‘진화적 설계’와 패턴을 중심으로 한 ‘컨텍스트에 의한 설계’ 방식으로 진행된다. 설계가 자리를 잡을 수 있는 컨텍스트를 제공하기 위해 ACCOUNTING 패턴 언어와 EVENT 패턴 언어를 기반으로 초기 소프트웨어 아키텍처를 확립할 것이다. 새로운 기능을 추가하면서 전체 컨텍스트 내에서의 조화를 맞추기 위해 리팩토링을 통해 설계를 진화시켜 나갈 것이다.

다루지 않는 내용
본 연재는 단순한 설계 아이디어에서 출발한 시스템이 개념적으로 통합된 구조를 유지한 채 성장해가는 과정을 다룬다. 연재에서 중점적으로 다루는 대부분의 내용은 코드의 설계 및 구현 행위와 밀접한 관련을 맺고 있으며 다음과 같은 영역은 논의에서 제외한다.

  • 요구사항 수집 및 분석 과정에 대해서는 다루지 않는다. 예제 시스템의 요구사항은 지면상의 제약으로 인해 초기 시점부터 잘 정리된 형태로 주어질 것이다. 그러나 일반적으로 프로젝트에서 깔끔한 요구사항을 발견하는 것은 예외에 가깝다는 사실을 명심하자.
  • 초기에 제시된 요구사항은 변경되지 않는다. 대신 예제 시스템이 새로운 요구사항을 수용하며 진화하는 과정에서 요구사항 변경과 유사한 정도의 충격을 리팩토링을 통해 흡수하는 과정을 그려낼 것이다. 연재에서 설명되는 모든 리팩토링 지침은 요구사항 변경 시에도 동일하게 적용될 수 있다.
  • 인프라스트럭처에 대해서는 고려하지 않는다. 따라서 초기에 종단 시스템 전체를 아우르는 ‘워킹 스켈레톤(Walking Skeleton)’을 구축하지 않을 것이며 설계의 초점을 도메인 레이어로 한정할 것이다. 또한 데이터베이스와 같은 인프라스트럭처가 정상적으로 가동하고 있다는 가정하에 개발을 진행할 것이다.

덧글

  • windily 2011/05/23 07:16 #

    정말 다음글이 기대됩니다. 힘내주세요!!
  • 백명석 2011/05/23 10:20 # 삭제

    다음 글(예제)이 기대됩니다. ^^
  • Outsider 2011/05/23 12:29 # 삭제

    와~ 예제도 나오는군요.. 다음편이 기대되는군요. 감사합니다.
※ 로그인 사용자만 덧글을 남길 수 있습니다.