Uncle Bob's Clean Architecture Principles in the AI Era
Introduction
Robert C. Martin's Clean Architecture principles have guided software development for years. As AI becomes more integrated into our development process, these principles take on new significance and require adaptation.
The Dependency Rule Revisited
Uncle Bob's fundamental rule states that dependencies should point inward, toward higher-level policies. With AI, this rule becomes even more critical as we need to ensure AI tools don't create unwanted dependencies.
Clean Architecture with AI
1. Entities Layer
The innermost layer contains enterprise business rules. AI should never modify these core entities.
// Core business entity - AI should not modify this
class User {
constructor(id, name, email) {
this.id = id;
this.name = name;
this.email = email;
}
isValidEmail() {
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
return emailRegex.test(this.email);
}
// Business rules - immutable by AI
canAccessFeature(feature) {
return this.subscriptionLevel >= feature.requiredLevel;
}
}
2. Use Cases Layer
AI can help implement use cases, but the business logic should remain human-defined.
class CreateUserUseCase {
constructor(userRepository, emailValidator) {
this.userRepository = userRepository;
this.emailValidator = emailValidator;
}
async execute(userData) {
// Business logic - human-defined
if (!this.emailValidator.isValid(userData.email)) {
throw new Error('Invalid email format');
}
const existingUser = await this.userRepository.findByEmail(userData.email);
if (existingUser) {
throw new Error('User already exists');
}
const user = new User(
this.generateId(),
userData.name,
userData.email
);
return await this.userRepository.save(user);
}
private generateId() {
return crypto.randomUUID();
}
}
3. Interface Adapters Layer
AI can generate adapters and controllers, but the interfaces should be human-designed.
class UserController {
constructor(createUserUseCase) {
this.createUserUseCase = createUserUseCase;
}
async createUser(req, res) {
try {
const user = await this.createUserUseCase.execute(req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
}
// AI can generate this implementation
class UserRepositoryImpl {
async save(user) {
// Database implementation
return await db.users.insert(user);
}
async findByEmail(email) {
return await db.users.findOne({ email });
}
}
AI-Safe Architecture Patterns
1. Interface Segregation
Define clear, small interfaces that AI can implement without breaking the architecture.
// Good: Small, focused interface
interface EmailValidator {
isValid(email: string): boolean;
}
// Bad: Large interface that's hard to implement correctly
interface UserService {
createUser(data: any): Promise;
updateUser(id: string, data: any): Promise;
deleteUser(id: string): Promise;
getUser(id: string): Promise;
listUsers(): Promise;
// ... many more methods
}
2. Dependency Inversion
Use dependency injection to make AI-generated components easily replaceable.
class UserService {
constructor(
private userRepository: UserRepository,
private emailValidator: EmailValidator,
private logger: Logger
) {}
async createUser(userData: CreateUserRequest): Promise {
this.logger.info('Creating user', { email: userData.email });
if (!this.emailValidator.isValid(userData.email)) {
throw new ValidationError('Invalid email format');
}
const user = new User(userData);
return await this.userRepository.save(user);
}
}
AI Integration Guidelines
- Keep Core Business Logic Human-Written: AI should not modify entities or core business rules
- Use AI for Implementation Details: Let AI handle database queries, API calls, and utility functions
- Maintain Clear Boundaries: Define interfaces that AI can implement without breaking architecture
- Review AI-Generated Code: Always review AI output for architectural compliance
Bibliography
- Martin, R. C. (2017). "Clean Architecture: A Craftsman's Guide to Software Structure and Design"
- Martin, R. C. (2009). "Clean Code: A Handbook of Agile Software Craftsmanship"
- Martin, R. C. (2011). "The Clean Coder: A Code of Conduct for Professional Programmers"
- Evans, E. (2003). "Domain-Driven Design: Tackling Complexity in the Heart of Software"
Conclusion
Clean Architecture principles remain fundamental in the AI era. By following these guidelines, we can leverage AI's capabilities while maintaining software quality and architectural integrity.