SRP Compliance Report — Auto-Table Generation System
How the Auto-Generator adheres to the Single Responsibility Principle
Single Responsibility Principle (SRP) Compliance Report
Overview
The Auto-Table Generation System has been refactored to strictly adhere to the Single Responsibility Principle, one of the five SOLID principles of object-oriented design. This document explains how each class maintains a single, well-defined responsibility.
What is SRP?
Single Responsibility Principle states: “A class should have one, and only one, reason to change.”
In practical terms:
- Each class should focus on doing one thing well
- Changes to one aspect of the system should only require modifying one class
- Classes should be highly cohesive (all methods relate to the single responsibility)
SRP-Compliant Architecture
The refactored GenerateTablePage.java contains 5 distinct classes, each with a single responsibility:
1. GenerationConfig - Configuration Management
Single Responsibility: Hold and compute all generation settings
static class GenerationConfig {
final String entityName;
final String entityPackage;
final String pageName;
final String pageLower;
final String repoName;
final String controllerPackage;
final String basePath;
final String projectRoot;
final String controllerClassName;
final String repoVarName;
final String modelAttrName;
GenerationConfig(String entityName, String entityPackage, String pageName) {
// Computes all derived values from inputs
}
}
Why it follows SRP:
- ✅ Only reason to change: Configuration logic changes (e.g., naming conventions)
- ✅ Single focus: Managing generation parameters
- ✅ No other concerns: Doesn’t generate code, doesn’t write files, doesn’t orchestrate
- ✅ High cohesion: All fields relate to configuration
Example change scenario:
- If we change URL structure from
/mvc/{entity}to/admin/{entity}, we only modify this class - No other classes need to change
2. FileWriter - File System Operations
Single Responsibility: Write generated code to the filesystem
static class FileWriter {
private final GenerationConfig config;
String writeController(String code) throws IOException {
// Creates directories and writes controller file
}
String writeView(String code, String filename) throws IOException {
// Creates directories and writes view file
}
}
Why it follows SRP:
- ✅ Only reason to change: File I/O logic changes (e.g., different output location)
- ✅ Single focus: Writing to disk
- ✅ No other concerns: Doesn’t generate code, doesn’t know what’s being written
- ✅ High cohesion: All methods relate to file operations
Example change scenario:
- If we switch from local files to cloud storage (S3, etc.), we only modify this class
- Generator classes remain unchanged
3. ControllerGenerator - Controller Code Generation
Single Responsibility: Generate Spring MVC controller source code
static class ControllerGenerator {
private final GenerationConfig config;
String generate() {
// Returns controller code as a String
}
}
Why it follows SRP:
- ✅ Only reason to change: Controller template changes (e.g., add new endpoint)
- ✅ Single focus: Creating controller code
- ✅ No other concerns: Doesn’t write files, doesn’t generate views
- ✅ High cohesion: Single method for single purpose
Example change scenario:
- If we add a
/batch-deleteendpoint, we only modify this class - File writing and view generation unaffected
4. ViewGenerator - View Template Generation
Single Responsibility: Generate Thymeleaf HTML templates
static class ViewGenerator {
private final GenerationConfig config;
String generateReadView() {
// Returns read.html code as a String
}
String generateEditView() {
// Returns edit.html code as a String
}
}
Why it follows SRP:
- ✅ Only reason to change: View template changes (e.g., new form field)
- ✅ Single focus: Creating HTML templates
- ✅ No other concerns: Doesn’t write files, doesn’t generate controllers
- ✅ High cohesion: All methods relate to view generation
Example change scenario:
- If we switch from Bootstrap to Tailwind CSS, we only modify this class
- Controller generation and file writing unaffected
5. GenerateTablePage (main) - Orchestration
Single Responsibility: Coordinate the generation workflow
public static void main(String[] args) {
// Create configuration
GenerationConfig config = new GenerationConfig(ENTITY_NAME, ENTITY_PACKAGE, PAGE_NAME);
// Initialize generators
ControllerGenerator controllerGen = new ControllerGenerator(config);
ViewGenerator viewGen = new ViewGenerator(config);
FileWriter writer = new FileWriter(config);
// Generate and write controller
String controllerCode = controllerGen.generate();
String controllerPath = writer.writeController(controllerCode);
// Generate and write views
String readViewCode = viewGen.generateReadView();
writer.writeView(readViewCode, "read.html");
String editViewCode = viewGen.generateEditView();
writer.writeView(editViewCode, "edit.html");
}
Why it follows SRP:
- ✅ Only reason to change: Workflow/sequence changes (e.g., add validation step)
- ✅ Single focus: Orchestrating the generation process
- ✅ No other concerns: Doesn’t generate code, doesn’t write files directly
- ✅ High cohesion: All code relates to workflow coordination
Example change scenario:
- If we add a step to generate unit tests, we only modify this class
- Individual generators remain unchanged
Before vs After SRP Refactoring
❌ Before (Monolithic - Violates SRP)
public class GenerateTablePage {
static String createController() throws IOException {
// 1. Computes configuration
// 2. Generates controller code
// 3. Creates directories
// 4. Writes to file
// Multiple responsibilities in one method!
}
static String createView() throws IOException {
// 1. Computes configuration
// 2. Generates view code
// 3. Creates directories
// 4. Writes to file
// Multiple responsibilities in one method!
}
}
Problems:
- ❌ Multiple reasons to change: Configuration changes, code generation changes, file I/O changes all affect the same method
- ❌ Hard to test: Can’t test code generation without file system operations
- ❌ Low reusability: Can’t reuse generation logic without file writing
- ❌ Tight coupling: Everything depends on everything
✅ After (SRP-Compliant)
// Each class has ONE reason to change
GenerationConfig → Configuration logic changes
FileWriter → File I/O changes
ControllerGenerator → Controller template changes
ViewGenerator → View template changes
GenerateTablePage → Workflow changes
Benefits:
- ✅ Single reason to change: Each class changes for only one reason
- ✅ Easy to test: Can test generators without file I/O
- ✅ High reusability: Can use generators independently
- ✅ Loose coupling: Classes interact through clean interfaces
SRP Benefits in Practice
1. Maintainability
- Changing controller template? → Only edit
ControllerGenerator - Changing file locations? → Only edit
FileWriter - Adding new configuration? → Only edit
GenerationConfig
2. Testability
// Can test code generation without file system
ControllerGenerator gen = new ControllerGenerator(mockConfig);
String code = gen.generate();
assert code.contains("@Controller");
// Can test file writing with different implementations
FileWriter writer = new FileWriter(config);
// Or: FileWriter writer = new InMemoryFileWriter(config); // for testing
3. Extensibility
// Easy to add new generators
class ApiControllerGenerator {
String generate() { /* REST API logic */ }
}
// Easy to add new writers
class S3FileWriter extends FileWriter {
String writeController(String code) { /* Upload to S3 */ }
}
4. Understandability
- New developers can understand one class at a time
- Clear separation makes the system architecture obvious
- Each class name describes exactly what it does
Dependency Flow (SRP-Compliant)
┌─────────────────────┐
│ GenerateTablePage │ ← Orchestrator (knows workflow)
│ (main) │
└──────────┬──────────┘
│
├──────────────────────────────────┐
│ │
↓ ↓
┌──────────────────┐ ┌──────────────────┐
│ GenerationConfig │←─────────────│ FileWriter │
│ (configuration) │ │ (file I/O) │
└──────────────────┘ └──────────────────┘
↑ ↑
│ │
├──────────────────┬───────────────┤
│ │ │
┌───────────────┐ ┌──────────────┐ │
│ Controller │ │ View │ │
│ Generator │ │ Generator │ │
│ (controller) │ │ (views) │ │
└───────────────┘ └──────────────┘ │
│ │ │
└──────────────────┴──────────────┘
Generate code → Pass to writer
Key points:
- Config is shared (dependency injection)
- Generators produce code (strings)
- Writer saves code (file I/O)
- Main orchestrates the flow
SRP Verification Checklist
| Class | Single Responsibility | Reason to Change | SRP Compliant? |
|---|---|---|---|
| GenerationConfig | Manage configuration | Configuration logic changes | ✅ Yes |
| FileWriter | Write to filesystem | File I/O changes | ✅ Yes |
| ControllerGenerator | Generate controller code | Controller template changes | ✅ Yes |
| ViewGenerator | Generate view templates | View template changes | ✅ Yes |
| GenerateTablePage | Orchestrate workflow | Workflow sequence changes | ✅ Yes |
Related SOLID Principles
While this refactoring primarily focuses on SRP, it also improves adherence to other SOLID principles:
Open/Closed Principle (OCP)
- Can extend with new generators without modifying existing ones
- Example: Add
RestApiGeneratorwithout changingControllerGenerator
Dependency Inversion Principle (DIP)
- All classes depend on
GenerationConfig(abstraction) - Could easily introduce interfaces for
FileWriter,ControllerGenerator, etc.
Interface Segregation Principle (ISP)
- Each class has a focused interface with minimal methods
- No “fat interfaces” with unnecessary methods
Liskov Substitution Principle (LSP)
- Future subclasses (e.g.,
CloudFileWriter) can replaceFileWriterwithout issues
Conclusion
The Auto-Table Generation System is fully SRP-compliant. Each class has:
- ✅ One responsibility
- ✅ One reason to change
- ✅ High cohesion
- ✅ Loose coupling
This architecture provides:
- Maintainability - Easy to modify individual components
- Testability - Can test each component in isolation
- Extensibility - Simple to add new features
- Understandability - Clear, logical structure
SRP Status: ✅ COMPLIANT