DEV Community

Saras Growth Space
Saras Growth Space

Posted on

LLD Design Patterns: The Problems SOLID Was Never Designed to Solve

In the previous article, we answered an important question:

What does SOLID actually solve?

We saw that SOLID helps us design software that is easier to understand, maintain, test, and extend by improving the quality of individual classes and their relationships.

But software engineering doesn't stop there.

Even when every class follows SOLID principles, experienced engineers continue to encounter a different category of problems.

These problems don't indicate that SOLID has failed.

They simply belong to a different level of design.

Understanding this distinction is one of the biggest mindset shifts in becoming a better software engineer.


Good Design Doesn't Mean Every Problem Disappears

Imagine you've built an e-commerce application.

You've carefully applied SOLID.

  • Every class has a single responsibility.
  • Dependencies are injected through interfaces.
  • Interfaces are small and focused.
  • The code is easy to test.

Everything looks clean.

Then the product team starts introducing new features.

  • Customers can pay using different payment providers.
  • Notifications can be sent through Email, SMS, Push, or WhatsApp.
  • Shipping partners vary by country.
  • Premium customers receive different pricing.
  • Recommendations use different algorithms.

Your classes are still well designed.

But new questions begin to appear.

Notice that these questions aren't about making a class smaller or splitting responsibilities.

They're about how multiple well-designed classes should work together.


SOLID Doesn't Decide How Objects Should Be Created

Suppose your application supports several payment gateways.

Stripe
PayPal
Razorpay
Apple Pay
Enter fullscreen mode Exit fullscreen mode

A business rule says:

"Choose the appropriate payment provider based on the customer's selection."

Where should that decision live?

Should every service contain a long if-else statement?

Should each class create payment objects itself?

Should object creation be centralized?

These are important design questions.

SOLID doesn't prescribe the answer.

That's because object creation is a different design concern.


SOLID Doesn't Decide How Behavior Should Change

Imagine a ride-sharing application.

Pricing depends on many factors:

  • Standard ride
  • Premium ride
  • Airport ride
  • Peak hours
  • Festival pricing

Initially, the pricing logic is simple.

As new pricing rules arrive, the calculation becomes increasingly complex.

Now ask yourself:

How should the system switch between different pricing algorithms without constantly modifying existing code?

SOLID encourages extensibility.

But it doesn't define the mechanism for organizing interchangeable behaviors.


SOLID Doesn't Decide How Independent Components Communicate

Think about an online shopping platform.

When an order is placed, many things happen.

Order Created
      │
      ├── Inventory Updated
      ├── Payment Confirmed
      ├── Loyalty Points Added
      ├── Notification Sent
      └── Analytics Recorded
Enter fullscreen mode Exit fullscreen mode

Should the OrderService directly call every other service?

If another feature is introduced tomorrow, should it be modified again?

Soon one service starts knowing too much about the rest of the system.

The issue isn't responsibility anymore.

The issue is communication.

SOLID doesn't define a general strategy for organizing interactions between many collaborating objects.


SOLID Doesn't Solve Integration Problems

Suppose your company integrates with a shipping partner.

Your system expects:

calculateShippingCost()
Enter fullscreen mode Exit fullscreen mode

The shipping partner provides:

getFreightEstimate()
Enter fullscreen mode Exit fullscreen mode

Both systems are correct.

Both work perfectly.

The challenge is simply that they speak different "languages."

No SOLID principle explains how to bridge incompatible interfaces.

That requires a different kind of design thinking.


SOLID Doesn't Tell You How to Add Features Dynamically

Imagine a coffee ordering application.

Customers can customize drinks.

Coffee
Enter fullscreen mode Exit fullscreen mode

Later they add:

Coffee
 + Milk
Enter fullscreen mode Exit fullscreen mode

Then:

Coffee
 + Milk
 + Caramel
Enter fullscreen mode Exit fullscreen mode

Then:

Coffee
 + Milk
 + Caramel
 + Whipped Cream
Enter fullscreen mode Exit fullscreen mode

Should you create a new class for every possible combination?

What happens when the menu grows?

The challenge is no longer about responsibility.

It's about extending behavior in a flexible way.


A Pattern Begins to Emerge

Look back at all the previous examples.

Although they belong to different domains, they're asking surprisingly similar questions.

  • Who should create objects?
  • How should behavior change dynamically?
  • How should components communicate?
  • How should incompatible systems work together?
  • How should features be added without creating an explosion of subclasses?

These questions appear in:

  • banking systems
  • e-commerce platforms
  • ride-sharing applications
  • hospital management systems
  • inventory systems
  • content platforms

The business domains are different.

The design problems are remarkably similar.

That observation changed the way experienced software engineers approached design.


Weak Thinking vs Strong Thinking

Weak Thinking

"Every new project has completely unique design challenges."

Strong Thinking

"Business requirements differ, but many underlying design problems repeat across projects."

Once you start recognizing recurring problems instead of isolated situations, you're thinking much more like an experienced engineer.


Common Beginner Mistake

Many developers believe that when their design starts becoming difficult, they simply haven't applied SOLID well enough.

Sometimes that's true.

But often, the responsibilities are already clear.

The real challenge lies elsewhere:

  • coordinating objects,
  • creating them,
  • extending them,
  • or allowing them to collaborate cleanly.

Trying to solve every problem with SOLID alone is like trying to fix every construction problem with better bricks.

Sometimes the challenge isn't the bricks.

It's the blueprint.


Interview Perspective

Interviewers often present scenarios that sound like business problems but are actually testing whether you recognize recurring design challenges.

For example:

  • "We need to support multiple payment gateways."
  • "Users can choose different notification channels."
  • "The pricing algorithm changes frequently."
  • "We're integrating with a third-party API."

They're not looking for pattern names immediately.

They're looking for whether you recognize the type of problem before proposing a solution.

Strong candidates identify the recurring design concern first.

Only then do they choose an appropriate pattern.


Key Insight

SOLID gives us principles for designing maintainable components.

As software grows, recurring challenges appear around object creation, behavior, communication, integration, and extension.

These aren't failures of SOLID.

They're simply different categories of design problems.

Understanding those recurring problems is what eventually led to the development of Design Patterns.


In This Article, You Learned

  • Why well-designed software still encounters new design challenges.
  • The categories of problems SOLID wasn't intended to solve.
  • Why recurring design problems appear across completely different domains.
  • Why recognizing the problem is more important than memorizing the solution.

One-Line Takeaway

SOLID builds strong components; Design Patterns help those components solve recurring collaboration and evolution problems.

Top comments (0)