개요
•
좋은 아키텍처를 만드는 작업은 객체 지향 설계 원칙을 이해하고 응용하는 것에서 시작된다.
•
그렇다면 객체 지향이란 정확히 무엇인가?
◦
어떤 이는 데이터와 함수의 조합이라고 말한다.
▪
하지만 o.f()가 f(o)와 다르다는 의미를 내포하고 있어 설득력이 부족하다.
◦
또 다른 이는 실제 세계를 모델링하는 새로운 방법이라고 한다.
▪
하지만 실제 세계를 모델링한다는 것의 의미와 그 방향성을 추구해야 하는 이유가 불분명하다.
◦
또 다른 이들은 캡슐화, 상속, 다형성을 중심으로 객체 지향을 설명한다.
▪
이들은 객체 지향이 이 세 가지 개념의 적절한 조합이라고 주장한다.
캡슐화?
•
객체지향을 정의하는 핵심 요소 중 하나로, 객체 지향 언어는 데이터와 함수를 효과적으로 캡슐화하는 방법을 제공한다.
◦
이를 통해 데이터와 함수가 응집력 있게 구성된 단위들을 명확하게 구분할 수 있다.
◦
이러한 구분선 바깥에서 데이터는 은닉되며, 특정 함수만이 외부에 노출된다.
◦
이런 개념들은 객체지향 언어에서 private, public과 같은 접근 제한자로 표현된다.
•
하지만 객체지향 언어는 캡슐화에 전적으로 의존하지는 않는다.
◦
대신 프로그래머가 올바르게 행동하여 캡슐화된 데이터를 우회하지 않을 것이라는 신뢰를 기반으로 한다.
상속?
•
객체지향 언어는 캡슐화를 약화시켰으나, 상속 기능만큼은 확실하게 제공했다.
◦
하지만 상속이란 본질적으로 변수와 함수를 하나의 유효 범위로 묶어 재정의하는 메커니즘에 불과하다.
•
이전의 프로그래밍 언어들도 상속과 유사한 기능을 제공했지만, 이는 진정한 상속이 아닌 모방에 가까웠다.
•
객체지향 언어는 이러한 상속 기능을 체계적이고 편리하게 제공한다.
다형성?
•
getchar() 함수는 STDIN에서 문자를 읽는다. 그렇다면 STDIN은 어떤 장치일까?
•
putchar() 함수는 STDOUT으로 문자를 쓴다. 그렇다면 STDOUT은 어떤 장치일까?
•
이러한 함수들은 다형적이다. 즉, STDIN과 STDOUT의 타입에 따라 그 행위가 달라진다.
•
함수를 가리키는 포인터를 응용한 것이 다형성이다.
•
객체지향 언어는 새로운 다형성을 제공하지는 않지만, 다형성을 더욱 안전하고 편리하게 사용할 수 있게 해준다.
•
다형성이 가진 힘 - 새로운 장치의 등장
◦
새로운 장치의 입출력 드라이버가 5가지 표준 함수를 구현한다면 장치와 무관하게 사용할 수 있다.
◦
즉, 입출력 드라이버가 프로그램의 플러그인이 된 것이다.
◦
유닉스 운영체제가 입출력 장치들을 플러그인 형태로 만든 이유는 프로그램이 장치에 독립적이어야 하기 때문이다.
◦
플러그인 아키텍처는 입출력 장치의 독립성을 지원하기 위해 만들어졌으며, 이후 대부분의 운영체제에서 구현되었다.
•
객체지향의 등장으로 플러그인 아키텍처를 어디서든 적용할 수 있게 되었다.
•
의존성 역전
◦
위 함수에서 Main은 고수준 → 중수준 → 저수준 모듈을 차례로 호출한다. 즉, 제어 흐름은 소스 코드 의존성을 반드시 따른다.
◦
하지만 다형성이 이 구조에 추가되면 특별한 일이 일어난다.
◦
위 그림에서 HL1 모듈은 ML1 모듈의 F() 함수를 호출한다(점선). 소스 코드에서 HL1 모듈은 인터페이스를 통해 F() 함수를 호출한다(실선).
◦
이 인터페이스는 런타임에는 존재하지 않으며, HL1은 단순히 ML1을 호출할 뿐이다.
◦
하지만 여기서 ML1과 인터페이스 사이의 소스 코드 의존성이 제어 흐름과는 역전된다.
◦
이러한 접근법을 사용하면 객체 지향 언어로 개발된 시스템의 소프트웨어 아키텍트는 시스템의 모든 소스 코드 의존성의 방향을 결정할 수 있다.
◦
위 예시를 보면 UI와 Database는 Business Rules에 의존하도록 소스 코드 의존성이 부여되었다.
◦
즉, UI와 Database가 Business Rules의 플러그인이 되어 각 컴포넌트가 독립적으로 동작하게 된다.
▪
배포 독립성 - 컴포넌트의 소스 코드가 변경되면 해당 코드가 포함된 컴포넌트만 다시 배포하면 된다.
▪
개발 독립성 - 배포 독립성이 있으면 서로 다른 팀에서 각 모듈을 독립적으로 개발할 수 있다.
결론
•
객체 지향이란 다형성을 통해 시스템의 모든 소스 코드 의존성을 완벽하게 제어할 수 있는 능력이다.
•
객체 지향 언어를 사용하면 아키텍트는 플러그인 아키텍처를 구성할 수 있으며, 이를 통해 고수준 정책을 담은 모듈이 중·저수준 모듈로부터 독립성을 확보할 수 있다.
•
저수준의 세부사항들은 플러그인 모듈로 분리할 수 있어, 고수준 정책 모듈과 독립적인 개발 및 배포가 가능하다.