클린 코드2
장민석
책
객체와 자료 구조
자료 추상화
• 변수 사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지
지는 않는다. 구현을 감추려면 추상화가 필요하다!
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
public interface Vehicle {
double getPercentFuelRemaining();
}
구현이 드러남 구현이 드러나지 않음
객체와 자료구조
• 객체는 추상화 뒤로 자료를 숨기고 자료를 다루는 함수를 제공
• 자료구조는 자료를 그대로 공개하고, 함수를 제공하지 않음
객체지향 코드와 절차적인 코드
• 절차적인 코드는 함수를 추가하기 쉽지만, 새로운 자료구조를
추가하기 어렵다.
• 객체지향 코드는 새 클래스를 추가하기 쉽지만, 함수를 추가하
기 어렵다.
• 두 가지는 상호 보완적인 특징이 있다.
자료 전달 객체 (DTO)
• 자료 전달 객체(DTO)는 자료구조체의 전형적인 형태로, 공개 변
수만 있고 함수가 없는 클래스다.
• Save나 find같은 탐색 함수를 넣기도 한다.
• 이 때, 비즈니스 규칙을 추가하면,
자료구조도 아니고 객체도 아닌 잡종 구조가 나온다.
• 잡종 구조를 만들지 마라!
오류 처리
오류 처리
• 클린 코드를 위해 오류 처리는 매우 중요
• 난잡한 오류 처리 때문에 실제 코드가 하는 일을 파악 못함!
오류 코드보다 예외를 사용하라
• 오류코드를 리턴 하는 방식은 이후 if문을 만들어낸다.
• If(deletePage(page) == E_OK)
미확인 예외를 사용하라
• Exception 종류별로 catch 하지 마라
• 피호출 함수에 오류를 추가하면 호출함수로 돌아가 함수 선언
부에 throws 절을 추가해야 한다.
호출자를 고려해 예외 클래스를 정의하라
• 오류를 정의할 때, 가장 중요한 관심사는 오류를 잡아내는 방법
이다.
• 외부 API를 쓰는 코드를 감싸게 되면 의존성이 크게 줄어듦
Null을 반환하지 마라
• Null 체크는 빼먹기 쉽다. 애초에 null을 반환하지 않도록 짜라!
• 대신 특수사례 객체를 만들어 return하라
public List<Employee> getEmployees() {
if(직원이 없으면)
return Collections.emptyList();
}
Null을 전달하지 마라
• 메서드로 null을 전달하는 방식은 매우 나쁘다!
• NullPointerException 터져나오게됨
경계
경계
• 개발 중 다양한 외부 라이브러리나 오픈 소스를 이용한다.
외부 코드 사용하기
• 외부에서 가져온 인터페이스를 여기저기 넘기지 마라.
• 이를 이용하는 클래스 밖으로 노출되지 않도록 주의한다.
학습 테스트
• 외부 코드는 익히기 어렵다.
• 바로 외부 코드를 호출하는 대신 간단한 테스트 케이스를 작성
• 가성비가 좋다
• 버전 올리기에도 좋다. TC가 있으므로
단위 테스트
TDD
• TDD시, 방대한 테스트 코드가 생성됨. 관리 문제를 유발
깨끗한 테스트 코드 유지하기
테스트 코드니깐 돌아가기만 하면 되지
안 하는 것 보단 낫지
테스트 코드가 복잡
케이스 추가 어렵고, 자꾸 실패함
개발자 극대노.
왜 했지 하지 말자.
단위 테스트 시러.
테스트 코드는 실제 코드 못지 않게 중요하다!
깨끗한 테스트 코드
• 가독성, 가독성, 가독성
깨끗한 테스트 코드
• 테스트에서만 사용하는 특수 API를 만든다
• 실제 코드만큼 효율적일 필요는 없다
• 앞선 규칙들을 약간 위반하더라도 가독성을 최우선으로 하라!
• 테스트 함수마다 한 개념만 테스트 하라
F.I.R.S.T
• Fast : 테스트는 빨라야 한다.
• Independent : 각 테스트는 서로 의존하면 안 된다.
• Repeatable : 어떤 환경에서도 반복 가능해야 한다.
• Self-Validating : 테스트는 Bool값으로 결과를 내야 한다.
• Timely : 단위 테스트는 실제 코드 구현 직전에 작성한다.
클래스
클래스 체계
• 자바 관례에서 가장 먼저 변수 목록이 나온다
• Static public 있으면 제일 먼저
• Static private 그 다음
• Private 인스턴스 그 다음
• 변수목록 다음 공개 함수
• 비공개 함수는 자기 호출한 공개 함수 직후
클래스는 작아야 한다!
• 작아야 한다. 작아야 한다.
• 클래스 이름은 클래스 책임을 기술
• 이름이 안 떠오른다? 책임이 너무 많은 것
단일 책임 원칙(SRP)
• 클래스나 모듈을 변경할 이유가 단 하나뿐이어야 한다.
• 돌아가는 프로그램만 생각하면 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()
}
응집도
• 몇몇 함수가 몇몇 변수만 사용한다면 쪼개라
시스템
아키텍처
도시를 세운다면?
• 혼자서 도시를 관리할 수 있는 가?
• 없다!
• 그럼에도 잘 돌아간다
• 수도 관리 팀, 전력 관리 팀 등 각 분야의 관리 팀이 있기에…
• 도시가 잘 돌아가는 이유는 적절한 추상화와 모듈화 때문이다.
시스템
• 시스템을 개발할 때 비슷한 수준의 관심사를 분리해 모듈화해
야 깨끗한 시스템을 유지할 수 있다
생성과 사용을 분리하라
• 소프트웨어 시스템은
• 객체를 생성하고 의존성을 서로 연결하는 준비과정과
• 준비 과정 이후에 이어지는 런타임 로직을 분리해야 한다.
생성과 사용을 분리하라
• 문제점
• getService가 MyserviceImpl과 그 파라메터에 의존
• getService 테스트 시, service를 mocking해 할당해야 함
• 객체 생성과 런타임 로직을 섞어 놓아 if기준 모든 실행
경로를 테스트해야 함
• MyServiceImpl이 모든 상황에 적합한 객체일지 알 수
없음
public Service getService() {
if(service == null)
service = new MyServiceImpl(...);
return service;
}
생성과 사용을 분리하라
• Main분리
생성과 사용을 분리하라
• 팩토리 : 객체가 생성되는 시점을 애플리케이션이 결정
생성과 사용을 분리하라
• 의존 주입(DI)
• 객체는 의존성을 인스턴스로 만드는 책임을 지지 않음
• 전담 매커니즘(main / 특수 컨테이너)에 책임을 넘김
• 클래스는 완전히 수동적
• Spring Framework
확장
• 처음부터 올바르게 시스템을 만들 수 있다는 믿음은 미신
• 관심사를 적절히 분리해 관리한다면, 소프트웨어 아키텍처는 점
진적으로 발전할 수 있다!
관심사를 적절히 분리하기 위한 노력
• EJB1/EJB2
• AOP
• 횡단 관심사를 분리하여 모듈성을 증가
• Spring, Jboss AOP, AspectJ
POJO
• Plain Old Java Object : 단순한 자바 객체
• POJO는 프레임워크에 의존하지 않는다.
= 코드 수준에서 아키텍처 관심사가 분리되어 있다.
• 애플리케이션 도메인 논리를 POJO로 구현한다.
• 무엇을 얻는가?
• 쉬운 테스트 주도 기법 적용
• 빠른 개발
• 코드의 단순성
정리
• 시스템 역시 깨끗해야 한다.
• POJO를 작성하고 관점 메커니즘을 이용해 관심사를 분리하라

클린 코드 part2

  • 1.
  • 2.
  • 3.
  • 4.
    자료 추상화 • 변수사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지 지는 않는다. 구현을 감추려면 추상화가 필요하다! public interface Vehicle { double getFuelTankCapacityInGallons(); double getGallonsOfGasoline(); } public interface Vehicle { double getPercentFuelRemaining(); } 구현이 드러남 구현이 드러나지 않음
  • 5.
    객체와 자료구조 • 객체는추상화 뒤로 자료를 숨기고 자료를 다루는 함수를 제공 • 자료구조는 자료를 그대로 공개하고, 함수를 제공하지 않음
  • 6.
    객체지향 코드와 절차적인코드 • 절차적인 코드는 함수를 추가하기 쉽지만, 새로운 자료구조를 추가하기 어렵다. • 객체지향 코드는 새 클래스를 추가하기 쉽지만, 함수를 추가하 기 어렵다. • 두 가지는 상호 보완적인 특징이 있다.
  • 7.
    자료 전달 객체(DTO) • 자료 전달 객체(DTO)는 자료구조체의 전형적인 형태로, 공개 변 수만 있고 함수가 없는 클래스다. • Save나 find같은 탐색 함수를 넣기도 한다. • 이 때, 비즈니스 규칙을 추가하면, 자료구조도 아니고 객체도 아닌 잡종 구조가 나온다. • 잡종 구조를 만들지 마라!
  • 8.
  • 9.
    오류 처리 • 클린코드를 위해 오류 처리는 매우 중요 • 난잡한 오류 처리 때문에 실제 코드가 하는 일을 파악 못함!
  • 10.
    오류 코드보다 예외를사용하라 • 오류코드를 리턴 하는 방식은 이후 if문을 만들어낸다. • If(deletePage(page) == E_OK)
  • 11.
    미확인 예외를 사용하라 •Exception 종류별로 catch 하지 마라 • 피호출 함수에 오류를 추가하면 호출함수로 돌아가 함수 선언 부에 throws 절을 추가해야 한다.
  • 12.
    호출자를 고려해 예외클래스를 정의하라 • 오류를 정의할 때, 가장 중요한 관심사는 오류를 잡아내는 방법 이다. • 외부 API를 쓰는 코드를 감싸게 되면 의존성이 크게 줄어듦
  • 13.
    Null을 반환하지 마라 •Null 체크는 빼먹기 쉽다. 애초에 null을 반환하지 않도록 짜라! • 대신 특수사례 객체를 만들어 return하라 public List<Employee> getEmployees() { if(직원이 없으면) return Collections.emptyList(); }
  • 14.
    Null을 전달하지 마라 •메서드로 null을 전달하는 방식은 매우 나쁘다! • NullPointerException 터져나오게됨
  • 15.
  • 16.
    경계 • 개발 중다양한 외부 라이브러리나 오픈 소스를 이용한다.
  • 17.
    외부 코드 사용하기 •외부에서 가져온 인터페이스를 여기저기 넘기지 마라. • 이를 이용하는 클래스 밖으로 노출되지 않도록 주의한다.
  • 18.
    학습 테스트 • 외부코드는 익히기 어렵다. • 바로 외부 코드를 호출하는 대신 간단한 테스트 케이스를 작성 • 가성비가 좋다 • 버전 올리기에도 좋다. TC가 있으므로
  • 19.
  • 20.
    TDD • TDD시, 방대한테스트 코드가 생성됨. 관리 문제를 유발
  • 21.
    깨끗한 테스트 코드유지하기 테스트 코드니깐 돌아가기만 하면 되지 안 하는 것 보단 낫지 테스트 코드가 복잡 케이스 추가 어렵고, 자꾸 실패함 개발자 극대노. 왜 했지 하지 말자. 단위 테스트 시러. 테스트 코드는 실제 코드 못지 않게 중요하다!
  • 22.
    깨끗한 테스트 코드 •가독성, 가독성, 가독성
  • 23.
    깨끗한 테스트 코드 •테스트에서만 사용하는 특수 API를 만든다 • 실제 코드만큼 효율적일 필요는 없다 • 앞선 규칙들을 약간 위반하더라도 가독성을 최우선으로 하라! • 테스트 함수마다 한 개념만 테스트 하라
  • 24.
    F.I.R.S.T • Fast :테스트는 빨라야 한다. • Independent : 각 테스트는 서로 의존하면 안 된다. • Repeatable : 어떤 환경에서도 반복 가능해야 한다. • Self-Validating : 테스트는 Bool값으로 결과를 내야 한다. • Timely : 단위 테스트는 실제 코드 구현 직전에 작성한다.
  • 25.
  • 26.
    클래스 체계 • 자바관례에서 가장 먼저 변수 목록이 나온다 • Static public 있으면 제일 먼저 • Static private 그 다음 • Private 인스턴스 그 다음 • 변수목록 다음 공개 함수 • 비공개 함수는 자기 호출한 공개 함수 직후
  • 27.
    클래스는 작아야 한다! •작아야 한다. 작아야 한다. • 클래스 이름은 클래스 책임을 기술 • 이름이 안 떠오른다? 책임이 너무 많은 것
  • 28.
    단일 책임 원칙(SRP) •클래스나 모듈을 변경할 이유가 단 하나뿐이어야 한다. • 돌아가는 프로그램만 생각하면 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() }
  • 29.
    응집도 • 몇몇 함수가몇몇 변수만 사용한다면 쪼개라
  • 30.
  • 31.
    도시를 세운다면? • 혼자서도시를 관리할 수 있는 가? • 없다! • 그럼에도 잘 돌아간다 • 수도 관리 팀, 전력 관리 팀 등 각 분야의 관리 팀이 있기에… • 도시가 잘 돌아가는 이유는 적절한 추상화와 모듈화 때문이다.
  • 32.
    시스템 • 시스템을 개발할때 비슷한 수준의 관심사를 분리해 모듈화해 야 깨끗한 시스템을 유지할 수 있다
  • 33.
    생성과 사용을 분리하라 •소프트웨어 시스템은 • 객체를 생성하고 의존성을 서로 연결하는 준비과정과 • 준비 과정 이후에 이어지는 런타임 로직을 분리해야 한다.
  • 34.
    생성과 사용을 분리하라 •문제점 • getService가 MyserviceImpl과 그 파라메터에 의존 • getService 테스트 시, service를 mocking해 할당해야 함 • 객체 생성과 런타임 로직을 섞어 놓아 if기준 모든 실행 경로를 테스트해야 함 • MyServiceImpl이 모든 상황에 적합한 객체일지 알 수 없음 public Service getService() { if(service == null) service = new MyServiceImpl(...); return service; }
  • 35.
  • 36.
    생성과 사용을 분리하라 •팩토리 : 객체가 생성되는 시점을 애플리케이션이 결정
  • 37.
    생성과 사용을 분리하라 •의존 주입(DI) • 객체는 의존성을 인스턴스로 만드는 책임을 지지 않음 • 전담 매커니즘(main / 특수 컨테이너)에 책임을 넘김 • 클래스는 완전히 수동적 • Spring Framework
  • 38.
    확장 • 처음부터 올바르게시스템을 만들 수 있다는 믿음은 미신 • 관심사를 적절히 분리해 관리한다면, 소프트웨어 아키텍처는 점 진적으로 발전할 수 있다!
  • 39.
    관심사를 적절히 분리하기위한 노력 • EJB1/EJB2 • AOP • 횡단 관심사를 분리하여 모듈성을 증가 • Spring, Jboss AOP, AspectJ
  • 40.
    POJO • Plain OldJava Object : 단순한 자바 객체 • POJO는 프레임워크에 의존하지 않는다. = 코드 수준에서 아키텍처 관심사가 분리되어 있다. • 애플리케이션 도메인 논리를 POJO로 구현한다. • 무엇을 얻는가? • 쉬운 테스트 주도 기법 적용 • 빠른 개발 • 코드의 단순성
  • 41.
    정리 • 시스템 역시깨끗해야 한다. • POJO를 작성하고 관점 메커니즘을 이용해 관심사를 분리하라