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
Interfaces should be defined in the layer that uses them, not the layer that implements them. The client owns the abstraction; the implementation adapts to it.
Incorrect (interface defined next to implementation):
// infrastructure/persistence/UserRepository.java
public interface UserRepository {
User findById(String id);
void save(User user);
}
// infrastructure/persistence/PostgresUserRepository.java
public class PostgresUserRepository implements UserRepository {
// Implementation
}
// application/usecases/CreateUserUseCase.java
import infrastructure.persistence.UserRepository; // Use case imports from infrastructure!
public class CreateUserUseCase {
private final UserRepository repository;
}Correct (interface defined where it's used):
// application/ports/output/UserRepository.java
public interface UserRepository {
User findById(String id);
void save(User user);
}
// application/usecases/CreateUserUseCase.java
import application.ports.output.UserRepository; // Same layer import
public class CreateUserUseCase {
private final UserRepository repository; // No infrastructure dependency
}
// infrastructure/persistence/PostgresUserRepository.java
import application.ports.output.UserRepository; // Infrastructure depends on application
public class PostgresUserRepository implements UserRepository {
// Implementation adapts to the port
}Note: This is the essence of the Dependency Inversion Principle. The high-level module defines what it needs; low-level modules conform to that contract.
Reference: Clean Architecture - Chapter 11: DIP
clean-architecture
evals
references
design-patterns
solid-principles
testable-design