11장 : 의식적으로 지름길 사용하기

지름길을 방지하기 위해서는 먼저 지름길 자체를 파악해야 한다.

정당한 지름길이라면 지름길의 효과를 의식적으로 택할 수도 있다.

왜 지름길은 깨진 창문 같을까 ?

example
  • 침실이 정돈돼 있지 않으면 옷을 옷장에 넣는 대신 바닥에 아무렇게 던져 놓기 쉽다.

  • 괴롭힘이 흔한 집단에서는 괴롭힘이 더 쉽게 일어난다.

  • ‘좋은’ 종네라도 차의 창문이 깨져있다면 차를 망가뜨리는 일이 쉽게 일어난다.

  • 기물 파손이 흔한 동네에서는 방치된 차를 도둑질하거나 망가뜨리는 일이 더 쉽게 일어난다.

코드 작업에 적용

  • 품질이 떨어진 코드에서 작업할 때 더 낮은 품질의 코드를 추가하기가 쉽다.

  • 코딩 규칙을 많이 어긴 코드에서 작업할 떄 또 다른 규칙을 어기기도 쉽다.

  • 지름길을 많이 사용한 코드에서 작업할 때 또 다른 지름길을 추가하기도 쉽다.

깨끗한 상태로 시작할 책임

  • 소프트웨어 프로젝트는 대개 큰 비용이 들고 장기적인 노력을 필요로 하기 때문에 깨진 창문을 막아야 한다.

  • 작업 중인 부분이 프로젝트 전체로 봤을 떄 그리 중요하지 않은 부분이거나, 프로토타이핑 작업 중이거나, 경제적인 이유로 인해 지름길을 취하는 것이 더 실용적일 때도 있다.

  • 의도적인 지름길에 대해서는 세심하게 잘 기록해둬야 한다.

💡 육각형 아키텍처에서 고려해볼 수 있는 지름길과 지름길의 효과를 살펴보고, 이 지름길에 대한 찬반 의견을 살펴보자.

유스케이스 간 모델 공유하기

유스케이스 간에 입출력 모델을 공유하게 되면 유스케이스들 사이에 결합이 생긴다.

하나의 클래스가 변경되면 두 유스케이스 모두 영향을 받는다. 단일 책임 원칙에서 이야기하는 ‘변경할 이유’를 공유하는 것이다. 출력 모델을 공유하는 경우에도 마찬가지다.

Case

  • 유스케이스 간 입출력 모델을 공유하는 것은 유스케이스들이 기능적으로 묶여 있을 때 유효하다.

  • 즉 특정 요구사항을 공유할 떄 괜찮다. 이 경우 특정 세부사항을 변경할 경우 실제로 두 유스케이스 모두에 영향을 주고 싶은 것이다.

  • 비슷한 개념의 유스케이스 여러 개를 만든다면 유스케이스가 독립적으로 진화할 필요가 있는지 주기적으로 질문하고 대답이 “예”가 되는 순간 바로 입출력 모델을 분리해야 한다.

도메인 엔티티를 입출력 모델로 사용하기

인커밍 포트는 도메인 엔티티에 의존성을 가지고 있다.

Account 엔티티는 변경할 또 다른 이유가 생겼다.

Case

  • 간단한 생성이나 업데이트 유스케이스의 경우 데이터베이스에 저장해야 하는 바로 그 상태 정보가 엔티티에 있기 때문에 괜찮을지도 모른다.

  • 유스케이스가 복잡한 도메인 로직을 구현해야 한다면, 유스케이스 인터페이스에 대한 전용 입출력 모델을 만들어야 한다.

  • 처음에는 도메인 엔티티를 입력 모델로 사용했더라도 도메인 모델로부터 독립적인 전용 입력 모델로 교체해야 하는 시점을 잘 파악해야 한다.

인커밍 포트 건너뛰기

인커밍 포트가 없으면 도메인 로직의 진입점이 불분명해진다.

인커밍 포트를 제거함으로써 인커밍 어댑터와 애플리케이션 계층 사이의 추상화 계층을 줄였지만,

특정 유스케이스를 구현하기 위해 어떤 서비스 메서드를 호출해야 할지 알아내기 위해 애플리케이션의 내부 동작에 대해 더 잘 알아야 한다.

전용 인커밍 포트의 장점

  • 한눈에 진입점을 식별할 수 있다.

  • 아키텍처를 쉽게 강제할 수 있다. 애플리케이션 계층에 대한 모든 진입점을 정의하는 것이 아주 의식적인 결정이 되기 때문이다.

애플리케이션의 규모가 작거나 인커밍 어댑터가 하나밖에 없어서 모든 제어 흐름을 인커밍 포트의 도움 없이 단숨에 파악할 수 있다면 인커밍 포트가 없는 것이 편하지만,

애플리케이션의 규모가 이후로도 계속 작게 유지되거나 인커밍 어댑터가 계속 하나밖에 없을 것이라고 확신할 수 없다.

애플리케이션 서비스 건너뛰기

애플리케이션 서비스가 없으면 도메인 로직을 둘 곳이 없다.

아웃고잉 어댑터에 있는 AccountPersistenceAdapter 클래스가 직접 인커밍 포트를 구현해서 애플리케이션 서비스를 대체한다.

Case

  • 간단한 CRUD 유스케이스에서는 보통 애플리케이션 서비스가 도메인 로직 없이 생성, 업데이트, 삭제 요청을 그대로 영속성 어댑터에 전달하기 때문에 구미가 당기는 방법이다. 하지만

    • 이 방법은 인커밍 어댑터와 아웃고잉 어댑터 사이에 모델을 공유해야 한다. 앞에서 이야기한 도메인 모델을 입력 모델로 사용하는 케이스가 된다.

    • 나아가 애플리케이션 코어에 유스케이스라고 할 만한 것이 없어진다. 시간이 지남에 따라 CRUD 유스케이스가 점점 복잡해지면 도메인 로직을 그대로 아웃고잉 어댑터에 추가하고 싶은 생각이 들텐데, 이렇게 되면 도메인 로직이 흩어져서 도메인 로직을 찾거나 유지보수하기가 어려워진다.

  • 유스케이스가 엔티티를 단순히 생성, 업데이트, 삭제하는 것보다 더 많은 일을 하게 되면 애플리케이션 서비스를 만든다는 명확한 가이드라인을 팀에 정해둬야 한다.

유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까 ?

경제적인 관점에서 지름길이 합리적일 떄도 있다. 지름길을 사용할지 여부를 결정하는 데 도움이 되도록 지름길을 사용한 결과에 대한 식견을 갖고있어야 한다.

간단한 CRUD 유스케이스에 대해서는 전체 아키텍처를 구현하는 것이 지나치게 느껴지므로 지름길의 유혹을 느낄 수 있다. 하지만 모든 애플리케이션을 처음에는 작게 시작하기 때문에, 유스케이스가 단순한 CRUD 상태에서 벗어나느 시점이 언제인지에 대해 팀이 합의하는 것이 매우 중요하다. 합의를 이루고 난 후에야 팀은 지름길을 장기적으로 더 유지보수하기 좋은 아키텍처로 대체할 수 있다.

어떤 경우든 아키텍처에 대해, 그리고 왜 특정 지름길을 선택했는가에 대한 기록을 남겨서 나중에 우리 자신 또는 프로젝트를 인계받는 이들이 이 결정에 대해 다시 평가할 수 있게 하자.

DISCUSSION

Last updated