Let’s Start from Simple - Architecture & Stack
무조건 새롭고 어려운 것.. 내가 했던 실수!
개발을 하다 보면(어쩌면 무슨 일을 하던지) 새로운 것, 새로운 개념, 어려운 것(있어 보이는 것), 이상적인 것이 더 좋아 보이며 그것만을 추구하는 실수를 할 때가 있습니다.
다른 분들은 안그러실 수 있지만 저는 그랬습니다.
우선 첫회사에서 생긴 여러가지 버그를 보면서 테스트 코드가 없는 것이 원인이라고 생각해, TDD를 도입하자고 했고 대대적인 리팩토링을 통해 테스트 코드를 도입하려고 했습니다. 시도는 좋았지만.. 바쁜 일정을 고려하지 않고 이상만 쫓다 보니 별 성과를 거두지 못했습니다. 주로 문제가 되는 부분에 대한 간단한 e2e 테스트를 작성하는 것부터 시작했으면 좋았겠습니다.
또 새로운 회사에서 기술 스택을 새롭게 정할 수 있는 기회가 있었습니다. 참고로 새로운 회사는 정말 초기 스타트업입니다. 저는 새롭게 기술 스택을 정할 수 있다는 것에 신이 나서 이것 저것 찾아보며 도입하려고 했습니다. 이 시도가 나쁜 것은 아니지만 나중에 합류하신 분과 이야기 했을 때 우리가 시간안에 우선 제품을 내놓으려면 우리가 익숙한 것(JAVA/Spring)을 사용해야 한다는 것을 인정할 수 밖에 없었습니다.
저는 경영학과 출신으로 혁신 특히 파괴적 혁신이라는 말을 많이 들었고 정말 좋아합니다. 그래서 가능하면 새로운 것, 해보지 않은 것을 하려고 합니다. 하지만 경우에 따라서는 간단한 것, 익숙한 것이 더 좋다는 것을 인정하게 됩니다.
도움이 될만한 중간다리
하지만 그래도.. 그래도.. 그냥 쉬운 것, 익숙한 것을 하기에는 뭔가 찝찝하신 분들에게 그 찝찝함을 조금 해결할 수 있는 몇가지 방법을 제안드려 봅니다.
Simple Monolithic to DDD to MSA
Monolithic는 하나의 어플리케이션에 모든 것을 다 구현하는 것이고, MSA는 하나의 어플리케이션을 좀 더 작은 단위의 어플리케이션으로 나누고 서로 소통하며 동작하도록 하는 것으로 이해하면 됩니다.
시스템의 크기가 크거나, 팀이 클 때는 MSA를 하는 것이 도움이 되지만.. 간단한 시스템 또는 사이드 프로젝트에서 절대 먼저 도입할 필요가 없습니다! 왜냐하면 어플리케이션을 여러개로 쪼개고 서로 소통하게 하는 과정에서 추가적인 작업이 들어가고 관련해서 필요한 것들을 제대로 공부하기에는 정말 많은 노오력이 들어가기 때문입니다.
하지만 요즘 그렇게 MSA가 Hot 하던데 나도 그것 공부하고 적용해보고 싶어라고 하시는 분들이 있다면 우선 DDD가 적용되어 있는 프로젝트들을 보고 그 구조를 자신의 서비스에 적용해는 것을 추천드립니다. 왜냐하면 DDD는 내용이 생각보다 어렵지 않고, 이미 그렇게 적용되어 있는 프로젝트 구조만 보고 자신의 서비스에 적용하면 비교적 성공적으로 적용할 수 있기 때문입니다. 또 Monolithic 시스템이지만 DDD가 적용되어 있으면 나중에 MSA로 쪼개기가 쉽습니다. 제가 참고했던 프로젝트들은 아래와 같습니다.
- Nest JS DDD : https://dev.to/bendix/applying-domain-driven-design-principles-to-a-nest-js-project-5f7b
- 우아한 객체지향 샘플 코드 : https://github.com/eternity-oop/Woowahan-OO-03-domain-event
3 Layer vs DDD
아직 DDD를 도입하기도 어려우신 분들에게 3Layer도 장점이 있다는 말씀을 드립니다.
회사 팀장님과 이야기를 하다가 3Layer와 DDD의 장단에 대해 이야기를 듣게 되었는데 아래와 같습니다.
- 3 Layer : 조회가 주로 일어나는 경우에 적합
- DDD : 생성 및 업데이트가 많고 내부에서 복잡한 처리들이 있는 경우에 적합
무조건 DDD를 적용하기 보다는 개발하려는 어플리케이션의 특성을 한번 더 생각해보고 적용하는 것을 추천드립니다. 소규모 프로젝트를 진행하고 DDD에 익숙하지 않다면 ‘아직도 DDD를 적용하지 못했네..’ 하기 보다는 우선 3Layer로 자신있게 진행한 후에 복잡한 로직이 생겼을 때 변경을 고려해보는 것이 더 좋지 않을까 싶습니다.
Interface, DI for TDD, BDD, Test Code.
TDD를 공부하다 보면 BDD를 알게 되고 관련 내용을 파악하다 보면 하루가 다가고 또 적용하려다 보면 많은 장애물에 부딪힙니다. 당장 TDD를 적용하기는 어렵지만 나중에 쉽게 적용할 수 있는 발판이라도 마련해 높고 싶은 분들에게 아래 3가지를 추천드립니다.
- Constructor Injection 사용
- 의존성 주입은 크게 Field Injection, Setter Injection, Constructor Injection로 나뉩니다. 이중에서 Field Injection을 사용하는 경우 이후 테스트 코드를 작성할 때 큰 어려움이 있습니다..! 그래서 Field Injection은 사용하면 안되며, Setter와 Constructor 중에서는 생성 시 꼭 필요한 객체가 누락되는 것과 순환 참조를 방지하는 Constructor Injection을 사용하는 것이 좋습니다.
- Interface 기반으로 코드 작성
- Interface를 사용한 추상화는 객체지향 프로그래밍에서 유용하게 사용됩니다. 하지만 경우에 따라 해당 클래스는 굳이 하나의 구현체만 있을 건데 굳이 Interface를 만들고 별도 구현체를 두는 방식으로 해야 하나라는 생각이 들 수 있습니다. 하지만 이런 경우에도 추후 테스트 코드 작성을 위해 Interface 기반으로 작성하는 것이 좋습니다. Interface 기반으로 되어있지 않으면 Mocking이 힘들기 때문입니다.
- 의존성 단순화 및 단일 책임 원칙 지키기
- 너무 단순한 원리이지만 테스트 대상이 되는 코드가 잘 정리되어 있다면 테스트 하기도 쉽습니다. 클래스별, 패키지별, (DDD를 하는 경우) 도메인별 의존성 흐름이 순환참조가 일어나지 않게 단순화 해 놓고 각 클래스를 단일 책임 원칙에 맞게 잘 쪼개 놓으면 나중에 테스트하기가 더 쉽습니다.