깨끗한 코드와 오류 처리는 확실히 연관성이 있다. 오류 처리는 중요하지만 오류 처리 코드로 인해 프로그램 논리를 이해하기 어려워진다면 깨끗한 코드라 부르기 어렵다.
오류가 발생하면 예외를 던지는게 호출자 코드가 더 깔끔해진다!
public class DeviceController {
...
public void sendShutDown() {
try {
tryToShutDown();
} catch (DeviceShutDownError e) {
logger.log(e);
}
}
private void tryToShutDown() throws DeviceShutDownError {
DeviceHandler handler = getHandle(DEV1);
DeviceRecord record = retrieveDeviceRecord(handle);
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDeivce(handle);
}
private DeviceHandler getHandler(DeviceID id) {
...
throw new DeviceShutDownError("Invalid handle for: " + id.toString());
}
}
예외에서 프로그램 안에다 범위를 정의한다는 사실은 매우 흥미롭다. try 블록에서 무슨 일이 생기든지 catch 블록은 프로그램 상태를 일관성 있게 유지해야 한다.
예외가 발생할 코드를 짤 때는 try-catch-finally문으로 시작하는 편이 낫다. 그러면 try 블록에서 무슨 일이 생기든지 호출자가 기대하는 상태를 정의하기 쉬워진다.
확인된 예외는 OCP (Open Closed Principle)를 위반한다. 메서드에서 확인된 예외를 던졌는데 catch 블록이 세 단계 위에 있다면 그 사이 메서드 모두가 선언부에 해당 예외를 정의해야 한다. 즉 하위 단계에서 코드를 변경하면 상위 단계 메서드 선언부를 전부 고쳐야 한다는 말이다.
최하위 함수를 변경해 새로운 오류를 던진다고 가정하면 변경한 함수를 호출하는 함수 모두가 1) catch 블록에서 새로운 예외를 처리하거나 2) 선언부에 throw 절을 추가해야 한다!
이렇게 되면 확인된 예외가 캡슐화를 깨버리게 된다
null을 반환하는 코드는 일거리를 늘릴 뿐만 아니라 호출자에게 문제를 떠넘긴다.
패키지 제공자나 프레임워크 제공자는 적용성을 최대한 넓히려 애쓴다. 반면 사용자는 자신의 요구에 집중하는 인터페이스를 바란다. 이런 긴장으로 인해 시스템 경계에서 문제가 생길 소지가 많다.
예) java.util.Map
Map은 다양한 인터페이스로 수많은 기능을 제공한다. Map이 제공하는 기능성과 유연성은 확실히 유용하지만 그만큼 위험도 크다.
Map<String, Sensor> sensors = new HashMap<Senser>();
Sensor s = sensers.get(sensorId);
프로그램에서 Map<String,Sensor> 인스턴스를 여기저기로 넘긴다면, Map 인터페이스가 변할 경우, 수정할 코드가 상당히 많아진다.
public class Sensors {
private Map sensors = new HashMap();
public Sensor getById(String id) {
return (Sensor) sensors.get(id);
}
...
}
해결하기 위해 Map을 Sensors안으로 숨겼다. Sensors 클래스 안에서 객체 유형을 관리하고 변환하기 때문에 Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않는다.
Map 인스턴스를 공개 API의 인수로 넘기거나 반환값으로 사용하지 않아야한다.
우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히는 것을 학습 테스트라고 한다.
학습 테스트는 패키지가 예상대로 도는지 검증한다. 새 버전이 우리 코드와 호환되지 않으면 학습 테스트가 이 사실을 곧바로 밝혀낸다. 학습 테스트를 이용한 학습이 필요하든 그렇지 않든, 실제 코드와 동일한 방식으로 인터페이스를 사용하는 테스트 케이스가 필요하다. 이런 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워진다.
❗ 출처
📖 클린코드 - 로버트 C. 마틴 저자