코틀린 멀티모듈 마이그레이션

Shaun·2024년 8월 3일
1

Kotlin

목록 보기
10/10
post-thumbnail

기존 회사 솔루션(자프링) 에서 코틀린+멀티모듈로 마이그레이션을 진행 하였다. 마이그레이션을 진행하면서 느낀점을 적어봤다.

기존 문제점

  • 버전 1을 만들고 난후 고도화 작업중 개선해야 문제점들을 나열해 봤다.

1.속도

  • 회사의 특성상 외부 오픈소스를 반드시 사용해야 한다. 여기서 가장 큰 문제점은 외부 오픈소스(LMS)에 너무 의존적이라는 점이다. 95% 의 API는 이 오픈소스와 통신을 해야하며 그러기 때문에 API의 속도들이 전반적으로 느렸다. 그 중에 특히나 성적이나 출석 같은 경우에는 모든 정보를 조회하고 계산까지 해야 했기때문에 속도가 너무 느렸다.

2.복잡한 코드

  • 외부코드에 의존적이다 보니 어쩔수없이 원하는 결과값을 출력하기 위해서 for문안에 for문 이런식의 복잡한 코드들도 많아 졌다.

  • 외부통신을 할때는 주로 oepnFeignm을 사용하였으며 외부 통신을 많이하다 보니 늘어가는 DTO등 코드량이 많아졌다.

3.모듈의 독립성

  • 한 프로젝트에 패키지로 모듈을 구분 해서 프로젝트를 진행 하였다. 프로젝트 초반에는 괜찮았지만 프로젝트가 점점 더 커지면서 서로 너무 의존적이라고 느꼈다. 왜냐하면 전혀 서로를 알지 못해도 되는 관계들도 많아졌으며 모르는 존재때문에 다른 모듈에 피해가가는게 너무 불편했다.

4.수정 로직 보장

  • 일을 하다보면 클라이언트의 변경 사항들과 그 복잡한 코드들을 고쳐가면 이게 제대로 고친건지 항상 찜찜했다. 항상 포스트맨으로 찍어볼 수도 없었다.

개선의 시작

1.자바 -> 코틀린

프로젝트 고도화 + 개선작업을 하면서 과감하게 언어를 자바에서 코틀린으로 변경했다. 자바와 코틀린의 장단점 비교글이 아니라 내용은 생략하고 크게 느꼈던 장점만 이야기 해보려 한다.

Java버전이 많이 올라가면서 코틀린을 의식했는지(?) 많은 기능들이 추가 되었다. 코틀린은 써본지 오래되지 않았지만 두가지 언어를 어느 정도 써본 입장으로서 자바와 비교했을때 더 명시적인 문법, null 안정성, 자바에서의 코드를 단 몇줄로 줄일 수 있는 장점등을 가지고 있기 때문에 코틀린을 선택했다. 자바에서도 코틀린과 비슷하게 문법을 만들고 있는것 같은데... 그렇게해서 굳이 자바를 쓸 이유도 없는것 같다.

또한 속도 개선을 위해 비동기 처리 방법을 알아보다 코틀린의 코루틴을 발견했고, 자바 비동기 처리 방식보다 가독성과 러닝커브가 조금 더 낮은 이유도 있다.

물론 코틀린도 단점이 존재 하기는 하지만 그렇게 크게 신경쓸만큼의 단점은 아닌것 같아 종합적으로 코틀린을 사용하기로 결정 했다.

2.속도 개선(NoSql + Scehduling)

이건 아니다 싶을정도로 속도가 느린 API가 있었고 이를 개선해야 겠다고 마음을 먹었다. 성능 개선을 경험이 적은 나에게 성능 개선의 방법들로는 당장 떠오르는 방법이 캐싱방법이나 인덱스를 태워서 성능 개선을 하는 방법이 뿐이였다.

하지만 문제가 있는 API는 자주 조회가 되지는 않고 여기저기 데이터를 종합해 한번할때 데이터 양이 많단는 문제라 적절하지 않다고 판단했다. (물론 내가 잘 못쓸수도 있다.)

그렇게 방법을 찾던 도중, 'NoSql' 이란걸 발견했다. NoSQL을 처음 접하면서 걱정이 많았지만, NoSQL의 장점을 살펴본 후 내가 원하던 고성능 읽기/쓰기, RDBMS에 비해 대용량 데이터 저장 가능, 그리고 Join이 필요 없는 구조 등 NoSql의 장점이 우리 요구 사항과 부합하여 적극 도입하게 되었다.

NoSql의 종류는 다양하지만 그 중에 'MongDB' 를 사용했다. 사실 많은 NoSql중에 이걸 택했을때는 레퍼런스도 많고 개인적으로 한번 써보고 싶은 욕심에 사용했다.

결론적으로 내가 사용한 방법은 mongoDb + 스케줄러' 미리데이터를 뽑아 놓는 방법이였다. 조회 속도야 기존 방법보다 32초 -> 0.4초 로 개선 되었다.

NoSql을 처음 써본거라 다양하게 써보지 못한점은 좀 아쉽기도 했다.

3.속도개선(코루틴)

Nosql 속도개선과 다른조건을 가진 순수 API 속도 개선을 할 필요가 있는 API들도 많았다. 로직적으로 코드를 최대한 수정했지만 한계가 있었다. 그래서 기존 프로젝트를 비동기 적으로 처리를 위해 코루틴을 적용 시켰다

사실상 코루틴은 아직도 적응중 이긴하다. 아직 완벽하게 쓰지는 못하고 그래도 한가지의 로직같은경우 어디에 비동기 처리를 적용해야할지 아는 수준인것 같다.

2초 -> 0.6 초/1.4 초 -> 0.8초 / 0.8초 -> 0.4/ 24초 -> 2초 정도로 평균적으로 60% 정도 시간이 줄은것 같다. 비동기 처리를 했을때 속도가 눈에 보이도록 감소 된걸 봤을때 너무 재밌었다. 코루틴에 대해서는 좀더 깊이 파볼 예정이다.

코루틴에 대해서는 따로 글을 작성해 보았다
https://velog.io/@wnsqud70/%EC%BD%94%EB%A3%A8%ED%8B%B4

4.수정 로직 보장

서비스 초반에는 몰랐다. 하지만 프로젝트가 점점 커지면서 요구사항이 수정되는 일도 많았고 기능이 추가되는 일도 많았다. 가면갈수록 관리 포인트가 늘어났으며 이 로직이 정상동작하는지도 보장하기 힘들었다.

테스트코드

예전에 들은적은 있지만 왜 사용하는지를 몰랐다. 하지만 정말로 필요성을 느끼며 이유가 있는 배움을 시작했다. 사실상 테스트코드를 처음 짜본 입장으로서 프로덕션 코드만큼은 아니지만 꽤나 큰 공수가 들어갔다. 안그래도 다듬을곳이 많은데 테스트 코드를 작성하는 입장에서 꽤나 스트레스도 많이 받았다.

하지만 테스트 커버리지 95%를 달성하고 이처럼 든든할수가 없었다. 변경되는 로직이나 새로운 기능이 추가되도 전혀 두려움이 없었다. 초반에는 바뻐 죽겠는데 테스트 코드까지 작성하니 약간은 손해 보는 느낌이 들었으나 가면갈수록 프로젝트는 변경사항이 추가될걸 생각하면 장기적으로 봤을때는 이게 더 우리에게 편하고 안전한 방법 이였다.


테스트 코드같은 경우는 PresentationLayer / BusinessLayser / PersistenceLayer 로 나눠서 진행 했으며 외부통신부분은 MockBean처리를 해서 진행 하였다. (참고로 나는 Classicist)

테스트 코드 관련해서는 글로 한번 정리 했다
https://velog.io/@wnsqud70/TestCode

5.모듈의 독립성

솔루션을 개선하면서 가장 어려웠던 부분이였다. 물론 멀티모듈의 난이도가 쉽지는 않으며 아예 처음이였고 년차가 비슷한 동료들끼리 그냥 유투브랑 블로그 보면서 진행을 한거라 쉽지는 않았다.

정상 동작하고 있는 프로젝트를 왜 뜯었을까? 답은 의외로 간단했다.우리 프로젝트의 각 모듈들은 서로 너무 짱짱하게 묶여 있었다. 모듈의 입장에서 내가 한일도 아닌데 내가 왜 혼나야하지? 라는 느낌일 것이다.
쉽게 말하면 a모듈은 b모듈을 알필요가 없는데 b모듈 때문에 a모듈이 피해를 보는것!

멀티 모듈의 장점을 간략하게 설명 하자면 각각의 모듈들은 서로 독립적이라 서로에 대한 영향력 이 최소이다. 기존같았으면 implments를 한곳에서 다하고 각 모듈에서 몰라도 되는 정보까지 implments를 했다. 멀티 모듈을 시작하면서 가장 큰 장점은 각각 모듈이 알아야할것만 gralde에서 implments 하면 된다. 또 하나의 장점은 모듈들이 독립적이니 뜯거나 붙이기 너무 편했다.

물론 행복하지만은 않았다. 초반에 멀티모듈 세팅을 할때가 정말 많이 힘들었다. 모듈은 어떻게 나눌것이며 하는 방법도 몰랐다.
https://www.youtube.com/watch?v=PdofVTuM-tE
멀티모듈 초반 세팅같은 경우는 제미니님의 유투브를 참고 했다.

모듈을 나눌때 최대한 잘게 독립적이게 나누었다.

6.복잡한 코드

Java

Kotlin

이 부분에서는 언어를 코틀린으로 바꾸면서 체감이 많이 됬다. 코틀린 문법상 자바보다 가독성도 좋고 코드양도 확실히 많이 줄었다.

facade패턴

코드의 복잡도를 낮추기 위해 눈이 들어온 부분은 businessLayer 였다. 서비스 레이어는 한눈에 봤을때 비지니스 로직만 딱 보여야 한다고 개인적으로 생각한다. 하지만 기존 코드는 구현체로 덕지덕지 붙은 코드 였다.

어떻게 정리를 할까 하다가 눈에 들어온 패턴이 facade패턴이다. 서비스단에 덕지덕지 붙은 객체들을 정리를해주면서 깔끔하게 비즈니스 로직만 보여주기에 적합하기 때문에 이 패턴을 선택 했다.

퍼사드 객체를 사용하는 곳(Client)에서는 여러 서브 클래스들을 호출할 필요 없이 편리하게 사용할 수 있으며 결합성도 낮아졌다.

결론

기존 버전1에 비해 많은것을 개선한것처럼 보이지만 앞으로도 고쳐야할 부분이 많다. 그래도 예전에는 이런게 있어도 왜 사용하는지 몰랐다. 하지만 필요성을 느끼고 직접 사용해보니 왜 사용하는지 알게 됬고 이러한 해결법을 사용하니 이제 그에따른 또다른 학습이 필요하다고 느끼고있다. 꼬리에 꼬리를 무는 필요성에 근거한 학습은 참 재밌는것 같다. 이게 개발의 매력이 아닐까 싶다.

최근 문제는 다른 성적이나 출석 서버를 따로 떼서 사용하고 있다. 이것외에도 db나 redis 등등 docker로 떠 있는게 대략 9개 정도 되는것같다. 자연스럽게 관리포인트가 많아지며 쿠버네티스에도 관심이 가고 있다. 그 외에도 변수 관리등등 고칠점이 참 많다. 차근차근 방향을 잡고 진행해 봐야겠다.

profile
호주쉐프에서 개발자까지..

0개의 댓글