Clean Code 스터디 내용 정리; 10장 클래스
이번 장에서는 깨끗한 클래스에 대해 이야기한다.
기본 클래스 체계
표준 자바 관례
public static 변수 -> private static 변수 -> private 인스턴스 변수 -> public 함수 -> private 함수
- 이때 private 함수는 자신을 호출하는 공개 함수 직후에 넣는다. 즉, 추상화 단계가 순차적으로 내려간다.
- 변수와 유틸리티 함수는 최대한 비공개로 유지하려고 노력하되, 때에 따라 protected로 테스트 코드의 접근을 허용한다.
깨끗한 클래스를 만들려면?
1. 단일 책임 원칙 (Single Responsibility Principle, SRP)
클래스는
하나의 책임
을 맡게 하여 클래스를 변경하는 이유를 단 하나로 만들고, 클래스 이름은 해당 클래스 책임을 기술하게 한다.
큰 클래스가 있다면
응집도가 높아지도록
변수와 메서드를 적절히 분리해 작은 클래스 여러 개로 쪼개주는 것이 좋다.
일반적으로
메서드가 변수를 더 많이 사용할수록
메서드와 클래스의 응집도가 높다.
큰 함수를 작은 함수 여러 개로 쪼개고, 몇몇 함수만 사용하는 인스턴스 변수가 늘어나 응집도가 낮아졌다면 클래스를 쪼개라.
// 메서드 수는 적지만 책임이 너무 많은 클래스
public class SuperDashboard extends JFrame implements MetaDataUser {
public Component getLastFocusedComponent()
public void setLastFocused(Component lastFocused)
public int getMajorVersionNumber()
public int getMinorVersionNumber()
public int getBuildNumber()
}
// 위의 클래스에서 버전 정보만을 다루는 메소드를 빼내 독자적인 클래스로 만들어 재사용이 쉽게 만든다.
public class Version {
public int getMajorVersionNumber()
public int getMinorVersionNumber()
public int getBuildNumber()
}
2. 개방-폐쇄 원칙 (Open-Closed Principle, OCP)
수정사항이 생겼을 때 클래스에 손대어 고쳐야 한다면 다른 코드까지 망가뜨릴 위험이 있다. 새 기능을 수정하거나 기존 기능을 변경할 때 건드릴 코드가 최소인 시스템 구조가 바람직하다.
따라서 수정 시에는 파생 클래스를 생성하는 방식을 취하여 새 기능에는 개방적이되 다른 클래스의 수정에는 폐쇄적이어야 한다.
// 새로운 SQL문을 지원하려면 반드시 Sql 클래스에 손대야 하는 구조.
public class Sql {
public Sql(String table, Column[] columns)
public String create()
public String insert(Object[] fields)
public String selectAll()
public String findByKey(String keyColumn, String keyValue)
private String valuesList(Object[] fields, final Column[] columns)
}
// SRP와 OCP를 지원하는 클래스로 수정한 결과
// 새로운 SQL문을 지원하려면 Sql 클래스를 상속하는 새 클래스를 만들면 됨.
abstract public class Sql {
public Sql(String table, Column[] columns)
abstract public String generate();
}
public class CreateSql extends Sql {
public CreateSql(String table, Column[] columns)
@Override public String generate()
}
public class SelectSql extends Sql {
public SelectSql(String table, Column[] columns)
@Override public String generate()
}
public class InsertSql extends Sql {
public InsertSql(String table, Column[] columns, Object[] fields)
@Override public String generate()
private String valuesList(Object[] fields, final Columns[] columns)
}
public class FindByKeySql extends Sql {
public FindByKeySql(String table, Column[] columns, String keyColumn, String keyValue)
@Override public String generate()
}
3. 의존관계 역전 원칙 (Dependency Inversion Principle, DIP)
상세한 구현에 의존하는 클라이언트 클래스는 구현이 바뀌면 위험해진다.
상세한 구현에 의존하는 코드는 테스트하기 어려우므로, 인터페이스와 추상 클래스를 사용해 테스트가 가능할 정도로 시스템의 결합도를 낮추고 클래스가 상세한 구현이 아니라 추상화에 의존하게 만든다.
시스템의 결합도를 낮추어서 클래스가 추상화에 의존하게 만들면 각 시스템 요소가 다른 요소와 변경으로부터 잘 격리되어서 각 요소를 이해하기가 더 쉬워진다.
자바프로그래밍및실습 과목을 들을 때 배웠던 원칙들이 나와서 반가웠다. 책에 수록된 예시를 읽으면서, 학교 수업에서 이론으로 배웠던 걸 실제로 적용해야 할 필요를 느낄 수 있었다.
저자는 이번 장에서 소프트웨어를 돌아가게 만드는 것과 소프트웨어를 깨끗하게 만드는 건 완전히 별개의 활동
이며, 한 번에 두 활동을 하기에는 두뇌 용량에 한계가 있을 수밖에 없다고 말하였다. 우선 프로그램을 돌아가게 만드는 것에 관심을 가지고, 프로그램이 돌아가면 그 이후에는 '깨끗하고 체계적인 소프트웨어'를 만드는 것에 주목해야 한다
고 조언하였다.
관심사를 분리하여 우선 코드가 돌아가게 만들고, 그 후에 리팩토링에 힘쓰는 과정이 TDD 그 자체라는 생각이 들었다. 작은 프로젝트에서도 TDD를 실천하도록 노력해야겠다.
'STUDY > Books' 카테고리의 다른 글
[Clean Code] 12장 창발성 (0) | 2021.06.05 |
---|---|
[Clean Code] 11장 시스템 (0) | 2021.06.04 |
[Clean Code] 9장 단위 테스트 (0) | 2021.05.25 |
[Clean Code] 8장 경계 (0) | 2021.05.24 |
[Clean Code] 7장 오류 처리 (0) | 2021.05.23 |