[TIL]객체지향프로그래밍을 인문학으로 이해해보자.

김형주·2021년 4월 9일
0
    1. 9 (금) TIL - OOP

    나는 프로그래밍을 공부할 때에 가능하면, 영어 원문으로 된 사이트를 보려고 노력한다. 그 이유는 프로그래밍의 기원 자체가 영어권 국가들에 있기 때문이다. 개념을 이해하기 위해서는 무엇보다, 원문 자체에서 의미를 뽑아내려는 노력이 가장 중요하다는 생각이 든다. 프로그래밍을 처음 공부하던 시기에는 원문보다 한국어가 편해서, 한국어로 작성한 블로그 위주로 돌아다녔지만, 아무래도 같은 언어라고 하더라도 다른 문화적 배경을 가지고 있는 한국인이 이해할 때는 개개의 방식으로 원 개념을 이해하려고하기 때문에 원본 내용과 차이를 보이는 경우가 많기 때문일 것이다.

Object Oriented Programming이란?


위에서 작성한 것처럼, 다른 것보다 먼저 저렇게 네이밍이 된 이유를 찾으려면 해당되는 단어들의 뜻을 명확히 할 필요가 있다. 간단하게 Object오 Oriented를 사전에서 찾아보면 다음과 같다.

Object (명사)

  1. 목적, 목표
  2. 객체, 대상, 목표물
  3. 목적어

Orient (동사)

  1. ~을 지향하게 하다. (특정 목적에) 맞추다.
  2. (주변 상황과 관련지어)자기 위치를 알다.
  3. (새로운 상황에) 적응하다.

당연히 알고 있는 뜻이겠지만, 어떤 '대상'이라는 것에 대해 중점적으로 파고드는 프로그래밍방식이라는 것을 이해할 수 있다. 지향이라는 단어 뜻도 중요하겠지만 가장 중요한 것은 Object 즉, 사물이라는 것에 집중하는 방식이라는 것을 쉽게 이해할 수 있다.

Object이란?

알파벳으로 이루어진 영어라는 언어는 기본적으로 유럽의 그리스에 그 언어가 기원하고 있다고 한다. 유럽권의 국가들중에 이 단어를 예술적/철학적 가치로 잘 사용하고 있는 국가가 있는데 프랑스다. 프랑스에서는 Object를 Objet(오브제) 으로 사용하고 있다. 예술을 공부해본 사람은 알겠지만, Objet이라는 단어는 기본적으로 사물의 상징성, 혹은 본질 그 자체를 의미하는 것으로 사용된다. 객체라는 것은 결국 세상에 있는 것들 모든 것의 본질이라고 볼 수 있으며 Object라는 것은 본질을 파악하는 것을 목적으로 한다는 의미를 담고 있다는 것을 알 수 있다.

사람들은 기본적으로 세상을 살아가면서 세상에 존재하는 모든 '것'이라는 것을 인식하고 이해하려고 한다. 역사가 있기 이전부터 태양이 뜨면 '태양'의 의미를 찾으려 노력했고, 달이 뜨면 '달'의 의미를 찾으려고 했다. '허기짐'이 온다면 사람들은 다시끔 그것이 무엇인지 의미를 찾으려고 했을 것이다. 그런 인간의 본질적인 행동양식 자체를 모방해서 프로그래밍에 적용하려고 했다는 의미로 볼 수 있다. 객체 지향 프로그래밍 언어라는 것은, 세상에 존재하는 것을 파악하는 인간의 방법을 컴퓨팅에 사용하고자한 것이다.

요람에서부터 인간들은 세상을 분류하기 시작한다.

아기들은 태어나서, 보통 18개월 쯤 되면 한가지 단어를 말할 수 있게 된다. 24개월이 넘어서면 2가지 단어를 이어 붙여 말할 수 있게 된다. 이때 아기들을 잘 살펴보면 되게 재밌는 것을 알 수 있다. 아기들은 세상을 나름의 방식으로 이해하려고 노력하는데, 그것이 언어로 나타난다. 처음엔 움직이는 것에 반응하고 움직이지 않는 것에 반응하고, 이후엔 색이나 소리에 따라서 사물을 구분한다.

예를 들면, 시간이 더 지나고 나서 모든 동물을 '멈멈이'라고 표현한다던지, 모든 타고다니는 것을 '빵빵'으로 표현한다던지. 더 크게되면 '멍멍이'가 강아지라는 것을 인식하게되고, 강아지만을 구분한다. 자라면서 더 크고 나면, 색깔이나 강아지가 짖는 소리에 따라 무서운 강아지, 안 무서운 강아지, 귀여운 강아지, 성인이 되면 하얗고 털이 몽글몽글 자라서 머리가 동그란 강아지는 "비숑"이라는 것까지 내려오게 된다.

이게 학문으로 발전하면서 동물을 분류하는 방식이 훨씬더 자세하게 바뀌어왔는데, 실제 동물 분류 체계를 살펴보면 다음과 같다. 이것은 꼭 동물이 아니더라도, 기본적으로 세상의 것들을 분류할 때 사람은 다음과 같은 방식을 즐겨쓴다. 공통점으로 묶고, 차이점에서 분기해서 중간에 공통점과 차이점이 만나는 곳에 분류 단계를 만들어 낸다. 이게 프로그래밍이랑 무슨 상관이냐고 하겠지만, 그냥 계속 깊이 들어가보고자 한다.

객체 지향 프로그래밍과 인간의 인식의 공통점

왼쪽의 이미지는 UML로 간단하게 표현해본 객체 관계도를 표현한 것이다. 간단하게 - 와 +는 public, private로 외부에 정보가 공개되어있는지 없는지에 대한 이야기라고 생각하면된다.

도형(Shape)이라는 분류 체계에서 형태의 차이에 따라 Circle, Triangle, Square가 Shape를 상속한다. 이 얘기는 부모 자식의 개념일 수도 있지만, 내 생각에는 공통점이라는 묶이는 것이라는 생각이 든다. 그리고 밑에서 나눠져 나가는 것은 차이에 따라 분기가 생기는 것이다.

이게 무엇을 이야기하는걸까?

세상은 프로그래밍처럼 순차적으로만 이해할수도 없고 표현할 수도 없다. 내가 지금 당장 이 블로깅을 멈추고 내 방에서 걸어나가는 순간 무슨 일이 무조건 발생한다고 확답할 수 없다. 내가 당장 부엌에 가서 커피를 탈 수도 있는 것이고, 화장실이 갑자기 급해져서 화장실에 갈 수도 있다. 그러한 급변하는 상황을 표현하기에 "순차적 방식"이라는 것은 어울리지 않는 것이다.

그게 무슨 말이야?

간단하게 생각해보자. 프로그래밍이 발전하기전에는 asembly, C언어처럼 절차적언어로도 충분히 구현할 수 있었다. 이 얘기는 그 이전에 프로그래밍이라는 분야 자체가 현실세계와 다르게 순차적인 작업들밖에 없었다는 것이다. 1을 더하고, 1을 더하고, 1을 빼면 1이 나오는 너무 당연한 순차적 논리만 필요했다. 애당초 Computer라는 것은 계산기을 위해 만들어낸 것이었기 때문이다.

그런데 세상이 발전하게 되면서 컴퓨터는 그 이상의 무언가를 계속해서 요구받았다. 사람은 밥을 먹으면서 책을 읽으면서 음악을 들을 수 있다. 화장실에서 다른 생각을 하면서 벽에 손가락으로 글씨를 적을 수도 있다. 이것은 순차적으로 일어날 수도 있지만, 동시에 일어나기도 하고, 순서가 계속해서 바뀌면서 발생하기도 한다. 사람들이 컴퓨터를 일상처럼 사용하게되면서, 이러한 사람의 행동양식과 분석방식을 받아들여야할 필요성이 생긴 것이다.

객체지향 프로그래밍

모든 동작과 데이터 값을 공통점과 차이점으로 분류해서 비절차적이고 소통가능한 방향으로 작동시키기 위해 사람을 베껴낸 방식이라고 볼 수 있다. 이를 이용하면 모든 사건을 분류할 수 있고 이것들간에 관계성이 이어지게 된다. Instance를 어떤 어플리케이션의 기능으로 이해하면, 세부 기능으로 분류하고 이것들간의 관계와 순서를 정할 수 있게 되고, Instance를 어떤 게임의 캐릭터라고 이해하면, 캐릭터간의 상호작용의 순서를 정하고 행위의 선후를 결정할 수 있게 된다.

AppFunction


class AppFunction {
	constructor(___, ___, ___){
		this.setting1 = 0;
		this.setting2 = 0;
		this.setting3 = 0;
	}
	on(){
	//기능을 작동한다.
	}
	off(){
	//기능을 멈춘다.
	}
	settingOn(){
	//기능 세부사항 설정을 켠다.
	}
	settingOff(){
	//기능 세부사항 설정을 끈다.
	}
}
const soundOption = new AppFunction();
soundOption.settingOn = ()=> {
										//사운드 옵션을 킨다.
										};
soundOption.settingOff = ()=> {
										//사운드 옵션을 끈다.
										};
const startOption = new AppFunction();
const displayOption = new AppFunction();

대략 이런 방식이 되지 않겟나 생각해본다. 앱 기능이라고 가정해보고 코드를 짜본 것인데, 아마 이런 식으로 세부 기능의 정의를 재설정해서 분류를 나눠가다보면 전체 기능을 구현할 수 있을 것이다. 만약 게임 캐릭터라고 하면 서로의 HP/MP/게임머니보유량 같은 것을 설정해두고 이것들을 변화시키도록 하는 방식으로하면 구현 가능할 것이다.

GamePlayer


class PlayableCharactor {
    constructor(str, dex, int, hp, mp){
        this.str = str;
        this.dex = dex;
        this.int = int;
        this.hp = hp;
        this.mp = mp;
    }
    hit(skill) {
        this.skill = skill;
    }
}
class Knight extends PlayableCharactor {
		constructor(className){
				this.className = className;
		}
		defend(shield) {
				this.shield = shield;
		}
}

이런 식으로 하게되면, 플레이할 수 있는 캐릭터 범주안에 나이트라는 직업을 포함시키고, 플레이할 수 있는 캐릭터들의 값을 가지되 나이트의 속성과 메소드를 포함한 나이트라는 객체가 생기게 된다. 지금은 제대로 공부하지 않아서 내맘대로 적었다.

하지만 아마도 이런 식으로 하면 객체간의 소통도 가능할 것이라고 생각한다. 결국에는 가장 최상단에는 게임 전체를 포괄하는 어떠한 객체가 위치할 것이고, 하단으로 트리구조로 이어져있는 어떤 프로그램이 될 것이다.

예시를 들어 코드를 적어보니 훨씬 더 깊은 이해가 가능하다는 생각이 들었다. 이것 외에도 Fight라는 인스턴스를 통해서 두 객체가 상호작용을 할 수도 있고, 그 객체는 다시 InterAction이라는 클래스에서 묶인다. Fight라는 클래스는 다시 세부적인 PVP과정에서 일어나는 사건들로 나누어지고, 이런 식으로 연계되어 설계될 수 있을 것이란 생각이 든다.

객체지향프로그래밍의 네가지 컨셉


위의 이야기들을 기반으로 다시 네 가지 기본 개념에 대해서 다시 생각해보자.

Encapsulation (캡슐화)

  • 데이터와 기능을 하나의 단위로 묶는 것
  • 은닉(hiding) : 구현은 숨기고, 동작은 노출시킴
  • 느슨한 결합(Loose Coupling)에 유리 : 언제든 수정가능

Inheritance (상속)

  • 다른 것에서 공통점을 찾는다.
  • 하지만 차이점이 있어서 공통점을 받은거다.
  • 선조로 부터 받아온 찬란한 유산을 보아라!ㅋㅋ

Abstraction (추상화)

  • 기능이 구현되는 방법을, 단어 하나로 대체
  • 내부가 어떻게 돌아가는지 모르지만, 이건 이거다.
  • 난 이걸 이렇게 부르겠다.

Polymorphisom (다형성)

  • 같으면서도 다른 것들이 오지게 많다.
  • 세상에는 많은 것들이 있다. individual하게 나타낼 수 있다.
  • 아무리 오지게 많아도 분류해낼 것이다.

캡슐화(Encapsulation)


말이 캡슐이지, 이렇게 이해하면 더럽게 어렵다. 왜 캡슐 안에 넣은건지 생각해보면 쉽다. 지금 보고 있는 컴퓨터를 보자. 노트북이면 노트북, 모니터면 모니터 하나로 있을 것이다. 어떤 미치광이가 만든 모니터나 노트북이 아니라면 정갈하게 물건하나로 딱 정리되서 깔끔하게 생겼을 것이다.

혹시 노트북을 이렇게 해놓고 쓰는 사람이 있나? 칩을 아예 빼두고, 키보드는 키보드대로, 스피커는 스피커대로, 버튼은 버튼대로 전부 따로따로 흩어놓고 사용하는 사람이 있나? 혹시 그렇게 판매하고 있는 노트북 회사가 있다면 알려주길 원한다.

왜 위에 사진처럼 해놓고 판매를 하고 사용을 하는지 모르겠다면, 당신은 사람이 아닐 것이다. 이유는 간단하다. 저렇게 한군데로 몰아서 조립해놓고 사용해야 편리하고, 수리가 편하고 일단 가장 중요한건 이게 뭔지 바로 알 수 있다는 것이다.

노트북이라는 것을 바로 인지할 수 있고, 이게 뭔지 안다면 바로 어떻게 다뤄야하는지 알 수 있다. 더불어 저런 전기선이나 보드판 따위를 보지 않아도 편리하게 "노트북" 그 자체로 이용할 수 있는 것이다.

추상화(Abstraction)


말을 이렇게 해놓으니까 어렵다. 그래서 내 방식대로 이해하자면, 이름 붙이기다. 진짜 쉽게 얘기해보자면 이런건데, 내가 어떤 친구를 불러서 만나려고 한다. 나는 내 친구를 부르기 위해 간단하게 "~야, 오늘 치맥 콜?"이라고 카톡만 보내면 된다. 이게 왜 간단한지 모르겠다면, 친구를 이름말고(별명도 이름이다.) 불러보도록하자.

머리둘레가 59cm에 키가 176cm정도되고, 몸무게는 65kg, 발사이즈는 270에 피부는 하얀편에 속하면서, 머리 색깔은 갈색에 머리카락 길이는 15cm 정도 되고, 시력은 양쪽 1.5정도에, 목소리는 굵은 편에 속하고, 어느 대학교를 나왔고, 어느 고등학교를 나왔고, , , , , , 기타 등등

친구 한 명을 부르기 위해 쓰잘데기 없는 정보들이 너무 많이 필요하다. 나는 그런 것들을 몰라도 내 친구를 찾고 싶다. 내가 하고자하는 건 내 친구와의 치맥이지, 내 친구를 하나 찾는데 저런 세부정보들을 다 찾아볼 필요가 없다. 그 친구는 "이름"이 있다. 난 이름만 알면 그 친구를 찾을 수 있다.(물론 동명이인도 있겠지만, 그런 걸 설명하기 위한 것이 아니다.) 복잡하게 그 친구가 누군지 구구절절 설명하지 않아도 이름만 있으면 해결된다.

이와 비슷하게, " 먹다. " 라는 이 정말 단순하고도 간단한 행위를 먹다라는 단어를 제외하고 설명해보자. 어떻게 설명하게 되지?

음식물을 집어서 입에 넣어서 치아를 이용해 씹어서 충분히 분해시켜서 침을 통해 1차적으로 아밀라아제를 이용해서 탄수화물을 분해시켜서 스무스하게 식도를 따라 내려보내서 이것을 위를 이용해 위산을 이용해 소화시켜서 영양분을 얻는 과정.

아 나 지금 마라탕을 "집어서 입에 넣어서 치아를 이용해 씹어서 충분히 분해시켜서 침을 통해 1차적으로 아밀라아제를 이용해서 탄수화물을 분해시켜서 스무스하게 식도를 따라 내려보내서 이것을 위를 이용해 위산을 이용해 소화시켜서 영양분을 얻는 과정."을 할거야. 이걸 내가 다 알아야할 필요도 없고, 그냥 먹는다는 사실만 알면 된다.

상속(Inheritance)


상속이라는 말을 쓰니까 괜히 숙연해진다. 근데 이게 상속이라는 단어로 붙은 것은 다른 것보다도 공통점이라는 것에 집중을 해야하는 것 같다. 분류를 하기위해 상속을 하는 것이다. 아까 사람은 세상을 분류로 이해한다고 했지않나? 결국에는 순차적으로 가기만 하는 것을 어떤 phase로 나누어서 이해하기 위한 하나의 방식인 것이다. 우리집 귀여운 비숑이를 생각해보면 좋은데, 컴퓨터한테 백날 우리 비숑이라고 해봤자, 그게 뭔지 모른다. 이걸 이해시키기 위해 분류를 시켰다고 생각하면 쉽다.

우리 비숑이는 2020년 9월 1일에 태어났다.
우리 비숑이는 강아지다.
우리 비숑이는 몸에 미색털이 거의 없다.
우리 비숑이는 털이 많이 자라서 얼굴이 둥글둥글하다.
우리 비숑이는 8개월 령이다.
우리 비숑이는 서울시 OO구에 산다.
우리 비숑이는 OO구 OO아파트 OO동 OO호에 같이 산다.
우리 비숑이는 얼굴만 보면 물려고 난리친다.
우리 비숑이 이름은 구름이다.

이런식으로 분류과정을 거친다. 생물이라는 공통점에서 시작해서, 강아지라는 공통점, 순백색 공통점, 얼굴이 둥글둥글한 공통점, 8개월령 연령 공통점, 사는 곳 공통점을 지나 행동습관 공통점을 거쳐, 이름 공통점까지. 수많은 공통점들을 겨쳐서 최종적으로 구름이라는 대상을 찾았다고 볼 수 있다. 결국에 상속이라는 것은 분류를 시키기 위한 것이다. 컴퓨터에게 어떠한 대상이나 행위를 사람이 이해한 방식으로 이해하도록 하기 위한 하나의 방법론이다.

다형성(Polymorphisom)


이것도 세상이 돌아가는 방식인데, 결국 생물이든 사물이든, 행위든 세상에는 엄청나게 다양한 것들이 있다. 우리는 우리가 커오면서 머릿속에 만들어진 분류체계를 가지고, 1초도 안되는 시간에 대상을 구분해낸다. 아무리 미세한 차이여도 다른 것으로 인식한다. 예를 들어 완전 동일한 사양에 동일한 부품을 사용한 본체여도 주인이 다르면 다른 것이다. 누가봐도 똑같이 생겼지만 쌍둥이는 서로 다르다. 이러한 다양한 것들을 분류해내고자 하는 것이 다형성이다. 프로그래밍 안에서도 수많은 다양성이 존재하고 오지게 많은 인스턴스들이 존재한다.

오른쪽 이미지는 노래 "We are the world"라는 곳의 앨범 커버인데, 저기에는 같은 사람이 한명도 없다. 너무도 당연한 소리지만, 우리는 "World"라는 범주에서 묶이지만, 결국은 Individual이다.

마치며

Object Oriented Programming의 의미

나는 맨 처음 C언어를 공부할 때는 얘는 확실히 나와 다르구나를 크게 많이 느꼈었다. 나에게는 의미도 없는 데이터 쪼가리처럼 보였기 때문일 것이다. 구조체같은 것이 있었지만 그 의미가 크게 다가 오지 않았는데, 객체 지향 프로그래밍에 대해서 깊게 생각해보니 프로그래밍이라는 것이 크게 진일보했다는 것을 크게 느꼈다. 결국 OOP라는 것은

사람이 세계를 보고 이해하는 방법을 흉내낸 방법론

이라는 결론에 이를 수 있었다. 프로그래밍은 본디 단순한 절차적 기능을 구현하기 위한 도구에 지나지 않았다. 하지만 시간이 지나면서 컴퓨터도 계산기가 아니라, 엔터테인먼트를 목적으로한 인터페이스로 발전했고 UI, UX라는 개념이 생겨나면서 사람과의 소통도 생겨났다. 이전에는 순차적인 행위만 이루어졌다면, 이제는 사람의 행동양식에 그대로 대응할 수 있는 무언가가 되어야할 소명이 생겼다는 것이다. OOP는 이러한 복잡한 세상을 코드와 데이터 쪼가리에 새겨놓기 위한 하나의 방법으로, 인간의 역사부터 시작한 삶의 방식이 컴퓨터에 적용된 것이라고 생각하면 좋을 것 같다.

이 글을 쓰면서 참 많이 오그라들기도 했지만, 기본적으로 왜 OOP라는 것이 여전히 중심적인 방법론인지 깨닫게 해주는 중요한 포인트였다고 생각한다. 시간이 지나면 다시 이런 생각은 접어두고 코드만 적어내려가는 내 자신을 발견하겠지만, 그때까지 여전히 이 생각을 머릿 속에서 잃어버리지 않는다면 훨씬 대단한 개발자가 될 수 있을거라 생각한다. 이만 글을 줄인다.

profile
만물에 관심이 많은 잡학지식사전이자, 새로운 도전을 꿈꾸는 주니어 개발자 / 잡학지식에서 벗어나서 전문성을 가진 엔지니어로 거듭나자!

0개의 댓글