Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

프로그래머 토론 : 절자치향과 객체지향 프로그래밍에 관한 토론

나느 15년 이상 주로 펄을 이용해서 다양한 종류의 프로그램을 만들어 왔다. 이러한 개인적인 프로그래밍 경험에 비추어 OOP(객체지향 프로그래밍)이 PP(절차지향 프로그래밍)에 비해서 가지는 장점이 무엇인지 여전히 이해가 가지 않는다.

나는 이 주제에 대한 토론을 가지고 싶다. 물론 나 역시 OOP(:12)와 PP를 모두 다루긴 하지만, 나 스스로 PP 진영에 강력하게 속해있다고 주장한다. 간혹 나는 버스를 놓치고 있는게 아닌가 ? 실수를 하고 있지 않은가 ? 라는 생각을 하곤 한다. 최근 Perl 6가 매우 강력한 OOP 프로그래밍 기반을 제공하며, 순수 OOP를 지원할 것이라는 얘기를 들었기 때문에 더욱 그러하다. 비록 Larry Wall이 OOP를 지향하는 방향으로 펄을 개발해 가고 있지만 나는 거기에 뭔가 실수가 있지 않을까 그렇게 생각하고 있다.

OOP에 대한 나의 생각을 요약하자면 이렇다. OOP는 읽기에 매우 어려우며, 관리하기도 쉽지 않다. 사용하기도 어렵다. PP는 매우 직관적이며, 앞이 명확히 보인다. OOP는 직관적이지 않으며 - 추상적이기 때문에 직관적이지 않는 것이 어쩌면 당연한 것일지도 모른다. - 앞이 뚜렷하지도 않다. 안개에 쌓여있는 느낌이라고나 할까. 안개를 헤치고 나가면 신천지가 기다릴 수도 있겠지만 말이다.

OOP에서는 문서화가 매우 중요하며, 문서화를 위한 별도의 툴(Doxgen 같은)들이 존재한다. 이들 툴을 사용해서 체계적으로 문서를 관리하지 않으면 코드 읽기가 매우 힘들다. 반면 내가 지금까지 보아온 PP방식의 프로그램들은 코드 자체가 문서다. 코드는 쭉 따라 읽을 수 있으며, 읽는 자체로 이해가 된다. 물론 이것은 당연한 특징이라 할 수 있을 것이다. PP는 말그대로 순차적인 코드의 흐름을 가지기 때문이다.

OOP코드를 읽으면서 나는 마치 성운에서 헤메는 느낌을 받고는 한다. 성운에 있는 수많은 별들을 따라가면서 어떤 규칙적인 흐름을 찾기 위해 노력하는 느낌이다. 예컨데, 밤 하늘 은하수에서 별자리를 만드는 것이라고나 할까 ? 뒤로 가기도 하고, 몇 단계 점프하기도 하고, 경로가 꼬이기도 한다. PP는 위에서 아래로 쭉읽으면 된다. 점프는 몇몇 특수한 경우를 제외하면 거의 사용되지 않는다.

나의 이러한 생각에 대해서 어떤 의견을 가지고 있는지 말해주면 좋겠다. 나는 어떤 방법을 비난하거나 혹은 홍보하려는게 아니다. 난 배우기를 원하고, 마찬가지로 배우려는 생각을 가진 누군가로 부터 응답을 받기를 원한다. 대략 다음과 같은 주제들에 대한 당신의 생각을 배우기를 원한다.
  1. OOP로 할 수 있는데 PP로 못하는 것. 혹은 PP로 할 수 있는데 OOP로 못하는 것
  2. OOP가 PP에 비해서 가지고 있는 잇점들
  3. OOP와 PP의 성능 이슈
  4. 관리
  5. 재사용
  6. 읽기 쉬움

이에 대한 답변들

문화적 차이와 난이도 상승

나는 오랜 시간 소프트웨어 개발을 해왔다.

OOP의 진정한 문제는 때때로 그것을 제대로 이해하기 위해서 심리학자나 철학자 정도를 필요로 한다는 것이다.

일반적으로 추상은 문화적 배경의 영향을 많이 받는다. 물론 절차지향적인 처리도 문화적 배경의 영향을 받는다고 할 수 있지만, 처리 방식의 단순/명로함으로 인해서 그리 많은 영향을 받지 않는다. 즉 동양인이든 서양인이든 절차지향적 코드는 이해하는데 어려움을 겪지 않는다.

객체지향은 그 자체가 문화적 영향을 크게 받는다. 예를 들어 동양인들과 서양인들은 객체에 대한 시각이 전혀 다르다. 서양인의 문화는 개인주의적 문화로 아리스토텔레스 시대부터 사물을 독립된 단일 객체로 인식하는 문화에서 살아왔다. 하지만 동양인은 의 문화, 즉 독립된 객체가 아닌 모든 사물이 기의 흐름속에 묶여있는 식으로 본다. 예컨데, 똑같은 그림을 보여주더라도 동양인과 서양인은 전혀 반응이 다르다. 주변사람이 모두 찡그리고 가운데 한사람만 환한 모습을 하고 있을 때, 서양인에게 가운데 사람의 상태를 물어보면 행복해 보인다고 하는 반면, 동양인들은 불행해 보인다고 한다.

저혀 다른 문화적 틀을 가지고 있다는 얘기다. - 이와 관련된 자세한 정보는 동과 서를 참고하자.

문화기반에 따라서 전혀 다른 시각의 코드가 만들어 질 수 있다는 것이며, 이는 OOP의 이해를 어렵게 하는 요인이 된다는 점이다. 특히 문화적 동질성을 확보하기 힘든 요즘에서는 더욱 그렇다. 디자인 패턴이라는 것은 정형화되고 약속된 방법을 제시함으로써, 추상화의 이러한 문제를 해결하기 위한 목적에서 나온 것이다. 절차지향에서는 패턴이 중요하지 않다.

이해가 어렵게 되면, 유지/보수에도 많은 비용이 소비된다. 계층적 추상화가 복잡함을 감추어주므로 유지/보수 비용이 적게 든다는 것은 추상의 잇점만을 고려한 생각이다. 절차지향적 프로그램은 적당한 수준의 프로그래머라고 하더라도, 높은 난이도의 프로그램을 분석하는데 어려움을 겪지 않는다 (개발하는 것은 다른 문제겠지만). 하지만 높은 난이도의 OOP 프로그램을 활용하려면, 그만큼의 경지에 다다른 프로그래머가 필요하다.

OOP를 사용하는 두가지 큰 이유

저는 두 가지 이유 때문에 큰 프로그램의 개발에 OOP를 사용하는 경향이 있습니다. 하나는 구문상의 문제이고 다른 하나는 실용적인 문제입니다.

주위에 있는 작은 데이터의 조각을 관리하는 프로그램을 만든다고 가정해 봅시다. 분명히 당신은 결과를 달성하기 위해서 OOP를 사용할 필요는 없습니다.

OOP에서는 클래스안에 데이터를 저장하기 위한 공간과 함께, 데이터를 처리할 메서드들을 모두 집어 넣을 수 있습니다. 이제 당신은 ->만을 이용해서 데이터를 다룰 수 있습니다. 이 방법은 단순하며, 실수할 가능성이 거의 없습니다. 반면 PP에서는 더 어럽습니다. PP에서는 메서드와 데이터가 분리되어서 독립적으로 존재합니다. 그래서 보통은 구조체를 선언하고 메모리를 할당해서 이것을 포인터로 메서드로 넘기게 됩니다. 메서드와 구조체가 분리되기 때문에, 프로그래머는 메서드의 이름과 구조체의 이름을 매우 세심하게 결정해야 합니다. 실수하기가 쉽기 때문이죠. 그래서 나름대로의 접두사, 접미사 규칙을 만들어서 관리하게 됩니다. 이 관리 규칙은 만들기가 매우 까다롭습니다.

다음은 문서 파일의 마지막을 출력하기 위해서 만든 함수입니다. 전체 문서는 tail 프로그램 만들기에 있습니다.
/* 
 * tail 관리를 위한 구조체 
 */ 
typedef struct _TAIL 
{ 
    FILE *fp;            // 파일 스트림  
    char filename[256];  // 오픈한 파일 이름 
    int fd;              // 파일 스트림에 대한 파일 지정자 
    int revsize;         // 최근에 읽었던 파일 크기  
} TAIL; 
 
TAIL *opentail(char *fname); 
int readtail(TAIL *LTAIL, char *buf, size_t size, int sec); 
void closetail(TAIL *LTAIL); 
위의 코드들은 접미사 규칙으로 tail을 사용하고 있군요. 그리고 TAIL 구조체를 정의 해서 이것을 포인터로 넘기는 것으로 3개의 함수들을 연결하고 있습니다. 직관적이지 않다는 것을 느낄 수 있습니다. OOP라면 하나의 클래스에서 모든 것을 해결할 수 있습니다.

실용적인 또 다른 이유는 상속에 있습니다. 많은 프로그래머들이 OOP를 어렵게 생각하는 이유로 상속을 들기는 합니다만, 얻을 수 있는 잇점이 있습니다. 객체지향의 상속 설명을 위해서 가장 널리 사용되는 예제 중의 하나로 Shape가 있습니다. 삼각형, 원, 사각형 혹은 다른 다각형의 면적을 구하기 위한 (혹은 그리기 위한)예제 입니다. 상속을 이용하면, 원형이 되는 Shape 클래스 하나를 만들고 새로운 도형이 추가될 때마다 상속해서 구현하면 됩니다. 같은 일을 하는 클래스 이지만 독립된 클래스로 존재하기 때문에 개발,유지,보수가 수월합니다. PP를 이용할 경우 switch-case를 이용하거나 전혀 다른 여러 개의 함수를 만들어야 합니다.

OOP로 할 수 있는데 PP로 할 수 없는 것 혹은 그 반대의 경우

없다. OPP와 PP의 이슈는 무엇을 할 수 있는가가 아니고 어떻게 할 수 있는가 하는 것이다. 만약 프로그램의 작성이 필요하면, 당신이 이미 프로그램한 컴포넌트가 필요하거나 아니면 나중에 필요할지도 모를 컴포넌트가 있을 것이나 퍼포먼스가 반드시 필요한 것은 아니다. 또는 다른 사람들이 개발하는 동안 도울수도 있고 또는 상대적으로 클수도 있다. (다른 사람의 역할이 클수도 있다는 얘기인것 같음). 그러면, 내 생각에는 OOP 는 유리할수도 있다. 그렇지 않다면 PP로 갈수도 있다.

OOP 혹은 PP가 가지는 장점들

당신이 프로그램을 개발 할때, 이미 만들어져 있는 어떤 기반들 예를 들면 다양한 컴포넌들을 필요로 하거나 그 기반위에서 다른 개발자들과 협업하면서 작업을 진행해야 할때, OOP의 추상화는 이를 수월하게 해준다. OOP는 사물을 단순화 할 수 있으며, 또한 여러 객체를 통합하는 것도 용이하다. 이는 OOP가 가지는 장점이다. 물론 PP로도 이러한 것들이 가능하지만 같은 능력을 가지고 있을 경우 OOP가 더 낫다.

OOP 혹은 PP로 했을 때의 성능상의 이득

각각의 방법에 정통한 매우 똑똑한 프로그래머가 동일한 수준의 프로그램을 개발한다고 하면, PP방식으로 했을 때 5%정도의 성능 이득을 얻을 수 있다고 한다. 일반적으로 어떤 방식으로 프로그램을 개발하느냐 보다는 해당 방식에 얼마나 정통한 이해를 하고 있느냐가 성능에 더 중요한 영향을 미친다.

오늘날의 컴파일러(:12)들은 높은 수준으로 최적화되어 있으며, 컴퓨터는 매우 빠르다. 이러한 프로그래밍 외적인 특징들은 OOP를 사용함으로서 발생할 수 있는 성능 하락을 보상한다. 또한 많은 경우 성능상의 이익보다 OOP로 얻을 수 있는 다른 이득들이 더 중요한 경우도 있다.

유지/보수성

어떤 코드냐에 관련되어 있겠습니다만, 저에게는 OOP가 유지하기가 더 쉬웠습니다. OOP는 클래스의 어디에 버그가 있는지 쉽게 범위를 좁혀할 수 있습니다. 객체가 최소 단위이기 때문입니다. 매우 복잡한 주제이긴 하지만 저의 입장에서는 그렇습니다.

여러 가지 다른 의견들

차이점은 당신의 머리속에 있다. 만약 극도의 효율성을 원한다면, 기계 코드나 어셈블리어(:12)로 개발할 수 있다. 그러나 여러가지 현실적인 문제들 때문에, 당신은 합리적인 타협점을 찾기를 원한다. 그래서 다른 많은 언어들이 개발되었다. 선형적인 문제를 풀려고 한다면, PP로 충분할 것이다. 메서드와 데이터가 연결되어서 처리되어야 한다면 OOP가 효율적이다.
OOP의 장점을 이해하지 못했다면, 사용하지 않는 것이 낫다에 대해서 그것은 토론에 기여하지 않는 다는 반응이 있었다. 그렇게 얘기한다면 PP의 장점을 이해하지 못한다면, 사용하지 않는 것이 낫다라고 얘기할 수 있을 것이기 때문이다. 이에 대해서, 이미 원글을 쓴이는 PP의 장점을 알면서 쓰고 있었으므로 그것을 언급하지 않은 것이다 라는 의견이 있었음.
멀티 스레드(:12)와 여러 스레드들간에 데이터를 공유해야 하는 복잡한 애플리케이션을 개발할 때 OOP는 좋은 선택이 된다. 간단한 프로그램이라면 PP로도 괜찮다. 일반적으로 유닉스(:12) 개발자들은 한 가지 일을 잘하는 작은 애플리케이션을 만들고, 이들 애플리케이션을 연결해서 사용하는 방식을 사용한다. 유닉스에서 여전히 C(:12)가 널리 사용되는 이유다.

만약 당신이 작은 유틸리티를 이것 저것 만들어야 한다면 PP를 선택하는게 좋다.

반면 대화형 애플리케이션은 여러가지 기능을 집약시키는 경우가 많다. 이 경우에 OOP를 선택하는 것이 좋다. 이것은 마치 emacs(:12)와 vi(:12)중 무엇을 선택할 것인가와 비슷한 류의 문제라 할 수 있다.
나는 심지어 대학에서 OOP를 배운적이 없다. 나는 항상 PP방식으로 모든 프로그래램 문제를 풀었으며, 교과 과정도 그러했다.

OOP를 처음 사용한건 웹사이트를 위한 데이터베이스 시스템을 구축할 때였다. 여기에는 애플리케이션 개발을 위해서 - 유저, 고객, 페이지, 제품, 쇼핑카트등 수많은 재용 가능한 객체들이 필요했다.

물론 PP의 서브루틴 기반으로 웹 사이트 코드를 만들어도 충분할 것이라고 생각할 수 있을 것이다. 그러나 PP 방식으로 프로젝트와 객체들을 제사용하는 것은 결코 쉽지 않다는 것을 알게 될 것이다.

나에게 있어서 분명한 것은 모든 경우에 있어서 PP 보다 OOP 코드가 훨씬 사용하기 쉬웠다는 점이다. 물론 모든 사람이 여기에 동의 하지 않을 것이지만 말이다. 몇몇 웹 사이트는 .Net 클래스로 개발되었는데, 윈도우 응용 프로그램에 동일한 객체를 재사용할 수 있었다.
OOP는 각자의 방식이 있다. 프로그래머다 자신의 방법이 있다. 문제는 그 방법이 너무 다양하다는 것이다. 그래서 OOP코드는 때때로 프로그래머의 두뇌의 복잡함에 비례해서 복잡해 지는 경우가 있다. 일반적으로 PP에서는 그런일이 그다지 일어나지 않는다. 약속된 패턴을 사용한다면 더 나아질까 ?
나는 대부분 PP 경험을 가지고 있다. 그렇지만 내 스스로 점점더 OOP의 컨셉을 따르는 프로그래밍을 하고 있다는 것을 알게 되었다. 그래서 나는 그것을 흉내내게 되어다. 그놈의 경우 C로 객체지향을 구현했다.

이에 대한 답변

그렇긴 하지만, 예를 들어 C로 OOP를 흉내내려면 데이터 드리븐 방식을 사용해야 한다. 그러나 OOP에서 데이터를 드리븐 하는 아이디어는 쓰레기 통에 버려야 할 생각이다. C와 C++을 비교해 보자면, C는 포인터를 이용해서 함수에서 함수로 데이터를 던져야 한다. 그러나 C++의 클래스를 이용하면, 자연스럽게 데이터와 메서드를 묶을 수 있다.

만약 OOP를 하고 싶다면, OOP를 지원하는 프로그래밍 언어를 사용하는게 맞다고 본다.
나는 25년의 프로그래밍 경험을 가지고 있다. 나는 시작은 PP로 했고, 2004년 정도가 되어서야 .NET과 C#을 하면서 OPP를 배우기 시작했다. 그리고 디자인:::패턴(:12)을 배우게 되었다.

나는 간혹 OOP로 작성된 코드를 이해하기 어렵다는 말을 듣기는 한다. 그 코드들은 OOP라기 보다는 흥분한 객체 이를테면 스파게티 객체에 가까웠다. 물론 개발자 입장에서 OOP는 쉬운 개념은 아니다. 철학적인 면이 분명 있다. 그러나 철학에서 말하는 깨침을 얻고나면, 훌륭한 하나의 개발도구를 가지게 된다. 나는 어느 때인가 갑자기 OOP의 의미가 명확해 졌다. 그리고 상소을 이용하고 다형성을 사랑하게 되었다. 당신에게 말하고 싶은것이 있다면 PP로는 다형성의 우아함을 알 수 없다는 것입니다.

내가 천재 프로그래머는 아닙니다만 PP와 OOP에 대한 저의 의견을 말하자면, OPP가 우수하다고 봅니다.----