클린코드 10장 클래스

kimjunkyung·2021년 8월 5일
0

클린코드

목록 보기
11/15
post-thumbnail

노션에서 정리한 내용을 벨로그로 옮겼기 때문에 노션으로 보면 조금 더 보기 더 편합니다🤗

이동하기 → junnkk's Notion


클래스 체계

클래스를 정의하는 표준 자바 관례에 따른 순서

  1. 변수 목록( 정적(static) 공개(public) 상수 → 정적 비공개(private) → 비공개 인스턴스 변수 순)
  2. 공개 함수
    1. 비공개 - ****함수 자신을 호출하는 공개 함수 직후에 넣는다 .

⇒ 추상화 단계가 순차적으로 내려감( like 신문 기사)

  • 캡슐화

    • 변수와 유틸리티 함수 → 공개하지 않는 편이 좋지만 반드시는 아님.

    • 테스트 코드가 함수를 호출하거나 변수를 사용해야 할 때 protected로 선언하거나 패키지를 전체 공개 하기도 하지만 그 전에 비공개 유지할 방법 강구

      ⇒ 캡슐화를 풀어주는 결정은 최후의 수단


클래스는 작아야 한다!

  • 클래스는 작아야 한다 → 맡은 책임 개수 ↓

  • 클래스 이름은 해당 클래스의 책임을 기술해야한다.

    → 간결하지 못한 이름 = 너무 많은 책임

    → 모호한 이름 ex) Processor, Manager, Super 등 = 여러 책임을 가짐

  • 클래스 설명은 if, and, or, but 없이 25 단어 내외

  • 단일 책임 원칙(SRP)

    : 클래스나 모듈을 변경할 이유(책임)가 단 하나 뿐이어야 한다.

    예시)

    p175~176 [10-2]

    → 변경할 이유 1. 소프트웨어가 출시할 때마다 달라지는 소프트웨어 버전 정보 추적

    → 변경할 이유 2. 자바 스윙 컴포넌트 관리. 즉, 스윙 코드 변경 시 버전 정보 변화

    p76 [10-3] 10-2에서 버전 정보를 다루는 메소드를 빼낸 독자적인 단일 책임 클래스

    → 재사용 용이

    ⇒ 예시처럼 책임(변경할 이유)을 파악하려 하면 추상화가 쉬워짐.

    • 규모가 있는 복잡한 시스템을 다루려면 체계적인 정리 필수.

      → 위치 파악이 용이해짐

      → 변경 시 직접 영향이 미치는 컴포넌트만 이해해도 됨.

      ⇒ 큰 클래스보다 작은 클래스 여럿이 더 바람직 함

      ∵ 작은 클래스는 각자 맡은 책임이 하나이며 변경할 이유가 없으며, 다른 작은 클래스와 협력해 시스템에 필요한 동작을 수행.

  • 응집도

    응집도가 높다 = 클래스에 속한 메서드와 변수가 서로 의존하며 논리적인 단위로 묶인다

    • 클래스는 인스턴스 변수 수가 작아야 한다.

    • 각 클래스 메서드는 클래스 인스턴스 변수를 하나 이상 사용해야 한다.

      → 일반적으로 메서드가 변수를 더 많이 사용할수록 메서드와 클래스는 응집도가 더 ↑

      → but 모든 인스턴스 변수를 메서드마다 사용하는 클래스는 응집도가 가장 높지만 불가능하고 바람직 X

    • '함수를 작게, 매개변수 목록을 짧게' 하면 몇몇 메서드만이 사용하는 인스턴스 변수 개수 ↑(응집도 낮아짐을 의미)

      ⇒ 응집도가 높아지도록 변수와 메서드를 적절히 분리해 새로운 클래스 두세 개로 쪼갠다.

      예시) p178 응집도가 높은 클래스

        public class Stack {
            private int topOfStack = 0;  // 인스턴스 변수
            List<Integer> elements = new LinkedList<Integer>(); // 인스턴스 변수
            
            public int size() { 
                return topOfStack;   // 클래스 인스턴스 변수 topOfStack 사용
            }

            public void push(int element) { 
                topOfStack++;   // 클래스 인스턴스 변수 topOfStack 사용
                elements.add(element);   // 클래스 인스턴스 변수 elements 사용 
            }
            
            public int pop() throws PoppedWhenEmpty { 
                if (topOfStack == 0)   // 클래스 인스턴스 변수 topOfStack 사용
                    throw new PoppedWhenEmpty();
                int element = elements.get(--topOfStack); // 클래스 인스턴스 변수 elements 사용 
                elements.remove(topOfStack);
                return element;
            }
        }
  • 응집도를 유지하면 작은 클래스 여럿이 나온다

    큰 함수를 작은 함수로 쪼개다 클래스가 응집력을 잃는다면 클래스를 쪼개야 한다.

    예시) p179~184 [10-5] → [10-6]~[10-8] 리팩터링

    → 프로그램의 길이가 길어진 이유

    1. 리팩터링한 프로그램은 좀 더 길고 서술적인 변수 이름을 사용한다.
    2. 리팩터링한 프로그램은 코드에 주석을 추가하는 수단으로 함수 선언과 클래스 선언을 활용한다.
    3. 공백을 추가하고 형식을 맞추어 가독성 ↑
    • 원래 프로그램 ⇒ 세 가지 책임(PrimePrinter, PowColumnPagePrinter, PrimeGenerator)

    • 원래 프로그램을 수정한 과정(리팩터링)

      1. 원래 프로그램의 정확한 동작을 검증하는 테스트 슈트를 작성
      2. 한 번에 하나씩 수 차례에 걸쳐 조금씩 코드를 변경
      3. 코드를 변경할 때마다 테스트를 수행해 원래 프로그램과 동일하게 동작하는지 확인

변경하기 쉬운 클래스

  • 깨끗한 시스템은 클래스를 체계적으로 정리해 변경에 수반하는 위험을 낮춘다

예시)

p186 [10-9] 변경이 필요한 클래스. 주어진 메타 자료로 적절한 SQL 문자열을 만드는 Sql 클래스

→ 변경할 이유(책임)가 두 가지(SRP 위반)이므로 수정이 필요하다.

p187~188 [10-10] 10-9를 개선한 닫힌 클래스 집합

→ 공개 인터페이스를 각각 Sql 클래스에서 파생하는 클래스로 만듦.

→ 비공개 메서드는 해당하는 파생 클래스로 이동 ex) valueList

→ 모든 파생 클래스가 공통으로 사용하는 비공개 메서드는 Where과 ColumnList라는 두 유틸리티 클래스로 이동

  • 재구성한 Sql 클래스 ⇒ SRP지원, OCP 지원(OCP: 클래스는 확장에 개방적이고 수정에 폐쇄적이어야 한다는 원칙)

⇒ 새 기능을 수정하거나 기존 기능을 변경할 때 건드릴 코드가 최소인 시스템 구조가 바람직. 새 기능 추가 시 시스템 확장 but 기존 코드 변경 X

  • 변경으로부터 격리

    • 구체적인 클래스 Concrete Class - 상세한 구현(코드) 포함

    • 추상 클래스 Abstract Class - 개념만 포함

      → 상세한 구현에 의존하는 클라이언트 클래스는 구현이 바뀌면 위험하므로 인터페이스와 추상 클래스를 사용해 구현이 미치는 영향을 격리한다.

      예시) p189~190 Portfolio

      → 5분 마다 값이 달라지는 API를 사용 구체적인 클래스를 사용하는 대신 테스트용 클래스는 stockExchange 인터페이스를 구현하며 고정된 주가를 반환하는 추상적인 클래스를 사용

      ⇒ 변경을 포함하는 구체적인 클래스 대신 추상 클래스로 테스트

      ⇒ 테스트가 가능할 정도로 시스템의 결합도를 낮추면 유연성과 재사용성이 높아짐.

      ( 결합도가 낮다 = 각 시스템의 요소가 다른 요소로부터 그리고 변경으로부터 잘 격리되어 있다

      → 각 요소도 이해하기 쉽다. )

      ⇒ 결합도를 최소로 줄이면 자연스럽게 DIP(클래스가 상세한 구현이 아니라 추상화에 의존해야 한다는 클래스 설계 원칙)을 따르는 클래스가 나온다.



11장 시스템

profile
#Backend #Developer

0개의 댓글