Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/arch-single-responsibility.md
1---2title: Single Responsibility for Services3impact: CRITICAL4impactDescription: "40%+ improvement in testability"5tags: architecture, services, single-responsibility6---78## Single Responsibility for Services910Each service should have a single, well-defined responsibility. Avoid "god services" that handle multiple unrelated concerns. If a service name includes "And" or handles more than one domain concept, it likely violates single responsibility. This reduces complexity and improves testability by 40%+.1112**Incorrect (god service anti-pattern):**1314```typescript15// God service anti-pattern16@Injectable()17export class UserAndOrderService {18constructor(19private userRepo: UserRepository,20private orderRepo: OrderRepository,21private mailer: MailService,22private payment: PaymentService,23) {}2425async createUser(dto: CreateUserDto) {26const user = await this.userRepo.save(dto);27await this.mailer.sendWelcome(user);28return user;29}3031async createOrder(userId: string, dto: CreateOrderDto) {32const order = await this.orderRepo.save({ userId, ...dto });33await this.payment.charge(order);34await this.mailer.sendOrderConfirmation(order);35return order;36}3738async calculateOrderStats(userId: string) {39// Stats logic mixed in40}4142async validatePayment(orderId: string) {43// Payment logic mixed in44}45}46```4748**Correct (focused services with single responsibility):**4950```typescript51// Focused services with single responsibility52@Injectable()53export class UsersService {54constructor(private userRepo: UserRepository) {}5556async create(dto: CreateUserDto): Promise<User> {57return this.userRepo.save(dto);58}5960async findById(id: string): Promise<User> {61return this.userRepo.findOneOrFail({ where: { id } });62}63}6465@Injectable()66export class OrdersService {67constructor(private orderRepo: OrderRepository) {}6869async create(userId: string, dto: CreateOrderDto): Promise<Order> {70return this.orderRepo.save({ userId, ...dto });71}7273async findByUser(userId: string): Promise<Order[]> {74return this.orderRepo.find({ where: { userId } });75}76}7778@Injectable()79export class OrderStatsService {80constructor(private orderRepo: OrderRepository) {}8182async calculateForUser(userId: string): Promise<OrderStats> {83// Focused stats calculation84}85}8687// Orchestration in controller or dedicated orchestrator88@Controller('orders')89export class OrdersController {90constructor(91private orders: OrdersService,92private payment: PaymentService,93private notifications: NotificationService,94) {}9596@Post()97async create(@CurrentUser() user: User, @Body() dto: CreateOrderDto) {98const order = await this.orders.create(user.id, dto);99await this.payment.charge(order);100await this.notifications.sendOrderConfirmation(order);101return order;102}103}104```105106Reference: [NestJS Providers](https://docs.nestjs.com/providers)107