목차
들어가기에 앞서 큐샵에 대해 부연설명이 필요하다.
- 관리자가 직접 사이트를 생성하고 편집할 수 있는 UI/UX 중심의 에디터 레포지토리 (이하 ED)
- 관리자가 사이트의 설정을 관리하고 지정할 수 있는 어드민 레포지토리 (이하 AD)
- 관리자가 만든 사이트를 실제 고객들이 사용할 수 있도록 구현된 라이브 레포지토리 (이하 LP)
나는 커머스 팀 소속으로서 엄밀히 업무 분배를 나누자면 ,
LP 안에서도 에디터 팀이 작성한 코드는 에디터 팀이 관리하고, 그 외 모든 영역은 내가 관리한다.
어느날 에디터팀 경수님과 가벼운 얘기 도중, 상당히 특이한(?) 방식으로 업무가 진행되고 있다는 것을 뒤늦게 깨달았다.
그 분께 여쭤보니, ED 에서 설정한 버튼이나 아코디언 등의 요소 코드를 LP 에 복붙 하여 사용하고 있다는 것이다.
혹여라도 ED 에서 코드를 수정하고 LP 에 반영하지 않는다면 말짱 도루묵이란다. 🤦🏻♀️ (조금 충격을 먹었다..)
이전까지 ED 코드는 평소 살펴볼 일이 없었지만, 프로젝트 규모가 커지고 함께 협업하는 일이 많아짐에 따라 공통 모듈화에 대한 필요성을 느꼈다.
아무래도 내가 직접 짠 코드가 아니기 때문에 경수님의 도움을 받아, 함께 사내 사이드 프로젝트 식으로 큐샵 서브모듈 프로젝트를 시작하게 되었다.
서브모듈을 선택하게 된 이유는 아래 글에서 따로 정리해두었다.
1. 공통 모듈 범위 정하기
서브모듈 작업 전, 어떤 부분들을 공통화 해야할지 정해야 했다.
중복되는 코드라고 전부 공통모듈에 넣었다간 오히려 사이드이펙트가 생길수도 있는 일이었다.
첫 시작인 만큼 변동사항이 가장 적고 의존성이 없는것들로 추렸다.
아이콘

일단 가장 dependency 가 없는 아이콘 svg 파일부터 추리기로 했다.
서브모듈 적용할 경우, 경로는
@sub
로 시작되고 나머지 경로는 동일하게 적용하여 혼선이 없도록 했다.Style Util

마찬가지로 공통적으로 static 하게 공통적으로 사용되는 스타일 관련 utils 객체들을 모듈화 하기로 했다.
특히 해당 코드들은 두개의 프로젝트 뿐만 아니라 어드민 레포지토리에서도 공통적으로 사용되기 때문에
추후에는 더 세분화 하여, 따로 모듈화가 가능할 것 같다.
하지만 이번은 처음이니 일단 이번 task 에 넣는걸로!
Slime 코드

Slime 코드는 에디터에서 사용자가 설정할 수 있는 버튼, 아코디언 등과 같은 블록들을 지칭한다.
처음에 단순하게 Slime 디렉토리 하위의 중복되는 모든 컴포넌트를 옮기면 될거라고 생각했지만, 곳곳에 묘하게 분기처리가 된 코드들이 존재해서 공통점을 찾아보았다.

각각의 Slime 컴포넌트는 Wrapper 로 한번 더 감싸져 있고, 그 Wrapper 컴포넌트 내부에서 복잡한 로직이 구현되고 있었다.
그 복잡한 로직 구현만 다르고, 하위에 실제 UI 를 그리는 컴포넌트는 완벽하게 동일했다.
간혹 Wrapper 로 감싸져 있지 않은 Slime 컴포넌트는 경수님께 코드 분리를 부탁했고, 일단 UI 컴포넌트만 공통 모듈화 하기로 했다.
비즈니스 로직까지 한꺼번에 고치기엔 양도 방대하고 분명 사이드이펙트가 발생할 것 같아 점진적으로 수정해가기로 한다. 이것까지 바꾼다면 그저 죽음뿐.
2. 서브모듈 초기 구축하기
테스트를 위해 각 세개의 레포를 구축하였다.
ED : 에디터 레포지토리 LP : 라이브 레포지토리 Next-Submodule : 에디터와 라이브의 공통 스타일 컴포넌트가 담길 서브모듈 레포지토리
서브모듈 레포지토리 생성
공통으로 사용할 코드 작업 후 push
서브모듈의 역할은 에디터와 라이브에서 공통으로 쓰일 컴포넌트만 작업하기 때문에 간단하다.
똑같이 레포지토리를 생성하고 내가 공통으로 사용할 컴포넌트 작업을 한다.
나같은 경우 테스트로 버튼 과 드롭다운 을 생성하여 commit , push 했다.
( 추후 설정 문제로 골머리를 썩고싶지 않으면 버전을 동일하게 가져가는것이 좋을 듯 하다. )
서브모듈을 push 까지 하고 난 후 아래의 명령어로 해시값을 확인하면 현재
febff4e
인것을 볼 수 있다.
git remote -v
로 현재 서브모듈의 저장소 위치 알아내기.
에디터와 라이브에서 적용하기 위해서 서브모듈의 저장소 주소를 알아두어야 한다.

에디터와 라이브에 서브모듈 추가하기
- 에디터와 라이브에 다음 명령어로 추가한다.
- 만약 특정 디렉토리를 생성하여 추가하고 싶다면 저장소 뒤에 생성할 디렉토리 이름만 추가하면 된다.
에디터/라이브 레포에 추가하면 내가 설정한 경로에 next-submodule 레포와 .gitmodules 가 생성될것이다.
- .gitmodules 파일
cd next-submodule
로 들어가서git log
를 찍으면 서브모듈 레포에서 찍은 해시값과 동일한것을 확인 할 수 있다.

서브모듈이 적용된 에디터, 라이브 push 하기
가져온 서브모듈의 컴포넌트가 잘 동작한다면 push 를 진행.
위에서 설명한대로, 서브모듈의 코드 자체가 올라가는것이 아니라 최신 해쉬값을 가진 서브모듈이 연결되어 올라가게 되는것을 볼 수 있다.


3. 서브모듈이 적용된 프로젝트 이용법
서브모듈 초기 클론
세팅해놓은 서브모듈이 적용된 ED,LP가 올라가면 다른 개발자들은 필요에 따라 각 레포를 업데이트한다.
초기에 서브모듈이 적용된 프로젝트를 클론하거나, 서브모듈이 적용된 브랜치를 이용한다면 처음에는 빈 디렉토리 밖에 보이지 않는다.
- submodule init 을 통해 .gitmodules 에 기입된 정보를 기반으로 로컬에 환경설정을 한다.
- update를 통해 리모트 저장소에서 데이터를 가져온다
수정 된 서브모듈 적용하기
서브모듈에서 수정 된 코드가 있다면 에디터, 라이브 레포지토리에서도 수정된 코드가 반영되어야 한다.
서브모듈은 최신 해시값을 통해 반영되는 독립적 프로젝트이기 때문에 에디터/라이브 루트 경로에서 아무리 git pull 해도 소용이 없다.
- 첫번째 방법 :
cd next-submodule
명령어로 들어와 git pull origin next-submodule 을 하여 적용한다
- ✨ 두번째 방법:
submodule update --remote
- 원격 저장소의 최신을 로컬 저장소에 바로 업데이트
- 만약 업데이트만 한다면 가장 마지막 커밋으로 업데이트가 된다.
두번째 방법을 사용하여 next-submodule 로 경로이동 없이 루트에서 바로 서브모듈을 업데이트 하니 변경되는것을 볼 수 있다.


4. 주의사항
경로 및 환경설정
에디터/라이브 에서 next-submodule 에 있는 컴포넌트를 절대경로로 가져오기 위해 jsconfig.json 에 path 를 추가한다.
에디터에서 서브모듈의 버튼을 import 하니 다음과 같은 에러가 발생한다.

그 이유로, 서브모듈의 스타일 절대경로도
@/styles
로 시작하고 부모레포의 절대경로도 @/styles
로 설정되어 있기 때문에 경로가 충돌되어 에러가 발생하는 것이었다.
처음부터
@sub/*
으로 해두었으면 좋았겠지만 어쩔 수 없이 둘 중 한 레포의 경로를 바꿔야 했다. 코드양이 더 많은 에디터/라이브 의 styles 는 그대로 두고 서브모듈에서 가져오는 컴포넌트는
@sub/*
, @sub/styles/*
로 path 를 구분하는 방향으로 해결했다. 실제로 서브모듈을 도입한다면 구분을 확실히 할 수 있도록 경로설정 에도 신경을 써야 할 것 같다.
경로 외에도, 서브모듈에 라이브러리가 많거나 웹팩 & 바벨 설정한 프로젝트라면 그만큼 환경설정 할것들이 많아 질 수 있다.
왠만하면 라이브러리 버전의 통일하고, 번들러를 구성하다면 웹팩에 추가 로더가 필요할 수도 있다.
필수적인 커뮤니케이션, 그리고 깃관리
그렇다면 서브모듈이 적용된 후 작업을하며 깃관리는 어떻게 진행되어야 할까 ?
서브모듈 파일 수정 후 부모레포에서 git status 를 치면 다음과 같이 next-submodule 이 수정된것으로 나온다.

서브모듈의 해시값이 변경되면 기존에 서브모듈을 이용하던 레포에서
git diff
명령어를 통해 서브모듈의 해시값과 diff가 발생됨을 확인할 수 있다.
이 과정에서 서브모듈을 이용하는 레포는 서브모듈의 코드를 저장하는 것이 아닌, 해당 서브모듈의 해시값을 저장함을 한번 더 알 수 있다.

만약 만약 고의든 실수든 에디터/라이브 레포에서 서브모듈을 변경했을 경우,
cd next-submodule
경로로 들어가 똑같이 git commit/push 를 진행하면 된다.
이럴경우 동일한 서브모듈이 적용되어있는 라이브페이지도 동시에 변경이 되기 때문에 주의가 필요하다.
우리는 변경된 해시값을 레포에서 커밋으로 남김으로써 이력관리를 하기로 팀원들과 약속했다.
5. 짧막한 사용 후기
이 방식이 정답인지 확신이 들지는 않지만, 감사하게도 팀원들이 아직까지 잘 써주고 있다.
우려했던 Slime 코드도 생각했던 것 만큼 수정 및 기능추가가 되고 있지 않아 당분간 유지되지 않을까 싶다.
하지만 언제든 기획이 추가되고 버그도 생길 수 있기 때문에 잦은 수정에 대한 위험부담감이 있다.
나중에 회사 규모가 더 커지고 충분히 관리체계가 잡힌다면, 그때 모노레포로 변경하는것이 좋을 것 같다.