slowlp
← 블로그
이야기 2026.06.22 · 4분 읽기

다들 ORM이 처음이라, 백엔드 개발 가이드를 썼다

복붙 중복을 막으려고 직접 쓴 17개 섹션짜리 백엔드 설계 스터디 가이드

이야기

복붙 중복을 막으려고 쓴 17개 섹션 개발 가이드

회사 코드는 다 똑같이 생겼다

전에 회사 프로젝트를 두세 개 들여다본 적이 있다. 그런데 셋이 다 똑같이 생겼더라. 한 군데서 짠 걸 복사해서 다음 프로젝트에 붙이고, 거기서 또 복사하고. 코드가 set처럼 통째로 돌아다녔다. 그러다 보니 한 프로젝트 안에서도 같은 로직이 여기저기 박혀 있고, 똑같은 쿼리가 파일마다 다시 쓰여 있었다. 중복, 중복, 또 중복.

돌아가긴 한다. 문제는 고칠 때다. 같은 걸 몇 군데서 동시에 고쳐야 하고, 한 군데라도 빠뜨리면 거기서 버그가 샌다.

그러던 차에 백엔드 스터디를 시작했다. 트레이딩 앱 아이디어가 괜찮아서 모인 자리였는데, 멤버 대부분이 ORM이랑 도메인 기반 설계를 처음 다뤄보고 있었다. 이대로 각자 감으로 짜게 두면 내가 회사에서 본 그 복붙 코드가 또 나올 게 뻔했다. 그래서 가이드를 직접 쓰기로 했다. 멤버들한테 “이 프로젝트에선 이렇게 짠다”를 알려줄 겸, 중복이 쌓이기 전에 막을 겸.

트레이딩 MVP라는 실제 프로젝트를 깔판 삼아 17개 섹션짜리 백엔드 개발 가이드가 나왔고, 이 시리즈는 그걸 일반화한 것이다. 도메인은 주식 계좌·포트폴리오지만, 패턴 자체는 어떤 백엔드에도 통한다.

사실 이걸 올릴까는 좀 망설였다. 스터디 멤버 보라고 쓴 거지 남한테 보여줄 생각으로 쓴 게 아니었으니까. 그래도 나름 열심히 정리한 문서고, 백엔드를 막 시작해서 “이 코드를 대체 어디다 둬야 하지”로 헤매는 사람한테는 쓸모가 있을 것 같았다. 그래서 프로젝트 색을 덜어내고 일반화해서, 한 편씩 요약해 올린다. 정답이라기보단 “우리는 이렇게 정리했다” 정도로 봐주면 된다.

스택부터 정했다

가이드를 쓰려면 먼저 뭘로 짤지부터 합의가 필요했다. 고른 건 Python 3.11에 FastAPI, 그리고 데이터 계층은 SQLAlchemy 위에 SQLModel을 올린 조합이다.

Python을 베이스로 둔 건 타입 힌트 때문이 크다. 타입을 붙여두면 FastAPI와 Pydantic이 그걸 그대로 받아 검증해주니, 개발 중에 데이터가 어긋나는 걸 미리 잡을 수 있다. FastAPI를 고른 이유도 둘이다. 하나는 의존성 주입. DB 세션이나 인증 같은 걸 매번 함수 안에서 만들지 않고 주입받게 하면 테스트가 한결 쉬워진다. 다른 하나는 비동기. I/O를 기다리는 동안 다른 요청을 처리할 수 있어서, 외부 API를 자주 부르는 서비스에 잘 맞는다.

데이터 계층에서 SQLModel을 얹은 게 스터디 입장에선 핵심이었다. SQLAlchemy가 ORM 표준이라면, SQLModel은 그 위에서 DB 테이블 모델과 API 데이터 모델을 한 클래스로 합쳐준다. 모델을 두 벌로 관리하다 보면 둘이 어긋나서 생기는 버그가 끊이질 않는데, 그 종류의 버그를 통째로 없애준다. ORM이 처음인 사람한테 설명할 게 한 겹 줄어드는 셈이라 가이드 쓰기에도 유리했다.

검증은 Pydantic이, 백그라운드 작업은 Celery가, 테스트는 Pytest가, 환경은 Docker Compose가 맡는다. 이 조합을 깔아두고 나서야 “그래서 코드는 어떻게 배치하나”를 본격적으로 적기 시작했다.

시리즈 지도

가이드가 길다. 한 번에 다 풀면 체할 테니 전체 그림을 먼저 펼쳐둔다. 미리 말해두면 거의 모든 편이 결국 한 가지를 향한다. 중복을 어디서 끊을 것인가. 로직은 모델로, 쿼리는 리포지토리로, 공통 코드는 base 클래스로 모은다. 아래 순서대로 한 편씩 다룬다.

  1. (이 글) 다들 ORM이 처음이라, 백엔드 개발 가이드를 썼다: 왜 쓰게 됐고 어떤 스택을 골랐나
  2. 폴더가 곧 설계다: 도메인 기반으로 프로젝트 구조를 잡는 법
  3. 라우터는 HTTP만, 로직은 서비스로: 계층을 어디서 자르나
  4. 모델에 로직을 넣으면 중복이 사라진다: ORM 도메인 모델 다루기
  5. 데이터 접근은 리포지토리로만: 제네릭 BaseRepository로 쿼리를 한곳에
  6. 경계마다 검증한다: 스키마(DTO)와 다층 방어
  7. 처리할 수 있는 예외만 잡는다: 예외 처리 전략
  8. 같은 코드를 두 번 쓰지 않으려고: 공통 모듈·Base 클래스·명명 규칙

다음 편에서는 폴더 구조부터 본다. 코드를 어디에 두느냐가 설계의 절반이라, 거기서 출발하는 게 맞다.

관련 프로젝트
주식앱 (마이폴리오) LAB
개별 종목 분석 없이 포트폴리오 단위로 투자하는 앱 — KIS 계좌 연동 실주문까지, 본인 계좌 전용으로 운영 중.
보기 →
댓글