4. 자료 추상화
• 변수 사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지
지는 않는다. 구현을 감추려면 추상화가 필요하다!
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
public interface Vehicle {
double getPercentFuelRemaining();
}
구현이 드러남 구현이 드러나지 않음
5. 객체와 자료구조
• 객체는 추상화 뒤로 자료를 숨기고 자료를 다루는 함수를 제공
• 자료구조는 자료를 그대로 공개하고, 함수를 제공하지 않음
6. 객체지향 코드와 절차적인 코드
• 절차적인 코드는 함수를 추가하기 쉽지만, 새로운 자료구조를
추가하기 어렵다.
• 객체지향 코드는 새 클래스를 추가하기 쉽지만, 함수를 추가하
기 어렵다.
• 두 가지는 상호 보완적인 특징이 있다.
7. 자료 전달 객체 (DTO)
• 자료 전달 객체(DTO)는 자료구조체의 전형적인 형태로, 공개 변
수만 있고 함수가 없는 클래스다.
• Save나 find같은 탐색 함수를 넣기도 한다.
• 이 때, 비즈니스 규칙을 추가하면,
자료구조도 아니고 객체도 아닌 잡종 구조가 나온다.
• 잡종 구조를 만들지 마라!
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 터져나오게됨
23. 깨끗한 테스트 코드
• 테스트에서만 사용하는 특수 API를 만든다
• 실제 코드만큼 효율적일 필요는 없다
• 앞선 규칙들을 약간 위반하더라도 가독성을 최우선으로 하라!
• 테스트 함수마다 한 개념만 테스트 하라
24. F.I.R.S.T
• Fast : 테스트는 빨라야 한다.
• Independent : 각 테스트는 서로 의존하면 안 된다.
• Repeatable : 어떤 환경에서도 반복 가능해야 한다.
• Self-Validating : 테스트는 Bool값으로 결과를 내야 한다.
• Timely : 단위 테스트는 실제 코드 구현 직전에 작성한다.
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()
}
31. 도시를 세운다면?
• 혼자서 도시를 관리할 수 있는 가?
• 없다!
• 그럼에도 잘 돌아간다
• 수도 관리 팀, 전력 관리 팀 등 각 분야의 관리 팀이 있기에…
• 도시가 잘 돌아가는 이유는 적절한 추상화와 모듈화 때문이다.
32. 시스템
• 시스템을 개발할 때 비슷한 수준의 관심사를 분리해 모듈화해
야 깨끗한 시스템을 유지할 수 있다
33. 생성과 사용을 분리하라
• 소프트웨어 시스템은
• 객체를 생성하고 의존성을 서로 연결하는 준비과정과
• 준비 과정 이후에 이어지는 런타임 로직을 분리해야 한다.
34. 생성과 사용을 분리하라
• 문제점
• getService가 MyserviceImpl과 그 파라메터에 의존
• getService 테스트 시, service를 mocking해 할당해야 함
• 객체 생성과 런타임 로직을 섞어 놓아 if기준 모든 실행
경로를 테스트해야 함
• MyServiceImpl이 모든 상황에 적합한 객체일지 알 수
없음
public Service getService() {
if(service == null)
service = new MyServiceImpl(...);
return service;
}
37. 생성과 사용을 분리하라
• 의존 주입(DI)
• 객체는 의존성을 인스턴스로 만드는 책임을 지지 않음
• 전담 매커니즘(main / 특수 컨테이너)에 책임을 넘김
• 클래스는 완전히 수동적
• Spring Framework
38. 확장
• 처음부터 올바르게 시스템을 만들 수 있다는 믿음은 미신
• 관심사를 적절히 분리해 관리한다면, 소프트웨어 아키텍처는 점
진적으로 발전할 수 있다!
39. 관심사를 적절히 분리하기 위한 노력
• EJB1/EJB2
• AOP
• 횡단 관심사를 분리하여 모듈성을 증가
• Spring, Jboss AOP, AspectJ
40. POJO
• Plain Old Java Object : 단순한 자바 객체
• POJO는 프레임워크에 의존하지 않는다.
= 코드 수준에서 아키텍처 관심사가 분리되어 있다.
• 애플리케이션 도메인 논리를 POJO로 구현한다.
• 무엇을 얻는가?
• 쉬운 테스트 주도 기법 적용
• 빠른 개발
• 코드의 단순성
41. 정리
• 시스템 역시 깨끗해야 한다.
• POJO를 작성하고 관점 메커니즘을 이용해 관심사를 분리하라