본문 바로가기

책/CleanCode

✨ Clean Code 6장: 객체와 자료구조

📌 자료 추상화

아래 두 코드는 2차원 점을 표현했다. 두 번째 코드는 인터페이스로 자료 구조를 명백하게 표현한다. 첫 번째 코드는 변수를 private로 선언하더라도 값마다 get/set 함수를 제공한다면 구현을 외부로 노출시키는 것은 마찬가지다. 따라서 추상 인터페이스를 제공하여 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 의미를 가지는 클래스를 나타낼 수 있다. 즉 개발자는 객체의 자료를 표현할 가장 좋은 방법을 신중하게 고민해야 한다. 생각 없이 get/set 함수를 추가하면 안 된다.

public class Point {
  public double x;
  public double y;
}
public interface Point {
    double getX();
    double getY();
    void setCartesian(double x, double y);
    double getR();
    double getTheta();
    void setPolar(double r, double theta);
}

📌 자료/객체 비대칭

  • 객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.
  • 자료 구조는 자료 그대로 공개하여 별다른 함수를 제공하지 않아야 한다.
  • 객체 지향 코드에서 어려운 변경은 절차적인 코드에서 쉽고, 절차적인 코드에 어려운 변경은 객체 지향 코드에서 쉽다. 

📌 디미터 법칙

디미터 법칙은 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙을 말한다. 디미터 법칙은 클래스 C의 메서드 F는 다음과 같은 객체의 메서드만 호출해야 한다.

  • 클래스 C
  • f가 생성한 객체
  • f가 인수로 넘어온 객체
  • C 인스턴스 변수에 저장된 객체

아래 코드는 디미터 법칙을 어기는 코드이다. 해당 코드를 한 줄로 이어진 기차처럼 보이는 기차 충돌(train wreck)이라 부른다.

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

 

위 코드는 일반적으로 조잡해 보여 지양해야 하며, 아래와 같이 나누는 것이 낫다. ctxt객체가 Options를 포함하고, Options가 ScratchDir을 포함하며, ScratchDir이 AbsolutePath를 포함한다는 사실을 알 수 있다. 이렇게 했다고 해서 디미터 법칙을 어기지 않는다고 할 순 없다. 객체인지 자료 구조인지에 따라 달라질 수 있다. 객체라면 내부 구조를 숨겨야 하니 디미터 법칙을 위반한다. 하지만 자료 구조라면 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();

 

그렇다면 매번 내부를 들여봐야 할까? 생각이 들 수 있다. 위 코드에선 get 함수를 사용해서 혼동이 올 수 있지만 자료 구조는 함수 없이 공개 변수만 포함한다면 아래와 같은 코드를 사용해야 할 것이다. 그렇다면 객체인지 자료 구조인지 쉽게 판별할 수 있다.

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

 

여기서 문제는 절반은 객체이고, 절반은 자료 구조인 잡종 구조가 되지 않도록 주의해야 한다. 양쪽 단점을 모아놓은 구조를 만들 수 있기 때문이다. 따라서 중요한 기능을 수행하는 함수도 있고, 공개 변수나 공개 get/set 함수가 있는 것을 피해야 한다. 

📌 자료 전달 객체(DTO)

변수만 가지고 별다른 함수가 없는 형태의 객체를 자료 전달 객체(DTO)라고 한다. 사용자에게 받은 메시지나 레이어 간에 데이터를 전달하기 위해 사용한다. DTO 하면 꼭 따라다니는 것이 VO(Value Object)이다. VO는 데이터 그 자체를 의미하는데 이 둘의 차이점에 대해 알아보는 것을 추천한다. (영상)

public class Address {
    private String street;
    private String streetExtra;
    ...
    
    public Address(String street, String streetExtra, ...) {
    	this.street = street;
        this.streetExtra = streetExtra;
        ...
    }
    
    public String getStreet() {
    	return street;
    }
    
    public String getStreetExtra() {
    	return streetExtra;
    }
    
    ...
}

' > CleanCode' 카테고리의 다른 글

✨ Clean Code 9장: 단위 테스트  (0) 2021.01.31
✨ Clean Code 7장: 오류 처리  (0) 2021.01.21
✨ Clean Code 5장: 형식 맞추기  (0) 2021.01.14
✨ Clean Code 3장: 함수  (0) 2020.12.15
✨ Clean Code 2장: 의미 있는 이름  (0) 2020.11.23