클린코드 8장 경계

 시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다 (오픈소스를 쓰거나, 다른 팀의 컴포넌트를 쓰거나..)

어떤식으로든 외부 코드를 우리 코드에 깔금하게 통합해야 한다.

외부 코드 사용하기

인터페이스 제공자의 경우 더 많은 환경에서 돌아가기 위해서 적용성을 최대한 넓히려고 애를 쓴다 → 그로 인하여 시스템 경계에서 문제가 생길 소지가 많다.

예를 들어 java.util.Map 을 살펴보면 Map 은 다양한 인터페이스로 수많은 기능을 제공한다. 제공하는 기능성과 유연성은 확실히 유용하지만 그만큼 위험하다 → 프로그램에서 Map 을 만들어서 넘긴다고 가정하면, 넘기는 쪽에서 아무도 Map 을 삭제하지 않으리라 믿을지도 모르지만, Map 내용을 지울 권한은 누구에게나 있다.

Map<String, Sensor> sensors = new HashMap<>();
...
Senser s = sensors.get(sensorId);

위 코드 보다 아래 코드와 같으 사용하는 것이 바람직하다.

public class Sensors {
	private Map<String, Sensor> sensors = new HashMap<>();
	
	public Sensor getById(String id) {
		return sensors.get(id);
	}
}

경계 인터페이스인 Map을 Sensors 안으로 숨긴다. 따라서 Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않는다. 또한 Sensors 클래스는 필요한 인터페이스만 제공할 수 있다.

Map 을 사용할 때마다 캡슐화를 해서 사용하라는 것이 아니라 Map 을 사용하여 여기저기 넘기지 말라는 말이다. (파라미터나 반환값으로 쓰지 말라는 것)

경계 살피고 익히기

외부 코드를 사용하면 적은 시간에 더 많은 기능을 출시하기가 쉬워진다.

외부 패키지 테스트는 우리의 책임은 아니지만, 우리 자신을 위해 우리가 사용할 코드를 테스트 하는 것이 바람직하다.

타사 라이브러리를 가져왔고 사용법이 분명하지 않다고 가정하면 대개는 하루나 이틀 문서를 읽으며 사용법을 결정한다. 그런 다음 우리 쪽 코드를 작성하여 예상대로 동작하는지 확인한다. 때로는 우리 버그인지 라이브러리 버그인지 찾아내느라 오랜 디버깅으로 골치를 앟는다.

외부 코드는 익히기 어렵다. 외부 코드를 통합하기도 어렵다. 두가지를 동시에 하는건 더 어렵다.

그렇기 때문에 다르게 접근할 필요가 있다. 곧바로 우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히면 어떨까.. (이를 학습테스트 라고 부른다.)

학습 테스트는 프로그램에서 사용하려는 방식대로 외부 API를 호출한다 .통제된 환경에서 API를 제대로 이해하는지를 확인하는 셈이고, 학습테스트는 API를 사용하려는 목적에 초점을 맞춘다.

학습 테스트는 공짜 이상이다

학습 테스트에는 비용이 들지 않는다. (어째든 익혀야 하니까.. 오히려 필요한 지식만 확보하는 손쉬운 방법이다)

학습 테스트는 이해도를 높여주는 정확한 실험이다.

학습 테스트는 공짜 이상이다. 투자하는 노력보다 성과가 크다.

패키지가 새로운 버전이 나온다면 학습 테스트를 돌려 차이가 있는지 확인할 수 있다.

학습 테스트는 패키지가 예상대로 도는지 검증한다. 일단 통합한 이후라고 하더라도 패키지가 우리 코드와 호환이되리라는 보장은 없다.

학습 테스트를 이용한 학습이 필요하든 그렇지 않든, 실제 코드와 동일한 방식으로 인터페이스를 사용하는 테스트 케이스가 필요하다. 이런 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워진다. (그렇지 않다면 낡은 패키지를 오랫동안 사용하게 된다.)

아직 존재하지 않는 코드를 사용하기

경계와 관련해 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 경계이다.

때로 우리 지식이 경계를 너머 미치지 못하는 코드 영역도 있다. 떄로는 알려고 해도 알 수 가 없다. 때로는 더이상 내다보지 않기로 결정한다.

다른 팀에 API를 설계하지 않았으므로 구체적인 방법은 모를 수 있기에 구현을 너중으로 미루고, 자체적인 인터페이스를 정의했다.

우리가 바라는 인터페이스를 구현하면 우리가 인터페이스를 전적으로 통제한다는 장점이 생긴다. 또한 코드 가독성도 높아지고 코드 의도도 분명해진다.

그런 다음 나중에 다른 팀이 구현한 API를 해당 인터페이스를 통하여 제공을 하면 된다.

깨끗한 경계

경계에서는 흥미로운 일이 많이 벌어진다. 변경이 대표적인 예다.

소프트웨어 설계가 우수하다면 변경하는데 많은 투자와 재작업이 필요하지 않다.

엄청난 시간과 노력과 재작업을 요구하지 않는다.

통제하지 못하는 코드를 사용할 떄는 너무 많은 투자를 하거나 햐ㅕㅇ후 변경 비용이 지나치게 커지지 않도록 각별히 주의해야 한다.

경계에 위치하는 코드는 깔끔히 분리한다. 또한 기대치를 정의하는 테스트 케이스도 작성한다.

외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자. Map 에서 봤듯이 새로운 클래스로 경계를 감싸거나 아니면 ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자.

댓글 없음:

댓글 쓰기

도서 내용 정리 - 스태프 엔지니어

개요 네이버 도서 정보:  https://bit.ly/3JzLvQr 개발자는 관리자로만 커리어를 쌓아야 하는가? 관리자가 아닌 기술 리더로 성장하는 길은 없을까? IT 업계가 계속 성장하면서 전에 없던 팀과 조직의 경계를 넘어서는 큰 문제를 다루게 되...