객체지향 프로그래밍에 대한 오해와 진실 2

Posted by 大山 Thu, 17 Aug 2006 07:56:00 GMT

[참고: 이 글은 객체지향 프로그래밍에 대한 오해와 진실에 이어지는 시리즈임.]

객체지향 언어에 대한 입문서를 보면, 상속, 캡슐화, 다형성 외에도 빠지지 않고 등장하는 설명이 하나 있다. 바로 객체는 실제 세상(Real World)의 물체를 모델링한다는 것이다. 물론 이 내용을 다루는 챕터는 모든 객체가 실제 세상의 물체와 대응될 필요는 없다며 어물쩍 마무리를 하기 마련이지만 말이다.

실제 세상에 대한 모델링이란 주장은 얼핏 객체의 필요성에 대한 그럴듯한 설명인 것 처럼 보이지만, GUI 프로그래밍이나 시뮬레이션 설계를 하는게 아니라면 전혀 맞아들어가지 않는 설명이다. 오히려 이 때문에 일부 뛰어난 해커들마저 OOP를 오해하는 경향이 있기 때문에 여기서 짚고 넘어가려고 한다.

객체지향 프로그래밍에 대한 또 한가지 오해는 상속이 코드 재사용의 핵심이라는 말이다. 이는 다분히 과장된 주장이라고 보여진다.

마지막으로 모든 객체지향 언어에 해당되는 것은 아니지만, 많은 개발자에게 '객체지향 언어 == C++ 또는 자바'로 받아들여지므로 이 내용을 같이 다루어도 좋을 성 싶다. 바로 스태틱 타이핑(Static Typing)이 버그를 줄여준다는 오해이다.

하나씩 짚어보자. 어쩌다가 객체지향 언어는 실제 세상의 물체를 모델링한다는 설명이 생기게 되었을까? 바로 최초의 객체지향 언어였던 Simula가 시뮬레이션 용으로 만들어진 언어였기 때문이다. 하지만 여기서 주의할 점은 Simula는 1960년대에 나온 프로그래밍 언어였다는 점이다. 실제로 1971년에 나온 Smalltalk-71은 Simula에서 객체에 대한 메세지 보내기 개념(즉 데이타와 함수를 묶어두는 방식)만 따와서 구현된 것으로 알려져 있다.

시뮬레이션 또는 GUI 프로그래밍에서는 객체지향 프로그래밍이 무척이나 자연스럽게 느껴지는 것이 사실이다. 하지만 프로그래밍의 범주는 이보다 훨씬 더 넓고, 객체지향(데이타에 함수 묶어두기) 프로그래밍은 꽤나 보편적으로 유용하다.

두번째로 상속과 코드 재사용성 부분인데, 상속을 통해서 코드 재사용을 추구하는 것은 프레임워크에서 제공하는 템플릿 클래스를 사용하는 등의 상당히 제한된 경우에만 적합한 것 같다. 이 때문에 Objective-C를 사용하는 Cocoa 같은 프레임워크에서는 조합(Composition)과 위임(Delegation)의 사용을 훨씬 더 강조하고 있다.

그런데 왜 상속을 통한 코드 재사용이 그토록 강조되는 것일까? 아마도 마케팅의 영향이 아닌가 싶다. C++와 자바는 모두 업계 주도적으로 확산된 언어이다. 마케터들은 실제로 중요한 것 보다는 사람들의 머리속에 각인될만한 내용으로 마케팅을 전개하기 마련이다. 이 마케팅이 너무 성공적이어서 수많은 개발자들을 헤매이게 만들기는 했지만 말이다.

마지막으로 스태틱 타이핑 부분인데, 스태틱 타이핑이 컴파일 최적화에 도움을 주기 때문에 프로그램의 성능을 높여주는 것은 사실이다. 무어의 법칙때문에 나날이 덜 중요해지는 요소이기는 하지만 말이다. 하지만 스태틱 타이핑이 개발자의 실수를 방지해서 버그를 줄여준다는 말은 낭설에 가까운 것 같다.

스태틱 타이핑의 옹호자들에게 물어보라. 당신들은 스태틱 타이핑이 자신들의 실수를 줄여준다고 생각하느냐고. 그들은 이렇게 말한다. 자신들은 그런 초보적인 실수를 안하지만, '평균'적인 개발자에게는 그런 안전장치가 필요할 것이라고. 사용자들이 멍청할 것이라고 가정하는건 개발자들이 범하는 가장 흔한 실수 중의 하나이다. 일부 프로그래밍 언어의 설계자들 역시 비슷한 오류에 빠졌던 것은 아닌가 싶다.

Posted in  | Tags ,  | 12 comments | 1 trackback

Comments

  1. 1.
    javanese said about 10 hours later:

    깊이 생각해 본 것은 아닙니다만 평소 느끼던 바가 있어서 적어봅니다. 사용자가 똑똑할 거라고 가정하는 것도 흔한 실수 중 하나라고 봅니다. 또는 코드를 제공하는 쪽이 스스로 사용자보다 더 똑똑할 거라 가정하는 것도 마찬가지구요.. 기존에는 어땠을지 모르지만 지금의 스태틱 타이핑의 의미는 성능이나 버그 회피보다는, 수많은 개발자 또는 그룹의 코드가 연관되는 과정에서 커뮤니케이션의 효율성을 높이기 위한 것이 아닌가 합니다. 서로 말안하고도 통할 만큼 표준이 정해져있다면 모르겠지만요.. (이것조차도 스태틱 타이핑스러운 생각입니다만..) 앞으로 가야할 방향이 다이나믹 프로그래밍이라는 것에는 공감하지만 지금의 다이나믹 프로그래밍 언어들도 API를 맞춰가는 과정에서는 스태틱 타이핑 언어들과 다를바 없어서 오히려 혼란이 크지 않나 생각합니다. 다이나믹한 객체를 만들었는데 결국 따로 제공하는 API 문서대로 동작해야한다면 스태틱 타이핑의 역할을 API 문서가 하고 있다고 봅니다. 스태틱 타이핑 언어들은 차라리 그럴바엔 그냥 언어가 API 문서 역할까지 겸하는 것이구요... 다이나믹 언어들은 다이나믹 개발환경과 실행환경이 갖춰져야 의미가 있다고 생각합니다. 물론 개발시 편리하고 표현이 깔끔한 것만으로도 좋은 일이긴 합니다만, 지금의 개발환경으로는 컴파일 에러를 런타임 에러로 미뤄둠으로써 개발자의 경각심을 높이는 차원이고, Squeak 같은 동적인 개발환경이 좀 더 발전되어 완성되어야 진가를 발휘하는게 아닌가 싶습니다. 사실 동적 언어를 많이 써본것도 아닌데 이런 글 쓰기는 부담스럽습니다만, IDE 매니아인데다가 평소 생각해보던 부분이라 적어봅니다. 덧글 분량에 담기엔 쉽지 않군요.. 앞으로도 많은 얘기 나와서 저도 동적 언어에 대한 깨우침을 얻기를 기대합니다. ^^


  2. 2.
    javanese said about 10 hours later:

    줄 바꿈을 안했더니 눈이 아프게 되버렸군요.. 죄송합니다 (_ _) 휘리릭~


  3. 3.
    大山 said about 11 hours later:

    @javanese: 좋은 의견 공유해 주셔서 감사합니다. :) 저는 인터페이스 설계가 (사용자 인터페이스, 프로그래밍 언어의 신택스, API를 모두 포함해서) 특정 사용자가 똑똑하냐 아니냐의 문제라기 보다는 사람의 보편적 인지구조상 과연 직관적으로 만들어졌느냐 아니냐의 문제라고 생각하는 편입니다.

    스태틱 언어로의 개발에서 컴파일 타임에 에러가 발생하는 것은 엉뚱한 객체의 메소드를 호출하기 때문이라기 보다는, 변수를 선언해주는 부분에서 실수로 잘못된 클래스를 사용하기 때문이지 않은가요? 개인적으로는 변수 이름만 잘 지어주어도 큰 문제는 없을 거라는 생각입니다만.. ^^;;

    저는 javanese님과는 반대로 텍스트 편집기(emacs) 위주의 개발을 하기 때문에 간과하는 부분이 있을 것 같습니다. 다만 말씀하신 것처럼 복잡한 프로그램에서는 무언가 코드의 안정성을 보장해주는 장치가 필요한 것이 사실이고, 저는 유닛 테스팅이 이 역할에 제격이라고 생각합니다.

    물론 개발팀 안에 악의적인 의도를 지닌 개발자가 한 명 있다면, 동적인 언어로 개발할 때 리스크가 훨씬 더 커지겠지요~ ㅎㅎ


  4. 4.
    kebie said 1 day later:

    상속보다는 조합과 위임을 강조하는 것은 마치 레고같은 방식인 것 같습니다. 사실 프로그램을 작성하는 것과 레고를 조립하는건 많이 닮은 것 같아요. 어떻게 보면 레고는 객체지향장난감이네요. 사람이 만든 가장 위대한 장난감이 아닐지... ^^;


  5. 5.
    大山 said 1 day later:

    @kebie: 적절한 비유라고 생각합니다, 상속은 새로운 레고 블록을 직접 설계/제작하는 것에 가깝겠죠? ㅎㅎ


  6. 6.
    홍민희 said 1 day later:

    글쎄, 저는 javanese 님의 말씀에 더 공감합니다. 사실 저는 동적 언어로 프로그래밍을 시작한 사람입니다. 그런데 지금에 와서는 타입을 명시할 수 있도록 언어적인 기능이 있었으면 할 때도 많습니다. 그래서인지, Python도 Python 3000부터는 함수의 인자에 타입을 지정하는 기능을 추가한다고 하고, PHP 역시 5부터는 타입 힌팅(type hinting) 기능을 추가했습니다. 분명 동적 언어의 장점은 굉장합니다만, 가끔은 타입 명시가 굉장히 유용하기도 합니다.


  7. 7.
    홍민희 said 1 day later:

    물론 일반적인 변수 선언에 있어서까지 정적 타입에 제약되어야 한다면 피곤하겠죠. ㅎ


  8. 8.
    大山 said 1 day later:

    @홍민희: javanese님의 API 이야기가 함수 인자의 타입 체킹을 말하는 것이었군요, 제가 그 부분을 놓치고 있었네요~ ^^;;

    저는 그 이슈에서도 스태틱 타이핑이 적합한 해법이라고는 생각하지 않습니다. 이미 Smalltalk, Objective-C 등에서는 아예 메소드 이름에서 각 인자에 대한 설명을 포함하고 있지요.

    // Objective-C에서 객체의 메소드를 호출하는 예
    [myRect setWidth:10.0 height:15.0];
    

    루비에서는 메소드 인자의 갯수가 늘어나면, 해시를 넘겨주는 형태로 이 문제를 해결하고 있습니다.

    # 레일스에서 해시를 사용해서 인자를 넘기는 예
    link_to p.name, :action => "new", :id => p.id
    

    루비 2.0에서는 아예 신택스 레벨에서 키워드 인자를 지원하는 것을 고려중이기도 하지요.

    javanese님의 말씀처럼 스태틱 타이핑의 존재 이유가 API 커뮤니케이션에 있다면, 저는 키워드 인자나 해시가 더 효과적인 해법이라는 생각입니다. 다른 분들의 의견이 궁금하네요~ :)


  9. 9.
    javanese said 3 days later:

    링크 걸어주신 곳에 제가 원하는게 딱 있군요. "Help you save Brain Power" ^^ 그런 고려사항이 있다는 것은 알겠습니다만, 제가 궁금한 것은 런타임의 루비 객체가 코딩할 때의 객체와 동일하다고 보장할 수 없는데 저런 것이 의미가 있는지입니다.

    제가 원하는 것은 굳이 찝어 말하자면 auto-completion을 에디터에서 구현할 수 있냐 없냐의 차이라서요 =,.= ruby 에디터 이클립스 플러그인 짜볼까하고 끄적끄적대다가.. 코딩 자체도 irb 상에서 하지 않는 이상, *.rb에 저장되어 있는 내용을 참조하여 자동 완성하는 것은 동적 언어의 특성에 맞지 않는 듯 하여 때려쳤는데요.

    예를 들어 루비로 작성된 서버가 있고, 관리자가 실행중인 런타임에서 바로 객체를 수정하고 있다면, 그 서버를 사용하는 사람은 실시간으로 런타임에서 객체 정보를 받아다가 코딩을 해야겠구나 하니까 더이상 하기가 귀찮더라구요. 제가 너무 오버한 것인지요? ^^

    해시든 키워드든 method call을 직관적이게 하는 것은 좋은데.. 그 method에 대한 call을 사용하려는 개발자(또는 개발도구)가 method에 대한 정보를 얻는 방법은 여전히 미약하다고 생각됩니다. 민희님이 말씀하신 Python의 추가 기능 같은 것이 답이 될 수는 있는데.. 그건 스태틱 언어스러워지는 길이니 웬지 반대로 가는것 같네요. 요점은 다소 많은 개발자가 개발할 때 서로서로 코드를 보고 짜는것으로 충분한 것인지 궁금합니다. 그런 상황에서 동적인 특성이 충분히 발휘되는 것인지도요.. 저는 루비 서버 하나 놓고 런타임 상에서 객체 변형 시켜가면서 코딩하고 싶은데요 ^^


  10. 10.
    大山 said 3 days later:

    @javanese: 제 블로그는 답글에서<p> 태그를 써주어야지 줄바꾸기가 됩니다.. ^^;;

    키워드 인자를 사용해서 메소드를 직관적으로 만드는 것에는 몇 가지 장점이 있습니다. 무엇보다도, 메소드에 어떤 인자가 있는지를 기억하기가 용이해지고(saving brain power), 또한 하나의 메소드를 꽤나 범용적으로 만들 수 있게 되지요. 스태틱 언어에서라면 여러 개의 메소드로 나눠지게 될 것을 루비에서는 하나의 메소드로 처리하는 경우가 많습니다.

    저의 경우에는 컴파일 타임에 컴파일러가 타입 체킹으로 실수를 잡아주는 것 보다는, 루비에서처럼 시스템 전체를 보다 직관적으로 구성해서 실수의 원인 자체를 줄여주는게 더 효과적이라는 입장입니다. 실제로 루비를 쓰면서는 API 문서를 뒤척이는 일이 많이 줄어들기도 했구요.

    코드 auto-completion을 원하시는 거였군요.. ^^;; 그건 컴파일타임에는 아무래도 스태틱 타이핑 언어에서만 온전한 구현이 가능할 것 같습니다. 다이내믹 타이핑 언어가 갖는 유연성은 객체의 타입이 런타임에 유동적이라는 점 때문에 가능하니까요. 사실 루비에서는 메소드 이름이 간결한 편이라 코드 완성 기능이 없는게 큰 불편으로 다가오지는 않습니다. 어떤 키워드 인자를 사용하느냐 어떤 블록을 넘겨주느냐에 따라 전혀 다른 메소드를 사용하는 것 같아지기도 하지요.

    말씀하신대로 루비에서는 실행중인 런타임에서 객체를 직접 변경하는 것이 가능합니다. 하지만 이는 일반적으로 사용되는 기법은 아닌 것 같습니다. 런타임에 객체 또는 클래스의 코드를 변경하는 작업은 보통 프로그래머가 수작업으로 한다기 보다는 그 용도로 작성된 다른 코드가 하게 되지요. 이렇게 런타임에 코드를 변경해주는 코드를 작성하는 기법을 흔히들 메타프로그래밍이라고 합니다.

    IDE만을 위해서 프로그래밍 언어의 구조가 달라져야 한다면 주객이 전도되는 일은 아닐까요? 많은 루비 프로그래머들은 오히려 루비가 프로그래머를 IDE로부터 해방시켰다고 생각할 것 같습니다만.. ^^;;

    javanese님께서 런타임에 직접 객체를 변경하면서까지 만드시려는게 무엇일까요? 돌아가고 있는 프로그램을 동적으로 변경하면서 다른 프로그래머들이 그 API를 동적으로 체크하면서 코딩한다니, 무언가 상당히 멋진 것을 구상하고 계시는 것 같습니다~ :)


  11. 11.
    charlz said 6 days later:

    말씀하시는 세가지 모두 나중(OOP 붐이 사그라들던 시기)에 깨닫게된 OOP의 결함들이고, OOP가 한창 성행일때는 말씀하시는 것들이 사실로 받아들여졌었죠. 어딜가도 그렇게 배우고 가르쳤으니까요. 당시에는 Dynamic 언어는 일반적으로 스크립트에만 쓰는 것 같이 이야기했고, 코드는 (이해)되지도 않는 상속을 써서 재사용해야되는 것처럼 이야기했고, 그 상속성/캡슐화/폴리모피즘은 세상을 모델링하는 것처럼 말이죠. 그 결함들로 인해 지금 이야기하는 다양한 패러다임의 도래가 온 것이니, OOP에 관한 오해나 마케팅보다는 OOP의 결함(실용성이나 복잡성등)으로 인한 변화가 맞을 것 같네요.^^


  12. 12.
    大山 said 7 days later:

    @charlz: 저는 OOP 개념 자체에 문제가 있었다기 보다는 C++/자바의 성공과 함께 OOP가 다소 왜곡되었었다는 생각입니다. Smalltalk나 Objective-C 같은 언어에서는 두드러지지 않았던 이슈이기도 하고요.

    알고 보면, OOP의 역사도 꽤 길답니다. 새로운 기술이 대중화 되고, 정착되는 데는 오랜 시간이 걸리는 것 같습니다. :)


Trackbacks

Use the following link to trackback from your own site:
http://beyond.daesan.com/articles/trackback/1245

  1. From
    모델링의 필요성
    고객이나 시장의 요구와 비즈니스 전략과개발되어져 나오는 솔루션 사이의 간격이 너무 크다.EA 와 같은 것들이 나오는 이유도 전략과의 연계를 강조하는 면이 강하다. 그럼에도 불구하

Comments are disabled