객체 사이의 의존성을 완전히 없애는 게 좋을까? o x
x. 객체지향 설계는 서로 의존하면서 협력하는 객체들의 공동체를 구축하는 것이다. 따라서 우리의 목표는 애플리케이션의 기능을 구현하는 데 필요한 최소한의 의존성만 유지하고 불필요한 의존성을 제거하는 것이다.
캡슐화란?
개념적이나 물리적으로 객체 내부의 세부적인 사항을 감추는 것을 말한다. 캡슐화의 목적은 변경하기 쉬운 객체를 만드는 것이다. 캡슐화를 통해 객체 내부로의 접근을 제한하면 객체와 객체 사이의 결합도를 낮출 수 있기 때문에 설계를 좀 더 쉽게 변경할 수 있게 된다.
- 객체지향이란 무엇인가….
- 유연성 vs 가독성
- 사용하기 편한 코드 vs 읽기 좋은 코드
- https://github.com/statelyai/xstate
- 상속 vs 합성

좋은 설계란?
- 응집도 높고 결합도 낮은 모듈로 구성된 설계
- 오늘의 기능을 수행하면서 내일의 변경을 수용
- 헷갈리지 말것) 하나의 모듈만 변경 → 모듈 관점에선 전체가 변경되는 게 좋은 거임
- 퍼블릭 인터페이스를 수정했을 때만 다른 모듈에 영향을 미치는 경우
- 변경될 확률이 매우 적은 안정적인 모듈에 의존하는 것은 좋다 o/x
데이터 중심 설계의 문제점
- 데이터 중심의 설계는 본질적으로 너무 이른 시기에 데이터에 관해 결정하도록 강요한다
- 데이터 중심의 설계에서는 협력이라는 문맥을 고려하지 않고 객체를 고립시킨 채 오퍼레이션을 결정한다
5장) 메시지를 결정한 후에 객체를 선택하기
문제 1. 객체지향 설계에서 책임을 할당할 때 가장 먼저 고려해야 할 것은 무엇일까요? 가) 객체가 가지는 데이터 나) 객체가 수행해야 하는 행동 다) 클래스 간의 상속 관계 라) 시스템의 전체적인 결합도
정답 1: (나) 객체가 수행해야 하는 행동
해설: 블로그 본문에 따르면, 객체지향 설계에서는 데이터보다 행동을 먼저 결정해야 합니다. 클라이언트의 관점에서 객체는 어떤 행동(책임)을 하는지가 중요하며, 이것이 객체의 존재 이유를 설명합니다. 즉, 객체가 어떤 데이터를 가지고 있는지보다 어떤 책임을 수행하는지가 우선 고려 대상입니다.
문제 2. 다음 중 GRASP 패턴의 '정보 전문가(Information Expert)' 원칙에 대한 설명으로 가장 올바른 것은? 가) 객체 생성 책임을 가장 관련 깊은 클래스에 할당한다. 나) 시스템의 변화에 따라 행동이 바뀌는 부분을 별도의 클래스로 분리한다. 다) 책임을 수행하는 데 필요한 정보를 가장 많이 아는 객체에 책임을 할당한다. 라) 여러 객체에 책임을 분산시켜 전체적인 결합도를 낮춘다.
정답 2: (다) 책임을 수행하는 데 필요한 정보를 가장 많이 아는 객체에 책임을 할당한다.
해설: 정보 전문가(Information Expert) 패턴은 말 그대로 책임을 수행할 정보를 가장 많이 알고 있는 '전문가'에게 그 책임을 맡기는 원칙입니다. 예를 들어, '영화 예매'라는 책임을 수행하려면 영화, 상영 시간, 좌석 정보 등을 알아야 하므로 '상영(Screening)' 객체에게 예매 책임을 할당하는 것이 이 패턴에 부합합니다. 이는 객체의 자율성과 응집도를 높이고 결합도를 낮추는 효과를 가져옵니다.
객체지향 프로그래밍에서 다형성이란?
다형성이란 객체 지향 프로그래밍에서 하나의 객체가 여러 타입 또는 형태로 나타날 수 있는 능력을 말합니다. 즉, 동일한 인터페이스를 통해 서로 다른 객체를 조작할 수 있게 해주는 특징입니다. 이는 코드의 재사용성을 높이고, 유연하고 유지보수가 용이한 프로그램을 만들 수 있게 합니다.
조건문(if-else, switch)의 사용을 줄여 코드를 유연하고 확장 가능하게 만든다.
6장) 명령과 쿼리를 분리하자!

위의 그림에서 빈칸에 들어갈 단어는?

- 메세지: 객체가 다른 객체와 협력하기 위해 사용하는 의사소통 메커니즘. 일반적으로 객체의 오퍼레이션이 실행되도록 청하는 것을 '메시지 전송'이라고 부른다. 메시지는 협력에 참여히는 전송자와 수신자 양쪽 모두를 포함하는 개념이다.
- 오퍼레이션: 객체가 다른 객체에게 제공하는 추상적인 서비스다. '메시지'가 전송자와 수신자 사이의 '협력 관계'를 강조 하는 데 비해 '오퍼레이션'은 메시지를 '수신하는 객체의 인터페이스'를 강조한다. 다시 말해서 메시지 전송지는 고려하지 않은 채 '메시지 수신자의 관점'만을 다룬다. 메시지 수신이란 메시지에 대응되는 객체의 오퍼레이션을 호출하는 것을 의미한다.
- 메서드: 메시지에 응답하기 위해 실행되는 코드 블록을 메서드라고 부른다. 메서드는 오퍼레이션의 구현이다. 동일한 오퍼레이션이라고 해도 메서드는 다를 수 있다. 오퍼레이션과 메서드의 구분은 다형성의 개념과 연결된다.
- 퍼블릭 인터페이스: 객체가 협력에 참여하기 위해 외부에서 수신할 수 있는 메시지의 묶음. 클래스의 퍼블릭 메서드들 의 집합이나 메시지의 집합을 가리키는 데 사용된다. "객체를 설계할 때 가장 중요한 것은 훌륭한 퍼블릭 인터페이스를 설계하는 것"이다.
- 시그니처: 시그니처는 오퍼레이션이나 메서드의 명세를 나타낸 것으로, 이름과 인자의 목록을 포함한다. 대부분의 언어 는 시그니처의 일부로 반환 타입을 포함하지 않지만 반환 타입을 시그니처의 일부로 포함하는 언어도 존재한다.
왜 명령과 쿼리를 분리해야 할까? (A) 객체의 메서드 개수를 줄여 전체적인 코드 라인을 감소시키기 위해 (B) 메서드 호출로 인해 발생하는 '부수 효과(Side Effect)'를 명확하게 통제하여 소프트웨어의 예측 가능성을 높이기 위해 (C) 모든 메서드가 값을 반환하도록 코드 스타일을 통일하여 일관성을 확보하기 위해 (D) 객체지향의 다형성(Polymorphism)을 극대화하여 유연한 설계를 만들기 위해
정답은 (B) 입니다.
글쓴이가 진짜 하고 싶은 말: "예측 가능한 코드가 좋은 코드다"
이전 퀴즈가 "원칙을 어긴 코드가 무엇이냐"를 물었다면, 이 질문은 "왜 그 원칙이 애초에 중요한가?" 를 묻고 있습니다.
글쓴이가 말하는 본질은, 좋은 소프트웨어는 동작을 쉽게 예측할 수 있어야 한다는 것입니다. 그리고 그 예측을 가장 방해하는 주범이 바로 '부수 효과(Side Effect)', 즉 "어떤 동작을 했는데 예상치 못한 다른 상태까지 바뀌는 것"입니다.
- 쿼리(Query)의 본질: 쿼리는 '질문'입니다. "네 이름이 뭐니?"라고 100번을 물어봐도 상대방의 이름이 바뀌지 않는 것처럼, 쿼리는 시스템의 상태를 절대 변경해서는 안 됩니다. 즉 부수 효과가 없어야 합니다. 그래야 개발자는 이 쿼리를 "안전하게" 언제든 호출하고 그 결과를 믿을 수 있습니다.
- 명령(Command)의 본질: 명령은 '행동 지시'입니다. "이름을 '철수'로 바꿔!"라고 지시하면 상태가 바뀌는 것이 당연합니다. 명령은 부수 효과를 일으키는 것이 자신의 명확한 임무입니다.
가장 위험한 것은 '배신하는 메서드'
글쓴이가 가장 경계하는 것은 쿼리인 척하는 명령, 즉 값을 반환하면서(쿼리처럼 보이면서) 몰래 시스템 상태를 바꾸는(명령의 짓을 하는) 메서드입니다. 이런 메서드는 개발자의 예측을 배신하고, 다음과 같은 질문을 던지게 만듭니다.
"어? 나는 그냥 데이터만 조회했는데 왜 시스템 전체가 이상해지지?"
결론적으로 저자가 말하는 본질은, 코드의 예측 가능성과 안정성을 무너뜨리는 '부수 효과'라는 위험 요소를 '명령'이라는 역할 안에 명확히 가두고 격리하자는 것입니다. 이를 통해 개발자가 코드의 동작을 의심 없이 신뢰하고 예측할 수 있게 만드는 것이 '명령-쿼리 분리 원칙'의 핵심 목표입니다.