ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디미터 법칙(Law of Demeter)을 위반한 코드 개선하기
    Java & Kotlin 2023. 3. 8. 18:51
    반응형

     

     

    최근 취업 준비로 여러 회사에 지원하였고, 사전 과제를 진행하였다.

     

    나름 시간을 들여 잘 작성했다고 생각했지만 불합격 메일을 받았고 그에 대한 피드백으로 몇 가지 이유를 들어주셨다.

    오늘은 그 중에 한 가지인 디미터 법칙에 대해서 알아보고 코드를 개선해 보고자 한다.

    역시 좋은 코드를 유지하고 자신의 문제점을 파악하기 위해서 코드 리뷰를 통한 피드백은 중요하다는 걸 다시 한번 느꼈다.

     

    먼저 문제의 코드를 살펴보자.

    도메인 모델은 member(회원)와 post(게시물)가 있고, member는 여러 개의 post를 게시할 수 있기 때문에 둘은 1:N 관계를 가진다.

     

    이번 과제에서 application과 DB의 데이터 매핑을 위해 ORM인 JPA를 사용하였고, post가 member_id를 foreign key로 가지고 있는 연관관계의 주인으로 Post 클래스는 Member 클래스를 직접적으로 참조하고 있다.

     

    해당 메서드는 PostService 클래스에 정의되어 클라이언트로부터 조회할 post의 offset과 limit 등의 정보를 받아서 DB로 부터 데이터를 조회한 후 post를 작성한 member의 정보를 lazy loading하여 함께 반환하는 역할을 한다.

     

    이때 lazy loading을 수행 하는 반복문 코드에서 디미터 법칙을 위반하였다는 피드백을 받았다.

     

    불합격 피드백 일부

     

    디미터 법칙이라는 용어를 처음 들어보았다.


    디미터 법칙(Law of Demeter)이란 ?

     

    디미터 법칙에 대해 ChatGPT에게 물어보았다.

     

    ChatGPT 답변:

    디미터 법칙(Law of Demeter)은 소프트웨어 개발에서 객체 지향 설계의 원칙 중 하나로, 객체 사이의 결합도를 낮추기 위한 방법 중 하나입니다.

     

    디미터 법칙은 "하나의 객체는 직접적으로 아는 객체의 메서드만 호출해야 한다"는 원칙을 말합니다. 즉, 객체 A가 객체 B를 호출하면서 동시에 객체 B가 알고 있는 다른 객체 C의 메서드를 호출하면, 객체 A와 객체 C 사이의 결합도가 높아져서 유지 보수성이 나빠지고, 코드의 확장성이 떨어지는 문제가 발생할 수 있습니다.

     

    이를 해결하기 위해 디미터 법칙은 객체 간의 의존성을 최소화하고, 각 객체가 자신의 책임 범위 내에서만 동작하도록 하는 것을 권장합니다. 따라서, 객체는 가능한 한 자신이 필요로 하는 정보와 기능을 직접적으로 가지고 있도록 설계해야 하며, 다른 객체의 내부 구현에 대한 의존성은 최소화해야 합니다. 이렇게 하면 코드의 결합도가 낮아져, 코드의 유지 보수성과 확장성이 향상될 수 있습니다.


    문제

    내가 작성한 코드를 디미터 법칙의 핵심과 연결지어 설명하면 하나의 객체(PostService)는 직접적으로 아는 객체(Post)의 메서드만 호출해야 한다.

     

    하지만 나는 Post가 알고있는 Member 객체를 꺼내어서 Member 클래스의 getAccount() 메서드를 호출하였고, 이 부분이 디미터 법칙을 위반하였다.

     

    이 코드가 왜 좋지 않은 코드인지 살펴보면 PostService와 Member 객체가 결합되어 Member 객체가 변경이 이루어질 때 Member와 직접적으로 연관되어 있는 Post 뿐 아니라 PostService 객체에도 영향을 끼치게 되어 유지 보수성이 떨어진다.


    개선

    그럼 해당 코드가 디미터 법칙을 위반하지 않도록 개선해 보자.

    public class Post {
    ...
    	public Long getMemberAccountId() {
            return this.member.getAccountId();
        }
    ...
    }

     

    먼저 Post에서 Member의 accountId를 가져올 수 있는 메서드를 만들자.

     

    pages.forEach(post -> post.getMemberAccountId());

    그럼 PostService에서는 Post와 직접적으로 관련있는 Member 객체를 사용하지 않으므로 결합도가 낮아지고, member의 getAccountId()가 변경된다고 해도 PostService에는 영향이 가지 않게 된다.

     

     

     

    반응형
Designed by Tistory.