리팩토링 책 후기

카일·2020년 3월 15일
2

객체지향

목록 보기
2/2
post-thumbnail
post-custom-banner

소프트웨어 악취를 제거하는 리팩토링이라는 책을 읽은 내용을 간략하게 적은 포스팅입니다. 제가 초심자이기에 초심자의 입장에서는 굳이 추천드리고 싶지는 않은 책인것 같습니다. 이해하고 있는 내용에 대해서도 번역에서 오는 어려움이나 말 자체의 어려움때문에 이해에 어려움이 있었던 것 같습니다. 다양하게 발생할 수 있는 설계에서 오는 문제점을 체계적으로 분류하여 설명하고 있는 책입니다.

1 . 추상화의 악취

  • 절차지향의 문제
  • 완전하지 않은 인터페이스
  • 원시타입의 비 객체화
  • 두가지 책임 이상을 갖는 추상화의 문제
  • 미활용, 불필요한 추상화 및 클래스 등
  • 중복된 추상화

2 . 캡슐화의 악취

구현 세부 사항 감추기

  • 불충분한 캡슐화 (private field method)
    • 캡슐화가 필요함에도 불구하고 public 혹은 상수화하는 경우
  • 누출된 캡슐화 : 의도하지 않게 노출된 캡슐화
    • 불변 객체의 사용
    • 복사본 사용
    • 구체적인 자료형을 제시하지 않는 형태로 반환(사용자의 필요에 맞게)

변형 감추기

  • 누락된 캡슐화
    • 캡슐화란 변형을 감추는 것을 의미하는데 하나의 클래스에 다양한 메서드를 통해 처리하는 경우 변형에 대해 감추지 않는 형태를 보이기 때문에 누락된 캡슐화라 부름.
    • 사용하지 않을 수도 있는 여러가지 서비스가 추상화에 내장된 경우 혹은 상속을 통해 숨긴 경우 복잡하고 이해하기 어렵고 복잡도가 높다.
    • 전략패턴을 통한 해결
    • 가교패턴
  • 미활용 캡슐화
    • If else & Switch 문을 통한 결과 반환의 문제점 — 캡슐화 되어 있음에도 불구하고 누락되기 쉽다.
    • 전략패턴을 통한 해결

3 . 모듈화 악취

망가진 모듈화

  • 정의 : 데이터를 담고 있는 객체가 담당해야하는 일이 외부에게 맡겨져 본인의 일을 타 객체에게 전가하는 모듈의 형태
  • 원인
    • 객체지향 언어에서 절차적인 사고
    • 기존 설계에 대한 지식 부족
  • 해결 : 관련된 데이터와 메서드의 지역화 즉 객체는 상태와 행동을 갖는다.
  • 예외적인 경우 : DTO

불충분한 모듈화

  • 정의 : 완벽하게 분해되지 않은 추상화가 있으며 추가로 분해하면 크기나 구현 복잡도 둘 모두를 줄일 수 있을 때 발생한다. 일반적으로 공개 인터페이스에 엄청 많은 변수가 있거나 구현 복잡도가 과도하게 높은 메서드가 존재하는 경우.
  • 원인
    • 중앙 집중적인 제어 제공
    • 여러 클라이언트가 사용하는 거대한 클래스
    • 모든 관련된 기능을 하나로 묶기
  • 해결 : 추상화를 관리할 수 있는 크기로 분해
  • 슈퍼 클래스나 인터페이스에서 메서드 혹은 클래스, 인터페이스를 분리하는 방식으로 이를 제어할 수 있다.
  • 예외 사항 : 핵심클래스는 어쩔수없이 다양한 클래스와 강하게 결합되는 형태를 보일 수 있다. 이런 경우 회피는 어렵지만 역시 내부적으로라도 분해하여 유지보수가 쉽도록 고려하는 것이 바람직하다.

순환 의존성이 있는 모듈화

  • 정의 : 추상화 둘 이상이 추상화 사이에 강한 결합을 만드는 방법으로 서로 직간접적으로 의존할 때 이런 현상이 발생한다.
  • 원인
    • 부적절한 책임 인식
    • 자체 참조 전달
    • 콜백 기능 구현
    • 시각화하기 어려운 간접 의존성
  • 해결 : 비순환적인 의존성 생성
    • 순환과 관련된 추상화 중 하나를 위한 인터페이스를 도입한다.
    • 의존성이 불필요하며 안전하게 제거가 가능할 때는 의존성을 제거한다. 혹은 순환 의존성에 해당하는 메서드를 옮긴다.
    • 순환의존성을 일으키는 코드를 완전히 다른 추상화로 옮긴다.
    • 순환과 관련된 추상화들이 의미상 단일 객체를 표현하는 경우 해당 추상화들을 단일 추상화로 합친다.
  • 크기가 1인 순환 즉 서로 항상 같이 이해되고 사용되고 재사용되는 클래스는 순환 의존이 발생하는 경우에 그나마 괜찮다. 하지만 이 경우에도 전체적으로 봤을 때 순환이 늘어나면서 관계를 명확하게 하기 힘들어진다. 순환의존은 최소한하는 것이 바람직하다. 언제나

허브와 같은 모듈화(병목)

  • 정의 : 특정 추상화가 다른 대다수 추상화에 들어오고 나가는 의존성이 있을 때 이런 현상이 발생한다.
  • 원인
    • 허브 클래스로 부적절한 책임 할당 : 추상화가 너무 많은 책임을 지는 경우
    • 모든 것을 쏟아붓는 유틸리티 클래스 : 일반적으로 유틸리티 클래스에서는 모든 보조기능을 쏟아 붓는 경향을 보인다. 이 경우 대부분의 클래스와 강하게 결합되는 단점을 갖는다.
  • 해결 : 의존성 제한 및 분할
    • 기존에 직 간접적으로 의존하고 있던 의존성을 별도의 클래스나 메서드로 분리하고 역할을 위임하여 의존성을 줄인다.

4 . 계층 악취

누락된 계층

  • 정의 : 계층을 생성하고 변종을 캡슐화하는 데 사용 가능한 행동 양식의 변종을 코드 조각이 조건부 논리를 사용하여 명시적으로 관리할 때 이러한 문제가 발생한다. 조건부 논리에서 빠지는 값이 있을 수 있음.
  • 원인
    • 지나치게 단순한 잘못된 설계
    • 설계에 절차적인 접근
    • 설계 기법으로서 상속 간과
  • 해결
    • 조건 검사 내부에서 둘 이상의 구현에 공통적인 메서드의 호출이 있으면 공통 프로토콜을 추상화하려고 적절한 인터페이스를 도입 할 수 있다.
    • 클래스로 변환 가능한 조건문이 있을 때 계층 추출 리팩토링을 적용하여 조건 점검에서 각 경우를 대표하는 개별 클래스의 계층을 생성할 수 있다. 이제 실행 시간 다형성을 사용하여 계층 활용이 가능하다.
  • 예외사항 : 타입과 관계없는 형태로 조건문을 타는 경우는 이러한 적용이 필요하지 않다.

불필요한 계층

  • 정의 : 특정 설계 맥락에서 상속을 불필요하게 적용하여 왔음을 보여주는 전체 상속 계층이 불필요할 때 이런 경우가 발생한다. 의미있는 분류 적용은 데이터가 아니라 행동 양식의 공통점과 차이점을 잡아내는 과정에 초점을 맞추는데 이를 위반하는 경우 주로 발생한다.
  • 원인
    • 불필요한 하위 클래스 생성
    • 분류 광
  • 해결
    • 타입의 인스턴스를 대신하여 해당 타입의 하위 타입으로 모델링할 때 계층을 제거하고 하위타입을 해당 타입의 인스턴스로 변환한다.
    • 적절한 언어 기능을 사용하는 대신 상속 계층을 생성할 때는 불필요한 계층을 제거하고 해당 언어의 기능을 활용한다.

팩토링되지 않은 계층

  • 정의 : 계층에 있는 타입 사이에 불필요한 중복이 있을 때 이런 악취가 발생한다. 이런 악취는 아래의 두 가지 형태로 드러난다
    • 형제 자매 타입에서 발생한 중복 : 계층에서 형제자매 타입이 상위 타입 중 하나로 이동가능한 유사한 코드조각
    • 상위 타입과 하위 타입에서 발생한 중복 : 상위 타입과 하위 타입에 유사한 코드가 있을때 하위 타입에서 중복 코드가 있음을 암시한다.
  • 원인
    • 하위 타입 복사
    • 튀는 클래스의 부적절한 처리
  • 해결
    • 하위 타입의 메서드 서식과 정의 필드가 동일하다면 관련된 메서드 인터페이스와 같은 형태의 상위 타입으로 끌어올린다.
    • 내부적으로 조금씩 달라보이는 것들도 공통적으로 일치하는 것이 존재할 수 있다. 이 부분을 추상화해보자.

넓은 계층

  • 정의 : 중간 타입이 빠졌을 수도 있다는 것을 암시하는 너무 넓은 상속관계가 존재할 때 이러한 현상이 나타난다. 상속 계층은 적절한 크기를 유지해야 효율적으로 설계할 수 있다. 이는 두가지 경우에서 주로 발생하는데 너무 많은 하위타입을 갖거나(직접적으로) 하위 타입과의 갭이 너무 큰 상태에서 주로 나타난다.
  • 원인
    • 일반화 무시
    • 리팩토링 부족
  • 해결

추측에 근거한 계층

깊은 계층

반체제적인 계층

망가진 계층

다중 경로 계층

순환 계층

post-custom-banner

1개의 댓글

comment-user-thumbnail
2020년 6월 15일

마저쓰시죠

답글 달기