우아한테크코스

"프리코스 6일차" 리팩토링(Law of Demeter, TDA 원칙), 클래스 다이어그램

kanado 2024. 10. 20. 23:36

📝 오늘의 Todo 리스트 체크

1. 클래스 다이어그램

     - (학습) 클래스 다이어그램 공부

     - 클래스 다이어그램 그리기
2. 코드 테스트/리팩토링
    - 코드 2차 테스트 및 리팩토링
    - 
프로그래밍 요구 사항, 과제 진행 요구 사항, 기능 요구 사항 확인


목차

- 리팩토링

     - 단순한 유틸리티 클래스 생각해보기

     - 디미터 법칙 (Law of Demeter) 위반 코드 발견
     - Tell, don't ask 원칙 위반 코드 발견
     - 세세한 수정들

- 모든 요구 사항 확인

- Readme 파일 업데이트

- 클래스 다이어그램
     - 클래스 다이어그램의 필요성과 정의

     - 클래스 다이어그램 설계

- 내일 Todo 리스트


 

1. 단순한 유틸리티 클래스 생각해보기

오늘 하루를 리팩토링으로 시작했다. 제일 거슬려 보였던 부분은 바로 MainController가 너무 많은 객체 속성을 가지고 있던 갓이다.

 

다시 생각해보니 InputView, OutputView 클래스가 속성을 가지고 있지않고 순수 메서드만 가지고 있는 단순한 유틸리티 클래스다. 그리고 Calculator 클래스도 마찬가지다. 그래서 이 3개의 클래스가 가진 메서드를 static으로 바꾸고 MainController에서 그 클래스들의 객체를 속성으로 선언하지 않고 메소드를 정적 호출로 사용하도록 수정했다.

public class MainController {
    private CustomDelimiter customDelimiter;

    public void start(){
        readUserFormula();
    }

    public void readUserFormula(){
        this.customDelimiter = new CustomDelimiter(InputView.readUserNumbers());
        calculate();
    }

    public void calculate(){
        Splitter splitter = new Splitter(customDelimiter);
        printSumToUser(splitter.getSplittedNumbers());
    }

    public void printSumToUser(String[] splittedNumbers){
        OutputView.printSumToUser(Calculator.plus(splittedNumbers));
    }
}

 

2. 디미터 법칙 (Law of Demeter) 위반 코드 발견

우선 디미터 법칙 (Law of Demeter) 다름 말로 최소 지식 원칙이 뭘까? 최소 지식 원칙은 객체가 다른 객체에 대해 최소한의 정보만 알고, 직접적으로 상호작용하는 객체들끼리만 통신하도록 제한하는 원칙이다. 이를 통해 객체 간 결합도를 낮추고, 시스템의 변경에 대한 영향을 최소화하는 것을 목표로 한다.

MainController클래스의 calculate 메서드와 printSumToUser 메서드 사이에 최소 지식 원칙을 위반하는 코드를 발견했다. 

 

위 코드에서 최소 지식 원칙이 위반된 이유는, Splitter 객체의 getSplittedNumbers() 메소드를 통해 Splitter의 내부 상태(즉, splitter가 가지고 있는 데이터)를 외부에서 직접 접근하고 있다는 점이다. 이로 인해 Splitter 클래스의 내부 구현에 대한 지식이 calculate() 메소드 안에 노출된다.

 

최소 지식 원칙은 객체 간의 관계를 최소화하여 객체가 자신의 책임에 대해서만 알도록 하는 원칙으로 위 코드에서 calculate() 메소드는 splitter.getSplittedNumbers()를 통해 Splitter 객체의 세부 사항에 직접 접근함으로써, Splitter 객체의 내부 구조에 의존하게 된다. 이로 인해 코드의 유지보수가 어려워질 수 있고, 객체 간의 결합도가 높아진다.

 

이 문제를 해결하기 위해 Calculator.plus() 메소드 내부에서 Splitter가 getSplittedNumbers() 메소드를 호출하는 방식은 그대로 유지하되, 외부에서 Splitter에 직접 접근하지 않도록 하였다. 즉, calculate() 메소드에서 Splitter 객체를 생성하고 getSplittedNumbers() 메소드를 호출하는 것이 아니라, Calculator.plus() 메소드가 Splitter 객체의 책임을 모두 처리하게 하였습니다. 이를 통해 calculate() 메소드는 Calculator 클래스에만 의존하게 되어, 외부에 불필요하게 많은 정보를 노출하지 않게 되다.

 

이로 인해 MainController클래스의 calculate 메서드와 printSumToUser 메서드의 역할이 더욱 더 명확해졌다.

 

3. Tell, don't ask 원칙 위반 코드 발견

우선 묻지 말고, 시켜라(Tell, don't ask) 원칙은 객체가 자신의 상태를 외부에서 물어보는 대신, 필요한 작업을 직접 수행하게 해야 한다는 개념이다. 이를 통해 객체의 자율성을 보장하고, 캡슐화를 유지하여 비즈니스 로직이 객체 내부에서 관리되도록 한다. 이 원칙을 지키기 위해 클래스가 자기의 속성에 대한 직접적인 Getter, Setter 메서드가 없어야한다.

 


Tell, don't ask 원칙이 위반되고 있는 코드를 Splitter 클래스에서 발견했다. Splitter 클래스의 속성을 직접 get하는 메서드로 다른 클래스에서 이를 사용할 수 있게 구현되어있었다. 이를 방지하기 위해서 다음과 같이 수정했다.


수정된 코드는 Tell, don't ask 원칙을 따르기 위해 내부 상태를 제거하고, splitNumbers 메서드를 static으로 변경하여 객체 생성 없이 호출할 수 있게 했다. 이제는 문자열 분리 작업은 FormulaHandler에서 필요한 정보(숫자 부분과 커스텀 구분자)를 받아서 처리하며, 기본 구분자(쉼표와 콜론)에 커스텀 구분자가 있을 경우 이를 추가하여 문자열을 분리한다. 이를 통해 객체의 상태를 외부에서 가져오지 않고, 필요한 작업을 메서드 내에서 직접 처리한다.

 

4. 세세한 수정들

마지막 리팩토링으로는 코드 여러 부분에서다음과 같은 세세한 수정들을 했다.
1. 네이밍 다시 생각해보고 수정

2. private로 해야하지만 아무 이유 없이 public으로 둔 메서드를 수정

3. 변경되면 안되는 클래스의 속성을 final로 수정

 

5. 모든 요구 사항 확인

 

우테코 사이트에서 제시된 프로그래밍 요구 사항, 과제 진행 요구 사항, 기능 요구 사항을 검토 후에 pr url를 제출 시도 해보았다.
(아직 회고를 작성하지 않은 상태에서)

너무나 다행이 모든 테스트를 정상적으로 통과했다.😭

 

5. 세세한 수정들

마지막 리팩토링으로는 코드 여러 부분에서다음과 같은 세세한 수정들을 했다.
1. 네이밍 다시 생각해보고 수정

2. private로 해야하지만 아무 이유 없이 public으로 둔 메서드를 수정

3. 변경되면 안되는 클래스의 속성을 final로 수정

 

6. Readme 파일 업데이트

어제 예외 처리를 다시 생각해본 것들과 오늘까지 한 리팩토링으로 인해 바뀐 코드를 readme 파일의 기능 목록과 MVC 구조 설게에 업데이트 시켰다.

 

7.  클래스 다이어그램의 필요성과 정의

"소프트웨어 공학의 모든 것" 책에서 프로젝트 설계 단계에서 사용되는 여러 가지 다이어그램에 대해 알게 되었다. 현재는 이미 구현이 완료된 상태이지만, 다이어그램을 언급한 이유는 그 중요성 때문이다.

 

모델링 과정에서 가장 마지막에 설계되는 다이어그램이 클래스 다이어그램이다. 따라서 모든 구현이 끝난 지금, 클래스 다이어그램을 그릴 수 있는데, 그 목적은 설계보다는 내가 구현한 애플리케이션의 클래스 간 관계를 쉽게 시각화하고 이해하는 데 있다. 이를 통해 코드 구조를 명확히 파악할 수 있어, 나중에 코드 리뷰를 받을 때 다른 사람들이 전체적인 구조를 한눈에 이해하는 데도 도움이 될 수 있을 것 같아.

 

우선, 클래스 다이어그램은 객체지향 설계에서 클래스 간의 구조적 관계를 표현하는 UML(Unified Modeling Language) 다이어그램이다. 클래스 다이어그램은 클래스의 속성, 메서드, 그리고 클래스 간의 상속, 연관, 집합 관계 등을 시각적으로 나타낸다. 이를 통해 클래스 간의 상호작용과 책임을 명확하게 보여주며 설계와 구현 과정에서 코드의 구조를 이해하는 데 중요한 역할을 한다.

 

8. 클래스 다이어그램 설계

내가 구현한 코드 바탕으로 쉽게 다음과 같이 클래스 다이어그램을 설계했다.

 

9. 내일 Todo 리스트

1. 1주차 회고 작성
     - 어떤 것이 제일 어려웠는지 생각해보기 🔳
     - 배운점이나 깨달은 것들을 정리하기 🔳

     - 지난 일주일을 돌아보며 앞으로 계획 세우기 🔳

2. 마지막 검토 및 최종 제출

     - PR링크 제대로 들어가지는지 확인하기 🔳

     - 우테코 사이트에서 회고 작성 및 제출 🔳

 

참고자료

 

[OOP] 객체지향 디자인원칙 -3- | jcheolho

원칙7 정말 친한 친구하고만 얘기하라.(최소 지식 원칙) (Principle of Least Knowledge) = (Law of Demeter) 일곱번째 원칙은 퍼사드 패턴에서 등장했다. 객체 사이의 상호작용, 즉 어떤 객체들이 다른 객체를

cheolhojung.github.io

 

 

[OOP] Tell, Don't Ask(TDA) 원칙과 캡슐화

Tell, Don't Ask. 객체에게 데이터를 요구(Ask) 하지 말고, 객체에게 일을 시켜라(Tell) 정도로 해석할 수 있다. 객체 지향적 사고방식 원칙 중 하나인데, 특히 객체지향의 핵심인 캡슐화가 잘 이루어진

seungtaek-overflow.tistory.com

 

 

[UML] 클래스 다이어그램 (Class Diagram)

클래스 다이어그램은 구조 다이어그램으로 클래스 내부 구성요소 및 클래스 간의 관계를 도식화하여 시스템의 특정 모듈이나 일부 및 전체를 구조화 합니다. 개발 하기 전, 클래스 다이어그램

brownbears.tistory.com

 

끝.