객체 지향 프로그래밍과 메시징

객체 지향 프로그래밍에서 메시징이란 무얼 말하는 걸까? 쉽게는 그냥 메서드 호출이라고 생각해도 될 것 같긴 하지만 그것만을 의미하는 것 같지는 않다. 그럼 도대체 뭘까?

원조에게 배우자. 앨런 케이

Object-Oriented라는 말을 처음 사용한 것으로 알려진 사람은 앨런 케이다. 앨런 케이에게 OOP란?을 보면 끝부분에 다음과 같은 글이 나온다.

OOP to me means only messaging, local retention and protection and
hiding of state-process, and extreme late-binding of all things.

우리말로는 대략 다음과 같이 옮길 수 있겠다.

내게 OOP란 오직 다음 3가지를 의미한다.

  • 메시지를 주고 받는 것
  • 상태 처리가 로컬 범위 내에서만 다뤄지도록 유지하고 상태 처리를 (외부로부터) 보호하고 숨기는 것
  • 모든 것에 대한 극단적인 late-binding (또는 모든 것이 가능한 가장 늦은 시점에 결정되는 것)

여기서 첫 번째 꼽는 messaging이 뭔지 잘 모르겠다. 그래서 더 찾아보니 ‘앨런 케이에게 OOP란?’에 이어 앨런 케이에게 메시징이란?도 있었다.

The big idea is “messaging” - that is what the kernal of Smalltalk/Squeak
is all about (and it’s something that was never quite completed in our
Xerox PARC phase). The Japanese have a small word - ma - for “that which
is in between” - perhaps the nearest English equivalent is “interstitial”.
The key in making great and growable systems is much more to design how its
modules communicate rather than what their internal properties and
behaviors should be.

대충 줄여서 의역하면 대략 다음과 같은 뜻이다.

중요한 건 (object라기보다는) 메시징이었고, 모듈 내의 속성 및 동작보다 모듈 간의 의사소통을 잘 설계하는 것이 성장 가능한 훌륭한 시스템을 만드는 데 훨씬 더 중요하다.

여기에서도 메시징이 중요하다는 건 알겠지만, 그래서 메시징이 정확하게 또는 구체적으로 뭘 의미하는지에 대한 얘기는 위 글 전체를 읽어봐도 안 나온다. 아니 안 나온다고 단정하긴 어렵고 내 수준에서는 안 보인다.

작자 미상의 명언

객체 지향 프로그래밍의 의미는 아무래도 그 용어를 처음 쓴 앨런 케이가 한 말이 가장 정확하겠지만, 부분적이나마 가장 쉽게 이해할 수 있게 해준 말은 바로 이거다.

객체에게 데이터를 요구하지 말고 작업을 요청하라.

누가 한 얘기인지는 모르지만 나는 토비의 스프링에서 저 말을 처음 봤는데, 책을 봐도 내용을 거의 기억 못 하는 뇌를 가지고 있지만 저 말만은 잊히지 않았다. 저 말은 앨런 케이가 짚어준 3가지 중에서 1과 2를 포괄한다고 생각한다.

거인의 어깨 위에서

그래서 위 3가지 글을 근거로 메시징에 대한 내 나름의 정의를 내려보면 다음과 같다.

메시징은 데이터를 요구하는 메서드 호출이 아니라 작업을 요청하는 메서드 호출을 의미한다.

이것마저도 조금 모호하게 느껴질 수 있으니 쉽게 풀어 써보자.

대학 입시 원서 접수 사례

대학 입시 원서 접수라는 상황을 생각해보자. 일반적으로는 지원자의 주민등록번호를 확인하지만, 주민등록번호가 없는 외국인 지원자는 비자 번호를 확인한다고 하자.

일반적인 내국인 지원자는 일반 전형을 통해 모집한다고 하고, 코드를 ‘A’라고 하자. 외국인 지원자는 외국인 전형을 통해 모집한다고 하고, 코드를 ‘F’라고 하자. 지원 정보는 application에 담겨있다고 하면, 대략 아래와 같은 코드가 나올 것 같다.

1
2
3
4
5
6
7
8
9
...

// 전형 타입이라는 데이터를 application 객체에게 요청하고,
String admissionType = application.getAdmissionType();

// 외국인 전형 여부를 확인하고 비자번호를 확인하자.
if ("F".equals(admissionType))
verifyVisaNumber(application.getVisaNumber());
...

이제 전형을 전기와 후기로 나누어 일 년에 두 번 접수를 받도록 정책이 바뀌었다. 따라서 외국인 전형도 전기 전형은 기존대로 ‘F’ 코드를 쓰고, 후기 전형은 ‘G’ 코드를 쓰게 되었다. 그럼 기존의 코드는 아래와 같이 변경되어야 한다.

1
2
3
4
5
6
7
8
9
10
...

// 전형 타입이라는 데이터를 application 객체에게 요청하고,
String admissionType = application.getAdmissionType();

// 추가된 코드를 반영하기 위해 소스를 변경한다.
if ("F".equals(admissionType)
|| "G".equals(admissionType)) // 후기 전형 추가
verifyVisaNumber(application.getVisaNumber());
...

이젠 전기, 후기 뿐아니라 수시 전형이 추가되었다. 외국인 수시 전형 코드는 ‘H’를 쓰게 되었다. 코드가 또 바뀌어야 한다.

1
2
3
4
5
6
7
8
9
10
11
...

// 전형 타입이라는 데이터를 application 객체에게 요청하고,
String admissionType = application.getAdmissionType();

// 추가된 코드를 반영하기 위해 소스를 변경한다.
if ("F".equals(admissionType)
|| "G".equals(admissionType) // 후기 전형 추가
|| "H".equals(admissionType)) //// 수시 전형 추가
verifyVisaNumber(application.getVisaNumber());
...

요구사항이 변경될 때마다 기존 코드에도 변경이 필요하다. 이 정도의 변경이라면 그냥 해줄 수도 있다. 하지만, 외국인 전형 여부를 확인하는 코드가 위와 같이 단 한 군데만 존재할까? 그렇지 않다. 외국인 지원자는 본국의 비상연락처도 필요하고, 영어 성적이 면제될 수도 있는 등 외국인 전형 여부 확인 로직은 아마 꽤 여러군데 등장할 것이다.

그리고 자주 발생하지는 않겠지만 코드가 ‘F’, ‘G’, ‘H’가 아니라 ‘F1’, ‘F2’, ‘F0’ 이렇게 바뀐다면? 전기, 후기, 수시 전형에 또 조기 전형이 추가된다면? 변경은 아주 고달플 것이다. 그리고 변경이 아니더라도 ‘F’, ‘G’, ‘H’가 각각 어떤 전형을 의미하는지 이 코드만 봐서는 알 수 없어 불편하기도 하다.

이렇게 application 객체에게 admissionType이라는 데이터를 요구해서 처리하는 방식은 유지관리가 괴롭다는 단점이 있다. 그럼 작자 미상의 명언처럼 데이터를 요구하지 않고 작업을 요청하면 어떻게 달라질까?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 기존 코드

// 전형 타입이라는 데이터를 application 객체에게 요청하고,
String admissionType = application.getAdmissionType();

// 외국인 전형 여부를 확인한다.
if ("F".equals(admissionType))
verifyVisaNumber(application.getVisaNumber());
*/

...
// application 객체에게
// 전형 타입이라는 데이터를 요구하지 말고,
// 외국인 전형 여부 확인이라는 작업을 요청하자.
if (application.isForeignAdmission()) // <-- 바로 이렇게
verifyVisaNumber(application.getVisaNumber());
...

위 코드에서 application.isForeignAdmission()단순히 외국인 전형 코드라는 데이터를 받아오는 게 아니라 외국인 전형 여부 확인이라는 작업을 요청하고 있다. 그리고 isForeignAdmission()은 외국인 전형 여부 확인이라는 상태 처리를 로컬에서 수행하고 외부로부터 보호하고 숨기고 있다.

많이 들어본 얘기 아닌가? 바로 앨런 케이가 강조했던 3가지 중 2번 항목이다. 이렇게 작업을 요청하는 방식으로 바꾸고 나니 외국인 전형이 후기, 수시로 추가된다 하더라도 isForeignAdmission()내부 구현만 바뀔뿐 작업을 요청하는 application.isForeignAdmission() 이 코드는 바뀔 필요가 없다. 따라서 내부 구현도 ‘F’, ‘G’, ‘H’ 같은 문자 코드 대신 enum을 쓰는 등 더 나은 로직으로 바꿀 수 있는 자유를 얻게 된다.

이렇게 데이터를 요구하는 메서드 호출이 아니라 작업을 요청하는 메서드 호출이 바로 객체 지향이란 용어를 만든 앨런 케이가 가장 강조하고 싶었던 메시징이 아닐까?


역시나 허접하게라도 써서 올려야 피드백을 통해 더 알게 된다. 토비님이 앨런 케이의 강연 영상 유튜브 링크를 알려주셨다.

(물론 여전히 틀릴 수도 있다는 전제하에) 결론부터 말하면 객체 지향 프로그래밍에서의 메시징은 그냥 일반 명사인 메시지 주고 받기라고 봐도 무방한 것 같다.

전체적으로 3시간 가까운 분량인데, 이 글과 관련있는 부분은 https://youtu.be/QjJaFG63Hlo?t=3752 여기서부터 보면 된다.

일단 앨런 케이는 나같은 외국인이 알아듣기에 쉬운 어투를 가진 사람은 아닌 것 같다 ㅠㅜ. 문장이나 말을 명료하게 딱딱 끊는 것도 아니고 발음도 살짝 뭉개는 부분도 많아서, 지금처럼 하나도 남김 없이 완벽하게 들으려고 하면 좌절스러울 뿐이다. 게다가 나는 스몰톡을 전혀 모르기 때문에 정확하게 해석한 것인지도 사실 자신 없다.

영상을 보면 메서드를 객체 내부에 존재하면서 외부의 메시지와 대응하는 것으로 설명하고 있는데, ‘대응하는(corresponding) 것’이라는 모호한 말을 ‘받은 메시지를 처리하는 데 필요한 것’이라고 구체적으로 해석한다고 해도, 받은 메시지를 처리하는 데 메서드를 사용하는 것은 메시지를 받은 객체가 알아서 하는 것일 뿐, 메시징 자체를 메서드 호출과 직접 관련지을 필요조차 없는 걸로 보인다.

그리고 메시지에 메서드가 아닌 단순한 데이터도 대응된다고 그림과 함께 설명하고 있으므로, 단순히 데이터를 요구하는 것도 앨런 케이가 말하는 메시징에 해당된다는 점이다.

메시징을 메서드 호출이라고 볼 수도 없고, 단순히 데이터를 요구하는 것도 메시징에 해당된다면 메시징은 그냥 메시지 주고 받기라는 뜻 이상도 이하도 아니라는 생각이다.

이 결론이 틀렸다고 생각하는 분들은 위 링크를 클릭해서 직접 보시고 좋은 의견 나눠주시면 정말 감사하겠다.

이제 영상 주요 부분 후기를 남기면서 알고 보니 별 건더기 없는 주제가 돼버린 글을 마무리지어 버리자.

아 건진 것도 있다. 원조인 앨런 케이가 말하는 메서드는 자바에서 말하는 메서드와는 다르다는 걸 알게 됐다. 그러니 객체 지향을 자바 버전으로 해석할 수는 있겠지만, 객체 지향을 자바 관점으로만 판단하려는 일은 경계해야 한다.

Imgur

위 캡처는 앨런 케이가 객체 지향 프로그래밍을 설명하면서 그린 그림이다.

그린 순서대로 각 요소에 대한 설명을 짚어보면 다음과 같다.

  1. 가장 먼저 방울 모양의 테두리를 그려서 내부와 외부를 분리(separate)했고,
  2. 테두리의 바깥쪽에 응답 대상인 메시지(message)를 그렸고,
  3. 테두리의 안쪽에 메시지와 직접 대응되는 메서드(method)를 그렸고,
  4. 테두리의 안쪽에 메시지와 직접 대응되는 데이터 구조를 작은 점으로 그렸고,
  5. 테두리의 안쪽에 메시지와 직접 대응되지는 않는 메서드를 그렸고,
  6. 마지막으로 (외부의) 프로토콜과 (내부의) 메서드를 분리(separate)했다.

안타깝지만 여기에서도 메시지에 대한 직접적이고 명확한 설명은 나오지 않는다. 아니 들리지 않았다. messages that we are willing to respond to라며 ‘응답 대상이 되는’이라는 수식어를 붙일 뿐이고, in effect, some of the messages that the object might be able to receive aren't directly characterized in terms of some outside protocols라며 ‘메시지가 외부의 프로토콜에 의해 특징지어지는 것은 아니다’라는 애매한 부연 설명이 있을 뿐이다.

영상을 보기 전에는 객체 지향은 데이터를 요구하는 대신 작업을 요청하는 것이 중요하고, 앨런 케이가 메시징을 그토록 강조한 것과 연결지으면 메시징은 작업을 요청하는 메서드 호출일 것이라고 결론지었다. 그런데 앨런 케이는 위 그림을 설명하면서 메시지는 객체 내부의 데이터에 대응되기도 한다고 분명히 말하고 있다.

결국 메시징이 특히 강조되긴 했지만 앨런 케이의 글이나 강연에서 메시징 자체에 대한 구체적인 설명을 찾기 어려웠던 이유는, 메시징이 그냥 일반 명사의 의미라서 별도의 설명이 필요하지 않기 때문인 것 같다.

메시징 자체의 의미가 중요한 것이 아니라, 내/외부를 분리하고 분리된 객체끼리 상대방의 내부는 모르는 채로 의사소통해야 복잡성을 낮출 수 있다는 점에서 메시징을 강조한 것 같다.


크리에이티브 커먼즈 라이선스HomoEfficio가 작성한 이 저작물은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.