1. 디자인 패턴이란?
디자인 패턴은 소프트웨어 디자인 과정에서 자주 발생하는 문제들에 대한 전형적인 해결책입니다. 이는 코드에서 반복되는 디자인 문제들을 해결하기 위해 맞춤화할 수 있는 미리 만들어진 청사진과 비슷합니다.
표준화된 라이브러리들이나 함수들을 코드에 복사해 사용하는 것처럼 패턴들을 붙여넣기식으로 사용할 수 없습니다. 패턴은 재사용할 수 있는 코드 조각이 아니라 특정 문제를 해결하는 방식을 알려주는 일반적인 개념들입니다. 당신은 패턴의 세부 개념들을 적용하여 당신의 프로그램에 맞는 해결책을 구현할 수 있습니다.
패턴은 알고리즘과 자주 혼동됩니다. 왜냐하면 두 개념 모두 알려진 문제에 대한 일반적인 해결책을 설명하기 때문입니다. 알고리즘은 어떤 목표를 달성하기 위해 따라야 할 명확한 일련의 절차를 정의하지만, 패턴은 해결책에 대한 더 상위 수준의 설명입니다. 예를 들어, 같은 패턴을 두 개의 다른 프로그램에 적용하면 두 프로그램의 코드는 다를 것입니다.
알고리즘은 요리법에 비유할 수 있지만, 패턴은 요리법이 아닌 청사진에 더 가깝습니다.
알고리즘과 요리법 둘 다 목표를 달성하기 위한 명확한 단계들이 제시되어 있습니다.
반면에, 청사진은 결과와 기능들은 제시하나, 구현 단계 및 순서는 사용자가 결정합니다.
1.1 패턴은 무엇으로 구성되어 있나요?
많은 상황에서 독자들이 패턴을 재현할 수 있도록 대부분의 패턴을 매우 형식적으로 설명했습니다. 패턴 설명에 일반적으로 표시되는 섹션들은 다음과 같습니다
- 패턴의 의도 섹션에서는 문제와 해결책을 간략하게 설명했습니다.
- 동기 섹션에서는 문제와 패턴이 가능하게 하는 해결책을 추가 설명했습니다.
- 클래스의 구조 섹션에서는 패턴의 각 부분과 이러한 부분들이 어떻게 연관되어 있는지를 보여주었습니다.
- 코드 예시 섹션에서는 여러 인기 있는 프로그래밍 언어들로 된 코드 예시를 제공하여 독자들이 패턴 뒤의 아이디어를 이해하기 쉽도록 했습니다.
일부 패턴 섹션에서는 패턴의 적용, 구현 단계 및 다른 패턴과의 관계와 같은 유용한 세부 정보들도 설명했습니다
1.2 패턴의 분류
디자인 패턴은 복잡성, 상세도 및 설계 중인 전체 시스템에 대한 적용 범위에 따라 분류됩니다. 저는 도로 건설에 비유하는 걸 좋아합니다. 교차로를 더 안전하게 만들기 위해 신호등을 설치하거나, 보행자를 위한 지하도가 있는 전체 다층 인터체인지를 구축하는 작업에 비유할 수 있습니다.
가장 기본적인 하위 수준 패턴을 이디엄이라고 합니다.
일반적으로 이디엄은 하나의 프로그래밍 언어에만 해당합니다.
가장 보편적인 상위 수준 패턴은 아키텍처 패턴입니다.
개발자들은 거의 모든 언어로 이러한 패턴을 구현할 수 있습니다.
다른 패턴들과 달리 아키텍처 패턴은 애플리케이션 전체의 구조 (아키텍처)를 설계하는 데 사용할 수 있습니다.
또한 모든 패턴은 패턴의 의도 또는 목적에 따라 분류할 수 있습니다. 이 책에서는 패턴의 주요 세 가지 그룹에 대해 다룹니다.
생성 패턴은 기존 코드를 재활용하고, 유연성을 증가시키는 객체 생성 메커니즘을 제공합니다.구조 패턴은 구조를 유연하고 효율적으로 유지하면서, 객체와 클래스를 더 큰 구조로 조합하는 방법을 설명합니다.행동 패턴은 객체 간의 효과적인 의사소통과 책임 할당을 처리합니다
1.3 누가 패턴을 발명했나요?
좋지만 아주 정확하진 않은 질문입니다. 디자인 패턴은 모호하고 복잡한 개념이 아니라 그 반대입니다. 패턴은 객체 지향 설계의 일반적인 문제에 대한 전형적인 해결책입니다. 한 해결책이 다양한 프로젝트에서 계속 반복되면 결국 누군가가 이름을 붙이고 해결책을 자세히 설명합니다. 이것이 기본적으로 패턴이 발견되는 방법입니다
패턴이라는 개념은『패턴 랭귀지: 도시 건축 시공1』(크리스토퍼 알렉산더)에서 처음으로 설명되었습니다. 이 책은 도시 환경을 설계하기 위한 ‘언어’를 설명하며, 이 언어의 단위가 패턴입니다. 패턴으로 창문이 얼마나 높아야 하는지, 건물이 몇 층이어야 하는지, 근처 녹지의 면적이 얼마나 넓어야 되는지 등을 설명할 수 있습니다.
이 개념은 에릭 감마, 존 블리시디스, 랄프 존슨, 리처드 헬름이라는 4명의 작가에 의해 정리되었습니다. 1994년에 이들은 『디자인 패턴: 재사용성을 지닌 객체지향 소프트웨어의 핵심 요소』 라는 책을 발간하였고, 거기서 디자인 패턴의 개념을 프로그래밍에 적용하였습니다. 이 책은 23가지의 객체 지향 디자인 관련 문제를 해결하는 패턴을 소개했으며 빠르게 베스트셀러가 되었습니다. 너무 긴 제목 때문에 사람들은 이 책을 ‘4인방 (Gang of Four)이 쓴 책’이라고 부르기 시작했으며, 곧 간단히 ‘GoF 책’으로 줄여 부르게 되었습니다
그 이후로 수많은 다른 객체 지향 패턴이 발견되었습니다. ‘패턴 접근법’이 다른 프로그래밍 분야에서도 인기를 얻으며 이제 객체 지향 디자인 외부에도 많은 패턴이 존재합니다.
2. 왜 패턴을 배워야 할까요?
현실은 당신이 패턴에 대해 아무것도 알지 못해도 수년 동안 프로그래머로 일할 수 있다는 것입니다. 실제로 많은 프로그래머가 패턴에 대한 아무런 지식 없이 업무를 수행합니다. 또 자신도 모르는 사이에 일부 패턴들을 구현하고 있을 수도 있습니다. 그럼에도 왜 패턴을 배워야 하는지, 그 이유들을 정리해 보겠습니다.
- 다양한 디자인 패턴은 소프트웨어 디자인의 일반적인 문제들에 대해 시도되고 검증된 해결책들을 모은 것입니다.
- 이러한 문제들을 다루지 않더라도 패턴을 알고 있으면 여전히 쓸모가 있는데,
- 그 이유는 패턴을 배우게 되면 객체 지향 디자인의 원칙들을 사용해
- 많은 종류의 문제를 해결하는 방법들을 배울 수 있기 때문입니다.
- 디자인 패턴은 당신과 당신의 팀원들이 더 효율적으로 의사소통하는 데 사용할 수 있는 공통 언어를 정의합니다.
- e.g. 당신의 팀이 디자인 패턴을 이해하면 업무 처리 중
- 당신이 ‘그 문제를 위해서는 그냥 싱글턴을 사용하세요’라고 말하면,
- 모두가 당신이 무엇을 뜻했는지 이해할 수 있습니다.
- 싱글턴 패턴에 포함된 개념들은 설명할 필요도 없죠.
3. 좋은 디자인의 특징
실제 패턴에 대해 논의하기 전에 소프트웨어 아키텍처를 설계하는 과정과 그 과정에서 목표로 삼거나 피해야 할 사항들에 대해 논의해 보겠습니다.
3.1 코드 재사용
모든 소프트웨어 제품을 개발할 때 가장 중요한 두 가지 지표는 비용과 시간입니다. 개발 시간이 짧으면 경쟁자들보다 일찍 시장에 진입할 수 있으며, 개발 비용이 낮아지면 마케팅에 더 많은 자금을 투자하여 더 광범위한 잠재 고객들에 접근할 수 있습니다.
코드 재사용은 개발 비용을 줄이는 가장 일반적인 방법의 하나입니다. 코드를 재사용하는 의도는 상당히 명백합니다.
무언가를 계속 처음부터 다시 개발하지 말고, 기존 코드를 새 프로젝트에 다시 사용하자는 것이죠.
이 개념은 이론상으로는 훌륭해 보입니다. 그러나 새로운 상황에서 기존 코드를 작동하게 하는 것은 쉽지 않습니다. 왜냐하면 컴포넌트 간의 단단한 결합, 인터페이스 대신 구상 클래스들에 대한 의존 관계, 하드코딩 된 작업과 같은 여러 가지 요인들이 코드의 유연성을 감소시키고 재사용을 어렵게 만들기 때문입니다.
디자인 패턴을 사용하는 것은 소프트웨어 컴포넌트들의 유연성을 높이고 재사용하기 쉽게 만드는 한 가지 방법입니다. 그러나 이 방법은 때때로 컴포넌트들을 더 복잡하게 만듭니다.
다음은 디자인 패턴의 선구자 중 한 명인 에릭 감마의 코드 재사용에서의 디자인 패턴의 역할에 대한 견해입니다
저는 재사용을 세 가지 수준으로 이해합니다.
가장 낮은 수준에서는 클래스들을 재사용합니다. 그 예로는 클래스 라이브러리, 컨테이너 및 컨테이너/반복자와 같은 어떤 클래스 ‘팀’이 있습니다.
반면 프레임워크들은 최고 수준에 있으며, 이들은 당신의 디자인 결정들을 정제하려고 열심히 노력합니다. 프레임워크들은 문제를 해결하기 위한 핵심 추상화들을 식별한 후, 해당 추상화들을 클래스들로 표현하고 그들 사이의 관계들을 정의합니다. 예를 들어 JUnit은 작은 프레임워크이며, 프레임워크의 ‘Hello, world’라고 간주할 수 있습니다. 이 프레임워크에는 Test , TestCase , TestSuite 및 관계들이 정의되어 있습니다.
프레임워크는 일반적으로 단일 클래스보다 입자들이 큽니다. 또한 프레임워크에 연결할 때는 어딘가를 서브클래싱하여 연결합니다. 그들은 ‘전화하지 마, 전화할께’라는 이른바 헐리우드 원칙을 사용합니다. 프레임워크는 사용자 지정 행동을 정의할 수 있도록 해주고, 당신이 어떤 작업을 수행할 차례가 되면 당신을 호출할 것입니다. JUnit도 마찬가지죠? JUnit도 당신을 위해 테스트를 실행하고 싶을 때는 당신을 호출하지만, 나머지는 프레임워크에서 작동합니다.
중간 수준의 재사용도 있습니다. 저는 패턴이 이 수준에 속한다고 생각합니다. 디자인 패턴은 프레임워크보다 더 작고 추상적입니다. 디자인 패턴은 몇 개의 클래스들이 서로 어떻게 관련되어 있으며, 상호 작용할 수 있는지에 대한 상세한 설명입니다. 클래스에서 패턴으로, 그리고 마지막으로 프레임워크로 이동할수록 재사용 수준이 높아집니다.
이 중간 수준 계층의 좋은 점은 패턴이 종종 프레임워크보다 덜 위험한 방식의 재사용을 제공한다는 점입니다. 프레임워크를 구축하는 것은 위험이 높을 뿐만 아니라 상당한 투자가 들어가는 일입니다. 패턴을 사용하면 구상 코드와 관계 없이 디자인 아이디어들과 개념들을 재사용할 수 있습니다.
cf. 에릭 감마가 말하는 유연성과 재사용: https://refactoring.guru/gamma-interview
3.2 확장성
변화는 프로그래머의 삶에서 유일하게 변하지 않는 것입니다.
- 윈도우용으로 비디오 게임을 출시했는데, 사람들은 이제 맥용 버전을 요구합니다.
- 그래픽 사용자 인터페이스 프레임워크에 네모난 버튼들을 만들었는데, 몇 개월 후에 둥근 버튼이 유행하게 되었습니다.
- 뛰어난 전자상거래 웹사이트 아키텍처를 디자인했는데, 불과 한 달 후 고객들이 전화 주문을 수락할 수 있는 기능을 요청합니다.
대부분 소프트웨어 개발자들은 이와 같은 상황들을 수십 번 이상 경험했을 것입니다. 이러한 상황들이 발생하는 데는 몇 가지 이유가 있습니다.
첫 번째 이유는 일단 문제를 해결하기 시작하면 문제를 더 잘 이해할 수 있기 때문입니다. 종종 개발자들은 앱의 첫 번째 버전의 개발을 끝마칠 때쯤에 문제의 여러 측면을 훨씬 더 잘 이해하기 때문에 처음부터 다시 개발하고 싶어 할 수 있습니다. 또, 개발자로서의 실력이 향상된 덕분에 작성한 코드가 쓰레기처럼 보일 수도 있습니다.
두 번째 이유는 통제할 수 없는 무언가가 변경되었기 때문입니다. 이는 많은 개발 팀들이 원래 아이디어에서 새로운 아이디어로 선회하는 이유입니다. e.g. 온라인 앱에서 플래시에 의존했던 개발자들은 브라우저들이 플래시에 대한 지원을 중단했을 때, 코드를 재작성하거나 마이그레이션해야 했습니다.
세 번째 이유는 목표들이 변했기 때문입니다. e.g. 당신의 고객은 앱의 현재 버전에 만족했고 이제 원래 기획 단계 미팅에서 언급하지 않은 11개의 ‘작은’ 변경을 수행하기를 원합니다. 사실 이러한 변경은 사소하지 않습니다. 당신의 첫 번째 버전이 훌륭하여 고객에게 더 많은 것들이 가능하다는 것을 보여준 것이죠
긍정적인 측면도 있습니다. 누군가 당신의 앱에서 뭔가를 바꿔 달라고 요청한다면, 그건 누군가 당신의 앱에 여전히 관심이 있다는 뜻이니까요
그러므로 모든 노련한 개발자들은 앱의 아키텍처를 설계할 때 미래에 변경들이 가능하게 하려고 노력합니다.