Strategic architecture, tactical design, and testable code principles (SOLID, Clean Architecture, Design Patterns, Testable Design)
97
97%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Mappers translate between domain entities and external representations (database rows, API responses, DTOs). Each layer has its own model; mappers bridge them.
Incorrect (domain entity used everywhere):
// Domain entity directly serialized to JSON and stored in DB
class User {
id: string
email: string
passwordHash: string // Exposed in API response!
createdAt: Date
lastLogin: Date
preferences: UserPreferences
roles: Role[]
toJSON() {
return { ...this } // Leaks everything
}
}
// Controller returns entity directly
app.get('/users/:id', (req, res) => {
const user = userRepo.findById(req.params.id)
res.json(user) // passwordHash in response!
})
// ORM couples domain to database schema
@Entity()
class User {
@PrimaryColumn() id: string
@Column() email: string
// Domain entity is now a database entity
}Correct (dedicated models per layer with mappers):
// domain/User.ts - Pure domain entity
class User {
constructor(
readonly id: UserId,
private email: Email,
private passwordHash: PasswordHash,
private roles: Set<Role>
) {}
hasRole(role: Role): boolean {
return this.roles.has(role)
}
}
// infrastructure/persistence/UserEntity.ts - Database model
interface UserRow {
id: string
email: string
password_hash: string
roles: string // JSON array in DB
created_at: string
updated_at: string
}
// infrastructure/persistence/UserMapper.ts
class UserMapper {
toDomain(row: UserRow): User {
return new User(
new UserId(row.id),
Email.create(row.email),
new PasswordHash(row.password_hash),
new Set(JSON.parse(row.roles))
)
}
toPersistence(user: User): UserRow {
return {
id: user.id.value,
email: user.email.value,
password_hash: user.passwordHash.value,
roles: JSON.stringify([...user.roles]),
updated_at: new Date().toISOString()
}
}
}
// interface/dto/UserResponse.ts - API response model
interface UserResponse {
id: string
email: string
roles: string[]
// No passwordHash!
}
// interface/mappers/UserResponseMapper.ts
class UserResponseMapper {
toResponse(user: User): UserResponse {
return {
id: user.id.value,
email: user.email.value,
roles: [...user.roles]
}
}
}Benefits:
Reference: Data Mapper Pattern
clean-architecture
evals
references
design-patterns
solid-principles
testable-design