Offroad의 멀티모듈 도입기

GongBaek·2024년 7월 3일

지난 이야기

지난 게시글에서 사실 멀티모듈에 대해 다룬 적이 있지만, 아쉬운 부분이나 앱잼을 위해 알아둬야 할 개념이 있을 것 같아서 글을 남깁니다.

이번 인풋안드에서 역시 멀티모듈을 도입하는 팀이 여럿 있다고 들었는데, 와비분들의 가랑이가 찢어지지 않게 열심히 같이 달려봐요...!

모듈? 멀티모듈?

지난번에도 말했듯, 모듈이란 소스 파일 및 빌드 설정으로 구성된 모음입니다. 멀티모듈은 결국 하나의 프로젝트를 여러 개의 기능 단위로 분리하여 구성하는 방식입니다.

멀티모듈의 가장 큰 장점?

사실 멀티모듈에는 테스트 용이, 관심사 분리 등 여러 장점이 있습니다. 하지만 대부분의 개발 과정에서 테스트를 직접 해보는 일이 흔한 일도 아니고, 관심사 분리라고 하면 눈에 보이지 않죠?

저희가 Build를 할 일은 언제일까요? 크게 세 가지가 있습니다.

  • 배포
  • 테스트
  • 개발

이 중에서도 저희는 개발할때 가장 빌드를 많이 하게 됩니다.

저희가 와닿게 표현할 수 있도록 예시를 들고왔어요. 구글이 조사한 바에 따르면 대기시간이 1초가 지나면 사용자의 주의력이 분산되고, 10초가 지나면 이미 사용자는 다른 일을 하고 있게 된다고 합니다.

이는 비단 서비스 사용자에게 국한되는 일이 아니라 개발자의 입장에서도 같습니다. 멀티모듈은 빌드시간을 유의미하게 단축시켜준다는 현업에서의 가장 큰 장점이 있습니다.

이는 빌드가 프로젝트 전체가 아닌 해당 모듈 에서 진행되기 때문인데요,
제가 참고한 블로그에서도 아래와 같이 유의미한 결과를 낼 수 있었죠

멀티모듈 좋기만 할까?

빌드 시간, 테스트 용이, 관심사 분리... 멀티모듈 무조건 써야지! 왜 안쓸까요?

우선 첫째로, 단순한 앱은 오히려 빌드시간이 증가할 수도 있습니다. 기본적으로 들어가는 코드 자체가 많아 불필요하게 코드만 뻥튀기될 수 있어요.

두 번째로, 멀티모듈 어렵습니다. 저도 열심히 공부한다고 계속 분석하고 있지만, 항상 정답이 없는 부분입니다. 사람마다 모듈을 나누는 방식도 다르고, 그 나누는 방식마다 장단점이 있습니다. 이를 위해서는 아키텍처에 대한 이해도가 어느정도 필요합니다. 처음 코드를 보거나 모듈이 많아진다면 의존도 관리 역시 어렵게 됩니다.

그럼 안쓸거야?

저희 Offroad Team에서는 이번에 멀티모듈을 도입하기로 했습니다. 일단 부딪쳐보고 배워보자는 느낌으로요.

겪어보지 않는다면 왜 좋고 왜 안좋은지 알 수 없잖아요?

좀 더 자세히 알아보자

흔히 나누는 Domain, Data, Feature 등의 계층별 모듈 분리는 면접시험같은데서 쓰이는 것이고, 현업에서는 잘 사용하지 않는다고 네이버 관계자분이 드나에서 강력하게 발표하시더라구요?

이 부분에 착안해서 이번 모듈 분리를 시작해 보았습니다.

계층별 모듈분리의 경우 서비스에서 Domain 모듈에 변화가 생긴다면 결국 Presentation 모듈에서도 변화가 생길 것이고, 이러한 변화는 새로운 컴파일을 요구합니다. 따라서, 기존에 제시된 빌드시간 단축이라는 멀티모듈의 장점을 활용할 수 없게 돼요 🥺

특히 새로운 기능을 추가하고 계속해서 뷰를 그려나가는 앱잼 특성상 모든 계층에서 여러명이 한번에 달려들어 빈번한 수정작업이 이뤄지곤 하죠.

게다가 당장 테스트 코드를 작성하고 진행할 것이 아니기 때문에 멀티모듈의 다양한 장점들을 활용할 수 없다고 생각했습니다.

🚨 이 부분은 어디까지나 정답이 없는 부분이라 이 프로젝트에서는 이렇게 진행했구나~ 정도 알아주시면 좋을 것 같습니다.

그래서 이전 게시글에서 나왔던 것처럼 기능과 계층의 혼합분리가 가장 베스트일 수도 있지만,
이 역시 모듈이 많아지며 의존성 관리가 어렵다는 단점도 존재해요...!

그래서 저희는 드나에서 소개되었던 Feature를 기준으로 모듈을 분리하고 앱잼을 진행해보고자 합니다.

우선 저희 팀은 모듈을 위와 같이 구성하였습니다.
그 중에서도 자주 접하게 되는 몇 가지에 대해 알아보도록 하죠.

우선 build-logic 입니다.

build-logic 모듈은 Gradle 빌드 설정과 관련된 로직을 포함합니다. 이 모듈은 프로젝트 전반에 걸쳐 공통적으로 사용되는 빌드 설정을 관리합니다.

여러 모듈을 생성하다 보면 수많은 gradle 파일이 생성되고, 중복되는 코드 또한 많아집니다. 하지만 gradle convention의 제작을 통해 획기적으로 코드 양을 줄일 수 있다는 장점이 있습니다.

import com.teamoffroad.app.setNamespace

plugins {
    id("offroad.android.feature")
    alias(libs.plugins.jetbrains.kotlin.serialization)
}

android {
    setNamespace("feature.home")
}

dependencies {
    implementation(libs.retrofit.kotlinx.serialization)
}

평소보다 gradle 파일이 굉장히 날씬해진 것을 볼 수 있죠?

프로젝트에서 사용된 build-logic 의 구조입니다.
DroidKnights와 nowinandroid 레포지토리 코드를 참고하였습니다.

위 컨벤션 내부에 gradle에서 중복될 수 있는 공통되는 코드를 작성하고,
Plugin을 통해 적용시키는 구조라고 보면 쉬울 것 같습니다!

이러한 build-logic 을 만드는 방법 역시 굉장히 다양하니,
관심이 있으시다면 공부해보시면 좋겠습니다.

다음으로 core 입니다.

core 모듈은 주로 앱의 핵심 비즈니스 로직과 공통 유틸리티를 포함합니다. 이 모듈은 여러 feature 모듈에서 재사용될 수 있는 로직을 관리합니다.

원래라면 여기에 domaindata 가 들어있어 core 모듈에서 재사용하는 경우가 꽤 있는데,

저희는 간단하게 공통되는 디자인 요소나 네비게이션, 확장함수, 레트로핏 모듈 등을 위치시킬 목적으로 사용하였습니다.

마지막으로, feature 입니다.

feature 모듈은 앱의 개별 기능을 독립적으로 개발하고 관리할 수 있도록 도와줍니다. 각 feature 모듈은 특정 기능과 관련된 모든 코드를 포함합니다.

위와 같이 각각의 feature 내에서 패키지로 관심사를 분리하였습니다.
물론 이렇게 진행하는 것이 장단점이 있을 수 있어요!

중복되는 코드를 관리하기가 애매해질 수 있고,
불필요한 의존성이 생겨날 수도 있습니다.

하지만 앞서 나왔듯, 여러 팀원이 달려들어 빈번한 수정이 발생하고,
테스트를 진행하지 않는다는 앱잼 특성을 고려해 선택한 방법입니다.

추후 개발을 통해 이러한 방식의 문제점을 발견한다면
data, domain을 feature 밖으로 꺼낸다거나,
feature 내부에서 다시 한 번 모듈을 분리
할 수도 있겠죠?

이는 어디까지나 개발을 진행하면서 맞춰갈 수 있는 부분이라고 생각합니다! 다시 한 번 말씀드리지만 정답은 없는 부분이니까요 😁

의존성 주입 이야기

의존성을 주입하는 방법에는 여러가지가 있겠지만,
구글에서는 현재 Dagger-Hilt를 공식적으로 권장하고 있는 것으로 알고 있어요.

이 이야기도 말하자면 길어서...! 저번 명석님의 세미나에서도 진행했고...!
제가 공부했던 참고 영상 링크만 남겨드리고 넘어가겠습니다.

아키텍처 이야기

저희는 구글 권장 아키텍처만 사용해본 팀원들끼리 모여서,
이번엔 클린 아키텍처를 시도해보자! 라는 이야기가 있었답니다.

사실 방법론적인 부분은 이미 구글에 차고 넘쳐서 사용법을 이야기하기 보다는,
제가 공부한 내용을 살짝 정리해드릴까 합니다.

아래를 보시면 굉장히 익숙한 과녁 그림을 볼 수 있습니다.

클린 아키텍처란 과녁모양에 앱을 끼워 맞추는 단순한 방법론이 아닙니다.
가장 중요한 부분인 의존성의 분리 라는 점을 놓쳐서는 안된다고 꽤 많은 분들이 강조하고 있어요.

사실 지금까지 헥사고날, 어니언, 스크리밍 등과 같이 굉장히 많은 아키텍처가 존재해 왔고,
우리는 그만큼 많은 서비스에서 다양한 아키텍처를 쓰고 있습니다.

계층의 완벽한 분리란 아무리 노련한 개발자라도 어려운 부분이고,
이 부분에 대해서는 항상 다양한 방면으로 논의가 되고 있습니다.

  • Q. 여러분은 도메인이 무엇이라 생각하시나요? 꼭 필요한가요?
  • Q. 클린 아키텍처에서 도메인이 빠진다면 어떻게 이루어질까요?
  • Q. 어디까지가 UI의 역할이고 어디까지가 도메인의 역할일까요?

위 질문에 간단하게 대답이 가능하시다면,
이미 어느 정도 공부해본 사람일 수도 있겠지만요.
사실 제가 요즘 고민중인 부분이라서요 🤔

의존성이 의도한 방향으로 주입되고 분리되기만 한다면 결국 아키텍처는 수단에 불과할 뿐이며,
클린 아키텍처라는 과녁에 퍼즐을 맞추는 것을 목표하기 보다는 각자 프로젝트에 맞는 형태를 찾아나가는 것이 바람직하다고 생각합니다!!
그래서 이것저것 시도해보는 부분이기도 하구요.

사실 글을 마치는 마무리 멘트였는데요,
팀원과 함께 논의하면서 각자 프로젝트에 맞는 방향을 찾아나가는 과정 역시 크게 성공할 수 있는 기회라고 생각합니다.
앱잼 내에서는 무지막지한 커스텀뷰나 빡구현 등을 진행하느라 이런 고민을 깊게 안해보고 끌려다닐 수 있을 것 같아서 노파심에 적어봐요 🤣

진짜 무엇보다도 앱잼은 행복해야 한다고 생각하거든요.
구현도 좋고 개발도 좋지만 다같이 소중한 추억 하나정도는 남기고 오는 합숙이 되었으면 좋겠습니다.

제 마지막 미미나에 함께해주신 여러분께 감사드립니다. 파이팅 🔥🔥

profile
Junior Android Developer

0개의 댓글