Post
EN

객체 지향 프로그래밍

이 질문에 흔히 “실제 세계를 모델링하는 새로운 방법” 이라고들 답한다.

이는 기껏해야 얼버무리는 수준에 지나지 않는다. 도대체 “실제 세계를 모델링한다”라는 말이 무엇을 의미하며, 왜 우리는 그 방향을 추구해야 하는가? 이 답변이 전달하려는 의도는 OO는 현실 세계와 의미적으로 가깝기 때문에 OO를 사용하면 소프트웨어를 좀 더 쉽게 이해할 수 있다는 데 있는 듯하다.

OO의 본질을 설명하기 위해 세 가지 주문에 기대는 부류도 있는데, 캡슐화(encapsulation), 상속 (interitance), 다형성(polymorphism)이 바로 그 주문이다.

캡슐화?

OO를 정의하는 요소 중 하나로 캡슐화를 언급하는 이유는 데이터와 함수를 효과적으로 캡슐화 하는 방법을 OO 언어가 제공하기 때문이다. 그리고 이를 통해 데이터와 함수가 응집력 있게 구성된 집단을 서로 구분 짓는 선을 그을 수 있다. 구분선 바깥에서 데이터는 은닉되고, 일부 함수만 노출된다.

자바와 C#은 헤더와 구현체를 분리하는 방식을 모두 버렸고, 이로 인해 캡슐화는 더욱 심하게 훼손되었다.

이 때문에 OO가 강력한 캡슐화에 의존한다는 정의는 받아들이기 힘들다.

실제로 많은 OO 언어가 캡슐화를 거의 강제하지 않는다.

상속?

OO언어가 더 나은 캡슐화를 제공하지는 못했지만, 상속만큼은 OO언어가 확실히 제공했다.

얼추 맞는 말이지만, 상속이란 단순히 어떤 변수와 함수를 하나의 유효 범위로 묶어서 재정의하는 일에 불과하다.

다형성?

함수를 가리키는 포인터를 응용한 것이 다형성이라는 점이다. 1940년대 후반 폰 노이만(Von Neumann)아키텍처가 처음 구현된 이후 프로그래머는 다형적 행위를 수행하기 위해 함수를 가리키는 포인터를 사용해 왔다. 따라서 OO언어가 새롭게 만든 것은 전혀 없다.

다형성이 가진 힘

왜 유닉스 운영체제는 입출력 장치들을 플러그인 형태로 만들었는가? 1950년대 후반에 우리는 프로그램이 장치적 독립적(device independent)이어야 한다는 사실을 이미 배웠기 때문이다. 무슨 말이냐고? 당시 우리는 장치에 의존적인 수많은 프로그램을 만들고 나서야, 이들 프로그램이 다른 장치에서도 동일하게 동작할 수 있도록 만드는 것이 우리가 진정 바랐던 일임을 깨달았다.

플러그인 아키텍처는 이처럼 입출력 장치 독립성을 지원하기 위해 만들어졌고, 등장 이후 거의 모든 운영체제에서 구현되었다.

의존성 역전

다형성을 안전하고 편리하게 적용할 수 있는 메커니즘이 등장하기 전 소프트웨어는 어떤 모습이었을지 생각해 보자. 전형적인 호출 트리의 경우 main 함수가 고수준 함수를 호출하고, 고수준 함수는 다시 중간 수준 함수를 호출하며, 중간 수준 함수는 다시 저수준 함수를 호출한다. 이러한 호출 트리에서 소스 코드 의존성의 방향은 반드시 제어흐름(flow of control)을 따르게 된다.

![](/assets/images/posts/222620301424/801bed62f59b.png?type=w580)

![](/assets/images/posts/222620301424/3fe24ad548b5.png?type=w580)

그림 5.2에서 HL1 모듈은 ML1 모듈의 F() 함수를 호출한다.

이 인터페이스는 런타임에는 존재하지 않는다. 단순히 HL1은 ML1 모듈의 함수 F()를 호출할 뿐이다.

하지만 ML1과 I 인터페이스 사이의 소스 코드 의존성(상속 관계)이 제어흐름과는 반대인 점을 주목하자. 이를 의존성 역전 (depedency inversion) 이라고 부르며, 소프트웨어 아키텍트 고나점에서 이러한 현상은 심오한 의미를 갖는다.

OO 언어가 다형성을 안전하고 편리하게 제공한다는 사실은 소스 코드의 의존성을 어디서든 역전 시킬 수 있다는 뜻이기도 하다.

소스 코드의 의존성은 소스 코드 사이에 인터페이스를 추가함으로써 방향을 역전시킬 수 있다.

이러한 접근 방법을 사용한다면, OO 언어로 개발된 시스템을 다루는 소프트웨어 아키텍트는 시스템의 소스 코드 의존성 전부에 대해 방향을 결정할 수 있는 절대적인 권한을 갖는다.

소프트웨어 아키텍트는 소스 코드 의존성을 원하는 방향으로 설정할 수 있다.

이것이 OO언어가 제공하는 힘이다. 그리고 이것이 바로 OO언어가 지향하는 것이다.(최소한 아키텍트의 관점에서는)

이러한 힘으로 무엇을 할 수 있는가? 예를 들어 업무 규칙이 데이터베이스와 사용자 인터페이스(UI)에 의존하는 대신에, 시스템의 소스 코드 의존성을 반대로 배치하여 데이터베이스와 UI업무 규칙에 의존하게 만들 수 있다.

![](/assets/images/posts/222620301424/5e0a690b4b0a.png?type=w580)

특정 컴포넌트가 소스 코드가 변경되면, 해당 코드가 포함된 컴포넌트만 다시 배포하면 된다. 이것이 바로 배포 독립성(Independent deployability)이다.

시스템의 모듈을 독립적으로 배포할 수 있게 되면, 서로 다른 팀에서 각 모듈을 독립적으로 개발할 수 있다. 이것을 개발 독립성(Independent developability)이다.

결론

OO란 다형성을 이용하여 전체 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력이다. 저수준의 세부사항은 중요도가 낮은 플러그인 모듈로 만들 수 있고, 고수준의 정책을 포함하는 모듈과는 독립적으로 개발하고 배포할 수 있다.

This article is licensed under CC BY 4.0 by the author.