본문 바로가기

Clean code

Clean Code - 10장. 클래스

  • 클래스 이름은 클래스의 책임을 기술해야 한다.
    • 만약, 클래스 이름을 짓기가 애매하다면 내가 클래스에 너무나도 많은 기능을 넣고 있다는 것이다.
    • EX : Manager, Processor등과 같이 모호한 단어가 좋지 않은 예이다.
  • 클래스 메서드가 클래스 인스턴스 변수를 더 많이 사용하도록 짜라.
    • 단지, 인스턴스 변수가 많아야 한다는 소리가 아니다.
    • 모든 인스턴스 변수를 각 클래스 메소드마다 쓰면 좋다. => 결국 이게 응집도가 높다는 말이다.
    • 응집도를 높이려면 어떻게 해야할까?
      1. 변수가 아주 많은 큰함수를 찾아보자.
      2. 큰함수를 작은함수 단위로 쪼개보자. 그러다보면, 빼내려는 작은함수에서 변수 넷을 사용해야 한다. 인수만 많아지고 더러워지자나...
      3. 인수 X, 클래스 인스턴스 변수 O
      4. 여기까지만 보면 응집도가 낮아진다. 방금 생성한 클래스 인스턴스 변수는 일부 함수에서만 사용하기 때문이다.
      5. 그렇다면, 몇몇 함수와 몇몇 클래스 인스턴스 변수를 클래스로 분리하면 된다!
      6. 1~5번을 반복하다면, 역할에 맞는 클래스를 나눌수 있게 된다.
  • 변경하기 쉬운 클래스
    • SQL문자열을 만드는 sql 클래스이다.
    • public class Sql {

      public Sql(String table, Column[] columns);

      public String create();

      public String insert(Object[] fields);
      public String select(Column column,String pattern);
      // TODO 1.update문 지원할 경우 => Sql class 수정 필요
      // TODO 2.select문을 수정해야 할 경우 => Sql class 수정 필요
      // FIXME => 변경해야 할 이유가 두가지 이므로 SRP 위반

      private String selectWithCriteria(String criteria);
      // FIXME 일부 메소드(select문)에서만 사용되는 private 함수 = SRP 위반
      // FIXME 파생 클래스 별도 생성

      private String columnList(Column[] columns);
      private String valuesList(Object[] fields, final Column[] columns)

      - 하나만 수정해도 전체를 다시 테스트해야 되는 문제점 1
      - SRP 위반 ( 위에 주석 설명 )

    • [수정 후]

      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 InsertSql extends Sql{
      public InsertSql(String table,Column[] columns,Object[] fields)
      @Override public String generate()
      private String valuesList(Object[] fields, final Column[] columns)
      }

      public class SelectWithCriteriaSql extends Sql {
      public SelectWithCriteriaSql(String table,Column[] columns, Criteria criteria)
      @Override public String generate()
      }

- 클래스가 극도로 단순해짐 => 코드 이해하기가 쉽고, 코드 하나를 수정했다고 다른 코드가 망가지지 않음

- update SQL 문을 추가해야 하는 경우 => 다른 코드가 망가질 일이 없음
- SRP !!!

- update SQL 문을 확장하는 경우 열려 있고, 기존 SQL문은 수정할 일이 없음 => Open-closed Principle 지원 



  • 변경으로부터 격리
    • 코드는 변하기 마련이다..
    • 우리는 변경으로부터 격리시키기 위해 인터페이스를 사용한다.
    • EX : 코인 값을 받아오는 ETHTokenExchange API를 이용해서 어떤 클래스를 만든다고 가정하자. 
      • 직접 API를 사용하면 테스트 코드 짜기가 쉽지 않다. 

    • public interface TokenExchange {
      Money currentPrice(String coin);
      }

      public Portfolio {
      private TokenExchange exchange;
      public Portfolio(TokenExchange exchange){
      this.exchange = exchange;
      }
      public class PortfolioTest {
      private FixedTokenExchange exchange;
      private Portfolio portfolio;

      @Before
      protected void setUp() throws Exception {
      exchange = new FixedTokenExchange();
      exchange.fix("ETH",10000);
      portfolio = new Portfolio(exchange);
      }

      @Test
      ...
      }

- 결합도가 낮아짐 : 추상화로 실제 코인 가격을 얻어오는 출처나 얻어오는 방식 등과 같은 구체적인 사실을 모두 숨겨줌