이번에 새로운 프로젝트에 들어가면서, 백엔드 파일들을 새롭게 만드는 일이 많았다.
당연히 처음에는 기존의 컨벤션 대로 파일들을 만들었는데, 작업하는 과정에서 불편함을 많이 겪었기 때문에...😢 좀 더 나은 파일명 or 폴더 구조가 없을지 고민하게 되었다.
처음에는 내가 만드는 파일들에 대해서만 새로운 방식을 적용했었는데, 해보니 꽤 괜찮았어서 팀 차원에서 함께 논의하게 되었다.
기존에 백엔드의 폴더 구조는 대충 아래와 같았다.
전형적이라면 전형적이라 할 수 있는 Node.js의 폴더 구조 였다.
기본 파일명들은 모두 도메인 명을 따랐다.
src/server
├── constants
│ ├── post.js
│ ├── review.js
│ └── like.ts
├── controllers
│ ├── postApi.js
│ ├── reviewApi.js
│ └── likeApi.js
├── models
│ ├── project
│ │ └── index.js
│ └── user
│ └── index.js
├── routers
│ ├── post.js
│ ├── review.js
│ └── like.js
├── service
│ ├── post.js
│ ├── review.js
│ └── like.js
└── utils
├── post.js
├── review.js
└── like.js
기본적으로는 기술적인 역할 (controllers, middlewares, models, routers…)을 바탕으로 폴더를 나누고, 그 안에 도메인만으로 파일명을 정해서(project.js, container.js) 파일들을 구성하는 식이었다.
위에서 간단하게 작성한 폴더 구조 하에서만 해도, post.js 파일만 6개나 있다.
기본적으로 한 도메인에 대한 작업을 수행하다보면 관련된 파일들을 함께 여는 경우가 많다 보니, 탭 매니저는 동일한 파일 이름으로 가득 차게 된다. 😭
이러한 상태에서 작업하다 보면 현재 어떤 파일에 있는지 혼동이 오고, 이는 생산성에 부정적인 영향을 미칠 수 있다.
파일명 검색에서 파일을 찾은 경우에도, 보통 [도메인명 → 기술적 역할명] 순으로 생각이 나는게 직관적이었다.
그래서 ‘post에 대한 service를 찾아야지~’라는 생각으로 postservice를 입력하면 원하는 파일을 찾을 수 없었다.
(servicepost로 입력해야 찾을 수 있다)
파일명 검색을 할 때 반드시 [기술적 역할명 → 도메인명]으로 찾아야 한다는 것이 단점으로 느껴졌다.
node best practice의 project structure 챕터에는 다음과 같이 설명되어 있다. 링크
최소한 해야 할 일은 구성 요소 사이에 기본 경계를 만들고 각 비즈니스 구성 요소에 대해 프로젝트 루트에 폴더를 할당하고 독립적으로 만드는 것입니다. 다른 구성 요소는 공용 인터페이스 또는 API를 통해서만 기능을 사용할 수 있습니다. 이는 구성 요소를 단순하게 유지하고 종속성 지옥을 피하며 향후 앱이 성장하면 완전한 마이크로 서비스로 가는 길을 닦는 기반입니다.
현 상황에서는 기술적 역할을 바탕으로 폴더를 나누고 있어서, 다양한 비즈니스 도메인들에 대한 파일들이 한 폴더 안에 뒤섞여 있다.
이렇게 되면 서로 간의 참조도 규칙 없이 이루어질 가능성이 높다.
장기적으로는 해당 파일들을 비즈니스 도메인/모듈 별로 구분하고, 프로젝트를 모듈화하는 작업이 필요하다고 느꼈다.
파일명에 도메인 내용, 기술적 역할이 동시에 담겨있는 형식이 좋다고 생각한다.
디렉토리와 조합할 필요 없이, 파일명 만으로 해당 파일에 담겨있는 로직들을 설명이 가능해야 한다고 느꼈다.
개인적으로는 Angular.js에서 차용하는 방식을 채택하는게 좋다고 느꼈다. 참고 링크
바로 도메인명.기술적역할.js
형식이다.
현재의 폴더 구조에 적용한다면 다음과 같다.
src/server
├── constants
│ ├── post.constant.js
│ ├── review.constant.js
│ └── like.constant.ts
├── controllers
│ ├── post.api.js
│ ├── review.api.js
│ └── like.api.ts
├── models
│ ├── post.model.js
│ ├── review.model.js
│ └── like.model.ts
├── routers
│ ├── post.route.js
│ ├── review.route.js
│ └── like.route.js
├── service
│ ├── post.service.js
│ ├── review.service.js
│ └── like.service.js
└── utils
├── post.util.js
├── review.util.js
└── like.util.js
만약 도메인명이 2단어 이상으로 구성된다면(ex. d2hubRepositoryService), 중간에 hypon을 삽입하면 된다.
ex) d2hubRepositoryService.js
→ d2hub-repository.service.js
이렇게만 해도 파일명 만으로 해당 파일의 역할을 명확하게 알 수 있다.
파일명 변경에서 더 나아간다면, 프로젝트 폴더 구조 자체를 변경해서 모듈화를 진행할 수도 있을 것이다.
(다만 이거는 너무 큰 변화이다 보니, 안전하게 진행하려면 각 로직에 대한 단위 테스트 작업이 먼저 이루어지는게 적절하다고 생각한다)
src/server
├── post
│ ├── post.api.js
│ ├── post.model.js
│ ├── post.route.js
│ ├── post.service.js
│ └── post.controller.js
├── review
│ ├── review.api.js
│ ├── review.model.js
│ ├── review.route.js
│ ├── review.service.js
│ └── review.controller.js
├── like
│ ├── like.api.js
│ ├── like.model.js
│ ├── like.route.js
│ ├── like.service.js
│ └── like.controller.js
└── ...
기술적 역할도 파일명에 들어가기 때문에 기본적으로 파일명의 길이가 2배가 된다.
여기에 만약 앞 단의 도메인 명이 길어지기라도 한다면, 파일명은 걷잡을 수 없이 길어질 수 있다
다만 이 부분은 도메인명이 지나치게 길어진 것 자체가 문제일 수 있다.
도메인 이름은 의미를 명확히 할 수 있도록 가능한 간결한 것이 좋다.
도메인 명을 짧게 유지하려고 노력하는 것도 좋은 구조를 짜는 하나의 방식이라는 생각이 든다
파일명을 변경하는 과정에서 기존의 git blame이 덮어씌어지기 때문에 불편할 수 있다.
작은 규모의 프로젝트라면 모르겠지만, 레거시 코드가 많이 쌓여있고 테스트 조차 잘 작성되어 있지 않은 상태라면 중요한 이슈가 될 수 있다.
따라서 가능하면 테스트 코드를 작성하면서, 각 로직들에 대한 정리가 함께 이루어지면서 파일명을 변경하는게 좋을 것 같다고 생각했다.
팀 내에서 해당 파일에 대한 이해도가 충분히 쌓였을 때 하나씩 바꿔가는게 좋을 것 같다는 생각이다.🤔