The 'Interfacing Net Thing' Challenged: Is Over-Interfacing an Anti-Pattern in Modern Development?

Derek Martin from codepinion.com recently ignited a discussion within the developer community, labeling the widespread practice of ‘interfacing everything’ as an anti-pattern, particularly within .NET development. Martin illustrates this with a common example: an IOrderService injecting IInventoryService, IPaymentService, and IEmailService, where each ‘service’ often functions as a single-implementation ‘dumping ground’ rather than a true abstraction. He contends that this prevalent approach frequently stems from a misinterpretation of Dependency Injection (DI) principles and an uncritical adoption of interfaces for every type, resulting in increased complexity without delivering the anticipated benefits of reduced coupling or enhanced extensibility. Martin attributes this over-interfacing to developers creating interfaces ‘just in case’ a future implementation might be needed, even when only one concrete class exists, effectively leading to ‘writing contracts to talk to themselves.’

Martin advocates for a more pragmatic design, suggesting that direct dependencies on concrete types are often sufficient, simplifying DI container registrations. For scenarios truly requiring behavior substitution, such as during testing, he proposes alternatives like delegates for single-method behaviors or extending concrete classes with virtual methods to override specific functionalities. While acknowledging the intrinsic value of interfaces, Martin emphasizes their appropriate application: simplifying API surfaces, defining clear contracts at system boundaries, and facilitating genuinely multiple, distinct implementations (e.g., integrating with various email providers like SendGrid or AWS SES). He concludes that the indiscriminate abstraction of every component, often propelled by an incomplete understanding of DI’s purpose, ultimately yields an overly abstract system that is harder to maintain rather than more flexible.