🧐 🤔 그거 어떻게 쓰더라 🙄 😙

OOP(객체지향프로그래밍)의 사고방식

2022. 12. 11. Kim Evergood이가 씀

Object-Oriented Programming

Object-Oriented Programming(OOP)는; 객체들의 모임으로서 프로그램을 취급하는 방식이다.

OOP는 흔히 ‘객체지향 프로그래밍’으로 번역된다. 하지만 만약 내가 이 말을 번역했다면 ‘객체중심 프로그래밍’, ‘객체위주 프로그래밍’이라고 했겠다. , ‘개체기반’도 맘에 든다. ‘지향’이라고 하면 목적, 목표라는 느낌인데; OOP에서 객체는 끝에 있는 목표라기보단 오히려 시작점, 관점이니까. OOP는 그러니까 말 그대로 객체 중심의 관점에서 프로그램을 만드는 것이다.

OOP는 절차지향적이던 기존 프로그래밍의 패러다임을 바꿨으며, 코드의 재사용성이 높고, 유지보수가 쉽고, 사람의 사고방식과 가깝다는 특징을 가졌다고 한다. 그런데 이렇게만 설명하면 그 ‘객체’란 무엇인지, 절차지향의 한계를 왜 하필 이 방식으로 극복했는지, 그 사고방식이란 구체적으로 어떤 사고방식인지 등이 설명되지 않는다.

예전에 「생각의 지도」라는 책을 봤다. 아주 재밌게 봤습니다. 동서양의 사고방식 차이를 연구해서 설명해주는 책. 그 땐 몰랐지만 이제와서 생각해보니 왠지 여기서 나오는 서양인의 사고방식이 OOP와 아주 닮았다고 느껴진다. 그러니까 이 사고방식이 바로 OOP의 근간이 되는 것일 테고; 따라서 이 사고방식을 이해하면 그 응용인 OOP 역시 자연스럽게 이해될 것이다. 뇌피셜이다. 이렇게 생각하는 사람 본 적 없음.

서양인의 사고방식

여기서 설명하는 동서양의 사고방식 대부분은 그 책에서 나오는 내용이다. 물론 서양인들은 다 이렇게만 생각하고 동양인은 다 저렇게만 생각한단 말은 아니다. 어디까지나 상대적으로 그런 경향이 있다는 말이다.

아주 짧게 말하자면; 명사위주 형식주의이다.

독립적 요소

동양에서는 무언가를 인식하면 그것과 그 주변의 관계에 관심을 가졌다. 그에 비해 서양에서는 무언가를 인식하면 그 주변을 배제하고 그 사물 자체에만 관심을 기울였다. 즉 사물/인물을 독립적인 존재로서 보았다.

예를 들어 동양적 사고방식에서는 나의 아버지는 회사에서는 회사원이고 누군가에겐 친구인 반면에; 서양적 사고방식에서는 철수는 집에서도 철수이고, 회사에서도 철수, 언제 어디서든 철수는 철수이다.

그래서 동양에서는 전체를 조화로운 것으로 여기는 반면; 서양에서는 이런 독립적 요소들의 단순합으로서 전체를 보는 경향이 있다.

요소의 속성

주변을 배제했으므로; 사건이 일어날 경우 그 사물/인물의 내부에서 원인을 찾게 된다. 그것이 바로 그 사물/인물의 속성이 된다. 예를 들어; 똑같이 높은 데에서 떨어져도 유리는 깨지고 스펀지는 안 깨지는 이유는 유리와 스펀지의 속성이 다르기 때문이다. 아리스토텔레스의 사원소설에 따르면 불이 위로 가는 이유는 불의 속성이 가벼움이기 때문이다.

반면에 동양에서는 맥락과 관계에서 원인을 찾는 경향이 있다. 예를 들어 누군가 묻지마 살인 사건을 일으켰다면 그 이유로 사회 부적응을 드는 것이 좀더 동양적, 원래 그 사람의 본성이 포악하기 때문으로 보는 쪽이 더 서양적이다.

공통속성을 모은 범주

세상 사물들의 속성들을 파악하고 나면; 같은 속성을 가진 것들이 있음을 알게 된다. 그 속성들을 추출하여 만든 추상적 개념을 범주라고 한다.

예를 들어; 팬더, 원숭이, 대나무, 바나나를 둘둘씩 엮을 때; 동양인들은 대체로 서로 연관된 것끼리 [팬더, 대나무], [원숭이, 바나나]로 묶는 반면; 서양인은 대체로 [팬더, 원숭이], [대나무, 바나나]로 묶는다. 동물, 식물이라는 범주가 기준이 된 것이다. 팬더와 원숭이는 둘 다 털가죽, 팔다리, 눈코입 등이 있고 움직일 수 있다는 공통점이 있기 때문에 같은 범주에 속한다.

또한 범주에는 적은 것들의 많은 공통점을 모은 하위범주, 많은 것들의 적은 공통점을 모은 상위범주가 있다. 이런 식으로 범주끼리의 계통도를 구성할 수 있다.

범주 기반 법칙

범주에 기반한 규칙을 세우고, 이 규칙으로써 사물들의 움직임을 설명한다. 이것이 세상의 법칙이 된다.

그래서 동양에서는 전혀 다른 곳에서 공통적으로 나타나는 패턴에 주목하여 만물의 연관성을 발견하려는 데에 비해; 서양에서는 분야가 다르면 별개의 것으로 본다. 예를 들어 인간사회에는 인간사회의 규칙이 있고, 원자세계에는 원자들의 규칙이 있고, 우주에는 천체들의 규칙이 있다.

프로그래밍에 적용

비트 하나로는 [참/거짓], [맞다/아니다], [있음/없음]을 나타낼 수 있다. 이런 생각은 인간적이다. 또한 비트는 2진수의 각 자리에 대응되어 수를 나타낼 수도 있다. 크고 복잡한 수도 비트들로 나타낼 수 있다. 수학적으로는 옳지만 그것은 비인간적이다. 인간은 큰 수를 다룰 때 10진법이라는 다른 방식을 쓰기 때문이다.

절차지향 프로그래밍은 원래 인간적이다. 우리가 사는 1차원 시간 속에서 일은 순차적으로 진행되기 때문이다. 하지만 그보다 더 크고 복잡한 일을 하는 프로그램을 만들어야 할 때 절차지향은 비인간적이게 되었다. 프로그램의 규모가 커질 수록 프로그래밍은 단순히 명령어 나열이 아니라 우리의 이성적 생각을 기계에 이식하는 일이 된다. 그러니까 조금 더 복잡한 시스템을 표현하고자 할 땐 조금 더 복잡한 인간의 생각을 따라해야 하고; 현대 대부분의 학문의 주축인 서양인들의 사고방식이 그 기준이 된 건 자연스러운 일이지 않을까? 딱히 근거는 없고 그냥 내 뇌피셜이다. 혹은; 서양적 사고방식이 동양적 사고방식보다는 세상을 좀 더 단순하게 취급하기 때문에; 절차지향의 바로 다음 자리를 차지할 수 있었을까? 나야 확신하진 못하지만…

어쨌든 앞서 소개한 그 사고방식을 프로그래밍에 적용해보자.

캡슐화

프로그램을 구성하는 많은 요소들 중 서로 연관이 깊은, 즉 독립적이지 않은 요소들을 모아서 독립적인 요소 즉 객체로 만든다. 달리 말하자면; 독립적이지 않은 것은 독립적인 무언가의 속성인 것으로 취급한다. 속성은 그 자체로는 아무것도 아니며; 객체를 통해서만 드러난다. 이를 캡슐화라 한다. 이로써 프로그램은 독립적인 요소들의 모임이 된다.

여기서 ‘독립적’이란; 그 자체로 의미를 가졌음을 뜻한다. 예를 들어 어떤 전화번호는 "누군가의" 전화번호일 때에야 의미가 있으므로 독립적이지 않다. 영희는 철수가 있든 없든 영희이므로 독립적이다.

캡슐화를 하면 무엇과 무엇이 연관있는지 명확해지고, 독립적인 의미를 가진 단위는 따로 떼어 생각하기 쉽기 때문에; 프로그램 일부를 수정할 경우 그 영향을 파악하고 제한하기 쉬워진다. 따라서 유지보수가 쉬워진다.

상속

공통 속성을 가진 객체들끼리 묶어 범주화하고 계통을 만든다. 그래서 하위 범주는 상위 범주의 속성을 모두 가지는데; 이를 상속이라 한다.

공통적인 것을 모아서 하나로 표현했으므로 코드의 재사용이 된다. 그러나 코드의 재사용이 곧 상속인 것은 아니다. 그건 앞뒤가 바뀌는 거다. IS-A, HAS-A 관계를 설명하는 클리셰가 있는 건 아마 이 앞뒤를 헷갈려서 그런 거겠지.

클래스
여기서 객체의 범주라는 개념은 많은 언어에서 ‘클래스’라고 일컬어진다.
프로토타입
범주의 역할을 하는 객체. 어떤 언어에선 추상화를 통해 범주를 만들기보다, 그 범주의 가장 대표적·전형적인 특징을 가진 객체 하나를 범주의 표본 즉 프로토타입으로 삼음으로써 상속을 구현한다.

다형성

객체의 범주에 기반하여 실행내용을 결정한다.

오버라이딩
주체의 범주에 따라 다른 명령이 실행됨.
오버로딩
인자의 범주에 따라 다른 메서드를 호출 즉 다른 명령을 실행시킴.

이상의 세 가지 개념(캡슐화, 상속, 다형성)은 OOP의 대표적인 특징으로 일컬어진다.

OOP를 설명할 때 가장 예시로 많이 들리는 언어는 Java이다. 이는 Java가 유명하기 때문이기도 하지만 아마 Java가 OOP의 이상형에 가장 가깝기 때문인 것도 같다.(뇌피셜)

…개인적으로 생각하는 한계

프로그래밍에서 새로운 개념이 등장했다 하면 맨날 하는 소리가; 이것으로써 변화에 유연하게 대응된다고 한다. 그 전에는 안 유연했다는 소리다. 객체지향을 설명하는 많은 글들은 객체지향을 절차지향과 비교하며, 변화에 잘 대응한다고 말하지만; 나는 미천한 경험을 통해 꼭 그렇지만은 않다고 느꼈다. 절차지향은 정적인 사건흐름을 기술하는데 비해 객체지향은 유동적인 사건흐름을 만들 수 있다. 하지만 그 수단은 정적인 세계관이다. 애초에 상기된 사고방식을 가지고 있던 사람들의 세계관은; 불변하거나, 변하더라도 그 변화가 직선적인 세계였다.

우리집 바둑이나 옆집 멍멍이는 태어났다가, 돌아다니다가, 죽을 수 있다. 하지만 ‘개’라는 추상적 개념은 불멸이다. 클래스는 불멸이다. 거기다; 사건의 근원이 객체 내부이며, 그 구체적 동작도 클래스에 따라 결정된다고 하는 믿음이 객체지향의 기반이다.

그래서 프로그램은 클래스라는 불멸의 틀을 벗어나지 못하며; 이 틀을 프로그래머들은 매우 신성시한다. 틀의 신성함이 잘못됐다는 얘긴 아니다! 단지 틀을 지키는 데에 너무 많은 노력이 든다. 목적을 위해 틀이 만들어졌음에도; 원래의 목적보다 틀 자체의 관리에 더 많은 노력이 드는 경우가 허다하다.

사건의 근원이 명백히 객체 밖에 있을 때, 이 틀에 유동성이 생겨야 할 때조차도 원래의 목적에 필요한 최소한의 것보다 더 많은 코드를 공들여 작성함으로써 객체지향을 지켜야 하는 운명에 처해있다. 불쌍한 나님! 객체지향 프로그램을 언제까지나 객체지향 프로그램으로 남기기 위해서; 나는 매일 종속성 문제에 허덕인다.

이제는 이 허덕임을 조금 해결해주는 기법과 기술들이 꽤 등장했다.

참고

Richard Nisbett (2003) 생각의 지도 떼잉~ 이것도 벌써 거의 20년이나 지난 책이 되어버렸군~ 이 때도 점점 그러긴 했지만 이젠 정말 그보다 더 서양적이니 동양적이니 구별이 더더더 의미없어진 거 같기도 해….

728x90