Search

객체지향의 사실과 오해

후기

제일 처음 저는 C언어를 공부했기 때문에 절차지향적 언어에 익숙해져 있었습니다.
자바를 갓 공부하고 난 후 객체지향에 대한 개념을 완벽하게 이해할 수 없었고 '토끼책'으로 유명한 이 책을 접했습니다.
260페이지쯤의 가벼운 분량과 이상한 나라의 앨리스를 통한 비유는 책에 대한 거부감을 말끔히 없애주었습니다.
초반엔 책을 읽으며 답답한 느낌이 들었습니다.
스스로 생각하도록 뇌를 계속해서 찌르지만 정작 코드는 단 한 줄도 없었기 때문에 무엇을 말하는건지 이해하기 어려웠습니다.
하지만 읽다보니 자연스럽게 객체지향에 대한 개념들이 뇌 속으로 녹아 들어왔고
자바를 공부할 때 배운 '붕어빵틀과 붕어빵' 에서 벗어나 객체들을 협력의 관점에서 바라볼 수 있었습니다.
깨달음을 얻은 이후엔 책의 내용이 재밌었습니다. 심지어 놀라웠습니다.
객체지향에 대한 매력을 제대로 느낄 수 있었으며 코드 한 줄 없던 내용으로 머릿 속에서 코드가 상상되기 시작했습니다.
때마침 스프링 공부를 시작하게 되며 객체지향의 진가를 더욱 느낄 수 있었습니다.
만약 이 책을 읽으려는 분이 계시다면 후회 없는 선택이라고 말씀드리고 싶습니다.
특히 자바를 갓 공부하고 객체지향 개념이 잘 잡히지 않는 분에게 가장 추천드리고 싶습니다.

Chapter 1. 협력하는 객체들의 공동체

객체지향 패러다임의 목적은 현실 세계를 모방하는 것이 아니라 현실 세계를 기반으로 새로운 세계를 창조하는 것입니다.
이 책에선 객체를 역할, 책임, 협력의 관점에서 바라봅니다.
현실 세계의 사람들이 암묵적인 약속과 명시적인 계약을 기반으로 협력하며 목표를 달성해 나가는 과정은
'메시지'를 주고 받으며 공동의 목표를 달성하기 위해 '협력'하는 객체들의 간계를 설명하는데 적합합니다.
일상생활에서 목표는 사람들의 협력을 통해 달성되며 목표는 더 작은 책임으로 분할되고
책임을 수행할 수 있는 적절한 역할을 가진 사람에 의해 수행됩니다.
협력에 참여하는 각 개인은 책임을 수행하기 위해 다른 사람에게 도움을 요청하기도 하며
이를 통해 연쇄적인 요청과 응답으로 구성되는 협력 관계가 완성됩니다.
이 때 사람의 역할은 객체의 역할과 유사하게 다음과 같은 특징을 지닙니다.
여러 객체가 동일한 역할을 수행할 수 있다.
역할은 대체 가능성을 의미한다.
각 객체는 책임을 수행하는 방법을 자율적으로 선택할 수 있다.
하나의 객체가 동시에 여러 역할을 수행할 수 있다.
객체지향 설계의 묘미는 다른 객체와 조화롭게 협력할 수 있을 만큼 충분히 개방적인 동시에
협력에 참여하는 방법을 스스로 결정할 수 있을 만큼 충분히 자율적인 객체들의 공동체를 설계하는데 있습니다.
객체지향의 핵심은 클래스가 아닙니다. 핵심은 적절한 책임을 수행하는 역할 간의 유연하고 견고한 협력 관계를 구축하는 것입니다.
객체지향의 중심에는 클래스가 아니라 객체가 위치하며 중요한 것은 클래스들의 정적인 관계가 아니라 메시지를 주고 받는 객체들의 동적인 관계입니다.
코드를 담는 클래스의 관점에서 메시지를 주고 받는 객체의 관점으로 사고의 중심을 전환하라!

Chapter 2. 이상한 나라의 객체

이 책의 매력은 여기서부터 시작됩니다. 이상한 나라의 앨리스를 객체에 비유해 설명하는데
앨리스가 하는 행동에 따라 앨리스의 상태가 변합니다. 즉, 앨리스가 한 행동의 결과는 앨리스의 상태에 의존적이라는 것입니다.
객체의 다양한 특성을 효과적으로 설명하기 위해선 객체를 상태, 행동, 식별자를 지닌 실체로 보는 것이 효과적입니다.
객체의 상태를 구성하는 모든 특징을 통틀어 객체의 프로퍼티라고 합니다.
또한 객체와 객체 사이의 의미 있는 연결은 '링크'라고 하고 객체의 링크를 통해서만 메시지를 주고 받을 수 있습니다.
링크는 객체가 다른 객체를 참조할 수 있다는 것을 의미하며 일반적으로 한 객체가 다른 객체의 식별자를 알고 있는 것으로 표현합니다.
객체를 구성하는 단순한 값은 속성이라고 하며 객체의 프로퍼티는 속성과 링크라는 두 가지 종류의 조합으로 표현할 수 있습니다.
객체는 수신된 메시지에 따라 적절히 행동하면서 협력에 참여하고 그 결과로 자신의 상태를 변경합니다.
객체는 협력에 참여하는 과정에서 자기 자신의 상태뿐만 아니라 다른 객체의 상태 변경을 유발할 수도 있습니다.
사용자는 객체가 제공하는 인터페이스를 통해서만 객체에 접근할 수 있습니다. 이 점은 객체의 캡슐화를 강조합니다.
하지만 상태를 중심으로 객체를 바라보는 것은 설계에 나쁜 영향을 끼칩니다.
상태를 먼저 결정할 경우 캡슐화가 저해된다.
객체를 협력자가 앙닌 고립된 섬으로 만든다.
객체의 재사용성이 저하된다.
객체지향 설계는 애플리케이션에 필요한 협력을 생각하고 협력에 참여하는데 필요한 행동을 생각한 후 행동을 수행할 객체를 선택하는 방식으로 수행됩니다.
협력 안에서 객체의 행동은 결국 객체가 협력에 참여하면서 완수해야 하는 책임을 의미하기 때문에 어떤 책임이 필요한가를 결정하는 과정이 전체 설계를 주도해야 합니다.
행동이 상태를 결정한다는 사실을 명심하라!

Chapter 3. 타입과 추상화

"현상은 복잡하다. 법칙은 단순하다. 버릴 게 무엇인지 알아내라." - 리처드 파인만
객체지향 패러다임은 객체라는 추상화를 통해 현실의 복잡성을 극복합니다.
공통점을 기반으로 객체들을 묶기 위한 그릇을 개념이라고 하고 개념을 이용해 객체를 여러 그룹으로 분류할 수 있습니다.
특정한 개념이 객체에 적용됐을 때 객체를 개념의 인스턴스라고 합니다.
적절한 분류 체계는 애플리케이션을 다루는 개발자의 머릿속에 객체를 쉽게 찾고 조작할 수 있는 정신적인 지도를 제공합니다.
따라서 우리는 객체를 최대한 직관적으로 분류해야 합니다.
타입의 정의는 개념의 정의와 완전히 동일합니다. 타입은 공통점을 기반으로 객체들을 묶기 위한 틀입니다.
동일한 책임을 수행하는 일련의 객체는 동일한 타입에 속한다고 말할 수 있습니다. 동일한 행동이란 동일한 책임을 의미하며 동일한 책임이란 동일한 메시지 수신을 의미합니다.
결론적으로 객체의 타입을 결정하는 것은 객체의 행동뿐입니다. 객체가 어떤 데이터를 보유하고 있는지는 타입을 결정하는데 아무런 영향도 미치지 않습니다.
타입은 추상화입니다. 타입을 이용하면 객체의 동적인 특성을 정적으로 다룰 수 있게 추상화 할 수 있습니다.
결국 타입은 시간에 따른 객체의 상태 변경이라는 복잡성을 단순화할 수 있는 효과적인 방법인 것입니다.

Chapter 4. 역할, 책임, 협력

객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메시지를 수신할 것인지를 결정하는 것으로부터 시작됩니다.
책임은 객체의 외부에 제공해 줄 수 있는 정보(아는 것)와 외부에 제공해 줄 수 있는 서비스(하는 것)의 목록입니다.
따라서 책임은 객체의 공용 인터페이스를 구성하는 것이고 객체지향 설계의 예술은 적절한 객체에게 적절한 책임을 할당하는 것입니다.
책임을 결정한 후 실제로 협력을 정제하면서 이를 메시지로 변환할 때는 하나의 책임이 여러 메시지로 분할되는 것이 일반적입니다.
역할은 협력 내에서 동일한 메시지를 이해할 수 있는 객체로 대체할 수 있음을 나타내는 일종의 표식입니다.
동일한 역할을 수행할 수 있다는 것은 해당 객체들이 협력 내에서 동일한 책임의 집합을 수행할 수 있다는 것을 의미합니다.
역할의 개념을 사용하면 유사한 협력을 추상화해서 인지 과부하를 줄일 수 있고
다양한 객체들이 협력에 참여할 수 있기 때문에 협력이 좀 더 유연해지며 다양한 객체들이 동일한 협력에 참여할 수 있기 때문에 재사용성이 높아집니다.
역할은 객체지향 설계의 단순성, 유연성, 재사용성을 뒷받침하는 핵심 개념입니다.

Chapter 5. 책임과 메시지

객체지향 공동체를 구성하는 기본 단위는 '자율적'인 객체입니다.
객체들은 애플리케이션의 기능 구현을 위해 협력하고 협력 과정에서 각자 맡은 바 책임을 다하기 위해 자율적으로 판단하고 행동합니다.
적절한 책임이 자율적인 객체를 낳고 자율적인 객체들이 모여 유연하고 단순한 협력을 낳습니다.
객체가 자율적이기 위해서는 객체에게 할당되는 책임의 수준 역시 자율적이어야 합니다.
자율적인 책임의 특징은 객체가 '어떻게' 해야 하는게 아니라 '무엇'을 해야 하는가를 설명한다는 것입니다.
객체가 다른 객체에 접근할 수 있는 유일한 방법은 메시지를 전송하는 것뿐입니다.
송신자는 메시지 전송을 통해서만 다른 객체의 책임을 요청할 수 있고 수신자는 오직 메시지 수신을 통해서만 자신의 책임을 수행할 수 있습니다. 메시지의 모양이 객체가 수행할 책임의 모양을 결정합니다.
객체가 제공하는 메시지는 외부의 다른 객체가 볼 수 있는 공개된 영역에 속합니다. (public)
메시지를 처리하기 위해 책임을 수행하는 방법은 외부의 다른 객체가 볼 수 없는 객체 자신의 사적인 영역에 속합니다. (private)
외부의 객체는 메시지에 관해서만 볼 수 있고 객체 내부는 볼 수 없기 때문에 자연스럽게 객체의 외부와 내부가 분리됩니다.
이 때 메시지를 처리하기 위해 내부적으로 선택하는 방법을 메서드라고 합니다.
객체지향에서 다형성은 역할, 책임, 협력과 깊은 관련이 있습니다.
서로 다른 객체들이 다형성을 만족시킨다는 것은 객체들이 동일한 책임을 공유한다는 것을 의미합니다. 즉, 대체가능성을 의미합니다.
이러한 다형성은 객체들의 대체 가능성을 이용해 설계를 유연하고 재사용 가능하게 만듭니다.
자율성과 다형성을 통해 메시지 송신자가 메시지를 수신할 객체의 내부 상태를 볼 수 없는 메시지 중심의 설계를 할 수 있게 해줍니다.
결과적으로 메시지 수신자의 캡슐화를 증진시키고 내부 상태를 미리 알 수 없기 때문에 송신자와 수신자가 느슨하게 결합됩니다.
메시지 중심의 설계를 하게되면 객체의 인터페이스를 발견할 수 있습니다.
인터페이스란 어떤 두 사물이 마주치는 경계 지점에서 서로 상호작용할 수 있게 이어주는 방법이나 장치로 다음과 같은 특징이 있습니다.
인터페이스의 사용법을 익히기만 하면 내부 구조나 동작 방식을 몰라도 쉽게 조작하거나 의사를 전달할 수 있다.
인터페이스 자체는 변경하지 않고 단순히 내부 구성이나 작동 방식을 변경하는 것은 인터페이스 사용자에게 아무런 영향이 없다.
대상이 변경되더라도 동일한 인터페이스를 제공하기만 하면 아무런 문제없이 상호작용 할 수 있다.
객체 외부에 노출되는 공용 인터페이스가 아닌 객체의 내부 구조와 작동 방식을 가리키는 것을 구현이라고 합니다.
훌륭한 객체란 구현을 모른채 인터페이스만 알면 쉽게 상호작용 할 수 있는 객체를 의미합니다.
객체 설계의 핵심은 객체를 두 개의 분리된 요소로 분할해 설계하는 것이고 그것은 바로 외부에 공개되는 인터페이스와 내부에 감춰지는 구현으로 이를 인터페이스와 구현의 분리 원칙이라고 합니다.
이러한 분리는 소프트웨어가 항상 변경되기 때문에 중요합니다.

Chapter 6. 객체 지도

소프트웨어 객체는 현실 객체를 모방한 것이 아니라 은유를 통해 현실 객체와 소프트웨어 객체의 차이를 최대한 줄여 재창조한 것입니다.
우리가 은유를 통해 투영해야 하는 대상은 사용자가 도메인에 대해 생각하는 개념들입니다.
도메인 모델을 기반으로 설계하고 구현하는 것은 사용자가 도메인을 바라보는 관점을 그대로 코드에 반영할 수 있게 합니다.
결과적으로 표현적 차이는 줄어들 것이며 사용자의 멘탈 모델이 그대로 코드에 녹아 스며들게 될 것이고 변경에 유연하게 대응할 수 있는 탄력적인 소프트웨어를 만들 수 있습니다.
유스케이스는 사용자의 목표를 달성하기 위해 사용자와 시스템 간에 이뤄지는 상호작용의 흐름을 텍스트로 정리한 것입니다.
유스케이스의 핵심은 사용자의 목표로 공통의 사용자 목표를 통해 강하게 연관된 시나리오 집합입니다.
유스케이스는 사용자와 시스템 간의 상호작용을 보여주는 '텍스트'다. 다이어그램이 아니다.
유스케이스는 하나의 시나리오가 아니라 여러 시나리오들의 집합이다. 시나리오는 유스케이스를 통해 시스템을 사용하는 하나의 특정한 이야기 또는 경로이다.
유스케이스는 시스템이 수행해야하는 기능의 목록을 단순하게 나열한 피처 목록과는 다르다.
유스케이스는 사용자 인터페이스와 관련된 세부 정보를 포함하지 말아야 한다.
유스케이스는 내부 설계와 관련된 정보를 포함하지 않는다.
변경에 유연한 소프트웨어를 만들기 위해서는 유스케이스에 정리된 시스템의 기능을 도메인 모델을 기반으로 한 객체들의 책임으로 분배해야 합니다.
책임-주도 설계는 유스케이스로부터 첫번째 메시지와 사용자가 달성하려는 목표를, 도메인 모델로부터 기능을 수용할 수 있는 안정적인 구조를 제공받아 실제로 동작하는 객체들의 협력 공동체를 창조합니다.
객체지향의 가장 큰 장점은 도메인을 모델링하기 위한 기법과 도메인을 프로그래밍하기 위해 사용하는 기법이 동일하다는 점입니다.
그리고 이러한 연결완전성의 역방향 역시 성립한다는 것입니다. 즉, 코드의 변경으로부터 도메인 모델의 변경 사항을 유추할 수 있습니다.

Chapter 7. 함께 모으기

마틴 파울러는 객체지향 설계 안에 존재하는 세 가지 상호 연관된 관점에 관해 설명합니다.
개념 관점 : 설계는 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현한다.
명세 관점 : 사용자의 영역인 도메인을 벗어나 개발자의 영역인 소프트웨어로 초점이 옮겨 객체의 인터페이스를 바라본다.
구현 관점 : 객체의 책임을 어떻게 수행할지에 초점을 맞추며 인터페이스를 구현하는데 필요한 속성과 메서드를 클래스에 추가한다.
클래스가 은유하는 개념은 도메인 관점을 반영합니다. 클래스의 공용 인터페이스는 명세 관점을 반영합니다. 클래스의 속성과 메서드는 구현 관점을 반영합니다.
개념 관점에서 소프트웨어 클래스가 도메인 개념의 특성을 최대한 수용하면 변경을 관리하기 쉽고 유지보수성을 향상시킬 수 있습니다.
명세 관점에서 클래스의 인터페이스를 바라보며 최대한 변화에 안정적인 인터페이스를 만들기 위해 구현과 관련된 세부 사항이 드러나지 않게 해야 합니다.
구현 관점에서 메서드의 구현과 속성의 변경은 원칙적으로 외부의 객체에게 영향을 미치지 않도록 해야하며 이것은 메서드와 속성이 철저하게 클래스 내부로 캡슐화돼야 한다는 것을 의미합니다.
세 가지 관점을 모두 수용할 수 있도록 개념, 인터페이스, 구현을 함께 드러내야 하고 동시에 코드 안에서 세 가지 관점을 쉽게 식별할 수 있도록 깔끔하게 분리해야 합니다.
인터페이스와 구현을 분리하라!
명세 관점은 클래스의 안정적인 측면을 드러내야 한다.
구현 관점은 클래스의 불안정한 측면을 드러내야 한다.