// ============================================================================
// DEEP MODULES - Simple interface, powerful functionality
// ============================================================================
// Example 1: Deep Module - File System Abstraction
class FileManager {
// Simple interface - just one method with minimal parameters
async saveData(filename: string, data: any): Promise<void> {
// Complex internal implementation hidden from user
try {
const serializedData = this.serialize(data);
const compressedData = await this.compress(serializedData);
const encryptedData = this.encrypt(compressedData);
await this.writeToFile(filename, encryptedData);
await this.updateMetadata(filename);
this.logOperation('save', filename);
} catch (error) {
await this.handleError(error, filename);
throw new Error(`Failed to save data to ${filename}`);
}
}
// All the complexity is hidden in private methods
private serialize(data: any): string {
// Handle circular references, dates, etc.
return JSON.stringify(data, this.replacer);
}
private async compress(data: string): Promise<Buffer> {
// Complex compression logic
return Buffer.from(data); // Simplified
}
private encrypt(data: Buffer): Buffer {
// Complex encryption logic
return data; // Simplified
}
private async writeToFile(filename: string, data: Buffer): Promise<void> {
// Handle file system operations, atomic writes, etc.
}
private async updateMetadata(filename: string): Promise<void> {
// Update file metadata, indices, etc.
}
private logOperation(operation: string, filename: string): void {
// Complex logging with different levels, formatters, etc.
}
private async handleError(error: Error, filename: string): Promise<void> {
// Complex error handling, cleanup, notifications, etc.
}
private replacer(key: string, value: any): any {
// Handle special cases in serialization
return value;
}
}
// Usage: Very simple despite complex internal operations
const fileManager = new FileManager();
await fileManager.saveData('user-data.json', { users: [...] });
// Example 2: Deep Module - HTTP Client
class HttpClient {
// Simple interface
async get<T>(url: string): Promise<T> {
return this.request<T>('GET', url);
}
async post<T>(url: string, data?: any): Promise<T> {
return this.request<T>('POST', url, data);
}
// Complex functionality hidden inside
private async request<T>(method: string, url: string, data?: any): Promise<T> {
// Handles retries, timeouts, authentication, caching,
// request/response transformations, error handling, etc.
const config = this.buildRequestConfig(method, url, data);
let attempt = 0;
while (attempt < this.maxRetries) {
try {
const response = await this.executeRequest(config);
return this.transformResponse<T>(response);
} catch (error) {
if (this.shouldRetry(error, attempt)) {
attempt++;
await this.delay(this.calculateBackoff(attempt));
continue;
}
throw this.transformError(error);
}
}
throw new Error('Max retries exceeded');
}
private buildRequestConfig(method: string, url: string, data?: any) { /* ... */ }
private async executeRequest(config: any) { /* ... */ }
private transformResponse<T>(response: any): T { /* ... */ }
private shouldRetry(error: any, attempt: number): boolean { /* ... */ }
private delay(ms: number): Promise<void> { /* ... */ }
private calculateBackoff(attempt: number): number { /* ... */ }
private transformError(error: any): Error { /* ... */ }
private maxRetries = 3;
}
// ============================================================================
// SHALLOW MODULES - Complex interface, limited functionality
// ============================================================================
// Example 1: Shallow Module - Over-parameterized Configuration
class DatabaseConnection {
// Complex interface with too many parameters and options
async connect(
host: string,
port: number,
database: string,
username: string,
password: string,
connectionTimeout: number,
queryTimeout: number,
maxRetries: number,
retryDelay: number,
poolSize: number,
poolTimeout: number,
ssl: boolean,
sslCert?: string,
sslKey?: string,
sslCA?: string,
charset: string,
timezone: string,
dateStrings: boolean,
debug: boolean,
trace: boolean,
acquireTimeout: number,
reconnect: boolean,
idleTimeout: number
): Promise<void> {
// Simple functionality - just connects to database
// All the complexity is pushed to the caller
console.log(`Connecting to ${username}@${host}:${port}/${database}`);
}
}
// Usage: Caller has to understand and provide too many details
const db = new DatabaseConnection();
await db.connect(
'localhost', 5432, 'mydb', 'user', 'pass',
30000, 60000, 3, 1000, 10, 5000,
true, '/path/cert', '/path/key', '/path/ca',
'utf8', 'UTC', false, false, false,
10000, true, 300000
);
// Example 2: Shallow Module - Leaky Abstraction
class TextProcessor {
// Interface exposes internal implementation details
processText(
text: string,
shouldTrim: boolean,
shouldLowercase: boolean,
shouldRemoveSpecialChars: boolean,
specialCharsRegex: RegExp,
shouldValidateLength: boolean,
minLength: number,
maxLength: number,
shouldSanitizeHtml: boolean,
allowedHtmlTags: string[],
shouldNormalizeWhitespace: boolean,
whitespaceNormalizationMode: 'single' | 'remove' | 'preserve'
): string {
// Minimal functionality that could be much simpler
let result = text;
if (shouldTrim) result = result.trim();
if (shouldLowercase) result = result.toLowerCase();
if (shouldRemoveSpecialChars) result = result.replace(specialCharsRegex, '');
// ... more simple operations
return result;
}
}
// ============================================================================
// REFACTORED: Converting Shallow to Deep
// ============================================================================
// Better version - Deep Module
class TextProcessor_Improved {
// Simple interface with sensible defaults
cleanText(text: string, options?: {
preserveCase?: boolean;
allowHtml?: boolean;
strictMode?: boolean;
}): string {
// Complex logic hidden with intelligent defaults
const config = this.buildConfig(options);
return this.applyTransformations(text, config);
}
// Specialized methods for specific use cases
sanitizeUserInput(text: string): string {
return this.cleanText(text, { strictMode: true });
}
prepareForDisplay(text: string): string {
return this.cleanText(text, { allowHtml: true });
}
// All complexity hidden in private methods
private buildConfig(options?: any) {
// Intelligent defaults based on common use cases
return {
trim: true,
normalizeWhitespace: true,
removeSpecialChars: options?.strictMode ?? false,
preserveCase: options?.preserveCase ?? false,
allowHtml: options?.allowHtml ?? false,
// ... more intelligent defaults
};
}
private applyTransformations(text: string, config: any): string {
// Complex transformation pipeline
let result = text;
if (config.trim) result = this.trim(result);
if (config.normalizeWhitespace) result = this.normalizeWhitespace(result);
if (config.removeSpecialChars) result = this.removeSpecialChars(result);
if (!config.preserveCase) result = this.normalizeCase(result);
if (!config.allowHtml) result = this.sanitizeHtml(result);
return this.validate(result, config);
}
private trim(text: string): string { /* ... */ return text; }
private normalizeWhitespace(text: string): string { /* ... */ return text; }
private removeSpecialChars(text: string): string { /* ... */ return text; }
private normalizeCase(text: string): string { /* ... */ return text; }
private sanitizeHtml(text: string): string { /* ... */ return text; }
private validate(text: string, config: any): string { /* ... */ return text; }
}
// Usage: Much simpler and more intuitive
const processor = new TextProcessor_Improved();
const clean = processor.cleanText(" Hello <script>World</script>! ");
const userInput = processor.sanitizeUserInput(userProvidedText);
const displayText = processor.prepareForDisplay(contentFromCMS);