4.8 KiB
4.8 KiB
Bad Example: God Object
A component that violates Atelier principles. Each violation is cited.
The Code
// UserManager.ts — 1,200 lines
class UserManager {
private users: User[] = [];
private cache: Map<string, User> = new Map();
private db: Database;
private emailService: EmailService;
private logger: Logger;
private auditLog: AuditLog;
constructor(db: Database, email: EmailService, logger: Logger, audit: AuditLog) {
this.db = db;
this.emailService = email;
this.logger = logger;
this.auditLog = audit;
}
// CRUD
async createUser(data: UserData): Promise<User> { /* 80 lines */ }
async getUser(id: string): Promise<User> { /* 40 lines */ }
async updateUser(id: string, data: Partial<UserData>): Promise<User> { /* 60 lines */ }
async deleteUser(id: string): Promise<void> { /* 50 lines */ }
async listUsers(page: number): Promise<User[]> { /* 40 lines */ }
// Email
async sendWelcomeEmail(user: User): Promise<void> { /* 50 lines */ }
async sendPasswordReset(user: User): Promise<void> { /* 50 lines */ }
async sendDeletionNotice(user: User): Promise<void> { /* 40 lines */ }
// Auth
async authenticate(email: string, password: string): Promise<boolean> { /* 70 lines */ }
async authorize(userId: string, action: string): Promise<boolean> { /* 60 lines */ }
async hashPassword(password: string): Promise<string> { /* 20 lines */ }
// Cache
private cacheGet(id: string): User | null { /* 20 lines */ }
private cacheSet(user: User): void { /* 20 lines */ }
private cacheInvalidate(id: string): void { /* 20 lines */ }
// Audit
private logAudit(action: string, userId: string): void { /* 30 lines */ }
// Validation
private validateEmail(email: string): boolean { /* 20 lines */ }
private validatePassword(password: string): boolean { /* 20 lines */ }
// Serialization
toJSON(user: User): Record<string, unknown> { /* 30 lines */ }
fromJSON(data: Record<string, unknown>): User { /* 30 lines */ }
// ... 200 more lines of helper methods
}
Violations
C3 Simplicity (Core)
- A 1,200-line class doing 8 different things (CRUD, email, auth, cache, audit, validation, serialization).
- The class cannot be understood in one read. Complexity is the liability.
- Fix: Split into
UserRepository(CRUD),UserEmailService(email),UserAuthService(auth),UserCache(cache),UserAuditLogger(audit),UserValidator(validation),UserSerializer(serialization).
C6 Composability (Core)
- The class takes 4 dependencies and does 8 jobs. It is not composable; it is monolithic.
- You cannot reuse the email logic without the DB, the cache, the audit log.
- Fix: Each responsibility is its own class. Compose them:
UserEmailServicetakes onlyEmailService.
components.md §1 Single Responsibility (UI/UX, applies to code)
- The class name is
UserManager. "Manager" is a smell — it manages what? Everything. - If the name is "Manager," it has no single responsibility.
- Fix: Name by responsibility:
UserRepository,UserAuthService. Names that cannot be "And"-ed.
C4 Locality (Core)
- Cache logic is in the same class as email logic. A change to cache touches the email methods' neighbor.
- Related logic (cache get/set/invalidate) is grouped, but unrelated logic (email) is adjacent.
- Fix:
UserCacheis its own class. Cache changes are local to cache.
C2 Clarity (Core)
- A reader cannot answer "what does
UserManagerdo?" in one sentence. - The class has 20+ methods. The reader must scan all of them to find the one they need.
- Fix: Smaller classes with clear names. The name is the documentation.
Security P2 Least Privilege (Security)
- The class has
db,emailService,logger,auditLog— all available to all methods. sendWelcomeEmailhas access todb.delete. Least privilege is violated.- Fix: Each service has only the dependencies it needs.
UserEmailServicehasEmailService, notDatabase.
Testing P2 Independence (Testing)
- To test
sendWelcomeEmail, you must constructUserManagerwith a real/mock DB, email, logger, audit. - The test setup is 4 mocks for one method. Independence is violated.
- Fix: Test
UserEmailServicewith one mock (EmailService).
What This Example Reveals
The "God Object" is the cardinal sin of OOP. It violates C3 (Simplicity), C6 (Composability), C4 (Locality), and C2 (Clarity) simultaneously. Every other principle suffers downstream:
- Testing is hard (T2 Independence).
- Security is loose (S2 Least Privilege).
- Evolution is brittle (a change to email risks cache).
- Review is exhausting (a 1,200-line diff).
The fix is always the same: decompose by responsibility. The class name is the test: if it is "Manager," "Handler," or "Helper," it has no single responsibility.