본문 바로가기
Study/디자인 패턴의 아름다움

[디자인 패턴의 아름다움] 3. 설계 원칙 - 3.6~3.8 정리 (KISS, YAGNI, DRY, LoD)

by Nahwasa 2024. 4. 24.

스터디 메인 페이지

목차

    - ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한대로 적어놓은 것으로, 책에 나오지 않는 내용입니다. 따라서 책에서 말하고자 하는 바와 다를 수 있습니다.

    - 모든 이미지의 출처는 디자인패턴의 아름다움(왕정 저) 책 입니다.

     


     

    3.6 KISS 원칙과 YAGNI 원칙

    KISS

    • Keep It Simple, Stupid
    • 코드를 단순하게 유지해라.
    • 적은 줄 수의 코드가 더 간단한건 아니다.
      • e.g. 유효한 IP 주소인지 확인하는 함수
      • 1. 정규식으로 짜는 경우
      • 2. StringUtils 클래스와 Integer 클래스에서 제공하는 유틸리티 함수를 사용하여 처리하는 경우
      • 3. 직접 전부 구현하는 경우
      • 당연히 가장 짧은건 '1'이지만, 정규표현식 기반의 구현 방식은 코드의 가독성 및 유지 보수성이 좋지 않다. '3'은 '2'보다 생각해야 하는 점도 훨씬 더 많고, 버그가 발생하기도 쉽다. '2'가 가장 KISS원칙을 따른다고 할 수 있다.
    • 복잡한 코드가 반드시 KISS 원칙을 위반하는 것은 아니다.
      • 복잡한 문제를 복잡한 알고리즘으로 해결하는 것은 KISS 원칙에 위배되지 않는다. (e.g. 충분히 데이터가 큰 문자열에 대한 문자열 검색을 위해 짠 kmp 알고리즘 코드)
      • 하지만 해당 프로젝트가 작은 텍스트를 다룬다면 이건 KISS 원칙을 위배한것
    • KISS 원칙을 만족하는 코드 작성 방법
      • 복잡한 정규표현식 등 지나치게 복잡한 기술을 사용하여 코드를 구현하지 않는다.
      • '바퀴를 다시 발명'하는 대신 기존 라이브러리를 상죵하는 것을 고려한다.
      • 과도하게 최적화하지 않는다. (코드를 최적화하기 위해 산술 연산 대신 비트 연산을 사용하는 등)
    • ☆ '바퀴를 다시 발명하지 마라'는 약간 경각심을 가질 필요도 있을 것 같다. 여러 리눅스 운영체제에서 사용하던 xz 유틸 오픈소스에 2024년 3월말에 백도어가 들어간 사건 등 개인적으로 너무 무분별하게 사용하는건 위험할수도 있겠다 싶었다.

     

    YAGNI

    • you ain't gonna need it
    • 현재 사용되지 않는 기능을 설계하지 말고 현재 사용되지 않는 코드를 작성하지 않는다.
    • 즉, 과도하게 설계하지 말라는 얘기.
    • 단, 이것이 코드의 확장성을 고려할 필요가 없다는 뜻은 아니다. (☆ 개인적으로 이 부분이 상당히 걸렸는데, 이 책에서 확장성 고려는 별개라 얘기해줘서 좋았던 부분이다.)

     


     

    3.7 DRY 원칙

    DRY

    • don't repeat yourself
    • 중복 코드를 작성하지 말라
    • 코드적으로 동일한 코드가 반드시 DRY 원칙을 위배하는 것은 아니다.
    • ☆ 개인적으로도 가장 중요하게 생각하는 원칙이다. 중복만 없어도 절반은 가는 것 같다.
    • ☆ 개인적으로 이 책에 나온 설명들 보다는, 조영호님의 오브젝트 책에 있던 '중복'에 대한 내용이 더 와닿았던 것 같다. "요구사항이 변경되었을 때 두 코드를 함께 수정해야 한다면 중복이다. 중복을 제거하지 않고 코드를 수정하는 유일한 방법은 새로운 중복 코드를 추가하는 것 뿐이다."
    • ☆ 3.7.3에 나온 코드는 약간 조심해서 볼 필요도 있을 것 같다. 이하 개인적인 의견이긴하다. 스프링부트 등으로 프로젝트를 진행할 때, layered architecture를 사용해 구성한다고 해보자. 도메인 계층에서 유효성 체크가 필요함은 너무나 당연하다. 근데 controller에서 service로 내리는 dto에서도 어느 정도의 유효성 체크를 해주는 책임을 넣을 수도 있다. 이 때 코드가 중복될 수 있으나, 전자는 도메인의 엔티티 객체의 유효함을 위한 체크이고, 후자는 단순히 데이터에 대한 유효함 체크이다. 그러니 이 경우 중복이 아니라 생각한다. 물론 언제나 명분과 팀의 합의가 가장 중요하므로, 미리 룰로 정해두면 애매모호할 일도 없을 것 같다(유효성 체크는 도메인 계층에서만 한다던지..). 오브젝트 책을 쓰신 조영호님 오프라인 강의에서도 이와 관련해 질문을 드렸는데, 비슷하게 답변해 주셔서 좋았다.

     

    코드 재사용성을 향상시키는 방법

    • 코드의 결합도를 줄인다.
      • 결합도가 높을 경우 코드를 분리하기 위해 보다 많은 코드를 재배치해야 한다.
    • 단일 책임 원칙을 충족시켜야 한다.
      • 그래야 해당 모듈이나 클래스에 의존하는 코드가 적을 것이므로
    • 코드의 모듈화는 필수다.
      • 모듈은 재사용하기 쉽고 복잡한 시스템을 구축하는 데 직접 사용할 수 있는 빌딩 블록과 같다.
    • 비즈니스 논리와 비즈니스 논리가 아닌 부분을 분리할 필요가 있다.
    • 일반적인 코드는 하위 계층으로 내려보낸다.
      • 하위 계층의 코드는 재사용하기 쉽다.
      • ☆ 사실 이게 예전 레거시 코드에서 쿼리문(SQL)에 비즈니스 로직이 전부 몰리게 된 이유기도 하다. DB가 가장 하위에 위치하므로, 그 이하로 종속성이 없어서 가장 수정하기 편한게 쿼리였기 때문이다. 그래서 클린 아키텍쳐나 헥사고날 아키텍쳐에서 도메인을 가장 하위에 격리해 두는 것이기도 하다.
    • 상속, 다형성, 추상화, 캡슐화를 활용한다.
    • 애플리케이션 템플릿과 같은 디자인 패턴을 활용하면 코드 재사용성을 향상시킬 수 있다.
      • 예를 들어 템플릿 메서드 패턴은 코드의 일부를 유연하게 교체할 수 있는 다형성을 사용하여 전체 프로세스의 템플릿 코드를 재사용할 수 있게 해준다.
    • ☆ 개인적으로도 템플릿 메서드 패턴을 좋아하는 편이다. 'TDD, Mock, SOLID 얘기 - 도시 가스 요금 계산' 글에서 '6. 리팩토링 2 - 디자인 패턴을 적용해보자!' 부분을 보면 리팩토링을 위해 템플릿 메서드 패턴을 사용한 예시를 볼 수 있다.

     


     

    3.8 LoD

    LoD

    • law of Demeter. 디미터 법칙 혹은 데메테르 법칙
    • == 최소 지식의 원칙 (the least knowledge principle)
    • 모든 유닛이 자신과 매우 밀접하게 관련된 유닛ㅇ제 대해서 제한된 지식만 알아야 한다.
    • 이 책의 저자가 정리한 LoD
      • 첫 번째, 직접 의존성이 없어야 하는 클래스 사이에는 반드시 의존성이 없어야 하며,
      • 두 번째, 의존성이 있는 클래스는 필요한 인터페이스에만 의존해야 한다.
    • ☆ 오직 하나의 도트만 사용하라는 원칙으로 해석되기도 한다. 오브젝트 책에서도 이와 같이 설명했고, "단, 디미터 법칙은 객체의 내부 구조가 외부로 노출되는 경우의 결합도에 관한 이야기 이므로, 무조건 하나의 도트만 쓰라는게 아니다." 라고 얘기했다.

    ☆ 무슨말이냐면, 이하는 디미터 법칙을 위반하는 코드의 모습이다. 전송자가 수신자의 내부 구조에 대해 물어보고 반환받은 요소한테 또 메시지를 전송한다. 클래스의 내부 구현이 외부로 노출된 경우이다. (오브젝트 책)

    screening.getMovie().getDiscountConditions();

     

    ☆ 하지만 이하의 경우 중간 연산 과정에서 계속 IntStream이라는 동일한 인스턴스를 반환하므로 이 경우는 디미터 법칙을 위반한게 아니다. (오브젝트 책)

    IntStream.of(1, 15, 20, 3, 9).filter(x->x>10).distinct().count();

     

     

     

    댓글