본문 바로가기
객체지향/객체지향의 사실과 오해

[객체지향 스터디] 2장 이상한 나라의 객체

by 잔디🌿 2024. 9. 24.

    책 내용 정리

    객체지향과 인지능력

    인간은 본능적으로 세상을 객체 단위로 인식한다.

    인간의 인지능력은 물리적인 한계를 넘어 개념적으로 경계지을 수 있는 추상적인 사물까지도 객체로 인지하도록 한다.(ex. 계좌이체내역)

    이와 소프트웨어의 유사성은 여기까지이고, 소프트웨어 세계에서는 현실과 다르게 객체가 주체적으로 일 할 수 있다.

     

    객체, 그리고 이상한 나라

    이 책에서는 객체지향을 설명하기 위해 이상한 나라의 엘리스 이야기를 예시로 든다.

    이 부분에서는 엘리스가 문들을 통과하기 위해 음료수를 먹고 몸이 작아지고, 케이크를 먹고 다시 몸이 커지는 부분을 중심으로 설명한다.

     

    엘리스는 키라는 상태가 있고, 원하는 바를 이루기 위해서 적당한 상태로 자신의 키를 변화시킨다.

    앨리스의 키를 변화시키는 것은 엘리스의 행동이다.

    -> 엘리스의 행동에 따라 엘리스의 상태가 변한다.

     

    앨리스의 상태를 결정하는 것은 행동이지만, 행동의 결과를 결정짓는 것은 상태다.(먹은 후의 키는 먹기 전의 키에 의존)

    또한 앨리스가 문을 통과했는지의 여부는 앨리스의 위치라는 상태를 보면 알 수 있다.

    따라서 앨리스가 한 행동의 결과는 앨리스의 상태에 의존적이다.

     

    또한 어떤 행동의 성공 여부는 이전에 어떤 행동들이 발생했는지에 영향을 받는다. 문을 통과하기 위해서는 음료나 케이크를 먹어서 상태를 변화시켜야하기 때문이다.

     

    또한 앨리스의 상태가 어떠하든, 앨리스는 항상 앨리스이다.

     

    객체, 그리고 소프트웨어 나라

    객체의 특성을 알기 위해서는 객체를 상태, 행동, 식별자를 지닌 실체로 보는 것이 가장 효과적이다.

     

    객체가 주변 환경과의 상호작용에 어떻게 반응하는가는 그 시점까지 객체에 어떤 일이 발생했느냐에 따라 좌우된다.

    어떤 행동의 결과는 과거에 어떤 행동들이 일어났었느냐에 의존한다.

    일반적으로 과거에 발생한 행동들의 이력을 통해 현재 발생한 행동의 결과를 판단하는 방식은 복잡하고 번거롭다.

    그래서 인간은 행동이 과정과 결과를 단순하게 기술하기 위해 상태라는 개념을 고안했다.

     

    상태를 이용하면 과거에 얽매이지 않고 현재를 기반으로 객체의 행동방식을 이해할 수 있다.

     

    숫자, 문자열 등의 단순한 값은 객체가 아니다. 비록 이들은 객체가 아니지만 객체의 상태를 표현하기 위한 중요한 수단이다.

     

    때로는 단순한 값이 아니라 객체를 통해서 상태를 표현해야 할 때가 있다.

    예를들어 앨리스와 앨리스가 들고 있는 음료가 있다. 둘은 서로 연결되어있다.

     

    객체를 구성하는 특징을 통틀어 프로퍼티라고 한다. 이는 정적이다.

    하지만 프로퍼티 값은 계속 변화하므로 동적이다.

     

    앨리스가 음료를 마시고 이를 버리면 둘의 연결선은 끊어진다. 이처럼 객체와 객체 사이의 의미있는 연결을 링크라고 한다.

    링크가 존재할 때에만 협력이 가능하다.

    프로퍼티는 링크와 단순한 값인 속성으로 구성된다.

     

    객체는 자율적인 존재이다. 객체지향의 세계에서는 객체는 다른 객체의 상태에 직접적으로 접근할수도, 상태를 변경시킬수도 없다.

    객체는 스스로의 행동에 의해서만 상태가 변경되는 것을 보장함으로써 객체의 자율성을 유지한다.

     

    객체가 취하는 행동에 의해 상태가 변화하는 것은 행동에 부수효과를 초래 뜻이다.

    • 객체의 행동은 상태에 영향을 받는다
    • 객체의 행동은 상태를 변경시킨다.

    이것은 상태라는 개념을 이용해 행동을 다음의 두 가지 관점에서 서술할 수 있음을 의미한다.

    • 상호작용이 현재의 상태에 어떤 방식으로 의존하는가
    • 상호작용이 어떻게 현재의 상태를 변경시키는가

    모든 객체는 다른 객체를 이용하고 서비스를 제공한다.

    객체는 받은 요청을 수행함으로써 협력에 기여한다. 행동은 협력에 참여할 수 있는 유일한 방법이다. 

    객체는 메세지를 통해서만 의사소통 할 수 있으므로 객체는 메세지에 따라 적절히 행동하면서 자신의 상태를 변화시킨다.

     

    행동으로 인해 두가지 부수효과가 날 수 있다.

    • 자기자신의 상태변화
    • 다른 객체애 대한 메세지 전송

    객체는 행동을 통해 다른 객체와의 협력에 참여하므로 행동은 외부에 가시적이어야한다.

     

    소프트웨어 세계의 모든 객체들은 능동적으로 행동할 수 있다.

     따라서 앨리스는 음료의 상태를 직접 변화시킬 수 없고 메세지를 통해서만 변화시킬 수 있다.

     

    메세지 송신자는 수신자의 상태변경에 대해서는 알지 못한다. 

    객체가 외부에 노출하는 것은 행동뿐이며 외부에서 객체에 접근할 수 있는 유일한 방법 역시 행동뿐이다. -> 캡슐화

    메세지를 전달받더라도 이를 행동할지의 여부를 결정하는 것은 수신객체이다.

     

    캡슐화는 객체의 자율성을 높이고, 협력을 단순하고 유연하게 만든다.

     

    객체가 식별 가능하다는 것은 객체를 서로 구별할 수 있는 특정한 프로퍼티가 객체 안에 존재한다는 것이다. 

    이 프로퍼티를 식별자라고 한다.

    모든 객체는 식별자를 가지며, 이를 통해 객체를 구별할 수 있다.

     

    반대로 단순한 값들은 식별자를 가지지 않는다.

     

    값은 문자열, 숫자, 날짜 등 변하지 않는 양을 모델링한다. 값의 상태는 변하지 않기 때문에 불변상태라고 한다.

    값은 상태가 같은지를 통해 인스턴스가 같은지 판단한다. 이처럼

    상태를 이용해 두 값이 같은지 판단할 수 있는 성질을 동등성이라고 한다.

     

    객체는 시간에 따라 변경되는 상태를 포함하는 가변상태이다.

    두 객체의 상태가 완전히 같더라도 두 객체는 다르다. 또한 객체의 상태가 다르더라도 식별자가 같으면 이를 동일성이라고 한다.

    식별자는 상태변경에 독립적이다.

     

    참조객체 또는 엔티티는 식별자를 지닌 전통적인 의미의 객체이고, 값객체(VO)는 식별자를 가지지 않는 값이다.

     

    • 객체는 상태를 가지며 상태는 변경 가능하다
    • 객체의 상태를 변화시키는 것은 객체의 행동이다.
    • 행동의 결과는 상태에 의존적이며 상태를 이용해 서술할 수 있다.
    • 행동의 순서가 결과에 영향을 미친다.
    • 객체는 어떤 상태에 있더라도 유일하게 식별 가능하다

    기계로서의 객체

    개발자의 주된 업무는 객체의 상태를 조회하고 이를 변경하는 것이다.

    객체의 상태를 조회하는 작업 : 쿼리

    객체의 상태를 변경하는 작업 : 명령

     

    버트란드마이어는 이를 기계에 비유해서 설명한다.

    이 기계는 상태에 대한 버튼과 행동에 대한 버튼이 있다. 평소에는 상태를 모르지만, 버튼을 통해서 조회할 수 있다.

    사용자가 기계의 버튼을 눌러 상태를 변경시키는 것은 메세지를 전송하는 것과 같다.

    하지만 이 명령에 대해 어떻게 반응할지는 기계에게 달렸다.

    버튼을 누르는 것 이외의 방법으로는 상태를 변화시킬 수 없다. -> 이는 행동을 통해서만 상태를 변화시킬 수 있다는 것을 의미한다. -> 캡슐화

     

    기계의 상태가 같아도 두 기계는 다르다. 이는 상태가 같아도 식별이 가능한 객체의 특징을 의미한다.

     

    앨리스 기계 뒤에 음료 기계가 있고 두 기계가 연결되어있다.

    이때 앨리스의 음료를 마시다 버튼이 눌리면 앨리스의 키 상태가 작아지고, 연결된 음료 기계로 메세지가 전송된다. 

    -> 링크를 통해 연결된 두 객체가 메세지 전송을 통해 협력하고있다.

     

    행동이 상태를 결정한다.

    상태를 먼저 결정하고 행동을 나중에 결정하는 것은 설계에 나쁜 영향을 끼친다.

    • 상태를 먼저 결정하면 캡슐화가 저해된다.
    • 객체를 협력자가 아닌 고립된 섬으로 만든다.
    • 객체의 재사용성이 저해된다.

    객체의 행동은 객체가 협력에 참여하는 유일한 방법이다. -> 객체가 적합한지는 상태가 아닌 행동에 따라 결정된다.

     

    어떤 책임이 필요한가를 결정하는 과정이 전체 설계를 주도한다.

    책임-주도 설계는 객체의 행동을 생각하도록 하여 응집도 높고 재사용이 가능한 객체를 만들 수 있도록 한다.

     

    은유와 객체

    흔히 객체지향을 현실세계의 추상화라고 한다.

    여기서 추상화란 실제의 사물에서 자신이 원하는 특성만 취하고 필요 없는 부분을 추려 핵심만 표현하는 행위를 말한다.

    그런데 객체지향은 현실세계의 단순한 모방이 아니라 이를 깔끔하게 설명하지 못한다.

     

    현실세계와 객체지향세계의 가장 다른 점은 모든 객체가 능동적이라는 것이다.

    소프트웨어 객체는 현실세계가 가지지 못하는 추가적인 능력을 보유하게 된다. 이런 특징을 의인화라고 한다.

     

    현실세계와 객체지향 세계 사이의 관계를 좀 더 정확하게 설명할 수 있는 단어는 은유이다.

    은유란 실제로는 적용되지 않는 한 가지 개념을 이용해 다른 개념을 서술하는 대화의 한 형태이다.

     

    은유 관계에 있는 실제 객체의 이름을 소프트웨어 객체의 이름으로 사용하면 표면적 차이를 줄여 소프트웨어의 구조를 쉽게 예측할 수 있다.

    이렇게 하면 표현적 차이를 줄일 수 있고, 이해하기 쉽고, 유지보수가 용이하다.

    따라서 현실세계의 도메인에서 사용되는 이름을 객체에 부여하라고 하는 것이다.

     

    객체의 특성을 상기시킬 수 있다면 현실 속의 객체의 이름을 이용해 객체를 묘사하라.

     

    스터디 내용

    질문

    행동을 먼저 생각하고 상태를 생성하라는 부분이 있는데 피그마를 보고 erd설계를 하는건 이에 위배되는가

    대형 프로젝트를 할 때 요구사항을 먼저 정리한다. 이 때 사용하는 것이 이벤트 시퀀스 다이어그램이다.

    이벤트 시퀀스 다이어그램

    여기서 디테일한 부분을 파악한다.

    또한 이벤트스토밍을 통해서 요구사항을 알아가는데, 이벤트스토밍은 개발자 뿐만 아니라 개발에 참여하는 사람 모두가 참여한다.

    이벤트스토밍

    요구사항을 잘 보고 erd설계를 하면 이를 지킨 것이다.

     

    현재까지는 개발하는 팀원도 기획에 참여해서 괜찮았지만, 피그마 보고 하는 건 살짝 위배이다. 회사에서는 기획자 따로 있으니까 이를 꼭 지켜야한다.

    또한 이들과의 용어통일도 중요하다.

     

    행동이 외부에 가시적이어야한다는 것이 어떤 의미일까

    이건 public interface처럼 객체의 행동을 외부에서 알 수 있어야 이에 요청을 할 수 있다는 것을 의미한다.

     

    equals와 hashcode 메서드를 override할 때 동등성 부여라고 하는 이유가 무엇인가

    책을 보니까 동등성은 불변인 값이 같은 것을 의미하고, 동일성은 식별자가 같아서 두 객체가 같다는 것을 의미하는데, 흔히 equals와 hashcode를 만들어줄 때 동일성이 아닌 동등성을 부여한다고 하는 것이 이해가 잘 되지 않았다.

    하지만 스터디원의 내용을 듣고, member의 식별자가 달라도 이름이 같으면 같은 객체로 보려고 할 때 여기서는 멤버와 멤버 객체 자체가 동일한지를 보는 것이 아니라 이름과 이름이라는 값이 같은지를 확인하는 동등성을 부여한다는 의미였다는 것을 알 수 있었다.

     

    여기서 hashcode를 override 해야하는 이유는 우리가 hashmap,hashset과 같은 자료구조를 사용할 때 이를 반영하도록 하기 위해서라고 한다.

     

    Setter이 필요하지 않아서 구현을 안했는데 테스트코드에서 필요한 경우 이를 구현해야하는가

    테스트코드를 위해서 원래 코드를 고쳐야 하는 경우 원래 코드가 잘못되지는 않았는지 다시 한번 확인해보아야한다. 또한 꼭 필요한 경우, 어떤 것이 더 중요한지 생각해보고 적용해 볼 필요가 있다.

     

    새로 알게된 내용

    VO는 메서드를 가질 수 있으나 상태를 변화시키면 안된다

    vo는 값이므로 불변성을 가져야한다. 만약 해당 값의 변화가 필요하다면 vo 내에서 상태를 변화시키면 안되고, 새로운 vo를 만드는 것이 더 좋은 방법이다.

     

    응집도가 높다는 것의 의미

    65p에서 응집도가 높다는 것은 자기의 일은 자기만 할 수 있고 외부에 노출되지 않는다.

    응집도를 높일 수 있는 패턴 -> grsp 패턴 

    객체는 그 객체 전문가에게 맡겨라

    객체의 상태를 내 모든 상태가 사용할 수 있다. -> 가지고 있는 상태가 그 엔티티의 메서드 안에 다 있어야 응집도가 높다.

    결합도가 높다는건 객체의 값이 달라지면 다른 객체의 값이 달라진다.

    응집도가 높아질수록 결합도가 낮아진다.

     

    의인화를 쓰는 이유

    의인화에서 가장 대표적인 예

    책을 페이지수집기라고 하지 않는다. 현실세계의 객체와 소프트웨어사이의 객체는 크지만 인지를 줄이기 위해서 이렇게 쓴다.

     

    레파지토리 내에서 명령과 쿼리 분리

    명령과 쿼리는 복잡성이 다르다. 명령은 데이터베이스의 상태를 변화시키고, 쿼리는 데이터베이스의 값을 그냥 읽는다.

    레파지토리가 도메인 당 하나만 있다고 생각하는데 그게 아니다.

    쿼리랑 명령은 지금은 레파지토리에서 쓰지만 추후에는 분리할수도 있다.