오브젝트: 코드로 이해하는 객체지향 설계 15장을 읽으며
오브젝트: 코드로 이해하는 객체지향 설계 15장을 읽으며
느낀점
패턴에 대해서 더 상세히 알게 되었음. 컴포넌트 재사용과 합성이 이상적으로는 좋지만 현실에서는 실패했다는 이야기에서 내 코드에서도 일부는 일관성있는 구조를 시간 및 여러가지 사유로 어긴 케이스가 있어서 이에 대한 근거를 찾으려고 마련하게 되었던 것 같음.
디자인 패턴과 프레임워크
소프트웨어 설계에서 반복적으로 발생하는 문제에 대해 반복적으로 적용할 수 있는 해결 방법을 디자인 패턴이라고 부름
- 디자인 패턴의 목적은 설계를 재사용하는 것
- 디자인 패턴을 익히고 나면 변경의 방향과 주기를 이해하는 것만으로도 필요한 역할과 책임, 역할들의 협력 방식을 순간적으로 떠올릴 수 있음
프레임워크는 설계와 코드를 함께 재사용하기 위한 것
- 프레임워크는 아키텍처를 구현 코드의 형태로 제공
- 애플리케잉션의 요구에 따라 적절하게 커스터마이징 할수 있는 확장 포인트 제공
- 일관성 있는 협력을 제공하는 확장 가능한 코드
소프트웨어 패턴
워드 커닝과 켄트 벡이 크리스토퍼 알렉산더의 패턴 개념을 소프트웨어 개발 커뮤니티에 소개한 때부터 패턴은 항상 소프트웨어 개발에 있어 중요한 화두.
- GOD가 저술한 디자인 패턴에 의해 패턴이 대중화된 이후 정의 역시 다양하고 풍부해짐
- 패턴이라는 거대한 숲 속에서 길을 잃지 않기 위해서는 패턴의 정의보다는 패턴이라는 용어 자체가 풍기는 미묘한 뉘앙스를 이해하는 것이 중요
- 패턴은 한 컨텍스트에서 유용한 동시에 다른 컨텍스트에서도 유용한 '아이디어'
- 일반적으로 패턴으로 인정하기 위한 조건으로 3의 규칙(Rule of Three)로 언급
- 패턴은 지식 전달과 커뮤니케이션의 수단으로 활용할 수 있기 때문에 패턴에서 가장 중요한 요소는 패턴의 이름
- 커뮤니티가 공유할 수 있는 중요한 어휘집 제공
- 인터페이스를 추가하고 인터페이스를 구체화하는 클래스를 만든 후 객체의 생성자나 setter 메서드에 할당해서 런타임 시에 알고리즘을 바꿀 수 있게 하자를 전략 패턴을 적용하자는 단순한 대화로 바뀜
- 연관된 패턴들이 모여 하나의 패턴 언어(Pattern Language)를 구성
- 패턴 언어라는 용어가 지닌 제약 조건을 완화하기 위해 패턴 시스템(Pattern System)이라는 특수한 용어 존재
패턴 분류
패턴의 범위나 적용 단계에 따라 아키텍처 패턴, 분석 패턴, 디자인 패턴, 이디엄으로 분리
- 아키텍처 패턴: 디자인 패턴의 상위에 소프트웨어의 전체적인 구조를 결정. 미리 정의된 서브시스템들을 제공하고 각 서브시스템들의 책임을 정의하며 서브시스템들 사이의 관계를 조직화하는 규칙과 가이드라인 포함
- 디자인 패턴: 특정 정황 내에서 일반적인 설계 문제를 해결하며, 협력하는 컴포넌트들 사이에서 반복적으로 발생하는 구조를 서술
- 이디엄: 디자인 패턴 하위에는 특정 프로그래밍 언어에만 국한된 하위 레벨 패턴으로 주어진 언어의 기능을 사용해 컴포넌트 혹은 컴포넌트 간의 특정 측면을 구현하는 방법을 서술
- 이디엄은 언어에 종속적이기 때문에 다른 언어에서는 무용지물
- 예를 들면 C++ 에서 객체들의 개수를 카운트해서 더 이상 자신이 참조되지 않을 경우 스스로를 삭제하는 COUNT POINTER 이디엄은 가비지 컬렉션 메커니즘을 가진 자바에서는 유용하지 않음
- 분석 패턴: 도메인 내의 개념적인 문제를 해결하는데 초점, 업무 모델링 시에 발견되는 공통적인 구조를 표현하는 개념들의 집합.
패턴은 출발점이다
패턴은 출발점이지 목적지가 아님
- 특정한 설계 이슈를 해결하기 위해 적절한 디자인 패턴을 이용해서 설계를 시작
- 디자인 패턴은 설계의 목표가 되어서는 안됨.
- 설계에 이를 수 있는 방향을 제시하는 나침반에 불과하여 패턴을 그대로 이용하는 것이 아닌 목적에 맞게 패턴을 수정
패턴을 사용하면서 부딪히게 되는 대부분의 문제는 패턴을 맹목적으로 사용할 때 발생
- 패턴을 적용하는 컨텍스트의 적절성은 무시한 채 패턴의 구조에만 초점을 맞추는 것
- 망치를 들면 모든 것이 못으로 보인다는 패턴 만능주의 조심
- 해결하려는 문제가 아니라 패턴이 제시하는 구조를 맹목적으로 따르면 불필요하게 복잡하고 난해하며 유지보수하기 어려운 시스템을 낳음
- 패턴은 남용하지 않기 위해서는 다양한 트레이드 오프 관계속에서 패턴을 적용하고 사용해 본 경험이 필요
어떤 패턴을 적용해서는 안되는지에 대한 감각을 익히는 것이 더 중요
- 패턴 입문자의 경우에는 사소한 설계라도 패턴을 적용해 보려고 시도하지만, 패턴을 적용해보고 싶은 의욕이 앞서면 안됨
- 패턴을 잘 알지 못하는 사람들은 불필요하게 복잡한 설계를 따라가느라 시간을 낭비할 수도 있음
정당한 이유 없이 사용된 모든 패턴은 설계를 복잡하게 만드는 장애물
- 패턴은 복잡성의 가치가 단순성을 넘어설 때만 정당화
- 코드를 공유하는 모든 사람들이 적용된 패턴을 알고 있어야 하며, 그렇지 못한 사람들은 복잡한 구조로 인해 코드를 쉽게 이해할 수 없게 됨
- 따라서 설계에 대한 지식과 패턴에 대한 공유도 필요
코드 재사용 대 설계 재사용
디자인 패턴은 프로그래밍 언어에 독집적으로 재사용 가능한 설계 아이디어를 제공하는 것을 목적으로 함
- 재사용 관점에서 설계 재상요보다 더 좋은 방법은 코드 재사용
- 개발자들은 컴포넌트를 조합해서 애플리케이션을 구축하는 방법을 추구
- 아쉽게도 컴포넌트 기반의 재사용 방법이라는 아이디어 자체는 이상적이지만 실제로 적용하는 과정에서 현실적이지 않다는 사실이 드러남
- 가장 이상적인 형태의 재사용 방법
- 코드 재사용과 설계 재사용을 적절한 수준으로 조합하는 것
설계를 재사용 하면서도 유사한 코드를 반복적으로 구현하는 문제를 피하기 위해 객체지향에서는 프레임워크를 사용
- 프레임워크: 추상 클래스나 인터페이스를 정의하고 인스턴스 사으의 상호작용을 통해 시스템 전체 혹은 일부를 구현해 놓은 재사용 가능한 설계 또는 개발자가 현재의 요구사항에 맞게 커스터마이징 할 수 있는 애플리케이션의 골격
- 프레임워크는 코드를 재사용함으로써 설계 아이디어를 재사용
상위 정책과 하위 정책으로 패키지 분리하기
프레임워크의 핵심은 추상 클래스나 인터페이스와 같은 추상화라고 할 수 있음
- 상위 정책은 일반적으로 변경에 안정적이지만 세부 정책 자주 변경됨
- 상위 정책이 세부 정책에 의존할 경우 변경에 대한 파급 효과로 상위 정책이 불안정해짐
- 상위 정책은 일반적으로 세부 정책보다 재사용 가능성 높음
의존성 역전 원칙 관점에서 세부 원칙은 변경을 의미
- 변하는 것과 변하지 않는 것을 서로 분리해야 함.
- 첫걸음을 변하는 부분과 변하지 않는 부분을 별도의 패키지로 분리하는 것
- 중요한 것은 패키지 사으의 의존성 방향
- 패키지가 충분히 안정적이고 성숙했다면 하위 패키지로 부터 완벽히 분리해서 별도 배포 단위로 만들 수 있음
- 다시 말해 재사용 가능한 요금 계산 로직을 구현한 프레임워크가 만들어진 것
제어 역전 원리
상위 정책을 재사용한다는 것은 결국 도메인에 존재하는 핵심 개념들 사이의 현력 관계를 재사용한다는 것을 의미
- 시스템이 진화하는 방향에는 항상 의존성 역전 원리를 따라야 함
- 휼룡한 객체지향 설계는 의존성이 역전된 설계라는 점을 강조
의존성 역전 원리는 프레임워크의 가장 기본적인 설계 메커니즘
- 프레임워크가 애플리케이션에 속하는 서브클래스의 메서드를 호출함
- 프레임워크를 사용할 경우 개별 애플리케이션에서 프레임워크로 제어의 흐름의 주체가 이동
- 이를 제어 역전(Inversion of Control)원리 또는 할리우드(HollyWood) 원리라고 부름.
프레임워크에서는 일반적인 해결책만 제공
- 애플리케이션에 따라 달라질 수 있는 특정한 동작은 비워둠
- 완성되지 않은 채로 남겨진 동작을 훅(hook)이라고 부름
- 훅의 구현 방식은 애플리케이션의 컨텍스트에 따라 다라짐
- 과거의 좋았던 시절에는 우리가 직접 라이브러리의 코드를 호출했지만, 객체지향의 시대엥서는 그저 프레임워크가 호출하는 코드를 작성해야 함.
- 제어가 우리에게서 프레임워크로 넘어가 버림
- 프레임워크를 처음 사용한다면 제어 흐름이 손가락 사이로 스멀스멀 빠져나가는 듯한 느낌에 불안해질 수 있음
- 프레임워크의 핵심 개념인 동시에 코드의 재사용을 가능하게 하는 힘이라는 사실을 이해해야 함.