핵사고날 아키텍처의 사용이유
일단 핵사고날을 왜 사용하는가 부터 생각해보자면,결국은 변경에 의한 영향을 최대한 막기위한 발버둥이라고 나는 생각한다
나는 핵사고날이 클린아키텍처의 하나의 구현방법이라고 생각하고,이걸 이글에서는 구분해서 쓰지않을거임
이건 어플리케이션을 구분하는것부터 시작하는데
보통 테스트 관련 서적을 보면,코드를 4분면으로 나눔
- 1사분면: 의존성과 로직이 모두 많아 테스트가 어려운 코드.
- 2사분면: 의존성이 없고 로직만 있는 코드로, 유닛 테스트로 충분.
- 3사분면: 단순히 성공 여부만 확인하면 되는 코드.
- 4사분면: 의존성은 많지만 로직이 없는 코드로, 통합 테스트로 대응 가능.
코드는 이 4가지 분류로 분류할수있고,
여기서 문제가 되는건 1사분면인데,의존성은 많아서 유닛테스트는 매우 힘든데,로직도 많아서 테스트없이 두기엔 너무 위험함
즉 여기서 의존성과 로직을 분리해서 1사분면의 코드를 2사분면과 4사분면으로 밀어내는게 필요해짐
험블 객체 패턴
그래서 사용되던게 험블객체 패턴인데,이건 코드를 테스트가 쉬운부분과 테스트가 어려운부분으로 분리한다음
테스트가 어려운 부분의 코드(뷰나 db통신등)들을 최대한 아키텍처의 외부로 밀어내서,해당 테스트가 어려운 부분을 테스트용 객체를 만들어서 대응하는 패턴임
그래서 레이어드 아키텍처 역시 어느정도는 험블객체 패턴을 따르고(뷰와 db통신등)있지만 아키텍처 상에서 험블객체 패턴을 강요하진 않음
즉 서비스가 외부 api와 통신을 한다고 하면,이건 험블객체패턴이라면 분리되어야하지만 레이어드 아키텍처에서는 굳이 분리하지않고 서비스에서 다 처리해도 된다는것(뭐 외부통신을 데이터 소스로 보냐,비즈니스로직의 일부로 보냐에 따라 좀 다르긴하겠지만)
포트 어댑터 패턴과 핵사고날 아키텍처
그래서 등장하는게 포트어댑터 패턴과 핵사고날 아키텍처임
포트어댑터 패턴이란,핵심로직에서 사용하는 모든 의존성은 인터페이스를 통해서 di받아야하고,해당 인터페이스의 소유권은 핵심로직(어플리케이션 코어)가 가진다 라는거임
비유
비유하자면 만약 AA공장이 다른곳이 만드는 기성 제품을 사용해서 자기 공장을 돌린다면, AA공장은 해당 기성제품에 의존하고 있고,만약 다른곳이 해당 기성제품을 변경하거나 한다면 그대로 공장의 동작을 변경해야 하거나 심각하면 공장의 동작을 멈춰야 할수있음
이걸 하청을 주게된다면
- AA공장은 발주서를 작성하고, 하청업체는 이를 기반으로 제품을 만들어 납품함
- 발주서(인터페이스)는 AA공장이 소유하며, 하청업체는 이를 수정할 수 없음
- 따라서 발주서만 유지되면 하청업체가 바뀌더라도 AA공장에는 영향이 없음
이렇게 AA공장이 제품에 대해 의존하던게,제품이 AA공장이 낸 발주서에 의존하게 바뀜(의존성 역전 원칙)
포트어댑터 패턴
즉 포트어댑터 패턴의 핵심은 비즈니스로직에서의 의존성을 전부 직접적으로 의존하는걸 전부 간접적으로 내가 만들어둔 인터페이스를 기반으로 의존하고 사용한다는거임
이렇게 되면 해당 의존성의 변경으로부터 핵심로직은 영향을 받지않게 됨(추가적으로 해당 인터페이스를 구현한 구현체쪽에서도 인터페이스의 변경만 없다면 핵심로직의 변경에 영향을 받지않게됨)
이걸 명시적으로 하기위해 인터페이스의 소유권을 비즈니스로직이 가져가고,패키지 구조에서 인터페이스는 비즈니스로직이 속한곳에 위치해야함
여기서 비즈니스로직이 만들어둔 인터페이스를 포트라고 하고,이 포트를 구현한 객체를 어댑터라고 함
이 포트어댑터 패턴을 사용하면 좋은점은 여러가지가 있음
- 어댑터의 변경으로부터 비즈니스로직에 가해지는 영향을 매우 줄이거나 없앨수있음
- 비즈니스로직의 변경으로 부터 어댑터에 가해지는 영향을 줄일수있음(아예 인터페이스를 바꿔야하지않는한)
- 포트만 만들어둔다면,어댑터를 구현하는것과 비즈니스로직을 구현하는걸 두사람이 동시에 할수있음
- 비즈니스로직에 직접의존성이 없기때문에,비즈니스로직의 모든 의존성을 모킹쳐서 테스트를 쉽게 돌릴수있음
결론
결국 외부와의 연결을 최대한 간접적으로 만들어서,로직간의 연결을 최대한 끊어내서 외부 의존성의 영향이 비즈니스로직에 가해지는걸 최대한 쳐내기위한 패턴임
뭐 패턴들이 그렇듯 단점이 있긴한데(클래스 갯수의 증가와 계층의 증가,간접호출로 인한 성능저하,보일러플레이트 코드 증가 등),주는 장점이 너무 커서 널리 사용되고 있음
가장 큰 단점이라고 생각되는게 기존 직관적인 레이어드 아키텍처보다 좀 어렵긴하니까 처음에 적응이 어렵다정도?
구현속도도 솔직히 익숙해지고나니 레이어드랑 큰 차이 없게되기도 하고(좀 더 생각을 쪼갤수있어서 약간 더 빨라진거같기도함)
뭐 작은 프로젝트에서는 계층늘어나고 클래스 늘어나니까 좀귀찮긴할듯,그래도 어지간하면 핵사고날 쓰는게 편하긴한거같음 지금와서 생각하면
이 포트어댑터 패턴을 아키텍처 레벨로 확장한게 핵사고날인데,사실상 똑같은거임