클린코드 정복하기 3주차

wannte·2021년 1월 19일
0

5. 형식 맞추기

코드의 형식은 의사소통의 일환이다.

신문 기사처럼 작성하라

이름을 간단하면서 설명적으로 짓는다.
소스 파일의 첫 부분은 고차원 개념과 알고리즘을 설명한다.
아래로 내려갈수록 의도를 세세하게 묘사한다.
마지막에는 저차원 함수화 세부 내역이 나온다.

개념은 빈 행으로 분리하라, 반대로 밀집도는 연관성을 의미한다.

패키지 선언부, import 문, 각 함수 사이에는 빈 행을.
인스턴스 변수사이에 의미 없는 주석 x

수직 거리

  • 서로 밀접한 개념은 세로로 가까이 두어야 한다. 타당한 근거가 없다면 서로 밀접한 개념은 한 파일에 속해야 마땅하다
    -> protected 변수를 피해야 하는 이유
  • 변수는 사용하는 위치와 최대한 가까이 선언
  • 인스턴스 변수는 클래스 맨 처음에 선언. 중간쯤에 선언하지 말아라.(설계한 대다수의 메소드가 인스턴스 변수를 사용하기 때문)
  • 종속 함수 : 함수가 다른 함수를 호출한다면 가까이 배치. 호출하는 함수가 호출되는 함수보다 먼저 배치
  • 개념적 유사성 : 서로 친화도가 높은 코드들을 가까이 배치. 비슷한 동작을 수행하는 경우
  • 세로 순서 : 함수 호출 종속성을 아래 방향으로 유지

상수를 적절한 수준에 두는 예제.

String pageName = getPageNameOrDefault(request, "FrontPage")

private String getPageNameOrDefault(Request request, String defaultPageName) {	
    pageName = request.getResource();
    if (StringUtil.isBlank(pageName)) {
    	pageName = defaultPageName;
    }
    return pageName;
}

상수를 알아야 마땅한 함수에서 실제로 사용하는 함수로 상수는 넘겨줌.

6. 객체와 자료 구조

아무 생각 없이 조회/설정 함수를 추가하는 방법은 나쁘다.

객체와 자료구조의 차이

객체: 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개
자료구조: 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.
ex)

public class Square {
  public Point topLeft;
  public double side;
}

public class Rectangle {
  public Point topLeft;
  public double height;
  public double width;
}

절차 지향 프로그래밍 vs 객체 지향 프로그래밍

//절차 지향 프로그래밍
public class Geometry {
  public double area(Object shape) throws NoSuchShapeException 
  {
    if (shape instanceof Square) {
      ...
    }
    else if (shape instanceof Rectangle) {
      ...
    }
    else if (shape instanceof Circle) {
      ...
    }
    throw new NoSuchShapeException();
  }
}
// area 말고 다양한 함수가 정의되어 있을 것인데, 만약 새로운 도형이 추가되게 된다면, 모든 함수를 다 수정해줘야함!

// 객체 지향 프로그래밍
public class Square implements Shape {
  private Point topleft;
  private double side;
  
  public double area() {
    ...
  }
}

public class Rectangle implements Shape {
  private Point topLeft;
  private double height;
  private double width;
  
  public double area() {
    ...
  }
}
// 새 도형을 추가하게 되었을 때, 기존 함수들은 아무런 영향을 미치지 않지만, 새 함수를 추가하고 싶다면, 모든 도형 클래스를 일일이 수정해줘야한다.

때로는 단순한 자료 구조와 절차적인 코드가 가장 적합한 상황도 있다

디미터 법칙

클래스 c의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다

  • 클래스C
  • f가 생성한 객체
  • f 인수로 넘어온 객체
  • C 인스턴스 변수에 저장된 객체
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
//<- 기차 충돌 아래와 같이 수정해야한다.
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
// 디미터 법칙 위반 여부는 ctx, opts, scratchDir이 객체인지 자료 구조인지에 달렸다.
// 객체인 경우 내부 구조를 숨겨야 하므로 디미터 법칙을 위반. 자료구조라면, 당연히 내부 구조를 노출 <- ?

절반은 객체, 절반은 자료 구조인 잡종구조는, 새로운 함수를 추가하기도, 새로운 자료 구조를 추가하기도 어렵다.

자료 전달 객체(DTO)와 활성 레코드? 그리고 Bean?

7. 오류 처리

오류 코드보다 예외를 사용하라

오류 코드를 사용하게 되었을 때, 호출자 코드가 복잡해지고, 호출한 즉시 오류를 확인해야함.
예외를 사용하는 측면이 훨씬 더 깔끔함.

Try-Catch-Finally 문부터 작성하라

미확인 예외를 사용

확인된 예외는 OCP를 위반한다.
하위 단계에서 코드를 변경하게 되었을 때, 만약 새로운 예외가 추가된다면, 상위 단계의 모든 선언부를 수정해야한다.

예외에 의미를 제공하라

모든 예외에 호출 스택을 제공하지만, 부족하며, 오류 메세지에 정보를 담아 예외와 함꼐 던진다.

호출자를 고려해 예외 클래스를 정의하라

컴포넌트, 유형 등으로 분류가 가능함.
외부 라이브러리가 던지는 예외를 일일이 예외 처리를 하는 것은 바람직하지 않다. 코드의 중복 또한 심하다. 대부분의 예외처리 방식은 비슷(오류를 기록, 프로그램을 계속 수행해도 좋은지 확인)하기 때문에, 코드를 간결하게 고쳐야한다.
API를 감싸서, 예외 유형 하나를 반환하면 된다.
이렇게 함으로써 외부 라이브러리의 의존성을 줄일 수 있으며, 외부 라이브러리 설계 방식에 발목 잡히지 않게 된다.

특수 사례 패턴

클래스를 만들거나 객체를 조작해 특수 사례를 처리하는 방식이다. 예외처리 방식을 클래스나 객체가 캡슐화하여 처리

null을 반환하지 마라, 전달하지 마라

null을 매번 확인해야 하는 코드는 바람직하지 않으며, null 확인을 안했을 때, 발생할 수 있는 위험성을 담보하게된다. 위의 특수 사례 패턴을 이용하여 처리해라.

몰랐던 사실
예외를 발생시키는 키워드 throw와 예를 메서드에 선언할 때 쓰이는 throws를 잘 구별하자
자바에서는 메서드를 작성할 때 메서드 내에서 발생할 가능성이 있는 예외를 메서드의 선언부에 명시하여 이 메서드를 사용하는 쪽에서는 이에 대한 처리를 하도록 강요
출처: https://devbox.tistory.com/entry/Java-예외-던지기

profile
The Process

0개의 댓글