Study/CleanCode

[클린코드] 6장. 객체와 자료 구조

Wonol 2023. 10. 25. 13:15
반응형

클린코드(CleanCode)를 읽고 간략하게 정리한 글입니다.


6장. 객체와 자료 구조

- 변수를 Private(비공개)로 정의하는 이유는 남들이 변수에 의존하지 않게 만들고 싶어서이다.

- 충동이든 변덕이든, 변수 타입이나 구현을 맘대로 바꾸고 싶어서다.

- 대부분 프로그래머들은 조회(get), 설정(set) 함수를 당연하게 Public(공개)으로 공개한다.

1. 자료 추상화

public class Point1 {
    public double x;
    public double y;
}

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

- 구현을 감추기 위해서는 추상화가 필요하다.

- 변수를 Private로 선언하더라도 각 값마다 조회(get) 함수와 설정(set) 함수를 제공한다면 구현을 외부로 노출이 된다.

- 변수 사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지지 않는다.

- 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 의미의 클래스(Class)이다.

2. 자료/객체 비대칭

- 객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.

- 자료 구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.


절차적인 코드는 기본 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다.
객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.

절차적인 코드는 새로운 자료구조를 추가하기 어렵다. 모든 함수를 고쳐야 한다.
객체 지향 코드는 새로운 함수를 추가하기 어렵다. 모든 클래스를 고쳐야 한다.

- 다시 말해, 객체 지향 코드에서 어려운 변경은 절차적인 코드에서 쉬우며, 절차적인 코드에서 어려운 변경은 객체 지향 코드에서 쉽다.

- 때로는 단순한 자료구조와 절차적인 코드가 가장 적합한 상황도 있다.

3. 디미터 법칙

- 디미터 법칙은 잘 알려진 휴리스틱으로, 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙이다.

- 객체는 자료를 숨기고 함수를 공개한다.

- 객체는 조회 함수로 내부 구조를 공개하면 안 된다는 의미이다.

3-1. 기차 충돌

  • 나쁜 코드1
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

- 위와 같은 코드를 기차 충돌이라 한다.

- 여러 객체가 한 줄로 이어진 기차처럼 보이기 때문이다.

  • 나쁜 코드2
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();

- 위 코드가 디미터 법칙을 위반하는지는 ctxt, Options, ScratchDir 이 객체인지 자료구조인지에 달렸다.

- 객체라면 내부 구조를 숨겨야 하므로 확실히 디미터 법칙을 위반한 것이고, 자료 구조라면 당연히 내부 구조를 노출하므로 디미터 법칙이 적용되지 않는다.

  • 좋은 코드
final String outputDir = ctxt.options.scratchDir.absolutePath;

- 자료구조는 무조건 함수 없이 공개 변수만 포함하고 객체는 비공개 변수와 공개 함수를 포함한다면 문제는 훨씬 간단해진다.

3-2. 잡종 구조

- 이러한 혼란으로 말미암아 때때로 절반은 객체, 절반은 자료구조인 잡종 구조가 나온다.

- 잡종 구조는 중요한 기능을 수행하는 함수도 있고, 공개 변수나 공개 조회/설정 함수도 있다.

- 이러한 잡종 구조는 새로운 함수는 물론이고 새로운 자료구조도 추가하기 어렵다.

3-3. 구조체 감추기

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

- ctxt, options, scratchDir 이 객체라면 함수 내에서 줄줄이 사탕으로 호출해서는 안된다.

// ctxt 객체에 공개해야 하는 메서드가 너무 많다.
ctxt.getAbsolutePathOfScratchDirectoryOption();

// ctxt가 객체라면 뭔가를 하라고 해야 하는데
// getScratchDirectoryOption()에서 속을 드러내라고 말하는 느낌이다.
ctxt.getScratchDirectoryOption().getAbsolutePath()

// ctxt 객체에게 임시 파일을 생성하라고 시킨다.
// ctxt는 내부 구조를 드러내지 않으며, 모듈에서 해당 함수는 여러 객체를 탐색할 필요가 없다.
// 디미터 법칙 충족
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);

4. 자료 전달 객체

- 자료 구조체의 전형적인 형태는 공개 변수만 있고 함수가 없는 클래스이다.

- 이런 자료 구조체를 자료 전달 객체(Data Transfer Object, DTO)라 한다.

- DTO는 여러모로 유용한 구조체이다.

  • 데이터베이스와 통신하거나 소켓에서 받은 메시지의 구문을 분석할 때 유용하다.
  • 가공되지 않은 정보를 애플리케이션 코드에서 사용할 객체로 변환하는 일련의 단계에서 처음 사용하는 구조체

4-1. 활성 레코드

- 활성 레코드는 DTO의 특수한 형태이다.

- 공개 변수가 있거나 비공개 변수에 조회/설정 함수가 있는 자료 구조이지만 대개 save나 find와 같은 탐색 함수도 제공한다.

- 종종 활성 레코드에 비즈니스 규칙 메서드를 추가해 객체로 취급하는 경우가 있는데 이는 바람직하지 않다. -> 잡종 구조

- 비즈니스 규칙을 담는 객체는 따로 생성하는 것이 옳다.

- 내부 자료는 활성 레코드의 인스턴스 일 가능성이 높다.

5. 결론

- 객체는 동작을 공개하고 자료를 숨긴다. 기본 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면, 기존 객체에 새 동작을 추가하기는 어렵다.

- 자료 구조는 별다른 동작 없이 자료를 노출한다. 기존 자료 구조에 새 동작을 추가하기는 쉬우나, 기존 함수에 새 자료구조를 추가하기는 어렵다.

- 어떤 시스템을 구현할 때, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적합하다.

- 다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.

- 중요한 것은 편견 없이 직면한 문제에 최적인 해결책을 선택해야 하는 것이다.

반응형