NestJS 모듈과의 싸움을 멈추세요: Rikta를 만나보세요
Source: Dev.to
위에 제공된 링크에 있는 전체 텍스트를 여기 채팅에 붙여 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. 코드 블록, URL 및 마크다운 형식은 그대로 유지됩니다.
The Module Problem
NestJS 모듈은 실제 문제인 의존성 경계를 해결합니다. 대규모 코드베이스에서 혼란을 방지하지만, 그에 따른 비용이 있습니다.
새로운 서비스마다 다음을 해야 합니다:
@Injectable()로 서비스를 생성합니다.- 모듈의
providers배열에 추가합니다. - 다른 모듈에서 필요하면
exports배열에 추가합니다. - 사용되는 모든 곳에서 모듈을 import 합니다.
전형적인 NestJS 모듈은 다음과 같습니다:
// user.module.ts
@Module({
imports: [
DatabaseModule,
ConfigModule,
AuthModule,
LoggingModule,
],
controllers: [UserController],
providers: [
UserService,
UserRepository,
UserValidator,
UserMapper,
],
exports: [UserService, UserRepository],
})
export class UserModule {}
그것은 많은 보일러플레이트—순수한 설정 오버헤드가 빠르게 증가합니다.
중간 규모의 앱은 20개 이상의 모듈을 가질 수 있으며, 각 모듈마다 5~10개의 프로바이더가 있습니다. 비즈니스 로직을 작성하기보다 배열을 관리하는 데 더 많은 시간을 소비하게 됩니다.
가장 안 좋은 점은? 배열 중 어느 하나라도 오타가 있으면 전체 의존성 그래프가 깨지고, 디버깅에 몇 시간이 걸릴 수 있습니다.
Source: …
모듈이 필요 없다고 가정한다면?
Rikta는 Fastify 위에 구축된 새로운 TypeScript 프레임워크입니다. NestJS에서 개발자들이 좋아하는 부분(데코레이터, DI, 구조)을 그대로 유지하면서 모듈 설정을 완전히 제거합니다.
imports배열이 없습니다.exports배열이 없습니다.providers배열이 없습니다.
클래스에 데코레이터만 붙이면 모든 것이 동작합니다.
// user.service.ts
import { Injectable } from '@riktajs/core';
@Injectable()
export class UserService {
getUsers() {
return ['Alice', 'Bob'];
}
}
// user.controller.ts
import { Controller, Get, Autowired } from '@riktajs/core';
import { UserService } from './user.service';
@Controller('/users')
export class UserController {
@Autowired()
private userService!: UserService;
@Get()
getUsers() {
return this.userService.getUsers();
}
}
그게 전부입니다—모듈 파일도, 별도 등록도 필요 없습니다. Rikta는 시작 시 코드를 스캔하고 의존성을 자동으로 해결합니다.
Zero‑Config 자동 와이어링 작동 방식
Rikta는 세 가지 메커니즘을 사용합니다:
- 자동 발견 – 시작 시
@Controller()또는@Injectable()로 데코레이트된 클래스를 프로젝트 전체에서 스캔합니다. 생성자 매개변수와@Autowired()데코레이터를 기반으로 의존성 그래프를 구축합니다. - 전역 제공자 레지스트리 – 모든 제공자는 단일 레지스트리에 저장됩니다. injectable 클래스는 앱 어디서든 사용할 수 있으며, 별도의 export 또는 import가 필요 없습니다.
- 의존성 해결 – Rikta는 TypeScript 메타데이터(
reflect-metadata활용)를 읽어 각 클래스가 무엇을 필요로 하는지 파악하고, 올바른 순서로 인스턴스를 생성하여 자동으로 주입합니다.
초기화 중에 순환 의존성이 감지되면 명확한 오류를 발생시킵니다:
Error: Circular dependency detected:
UserService -> AuthService -> UserService
암호 같은 스택 트레이스도 없고, 런타임에서 깜짝 놀라움도 없습니다.
나란히 비교
NestJS에서 새로운 기능 만들기
// 1. Create the service
@Injectable()
export class PaymentService {
constructor(private configService: ConfigService) {}
}
// 2. Create the module
@Module({
imports: [ConfigModule],
providers: [PaymentService],
exports: [PaymentService],
})
export class PaymentModule {}
// 3. Import in app.module.ts
@Module({
imports: [PaymentModule, /* ... */],
})
export class AppModule {}
// 4. Import in any module that needs it
@Module({
imports: [PaymentModule],
providers: [OrderService],
})
export class OrderModule {}
Rikta에서 동일한 기능 만들기
@Injectable()
export class PaymentService {
@Autowired()
private configService!: ConfigService;
}
완료.
성능 이점
Rikta는 HTTP 레이어로 Fastify를 사용합니다. Fastify는 벤치마크에서 초당 30,000 요청을 처리합니다.
공식 벤치마크 결과:
| Metric | Rikta vs. NestJS |
|---|---|
| Startup time | 43 % 더 빠름 |
| GET requests | 41 % 더 빠름 |
| POST requests | 25 % 더 빠름 |
| Route parameters | 46 % 더 빠름 |
Rikta는 기본 Fastify에 비해 **2‑5 %**의 오버헤드만 추가하며, 속도를 희생하지 않고 DI와 데코레이터를 제공합니다.
내장 Zod 검증
NestJS는 class-validator 데코레이터에 의존하므로 타입을 두 번 정의해야 합니다: 한 번은 TypeScript용, 한 번은 검증용입니다.
Rikta는 Zod를 기본적으로 통합합니다. 스키마를 한 번 정의하면 검증과 TypeScript 타입을 자동으로 얻을 수 있습니다.
import { Controller, Post, Body, z } from '@riktajs/core';
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
age: z.number().optional(),
});
@Controller('/users')
export class UserController {
@Post()
create(@Body(CreateUserSchema) user: z.infer<typeof CreateUserSchema>) {
// 'user' is validated AND typed
// Invalid requests return 400 automatically
return { created: user };
}
}
중복된 타입 정의가 없고, 검증 실패에 대한 수동 오류 처리도 필요 없습니다.
Rikta를 언제 사용해야 할까
Rikta가 가장 잘 작동하는 경우:
- 스타트업 및 MVP(Minimum Viable Product)에서 개발 속도가 중요한 경우.
- 소규모~중간 규모 팀(1‑15명 개발자)으로, 깔끔하고 설정이 필요 없는 DI 시스템을 원하는 경우.
NestJS의 사용 편의성을 좋아하지만 모듈 보일러플레이트가 지겹다면 Rikta를 시도해 보세요.
- 마이크로서비스 – 각 서비스가 집중된 상태를 유지할 때.
- NestJS를 알고 있는 개발자이며 보일러플레이트를 줄이고 싶을 때.
NestJS를 고려해야 할 경우:
- 엄격한 모듈 경계가 필요한 대규모 팀이 있을 때.
- 방대한 NestJS 생태계(특정 어댑터, 플러그인 등)가 필요할 때.
- 조직에서 명시적인 의존성 문서화를 요구할 때.
Getting Started
Create a new project in seconds:
npx @riktajs/cli new my-app
cd my-app
npm run dev
Your API runs at http://localhost:3000.
The CLI generates a complete project with:
- Rikta에 최적화된 TypeScript 설정
- REST 엔드포인트가 포함된 예제 컨트롤러
- 의존성 주입이 포함된 예제 서비스
- 핫‑리로드 개발 서버
Resources
- Documentation: (link)
- GitHub: (link)
- NPM: (link)
Rikta는 MIT 라이선스를 가지고 있으며 오픈 소스입니다.
제로‑컨피그 프레임워크를 사용해 보셨나요? 모듈과 자동 와이어링 간의 트레이드‑오프에 대해 어떻게 생각하시나요? 댓글로 경험을 공유해주세요.