디미터의 법칙

Socra·2025년 2월 11일
0
post-thumbnail

Demeter's Law란?

Demeter's Law는 “객체는 자신과 밀접하게 관련된 객체들(친구) 외의 다른 객체들과 상호작용하면 안 된다”는 원칙이다.

다시 말해, 한 객체가 다른 객체의 내부 구조나 하위 구성요소에 지나치게 의존하지 않아야 한다는 뜻이다.

이 원칙은 1987년 Northeastern University의 연구 프로젝트에서 처음 제안되었으며, 그 이름은 그리스 신화의 여신 데메테르(Demeter)에서 유래했다.

핵심 원칙

디미터 법칙의 핵심 원칙은 다음과 같다.

다른 유닛들에 대해 최소한의 지식만 가져야 한다

  • 객체는 자신이 직접 소유하거나 생성한 객체, 파라미터로 전달받은 객체, 혹은 내부에 구성되어 있는 객체만 다뤄야 한다.
  • 다른 객체의 내부 구조나 반환값에 직접 접근하여 메서드를 호출하는 행위는 피해야 한다.

낯선 이와 대화하지 말고 가까운 친구들과만 대화해야 한다

Don't talk to strangers

  • 객체가 자신과 직접 연관되지 않은 다른 객체의 메서드를 호출하게 되면, 시스템 전체의 결합도가 높아지고 유지보수가 어려워진다.

핵심 원칙을 읽어보면 결합도를 느슨하게 하는 것이 목적임을 쉽게 알 수 있다.

디미터의 법칙을 따르는 이유

  • 결합도 감소: 객체 간 의존성이 낮아져 변경의 파급효과를 최소화할 수 있다.
  • 유지보수성 향상: 각 객체가 독립적으로 설계되어 시스템 수정/확장이 용이하다.
  • 테스트 용이성: 객체 간 의존성이 줄어들면 단위 테스트, Mock을 활용한 테스트도 쉬워진다.

디미터 법칙을 위반하는 예시

여러 객체에 대해 체인 호출(Chained Calls) 을 통해 내부 객체에 직접 접근하고 있다.

String zipCode = person.getAddress().getStreet().getZipCode();

문제점

  • 체인 호출로 personzipCode를 얻고 있다.
  • 클라이언트가 Person 내부의 구조(Address, Street)에 대해 알아야 한다.
  • 내부 구조가 변경되면 클라이언트 코드도 수정해야 한다.

→ 객체 간의 결합도가 높아져 유지보수가 어려워진다.


디미터 법칙을 준수하도록 개선한 예시

객체 간의 세부 구조를 감추고, 클래스에 필요한 기능을 위임해 클라이언트가 단순히 person 객체와만 상호작용하도록 개선해보자.

String zipCode = person.getZipCode();

단순히 메서드를 추가하는 것만으로 쉽게 해결할 수 있다.

개선점

  • Order 클래스에 getCustomerCity() 메서드를 추가하여 내부의 Customer와 Address 객체에 대한 접근을 숨겼다.
  • 클라이언트는 이제 Person 객체의 메서드만 호출하면 되므로, 객체의 내부 구조 변경 시 클라이언트 코드가 영향을 받지 않는다.

→ 객체 간 결합도를 낮춰 유지보수성과 확장성을 높인다.

디미터 법칙을 준수하면 각 객체의 내부 구현을 감추고, 인터페이스를 통해서만 상호작용하게 되어, 코드의 결합도가 낮아지고 유지보수가 용이해진다.

혹시 내 코드는 무분별하게 체인 호출을 하고 있진 않은가 점검해보자.

디미터의 법칙 위반 여부를 판단하는 기준

  1. 객체가 본인이 직접 소유한 객체만 다루는가?
  2. 객체의 내부 구조를 노출하지 않는가?
  3. 다른 객체의 내부 상태를 직접 조작하지 않는가?

일반적으로 “도트(.)을 여러 번 찍지 마라”라고 직관적으로 설명되어 디미터의 법칙을 접하면 단순히 도트(.)를 여러 번 사용하지 말라는 법칙이라고 느껴질 수 있다. 대부분 상황에선 맞는 말이긴 해서 오해의 소지가 생길 수 있다.

디미터의 법칙은 객체가 다른 객체의 내부 구조에 의존하지 않도록 설계하는 원칙이라는 본질을 생각해보면 도트를 여러번 쓰더라도 디미터의 법칙과는 관계가 없는 경우도 있다.

(객체는 자신이 직접 가진 속성이나 메서드, 또는 자신이 생성한 객체의 메서드만 호출해야 한다)

Stream에서 .을 여러 번 사용하는 건 디미터의 법칙 위반인가?

Stream API 자체는 객체의 내부 구조를 노출하는 것이 아니라 컬렉션을 다루는 도구이므로, 디미터의 법칙과 직접적인 관련이 없다.

Stream의 메서드 체이닝에선 같은 Stream이 반환되기 때문에, 도트(.)를 여러 번 사용하는 건 문제가 되지 않는다.

물론 아래의 코드처럼 객체를 사용하면 Stream과 무관하긴 하지만 위반할 수도 있다.

List<String> usernames = getMembers().stream()
    .map(member -> member.getProfile().getUsername()) // getProfile()을 통해 내부 구조에 직접 접근
    .collect(Collectors.toList());

자료구조, DTO에서 .을 여러 번 사용하는 건 디미터의 법칙 위반인가?

DTO는 본질적으로 데이터 전달 용도라 내부 구조를 직접 탐색해도 문제가 되지 않는다.

DTO는 도메인 객체가 아니며, 비즈니스 로직도 갖지 않는다.

디미터의 법칙은 객체 간의 결합도를 낮추기 위한 설계 원칙이라는 본질을 생각해보면, 자료구조에 디미터의 법칙을 엄격하게 적용하는 의미는 없다.

0개의 댓글

관련 채용 정보