중간 정리

이쯤 해서 왜 "객체지향의 올바른 이해"라는 포스팅을 만들게 되었는지 그 동기를 설명하고 넘어가는 편이 전체적인 이해에 도움이 될 것이라고 생각한다.

이전 포스팅들에서 객체지향 4대 원칙이 나온 배경을 유연성의 예를 통해 설명하였다. 개인적으로 여러 책을 읽어보고 검색을 해 봤지만 이와 같은 방식으로 객체지향을 설명한 글은 없었다. 하지만 포스팅의 내용을 이해했다면 현실 세계에서 나온 개념을 프로그래밍 언어에서 차용했다고 보는 편이 더 타당하다는 점을 알 수 있을 것이다. 개인적으로 이 부분은 나름대로 확신하는 편이다. 하지만 그렇다고 해서 굳이 이미 사람들이 객체지향을 이해하고 있는 방식을 바꿔서 설명해야 할 필요가 있겠는지 하는 의문은 생길 것이다. 나는 그것이 필요하다고 봤다.


객체지향을 설명하는 일반적인 방식은 이렇다.

추상화(Abstraction)에 대해서는 공통된 속성과 행위를 추출하는 것으로 주로 설명한다. 이 설명이 틀린 것은 아니다. 하지만 공통된 속성과 행위를 추출하는 과정의 목적이 명확하지 않다. 유연성을 확보하기 위한 목적으로 설명하지 않기 때문에 추상화 과정이 필요한 이유를 설명하기가 어렵다. 그래서 어떻게든 가져다 붙이는 설명이 "속성과 행위를 중복 구현하지 않기 위해서"라고 말한다. 만약 추상화의 목적이 중복 구현의 방지, 즉 재사용이라면 일반적인 언어에서 말하는 작은 규모의 재사용, 즉 라이브러리와 무엇이 다른지를 명확히 해야 한다. 하지만 애초에 목표가 제시되지 않은 상태에서 추상화의 목적을 설명하기 때문에 그 본질적인 용도가 불명확해지는 것이다.

애초에 설명이 이렇게 시작하다보니 다른 개념들도 점차 모호해지기 시작한다. 캡슐화는 속성과 행위의 묶음이고, 이들 중에서 일부는 외부에 노출시키지 않는 것, 소위 정보 은닉을 통해 객체 내부 변경이 외부에 영향을 적게 미치도록 만든다고 말한다. 그래서 객체지향이 다른 언어보다 좋다고 이야기 한다. 캡슐화의 가장 큰 이점은 추상화를 통해 만들어진 객체(추상 객체라고 하자)가 그 고유한 타입을 가지게 되고, 이 추상화된 객체의 타입(추상 타입이라고 하자)을 통해서 여러 개별 객체가 공통으로 다루어 질 수 있음으로써 유연성이 확보된다는 점이다. 이 과정에서 캡슐화의 의미가 "공통의 속성과 행위에 타입을 부여하여 다루어질 수 있는 대상으로 만드는 것"이라는 정의를 성립시킬 수 있다. 따라서 캡슐화에서 가장 강조되어야 하는 부분은 타입의 부여이다. 하지만 캡슐화를 단순한 속성과 행위의 묶음 또는 일부 속성이나 행위를 외부에 노출시키지 않는 것이라고 정의한 덕분에 다른 개념들의 설명은 더욱 모호해진다.

상속에 대해서는 다른 객체의 속성과 행위 "만"을 가져 오는 것으로 보통 설명한다. 앞서 강조했듯이 캡슐화된 객체에 있어서 가장 중요한 것은 타입이다. 상속은 타입을 상속 받음으로써 그 타입으로 다뤄질 수 있도록 만드는 것이 핵심이다. 그래야 구체적인 타입이 아닌 상위 타입, 즉 추상 타입으로 다뤄지면서 유연성을 확보할 수 있게 된다.

다형성(Polymorphism)의 경우 역시 왜곡이 심하다. 다형성을 메소드 오버로딩과 혼돈하는 경우가 많고, 기껏해야 상위 타입으로 호출된 메소드를 하위 타입의 메소드로 대체되어 호출되는 것 정도로 말하는 경우가 대부분이다. 다형성은 하나의 타입이 서로 다른 타입으로 지칭될 수 있는 특성이다. 이 다형성은 객체지향 언어에서 상속을 통해 확보된다. 상속이라는 특성은 속성과 행위 뿐 아니라 타입도 상속시킨다. 이를 통해 상속을 받은 클래스는 자기 고유 타입 뿐 아니라 상위 타입도 가지게 된다. 이러면 가지고 있는 타입이 두 개가 되는데 이것이 다형성(multiple type)이다. 따라서 다형성이라는 단어만으로는 유연성을 이해하기 어렵다.


많은 소프트웨어 개발자들은 새로운 언어를 빨리 배우는 것이 자신의 능력과 연결된다고 생각한다. 그것 자체는 틀린 것이 아니다. 하지만 C언어와 같은 절차지향 언어를 쓰다가 Java와 같은 객체지향 언어를 배우게 되는 경우에도 이런 생각에 사로잡힌다. 특히 개발자들은 자신이 하는 분야에 대한 자부심이 크기 때문에 다른 분야 업무를 경시하는 경향이 있다. C언어와 객체지향 언어는 사용되는 분야가 많이 다르다. 언어를 빨리 배워야 뛰어난 개발자라는 생각과 다른 분야에 대한 경시가 객체지향 언어에 대한 이해 부족으로 나타난다. 빨리 배워서 기능 하나 빠르게 개발해서 보여주고 "쉽네!" 라고 빨리 말할 수 있어야 한다는 강박관념에서 언어를 배우는 것이다. 일반적인 형식의 객체지향 설명이 추구하는 방향이 딱 이런 정도다.

객체지향 언어는 애초에 프로그래밍을 시작할 단계에서부터 유연성을 염두해 두고 시작해야 하는 언어다. 프로그램을 구성해야 하는 요소(즉 객체)가 둘이 되었을 때부터 둘 간의 관계에 대해서 생각해보고, 이들의 관계가 확장될 소지가 있는지, 즉 유연성을 확보해야 할 필요가 있는지를 고려해야 한다. 또 이미 구현되어 있는 프로그램이라고 해도 서로 유사성이 있는 요소는 없는지, 그리고 유사한 요소들을 함께 다룰 수 있도록 함으로써 유연하고 간결한 프로그램으로 만들 수는 없는지를 생각해야 한다. 이런 과정에서 유연성을 확보하는 방법에 대한 일종의 청사진을 가지고 있다면 그 일이 매우 수월해질 것이다. 이것이 현실 세계에서 오케스트라 지휘자의 문제를 보여주고, 이를 객체지향 4대 원칙과 비교하면서 설명하게 된 계기이다.


이것을 통해 얻은 것은 무엇인가? 

우선 객체지향 언어를 배우는 과정에서 많이 간과되거나 잘못 설명되었던 개념들을 정확하게 정립할 수 있었다. 특히 객체지향 언어에서 "타입"이 얼마나 중요한지를 재발견할 수 있게 해주었다. 이제껏 일반적인 객체지향 도서들이나 블로그 들에서는 타입에 대해 거의 언급하지 않았거나 단편적으로만 설명했을 뿐이다. 하지만 이 포스팅을 통해서 객체가 속성과 행위의 집합이 아닌 타입과 속성과 행위의 집합으로 이해될 수 있었다. 그리고 캡슐화가 타입을 부여하는 과정이라는 점, 상속은 속성과 행위만이 아니라 타입까지도 물려 준다는 점, 마지막으로 다형성의 의미가 여러 타입을 가질 수 있는 특성이라는 점까지 이해할 수 있게 되었다.

객체지향 언어의 4대 특성이 왜 도입되었는지를 알 수 있었다. 객체지향이 실제 세계의 반영이라는 점은 많은 글들에서 설명하고 있다. 그러나 단순히 실세계를 반영하기 위해서 4대 특성을 도입했다는 것은 설득력이 부족하다. 앞서서도 이야기 했듯이 객체지향의 개념은 절차지향에 비해 이해하기가 어렵다. 굳이 더 어려운 개념을 도입해서 언어를 개발하고, 그렇게 개발된 언어가 지금처럼 널리 쓰일 수 있게 된 이유가 있어야만 한다. 유연성이라는 목적은 그 이유에 부합한다. 그리고 이해하기 어려운 개념임에도 불구하고 유연성이라는 목적을 명확히 이해하고 사용하면 객체지향을 빠르게 익히는데 많은 도움이 된다.

객체지향 언어의 목적이 유연성이라는 점을 이해하고 있고, 이 목적에 맞게 4대 특성을 이해하고 있으면 이제 디자인 패턴과 같은 설계적인 특성에도 빨리 다가갈 수 있다. GoF의 디자인 패턴 23가지 중 약 10가지는 그 목적이 유연성 확보에 있고, 앞서 설명한 유연성 확보 방식을 기반으로 구현된다. 나머지 패턴들 중 일부는 일부 특수한 목적을 위한 것이거나 객체지향 4대 특성의 일부를 활용한 것들이다.


Posted by 이세영2
,