Bounded Context
❌ Framework Code in Domain
// BAD: Using Express in domain
import { Request, Response } from 'express';
class CreateUserCommand {
execute(req: Request, res: Response) { ... }
}
❌ Environment Variables in Domain
// BAD: Reading env vars in BC
const apiKey = process.env.API_KEY;
❌ Direct Cross-BC Import
// BAD: Importing from another BC
import { OrderAggregate } from '../order/domain/aggregates';
Infrastructure
❌ Business Logic in Repository
// BAD: Price calculation in repository
async findWithDiscount(id: string): Promise<Product> {
const product = await this.db.find(id);
product.price = product.price * 0.9; // BAD!
return product;
}
❌ implements in Persistence/External
// BAD: Persistence should NOT implement port
class UserPersistence implements UserRepositoryOutboundPort { ... }
// GOOD: Only implementations/ use `implements`
class UserRepository implements UserRepositoryOutboundPort {
constructor(private persistence: UserPersistence) {}
}
Presentation
❌ Business Logic in Access Guard
// BAD: Custom logic in guard
async guard(request: Request): Promise<GuardResult> {
const discount = request.user.isVIP ? 0.2 : 0; // BAD!
return { allowed: true, discount };
}
❌ Business Logic in Mapper
// BAD: Calculation in mapper
function toResponse(order: Order): OrderResponse {
return {
...order,
total: order.items.reduce((sum, i) => sum + i.price, 0), // BAD!
};
}
Dependencies
❌ Outer Layer Import in Inner Layer
// BAD: BC importing from Infrastructure
import { DrizzleUserRepository } from '@infra/repositories';
❌ Two-Way Module Dependencies
// BAD: Module A imports Module B, AND Module B imports Module A
// This creates circular dependency
Naming
❌ Inconsistent Port Naming
// BAD: Missing port suffix
interface UserRepository { ... }
// GOOD
interface UserRepositoryOutboundPort { ... }