내부 객체 직접 접근에 관하여.
83
작성한 질문수 3
토비님 안녕하세요!
좋은 강의 만들어 주셔서 감사합니다.
객체지향 프로그래밍에서는 객체의 내부 구현이나 구조를 외부에서 직접 알 필요가 없도록 캡슐화하고, 객체의 행동을 통해 상호작용하는 것이 중요하다고 알고 있습니다.
기존 테스트에서는 Course 내부의 detail 객체에 직접 접근합니다. 이를 아래와 같이 수정해봤습니다.
public class Course extends AbstractEntity {
public LocalDateTime getPublishedAt() {
return detail.getPublishedAt();
}
}@Test
void publish() {
course.submitForReview();
course.publish();
assertThat(course.getStatus()).isEqualTo(CourseStatus.PUBLISHED);
//assertThat(course.getDetail().getPublishedAt()).isNotNull();
assertThat(course.getPublishedAt()).isNotNull();
assertThatThrownBy(() -> course.publish())
.isInstanceOf(IllegalStateException.class);
}이러한 판단이 객체지향의 캡슐화, 정보 은닉 관점에서 올바른지 궁금합니다.
답변 2
1
좋은 질문을 해주셨네요. 애그리거트 안에 루트 외에 내부 엔티티가 존재할 경우에 내부 엔티티에 접근하거나 기능을 수행하는 것은 최대한 제한되는 것이 바람직합니다. 애그리거트 내부 구조가 노출되고 내부 엔티티의 기능까지 직접 사용하게 되면 애그리거트 단위로 작업을 수행하려고 한 애초의 목적을 놓칠 수 있게 됩니다. 그래서 모든 내부 엔티티에 대한 조작과 접근을 루트 엔티티로 제한하는 방법을 선택할 수 있습니다. 그래서 보여주는 방법처럼 내부 detail 엔티티가 가지고 있는 정보를 조회할 때도 루트 엔티티의 메소드를 통해서 정보를 가져오는 작업을 위임할 수 있습니다.
그런데 저는 이렇게 모든 정보의 조회까지 루트에 다 구현을 해두면 루트 엔티티가 너무 복잡해진다는 느낌이 들더라고요. 그래서 저는 트레이드 오프를 통해서 단순 조회인 경우, 그리고 변경이 크게 일어날 가능성이 없다고 판단되는 경우엔 조회 로직은 내부 엔티티에 접근해서 가져오는 방식을 선택했습니다. 물론 변경이 필요한 작업은 애그리거트 단위에서 일관성을 지키는 것이 중요하기 때문에 내부 엔티티의 변경 로직은 철저하게 차단을 해두고, 루트 엔티티가 외부에 공개한 퍼블릭 메소드를 통해서만 일어나게 제한을 두는 방식을 선택한 것입니다.
보여주신 방식처럼 조회 메소드도 루트 엔티티로만 제한을 하는 방법도 선택이 가능한 옵션입니다. 가벼운 트레이드 오프를 통해서 접근 방식을 결정하고 일관되게 적용하시면 됩니다. 루트 엔티티가 커지는 문제 vs 애그리거트 내부 엔티티 구조가 변경됐을 때 조회 로직도 따라서 바뀌어야 하는 문제 중에서 어느 부분에서 손해를 감수하고 다른 장점을 취할 것인가를 실제 코드를 구현해보시면서 판단에 따라 트레이드 오프 해보세요.
0
안녕하세요, 인프런 AI 인턴입니다. 잉여인간님!
질문하신 것처럼 Course 외부에서 내부 객체인 detail에 직접 접근하지 않고, Course가 필요한 정보를 제공하도록 만드는 방식은 캡슐화와 정보 은닉 관점에서 적절한 방향입니다.
course.getDetail().getPublishedAt()처럼 내부 구조를 외부에 노출하면 테스트나 사용하는 코드가 Course 내부에 detail 객체가 존재한다는 사실을 알아야 합니다. 이후 detail의 구조가 변경되면 외부 코드와 테스트도 함께 수정해야 할 수 있습니다.
반면 다음과 같이 Course가 위임 메서드를 제공하면 외부에서는 Course의 내부 구조를 알 필요가 없습니다.
public LocalDateTime getPublishedAt() {
return detail.getPublishedAt();
}
다만 단순히 값을 반환하는 getter를 추가하는 것보다, 외부에서 정말 필요한 의미를 메서드로 표현하는 방법도 고려할 수 있습니다.
public boolean isPublished() {
return status == CourseStatus.PUBLISHED;
}
public boolean hasBeenPublished() {
return detail.getPublishedAt() != null;
}
즉, 테스트가 publishedAt이라는 내부 데이터 자체를 검증해야 하는 경우에는 getPublishedAt()도 괜찮지만, 비즈니스 관점에서 “강의가 이미 발행되었는가?”를 확인하는 것이 목적이라면 isPublished()와 같은 도메인 행동 또는 질의 메서드가 더 명확할 수 있습니다.
이와 관련해 애그리거트 내부 엔티티나 값에 접근할 때의 기준을 설명한 기존 답변을 참고해 보시면 도움이 됩니다.
개인적질문 - 애그리거트 루트와 내부 객체 접근 기준
기존 답변에서도 단순 조회라면 내부 값을 조회할 수 있지만, 변경이나 조건 판단 같은 로직은 애그리거트 루트에 두고 루트가 필요한 기능을 수행하도록 하는 것이 바람직하다고 설명하고 있습니다. 이렇게 하면 내부 구조가 변경되어도 외부 코드의 영향을 줄이고, 도메인 규칙을 Course 안에서 일관되게 관리할 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
22강 [토큰 저장] 질문
0
7
1
업캐스팅 원칙
0
7
1
음성불량
0
15
1
13강 [로그인 단일 토큰] 에서 프로젝트 실행 시 에러
0
21
1
11강 [실습] Docker로 MySQL1 분만에 실행하기
0
25
2
11강 [실습] Docker로 MySQL1 분만에 실행하기
0
24
2
6분46초
0
31
2
공략법
0
40
1
isInterrupted 질문 있다.
0
24
1
구현 방법에 대한 문의
0
36
2
fieldInjectionTest() 질문
0
36
1
선생님 샤딩에 대한 강의도 좀 해주세요
0
37
1
몽고DB CAP 이론 관련
0
47
2
AutoAppConfig의 존재이유
0
37
1
모의고사 파일과 이론파일 업데이트
1
61
2
장애 격리 관련해서 궁금한 부분이 있어요
0
41
1
이론 pdf 다운은 어디서 하나요?
0
54
2
RunIdIncrementer batch 5랑 6랑
1
47
2
AppConfig와 스프링 빈 질문
0
39
1
핵사고날 아키텍처 기반으로 멀티 모듈 설계 시 질문드립니다..
0
54
2
InvalidCurriculumException DIP 적용 여부 문의
0
63
2
설계 트레이드 오프 링크 접속 안됨
0
125
2
헥사고날 아키텍처와 DDD를 적용할 때, 화면에 강하게 연관된 조회 데이터를 어떻게 다루는 게 좋은지 궁금합니다.
0
172
2
Request DTO에서 Entity를 생성할 때 의존성 방향을 반대로 하면 어떨까요?
0
152
2





