오브젝트 독서회 3회차 - 3장 역할, 책임, 협력

Intro

이번 3회차 독서회는 강남역 부근 옐로스톤 스터디룸에서 진행했습니다.
스터디룸이 꽤 작았습니다.
스터디 장소에 도착했을 때 카운터에 아무도 안계셨는데, 스터디를 마치고 나오는 길에도 카운터에 아무도 안 계셔서 의아했는데, 문을 나서기 직전 '에어컨과 비어있는 스터디룸의 전등을 꺼달라’는 요청을 받았습니다.
뭐 어려운 것은 아니기에 하긴 했지만, 신선한 경험이었습니다.

이번에도 안타깝게도 @아메리카노 님께서 대학교 개강 일정으로 불참하셨습니다.
2회차 때처럼 시간이 많이 남았기 때문에 여유롭게 스터디 나눔을 했습니다.


독후감 문장

73P

객체지향 패러다임의 관점에서 핵심은 역할(role), 책임(responsibility), 협력(collaboration) 이다.

@muki4742 @콘크리트장인

객체지향의 본질은 협력하는 객체들의 공동체를 창조하는 것이다.

@Vincent @콘크리트장인

애플리케이션의 기능을 구현하기 위해 어떤 협력이 필요하고 협력을 위해 어떤 역할과 책임이 필요한지를 고민하지 않은 채 너무 이른 시기에 구현에 초점을 맞추는 것은 변경하기 어렵고 유연하지 못한 코드를 낳는 원인이 된다.

@콘크리트장인 @freebear

74P

다시 한번 강조하지만 객체지향에서 가장 중요한 것은 역할, 책임, 협력이다.

@freebear

역할, 책임, 협력이 제자리를 찾지 못한 상태라면 응집도 높은 클래스와 중복 없는 상속 계층을 구현한다고 하더라도 여러분의 애플리케이션이 침몰하는 것을 구원하지 못할 것이다.

@Vincent @콘크리트장인

여기서 중요한 것은 다양한 객체들이 영화 예매라는 기능을 구현하기 위해 메시지를 주고받으면서 상호작용한다는 점이다.

@freebear

이처럼 객체들이 애플리케이션의 기능을 구현하기 위해 수행하는 상호작용을 협력이라고 한다. 객체가 협력에 참여하기 위해 수행하는 로직은 책임이라고 부른다. 객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 역할을 구성한다.

@Vincent @콘크리트장인

75P

객체는 고립된 존재가 아니라 시스템의 기능이라는 더 큰 목표를 달성하기 위해 다른 객체와 협력하는 사회적인 존재다.

@freebear

메시지 전송은 객체 사이의 협력을 위해 사용할 수 있는 유일한 커뮤니케이션 수단이다.

@muki4742

객체 사이의 협력을 설계할 때는 객체를 서로 분리된 인스턴스가 아닌 협력하는 파트너로 인식해야 한다.

@Vincent

메시지를 수신한 객체는 메서드를 실행해 요청에 응답한다.

@콘크리트장인

76P

자신이 할 수 없는 일을 다른 객체에게 위임하면 협력에 참여하는 객체들의 전체적인 자율성을 향상시킬 수 있다.

@Vincent @콘크리트장인

어떤 객체도 섬이 아니다.

@콘크리트장인

77P

협력이 바뀌면 객체가 제공해야 하는 행동 역시 바뀌어야 한다.

@Vincent

객체는 자신의 상태를 스스로 결정하고 관리하는 자율적인 존재이기 때문에 객체가 수행하는 행동에 필요한 상태도 함께 가지고 있어야 한다.

@콘크리트장인

78P

즉, 객체의 책임은 객체가 '무엇을 알고 있는가’와 '무엇을 할 수 있는가’로 구성된다.

@콘크리트장인

80P

CRC 카드

@freebear

81P

앨리스터 코오번(Alistair Cockburn)은 'Agile Software Development’에서 효과적으로 일하는 사람들은 추상적으로 가상적인 것보다는 구체적이고 실재적인 것을 사용하는 경향이 있다고 설명한다.

82P

객체지향 설계는 시스템의 책임을 완료하는 데 필요한 더 작은 책임을 찾아내고 이를 객체들에게 할당하는 반복적인 과정을 통해 모양을 갖춰간다.

@freebear

객체가 책임을 수행하게 하는 유일한 방법은 메시지를 전송하는 것이므로 책임을 할당한다는 것은 메시지의 이름을 결정하는 것과 같다.

@Vincent

83P

이처럼 책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방법을 **책임 주도 설계(Responsibility-Driven Design, RDD)**라고 부른다.

@Vincent @콘크리트장인

84P

구현이 아닌 책임에 집중하는 것이 중요한 이유는 유연하고 견고한 객체지향 시스템을 위해 가장 중요한 재료가 바로 책임이기 때문이다.

@Vincent

하나는 메시지가 객체를 결정한다는 것이고, 다른 하나는 행동이 상태를 결정한다는 것이다.

@muki4742 @콘크리트장인

85P

객체지향 패러다임에 갓 입문한 사람들이 가장 쉽게 빠지는 실수는 객체의 행동이 아니라 상태에 초점을 맞추는 것이다.

@Vincent

캡슐화를 위반하지 않도록 구현에 대한 결정을 뒤로 미루면서 객체의 행위를 고려하기 위해서는 항상 협력이라는 문맥 안에서 객체를 생각해야 한다.

@freebear

86P

실제로 협력을 모델링할 때는 특정한 객체가 아니라 역할에게 책임을 할당한다고 생각하는 게 좋다.

@콘크리트장인

87P

역할이 중요한 이유는 역할을 통해 유연하고 재사용 가능한 협력을 얻을 수 있기 때문이다.

@Vincent @콘크리트장인

88P

안타깝게도 이런 방법으로 두 협력을 구현하면 대부분의 코드가 중복되고 말 것이다. 프로그래밍에서 코드 중복은 모든 문제의 근원이기 때문에 이런 방법은 피해야 한다.

@콘크리트장인

이 대표자를 협력 안에서 두 종류의 객체를 교대로 바꿔 끼울 수 있는 일종의 슬롯으로 생각할 수 있다. 이 슬롯이 바로 역할 이다.

@콘크리트장인

89P

이제 새로운 할인 정책을 추가하기 위해 새로운 협력을 추가할 필요가 없어졌다.

@Vincent

추상화라는 말에서 예상했겠지만 역할을 구현하는 가장 일반적인 방법은 추상 클래스인터페이스를 사용하는 것이다.

@콘크리트장인

90P

객체에 관해 생각할 때 '이 객체가 무슨 역할을 수행해야 하는가?'라고 자문하는 것이 도움이 된다. 이 질문은 객체가 어떤 형태를 띠어야 하는지, 그리고 어떤 동작을 해야 하는지에 집중할 수 있게 도와준다.

@muki4742

91P

도메인 모델 안에는 개념과 객체와 역할이 어지럽게 뒤섞여 있으며 이것은 사람들이 세계를 바라보는 일반적인 관점이다.

@muki4742

이에 대한 개인적인 견해는 설계 초반에는 적절한 책임과 협력의 큰 그림을 탐색하는 것이 가장 중요한 목표여야 하고 역할과 객체를 명확하게 구분하는 것은 그렇게 중요하지 않다는 것이다.

@Vincent @muki4742

96P

배우가 여러 연극에 참여하면서 여러 배역을 연기할 수 있는 것처럼 객체 역시 여러 협력에 참여하면서 다양한 역할을 수행할 수 있다.

@freebear

따라서 객체는 다양한 역할을 가질 수 있다.

@콘크리트장인


이번에는 개인적으로 아주 중요한 챕터였다고 생각합니다. 객체지향의 주요 개념이 모두 소개되었고 객체가 사회적이고 능동적이어야 한다는 것을 요약해서 보여줬기 때문입니다.

이후에 나올 실질적인 추상화 스킬이 기대됩니다.

6 Likes

이번 독서회에서는 메시지가 객체를 결정한다라는 부분에 대해서 다들 궁금해하신 부분이 있었습니다.

그래서 제가 이해한 바를 나눔 했었습니다.

저도 처음 2년 전에 오브젝트 책을 읽었을 때는 객체들이 메서드로 상호작용을 한다고 해서 메서드의 Parameter가 메시지 구나 하고 생각했습니다.

객체지향에 대해 고민했던 시간이 조금 더 길어진 지금, 메시지는 구체화의 key라고 생각하게 되었습니다.

이번 3챕터의 82페이지 마지막 문장을 보면

따라서 새로운 메시지가 필요하다.

라는 문장이 있습니다.

시작은, 어떤 목표에 도달하기 위해 추상적으로 메세지를 던져보는 것입니다.

그리고 점점 생각을 깊게 들어가면서 중간 중간 Goal이 어떤 게 있을지 생각해보는 것입니다.

내가 머리속으로 상상하는 것들이 객체로 있으면 좋겠다고 생각하면서 클래스를 하나씩 구현해보는 것입니다.

끝으로 그 객체의 이름이 곧 클래스 명이 되는 것입니다.


제 경험상, 국내의 개발 문화는 클래스를 너무 많이 만드는 것에 대한 공포가 있다고 생각합니다.

하지만 그 너무 많이에 대한 기준이 없다는 것입니다.

단순히 본인 경험보다 많은 클래스 파일의 목록과 프로젝트 목록을 보면 유지보수에 대한 공포감을 느끼는 것입니다.

물론 객체지향이란 지난 회차에서 살펴봤듯 트레이드오프를 고려하며 맞다/틀리다 보다는 상황에 맞춰 적당하게 하는 것에 포커스를 두고, 서로를 인정해주고 협업하는 좋은 문화를 빌드업하는 것도 포함됩니다.

이번 회차에서는 책임을 기준으로 클래스를 추상화해나가라고 방향을 잡아주고 있습니다.

책임을 가지고 중간 Goal 메세지들을 생각하면서 하나씩 추상화를 해서 클래스를 만들다보면, 겹치는 책임이 생기고 그때 추상클래스와 인터페이스로 추상화해가면서 소스코드의 중복 또한 최소화할 수 있는 것입니다.

그렇게 중간 Goal 로서 추상화된 클래스들은 중간 Layer가 되기 때문에 도메인이 확장될 때 이런 중간 Layer 들을 이용해서 최소한의 수정으로 도메인을 발전시켜 나갈 수 있습니다.

객체지향이 아니라 DevOps 같은 것을 봐도 느슨한 결합으로 중간 Build Layer를 구성해서 Layer를 많이 구성할수록 구성하는 복잡함은 있지만, 중간 Layer를 이용해서 배포슬롯을 여러개 구성하거나 테스트 자동화 같은 더 많은 것들을 할 수 있습니다.

따라서 도메인의 확장을 위해서는 중간 Layer는 필수인 것이고, 더욱 단단한 도메인의 Boilerplate 구성을 위해 RDD기반의 객체지향도 중요한 것입니다.

일을 할 때도 추상적인 명령보다는 구체적으로 Atomic 하게 잘 쪼개진 Task가 일정을 관리하기에도 편하고 달성률도 좋습니다.

따라서 중간 Layer가 되는 계층, 즉 메시지들은 유용하고 도메인을 발전시키며 더 많은 확장의 기회를 가져다줍니다.

추상화를 위한 클래스를 만들어 나가는 것에 대해 두려움을 갖지 말고, 도메인 성장의 기회로 생각하며 개발했으면 좋겠습니다.

(물론 그런 중간 Layer가 좋다고해서 IT서비스를 처음부터 MSA(Micro-Service-Architecture)로 시작하는 게 올바른 것은 아니듯, 성숙하지도 않은 도메인에 대해 무조건 최고의 추상화와 중간 Layer 메시지들을 구성하면 안 됩니다.)

6 Likes

" 클래스를 너무 많이 만드는 것에 대한 공포"에서 순살이 되었습니다. 생각해보니 아직 클래스가 많았던 경험을 해보지 못해서 생긴 명확하지 않은 두려움 같습니다. ㅎㅎ 좋은 글 감사합니다~

2 Likes