객체지향 이야기 – 4.상속 구현(2)

대한민국 개발자와 객체지향 이야기 – 4.상속 구현(2)

재사용 관점에서 절차적 언어인 C가 실톱이라면, C++의 상속은 전기톱에 비유할 수 있다. 하지만 다중상속에 대해서는 C++의 대가들 사이에도 사용에 대한 견해가 천차만별이다. 스콧메이어는 조심해서 사용하길 권장하지만 다중상속의 장점을 이용한 응용(1997년)을 추천한다. 반면 스티브 맥코넬은 다중상속을 안전장치가 없는 1950년대식 전기톱에 비유하며 사용불가 입장을 고수한다. 여러 주장에도 불구하고 다중상속은 분명 실세계를 서술하는 데 있어서 명쾌한 부분을 갖고 있다. 또한 인터페이스와 같은 추상화 툴과 함께 사용되면 템플릿보다 훨씬 강력한 범용 프로그램을 제작 할 수 있다. 이번 시간에는 다중상속에 대한 올바른 이해와 구현 상속 시 다중상속을 피해 갈수 있는 대체 모델에 대해 알아본다.

정명수 ㅣmsguns.jung@samsung.com ㅣ 삼성전자 메모리사업부 플래시 소프트웨어 개발 관련 연구원

상속은 객체지향 언어가 이제까지 VOP(Value Oriented Paradigm), FOP(Feature Oriented Paradigm)이나 함수형 언어들과 함께 각광 받았던 큰 이유 중 하나이다. 그 만큼 소프트웨어 위기를 극복하는 데 있어서 재사용이 핵심적인 역할을 했다. 상속의 ‘판도라 상자’로 불리는 다중상속을 알아보기 전에 상속의 핵심인 동적 바인딩을 사용하기 위한 가상함수 사용에 대한 주의 점을 알아보고, 다중상속을 리모델링하는 방법을 알아볼 것이다. 동적 바인딩에 대한 이야기가 생소하다면 3, 4회(2007년 마소, 5, 6월호)를 참조하기 바란다. 가상함수를 사용하여 런타임 시에 사용될 메소드를 결정한다는 것은 객체지향 언어에서 가장 매력적인 항목이긴 하나 특정 메소드에 따라 그 의미가 조금씩 달라진다. 그러한 메소드가 바로 생성자와 소멸자이다.

가상의 생성자와 소멸자

상속 구조에서 생성자 호출 구조는 상위 클래스의 생성자로부터 하나씩 호출돼 하위 클래스의 생성자까지 전달된다. 반면, 소멸자의 경우는 하위 클래스의 소멸자로부터 호출돼 루트가 되는 클래스의 소멸자를 호출함으로써 Call history를 마감한다. C++에서 폴리모피즘을 적용하기 위해 상위 기본 클래스의 타입으로 파생 클래스의 포인터를 변환해 사용하면 생성자와 소멸자는 두 가지 문제를 갖게 된다. 우선 가상함수로 선언되지 않았을 때의 메모리 누수 발생과 같은 기본적인 문제가 발생한다. 다른 하나는 가상으로 선언돼도 생성자와 소멸자가 갖는 Call History때문에 생성자와 소멸자 내부에서 호출되는 메소드의 바인딩이 미묘한 문제를 갖게 된다. 더불어 생성자와 소멸자는 보통 직접 호출하지 않는 것이 관례이므로 눈에 보이지 않는 곳에서 프로그램에 치명적인 문제를 발생시킬 가능성이 높다. 정적으로 선언된 생성자와 소멸자 문제와 더불어 내부에서 호출되는 메소드에 의해 치명적 오류를 갖게 되는 상속 클래스를 예로 살펴보자(<리스트 1> 참조).

<리스트 1>과 같은 상속 관계를 가지는 Developer 클래스의 생성자와 소멸자의 문제를 짚어 보자. Developer의 생성자에서는 개발자의 이름과 고유 아이디를 할당 받는다. 물론 내부적으로 스트링을 저장하는데 자체적으로 char *를 쓰는 경우가 흔하지 않겠지만 어디까지나 생성자와 소멸자의 문제를 인식하기 위한 예제이므로 독자들의 양해를 바란다.

생성자와 소멸자를 가진 Developer 클래스의 문제는 무엇일까? Developer 클래스는 두 가지 문제점을 안고 있다. 흔히 이런 문제점을 발견하지 못하는 이유는 개발 1, 2년차의 C++개발자들이 C++의 클래스를 단지 구조체와 같은 정보 래퍼 수준에서 사용하기 때문이다.
즉 문제가 굴어질 이슈들을 겪어보지 못했기 때문이다. 가장 눈에 띄게 확인되는 부분부터 살펴보자. 우선 고질적으로 메모리 누수 문제를 껴안고 태어난다. Developer 클래스를 사용하는 예를 보면 좀 더 명확해 진다(<리스트 3> 참조).

상속구조의 소멸자는 가급적 가상으로 선언하자

<리스트 3>의 CreateInstance 메소드내에서 Developer 클래스가 Delete되는 순간에 클래스에 대한 소멸자가 어떻게 처리될지 생각해보면 현재 Developer 클래스의 문제를 알 수 있다. 일단 operator delete가 별도로 오버로딩 되지 않으므로 오리지널 delete를 호출한다. operator delete에 대한 문제는 C++ 최적화 문제(2006년 마소, 12월호)를 참고하길 바란다. 이 delete는 소멸자를 호출하는 데 C++는 Developer 클래스의 소멸자를 호출 순서에서 제외한다. 정확히 말하면 C++에서는 Devel oper의 존재를 알 수 없기 때문에 Developer의 소멸자를 호출하지 않는다. 결과적으로 이 코드는 m_cName과 m_cId에 대해 정상적으로 메모리를 해제하지 못해 메모리 누수를 일으킨다. <리스트 3>과 같이 아무것도 하지 않는 프로그램에는 크게 영향 받지 않겠지만, Developer 클래스를 여러 번 생성하고 삭제하는 프로그램이라면 얼마 지나지 않아 프로그램을 포함한 전체?? C++는 Developer의 소멸자를 알 수 없을까? 필자가 몇 회에 걸쳐 귀에 못이 박히도록 이야기한 동적 바인딩 문제가 바로 원인이다. 소멸자는 가상함수가 아니므로 People의 뷰를 통해 작업을 수행하기 때문에 소멸자가 호출 될 때 People의 소멸자만 호출하고 Developer 클래스의 리소스에 대해서는 메모리를 해제하지 않은 채로 Developer 클래스의 인스턴스는 사라진다. 이러한 문제는 소멸자를 <리스트 4>와 같이 가상으로 선언해서 C++에게 Developer의 소멸자를 인식 시킬 수 있다.

앞에서 말했던 것처럼 <리스트 4>에서 메모리 누수를 막기 위해 사용한 것은 소멸자에 virtual을 사용한 것 밖에 없다. 이렇게 함으로써 컴파일러는 소멸자의 바인딩 시기를 런타임까지 미룰 것이고 이는 Developer 클래스의 인스턴스가 delete될 때 기대하는 것처럼 Developer부터 메모리를 해제하고 상위 부모인 People 클래스의 소멸자를 정상적으로 호출한다. 가상함수를 써서 메모리 누수를 막는 것으로 폭탄 한 개를 제거 했다면 또 다른 폭탄은 무엇일까? <리스트 3>처럼 클래스를 변경해도 프로그램은 여전히 큰 문제를 안고 있다. 그것은 생성자로부터 호출되는 BuildDeveloper의 문제다. BuildDeveloper라는 메소드가 Developer의 클래스에서 미디어나 NV(Non volatile)메모리로부터 이전에 저장된 정보를 가져와 설정하기 위해 <리스트 5>와 같이 구현 됐다고 생각해보자.

구체 클래스가 인스턴시에이션 하면서 가장 먼저 기본 클래스의 생성자를 호출한다. 이때 생성자에 BuildDeveloper 메소드처럼 가상함수를 호출하는 부분이 있다면 이 가상함수는 어느 클래스에 바인딩 되어 동작을 수행할까?

가상함수의 생성자와 소멸자에서는 가상함수를 쓰지 말자

C++의 가상함수에서 한 가지 유의할 점은 가상함수로 선언된 메소드라고 해서 런타임 시에 모두 바인딩되지 않는다는 것이다. 예를 들면, 가상 생성자와 소멸자내에서 호출되는 경우이다. 예를 들어 People 클래스의 인스턴스를 만들 때 호출 되는 생성자가 가상함수 DisplayProperty를 호출한다고 생각해보자. Developer 클래스의 인스턴스를 만들면 가장 먼저 People 클래스의 생성자가 호출된다. 그때 DisplayProperty는 가상함수지만 People 클래스에서 구현된 DisplayProperty를 호출해 People의 속성을 출력한다.

그렇다면 왜 C++에서는 생성자 내부의 가상함수 호출을 정적으로 처리하는 것일까? 그것은 생성자 내부의 가상함수가 동적으로 바인딩 된다면 기초 클래스에서 호출하는 가상함수가 아직 초기화 되지 않은 파생 클래스의 리소스를 사용하기 때문이다. 아직 생기지도 않은 객체의 메소드를 쓴다는 것이 말이 되겠는가? 그래서 C++는 생성자나 소멸자에서 가상함수가 호출될 경우 더 이상 가상함수로 보지 않고 이를 동적으로 바인딩 시킨다. C#이나 자바 같은 다른 객체지향 언어에서는 이러한 문제를 C++와 같이 처리하지 않기 때문에 생성자나 소멸자에서 가상함수를 호출할 경우 치명적 오류가 발생할 수 있다. 그렇다면 C++는 원천적으로 문제를 해결 한 것으로 볼 수 있을까?

<리스트 2>에서 보면 현재 가상으로 선언된 생성자와 소멸자에서 가상함수를 호출하는 경우는 없다. 하지만 생성자에서 호출되는 BuildDeveloper가 <리스트 4>처럼 가상함수를 호출한다. C++가 생성자내에 가상함수의 사용을 무시해도 이런 식으로 가상함수가 생성자 자체에서 호출되는 것이 아니라 생성자가 호출하는 메소드의 내부에서 가상함수를 호출할 경우에 동적 바인딩이 된다. People 클래스와 Developer 클래스를 가지고 실제 문제가 되는 과정을 살펴보자. Developer 클래스를 생성하기 위해서 호출되는 People 클래스의 생성자가 실행될 때는 분명 Developer 클래스가 인스턴시에션 되기 전이므로 그 인스턴스가 메모리에 잡혀있지 않다. 하지만 가상함수는 Developer 클래스로 동적 바인딩되므로 생성되지 않은 Developer의 클래스, 즉 초기화 중인 클래스의 메소드에 접근하려 한다. 이는 메모리에 잡히지도 않은 메소드의 주소를 액세스하기 때문에 프로그램은 예외상황에 빠지게 된다.

간혹 MFC 프로그래밍을 할 때 클래스 초기화를 생성자내에서 하면 죽는 것을 경험한다. 마이크소프트는 생성자와 소멸자에서 이런 호출을 피하기 위해 Init에 관련된 메소드를 별도로 제공하고 사용자로부터 InitXXX와 같은 함수에서 초기화 하도록 권고하고 있다. 스콧메이어의 경우는 static으로 초기화 메소드를 제공하고 이를 생성자나 소멸자에서 사용하게 함으로써 클래스가 메모리에 잡히기 전에 일어나는 오류를 막아내는 방법을 제공했다.

하지만, static 멤버 함수는 실제 클래스에 속하는 메소드로 보기보다는 전역 함수로 보는 것이 적합하다. 객체지향 패러다임에서 특권을 가진 함수나 구조체 등은 제거되는 게 일반적이다. 그럼에도 불구하고 C++대가들이 묘수를 제공하는 것은 C++가 그만큼 OOP에 충실하지 못하다는 반증일 수도 있다. static의 사용은 생성자와 소멸자의 가상함수 호출문제 뿐만 아니라 예전 C++ 스펙이 RTTI를 지원 하지 못할 때, MFC에서 객체의 타입을 바로 알아 내주기 위해서도 사용됐다. 아직까지도 많은 MFC 응용 프로그램들에 잔존하고 있다.

다중상속

다중상속(Multiple Inheritance)은 상속 설계를 이야기 할 때 가장 골칫덩이로 간주 된다. 스콧메이어는 다중상속에 대해 이렇게 소개한다.

“C++의 다중상속에 대해서 한 가지 명백한 사실이 있다. 다중상속을 사용 한다는 것은 단일 상속에서는 존재하지 않는 복잡성의 판도라 상자를 여는 것과 같다.”

그럼에도 불구하고 왜 C++에서는 다중상속이 필요하게 되었을까? 실세계를 추상화하려면 단일 상속으로는 부족한 모델들이 간혹 존재하기 때문이다(사실 여기에 대해서는 많은 논란의 여지가 있을 수 있다). 이러한 모델들에 대해 많은 예제들이 있지만 필자가 본 것 중에서 다중상속의 필요성에 대해 가장 잘 표현하고 있는 것은 김태균 교수가 그의 저서(참고자료 2)에서 제시하는 박쥐의 상속 모델이다.

박쥐는 이솝 우화에서 나오듯이 새이기도 하고, 포유류이기도 하다. 독자들은 박쥐를 클래스로 모델링할 경우 어느 쪽으로 분류할 것인가? 포유류의 정의상 사자, 호랑이와 같은 클래스들은 이빨이 있고 젓이 있기 때문에 쉽게 포유류로 분류될 수 있고 참새나 독수리들은 부리가 있고 날 수 있는 날개가 있으므로 쉽게 조류로 분류한다. 하지만 박쥐의 경우 이빨, 날개 그리고 젓도 있으므로 어느 한쪽으로 포함시키기가 쉽지 않다. 이럴 때 다중상속이 아주 유용한 도구로 사용된다. 즉 이빨과 젓을 가진 것은 포유류 쪽에서 자료 구조와 연산을 가져오고 날개를 통한 비행과 같은 행동은 조류 클래스로부터 상속받아 박쥐를 구현한다. 이를 좀 더 쉽게 UML로 도식화 하면 <그림 1>과 같다.

<그림 1> 다중상속을 통해 모델링되는 UML

언어 의존적인 다중상속

박쥐 모델처럼 다중상속을 이용함으로써 실세계 모델을 단순하게 구현한다는 점은 누구도 부인하지 않는다. 다중상속은 많은 개발자의 이해관계가 얽혀있어 좋다 나쁘다로 단정 짓기 힘들다. 하지만 많은 개발자들이 객체지향 언어에 숙달되지 않은 개발자가 다중상속을 써서 시스템을 구현하는 데 있어서 부정적인 입장을 보인다. 다중상속에 대한 부정적인 의견 중 다중상속의 기능이 언어 의존적이라는 문제는 이 기능이 객체지향의 본질이라고 볼 수 없다는 것을 부각 시킨다. 객체지향 언어 중에는 다중상속을 지원하는 언어도 있고 지원하지 않는 언어도 존재하기 때문에 다중상속으로 모델링된 시스템을 구축할 경우 해당 구현 언어가 다중상속의 기능을 지원하지 않으면 다중상속에 대한 부분을 코드로 옮길 때 복잡해진다. 다중상속이 언어에 의존적이라는 말을 다른 관점에서 보면 이질적인 시스템 간의 포팅 시에 이식성이 현저히 떨어지는 약점을 가진다.

즉 자바의 경우 다중상속을 원칙적으로 허용하지 않으므로 다중상속이 적용된 C++로 제작된 시스템의 디자인을 자바나 C#으로 옮길 경우 이 부분을 포팅하기 위해서는 특정 모듈을 구현하기 까지 많은 시간과 비용을 지불할 수도 있다. 물론 자바의 인터페이스를 써서 다중상속을 유도할 수 있지만 이는 전체적인 시스템의 구조 변경이 불가피한 상황임을 부인하기 어렵다. 간혹 자바의 인터페이스가 다중상속을 구현하기 위한 수단으로 치부하는 개발자들이 있는데 자바의 인터페이스는 다중상속을 지원하기 위한 기능이나 수단이라기보다는 실체를 가지지 않는 인터페이스의 특징 때문에 다중상속이 가능한 것이라고 보는 게 올바르다. 이는 다음 기사에서 좀 더 자세하게 다룰 예정이다.

본론으로 돌아와 자바나 C#이 인터페이스 등을 통해 일부 다중상속을 허용하지만 객체지향 패러다임의 원칙을 가장 잘 보여주는 스몰토크가 OOP의 아버지로 불림에도 불구하고 다중상속을 지원하지 않는 것에 주목할 필요가 있다. 스몰토크 같은 객체지향 언어가 다중상속을 지원하지 않는 것은 다중상속이 가지는 특징을 구현하는 데 있어서 다중상속의 기능을 객체지향의 다른 특징들을 써서 객체지향 소프트웨어를 얼마든지 구현할 수 있기 때문이다. 이제 박쥐 모델을 다중상속 사용을 지양하는 방향으로 변경해 어떻게 구현되는지 살펴보자.

다중상속의 본질적인 문제

그렇다면 다중상속은 언어에 종속적인 단점 이외에 다른 단점은 없는 것일까? 만약 언어에 종속적인 문제가 다중상속의 문제라면 시스템 구현에서 얼마든지 다중상속을 사용할 수 있다. 시스템을 구현하며 언어를 다시 한 번 넘나들며 포팅한다면 포팅이라고 하기보다 새로운 모델을 가지고 구현하는 것이나 마찬가지다. 실무에서 제작된 시스템을 언어 차원을 넘어 다시 구현하는 경우는 드물기 때문이다. 물론 클라이언트에 따라 여러 언어로 구현하는 경우도 있지만 대부분의 경우 요구사항이 언어의 플랫폼을 넘나드는 경우는 드물다. 안타깝게도 다중상속은 언어에 대한 종속적인 단점 이외에 본질적으로 치명적인 단점을 지녔다.

<그림 1>의 박쥐의 다중상속 모델에서 지난 호에서 이슈가 됐던 IS-A관계를 다시 한 번 고려해 보자. IS-A 모델조건을 만족하려면 “박쥐는 포유류인가?”에 대한 질문이 명확한 해답을 가져야한다. 하지만 질문에 정확히 대답하기란 어렵다.

‘박쥐는 날아다니기 때문에 포유류가 아니다’라고 대답할 수도 있다. 더 나아가 다중상속에 대한 정의대로 ‘박쥐는 포유류이면서 조류이다’라는 IS-A 모델을 만족 시킬 수 있겠는가? 결국 다중상속의 사용은 실세계에 대한 모델링에 대해 본질적인 문제를 가진다.

다이아몬드 타입 모델링

다중상속을 지원하는 언어의 구조적 문제를 살펴보자. 이는 다중상속의 본질적인 문제로 실세계를 잘 못된 객체지향적 방식으로 모델링한다. 이른바 다이아몬드 타입으로 다중상속이 이루어진 경우다. 다이아몬드 타입의 다중상속의 경우 다른 부모들로부터 다중상속을 통해 구현된 클래스의 조부모가 같은 경우이다.

<그림 2> 전형적인 다이아몬드 타입 모델링

<그림 2>의 다이어그램에서 Bat는 조부모의 메소드를 조류와 포유류, 두 개의 클래스를 통해 두 번 상속받게 된다. 다시 말해 동물에 Sleep을 포유류 쪽으로 한번 상속 받고 또 다른 쪽으로는 조류로부터 상속받았기 때문에 개발자는 Bat의 Sleep을 사용함에 있어서 물려받은 두 개의 Sleep()을 구분하며 프로그래밍 해야 한다. 이러한 특성은 Sleep과 같은 메소드뿐만 아니라 다이어그램의 성별(Sex) 및 나이(Age)와 같은 데이터 멤버도 똑같이 영향을 미치므로 다중상속의 사용 시 개발자의 각별한 주의를 요한다.

다중상속 리모델링

다중상속이 있다면 Aggregation으로 바꾸어라

그렇다면 다중상속의 기능을 사용하지 않고 다중상속으로 모델링 된 상황을 어떻게 정상적으로 변경 할 것인가? 대부분의 다중상속의 경우 두 가지로 변형 모델링이나 구현이 가능하다.

1) 다중상속이 이루어진 말단 클래스를 완전히 독립적인 클래스로 제작
2) Aggregation을 통해 다중상속의 부모 클래스 계층을 일부 컴포넌트화

다중상속이 이루어진 말단 클래스를 완전히 독립적인 클래스로 제작하면 상위 Bat와 같은 말단 클래스의 경우 포유류와 조류의 부모 클래스와 무관하게 만들어진다. 하지만 Bat가 가지는 자료 구조 및 연산을 개별적으로 설계 및 구현을 한다. 지난 호에서 논의했던 바와 같이 이런 방식으로 데이터 멤버가 반복되고 코드가 중복되는 것은 재사용성이라는 강력한 도구를 완전히 무시한 설계이다. 그러므로 다중상속을 새롭게 모델링하려면 두 번째 방법인 Aggregation을 통해 부모에게서 필요한 자료구조 및 연산을 부분적으로 조합하는 방식을 선택할 수 있다. 물론 Aggregation으로 새로 모델링하는 부분에 대해서는 설계자나 개발자의 취향이나 가치관에 따라서 충분히 다른 모델들로 다중상속을 표현할 수 있다.

 

 

 

<그림 3> Aggregation을 통해 재구성 예1

<그림 3>은 조류로부터 상속받아 일반적인 자료구조와 연산을 따오고 포유류로부터 필요한 연산들을 Aggregation을 통해 조합한 구조이다. 짐작하건대 이 모델에 대한 설계자의 생각은 박쥐는 조류이지만, 박쥐의 일부 기능이 포유류의 기능과 같기 때문에 그 기능을 이용해야 한다고 판단한 것 같다. 물론 이와 반대로 모델링이 가능하다.

<그림 4> Aggregation을 통해 재구성 예2

<그림 4>는 <그림 3>의 다이어그램과 달리 박쥐는 포유류지만 일부 기능이 조류의 기능과 유사하므로 이러한 기능을 Aggre gation을 통해 가져 오겠다는 것이다. 두 가지 방법의 Aggre gation이외에 박쥐는 아예 포유류도 아니고 조류도 아니지만 포유류와 조류의 일부 기능이 각각 유사하기 때문에 <그림 5>와 같이 일반화나 특수화와 같이 상속받지 않고 Aggregation으로만 조합해 구성하는 경우도 있을 것이다. 물론 Aggregation과뿐만 아니라 Composition처럼 Bat 클래스의 생명 주기와 같은 라이프 사이클을 가지는 Bird와 Mammalia를 통해 조합할 수 도 있다. 단 Aggregation이 좀 더 포괄적인 의미를 가지므로 범용적인 모델링에 적합하다.

<그림 5> Aggregation을 통해 재구성 예3

다중상속을 피해 이에 대한 클래스를 리모델링하는 과정을 살펴봤다. 정리하면, 독자나 필자가 주의해야 할 것은 한가지다. 다중상속이 실세계의 문제를 추상화 시키는데 분명 큰 도움이 되는 도구지만 구현 시에 여러 가지 제약사항이나 어려움이 따르기 때문에 설계자 및 개발자는 이에 대한 충분한 경각심을 가져야 한다. 논리적 모델링 시에 가급적 <그림 3>이나 <그림 4>와 같이 중요하다고 생각되는 부모 클래스 한쪽으로부터 상속을 취하고 나머지 기능은 Aggregation을 통해 다중상속 모델을 변형하는 것이 바람직하다.

설계의 중요성

간혹 설계나 재사용, 유연성을 고려한 프로그래밍이 비난을 받기도 한다. 그도 그럴 것이 시스템을 설계에 투자한 비용만큼 효과적으로 구현하지 못하는 개발자들이 존재하기 때문이다. 설계과정은 아무리 작은 프로그램을 개발하더라도 몸에 베이도록 고민해보는 게 좋다. 어느 조직이나 처음에 개발이 이슈화가 되고 개발을 통한 상품이 실체화되기 전까지는 소위 ‘날코딩’을 하는 개발자가 필요하다. 어떤 사람들을 ‘날코딩’을 ‘몸빵 코딩’이라고도 한다. 이러한 코딩을 구사하는 개발자는 조직에서 빨리 상품화가 진행되도록 고무적인 역할을 한다. 하지만 조직이 커지고 상품이 성공할수록 당연히 막무가내 식 코딩을 하는 개발자 보다 관리자가 필요하게 되고 막연하게 마감 날짜만 기다리며 재촉하는 관리자보다는 체계적인 설계자가 필요하다.

독자들이 최소한 개발자라는 마인드를 가지고 살아가려면 코딩보다는 설계측면에서 중요하게 되는 것들을 고려하며 시스템을 구성해보는 경험이 필요하다. 설계는 단지 재사용성을 높이고 유연한 시스템을 만들기 위한 것이 아니다. 시스템에 있어서 퍼포먼스, 메모리 운용, 코드 이미지 사이즈, 하드웨어의 제약사항등 설계에서 충분히 고려할 사항들은 너무도 많다.

C++이라는 언어는 C와 같은 절차적 언어와 달리 분명히 코딩에 있어서 개발자의 수고를 덜어준다. 대신 설계 작업에 개발자가 좀 더 많은 시간을 할애 하도록 설계와 구현의 중간 다리 역할을 맡는다. 설계와 구현을 번갈아 가며 시스템을 구성하는 나선형 개발 프로세스를 사용하면서 막무가내 식 코딩을 하는 것은 부끄러운 일이 아닐까 ? 3회에 걸쳐 모델링과 모델링 평가 그리고 모델링 이후 구현 이슈에 대해 언급하는 이유도 이러한 소프트웨어 엔지니어링 마인드를 갖추기 위함이다.

개발자는 다른 사람들이 자신이 한 것을 바탕으로 또 다른 것을 만들 수 있도록 자신의 작업을 설계하려고 노력해야 한다. 독자들이 어떤 문제를 해결하기 위해 문제를 정의하고 다이어그램을 그릴 때 누군가 여러분을 한심하게 평가 한다고 고민할 필요가 없다. 설계를 무시하는 개발자는 일분에 500타를 치니, 하루에 1200라인의 코드를 만들어 낸다고 말하는 사람과 다를 바 없기 때문이다.

참고 자료

1. Addison Welsey, Scott Meyers. More Effective C++
2. 배움터, 김태균 저, K교수의 객체지향 이야기

제공 : DB포탈사이트 DBguide.net
출처 : 마이크로소프트웨어 2007년 11월

답글 남기기