[루비 사용자 가이드] 객체 지향적 사고

루비/레일스 프로그래밍/루비 사용자 가이드 2007.04.30 14:46

객체지향(Object oriented)은 캐치프레이즈입니다. 무언가를 객체지향적이라고 말하는 것으로, 여러분이 아주 똑똑해 보이도록 할 수 있습니다. 루비는 객체지향적 스크립트 언어라고 주장합니다. 하지만, 도대체 "객체지향"이란 정확히 어떤 뜻일까요?

그 질문에 대해 다양한 답이 있어왔지만, 아마도 그 모두가 동일한 것으로 귀결될 것입니다. 결론을 성급히 말하기 보다, 전통적인 프로그래밍 패러다임에 대해서 잠깐 생각해 보도록 합시다.

전통적으로 프로그래밍 문제는 어떤 종류의 데이터 표현(data representation)과 그 데이터를 다루는 처리절차(procedure)를 가지고 공략되어 왔습니다. 이런 모델 아래서 데이터는 수동적이고, 스스로 동작하지 않으며, 무력한 존재입니다. 데이터는 단지 능동적이고, 논리적이며, 전능하고, 커다란 처리 절차가 명령하는 데로 바뀔 뿐입니다.

이런 접근 방법의 문제는 프로그램이 사람에 불과한, 머리속에 세세한 부분을 명확히 기억하는 것이 제한되어 있는, 프로그래머에 의해 작성된다는 것입니다. 프로젝트가 커져감에 따라, 절차적인 핵심 부분들은 어떻게 전체가 돌아가는지를 기억하는 것이 어려울 정도로 커져버립니다. 그에 따라 생각의 사소한 오류나 단순한 타이핑 실수가 찾기 어려운 버그의 근원이 될 가능성도 더 커져버립니다. 복잡하고 의도하지 않은 상호 작용이 절차 부분 내에서 생겨나기 시작하고, 그런 상호작용을 잘 처리하는 것은, 싱싱한 산낙지가 빨판을 입 천장에 붙이지 못하도록 막는 것 만큼이나 어려운 일입니다. 전통적인 프로그래밍 패러다임 하에서 버그를 최소화하고 국소화 하도록 도울 수 있는 여러 프로그래밍 가이드라인이 있습니다만, 작업하는 방법을 근본적으로 바꾸는 것을 포함하는 더 좋은 해결 방안이 있습니다.

객체지향 프로그래밍은 평범하고 반복적인 논리적 작업을 대부분 데이터 자체에 위임하는 것입니다. 따라서 데이터에 대한 개념이 수동적인 것에서 능동적인 것으로 바뀝니다. 다른 식으로 이야기하자면,

  • 각각의 데이터를 뚜껑이 열려 있어서, 그 안의 내용물을 꺼내거나 여러 물건을 넣을 수 있는 박스로 생각하는 것을 중단합니다.
  • 각각의 데이터를 뚜껑이 닫혀있고, 잘 표시된 몇 개의 스위치와 다이얼이 달려있는 잘 작동하는 기계로 다루는 것을 시작합니다.

앞에서 "기계"라고 설명한 존재의 내부는 단순할 수도 있고, 복잡할 수 있습니다. 하지만 내부가 복잡한지 단순한지를 외부에서 알 수는 없으며, 기계를 열어보는 것도 (그 기계의 설계가 무언가 잘못되었다는 것이 절대적으로 확실하지 않은 한) 허용되지 않습니다. 따라서, 데이터를 처리하기 위해 스위치를 켜고 끄거나, 다이얼을 읽는 것과 같은 일만 하도록 허용됩니다. 일단 그런 기계가 만들어지면, 기계 내부가 어떻게 돌아가는지에 대해서 관심을 가질 이유가 없습니다.

이 이야기를 듣고, 아마도 쓸데 없는 일을 일부러 더 만들어내고 있다고 생각할수도 있습니다. 하지만, 이런 접근 방법은 모든 일이 한꺼번에 잘못되는 것을 멋지게 막을 수 있습니다.

실제적 가치는 없지만, 앞에서 설명한 개념의 적어도 일부분라도 보여주는 단순한 예를 들겠습니다. 자동차에는 주행 거리계가 있습니다. 그 목적은 가장 마지막으로 리셋 버튼이 눌린 시점부터 차가 얼마나 많은 거리를 주행했는지 저장하는 것입니다. 이것을 프로그래밍 언어로 어떻게 모델링할까요? C언어에서 주행 거리계는 단순한 수를 저장하는 변수이고, 아마도 float 타입으로 할 수 있을겁니다. 프로그램은 그 변수를 조금씩 증가시키고, 때때로 필요할 때 0으로 초기화하면서 사용할 것입니다. 이 구조에서 잘못된 것이 무엇일까요? 수많은 이유로 인해 버그가 잘못된 값을 변수에 대입할 수 있습니다. C로 프로그램을 짜 본 사람이라면 며칠이나 버그를 잡았는데, 결국에는 어이없게도 너무나 단순한 이유로 인해서 그 버그가 발생했음을 알게된 허탈한 경우를 겪어보았을 것입니다(그런 버그를 찾는 그 순간은 보통 이마를 때리는 찰싹 소리로 알 수 있습니다).

똑같은 문제가 객체지향적인 환경에서는 확연히 다른 방식으로 처리될 수 있을겁니다. 프로그래머가 주행 거리계를 디자인할 때, 첫번째 질문은 "이것과 가장 잘 들어맞는 나에게 익숙한 데이터타입이 뭐가 있을까?"가 아니고, "이것이 정확히 어떻게 동작해야 할까?"입니다. 그 둘은 심오한 차이가 있습니다. 정확히 주행 거리계가 어떤 것이고, 외부 세계가 그 주행거리계와 어떻게 상호작용 하는지를 결정하는 것은 약간의 시간이 필요합니다. 우리는 증가시키고, 리셋할 수 있고, 값을 읽을 수 있지만 다른 기능은 제공하지 않는 작은 기계를 만들기로 결정합니다.

우리는 주행 거리계에 특정 값을 지정하는 방법을 제공하지 않습니다. 왜일까요? 왜냐하면 주행 거리계는 그렇게 동작하지 않기 때문입니다. 주행거리계를 가지고 할 수 있는 일은 몇 가지 되지 않고, 우리가 허용하는 기능은 그게 전부입니다. 따라서 만약 프로그램에서 무언가가 주행 거리계의 값을 실수로 다른 어떤 값으로 변경하려고 한다면(예를 들어 자동차의 온도 조절 시스템의 목표 온도), 잘못된 일이 벌어졌다는 것을 바로 알 수 있습니다. 우리는 프로그램을 실행할 때 (언어의 특성에 따라서는 컴파일하는 동안에) 임의의 값을 주행거리계에 대입할 수 없다는 메시지를 받게 됩니다. 정확히 동일한 메시지는 아니어도, 최소한 그와 어느정도 비슷한 메시지를 받을 수는 있을겁니다. 그것이 에러를 방지하지는 못합니다. 그렇지요? 하지만 그로 인해 에러의 원인이 무엇인지를 빨리 알 수 있습니다. 이것이 OO 프로그래밍이 시간 낭비를 줄여주는 수많은 경우 중 한 가지입니다.

보통 이 수준보다 한 단계 더 추상화를 진행합니다. 왜냐하면 개별 기계를 만드는 것 만큼 기계를 만드는 공장을 만드는 것도 쉬운 것으로 드러났기 때문입니다. 보통 주행 거리계를 한 개만 만드는 일은 없을 것입니다. 대신 한 가지 패턴으로 여러 주행 거리계를 제작할 수 있도록 준비할 것입니다. 패턴(혹은 주행 거리계 공장)은 우리가 클래스(class)라 부르는 것에 해당하고, 그 패턴으로 제작되는 (혹은 그 공장에서 생산되는) 개별 주행 거리계는 객체(object)에 해당합니다. 대부분의 OO언어에서는 개별 객체를 생성하기 전에 클래스를 정의할 필요가 있지만, 루비는 그렇지 않습니다.

여기서 객체지향 언어를 사용하는 것이 좋은 객체지향 디자인을 하도록 강제로 만들수는 없다는 것을 밝힐 가치가 있을겁니다. 실제로 어떤 언어로든 불명확하고, 너저분하며, 부주의하고, 버그 투성이의 불안정한 프로그램을 짤 수 있습니다. 루비가 제공하는 것(특히 C++과 대비했을 때)은 객체지향 프로그래밍의 기법들이 자연스럽게 느껴질 수 있도록 해서, 아주 작은 프로그램을 작성할 때 마저도 노력을 줄이기 위해 나쁜 기법의 코드를 작성할 필요를 느낄 수 없게 하는 것입니다. 우리는 루비가 이런 경탄할만한 목적을 어떻게 달성하는지에 대해 이 가이드를 진행해 나가면서 살펴볼 예정입니다. 다음에 다룰 주제는 "스위치와 다이얼"(객체의 메소드)이고, 그로부터 "공장" (클래스)으로 진행해 나갈 것입니다. 여러분, 이 여행을 계속 함께 하십시다.


Trackbacks 1 : Comments 0

Write a comment