보일러플레이트 작성을 멈추세요: NestJS 개발을 자동화하기 위해 코드 생성기를 만든 방법
Source: Dev.to
요약
- 반복되는 코딩 패턴을 식별하고 코드 생성기를 구축하여 자동화했습니다.
- 코드 일관성을 확보하고 유지 보수를 용이하게 하며 개발 주기를 크게 단축했습니다.
- AI를 활용해 생성기 자체를 유지 관리함으로써 도구 유지 보수에 드는 부담을 줄였습니다.
소개: 왜 코딩을 직접 하지 않기로 했는가
백엔드 엔지니어로서 나는 반복적인 보일러플레이트 코드와 끊임없이 싸우고 있었다. 새로운 기능을 만들 때마다 같은 구조를 계속해서 타이핑하고 있었다. 나는 스스로에게 물었다:
“비즈니스 로직과 구현에만 집중한다면 개발 속도가 훨씬 빨라지지 않을까?”
“아하!” 순간은 gRPC를 작업하면서 찾아왔다. .proto 파일에서 기본 코드가 자동으로 생성되는 모습을 보았다. Node.js 생태계(NestJS, React, Next.js)가 이미 코드‑생성 도구를 받아들이고 있기 때문에, 우리 팀의 특정 아키텍처에 맞춘 맞춤형 코드 생성기를 만들기로 결심했다.
1단계: 자동화 전 표준화
제너레이터를 만들기 전에 혼돈은 자동화할 수 없습니다라는 엄격한 코드 패턴을 정의해야 했습니다. 저는 표준 Controller → Service → Repository 패턴을 채택하고 Data Transfer Object(DTO)에 대한 엄격한 규칙을 적용했습니다.
1. 응답 및 요청 DTO 표준화
응답 예시
{
"statusCode": 200,
"message": "Success",
"data": {
"id": 1,
"name": "John Doe"
}
}
data: 항상 객체입니다. 리스트인 경우items배열을 포함합니다.statusCode및message: 필수 필드입니다.
요청 기본 클래스(예: 페이지네이션, 관리자 요청)
// Example: Composing DTOs using IntersectionType
export class DomainGetDto extends IntersectionType(
BasePaginationRequestDto,
AdminRequestDto,
) {}
class DomainResponseData {
@ApiProperty({ item: DomainResponseDataItem, isArray: true })
items: DomainResponseDataItem[];
}
export class DomainResponse extends BaseResponse {
@ApiProperty({ type: DomainResponseData })
data: DomainResponseData;
}
2. Controller와 Service 역할 정의
| 레이어 | 책임 |
|---|---|
| Controller | - DTO(쿼리/바디)를 받아 Service에 전달합니다. - Service에서 반환된 data 필드를 BaseResponse로 감싸서 반환합니다.- 인증 가드와 로깅을 처리합니다. |
| Service | - 비즈니스 로직만 포함합니다. - 응답 래퍼 없이 원시 데이터 페이로드를 반환합니다. |
아키텍처 개요

Source: …
2단계: 제너레이터 구축
패턴을 마련한 뒤, CLI 제너레이터를 만들었습니다. 핵심 로직은 다음과 같습니다.
- DTO 분석 – DTO 정의 파일을 읽어들입니다.
- 메서드 결정 – DTO 이름에서 HTTP 메서드를 추론합니다 (예:
CreateUserDto → POST). - 코드 생성
- Controller API 엔드포인트 생성.
- Service 보일러플레이트 스캐폴드.
- Module 파일을 생성하고 메인 모듈에 자동으로 등록.
- 타입 안전성 – TypeScript 제네릭을 사용해 Service가
BaseResponse가 기대하는 정확한 타입을 반환하도록 합니다.
결정론적 생성 로직
이 제너레이터는 100 % 결정론적입니다. 엄격한 패턴 매칭과 미리 정의된 템플릿에 의존하므로, 예측 불가능한 AI‑생성 코드와는 달리 모든 문자가 정확히 지정된 위치에 배치됩니다.
생성 워크플로우

개발에서 AI의 역할
Generator 자체는 엄격한 규칙을 따르지만, 나는 AI를 generator를 구축하고 유지보수하는 데 사용했다. AST 파서를 작성하거나 복잡한 정규식 패턴을 만드는 것은 번거롭다; AI가 내가 정의한 패턴을 기반으로 해당 스크립트를 생성하도록 도왔다. 워크플로우는 다음과 같이 바뀌었다:
인간이 패턴을 정의한다 → AI가 생성기 코드를 작성한다 → 생성기가 제품 코드를 만든다
Phase 3: The Results
Implementing the Code Generator delivered immediate benefits.
1. Focus on Business Logic
Developers no longer worry about boilerplate. Unless there’s a special edge case, they only touch the Service layer. The generator also scaffolds unit tests, so developers can jump straight into implementation and testing.
2. Consistency & Faster Code Reviews
Common review questions disappear:
- Did they import the right module?
- Is the naming convention correct?
- Did they extend
BaseResponse?
Because the code is guaranteed to be consistent, reviewers can concentrate solely on the logic, drastically reducing review time.
3. Accelerated Development Speed
Boilerplate and test‑file setup used to consume significant time. Now it’s instantaneous.
보너스: Protobuf를 활용한 gRPC 자동화
For gRPC, the process is even smoother. Unlike REST—where intent must be inferred from DTO names—gRPC provides .proto files that strictly define services and messages, allowing the generator to produce both client‑ and server‑side code without guesswork.
서비스와 메시지 정의
나는 build‑proto 명령을 만들었습니다:
protoc를 실행하여 기본 타입을 빌드합니다..proto정의를 읽습니다.- Proto 정의에 매핑되는 NestJS Controller와 Service 레이어를 자동으로 생성합니다.

결론
코드 생성기를 만드는 것이 처음엔 “과잉 설계”처럼 보이거나 유지 관리 부담이 추가되는 것처럼 느껴질 수 있습니다. 하지만 ROI는 엄청났습니다.
- 유지 관리? 네, 도구는 유지 관리가 필요합니다. 하지만 AI 도움을 받으면 생성기를 업데이트하는 것이 수백 개의 파일을 수동으로 수정하는 것보다 빠릅니다.
- 가치? 저를 “그냥 코더”에서 “시스템을 설계하는 엔지니어”로 변모시켰습니다.
팀이 반복 작업에 시달리고 있다면, 타이핑을 멈추세요. 생성을 시작하세요.