* UML (Unified Modeling Language)

    > 시스템 시가고하나 사양 및 설계를 문서화할때 사용하는 표현 방법

    > 이탤릭체 (interface, abstract)

        - 추상 클래스, 인터페이스, 추상 메서드

    > 밑줄 (static)

        - 클래스 필드, 클래스 메서드

    > Realization (실체화, -----▷)

        - concrete class 에서 interface 방향으로 긋는다

    > Inheritance (상속, ─▷)

        - child class 에서 parent class 방향으로 긋는다

    > Aggregation (집합, ◇─>)

        - 객체를 포함하는 쪽에서 포함되는 쪽으로 긋는다

        - 필드에 포함되어 있음을 강조할 때 사용

    > Directed Association (직접 연관, ─>)

        - class A 는 class B 를 알고 있음

        - 필드에 들어 있음을 강조할 때 사용

    > Dependency (의존, ----->)

        - class A는 class B 를 사용함

        - 매개변수나 임시 변수 등으로 사용할 때 사용

    > 화살표의 방향은 의존하는 것을 의미하기 때문에 매우 중요하다

 

* Sequence Diagram

    > 프로그램 동작 순서를 표현

    > Method Call (─▶)

    > Method Return (<-----)

 

* Refactoring

    > 외부에서 보는 프로그램 동작은 바꾸지 않고 프로그램의 내부 구조를 개선

        - 리팩토링해도 외부에서 보는 프로그램 동작은 변하지 않는다

        - 리팩토링하면 프로그램의 내부 구조가 개선된다

 

* Refactoring 의 장점

    > 버그를 발견하기 쉽게 만든다

    > 기능을 추가하기 쉽게 만든다

    > 리뷰하기 쉽게 만든다

 

* Refactoring 의 한계

    > 프로그램이 아직 동작하지 않을 때는 불가능하다

    > 시간이 너무 촉박할 때 하는 건 현명하지 않다

 

* 22가지 Code Smell

    1. 중복코드

    2. 너무 긴 메서드

    3. 방대한 클래스

    4. 과다한 매개변수

    5. 변경 발산

        > 사양 변경이 있을 때 수정해야 할 내용이 곳곳에 흝어져있다

    6. 변경 분산

        > 어떤 클래스를 수정하면 다른 클래스도 수정해야 한다

    7. 속성, 조작 끼어들기

        > 언제나 다른 클래스 내용을 수정하는 클래스가 있다

    8. 데이터 뭉치

        > 합쳐서 다뤄야 할 데이터가 한 클래스에 모여 있지 않다

    9. 기본 타입 집착

        > 클래스를 만들지 않고 int 같은 기본 타입만 사용한다

    10. 스위치 문

        > switch 문이나 if 문으로 동작을 나눈다

    11. 평행상속

        > 하위 클래스를 만들면 클래스 계층의 다른 곳에서도 하위 클래스를 만들어야 한다

    12. 게으른 클래스

        > 클래스가 별로 하는게 없다

    13. 의심스러운 일반화

        > '언젠가 이런 확장을 하겠지'라고 너무 일반화한다

    14. 임시 속성

        > 임시로만 쓰는 필드가 있다

    15. 메시지 연쇄

        > 메서드 호출 연쇄가 너무 많다

    16. 중개자

        > 맡기기만 하고 자신은 일하지 않는 클래스가 있다

    17. 부적절한 관계

        > 그럴 필요가 없는데도 양방향 링크를 걸거나 Is-A 관계가 없는데 상속을 사용한다

    18. 클래스 인터페이스 불일치

        > 클래스 인터페이스가 적절하지 않다

    19. 불완전한 라이브러리 클래스

        > 기존 라이브러리 클래스를 사용하기 어렵다

    20. 데이터 클래스

        > 필드와 getter, setter 뿐인 클래스가 있다

    21. 상속 거부

        > 상속한 메서드인데 호출하면 문제가 발생한다

    22. 주석

        > 코드의 부족한 부분을 설명하기 위해 자세한 주석이 붙어있다

 

* Replace Magic Number with Symbolic Constant (매직 넘버를 기호 상수로 치환)

    > 문제점

        - Magic Number 를 사용하는 경우, 해당 값이 무엇을 뜻하는지 알기 어렵다

        - 여러 곳에 있으면 변경하기도 어렵다

    > 해법

        - 매직 넘버를 기호 상수로 치환

    > 결과

        - 상수의 의미를 알기 쉬워짐

        - 값 변경 시, 상수를 사용하는 모든 곳의 값이 변경됨

        - 이해하기 어려운 이름을 사용하면 오히려 오해가 생길 수도 있음

 

* Remove Control Flag (제어 플래그 삭제)

    > 문제점

        - 처리 흐름을 제어하는 플래그 때문에 코드가 복잡해진다

    > 해법

        - 제어 플래그를 삭제하고 break, continue, return 을 사용

    > 결과

        - 조건 의미와 제어 흐름이 명확해짐 (이후에 오는 코드를 읽지 않아도 됨)

        - 단순 반복에도 무리하게 적용하면 코드가 부자연스러워짐

 

* Introduce Assertion (어서션 도입)

    > 문제점

        - 주석으로 '어떤 조건이 성립한다'라고 적어도 프로그램 실행시 확인되지 않음

    > 해법

        - Assetion 도입

    > 결과

        - 해당 부분에서 성립해야 할 조건이 명확해지고 소스 코드가 읽기 좋아짐

        - 버그를 빨리 발견 가능함

 

* Introduce Null Object (널 객체 도입)

    > 문제점

        - null 확인이 너무 많음

    > 해법

        - null 을 나타내는 특별한 객체를 도입해 '아무것도 안 함' 이라는 처리를 함

    > 결과

        - null 확인이 줄어듦

        - 널 객체 종류 만큼 클래스가 늘어날 수 있음

 

* Extract Method (메서드 추출)

    > 문제점

        - 메서드 하나가 너무 긺

    > 해법

        - 기존 메서드에서 묶을 수 있는 코드를 추출해 새로운 메서드를 작성함

    > 결과

        - 각 메서드가 짧아짐

        - 메서드 개수가 늘어남

 

* Extract Class (클래스 추출)

    > 문제점

        - 한 클래스가 너무 많은 책임을 지고 있음

    > 해법

        - 묶을 수 있는 필드와 메서드를 찾아 새로운 클래스로 추출

    > 결과

        - 클래스가 작아짐

        - 클래스의 책임이 명확해짐

        - 클래스 개수가 늘어남

 

* Replace Type Code with Class (분류 코드를 클래스로 치환)

    > 문제점

        - 타입 판별이 안 됨

    > 해법

        - 분류 코드를 나타내는 새로운 클래스를 작성

    > 결과

        - 분류 코드의 타입 판별이 가능해짐

        - 클래스 개수가 늘어남

 

* Replace Type code with Subclasses (분류 코드를 하위 클래스로 치환)

    > 문제점

        - Switch 문을 써서 동작을 구분함

    > 해법

        - 분류 코드를 하위 클래스로 치환해서 다형적 메서드를 작성

    > 결과

        - 동작이 클래스별로 나뉨

        - 클래스 개수가 늘어남

 

* Replace Type Code with State/Strategy (분류 코드를 상태/전략 패턴으로 치환)

    >  문제점

        - 동작을 switch 문으로 나누고 있지만 분류 코드가 동적으로 변하므로 분류 코드를 하위 클래스로 치환은 불가

    > 해법

        - 분류 코드를 나타내는 새로운 클래스를 작성해서 상태/전략 패턴을 사용함

    > 결과

        - 분류 코드 타입 판별이 가능해짐

        - 분류 코드에 따른 클래스 동작을 다형성으로 해결 가능

        - 클래스 개수가 늘어남

 

* Replace Error Code with Exception (에러 코드를 예외로 치환)

    > 문제점

        - 정상 처리와 예외 처리가 혼재함

        - 에러 코드 전파 처리가 넓은 범위에 있음

    > 해법

        - 에러 코드 대신에 예외를 사용함

    > 결과

        - 정상 처리와 에러 처리를 명확하게 분리 가능

        - 에러 코드를 반환해서 전파하지 않아도 됨

        - 에러 관련 정보를 예외 객체에 저장 가능

        - 에러 발생 부분과 에러 처리 부분이 분리되기 때문에 알기 어려워지는 경우도 있음

 

* Replace Constructor with Factory Method (생성자를 팩토리 메서드로 치환)

    > 문제점

        - 생성하고 싶은 인스턴스가 속한 실제 클래스를 클라이언트에는 숨기고 싶음

    > 해법

        - 생성자를 팩토리 메서드로 치환함

    > 결과

        - 어느 클래스 인스턴스를 생성할지를 팩토리 메서드안에서 정할 수 있음

        - 생성한 인스턴스를 변경해도 클라이언트 쪽은 변경하지 않아도 됨

        - 추상도가 너무 올라가면 코드가 오히려 어려워짐

 

* Duplicate Observed Data (관측 데이터 복제)

    > 문제점

        - 모델과 뷰가 한 클래스 안에 뒤섞여 있음

    > 해법

        - 양쪽을 분리하고 관찰자 패턴 또는 이벤트 리스너로 동기화함

    > 결과

        - 클래스 역할이 확실해짐

        - 여러 뷰를 가지거나 뷰를 전환하기 쉬워짐

        - 클래스 숫자가 늘어남

        - 주의하지 않으면 동기화 이벤트가 무한히 발생할 수도 있음

 

* Replace Inheritance with Delegation (상속을 위임으로 치환)

    > 문제점

        - 하위 클래스가 상위 클래스 기능의 일부만 사용함 (상속 거부)

        - 하위 클래스가 상속 클래스와 IS-A 관계가 아님

        - 리스코프 치환 원칙 위반

        - 계약을 지키지 않음

    > 해법

        - 위임을 사용해서 상속을 치환함

    > 결과

        - 부적절한 상속 관계를 해소 가능함

        - 클래스에 필요한 기능이 명확해짐

        - 클래스 개선, 기능 추가가 편해짐

        - 위임하는 메서드를 작성해야함

 

* Hide Delegate (대리자 은폐)

    > 문제점

        - 클라이언트 클래스가 서버 클래스뿐만 아니라 대리 클래스까지 이용함

    > 해법

        - 서버 클래스에 위임 메서드를 추가해서 클라이언트 클래스로부터 대리 클래스를 은폐

    > 결과

        - 클래스 사이의 불필요한 관계가 줄고 코드 수정이 쉬워짐

        - 서버 클래스의 책임이 늘어남

 

* Tease Apart Inheritance (상속 구조 정리)

    > 문제점

        - 클래스 계층 하나에서 다양한 작업을 함

    > 해법

        - 상속을 분할하고 필요한 작업은 위임을 사용해 이용함

    > 결과

        - 부적절한 상속 관계를 해소 가능

        - 클래스 개선, 기능 추가가 편해짐

        - 클래스 개수가 늘기도 함

 

+ Recent posts