책/클린코드 Clean Code

[클린 코드 Clean Code] 5장 - 8장 정리

keep it simple 2023. 12. 29. 00:57

5장 - 형식 맞추기

  • 코드 형식은 매우 중요하다! 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다. 
  • 신문 기사처럼 작성하라. 이름은 간단하면서도 설명이 가능하게 짓는다. 아래로 내려갈수록 의도를 세세하게 묘사한다. 
  • 명백하게 짧은 행이 가독성이 좋다. 
  • 들여쓰기를 중요시 여겨야한다. 

7장 - 오류 처리 

  • 오류 코드보다 예외를 사용해라. 
public class DeviceController{
 ...
 public void sednShutDown(){
 	DeviceHandle handle = getHandle(DEV1);
    // 디바이스 상태를 점검한다.
    if (handle != DeviceHandle.INVALID){
    	// 레코드 필드에 디바이스 상태를 저장한다.
        retrieveDeviceRecord(handle);
        // 디바이스가 일시정지 상태가 아니라면 종료한다.
        if (record.getStatus() != DEVICE_SUSPENDED){
        	puaseDevice(handle);
            clearDeviceWorkQueue(handle);
            closeDevice(handle);
        }else{
        	logger.log("Device suspended. Unable to shut down");
        }
    } else{
    	logger.log("Invalid handle for: " + DEV1.toString());
    }
 }
 ...
}

 

위와 같이 예외를 던지지 않고 오류를 체크하면 코드가 많이 복잡해진다.  밑과 같이 예외 처리하면 코드가 훨씬 가독성이 좋아지고 간결해진다. 

public class DeviceController{
 ...
 
 public void sendShutDown(){
   try{
    	tryToShutDown();
    } catch (DeviceShutDownError e) {
    	logger.log(e);
    }
 }
 
 private void tryToShutDown() throws DeviceShutDownError {
    DeviceHandle handle = getHandle(DEV1);
    DeviceRecord record = retrieveDeviceRecord(handle);
    
    puaseDevice(handle);
    clearDeviceWorkQueue(handle);
    closeDevice(handle);
 }
 
 private DeviceHandle getHandle(DeviceId id){
    throw new DeviceSHutDownError("Invalid handle for: " + id.toString());
 ...
}
  • null을 반환하지 마라. 한줄 한줄 null을 확인하는 코드는 나쁜 코드다. 호출자에게 문제를 떠넘기는 매우 나쁜 방법이다. 누구 하나라도 null확인을 빼먹는다면 어플리케이션이 통제 불능에 빠진다.

8장 - 경계

  • 외부 코드 사용 할 때는 경계해야한다. 인터페이스 제공자는 최대한 사용자를 쓰게끔하고 사용자는 최소한의 인터페이스만 사용해 집중하길 바란다. 예를 들어보자.
    • 사용자는 java.util.Map 인터페이스를 사용한다 가정하자. 해당 인터페이스는 밑과 같이 많은 기능을 지원한다.
clear() void - Map
containsKey(Object key) boolean - Map
containsValue(Object value) boolean - Map
entrySet() set - Map
equals(Object o) boolean - Map
get(Object key) Object - Map
getClass() Class<? extends Object> - Object
...



Map Sensors = new HashMap();
Sensor s = (Sensor)sensors.get(sensorId);
  • 위와같이 Map 인터페이스를 사용해서 Sensor 객체를 가져온다 치면 코드는 동작하지만 꺠끗한 코드라 보기 어렵다. 의도가 분명히 드러나지 않기 때문이다. 프로그램에서 위 인스턴스를 여기저기 넘긴다면 Map인터페이스가 변할경우 수정할 코드가 많아진다. 밑과 같이 변경하면 만약 Map인터페이스가 변경되도 나머지 프로그램에는 영향을 미치지않고 Sensors클래스만 수정하면 된다.
public class Sensors {
    private Map sensors = new HashMap();
    
    public Sensor getById(String id){
    	return (Sensor) sensors.get(id);
    }
}
  • 위의 예제에서 강조하는 부분은 여기저기 Map과 같은 인터페이스를 여기저기 넘기면 안된다. 항상 제공되는 인터페이스는 변경될 수 있음을 감안하고 변경이 되더라도 수정하기 쉽게 최대한 클래스나 클래스 계열밖으로 노출되지 않게 주의해야한다.
  • 통제가 불가능한 외부 패키지에 의존하기 보단 통제가 가능한 우리코드에 의존하는 편이 좋다. 새로운 클래스로 Map처럼 경계를 감싸거나 아니면 ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자.