Post
KO

오브젝트 (2)

1~2장에 걸쳐서 기본적인 객체지향 관련 내용이 많이 담겨있다.

예제 코드와 더불어 무엇이 문제인지, 어떤 방법으로 생각하는 것이 좋은지에 대해 잘 설명해준다.

로버트 마틴(Robert C. Martin)은 클린 소프트웨어: 애자일 원칙과 패턴, 그리고 실전방법에서 소프트웨어 모듈이 갖야 할 세가지 기능에 대해서 다음과 같이 이야기 했다고 한다.

모든 소프트웨어는 3가지 목적이 있다. 첫 번째 목적은 실행 중 제대로 동작하는 것. 두 번째 목적은 변경을 위해 존재하는 것. 세 번째 목적은 코드를 읽는 사람과 의사소통 하는 것.

앞서 이야기 한 것들 중에서 변경을 위해 존재하는 것에 대해서는 예전에도 한번 머리를 크게 얻어 맞는 것 같은 충격을 받은 적이 있다.

객체지향 사실과 오해 6장에서도 저자분께서 언급한 부분도 있다.

유일하게 변하지 않는 것은 모든 것이 변한다는 사실 뿐이다. - 헤라클레이토스 (Heraclitus of Ephesus)

변경 이라는 것은 우리가 일을 할 때에도 많이 겪게 되는 스트레스 중 하나 인 것 같다.

처음 이야기와 두번째 이야기가 달라지고, 기능도 달라지고 계속해서 변하는 것이 발생할 때 마다 개발자는 짜증을 내고 힘들어 할 수 밖에 없다.

이러한 것을 좀더 유연하게 당연하다 여기고 변경에도 취약하지 않게 잘 설계할 수 있는 방법이 없을까? 라는 고민을 했더라면 더 나은 해결책을 얻었을텐데..

변경에 취약한 코드란 의존성과 결합도에 의하여 문제가 발생되며 이러한 부분을 해결 할 수 있는 방법을 모색하는 것이 더 나은 코드를 작성 할 수 있는 방법이 아닐까 싶다.

책에서는 객체지향 설계의 핵심은 적절한 객체에 적절한 책임을 할당하는 것 이라고 한다.

이런 부분이 나올 때 마다 DDD가 생각 나는 것은 무엇일까? 개인적으로는 매우 어렵다. 적절한 객체와 적절한 책임을 가질 수 있도록 객체 설계를 잘해야 하며 도메인에 대해서 정확하게 잘 이해하고 있어야 한다는 것..

설계를 어렵게 만드는 것은 의존성이며 해결 방법은 불필요한 의존성을 제거 함으로써 객체 사이의 결합도를 낮추는 것이다. 결합도를 낮추기 위해 선택한 방법은 캡슐화가 있다. 여기서 캡슐화란 객체의 자율성을 높이고 응집도 높은 객체들의 공동체를 창조할 수 있도록 한다고 한다.

어떠한 설계를 할 때에는 다음과 같이 생각해 볼 수 있다.

어떤 기능을 설계하는 방법은 한가지 이상일 수 있다.

동일한 기능을 한 가지 이상의 방법으로 설계할 수 있기 때문에 결국 설계는 트레이드 오프의 산물이다.

-> 트레이드 오프의 산물.. 이 것을 이해하지 못한체 얼마나 많은 시간과 감정을 서로에게 쏫아 부었는지 모르겠다. 합리적으로 생각하면 나올 거라 생각하는데, 이때 문제는 서로 간의 이해하고 있는 지식에 바탕이 되는 것이 문제가 아닌가 싶다.

객체지향 설계

설계란 코드를 배치하는 것이다.

좋은 설계란 오늘 요구하는 기능을 온전히 수행하면서 내일의 변경을 매끄럽게 수용할 수 있는 설계 라고 한다.

변경에 수용할 수 있는 설계는 위와 같이 언급한 요구사항은 항상 변경되기 때문이다.

훌륭한 객체지향 설계란 협력하는 객체 사이의 의존성을 적절하게 관리하는 설계이다.

협력, 객체, 클래스

객체지향은 객체를 지향하는 것이다. 객체지향 언어에 익숙한 사람이라면 가장 먼저 어떤 클래스(class)가 필요한지 고민할 것이다. 그런데 안타깝게도 이것은 객체지향의 본질과는 거리가 멀다. 객체지향은 말 그대로 객체를 지향하는 것이다.

(한국 말은 너무 어려움 -_-;)

첫째, 어떤 클래스가 필요한지 고민하기 전에 어떤 객체들이 필요한지 고민하라.

둘째, 객체를 독립적인 존재가 아니라 기능을 구현하기 위해 협력하는 공동체의 일원으로 봐야 한다.

<도메인이란 문제를="" 해결하기="" 위해="" 사용자가="" 프로그램을="" 사용하는="" 분야를="" 도메인이라고="" 부른다.=""> ​ **자율적인 객체** ​ 객체가 상태(state)와 행동(behavior)을 함께 가지는 복합적인 존재이다. 객체가 스스로 판단하고 행동하는 자율적인 존재 이다. ​ 객체라는 단위 안에 데이터와 기능을 한 덩어리로 묶음으로써 문제 영역의 아이디어를 적절하게 표현 할 수 있다. 이러한 데이터와 기능을 객체 내부로 함께 묶는 것을 **캡슐화** 라고 부른다. ​ **프로그래머의 자유** ​ 프로그래머의 역할을 클래스 작성자(class creator)와 클라이언트 프로그래머(client programmer)로 구분하는 것이 유용하다. ​ 클래스 작성자는 클라이언트 프로그래머에게 필요한 부분만 공개하고 나머지는 꽁꽁 숨겨야 한다. 이를 구현 은닉(implementation hiding)이라고 부른다. ​ 설계가 필요한 이유는 변경을 관리하기 위해서라는 것을 기억하라. ​ (변경! 변경! 변경!! 손정의 따라해 봄) ​ **협력** **​** 객체가 다른 객체와 상호작용할 수 있는 유일한 방법은 메시지를 전송하는 것 뿐이다. 다른 객체에게 요청이 도착할 때 해당 객체가 메시지를 수신했다고 이야기 한다. 이 처럼 수신된 메시지를 처리하기 위한 자신만의 방법을 메서드(method)라고 부른다. ​ 설계가 유연해질수록 코드를 이해하고 디버깅하기는 점점 더 어려워진다는 사실을 기억하라. ​ **상속과 인터페이스** **​** 상속이 가치 있는 이유는 부모 클래스가 제공하는 모든 인터페이스를 자식 클래스가 물려받을 수 있기 때문이다. 이것은 상속을 바라보는 일반적인 인식과는 거리가 있는데 대부분의 사람들은 상속의 목적이 메서드나 인스턴스 변수를 재사용 하는 것이라 생각하기 때문이다. ​ (완전 뜨끔 -_-;) ​ 인터페이스는 객체가 이해할 수 있는 메시지의 목록을 정의한다는 것을 기억하라. ​ **다형성** 동일한 메시지를 전송하지만 실제로 어떤 메서드가 실행될 것인지는 메시지를 수신하는 객체의 클래스가 무엇이냐에 따라 달라진다. 이것을 **다형성** 이라고 부른다. ​ 다형성을 구현하는 방법은 매우 다양하지만 메시지에 응답하기 위해 실행될 메서드를 컴파일 시점이 아닌 실행 시점에 결정한다는 공통점이 있다. ​ **구현 상속과 인터페이스 상속** 상속은 구현 상속이 아니라 인터페이스 상속을 위해 사용해야 한다. 대 부분의 사람들은 코드의 재사용을 상속의 주된 목적이라고 생각하지만 이것은 오해다. 인터페이스를 재사용할 목적이 아니라 구현을 재사용할 목적으로 상속을 사용하면 변경에 취약한 코드를 낳게 될 확률이 높다. ​ 특정 설계를 했는데 기존에 취급하던 방식과 일관성이 유지되는지 생각해봐야 한다. 일관성이 무너지는 순간 협력하던 객체간 문제가 발생할 수 있다. ([명사] 하나의 방법이나 태도로써 처음부터 끝까지 한결같은 성질.) ​ 상속은 객체지향에서 코드를 재사용하기 위해 널리 사용되는 기법이다. 하지만 두가지 관점에서 설계에 안좋은 영향을 준다. ​ 상속이 캐슐화를 위반 한다는 것. 설계를 유연하지 못하게 한다는 것. ​ **합성** ​ 합성은 상속이 가지는 두 가지 문제점을 모두 해결한다. 구현을 효과적으로 캡슐화 할 수 있고, 의존하는 인스턴스를 교체하는 것이 비교적으로 쉽기 때문에 설계를 유연하게 만든다. 상속은 클래스를 통해 강하게 결합되는데 비해 합성은 메시지를 통해 느슨하게 결합된다. 따라서 코드 재사용을 위해서는 상속보다는 합성을 선호하는 것이 더 좋은 방법이다. ​ 책에서는 마지막에 다시한번 정리하고 있다. ​ 객체지향이란 객체를 지향하는 것이다. 객체지향 패러다임의 중심에는 객체가 위치한다. 협력에 참여하는 객체들 사이의 상호작용이고, 결론적으로는 적절한 협력을 식별하고 협력에 필요한 역할을 정의한 후 역할을 수행 할 수 있는 적절한 객체에게 적절한 책임을 할당하는 것이다. ​ ​
This article is licensed under CC BY 4.0 by the author.