9

Most readers will be familiar with Bob Martin's famous dependency inversion principle, which states

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions

  2. Abstractions should not depend upon details. Details should depend upon abstractions

I believe I understand it all pretty well, except for the first sentence in the second line - "Abstractions should not depend upon details". What does this mean exactly? What would be a simple example of an abstraction being dependent upon a detail?

1
  • 1
    The definition of "abstraction" and "detail" should clarify this. What part of the definition of "abstraction" confuses you? Perhaps you could update the question to explain why the words are confusing. We're not you, so we don't know what part of this confuses you.
    – S.Lott
    Commented Apr 4, 2011 at 15:13

3 Answers 3

14

What he's saying here is that you should avoid a scenario where a base class takes a dependency to meet the need of a descendant. Let's look at the case of a Switch and its descendant the TimedSwitch. The TimedSwitch is a Switch that resets itself after a certain amount of time. We have the TimedObject class already so it would make sense for TimedSwitch to derive from it...however TimedSwitch already derives from Switch. So in order to meet the needs of the TimedSwitch, Switch will inherit from TimedObject even though it doesn't need that functionality itself.

The Switch (abstraction) is dependent on the details of TimedSwitch. To fix this violation of the DIP, we have TimedSwitch implement ITimedObject and delegate to a contained TimedObject class (prefer composition over inheritance).

Another more generic example is the layered approach. The higher level layers are abstractions and in most cases they depend on the details. DIP says that instead, the lower layers should conform to an interface which they both take dependency on. Thus the dependency is inverted from Higher Layer depending on lower layer to both layers depending on an interface.

2
  • So where is the inversion in the layers example? I can only see new abstraction introduced with additional dependency on it. What exactly is inverted?
    – ᄂ ᄀ
    Commented May 5, 2013 at 12:33
  • Unless I misread, the answer pivots on implementation-inheritance being singular. Commented Jun 7, 2021 at 15:53
2

The controller module uses the ControllableThing abstraction (interface) to control a Thing module.

A bad design would have the ControllableThing interface exposing the number of LED lights in the FizzBuzz corporation Thing the project was written for originally. setLed1(boolen state) setLed2(boolen state) setLed3(boolen state) setLed4(boolen state)

that sort of thing...

So now, both modules will break when we go to control a Nazbatag intelligent rabbit module.

The DI principle is really about getting the dependancy graph for the system to have very short paths from modules to interfaces.

When the abstractions are done right the systems won't break next week.

Judgement should be used, because the temptation to make generic interfaces leads things that look like SOAP and the Unix device model. A meta system can help if you're architecting systems of systems. There is a design force here pushing towards dynamic languages and call-time binding. It's not necessary or helpful to give in to it all the time.

1
  • +1 Great footnote about using the right tool for the job.
    – jv42
    Commented Apr 4, 2011 at 8:27
0

Abstraction means to "forget" or "surpress" details and only use what you need. I find the best way to word abstraction is taken from Ole John Dahl in Structured Programming (https://dl.acm.org/doi/book/10.5555/1243380 section 3). He says something along the lines of "abstract away details that are too far removed and concentrate on the details that are most related to your problem".

So he's saying, don't make your abstractions based on details that you are supposed to be abstracting away. Here's an example:

class String
{
public:
    char characters[32];
};

Applying what he is saying here, the abstraction String shouldn't depend on the details of how its implemented. Or worded differently - the users of string should not depend on the details that are too far removed on what they're using the string for. A user of string doesn't usually care about the computer representation, but cares about what can be done to it.

Here is the String abstraction properly abstracted:

class String
{
public:
    void Concat(String* other_string);
    void Append(char c);
    int Length();
    
private: /* Private here, this is suppressing the details */
    char characters[32];
};

Note how the "details" being the character array is now hidden (or surpressed, abstracted away) and the users of the String class no longer depend on the details.

This book has an amazing explanation of abstraction. Highly recommend skimming it to see how simple abstraction (both procedural and data abstraction) is.

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-4.html#%_toc_start

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-9.html#%_chap_1 https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1 https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-17.html#%_sec_2.4.1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.