클린코드 3

sdg's blog·2022년 6월 30일
0

개발 관련 독서

목록 보기
3/4

2022.06.30

객체와 자료구조

  1. 구현을 감추기 위해선 자료의 추상화가 필요하다. - 변수 사이에 함수라는 계층을 넣는다고 (getter와 setter)를 넣는다고, 구현이 감춰지는 것이 아니라, 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야한다. (ex. point class의 예시에서
  2. 자료/객체 비대칭 - 객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다. 반면, 자료구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.
  3. 절차적인 코드는 기존 자료구조를 변경하지 않으면서 새 함수를 추가하기 쉽다. 반면, 객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.
  4. 분별 있는 프로그래머는 모든 것이 객체라는 생각이 미신임을 잘 안다. 때로는 단순한 자료 구조와 절차적인 코드가 가장 적합한 상황도 있다. 각각의 장점과 단점은 서로 정반대이다.
  5. 각각이 섞인 잡종구조는 피하는 것이 좋다.
  6. 활성 레코드(DTO의 특수한 형태)에 비즈니스 규칙 메소드를 추가하여 자료 구조를 객체로 취급하는 것은 잡종 구조가 될 위험이 있다. 따라서 활성레코드의 경우 자료구조로 취급하고, 비즈니스 규칙을 담으며 내부자료를 숨기는 객체를 따로 생성한다.

오류처리

  1. 오류코드보다 예외를 사용하라. 오류 발생시 예외를 던지는(throws) 편이 좋다.
  2. Try-Catch-Finally문을 사용하라.
  3. 미확인 예외를 사용하라 (확인된 예외는 모든 예외를 사전에 처리할 수 있지만, 의존성이라는 막대한 비용이 발생한다. 연쇄적으로 throws 달아줘야하고, 캡슐화도 깨진다.)
  4. 예외에 의미를 제공하라. (호출 스택만으로는 부족한 정보를 충분히 덧붙여야함.)
  5. 호출자를 고려해 예외 클래스를 정의하라. (호출자가 모든 종류의 예외를 잡아내도록 처리하는 것보다, 호출 라이버리 API를 감싸 여러 예외유형을 처리한 한 가지 예외 유형을 반환하는 방식으로 단순화.)
  6. 정상 흐름을 정의하라 (중단이 적합하지 않을 때에는 클라인트 코드가 아닌, 클래스나 객체가 예외적인 상황을 캡슐화해서 내부적으로 처리한다.)
  7. null을 반환하거나 전달하지 마라. (null을 반환하고 이를 object != null의 식으로 확인하는 방식은 나쁘다. 대신 Collections.emptyList()등을 반환하여 null-pointer-exception이 발생할 가능을 줄이는 것이 가장 좋다.

경계

  1. 외부코드 사용하기
  • 인터페이스 제공자는 최대한 많은 사용자가 잘 사용할 수 있도록 적용성을 최대화하고, 사용자는 자신의 요구에 따라 사용해야한다.
  • java.util.Map으로 맵을 만들어 넘기면, 다른 사용자가 내 의도와는 다르게 .clear()로 데이터 전부 삭제할 수 있음. 이러한 가능성을 없애고 필요한 기능만 사용하기 위해, 클래스 안에 경계 인터페이스인 Map을 캡슐화하여 사용할 수 있다.
  1. 깨끗한 경계
  • 소프트웨어 설계가 우수하다면 변경하는데 많은 투자와 재작업이 필요하지 않다. 통제하지 못하는 외부, 경계코드를 사용할 때는 너무 많은 투자를 하거나, 향후 변경 비용이 지나치게 커지지 않게 해야한다.
  • 경계에 위치한 코드는 깔끔히 분리한다. 웬만하면 우리코드를 사용한다.

단위테스트

TDD(테스트 주도 개발)는 실제코드를 짜기 전에 단위 테스트부터 짜라고 요구한다. (실패하는 테스트 -> 코드 작성하여 성공 -> 리팩토링). 이러한 단위 테스트에 대한 클린코드 원칙.
테스트 코드는 실제 코드의 유연성 유지보수성 재사용성을 보존하고 강화하기에 매우 중요. 단위 테스트 파트는 테스트를 해볼일이 있을 때 추후 보는 것이 나을 것이라 생각해서 간략하게만 봄.

깨끗한 테스트 코드는 다음과 같은 규칙을 따른다. (First)
1. Fast : 테스트는 빨라야한다. 느리면 자주 돌릴 엄두를 못낸다. 자주 돌리지 않으면 초반에 문제 찾기 어렵다.
2. Independent : 각 테스트는 서로 의존적이면 안 되고, 독립적이어야한다.
3. Repeatable : 테스트는 어느 환경에서도 반복 가능해야한다. 어느 환경에서도 돌릴 수 있어야한다.
4. Self-Validating: 테스트는 부울 값으로 결과를 내야한다.
5. Timely : 테스트는 적시에 작성해야한다. 실제 코드보다 먼저 테스트 코드를 작성해야한다.

클래스

  1. 클래스는 체계가 있다.
  • 클래스는 체계를 가지고 있다. 정적 공개 상수 (클래스 변수) -> 정적 비공개 변수 -> 비공개 인스턴스 변수 (공개 변수는 거의 필요하지 않음) -> 변수목록 다음에는 공개 함수 -> 비공개 함수는 자신을 호출하는 공개함수 직전에 넣음.
  • 캡슐화를 통한 비공개 상태를 별 이유가 없다면 최대한 유지하려고 해야함.
  1. 클래스는 작아야 한다!
  • 작은 클래스의 기준은 SRP (단일 책임 원칙)에 따른다. 클래스 이름은 해당 클래스의 책임을 명시할 수 있어야하는데, 이름이 너무 길다면 책임이 너무 많다는 방증이다. 하나의 책임을 가지고 있는 클래스가 적당한 크기의 클래스라할 수 있다. 큰 클래스 하나가 아니라 작은 여러개의 클래스가 더 바람직하다.
  • 응집도: 응집도란 인스턴스 변수와 클래스 메서드가 하나의 논리적인 단위로 묶인다는 것. 인스턴스 수는 적게 유지하되, 인스턴스 변수를 여러 클래스 메서드에 최대한 많이 등장하도록 짜면 응집도가 높아진다. 응집도가 낮아지면 메서드를 적절히 분해해 클래스를 두 세개로 쪼개주어 응집도를 높여준다. 응집도를 유지, 높여주려는 것만으로도 클래스 크기가 조절된다.
  1. 변경으로부터의 격리
  • 대다수 시스템은 지속적인 변경이 가해진다. 그리고 뭔가 변경할 때마다 시스템이 의도대로 동작하지 않을 수 있다. 깨끗한 시스템은 클래스를 체계적으로 정리해 변경에 수반하는 위험을 줄인다.
  • 인터페이스와 추상클래스를 사용해 구현이 미치는 영향을 격리한다. 상세한 구현에 의존하는 클라이언트 클래스는 구현이 바뀌면 위험에 빠진다.
  • 시스템의 결합도를 낮추면 유연성과 재사용성도 높아진다. 결합도가 낮다는 소리는 각 시스템 요소가 다른 요소로부터 그리고 변경으로부터 잘 격리되어 있다는 의미이다.

0개의 댓글