포스트

[Clean Code][TIL] 클래스

이 포스트는 로버트 C.마틴의 Clean Code 속 10장(172p ~ 191p) 내용에 대한 정리입니다.


“클래스를 설계할 때도, 함수와 마찬가지로, ‘작게’가 기본 규칙이라는 의미다.” (10장 172p)


작은 클래스

클래스는 깨끗한 함수처럼 물리적인 행 수로 크기를 제한하는 것이 아니라
함수가 한 가지 일을 잘 하는 것처럼 클래스도 한 가지 일을 잘 한다면
단일 책임 원칙(Single Responsibility Principle) 에 의해 적절한 클래스 크기를 유지할 수 있습니다.

따라서 클래스의 구조는 이름부터 역할이 명확하게 드러나야 합니다.
작명할 때는 “if”, “and”, “-“, “or”, “buf” 을 사용하지 않고 25글자 이내로 작성하는 것이 바람직합니다.
또한 Processor, Manager, Super 와 같은 단어가 들어갔다면
해당 클래스의 책임은 여러 책임을 떠안겼다는 증거입니다.
마지막으로 클래스의 특징 중 하나인 캡슐화를 지켜 변수 혹은 함수를 최대한 숨기는 것이 좋습니다.

응집도

클래스는 인스턴스 변수의 수가 적어야 합니다.
각 클래스 메서드는 클래스 인스턴스 변수를 하나 이상 사용해야 하며,
많이 사용할수록 메서드와 클래스의 응집도가 높습니다.
응집도가 높은 클래스는 메서드와 변수가 서로 의존하며
논리적인 단위로 묶인다는 장점을 갖고 있기 떄문입니다.

만약 클래스 속 몇몇 메서드만 사용하는 인스턴스 변수가 많다면
이는 새로운 클래스로 쪼개야 한다는 신호로 응집도가 높아지도록 변수와 메서드를 적절히 분리해줘야 합니다.

변경하기 쉬운 클래스

깨끗한 코드를 유지하기 위해서는 꾸준한 유지 보수가 필요합니다.
변수의 이름이 변경되거나 함수의 역할이 분할될 수 있고 새로운 알고리즘이 적용될 수 있습니다.
따라서 클래스 또한 체계적으로 정리하여 변경이 필요할 때 수반하는 위험을 찾워야 합니다.

1
2
3
4
5
6
7
8
9
class Sql {
public:
    Sql(string bable, Column* columns);
    string create();
    string insert(vector<FIELD> fields);
    string selectAll();
    string findByKey(string keyColumn, string value);
    //...
}


위 클래스는 Sql의 여러 명령어를 실행하는 클래스입니다.
완성된 클래스가 아니라 update 문, select 문 등 여러 기능이 추가되어야 합니다.
이때, 클래스를 직접 수정하기 때문에 다른 코드를 망가뜨릴 잠재적인 위험이 존재합니다.
그리고 기존 메서드를 수정할 때에도 동일하게 문제가 됩니다.
결국 클래스를 변경해햐 하는 이유가 2가지 이상이므로 이는 단일 책임 원칙을 위반합니다.

이 문제를 해결하기 위해 클래스의 상속을 이용해 아래의 코드처럼 개선할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Sql {
public:
    Sql(string table, Column* columns);
}

class CreateSql : public Sql {
public:
    CreateSql();
}

class InsertSql : public Sql {
public:
     string insert(vector<FIELD> fields);
}


위의 클래스처럼 수정하게 되면 각 클래스는 극도로 단순해지고 가독성 또한 증가합니다.
또한 메서드 하나를 수정하면 다른 메서드가 영향받을 위험이 낮아졌으며
새로운 기능을 구현하려고 하면 Sql 혹은 해당하는 클래스를 상속받아 구현할 수 있습니다.

위 코드는 객체 지향 설계의 핵심 중 하나인 개방 폐쇠 원칙 (Open-Closed Principle)도 지원합니다.
이 원칙은 확장에 개방적이고 수정에 폐쇄적이어야 한다 라는 원칙으로
클래스 상속을 통해 기능 확장에는 개방적이지만 동시에
다른 클래스를 닫아놓는 방식으로 수정에는 폐쇄적이기 떄문입니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.