5장 형식 맞추기
형식을 맞추는 목적
- 형식을 맞추면 가독성 향상, 향상된 가독성은 유지보수와 확장성을 좋게 한다,.
형식 맞추기
- 적절한 행 길이를 유지하라
- 일반적으로 작은 파일이 큰 파일보다 이해하기 쉽다.
- 대부분 200줄, 최대 500줄을 넘지않는 코드로도 대형 시스템 구축이 가능하다.
신문기사처럼 작성하라
- 이름은 간단하면서도 설명이 가능하도록
- 소스파일 첫 부분은 고차원 개념과 알고리즘 설명
- 마지막은 저차원 함수와 세부 내역
- 신문은 대다수 기사가 짧다
개념은 빈 행으로 분리하라
- 새로운 개념이 시작될때는 빈행을 넣는다.
- 줄 바꿈 하나로 가독성이 좋아진다.
- 개념의 분리
세로 밀집도
- 위와 반대되는 개념으로 밀접한 코드는 세로로 가까이 놓는다.
수직거리
- 밀접한 개념끼리는 세로로 가까이 둔다.
- 밀접한 개념끼리 수직거리가 멀어지면 연관 관계를 찾느라 시간과 노력이 소모된다.
- protected 함수를 피해야 되는 이유 - 서로 밀접한 개념은 세로로 가까이 둬야 하는데 다른 파일에 속하면 규칙이 통하지 않는다.
지역변수
- 함수내 맨 처음에 선언, 루프제어 변수의 경우 루프직전이나 블록 상단에 선언하는 경우도 있다.
인스턴스 변수
- 클래스 맨 처음에 선언하고 변수간 세로거리를 두지 않는다. 대다수 클래스 메서드가 인스턴스 변수를 사용하기 때문
- 하지만 모든 인스턴스 변수를 맨 마지막에 선언하는 경우도 있다(C++의 가위규칙)
- 잘 알려진 위치에 모으는게 중요
종속함수
- 한 함수가 다른 함수를 호출하는 경우 세로로 가까이 배치하고 호출하는 함수를 호출되는 함수보다 먼저 배치한다.
- 상수는 종속함수에서 직접 넣어줄 수 있지만 적절치 않은 위치이므로 상위 함수에서 실제 사용하는 함수로 넘겨서 사용하는 방식이 더 좋다
개념적 유사성
- 개념적으로 비슷하면 가까이 배치한다.
- 종속함수도 포함되며 변수를 공유하거나 기본 기능이 유사한 경우 포함
세로 순서
- 종속성은 위에서 아래로 배치한다. 고차원→ 저차원
가로형식 맞추기
- 짧은행이 바람직. 저자는 최대 가로 120자 정도를 추천
가로 공백과 밀집도
- 연산자 사이는 공백을 넣고, 함수의 인수에는 괄호를 넣지 않는다. 인수끼리는 공백으로 구분하면 가독성이 좋아진다.
a = 1
b = 2
sum(a, b)
a + b*c
|
가로정렬
- 딱히 할 필요가 없다. 변수형보다 변수명부터 읽게 되는 부작용이 있다.
requestParsingTimeLimit = 10000;
socket = s;
|
들여쓰기
가짜범위
팀규칙
- 여러사람이 만들어도 한사람이 만든것처럼 규칙을 정해서 코딩한다.
요약
- 가로 세로 적정한 글자수로 함수를 나누고, 나눈 함수는 위에서 아래로 읽히도록(고차원에서 저차원으로) 신문 기사처럼 작성한다.
- 비슷한 개념은 세로로 가까이 배치하고, 코드는 문단처럼 개념과 개념사이 빈행을 넣어 구분해 준다.
- 변수는 상단에 선언한다.
- 들여쓰기를 잘한다.
6장 객체와 자료구조
자료 추상화
- 자료를 세세하게 공개 하기 보다는 추상적으로 제공하는것이 좋다.
구체적
추상적
- 객체는 추상화로 자료를 숨긴채 자료를 다루는 함수만 공개한다.
- 자료구조는 자료를 그대로 공개하며 별다른 함수를 제공하지 않는다.
절차지향
- 함수 추가 → 도형 클래스에 영향을 미치지 않는다.
- 도형 클래스 추가 → 함수 전부 고쳐야 된다.
객체지향
- 도형 추가 → 함수에 영향을 미치지 않는다.
- 함수 추가 → 도형클래스 전부 고쳐야 된다.
- 객제지향과 절차지향은 서로 반대개념이다.
- 개발하다보면 객제지향이 적합한 상황도 있고 절차지향이 적합한 상황도 있다.
- 노련한 개발자는 visitor pattern 사용하여 객체 지향의 문제점을 해결
디미터 법칙
- 클래스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다.
- 클래스C
- f가 생성한 객체
- f인수로 넘어온 객체
- C 인스턴스 변수에 저장된 객체
class Demeter {
private A a;
public method(Object object) {
...
}
public okLawOfDemeter(Paramemter param) {
method();
param.paramMethod();
Local local = new Local();
local.localMethod();
a.aMethod();
}
}
|
다른 객체와의 결합도를 낮추는게 목적
기차충돌
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
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 인 경우 메세지;
|