Law of Demeter - 디미터 (데메테르) 법칙

    Law of Demeter 개요

    소프트웨어 엔지니어링 관점에서 소개되는 법칙 중 하나로, Law of Demeter (디미터/ 데메테르)의 법칙이 있다. 줄여서 LoD라고도 하는데, 이 법칙이 뜻하는 바는 principle of least knowledge (최소 지식의 원칙)이다. 이 가이드라인은 1987년말, Northesatern Univsersity의 Ian Holland에 의해 소개되었다.

    • Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
    • Each unit should only talk to its friends; don't talk to strangers.
    • Only talk to your immediate friends.

    즉, 친한 친구(인접 객체) 하고만 이야기 하라는 것이고, 친구의 친구는 남이므로 먼 객체는 직접 사용하지 말라는 뜻이다.

     

    Why Demeter?

    본래 Demeter는 그리스 로마 신화에 나오는 여신이다. 제우스와 남매 지간이지만, 배우자(?) 중 하나이기도 한 여신이긴 하지만, 곡물과 수확의 여신이며, 계절의 변화와 결혼의 유지를 관장하는 것으로 알려져 있다. 그런데, 이 Demeter가 최소 지식을 나타내는 것과 무슨 관계가 있고, 더더욱 소프트웨어 엔지니어링의 관점에서 왜 이름이 나오는 것일까?

     

    Law of Demeter 이름 기원

    Demeter 법칙은 Demter 프로젝트를 수행하는 과정에서 따온 것이다. 당시에, 프로젝트를 진행하던 연구원들이 Zeus라는 하드웨어를 기술하는 언어를 작업중이었는데, Zeus의 효율성을 개선하고자 툴을 만들고 그 툴의 이름을 고심하던 중, 그리스 로마 신화에 등장하던 Zeus와 관련된 여신 중 Demeter를 이름 후보로 낙점하였다. 곡물을 점진적으로 키워가는 점과 소프트웨어를 점진적으로 발전시켜가는 것이 닮았다고 생각하여, 이를 소프트웨어 개발 방법론/ 가이드화에 이르게 되었다. 즉, 작은 블럭으로부터 점진적으로, bottom-up 방식으로 키워가는 방식이기에 Demeter 여신이 주는 상징성과 부합하다고 보게 된 것이다. 이렇게 Demeter 프로젝트를 하던 중, 소프트웨어 엔지니어링 관점에서 발견하고 느낀 바를 모아서 공표한 것이 Demeter의 법칙이라 보면 되겠다.

     

    Demeter 시스템

    Law of Demeter의 기원이 된 프로젝트가 Demeter 시스템이다. Demeter 프로젝트는 소프트웨어를 크게 두 파트로 나누는 방식으로 접근하였다.

    1. 객체 정의
    2. 오퍼레이션 정의

    객체간 커플링을 낮추고, 어느 한쪽의 변경이 다른 쪽에 가는 영향도를 최소화하여 유지보수성을 높이고자 하였다. 그리고, 그 목적은 잘 진화(변경)하는 시스템을 만들고자 함에 있다.

     

     

     

    Law of Demeter

    Demeter 법칙의 주요 두 가지 목표는 다음과 같다.

    1. 수정의 간소화: 클래스 구조/ 내용이 변경되더라도 프로그램 변경이 쉬워야 한다.
    2. 프로그래밍 복잡도의 간소화: 메소드 작성시 프로그래머가 인지해야 하는 변경 유형을 최소화 시켜야 한다.

    이를 위해, 코드 중복을 최소화 하고, 메소드로 넘겨지는 파라미터 수를 최소화 하고, 클래스가 제공하는 메소드 수도 최소화하는 것을 권고한다.

    원문 링크는 아래와 같다.
    https://www2.ccs.neu.edu/research/demeter/papers/law-of-demeter/oopsla88-law-of-demeter.pdf

    어떤 클래스 C(class)에 대해, 메소드 M(method)이 있다고 하자. 그리고, 우리는 이 클래스 C로부터 어떤 객체 O(object)를 만든다. Demeter의 법칙은, 이 메소드 M이 다음의 경우만 호출할 수 있도록 해야 한다고 한다.

    • 자신과 동일한 객체, 즉 O
    • 메소드 M에 argument로 전달된 객체들
    • 메소드 M 내부에서 자체적으로 생성한 다른 객체들
    • 객체 O가 접근할 수 있는 글로벌(전역) 객체들
    • 객체 O가 직접 접근할 수 있는 컴포넌트 객체들

    new Employee().getDepartment().getCompany().getName() 에서 보는 바와 같이, 줄줄이 비엔나 처럼 엮여 있는 것을 하지 말자는 것이다. 참고로, Train Wreck 안티패턴이라 한다. 안타깝게도 JPA를 위와 같이 막 쓰는 경우도 심심찮게 볼 수 있다. 객체 연결을 자동으로 해주다보니, 쉽게 연결하고 그로 인해 서비스 장애가 나기도 한다.

     

    장점

    • 클래스간 의존성을 낮춤으로써, 커플링을 줄일 수 있다.
    • 클래스의 목적이 명확해지므로, 재사용성이 높아진다.
    • 유지보수성이 좋고, 변경이 더 쉬워진다.

     

    단점

    • wrapper 메소드를 더 작성해야 할 수 있으므로, 코드 작성량이 늘어난다.
    • 공간 복잡도/ 시간 복잡도도 증가할 수 있다.

     

    Java8 Stream 함수와 Demeter 법칙

    java8 이상에서 사용하는 stream 함수는 어떨까? 위에서 말한, 내부 객체의 데이터를 조회하는데 여러 함수를 사용하는 것이므로 괜찮지 않을까?

    라는 질문이 자연스럽게 생기게 마련이다.

    stream 계열의 함수를 사용하다보면, 자연스럽게 여러 개의 dot을 사용하게 될 것이다. 그리고 이렇게 하는 대부분의 이유는, 그 객체가 데이터는 들고 있되 스스로 자신에 대해 알려주지 않기 때문인 경우가 많다. 따라서, 그 객체를 사용하는 다른 객체들은 그 객체와 말하는 대신 많이 물어봐야 한다. 그리고, 그 데이터들을 바탕으로 사용하는 쪽에서 자의적으로 판단해야 한다. 만약 그 데이터를 들고 있는 객체가 단순히 데이터만 제공하는 것을 넘어, 자신의 데이터를 바탕으로 자신에 대해 좀 더 많이 알려준다면, 그 객체와 협업하는 다른 객체들은 dot의 숫자를 줄일 수 있게 될 것이다. 즉, 내부 로직 내에서 stream 함수를 쓰더라도 외부에는 별도의 wrapper로 공개하는 편이 정보 은닉 차원에서 뿐만 아니라, 전체적인 유지보수성을 좋게 할 것이다.

     

    정리

    Demeter의 법칙이 시사하는 바는 다음과 같다.

    • 컴포넌트간의 의존성을 줄이자.
    • 컴포넌트간 커플링을 낮추면
    • 재사용성을 높일 수 있다.
    • 유지보수가 쉬워진다.
    • 테스트가 용이해진다.

    댓글

    Designed by JB FACTORY