DEV Community

kirandeepjassal-crypto
kirandeepjassal-crypto

Posted on

SOLID Principles in C# — I Refactored 60 Ugly Lines, One Rule at a Time

SOLID is a default, not a religion.

Most articles teach the five principles with toy examples — a Square that violates LSP, a Logger that violates SRP. You finish having memorised five acronyms with no idea what to do on Monday morning when your real order service has 11 reasons to change and a switch statement on payment type.

So I took a real, ugly 60-line order-processing service that breaks every SOLID rule, and refactored it one principle at a time.

The starting point

public class OrderService
{
    public void PlaceOrder(Order order)
    {
        // validate, apply discount, charge Stripe,
        // open SqlConnection, send SMTP email,
        // append to a log file
        // 60 lines. 6 jobs. 3 hard-coded providers.
    }
}
Enter fullscreen mode Exit fullscreen mode

Untestable without a real Stripe key, a real database, and an SMTP server. Every change touches the same file.

One principle at a time

  • S — Single Responsibility: 6 jobs in one method → 6 collaborators, each with one stakeholder (finance owns payments, marketing owns email, DBA owns schema).
  • O — Open / Closed: a switch statement on payment type → strategy interface. Adding Apple Pay is one new class, zero edits to existing code.
  • L — Liskov Substitution: cash-on-delivery silently returning success from ChargeAsync → honest PaymentResult with a DeferredToDelivery status. The type system tells the truth.
  • I — Interface Segregation: a god IPaymentMethod interface forcing COD to throw NotSupportedException from three methods → split into capabilities (IRefundable, IRecurringCapable, IDisputable).
  • D — Dependency Inversion: hard-coded Stripe + SQL + SMTP inside the service → injected abstractions. Now I can write a unit test that runs in 5 ms with zero infrastructure.

The honest disadvantages

SOLID has real costs:

  • More files (6 classes instead of 1)
  • More constructor parameters
  • Harder for new devs to follow the flow (interface → implementation jumping)
  • Premature abstraction is worse than no abstraction

Apply by default, break with a reason. Document the reason. That's the whole game.

Watch the 2-min walkthrough

Go deeper

The full guide has the complete side-by-side refactor, a 5-question pull-request checklist you can paste into your PR template, and the 6 honest disadvantages each principle costs you:

https://prepstack.co.in/blog/solid-principles-csharp-real-project-deep-dive


Which principle do you find yourself bending most often in real code? Drop your honest answer in the comments.

Top comments (0)