객체 지향의 사실과 오해를 읽고

Park Suyong·2022년 4월 11일
0

Study

목록 보기
4/12

전반적으로 책에선 객체지향의 오해로써 아래의 내용을 언급한다.

  • 객체지향의 핵심은 클래스가 아니다. 객체들이다.

  • 객체지향 어플리케이션을 설계할 때 주목해야 할 것은 클래스를 어떻게 작성할 것인지가 아니라, 메시지와 협력 그리고 책임과 역할을 적절한 객체에 부여함에 있다.

  • 객체지향은 실세계의 투영이 아니다. 소프트웨어 세계에서는 실세계와 다른 면이 많다.

위 내용 중 특히 흥미로웠던 내용은 1, 2번이다. 그 동안 객체지향 프로그램을 설계해 오면서 클래스에 집중했었다. 하지만, 설계 방식 자체를 클래스가 아닌 객체에 집중하고, 어떤 책임을 할당할 것인지 어떤 메시지를 수신 및 송신할 수 있는지를 고민하는 방향성을 통해 Testable 하고 유연한 구조를 갖춘 프로그램을 개발할 수 있음을 알게 됐다.

책임-주도 설계(Responsibility Driven Design)는 어떤 행동이 필요한지, 그리고 그 행동을 수행할 수 있는 객체는 무엇인지 결정하는 설계 방법이다. 이는 What/Who Cycle 라고도 한다. 이를 통해 응집도 높고 결합력 낮은 객체를 만들 수 있다.

책에서 전반적으로 캡슐화, 추상화, 다형성에 대해 많은 내용을 다루고 있다.

캡슐화

캡슐화란 말 그대로 코드를 캡슐 안에 숨겨버리는 것을 말한다. 비즈니스 로직을 최대한 외부로 공개하지 않고 내부적으로 처리하도록 한 뒤, 비즈니스 로직이 구성된 메서드를 호출하는 public 메서드를 작성한다. 객체의 메서드와 지역 변수를 공개하는 것은 위험하다. 실제 객체의 데이터가 변경되거나 실제 구현 내용이 공개될 수 있기 때문이다.

"객체지향에서는 데이터와 프로세스를 하나의 틀 안으로 함께 묶어 놓음으로써 객체의 자율성을 보장한다." -> 클린 아키텍쳐 참고 반박

추상화

구체적인 사물들 간의 공통점을 가져 가며, 차이점을 과감히 버리는 방식이다. 주로 인터페이스, 추상 클래스를 통해 구현하는 방법이다. 이는 캡슐화와 연관될 수 있다. 불필요한 부분을 숨기고, 인터페이스와 구현을 분리(ISP)시킬 수 있다.

다형성

다형성은 정말 강력한 도구다. 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것을 말한다. 이를 통해 변경에 유연하고 Testable 한, 유지보수성이 뛰어난 어플리케이션을 개발해 낼 수 있다.

(재판 참석자 - 모자 장수, 요리사, 앨리스)

객체지향 설계 기법

1. 책임-주도 설계 (Responsibility Driven Design)
2. 디자인 패턴

추후 GoF 디자인 패턴 도서를 참고한다.

3. 테스트-주도 개발 (Test Driven Development)

TDD는 테스트 코드를 실패하는 코드를 먼저 작성한 뒤, 성공하는 테스트 케이스를 작성하고 그 이후 테스트를 통과했을 때 실제 로직을 작성해 나가는 개발 방법을 말한다. 다만 이 방법은 기본적으로 러닝 커브가 높다. 우선 테스트 케이스를 작성할 수 있어야 하며, 디자인 패턴에 대한 지식과 구현 능력을 어느 정도 갖추어야 하지 않나.. 라고 생각했다.

(추후 공부할 키워드 TDD, BDD, DDD, TDDDD, Mock, Spy)

그렇다면 확장 가능하며 유연하고, 재사용성이 높은 객체는 어떤 이득을 가져다 줄까?

"유일하게 변하지 않는 것은 변한다는 사실 뿐이다." 라는 말을 짚고 넘어가자. 요구사항은 언제나 변할 수 있다. 만약 요구사항이 변경되었을 때, 코드와 구조를 변경하는 것이 매우 어려운 일이 되어 있다면? 되돌릴 수 없는 큰 문제가 발생하게 될 것이다. 그러므로, 어플리케이션은 유연하며 확장 가능한 구조를 바라보며 성장해야 한다. 확장 가능하며 유연하고 재사용성이 높은 객체는 이러한 이점을 가져다 줄 수 있다. 즉, 객체가 어떻게 할 것인지에 집중하지 말고 무엇을 할 것인지에 집중한다. 이로써 시스템은 행위를 변경하기 쉬워진다.

디미터 법칙 (Law of Demeter)

최소 지식 원칙 (Principle of least knowledge) 혹은 Don't Talk to Strangers 라고도 불리는 법칙이다.

특정 객체가 다른 객체에 대해 지나치게 많이 알고 있다면, 해당 객체와의 결합도는 상당히 높은 편이 된다. 객체가 응집도가 떨어지고 결합력이 높아진다면 유지보수성에 커다란 해악이 된다. 하나의 객체를 변경하는 일은 반드시 다른 객체를 변경하는 일로 수반되기 때문이다. 따라서, 객체에게 데이터를 숨기고 함수를 공개하도록 한다. 이것이 디미터 법칙이다.

객체는 다른 객체가 어떤 데이터를 갖고 있는지 알 수 없어야 하며, 이에 대해 쉽게 이해하기 위해서는 dot notation을 여러 개 사용하지 말라는 의미로도 통용된다.

만약 작성한 코드가 다른 객체의 데이터를 직접 확인하고 있다면 디미터 법칙을 위반하고 있지는 않은지 의심하자. 객체의 내부 구조를 외부로 누출시키지 말자.

인터페이스와 구현의 분리 원칙

구현을 변경할 때 외부에 대한 의존성, 영향력을 최소화시키기 위해서는 외부의 객체는 공개된 메서드 등에만 접근할 수 있어야 한다. 객체의 데이터, 구현 세부 사항에 접근한다면 객체 간의 결합력을 높이고 이로 인해 유지보수성이 굉장히 떨어지게 된다.

책임의 자율성이 협력의 품질을 결정한다.

책임이 자율적일수록 적절하게 추상화되며 응집도가 높아지고 결합도가 낮아진다. 또한, 캡슐화가 증진되며 인터페이스와 구현이 명확히 분리되고 설계의 유연성재사용성이 향상된다.

하나의 클래스에는 하나의 책임을 부여한다. 메서드에서도 마찬가지다. 그 책임에 맞도록 네이밍하고, 비즈니스 로직은 추상화한다. 다른 무언가 필요하다면 다른 객체에 요청한다. 다른 객체는 요청한 객체가 알 수 없는 어떤 동작을 취하고, 값을 반환한다.

구조적 설계

불확실한 미래의 변경을 예측한다면서 이를 성급하게 설계에 반영하는 것은 불필요하게 복잡한 설계를 낳는다. (YAGNI 원칙과도 연결될 듯 하다.)

따라서, 미래의 변경을 예측하는 것이 아니라 대비하는 선택지를 취한다. 미래의 변경이 발생할 수 있으므로 변경에 유연한 구조를 취하는 것이다. 기능적인 부분, 혹은 화면은 변화가 구조에 비해 상대적으로 잦다. 따라서, 자주 변경되지 않는 구조를 바탕으로 시스템 전체의 책임을 분할해 각 객체의 책임으로 전환시키도록 한다.

도메인 모델

도메인 모델은 시스템의 다른 부분과 비교했을 때 변경이 그나마 적은 곳이다. 어차피 도메인이 변경된다면 시스템 상의 전체적인 변경은 반드시 발생한다. 따라서, 어플리케이션은 도메인 모델을 기반으로 설계되는 것이 바람직하다. 또한, 어플리케이션을 설계하고 개발하는 과정에서 네이밍은 도메인 모델에서 차용하는 것이 가장 깔끔하다.

상속

후기

생각보다는 책을 읽으며, 쉬운 책은 아니라는 생각을 하게 됐다. 최소한의 디자인 패턴, 각종 개발 방법론 등에 대해 고민해 본 적이 있거나 고민했다면

읽으면서 인상 깊었던 내용도 많고, 조금 아쉬웠던 내용들도 있었다. 간단히 살펴 보자면 역할과 책임, 협력이라는 관점으로 객체를 설명한 부분은 인상 깊은 부분이었다. 객체지향 프로그램을 설계할 때 가장 중요한 것은 각 클래스 혹은 객체가 맡은 책임과 역할이다. 다만, 여기서의 핵심은 단 하나의 책임을 가져야 한다는 것(SRP)이다. 책에서는 객체지향에 대해 비유를 들며 한 사람이 동시에 여러 역할을 수행할 수 있다고 한 부분이 있다. 이에 대해 의구심을 갖게 된다. 한 사람이 하나의 객체를 말하는 것인가, 혹은 클래스를 말하는 것인가? 객체라면 여러 역할을 수행할 수 있다고 볼 수 있다. 메서드 또한 하나의 책임을 수행한다고 볼 수 있으므로. 그러나 클래스라면 여러 책임을 수행할 수 있다는 말이 되버린다. 이는 명백한 SRP 위반이 아닌가?

조금 아쉬웠던 내용으로 말하자면, 비유다. 책의 저자는 객체를 쉽게 설명하고자 비유를 지속적으로 들었다. 하지만, 책의 내용을 읽으면서 지나친 끼워 넣기의 느낌을 없잖아 받게 됐다.

결과적으로는 개발과 유지보수성까지 바라보며 객체지향 원칙과 설계에 대해 짚은 책이다. 한번 쯤은 더 읽어 보는 것이 좋겠다.

profile
Android Developer

0개의 댓글