종류
-
어떤 스타일의 팀에, 어느정도 규모의 팀에 어울릴지. 무조건 좋은건 없음.
-
누구는 복합적으로 사용한다고 말할수도 있을텐데, 정확히 어떻게 나눠서 얘기할수있는가?
Monolith
Multorepo
-
독자적인 repository로 소스를 관리하는 방법
-
git을 사용할 경우 독자적인 repository를 하나의 repository 안에서 submodule로 구성/관리할 수 있음
-
Polyrepo 구조라고도 불림
-
각 프로젝트는 높은 자율성을 가지며, 독자적인 개발, 린트, 테스트, 빌드, 게시, 배포 파이프라인을 갖게 됨
-
팀의 자율성 때문에 선호하기도 함
-
단점
-
번거로운 프로젝트 생성
-
패키지의 중복 코드 가능성
-
관리 포인트 증가
-
일관성 없는 개발자 경험
-
다른 패키지의 변경 사항 파악
-
교차 리포지토리의 리팩터링 비용
-
-
일부 단점에 대해서 IntelliJ를 통해서 어느정도 해소 가능하나, 개발자 개개인의 도구 숙련도가 필요함
Monorepo
?
-
monorepo + 1 git repo
-
어떤 관심사로 repo를 모을 것인가?
-
-
multi git repo (monolithic?)
-
git submodules + multi git repo
-
intellij 에서 multi git repo에 대한 지원 활용
-
-
작은 토이 프로젝트가 아닌 이상 프로젝트는 점차 커지고 효율적인 관리를 위해 소스코드를 분리하게 됨
-
Spring Framework 기반에서 주로 아래와 같은 빌드 툴과 기능을 활용함
-
Gradle: multi-project 활용
-
Maven: Module 활용
-
-
프로젝트가 단위별로 나눠지는 것은 당연한 일이라고 할 수 있지만, 어떤 관점으로 어떻게 나누냐는 팀마다 다를 수 있음
Core
-
재활용이 가능한 중복 코드를 Core라는 패키지, 모듈, 프로젝트 혹은 저장소에 모아두는 구조
-
코어 기반 구조는 Common, Parent 등으로도 불려짐
장점
-
중복 코드 제거
-
중복 코드를 제거할 수 있다.
-
코드 재활용에 수월하다.
-
수정해야하는 비지니스를 한번에 관리할 수 있다.
단점
-
크기
-
시간이 지남에 따라 점점 비대해진다. 팀원이 많다면 더 빠른 속도로 증가한다.
-
-
접근성
-
누구나 비지니스 로직을 넣기 쉬워진다. 이는 다양한
-
-
컴포넌트를 분리하기 어려워진다(싫어진다)
-
빌드시간이 길어진다 (테스트 포함)
-
사이드 이펙트
-
런타임 오버헤드
-
쓰지도 않는 빈이 같이 올라간다. 부팅시간 올라감
-
-
빅브라더
-
스파게티 코드
-
한곳만 수정하면 되니 장점으로 말하는 사람도 있을테지만, 장점보다 단점이 더 크지 않은가?
-
-
의존성 덩어리
그럼?
-
무엇을 코어에 두어야 하나
-
코어라는 이름을 버릴까?
-
enum들이 적당
-
어노테이션, 각 코드(상수)
-
유틸, 익셉션, 엔티티, …
-
엔티티가 비지니스를 가졌다고 생각든다면 DB 테이블에 대해 추상화가 안된게 아닐까
-
-
client
Multi Module Project
특징
-
API 클라이언트들이 각 모듈로 나눠져있을 때,
build.gradle.kt
만으로 어떤 클라이언트들을 사용하지는지 명확하게 알 수 있음 -
API 클라이언트들이 각 모듈로 나눠져있을 때, 새로운 클라이언트 의존성을 추가할 때 gradle 리로드가 필요함(개발 속도)
-
너무 잘게 나눠져있을 경우, 새로운 코드짤 때 어디에 넣어야할지 고민하게 됨
-
불가피한 코드 중복이 발생하게 됨
-
e.g. DB저장용 Country, API 인터페이스용 Country, VO 개념의 Country
-
관리 방법
-
빌드 도구를 활용한 서브 모듈
-
js 진영에서는 monorepo(lerna), workspace(npm)
-
multi-project(gradle)
-
-
Git Repository 별로 분리
-
Git을 활용한 submodule 활용 가능
-
굳이 submodule repo를 만들지 않아도 IDEA 툴에서 원활하게 개발할 수 있도록 지원함
-
중복 코드에 대한 새로운 관점
-
리팩토링 책에서 중복 코드에 대해서 메서드 올리기를 통해 부모로 옮기라고 말하지만, 여기서 부모는 core 모듈을 말하는 것이 아닌 상위 호출자를 말하는거라 생각한다.
-
"부모로 옮긴다."에만 포커싱을 갖게 되면 결국 core가 만들어진다.
-
상위로 올리고, 유틸리티를 만들고, 부모가 커지는 느낌을 받는다면 다시 한번 전체를 살펴보자. (나무가 아닌 숲을 보기)
-
계층을 갖게되면 다른 고민/문제점이 발생함.
-
유연함을 생각하자
-
ApiClient 들은 서킷브레이커랑
WebClient
를 주입 받을 것인가? -
사용하는 곳마다 ReadTimeout, ConnectionTimeout이 다를텐데?
-
이와 같이 다를 경우가 얼마나 있을 것인지. 우선 통합해서 사용하다가 추후에 타임아웃 시간과 BaseUrl 정도만 주입받아도 충분할 듯
-
모든 중복을 제거할 순 없다.
코드 중복은 죄악이 아니다.
Core-Less?
-
어느정도 중복은 허용하자. 이젠 강력한 기능을 지닌 IDEA에서 중복코드 제거는 껌.
-
분리가 필요한 시기에 옮겨도 충분. 하지만 무지성으로 코드 중복 제거, 메서드 옮기기 하지 않고 중복을 유지하는게 더 낫다면 유지.
-
빌드 속도, 어플리케이션 실행 속도에 중점?
-
디펜던시는 모두 API를 호출하게끔? 이건 결국 API가 코어가 되는게 아닐까?
-
"그럼 무슨 문제가 있는가? 요즘 MSA 기반에서 무슨 문제인가?"
-
Etc
-
그럼 언제 구조를 변경할 것인가? core → core-less or multomodule, …
-
빌드 캐시
개인고민
팀원 모두 기술 수준, 이해도가 높다면 걱정 x 어떻게 얼만큼 제한할 수 있는지? 최소한의 제약을?? 패키지로?? 도메인으로?(이게 젤 어려움), 의존성으로?
References
-
https://kwonnam.pe.kr/wiki/web/%EC%8B%A0%EA%B7%9C%EC%84%9C%EB%B9%84%EC%8A%A4
-
https://kwonnam.pe.kr/wiki/web/신규서비스
절대 하지 말아야 할 일 : ecommerce-core 혹은 ecommerce-common 형태의 여러 도메인 비즈니스 로직을 모아둔 공통 모듈을 만들면 절대로 안 된다.