이번 글은 회사 코드를 1차적으로 개선하며, 회사의 요구사항을 받아낼 수 있는 구조를 생각하기 위해 고군분투한 내용을 공유합니다. 이번 일은 자바 레거시를 정리하고 프로젝트를 어떻게 시작할지 가늠하던 중 생긴 일입니다. 일정이 여유롭다가 갑자기 1달내로 출시해야한다는 소식을 듣고 화들짝 놀라서 작업하기 시작했죠.
레거시에서는 해야할 일을 코드로 풀어낸 것이 도저히 이해가 되지 않아, 아예 새로 만들자는 결론을 냈습니다. 그 외에도 여러 결함이 있었지만 제 손에서 새시작을 할 수 있는 시간과 당초 계획이 그랬어서 가능했죠.
요구사항은 파악했으니, 남은건 코드와 인프라 구성을 하는 것만 남았습니다.
아무튼, 주요 액터 기준으로 “도메인”이란 이름을 붙여서 시작했습니다. 도메인 기반으로 비즈니스 로직을 풀어봐야지! 라고 생각했지만 방향성이 명확하지 않았습니다. 그러다보니 자연스럽게 도메인은 뒷전인 채로, 도메인만 담는 DTO로 전락하며 비즈니스 로직은 쿼리와 DTO를 아우르는 서비스 계층에 생겼고, 그게 비대하게 점점 커져갔습니다.
예를 들어 로그인만 하더라도 이런저런 인증과 권한 후 토큰을 발부하는데, DB나 외부 저장소에서 꺼내온 값을 조합해서 이를 토대로 관리하는 형태였죠. 물론 처음 짜는거다보니 작업속도는 제가 코드에 익숙한 만큼 바로바로 나왔습니다만, 문제는 그것만이 아니었습니다.
예상데이터를 만들고, 처음엔 테스트도 구상하고 진행했습니다만 차츰 가면 갈 수록 일정을 맞추기 위해선 달려야했던지라 별 수 없이 완성에 힘을 쏟았습니다. 그러다보니 “원래 하던대로” 만들고, 포스트맨으로 검증하고, 버그가 나면 다시 수정커밋을 하는 식으로 시간을 맞추기 위해 계속 작업할 수 밖에 없었죠.
작업이 간단하니 상관은 없습니다만, 결국 이렇게 설명없고 테스트 없이 짜면 이전 레거시와 다를 게 없다는 생각을 하게 됩니다. 일단 일정은 맞췄으니, 다음 태스크를 생각하게 되었어요.
테스트가 없다보니 버그가 나면 로그를 보고 self hosted sentry 로그로 체크할 수 밖에 없었죠. 간신히 이슈로 만들고 이를 겨우 잡아내는 방식이다보니 불안했고, 요구사항이 추가될 때마다 이래도 되나 싶은 생각이 들었습니다. 한다 해도 결국 처음부터 끝까지 다 꿰고있어야 “한번에 실수 없이” 추가할 수 있었을테니까요.
도메인도 사실 단순 DTO에 불과하다보니 더욱 이상했습니다. 이거 사실상 트랜잭션 스크립트가 아니었나..? 하는 생각과 함께요.
작년과 올해에는 기회가 되어서 조영호님의 강의를 두 편 가량 들었습니다. <<객체지향의 사실과 오해>>와 <<오브젝트>>를 워낙 감명깊게 보아서 말씀하신 부분을 테스트와 함께 꼭 실천하면 좋겠다는 생각이 있었다보니 실제 현장강의를 바로 신청했습니다.
기존 개발방법을 이용해서 데이터를 조회하는 트랜잭션 스크립트로서의 코드들이 배치된게 “나쁜 것은 아닙니다”. 세상에 정답은 없습니다. 개발자라면 주어진 일정에 맞게 결과를 내는 것이 더 중요하니까요. 다만 이대로 갔을 때 유지보수할 수 있고, 단점이 없다면 당연히 수용하는게 정답입니다.
그렇지만 제가 생각했을 땐 현재 담당하는 서비스의 복잡도는 계속 늘어날 것이고 현재 작업이 쌓이면 제가 겉잡을 수 없이 힘들 것이란 것을 알고 개선작업을 시작하게 되었습니다.
도메인 주도 설계의 사실과 오해 를 들으며, 교조적으로 바라보던 “DDD” 란 개념만을 주요하게 생각했던 부분을 바로잡았습니다. 어떤 배경을 통해 DDD로 통칭되는 이야기가 나왔고, 개념의 등장에 뒷받침하는 개념과 “도메인”을 정확히 바라보기 위한 큰 방안-작은 방안을 명확히 이해할 수 있었습니다. 강의를 토대로 해서, 도메인 모델이 무엇이고 이를 설계하는 방안이 어떤지, 그리고 이 모델을 구성하는 요소들이 무엇이 있으며, 문제 해결을 위해 어떻게 접근하면 되는지를 살펴볼 수 있었죠.
그리고 소문만 무성하던 DDD (Evans, 2003), IDDD (Vernon, 2013)의 책을 어떻게 살펴보면 되는지, 코어 개념이 무엇이며 관련해서 어떤 개념을 살펴보면 올바른 접근을 할 수 있는지 볼 수 있습니다. 이후 위에 소개한 두 책을 다시 살펴보고 내재화하면 정말 좋겠다라는 생각과 함께요.
(신청 강의가 페이스북이나 링크드인에 생겨 공유가 어렵네요. 검색하시면 바로 확인하실 수 있습니다)
현재 파이썬으로 개발하는데 뜬금없이 JPA를 왜 듣는가? 라고 하실 수도 있으실 겁니다. 하지만 위의 강의의 하위 심화과정이라는 생각이 대번 들었습니다. 자바에서 객체가 가진 데이터를 영속화 하기위한 표준기술이 JPA니 연관이 없다면 그게 이상하죠. 그렇다보니 현재 사용하는 SQLAlchemy도 ORM으로서 JPA와 연관이 없지 않을 것이다 라는 생각을 하게 되었고, 그것이 정답이었습니다.
도메인을 생각한다 한들 데이터베이스에 저장되는 값과는 패러다임의 차이가 분명히 있기 때문에, 이를 어떻게 극복할 것인지 어떻게 테스트를 쌓아올리고 로직을 방어할 지 고려해보았습니다. 이 강의는 제가 고민하던 ORM의 단점을 심도있게 알려주었고, JPA의 그것과 SQLAlchemy의 그것은 큰 차이가 없음을 알게되자 작업속도가 생각보다 나기 시작했습니다.
요즘은 작업을 이렇게 수행합니다.
정도만 하니 문제 해결에 큰 어려움은 없었어요.
다만, 아직은 익숙치 않은 방법이라 시간이 꽤나 오래걸립니다. 적절한 테스트 방안도 모르고(필요에 따라 JUnit의 방안, 스프링의 방안을 살펴보는 건 기분탓이 아니더라구요), 이를 파이썬 영역에서 맞게 쓰는 것도 어렵구요.
이에 대한 내용은 2부에서 주요 기능 설계-객체설계-영속화설계-테스트를 한번에 살펴보도록 합시다.
감사합니다.