본문으로 건너뛰기
2026. 6. 30·약 6분

백엔드 도구들, FE로 치면 무엇일까요?

열린 상자에서 렌치와 톱니바퀴, 빨간 정육면체가 솟아 있는 그림

첫 PR을 올리기까지 코드보다 도구와 싸운 시간이 길었습니다. 커밋하면 처음 보는 린터가 막아서고, 빌드 파일은 어디를 고쳐야 하는지 모르겠고, 테스트를 돌리려니 Docker를 켜라고 합니다. 하나씩 읽다 보니 포맷 검사나 빌드 설정처럼 익숙한 역할이 보였습니다. 반면 DB를 옮기고 변경 이력을 남기는 도구는 사용법부터 새로 익혀야 했습니다.

백엔드의 도구들은 FE의 무엇에 대응하고, 대응물이 없는 도구는 왜 없을까요?


이 글에서 다루는 내용​

시리즈의 마지막 글입니다. 코드 품질(ktlint·detekt), 빌드와 구조(Gradle 멀티모듈, 템플릿 레포, 도메인별 레포 분리), 테스트(Testcontainers)를 익숙한 FE 도구와 비교하고, 저장된 데이터를 다루는 도구도 살펴봅니다. 끝에는 시리즈 전체의 FE ↔ BE 대응표를 한 장으로 모았습니다.





코드 품질: ktlint와 detekt​

커밋을 막아섰던 린터는 ktlint와 detekt였습니다.

도구하는 일FE 대응물
ktlint포맷 검사와 자동 수정Prettier
detekt코드 스멜·복잡도 정적 분석 (긴 메서드, 복잡한 조건식 등)ESLint

익숙한 도구와 역할이 비슷해 이해하기 쉬웠습니다. 흥미로웠던 것은 baseline이라는 장치입니다. detekt를 기존 코드베이스에 도입하면 위반이 수백 개씩 나오는데, 그걸 다 고치는 대신 현재 위반 목록을 스냅샷으로 얼려두고 새로운 위반만 막습니다. 레거시 코드 곳곳의 eslint-disable 주석을 파일 하나에 모아둔 것과 같은 개념입니다.

여기서 한 가지 데인 것이 있습니다. baseline 항목은 코드 위치가 아니라 코드 내용을 서명으로 기억합니다. 수정한 부분이 서명에 포함되면 기존 항목과 매칭되지 않아 "새 위반"으로 드러날 수 있습니다. 저는 이를 관련 코드를 고칠 때 남아 있던 문제도 함께 살펴보는 계기로 삼았습니다. 다만 이 빚을 갚는 방법은 구분해야 합니다. 다른 사람이 남긴 위반이 다시 드러난 것이면 baseline을 갱신할 수도 있지만, 내가 새로 만든 위반은 baseline에 얼리는 게 아니라 리팩터링으로 없애는 것이 맞습니다.




빌드와 구조: Gradle, 템플릿, 레포 경계​

구조를 만드는 도구들은 이 시리즈에서 이미 여러 번 등장했습니다. 역할만 표로 정리하면 이렇습니다.

도구/관습하는 일FE 대응물
Gradle 멀티모듈 (settings.gradle)모듈 선언·의존 방향·빌드 오케스트레이션pnpm workspace + Turborepo
스켈레톤 템플릿 레포새 레포의 출발점, 모든 레포가 같은 구조를 따름create-app 계열 보일러플레이트
도메인별 레포 분리도메인 = 레포. 담당과 맥락의 분리모노레포 패키지 경계, 마이크로프론트엔드

settings.gradle에는 프로젝트의 모듈들이 선언되어 있고, 각 모듈의 빌드 설정에는 의존 관계가 적혀 있습니다. 1편과 2편에서 본 모듈 구분을 여기서 실제로 확인할 수 있습니다. 새 모듈을 추가할 때는 기존 모듈의 선언과 의존 설정을 함께 보면 됩니다.

템플릿 레포는 레포가 많아지면서 필요해진 도구입니다. 도메인마다 레포가 늘어나는 구조에서는 "새 레포를 어떻게 시작하는가"가 반복 문제가 되고, 그 답이 모두가 따르는 출발 템플릿입니다. 모든 레포가 같은 구조라는 것은 처음 온 사람에게 큰 선물이기도 합니다. 하나를 익히면 열을 읽을 수 있습니다.




테스트: 진짜 DB를 띄우는 Testcontainers​

테스트를 돌리려니 Docker를 켜라고 했던 이유가 이것입니다. Testcontainers는 테스트가 시작될 때 진짜 MySQL 같은 것을 Docker 컨테이너로 띄우고 끝나면 걷어 갑니다. 인메모리 가짜 DB로는 못 잡는 것들(실제 SQL 방언, 제약 조건, 트랜잭션 동작)을 실물로 검증하는 것입니다.

실제 실행 환경에서 검증한다는 점은 Playwright로 브라우저를 띄우는 테스트와 비슷합니다. 여기서는 브라우저 대신 DB를 실행하므로 로컬에 Docker 환경이 필요합니다.

1편에서 분리한 코어의 업무 규칙은 DB 없이 테스트할 수 있습니다. Testcontainers는 그 테스트에서 확인하지 못한 어댑터의 SQL과 DB 동작을 검증하는 데 씁니다.




저장된 데이터를 다루는 도구들​

제가 해온 프론트엔드 작업에서는 자주 다루지 않았던 도구도 있습니다.

  • 마이그레이션 도구 (Liquibase 등): 8편에서 본 것처럼 기존 데이터를 유지하면서 스키마 변경을 적용합니다. 브라우저의 IndexedDB에도 버전 변경과 업그레이드 처리가 있지만, 여기서는 여러 서버와 사용자가 공유하는 DB의 변경 순서를 관리합니다.
  • JPA / Entity (ORM): 객체와 DB 테이블을 매핑합니다. API 응답을 화면용 데이터로 바꾸는 코드와 비교할 수는 있지만, 실제 저장과 조회까지 담당한다는 차이가 있습니다.

온보딩에서 특히 낯설었던 것은 배포 뒤에도 남아 있는 데이터를 다루는 일이었습니다. 새 코드가 동작하는지에 더해 기존 데이터를 어떻게 읽고 옮길지도 확인해야 했습니다.




시리즈 한 장 요약: FE ↔ BE 대응표​

아홉 편에 걸쳐 쌓아온 대응표의 전체판입니다.

BE 개념FE에서 가장 가까운 것대응의 핵심다룬 글
도메인 모델프레임워크와 분리한 업무 규칙 함수순수한 중심, 바깥을 모름1편
어댑터렌더러 (react-dom 등)갈아끼울 수 있는 바깥 부품1편
포트 (인터페이스)스토리지 인터페이스 계약계약은 안쪽이 소유한다1편
인바운드 어댑터이벤트 리스너세상이 나를 부른다2편
아웃바운드 어댑터fetch / API 클라이언트내가 세상을 부른다2편
의존성 규칙모노레포 import 방향덜 바뀌는 쪽으로만 의존2편
의존성 역전 (DIP)props 콜백안쪽이 선언, 바깥이 구현2편
도메인 서비스순수 도메인 util프레임워크를 모르는 업무 규칙3편
애플리케이션 서비스오케스트레이션 훅조율만, 로직은 위임3편
인가의 자리라우트 가드모델 밖, 흐름의 관문에서3편
인터널 APIBFF의 서버 간 조립클라 대신 서버가 합친다4편
모델 ↔ Response 정합리소스 REST vs 뷰모델 논쟁같은 축의 서버판5편
DTO 레이어링응답 타입·뷰모델·폼 상태 어댑터경계마다 자기 표현5편
필드 마스크 / permit폼의 dirty fields의도를 값이 아니라 목록에6편
컬럼 vs JSON 컬럼atom 쪼개기 vs 상태 객체그 단위로 일하는 쪽이 누구인가7편
마이그레이션IndexedDB 버전 업그레이드와 일부 유사살아 있는 데이터를 옮기는 일8편
ktlint / detektPrettier / ESLintbaseline은 얼려둔 빚이 글
Gradle 멀티모듈pnpm workspace + Turborepo빌드가 강제하는 경계이 글
TestcontainersPlaywright 통합 테스트흉내 대신 실물이 글

긴 시리즈를 함께 읽어주셔서 감사합니다. 언젠가 반대 방향의 온보딩, 그러니까 백엔드 개발자를 위한 프론트엔드 개념 지도를 쓰는 분이 있다면, 이 표가 거울처럼 쓰일 수 있기를 바랍니다.




References​

도구 공식 문서

  1. ktlint: An anti-bikeshedding Kotlin linter
  2. detekt: Static code analysis for Kotlin
  3. Gradle: Structuring Projects with Gradle (multi-project builds)
  4. Testcontainers


좋은 사람들과 재미있는 일을 하며 열정적이고 즐겁게 살고 싶은 개발자