클린코드

북마크 추가

5장 형식 맞추기


형식을 맞추는 목적

  • 형식을 맞추면 가독성 향상, 향상된 가독성은 유지보수와 확장성을 좋게 한다,.


형식 맞추기

    • 적절한 행 길이를 유지하라
    • 일반적으로 작은 파일이 큰 파일보다 이해하기 쉽다.
    • 대부분 200줄, 최대 500줄을 넘지않는 코드로도 대형 시스템 구축이 가능하다.

신문기사처럼 작성하라

    • 이름은 간단하면서도 설명이 가능하도록
    • 소스파일 첫 부분은 고차원 개념과 알고리즘 설명
    • 마지막은 저차원 함수와 세부 내역
    • 신문은 대다수 기사가 짧다


개념은 빈 행으로 분리하라

    • 새로운 개념이 시작될때는 빈행을 넣는다.
    • 줄 바꿈 하나로 가독성이 좋아진다.
    • 개념의 분리


세로 밀집도

    • 위와 반대되는 개념으로 밀접한 코드는 세로로 가까이 놓는다.


수직거리

    • 밀접한 개념끼리는 세로로 가까이 둔다.
    • 밀접한 개념끼리 수직거리가 멀어지면 연관 관계를 찾느라 시간과 노력이 소모된다.
    • protected 함수를 피해야 되는 이유 - 서로 밀접한 개념은 세로로 가까이 둬야 하는데 다른 파일에 속하면 규칙이 통하지 않는다.

지역변수

    • 함수내  맨 처음에 선언, 루프제어 변수의 경우 루프직전이나 블록 상단에 선언하는 경우도 있다.


인스턴스 변수

    • 클래스 맨 처음에 선언하고 변수간 세로거리를 두지 않는다. 대다수 클래스 메서드가 인스턴스 변수를 사용하기 때문
    • 하지만 모든 인스턴스 변수를 맨 마지막에 선언하는 경우도 있다(C++의 가위규칙) 
    • 잘 알려진 위치에 모으는게 중요


종속함수

    • 한 함수가 다른 함수를 호출하는 경우 세로로 가까이 배치하고 호출하는 함수를 호출되는 함수보다 먼저 배치한다.
    • 상수는 종속함수에서 직접 넣어줄 수 있지만 적절치 않은 위치이므로 상위 함수에서 실제 사용하는 함수로 넘겨서 사용하는 방식이 더 좋다


개념적 유사성

    • 개념적으로 비슷하면 가까이 배치한다.
    • 종속함수도 포함되며 변수를 공유하거나 기본 기능이 유사한 경우 포함


세로 순서

    • 종속성은 위에서 아래로 배치한다. 고차원→ 저차원


가로형식 맞추기

    • 짧은행이 바람직. 저자는 최대 가로 120자 정도를 추천


가로 공백과 밀집도

    • 연산자 사이는 공백을 넣고, 함수의 인수에는 괄호를 넣지 않는다. 인수끼리는 공백으로 구분하면 가독성이 좋아진다.
a = 1
b = 2
sum(a, b)
a + b*c


가로정렬

    • 딱히 할 필요가 없다. 변수형보다 변수명부터 읽게 되는 부작용이 있다.
requestParsingTimeLimit = 10000;
socket                          = s;


들여쓰기

    • 들여쓰기를 잘하자 - 기본


가짜범위

    • 빈 while문이나 for문 작성을 피한다.


팀규칙

    • 여러사람이 만들어도 한사람이 만든것처럼 규칙을 정해서 코딩한다.


요약

  • 가로 세로 적정한 글자수로 함수를 나누고, 나눈 함수는 위에서 아래로 읽히도록(고차원에서 저차원으로) 신문 기사처럼 작성한다.
  • 비슷한 개념은 세로로 가까이 배치하고, 코드는 문단처럼 개념과 개념사이 빈행을 넣어 구분해 준다.
  • 변수는 상단에 선언한다.
  • 들여쓰기를 잘한다.


6장 객체와 자료구조

자료 추상화

    • 자료를 세세하게 공개 하기 보다는 추상적으로 제공하는것이 좋다.

구체적

      • 기름탱크용량 반환
      • 휘발유양 반환

추상적

      • 연료잔량반환

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

절차지향

    • 함수 추가 →  도형 클래스에 영향을 미치지 않는다.
    • 도형 클래스 추가 → 함수 전부 고쳐야 된다.

객체지향

    • 도형 추가 → 함수에 영향을 미치지 않는다.
    • 함수 추가 → 도형클래스 전부 고쳐야 된다.

  • 객제지향과 절차지향은 서로 반대개념이다.
  • 개발하다보면 객제지향이 적합한 상황도 있고 절차지향이 적합한 상황도 있다.
  • 노련한 개발자는 visitor pattern 사용하여 객체 지향의 문제점을 해결


디미터 법칙

    • 클래스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다.
      • 클래스C
      • f가 생성한 객체
      • f인수로 넘어온 객체
      • C 인스턴스 변수에 저장된 객체



class Demeter {
    private A a;
     
    public method(Object object) {
        ...
    }
     
    public okLawOfDemeter(Paramemter param) {
        method(); // 1. 객체 자신의 메서드
        param.paramMethod(); // 2. 메서드의 파라미터로 넘어온 객체들의 메서드
        Local local = new Local();
        local.localMethod(); // 3. 메서드 내부에서 생성, 초기화된 객체의 메서드
        a.aMethod(); // 4. 인스턴스 변수로 가지고 있는 객체가 소유한 메서드
    }
}


다른 객체와의 결합도를 낮추는게 목적

기차충돌

    • Demeter 법칙 위배


final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

getOptions함수가 반환하는 객체의 getScratchDir함수를 호출한후 함수가 반환하는 객체의 getAbsoultePath함수를 호출

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
Final String outputDir = scratchDir.getAbsoultePath();

위와 같이 바꾸는 경우 객체라면 내부구조를 숨겨야 하므로 디미터 법칙 위반

      • 자료구조라면 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.


final String outputDir = ctxt.options.scratchDir.absolutePath;

자료구조는 공개 변수만 포함하고 객체는 비공개 변수와 공개 함수만 포함하면 간단하지만 bean처럼 자료 구조에도 조회 함수와 설정함수를 정의하라 요구하라는 프레임워크가 존재한다.


      • 위 코드가 임시파일 생성을 위해 경로를 얻는 목적이라면 아래와 같이 작성시 디미터 법칙을 위반하지 않는다.
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);

ctxt의 내부구조를 드러내지 않고 해당 함수는 모르는 여러 객체를 담을 필요가 없다.


잡종구조

    • 위와 같인 이유로 객체와 자료구조가 섞인 잡종 구조가 나온다.
    • 함수나 자료구조를 추가하기 어려우므로 피한다.


자료 전달 객체

    • DTO(Data Transfer Object)
    • 보통 DB에 저장된 가공되지 않은 정보를 객체로 변환하기 위해 사용
    • DTO의 일반적인 형태는 bean이며 private 변수를 getter, setter로 조작하는 방식이다. 다만 이는 구현이 노출되는 방식이므로 진정한 객체지향이 아님 


활성레코드(Active Record)

    • DTO의 특수한 형태
    • 공개 변수가 있거나 비공개 변수에 조회/설정 함수가 있는 자료 구조
    • save나 find 같은 탐색 함수도 제공한다.
    • 활성레코드는 DB의 테이블이나 다른 소스에서 자료를 직접 변환한 결과
    • hibernate 같은 ORM툴에서 많이 사용


public class Employee extends ActiveRecord {
  private String name;
  private String address;
  ...
}
 
 
Employee bob = Employee.findByName("Bob Martin");
 
 
bob.setName("Robert C. Martin");
bob.save();




요약

  • 자료구조나 객체지향은 상황에 따라 적절히 사용한다.


7장 오류처리

  • 오류 코드보다 예외를 사용하라
  • try-catch문을 사용한다.
  • 예외처리가  발생할 코드를 짤때는 try-catch-finally문 부터 시작한다.
  • unchecked exception을 사용하라
  • 예전에는 checked exception을 사용했으나 지금은 필요치 않다. 
  • checked exception은 OCP(Open Closed Principle)을 위반한다
    • OCP 개방-폐쇄 원칙(OCP, Open-Closed Principle)은 '소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다'는 프로그래밍 원칙이다.

OCP 원칙이란

  • 메서드에 확인된 예를 던졌는데 catch 블록이 3단계 위에 있다면 중간 메서드 전부 선언부에 해당 예외를 정의해야 한다.
  • 최하위가 수정될 경우 최상위까지 코드 수정이 이루어 져야 하며 모든 함수가 최하위 예외를 알아야 하므로 캡슐화가 깨짐

Java의 exception 종류

  • Error

    • java.lang.Error의 서브 클래스 - 시스템 에러가 발생했을때 VM이 발생시킴 (OutofMemory)등 프로그래밍 레벨에서는 크게 신경쓸 필요가 없다.

  • Exception

    • checked Exception 
      • Exception의 서브 클래스이면서 RuntimeException의 서브 클래스가 아닌것들
      • 반드시 try-catch로 처리하거나 throw로 던져야됨 처리 안할시 컴파일 에러 (FileNotFoundException) 등
  • unchecked Exception
    • RuntimeException의 서브 클래스 - 명시적인 에러처리를 강제하지 않는다. 주로 개발자의 실수로 발생
    • ArithmeticException(0으로 나누기), IndexOutOfBoundsException (배열범위) 등


예외에 의미를 제공하라

    • catch에서 오류에 대해 충분한 정보를 logging 하도록 한다.


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

    • 예외를 처리하는 방식이 비슷하다면 Wrapper 클래스로 감싸 하나의 유형으로 반환한다.
    • 외부  API를 사용할때 wrapper 클래스를 사용하면 라이브러리와 프로그램간 의존성이 줄어든다.


정상 흐름을 정의하라

    • 특수 사례 패턴 - 예외적인 상황을 캡슐화 하여 처리
    • 반환값이 없다면 exception을 던지는게 아니라 기본값을 반환시킨다.

null을 반환하지 마라

    • null이 발생할 상황이라면 exception처리를 하거나 특수 사례 개체를 반환한다.
    • List에서 null 대신 empty list를 반환 한다면 코드가 깔끔해짐

null을 전달하지 마라

    • null 반환보다 null 전달이 더 나쁨
    • null에 대해 exception을 던질수도 있지만 Assert문을 사용할 수도 있다.
      • Java에서 Assert문은 JDK 1.4 부터 지원한다.
      • Java VM실행시 기본적으로 assert문은 제외되서 실행되기 때문에(-ea 옵션 필요) 예외처리 용도로 사용 부적합 
      • 사용법


assert boolean조건;
true면 패스 / false 면 assertionError 발생
assert boolean조건 : false인 경우 메세지;
AD
관리자
2021-02-17 14:40
SHARE