--- id: solid-isp-interfaces title: SOLID - Interface Segregation (Small Interfaces) category: solid-principles priority: critical tags: [SOLID, ISP, interface-segregation, cohesion] related: [solid-isp-clients, solid-srp-class, core-separation-concerns] --- # Interface Segregation Principle - Small Cohesive Interfaces Interfaces should be small and cohesive, grouping only closely related methods. Split large interfaces into smaller, more focused ones. ## Bad Example ```typescript // Anti-pattern: Large interface with unrelated methods grouped together interface Document { // Content operations getContent(): string; setContent(content: string): void; appendContent(content: string): void; // Persistence operations save(): Promise; load(id: string): Promise; delete(): Promise; // Export operations exportToPdf(): Promise; exportToWord(): Promise; exportToHtml(): Promise; // Collaboration operations share(userId: string): Promise; getCollaborators(): Promise; addComment(comment: Comment): Promise; getComments(): Promise; // Version control createVersion(): Promise; getVersionHistory(): Promise; revertToVersion(versionId: string): Promise; // Permissions setPermissions(permissions: Permissions): Promise; getPermissions(): Promise; checkPermission(userId: string, action: string): Promise; } // Simple note-taking app forced to implement everything class SimpleNote implements Document { private content: string = ''; getContent(): string { return this.content; } setContent(content: string): void { this.content = content; } appendContent(content: string): void { this.content += content; } // Forced to implement methods it doesn't need async save(): Promise { throw new Error('Not supported'); } async load(id: string): Promise { throw new Error('Not supported'); } async delete(): Promise { throw new Error('Not supported'); } async exportToPdf(): Promise { throw new Error('Not supported'); } async exportToWord(): Promise { throw new Error('Not supported'); } async exportToHtml(): Promise { throw new Error('Not supported'); } async share(userId: string): Promise { throw new Error('Not supported'); } async getCollaborators(): Promise { throw new Error('Not supported'); } async addComment(comment: Comment): Promise { throw new Error('Not supported'); } async getComments(): Promise { throw new Error('Not supported'); } async createVersion(): Promise { throw new Error('Not supported'); } async getVersionHistory(): Promise { throw new Error('Not supported'); } async revertToVersion(versionId: string): Promise { throw new Error('Not supported'); } async setPermissions(permissions: Permissions): Promise { throw new Error('Not supported'); } async getPermissions(): Promise { throw new Error('Not supported'); } async checkPermission(userId: string, action: string): Promise { throw new Error('Not supported'); } } ``` ## Good Example ```typescript // Correct approach: Small, cohesive interfaces // Core content interface - the essence of a document interface DocumentContent { getContent(): string; setContent(content: string): void; } // Extended content operations interface EditableContent extends DocumentContent { appendContent(content: string): void; insertContent(position: number, content: string): void; deleteRange(start: number, end: number): void; } // Persistence operations interface Persistable { save(): Promise; load(id: string): Promise; } interface Deletable { delete(): Promise; } // Export capabilities interface PdfExportable { exportToPdf(): Promise; } interface WordExportable { exportToWord(): Promise; } interface HtmlExportable { exportToHtml(): Promise; } // Combine export interfaces when needed interface FullyExportable extends PdfExportable, WordExportable, HtmlExportable {} // Collaboration interfaces interface Shareable { share(userId: string, permission: Permission): Promise; unshare(userId: string): Promise; getCollaborators(): Promise; } interface Commentable { addComment(comment: Comment): Promise; removeComment(commentId: string): Promise; getComments(): Promise; } // Version control interface Versionable { createVersion(message?: string): Promise; getVersionHistory(): Promise; revertToVersion(versionId: string): Promise; } // Permissions interface PermissionControlled { setPermissions(permissions: Permissions): Promise; getPermissions(): Promise; checkPermission(userId: string, action: string): Promise; } // Simple note only implements what it needs class SimpleNote implements DocumentContent { private content: string = ''; getContent(): string { return this.content; } setContent(content: string): void { this.content = content; } } // Persistent note adds storage class PersistentNote implements EditableContent, Persistable { private content: string = ''; private id: string | null = null; constructor(private storage: StorageService) {} getContent(): string { return this.content; } setContent(content: string): void { this.content = content; } appendContent(content: string): void { this.content += content; } insertContent(position: number, content: string): void { this.content = this.content.slice(0, position) + content + this.content.slice(position); } deleteRange(start: number, end: number): void { this.content = this.content.slice(0, start) + this.content.slice(end); } async save(): Promise { this.id = await this.storage.save(this.content); } async load(id: string): Promise { this.content = await this.storage.load(id); this.id = id; } } // Full-featured collaborative document class CollaborativeDocument implements EditableContent, Persistable, Deletable, FullyExportable, Shareable, Commentable, Versionable, PermissionControlled { constructor( private storage: StorageService, private exportService: ExportService, private collaborationService: CollaborationService, private versionService: VersionService, private permissionService: PermissionService ) {} // Implement all methods with actual functionality // Each service handles its domain getContent(): string { /* ... */ } setContent(content: string): void { /* ... */ } appendContent(content: string): void { /* ... */ } insertContent(position: number, content: string): void { /* ... */ } deleteRange(start: number, end: number): void { /* ... */ } async save(): Promise { /* delegate to storage */ } async load(id: string): Promise { /* delegate to storage */ } async delete(): Promise { /* delegate to storage */ } async exportToPdf(): Promise { return this.exportService.toPdf(this); } async exportToWord(): Promise { return this.exportService.toWord(this); } async exportToHtml(): Promise { return this.exportService.toHtml(this); } async share(userId: string, permission: Permission): Promise { /* ... */ } async unshare(userId: string): Promise { /* ... */ } async getCollaborators(): Promise { /* ... */ } async addComment(comment: Comment): Promise { /* ... */ } async removeComment(commentId: string): Promise { /* ... */ } async getComments(): Promise { /* ... */ } async createVersion(message?: string): Promise { /* ... */ } async getVersionHistory(): Promise { /* ... */ } async revertToVersion(versionId: string): Promise { /* ... */ } async setPermissions(permissions: Permissions): Promise { /* ... */ } async getPermissions(): Promise { /* ... */ } async checkPermission(userId: string, action: string): Promise { /* ... */ } } // Functions can accept only the interfaces they need function renderDocument(doc: DocumentContent): void { console.log(doc.getContent()); } async function exportToPdf(doc: PdfExportable): Promise { const pdf = await doc.exportToPdf(); // Send pdf... } function canUserEdit(doc: PermissionControlled, userId: string): Promise { return doc.checkPermission(userId, 'edit'); } // All document types work where their interfaces are expected const simpleNote = new SimpleNote(); renderDocument(simpleNote); // Works! const collabDoc = new CollaborativeDocument(/* ... */); renderDocument(collabDoc); // Works! await exportToPdf(collabDoc); // Works! await canUserEdit(collabDoc, 'user123'); // Works! ``` ## Why 1. **Cohesion**: Each interface groups related methods. `Commentable` is about comments, `Versionable` about versions. 2. **Flexibility**: Classes implement only the interfaces that match their capabilities. 3. **Composability**: Complex types are built by combining simple interfaces: `EditableContent & Persistable & Shareable`. 4. **No Empty Implementations**: No need for `throw new Error('Not supported')` - just don't implement the interface. 5. **Clear Capabilities**: Looking at a class's implemented interfaces tells you exactly what it can do. 6. **Easier Evolution**: Add new capabilities by creating new interfaces without modifying existing ones. 7. **Better Typing**: Functions declare exactly what they need. `exportToPdf(doc: PdfExportable)` is self-documenting.