Kilian
by Kilian

Categories

Tags

내용 요약

로버트 마틴은 소프트웨어 모듈이 가져야 하는 세 가지 기능에 관해 설명한다.
여기서 모듈이란 크기와 상관 없이 클래스나 패키지, 라이브러리와 같이 프로그램을 구성하는 임의의 요소를 의미한다.
마틴에 따르면 모든 모듈은 제대로 실행돼야하고, 변경이 용이해야하며, 이해하기 쉬워야한다.

이해 가능한 코드란 그 동작이 우리의 예상에서 크게 벗어나지 않는 코드다.
현실에서는 관람객이 직접 자신의 가방에서 초대장을 꺼내 판매원에게 건넨다. 티켓을 구매하는 관람객은 가방 안에서 돈을 직접 꺼내 판매원에게 지불한다. 판매원은 매표소에 있는 티켓을 직접 꺼내 관람객에게서 직접 돈을 받아 매표소에 보관한다.

변경에 취약한 코드는 많은 객체사이의 의존성(dependency)이 있는 코드다.
의존성은 변경에 대한 영향을 암시한다. 의존성이라는 말 속에는 어떤 객체가 변경될 때 그 객체에게 의존하는 다른 객체도 함께 변경될 수 있다는 사실이 내포되어있다.
그렇다고 해서 객체 사이의 의존성을 완전히 없애는 것이 정답은 아니다.
객체지향 설계는 서로 의존하면서 협력하는 객체들의 공동체를 구축하는 것이다.
따라서 우리의 목표는 필요한 최소한의 의존성만 유지하고 불필요한 의존성을 제거하는 것이다.
객체 사의의 의존성이 과한 경우를 가리켜 결합도(coupling)가 높다고 말한다.
반대로 객체들이 합리적인 수준으로 의존하는 경우에는 결합도가 낮다고 말한다.
결합도는 의존성과 관련돼 있기 때문에 결합도 역시 변경과 관련이 있다.
두 객체 사이의 결합도가 높으면 높을수록 함께 변경될 확률도 높아지기 때문에 변경하기 어려워진다.
따라서 설계의 목표는 객체 사이의 결합도를 낮춰 변경이 용이한 설계를 만드는 것이어야한다.

자율성을 높이자

설계를 변경하기 어려운 이유는 하나의 객체가 다른 객체가 가지고있는(has)객체까지 마음대로 접근할 수 있기 때문이다. 해결방법은 객체를 자율적인 존재=로 만들면 되는 것이다.
자율적인 존재인 객체는 객체가 자신의 문제를 스스로 해결하도록 변경하는 것이다.
이 처럼 자율적인 존재가 된 객체가 내부의 세부적인 사항을 감추는 것을 캡슐화(encapsulation)라 부른다.
캡슐화의 목적은 변경하기 쉬운 객체를 만드는 것이다. 캡슐화를 통해 객체 내부로의 접근을 제한하면 객체와 객체 사이의 결합도를 낮출 수 있기 때문에 설계를 좀 더 쉽게 변경할 수 있게 된다.
객체를 인터페이스(interface)구현(implementation)으로 나누고 인터페이스만을 공개하는 것은 객체 사이의 결합도를 낮추고 변경하기 쉬운 코드를 작성하기 위해 따라야 하는 가장 기본적인 설계 원칙이다.

캡슐화와 응집도

핵심은 객체 내부의 상태를 캡슐화하고 객체간의 오직 메시지를 통해서만 상호작용하도록 만드는 것이다.
밀접하게 연관된 작업만을 수행하고 연관성 없는 작업은 다른 객체에게 위임하는 개체를 가리켜 응집도(cohesion)가 높다고 말한다.
자신의 데이터를 스스로 처리하는 자율적인 객체를 만들면 결합도를 낮출 수 있을뿐더러 응집도를 높일 수 있다.
객체의 응집도를 높이기 위해서는 객체 스스로 자신의 데이터를 책임져야 한다.
자신이 소유하고 있지 않은 데이터를 이용해 작업을 처리하는 객체에게 어떻게 연관성 높은 작업들을 할당할 수 있겠는가?
객체는 자신의 데이터를 스스로 처리하는 자율적인 존재여야 한다. 그것이 객체의 응집도를 높이는 첫걸음이다.
외부의 간섭을 최대한 배제하고 메시지를 통해서만 협력하는 자율적인 객체들의 공동체를 만드는 것이 훌륭한 객체지향 설계를 얻을 수 있는 지름길인 것이다.

책임

객체지향 설계에서는 독재자가 존재하지 않고 각 객체에 책임이 적절하게 분배된다.
따라서 각 객체는 자신을 스스로 책임진다. 객체지향 애플리케이션은 스스로 책임을 수행하는 자율적인 객체들의 공동체를 구성함으로써 완성된다.
사실 객체지향 설계의 핵심은 적절한 객체에 적절한 책임을 할당하는 것이다.
객체는 다른 객체와의 협력이라는 문맥안에서 특정한 역할을 수행하는 데 필요한 적절한 책임을 수행해야 한다.
따라서 객체가 어떤 데이터를 가지느냐보다는 객체에 어떤 책임을 할당할 것이냐에 초점을 맞춰야한다.

트레이드오프

첫째 어떤 기능을 설계하는 방법은 한가지 이상일 수 있다.
둘째 동일한 기능을 한 가지 이상의 방법으로 설게할 수 있기 때문에 결국 설계는 트레이드오프의 산물이다.
어떤 경우에도 모든 사람들을 만족시킬 수 있는 설계를 만들 수는 없다.
설계는 균형의 예쑬이다. 훌륭한 설계는 적절한 트레이드오프의 결과물이라는 사실을 명심하라.
이러한 트레이드오프 과정이 설계를 어려우면서도 흥미진진한 작업으로 만드는 것이다.

의인화

객체지향의 세계에 들어오면 모든 것이 능동적이고 자율적인 존재로 바뀐다.
예를 들어, Bag(가방)과 Theater(소극장)은 실세계에서는 자율적인 존재가 아니다.
소극장에 관람객이 입장하기 위해서는 누군가가 소극장의 문을 열고 입장을 허가해줘야 한다.
가방에서 돈을 꺼내는 것은 관람객이지 가방이 아니다.
그럼에도 우리는 이들을 관람객이나 판매원 같은 생물처럼 다뤘다. 무생물 역시 스스로 행동하고 자기 자신을 책임지는 자율적인 존재로 취급한 것이다.
이처럼 능동적이고 자율적인 존재로 소프트웨어 객체를 설계하는 원칙을 가리켜 의인화(authropomorphism)라고 부른다.
훌륭한 객체지향 설계란 소프트웨어를 구성하는 모든 객체들이 자율적으로 행동하는 설계를 가리킨다.
그 대상이 비록 실세계에서는 생명이 없는 수동적인 존재라고 하더라도 객체지향의 세계로 넘어오는 순간 그들은 생명과 지능을 가진 싱싱한 존재로 다시 태어난다.

좋은 설계

좋은 설계란 무엇인가?
우리가 짜는 프로그램은 두 가지 요구사항을 만족시켜야한다.
우리는 오늘 완성해야 하는 기능을 구현하는 코드를 짜야하는 동시에 내일 쉽게 변경할 수 있는 코드를 짜야한다.
변경을 수용할 수 있는 설계가 중요한 이유는 요구사항이 항상 변경되기 때문이다.
개발을 시작하는 시점에 구현에 필요한 모든 요구사항을 수집하는 것을 불가능에 가깝다.
모든 요구사항을 수집할 수 있다고 가정하더라도 개발이 진행되는 동안 요구사항을 바뀔 수밖에 없다.

객체지향 설계

객체지향 프로그래밍은 의존성을 효율적으로 통제할 수 있는 다양한 방법을 제공함으로써 요구사항 변경에 좀 더 수월하게 대응할 수 있는 가능성을 높여준다.
단순히 데이터와 프로세스를 객체라는 덩어리 안으로 밀어 넣었다고 해서 변경하기 쉬운 설계를 얻을 수 있는 것은 아니다.
객체지향의 세계에서 애플리케이션을 객체들로 구성되며 애플리케이션의 기능은 객체들 간의 상호작용을 통해 구현된다. 그리고 객체들 사이의 상호작용은 객체 사이에 주고 받는 메시지로 표현된다.


느낀점

같은 작가인 조영호님의 <객체지향의 사실과="" 오해="">라는 책을 먼저 읽고나서 한참이 지난 후 다시 객체지향 프로그래밍에 대해 되짚어 볼 수 있었다. 객체는 자기 자신의 세부정보를 캡슐화하여 구현을 숨기고, 인터페이스에 의존하여 구현하도록하여 자신의 데이터를 스스로 책임을 지도록 해야한다는 부분을 다시 되새길 수 있었다. 회사 코드를 보고 내부 구현을 외부로 노출하는 형식의 구현이 있었나 다시 확인 해봐야겠다는 생각이 먼저 들었다. 멀티모듈 프로젝트에 대해 고민하고 레이어드 아키텍처 기준으로 모듈을 분리하면서 책임이라는게 코드수준 뿐만아니라 아키텍처 수준에서도 다시 생각하게 되는 부분이었다.