Design Pattern 강의 시작하면서 : 디자인 패턴이란? 왜 필요한가 ?

오늘부터 "GoF 디자인 패턴! 이렇게 활용한다"라는 책을 통해 디자인패턴을 쭈욱 정리해보려고 합니다.
물론 내용에 대한 참고는 책에서 하겠지만, 이를 활용하여 class 를 직접 설계, 구현하는 것은 되도록이면 제가 직접 한 내용을 올릴 것입니다. 물론 책의 코드를 이용하는 경우도 있겠습니다.

최근 c++ 을 통해 프로젝트를 진행하고 있는데, 설계 시에 고려할 것들이 c 와는 다른 경우들이 많습니다. 설계의 접근 방식부터가 c 와는 근본적으로 다르죠. 그 동안 c 에 익숙해져 있던지라 c++ 로 좋은 설계를 하는 것이 만만치 않다는 것을 느꼈습니다.

처음에는 c 로 설계를 하다가 일주일 정도 진행한 설계를 버리고 c++ 로 방향을 바꾸었습니다.
왜냐하면, 제가 진행하는 프로젝트에서는 공유메모리를 사용하는데, 모든 관리 정보들을 공유메모리에 둘 뿐 아니라 저장하려는 모든 정보들도 잘게잘게 쪼갠 공유 메모리의 약속된 장소에 저장됩니다.
(사실은 공유메모리를 이용한 DB 를 개발하고 있습니다. Row Level Lock 과 MVCC, 복구 등의 기능을 모두 제공해야 합니다.)

그러다 보니, 각 모듈 별로 자신이 관리하는 영역의 메모리 시작 지점이 다르고 모양도 다르게 생겼습니다. 당연히 각 모듈이 하는 일도 제각기 다릅니다. 이를 c 로 구현하려고 하면, 자신이 사용하는 영역의 메모리 주소들을 항상 함수마다 달고 다녀야 합니다. 각 자료구조의 저장 지점을 알아내려면 적어도 공유메모리 세그먼트의 시작주소는 알고 있어야하기 때문이죠. 시작 주소가 없다면 해당 세그먼트의 특정 위치에 있는 영역을 찾아가는 것이 불가능하죠. 코드를 짜다 보니 이렇게 주소를 전달하고 이를 통해 특정 영역을 가기 위한 주소 획득 매크로를 작성하고...
이런 일들이 너무 복잡하고 짜증이 났습니다.

그래서, 이런 형태는 객체지향으로 설계하는 것이 맞겠다는 결론을 내리게 된 것입니다.
객체 지향으로 설계하면 각 모듈의 매니저 class 를 설계하고 각 class 객체는 자신이 접근할 영역의 시작 포인터는 멤버 변수로 가지고 있으면 됩니다.
멤버함수 내에서는 당연히 인자로 넘어오지 않아도 객체 자신(this)의 멤버 변수 포인터를 바로 사용할 수 있으니 아주 편리합니다.

예를 들어 볼까요 ?

DB API 를 통해 만약 사용자가 "aaaaa" 라는 데이터를 DB 에 Insert 를 했다고 칩시다.
그러면, DB 내부적으로는 비어있는 공간을 하나 할당하여 그 장소에 "aaaaa" 를 저장해 두어야 합니다.
그 공간 하나하나를 slot 이라고 부릅니다.

이 때, 비어있는 slot 공간을 찾아내는 함수이름을 alloc_slot 이라고 합시다.
alloc_slot() 함수는 prototype 이 어떻게 생겼을까요 ?
아마도 아래와 같을 것입니다.

char * alloc_slot( char * shm_seg_start );

alloc_slot 내에서는 어떤 식으로건 free 한 slot list 를 마찬가지로 공유메모리 내에 관리하고 있을텐데, 그 공유메모리 주소를 알아야만 free 한 slot 을 추출해낼 수 있겠죠.
그러니, 사용자는 alloc_slot 에게 그에 대한 주소를 제공해야 합니다.
그렇게 주소를 제공하면 alloc_slot 내에서는 그 주소를 바탕으로 free slot 들에 대한 list 를 확인한 후 하나를 골라서 해당 slot 에 대한 포인터를 리턴하게 될 것입니다.

이를 class 로 구현해볼까요 ?

class slot_allocator
{
private:
    char   * shm_seg_start;
public:
    char   * alloc_slot();
};

어떤가요 ?
alloc_slot 의 주소 포인터 하나가 사라졌죠 ?
사용자는 그냥 slot_obj->alloc_slot() 과 같이 객체의 함수를 인자없이 호출만 해주면 바로 빈 slot 에 대한 포인터가 리턴됩니다.
참 편리하죠 ?

c 로는 디자인 패턴을 구현하는 것이 아주 어렵습니다.
물론 불가능하지는 않겠지만 객체 지향 언어보다 훨씬 많은 것을 고려해야 할 것입니다.
그냥 그렇게는 생각하지도 않는 것이 좋겠습니다.

서론이 길었습니다만, c++ 로 프로젝트를 진행하려고 해도 당연히 초기 설계가 프로젝트의 성패를 좌우합니다. 물론 꾸역꾸역 어떤 기능이나 사용자 요구사항을 구현해낼 수는 있겠죠.
잘 구현하면 성능과 안정성도 디자인 패턴의 고려없이 얻어낼 수 있습니다.
불가능하지는 않습니다.

하지만...!!!

그러면 안된다는 것을 제가 심각하게 체험한 순간이 있습니다.
그렇게 디자인 패턴이란 개념없이 순수 c 로 성능과 안정성 모두를 구현해낸 저의 머리 좋은 동료의 특정 솔루션 소스를 보게 되었습니다. 그런데, 그 소스량이 약 5 만 라인 정도 되었습니다만, 과연 다수의 사람들이 유지보수를 할 수 있을까싶을 정도로 상당히 복잡하게 다가왔습니다.
그 코드가 생기게 된 사상을 이해하지 못하면 전혀 코드를 읽을 수 없었습니다.
사상을 이해하고 보더라도 이 코드를 과연 내가 나중에 자유롭게 유지보수할 수 있을까하는 의문이 들었습니다.
물론 Detail 한 경험이 많지 않은 상태에서 극도의 Low Latency 와 복잡한 Thread 간 동시성 제어를 해야하는 쉽지 않은 솔루션을 그정도까지 구현해낸 것만 해도 대단한 것임은 분명합니다.
훌륭한 결과임에는 틀림없지만 IT 프로젝트 성격 상 다수의 사람이 협업을 통해 관리해야한다는 면에서는 약간 아쉬운 점이 남는다는 생각을 했습니다.

10 년이 넘게 이 업종에 종사하면서 제가 좋은 코드에 대해 내린 결론은 이겁니다.

"다른 사람이 볼 때 마치 자기가 짠 코드로 착각할 정도로 coding convention 을 잘 지켜야 하고, 코드를 소설책 읽듯이 흐름이 한 눈에 들어오는 형태로 구현해야 하며,
특정 기능을 하나 추가하는 것이 아주 쉬운 구조여야 한다.
그리고, 중요 로직의 첫 부분
에는 반드시 그림과 설명 주석을 잘 달아서 작성자의 사상을 읽을 수 있어야 한다."

결국 이말은 "그 어떤 사람이 와도 되도록 손쉽게 유지보수할 수 있는 코드"가 좋은 코드라는 것입니다. 물론 그 이전에 코드가 그 시스템에서 요구하는 성능과 안정성을 만족해야하는 것은 너무나 당연한 것이겠죠. 극단의 Low Latency 를 추구하는 시스템에서 사용할 솔루션을 개발하다 보면 모듈화와 성능 두마리 토끼를 다 잡는 것이 그리 쉬운 일은 아닙니다. 하지만, 아주 일부의 성능을 포기하고 모듈화가 가능하다면 저는 그렇게 하는 것이 맞다는 입장입니다. 물론 아주 일부의 성능 포기일 때만입니다. ^^

디자인 패턴(Design Pattern)은 이런 의미에서 아주 중요합니다.

디자인 패턴이라는 것이 아주 많은 선배들이 겪었던 설계 상의 시행착오들을 수십가지 패턴으로 묶어서 정형화하여 정리한 것입니다.
이렇게 정형화되어 표준처럼 정리가 되어 있으면, 개발자끼리 설계에 대한 이야기를 할 때 같은 용어로 통일하여 사용할 수 있어서 장황한 말로 설명할 필요가 없습니다.
"이 쪽 모듈은 singleton 패턴을 이용해서 객체 하나만 생성하도록 하는게 좋겠어요"
이 말 한마디로 몇 분의 설명 시간을 줄일 수 있다는 말입니다.
그리고, 당연히 선배들이 겪었던 시행착오를 사전에 차단할 수 있는 좋은 설계를 할 수가 있겠죠.
위에서 말한 것처럼 디자인 패턴에 대한 이해가 없더라도 꾸역꾸역 목적을 달성할 수는 있겠지만, 그것이 좋은 코드인가는 의문이 남습니다.

객체 지향 프로그램을 만들 때 디자인 패턴에 대한 구현 경험이 많은 사람과 그렇지 않은 사람 간의 설계 능력은 아마도 하늘과 땅차이는 아닐지라도 하늘과 구름 정도의 차이는 있지 않을까요 ? ^^

끝으로 임백준씨가 "소프트웨어 산책"이라는 책에 언급했던 글을 남겨봅니다.

디자인 패턴을 공부하는 목적은 카탈로그의
목록을 외우는 것이 아니라 바로 패턴의 철학을 이해하는 것이다.
패턴의 철학은 기존 객체나 알고리즘의 수정을
억제함으로써 유지보수를 향하고 있다.
그래서 패턴을 학습한 프로그래머는 유지보수를 고민하게 된다.
그것이 좋은 프로그래머다.

You may also like...

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x