티스토리 뷰

코드 리팩토링

Chapter3. Claass

lkh's 2020. 2. 8. 17:55

Class Should be Small!


SRP(단일책임원칙)는 한번쯤 들어봤을 것이다. 클래스는 수행해야할 하나의 책임만을 가져야 한다. 책임이라는 것은 유사한 목적을 가진 기능들의 집합이라고 할 수 있다.

내가 생성한 클래스가 여러 책임을 가진 마구니가 낀 클래스인지? 하나의 책임만을 가진 클래스인지 확인하는 방법은 클래스의 이름을 보면 알 수 있다.

클래스의 이름이 간결하고, 클래스의 인스턴스 멤버와 메소드들이 클래스의 이름과 관련이 있는지 보면 알 수 있다.

클래스의 이름은 클래스의 크기와 책임, 그리고 향후 클래스의 운명을 결정짓는 중요한 역할을 수행한다.

클래스의 이름이 모호할 수록 클래스가 많은 책임을 갖게 된다. 그리고 향후 유지보수를 하는 과정에서 이름이 모호한 클래스에 많은 메소드들과 책임들이 부가될 것이다.

그리고 깨진 유리창의 법칙처럼 빠른 속도로 클래스가 변질 될 것이다. 예를들어, 이미지업로드와 관련된 기능을 가진 클래스를 ImageUtil 이라는 이름으로 명명한다면, 

이 클래스는 처음에는 이미지 업로드와 관련된 메소드만 있겠지만 시간이 지나면  이미지 리사이징, 이미지 크기 확인, 이미지 확장자 확인 ... 등 이미지와 관련된 모든 메소드들이 

구현될 것이다. 내가 그러한 것을 봤고, 그러하게 구현한 경험도 있다. 특히, Processor, Manager 와 같은 키워드가 포함되면 모호하고 여러 책임을 가질 수 있는 가능성이 있기 

때문에 사용하지 않는 것을 권장한다.


The Single Responsibility Principle


클래스가 하나의 책임을 가진다는 것은, 클래스가 변하는 이유가 오직 한가지라는 것을 의미한다. 이 부분이 정말 이해가 되지 않았지만, 아래 예제를 보고 이해가 되었다.

첫번째 코드를 보면 잘 만든 클래스라 할 수 있을까? SQL 관련된 로직만 모여있는 SQL이라는 하나의 책임을 가지고 있는 클래스라 생각할 수 있다.

그러나 첫번째 코드는 하나의 책임만을 가진 클래스라 할 수 없다. 책임이라는 것은 변하는 이유가 오직 하나라고 했다.

아래 클래스는 두가지의 변화 이유를 가지고 있다.

  1. 새로운 SQL 쿼리가 추가된다.

  2. SQL 쿼리 내용이 변경된다. 

이러한 이유로, 이 클래스는 하나의 책임만을 가지고 있을 수 없다. 이 클래스를 두번째 코드로 변경한다면 어떤 이점이 있을까?
두번째 코드는 새로운 SQL 쿼리가 추가되면 새로운 클래스를 생성하면 된다. 변하는 이유는 오직 쿼리의 내용이 변경되는 한가지 이유이기 때문에 하나의 책임을 가질 수 있다고
할 수 있다. 그리고 새로운 쿼리가 추가될때, 첫번째 코드는 클래스에 계속해서 덧붙여야 한다. 확장이 발생했을 때, 기존 코드의 변화가 발생한다. 
확장에는 열려있고, 변화에는 닫혀있어야하는 OCP 원칙에 맞지 않는다. 그러나 두번째 코드에서 새로운 쿼리의 생성은 새로운 클래스를 생성하면 되기 때문에 기존 코드에 대한 변경이
전혀 없다. 그리고 클래스의 내용을 일일이 확인하지 않아도 클래스의 이름만 보고 역할을 명확하게 파악할 수 있다. 

public class sql {
 public Sql(String table, Column[] columns);
 public String create();
 public String findByKey(String key, String value);
 public String selectWithCreteria(String creteria)
}
abstract public class Sql {
 public Sql(String table, Column[] columns);
 abstract public String generate();
}

public class CreateSql extends Sql [
 public CreateSql(String table, String [] columns)
 @Override public String generate();
}

public class FindByKeySql extends Sql [
 public FindByKeySql(String table, String [] columns, String key, String value)
 @Override public String generate();
}


Maintaining Cohesion Result in Many Small Classes


클래스는 소수의 인스턴스 필드만을 가져야 한다. 마치 메소드의 파라미터의 수가 2개 이하가 가장 적합한 것처럼 말이다. 그렇다고 인스턴스 필드가 2개이어야만 한다는 것은 아니다.

그리고 클래스의 메소드는 하나 이상의 인스턴스 필드를 사용해야만 한다. 굳이 왜 그래야지? 라는 의문을 가질 수 있다.

클래스의 인스턴스 필드는 클래스와 연관된 요소들이다. 메소드가 그러한 클래스의 인스턴스 필드를 사용하지 않는다는 것은 해당 메소드가 클래스와의 연관성이 적다고 의심해야 한다.

연관성이 적다는 것은 응집도가 낮다고 볼 수 있다. 응집도가 낮은 메소드들이 있다는 것은 해당 클래스가 하나 이상의 책임을 가지고 있을 수 있다.

그러할 경우는, 의심해보고, 다른 클래스로 분리해봐라.


클래스는 작게 유지하려고 하다보면, 클래스의 수가 많아지는 것은 당연하다. 클래스가 많으면 코드를 분석하는 것이 어렵지 않을까? 코드를 분석하기 위해서 여러 클래스를 계속 

탐색하면 불편하지 않을까? 가독성이 떨어지지 않을까? 의심이 된다. 그런데 클래스의 책임이 명확하다면, 클래스의 코드들을 모두 분석하지 않아도 해당 클래스의 역할을 쉽게

파악하고 코드를 분석할 수 있을 것이다. 코드를 읽는 것은 신문을 읽는 것과 똑같다. 우리가 신문을 읽을 때 신문의 모든 기사의 내용은 읽지는 않는다.

헤더라인만 보고, 관심있는 기사만을 자세히 읽어본다. 코드도 마찬가지이다. 클래스라는 큰 제목과 메소드라는 작은 제목을 쉽게 읽고 이해한다면 전체 코드를 분석하는데

많은 도움이 될 것이라고 생각한다.


'코드 리팩토링' 카테고리의 다른 글

Humble Object Pattern  (0) 2020.07.19
Chapter2. Function (2)  (0) 2020.01.27
Chapter2. Function (1)  (0) 2020.01.26
Chapter1. 의미있는 변수 사용  (0) 2020.01.08
생성자의 인자가 많을 때 빌더 패턴  (0) 2019.01.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함