Clean Code 3판을 읽고 정리한 글입니다
Ⅷ. 경계
모든 프로그램을 직접 개발하지 않음
- 패키지, 오픈소스, 다른 사내의 컴포넌트등
- 외부 코드와 우리 코드를 깔끔하게 통합하는 방법?
외부 코드 사용
인터페이스 제공자와 인터페이스 사용자의 긴장
- 제공자
- 패키지 제공자, 프레임워크 제공자
- 적용성 최대한 넓히려 → 더 많은 환경에서 돌아가도록
- 사용자
– 자신의 요구에 집중하는 인터페이스를 원함
Java.util.Map
- Map : 굉장히 다양한 인터페이스로 수많은 기능 제공
- Map의 기능성/유연성은 유용하나 위험도 큼
- Map을 여기저기 넘길때 Map.clear()로 누구나 내용 삭제 가능
- 객체 유형 제한 없음 : 마음만 먹으면 어떤 객체든 추가 가능
일반적인 Map 사용 1
2
3
4// Sensor 객체를 담는 Map
Map sensors = new HashMap();
// Sensor 가 필요하면
Sensor s = (Sensor) sensors.get(sensorId); - 동작은 하나 클린 코드는 아님
- Map의 리턴값인 Object의 cast 책임이 클라이언트에 있음
- 코드의 의도가 들어나지 않음
1 | Map<Sensor> sensors = new HashMap<Sensor>(); |
- 사용자에게 필요하지 않은 기능까지 제공하는 문제를 해결하지 못함
- Map 인터페이스도 변함 (ex)자바5의 제네릭 추가등 : 이경우 수정코드가 많음
1 | public class Sensors { |
- 경계 인터페이스인 Map을 Sensors 안으로 숨김
- Map 인터페이스가 변하더라도 나머지 프로그램에 영향 없음
- 제네릭 사용 여부에 영향 X → Sensors 클래스 안에서 객체 유형 관리/변환
- Sensors 클래스가 프로그램에 필요한 인터페이스만 제공
- 코드 이해가 쉬우며 오용하기는 어려움
- 나머지 사용 클라이언트에 설계 규칙/ 비지니스 규칙을 따르도록 강제 가능
Map(또는 유사한 경계 인터페이스를 )여기저기 넘기지 마라
- 이용하는 클래스나 클래스 계열 밖으로 노출되지 않도록 주의
- 공개 API 인자나 반환값으로 Map 인스턴스를 사용하면 안된다
경계 살피고 익히기
- 외부 패키지 테스트는 우리 책임이 아니나 사용할 코드를 테스트 함이 바람직함
- 외부 코드 익히기 어려움
- 타사 라이브러리 문서 읽음으로사용법 결정
- 코드 작성해서 라이브러리 예쌍 작동 확인
- 디버깅 문제 : 우리 코드 버그 or 라이브러리 버그?
학습 테스트
- 간단한 테스트 케이스를 작성해서 외부 코드를 익히는 방법
- 프로그램에서 사용하는 방식대로 외부 API 호출
- 통제된 환경에서 API를 제대로 이해하는가 확인
- API 사용목적 초점
log4j 익히기
학습 테스트
지금까지 간단한 콘솔 로거 초기화 방법 익힘
이제 모든 지식을 독자적 로거 클래스로 캡슐화
나머지 프로그램은 log4j 경계 인터페이스를 몰라도 사용 가능
학습 테스트는 공짜 이상이다
- 학습테스트는 이해도를 높여주는 정확한 실험
- 투자노력보다 얻는 성과가 더 큼
- 패키지 새 버전 나오면 학습 테스트를 돌려서 차이가 있는지 검증 가능
- 이런 경계 테스트가 있으면 패키지 새 버전 이전이 쉬어짐
- 아니면 필요이상 낡은 버전을 오랫동안 사용하려는 유혹에 빠지기 쉬움
아직 존재하지 않는 코드를 사용하기
경게의 또 다른 유형 : 아는코드와 모르는 코드를 분리하는 경계
예시)
- 상황
- sw에 ‘송신기’가 필요
- 송신기 시스템 책임진 사람들은 인터페이스도 정의하지 못한 상태
- 프로젝트 지연 없게 하기 위해 송신기와 먼 부분부터 작업
- 작업 부분과 송신기 시스템 부분의 경계를 부딫치게 되며 기능정의를 하게 되었음
지정한 주파수를 이용해 이 스트림에서 들어오는 자료를 아날로그 신호로 전송하라
- 아직 API설계가 되지 않으므로 구체적인 방법은 모름 → 구현을 나중으로
- 자체적 인터페이스 정의
- Transmitter 인터페이스 클래스 정의
- transmit 메서드 추가
- 주파수와 자료스트림을 입력받음
- 바라는 인터페이스 구현 → 인터페이스 전적 통제한다는 장점 → 코드 가독성과 분명한 코드 의도 반영
- (통제할수도 없고 정의되지도 않은) 송신기 API에서 Communication Controller 분리
- 필요한 인터페이스 정의 했으므로 Communication Controller는 깔끔 / 깨끗
- 실제 송신기 API가 정의된 뒤에는 Transmitter Adapter 구현으로 간극을 매운다
- ADAPTER 패턴 사용 → API 사용 캡슐화 → API 수정 시 수정될 코드를 한 곳으로
- 테스트도 간편 : 적절한 Fake Transmitter 사용 → Communication Controller 테스트 가능
- Transmitter API 인터페이스가 나온다음에 경계 테스트 생성해서 올바로 API 사용하는지도 테스트 가능
깨끗한 경계
경계의 변경
- sw 개발설계가 우수하다면? 변경시 많은 투자와 재작업이 필요하지 않음
- 통제 못하는 코드 사용시 너무 많은 투자나 향후 변경 비용이 너무 커지지 않도록 각별히 유의
경계 코드는 깔끔히 분리
- 기대치 정의 테스트 ㅂ작성
- 외부 호출한 코드를 가능한 줄여 경계를 관리하자
- Map의 예처럼 새로운 클래스로 경계를 감싸거나
- ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자
- 어떤 방법이든 가독성향상, 경계 인터페이스 사용 일관성 향상, 패키지 변경시 변경 코드 감소
Related POST
- [Clean Code] Ⅰ. 깨끗한 코드
- [Clean Code] Ⅱ.의미 있는 이름
- [Clean Code] Ⅲ. 함수
- [Clean Code] Ⅳ. 주석
- [Clean Code] Ⅴ. 형식 맞추기
- [Clean Code] Ⅵ. 객체와 자료구조
- [Clean Code] Ⅶ. 오류 처리
- [Clean Code] Ⅷ. 경계
- [Clean Code] Ⅸ. 단위 테스트
- [Clean Code] Ⅹ. 클래스
- [Clean Code] Ⅺ. 시스템
- [Clean Code] Ⅻ. 창발성(創發性)
- [Clean Code] XIII. 동시성
- [Clean Code] XIV. 점진적 개선(SUCCESSIVE REFINEMENT)
- [Clean Code] XV. JUnit 들여다보기
- [Clean Code] XVI. SerialDate 리팩터링
- [Clean Code] XVII. 냄새와 휴리스틱
- [Clean Code] 다 읽었다~