STUDY/Books

[Clean Code] 10장 클래스

hyunah 2021. 5. 30. 18:18

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