[Clean Architecture] CH5 객체 지향 프로그래밍

2 minute read


객체 지향(Object Oriented)은 무엇인가?

  • 객체 지향의 본질은 세 가지(캡술화, 상속, 다형성)를 통해 설명하려는 부류가 존재함
  • 이 사람들은 객체 지향은 세 가지 개념을 적절하게 조합한 것이거나, OO 언어는 최소한 세가지 요소를 반드시 지원해야 한다고 함

캡슐화(Encapsulation)

  • 객체 지향 언어느 데이터와 함수를 쉽고 효과적으로 캡슐화하는 방법을 제공함
    • 이를 통해 데이터와 함수는 응집력 있게 구성된을 서로 구분 짓는 선을 그일 수 있음
    • 구분선 바깥에서 데이터는 은닉되며, 일부 함수만이 외부에 노출됨
    • 이 개념들은 실제 객체 지향 언어에서 각각 클래스의 private 맴버 데이터와 public 맴버 함수로 표현됨
    • C언어는 완전한 캡슐화를 지원함
      • 데이터 구조와 함수를 헤더 파일에 선언, 구현 파일에서 이들을 구현
      • 프로그램 사용자는 구현 파일에 작성된 항목에 대해서는 어떠한 방법으로 접근 불가능함
    • C++ 컴파일러는 기술적인 이유로(인스턴스 크기를 알야 함) 클래스의 맴버 변수를 해당 클래스의 헤더 파일에 선언할 것을 요구함
      • 이 떄문에 사용자는 맴버 변수에는 접근할 수는 없지만 존재를 알게되어 완벽한 캡술화는 깨짐
    • JAVA와 C#은 헤더와 구현체를 분리하는 방식을 모두 버려 캡슐화는 더욱 훼손됨
      • 즉, 클래스 선언과 정의를 구분하는 것이 아예 불가능함
    • 따라서 객체 지향 언어가 강력한 캡슐화에 의존한다는 정의는 받아들이기 힘들며, 실제로 많은 객체 지향 언어는 캡슐화를 거의 강제하지 않음
    • 객체 지향 프로그래밍은 프로그래머가 충분히 올바르게 행동함으로써 캡슐화된 데이터를 우회해서 사용하지 않을 거라는 믿음을 기반으로 함
  • 이러한 점을 고려하면 캡슐화는 객체 지향 언어에 점수를 줄 수 없음

상속(Inheritance)

  • 상속이란 단순히 어떤 함수와 함수를 한의 유효 범위로 묶어서 재정의하는 일이며, 이는 객체 지향 언어가 아닌 C언어세도 구현 가능함
  • 다만, 상속만큼 편리한 방식이 아니며, 다중 상속을 구현하는 것은 훨씬 더 어려운 일임
  • 또한 진짜 객체 지향 언어에서는 업캐스팅이(자식 클래스의 객체가 부모 클래스 타입으로 형변환 되는 것) 암묵적으로 이루어짐
  • 따라서 객체 지향 언어는 새로운 개념을 만들지는 못했지만, 데이터 구조에 가면을 씌우는 일을 상당히 편리한 방식으로 제공함
  • 이러한 점을 고려하면 상속에 대해서는 객체 지향 언어에 0.5점의 점수를 줄 수 있음

다형성(Polymorphism)

  • 다형성은 함수를 가리키는 포인터를 응용한 것임
  • 이는 객체 지향 언어가 아닌 언어에서도 함수 포인터를 활용하여 사용 가능하지만, 이는 위험한 일임
    • 왜냐하면 프로그래머는 포인터를 초기화해야하며, 모든 함수를 포인터를 통해 호출해야 한다는 관례를 준수해야하기 떄문
    • 이 관례가 지켜지지 않을 경우, 버그가 발생하며, 이러한 버그는 찾아내고 없애기가 매우 힘듦
  • 객체 지향 언어는 이러한 관례를 없애주기에, 제어흐름을 간접적으로 전환하는 규칙을 부과한다고 결론지을 수 있음

다형성이 가진 힘

  • 프로그램은 장치 독립적이어야 함
    • 즉, 어떤 장치를 연결해도 동일한 프로그램에서 동작하도록 해야 함
  • 플러그인 아키텍처는 이렇게 장치 동립성을 지원하기 위해 만들어짐
  • 객체 지향 언어의 등장으로 어디서든 플로그러인 아키텍처를 적용할 수 있음

의존성 역전

  • 다형성 전의 프로그램의 제어 흐름은 고수준에서 저수준 함수를 호출하는 방식으로 이루어짐
    • 이에 따라 소스 코드 의존성의 방향은 제어흐름을 따르게 되어 있음
      • 즉, 고수준 함수는 저수준 함수에 의존적임
  • 이에 따라 제어흐름은 시스템의 행위에 따라 결정되며, 소스 코드 의존성은 제어흐름에 따라 결정됨
  • 다형성이 끼어들면 상위레벨의 모듈이 하위레벨의 모듈(인터페이스)을 호출할 때 의존성 역전(Dependency Inversion)이 일어남
    • 왜냐하면 인터페이스와 이 인터페이스를 구현한 모듈 사이의 의존성이 반대이기 때문
      • 즉, 인터페이스와 모듈 사이의 소스 코드 의존성은 제어흐름과는 반대임
  • 객체 지향 언어가 다형성을 안전하고 편리하게 제공한다는 사실은 의존성을 어디에도 역전시킬 수 있다는 뜻임
  • 이를 활용하면, 컴포넌트 간 분리가(즉, 컴포넌트 사이의 의존 관계를 없앨 수 있음) 가능하며, 이는 컴포넌트가 개별적이고 독립적으로 배포 가능함을 의미
    • 즉, 배포의 독립성(independent deployability)이 생김
      • 가령, 특정 컴포넌트의 소스 코드가 변경되면 해당 코드가 포함된 컴포넌트만 다시 배포하면 됨
    • 시스템의 배포가 독립적이면, 모듈은 개발 독립성(independent developability)을 가지게 됨
      • 즉, 서로 다른 팀에서 모듈을 독립적으로 개발할 수 있음
  • 요약하면, 소프트웨어 아키텍트 관점에서 객체 지향이란 다형성을 이용하여 전체 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력임
    • 객체 지향을 사용하면 플러그인 아키텍처를 구성할 수 있고, 이를 통해 고수준의 정책을 포함하는 모듈은 저수준의 세부상을 포함하는 모듈에 대해 독립성을 보장할 수 있음
    • 저수준의 세부사항은 중요도가 낮은 플러그인 모듈로 만들 수 있고, 고수준의 정책을 포함하는 모듈과는 독립적으로 개발하고 배포할 수 있음