Win a copy of Building Blockchain Apps this week in the Cloud/Virtualization forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Paul Clapham
  • Liutauras Vilda
  • Knute Snortum
  • Bear Bibeault
Sheriffs:
  • Devaka Cooray
  • Jeanne Boyarsky
  • Junilu Lacar
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
  • salvin francis
Bartenders:
  • Tim Holloway
  • Piet Souris
  • Frits Walraven

Dependency Inversion Principle

 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm reading Robert Martin's Agile Software Development and enjoying it a lot. But his description of DIP runs counter to some common "top down" practices. I wonder if it's just a matter of knowing when to use it and when not to.
For example, in architectural layers we usually think of services making interfaces available to clients. Clients have compile-time dependency on services, never the other way around. The theory is that many clients can use a service. So in MVC, many views can use a model.
With DIP, the client publishes an interface which the server must implement. The theory is that the client contains high level policies, the core business rules that define the company. The services are details, like how to persist data. We want to preserve the high level policies across changes in details.
Java actually uses both patterns at once. For example JDBC is a service with a set of interfaces that many clients can use. On the other side, as a client to an RDBMS, it defines a set of interfaces that the database must implement.
Any thoughts on how to chose which way to turn your dependencies? Less stable depends on more stable? Core policies do not depend on details? Client can use any number of plug-and-play services?
 
Ranch Hand
Posts: 67
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Originally posted by Stan James:
I'm reading Robert Martin's Agile Software Development and enjoying it a lot. But his description of DIP runs counter to some common "top down" practices. For example, in architectural layers we usually think of services making interfaces available to clients. Clients have compile-time dependency on services, never the other way around. The theory is that many clients can use a service. So in MVC, many views can use a model.


I haven't read the book yet, but I've read the article on the Object Mentor website (here). He does say:

Frankly, it is because more traditional
software development methods, such as Structured Analysis and Design, tend to create
software structures in which high level modules depend upon low level modules, and in
which abstractions depend upon details. Indeed one of the goals of these methods is to
define the subprogram hierarchy that describes how the high level modules make calls to
the low level modules.


So I agree he's differing with traditional 'top-down' practices. But I'm unclear of how that leads to a server having a compile-time dependency on the client.
He states the Dependency Inversion Principle as:

  • HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.
  • ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS
  • Is the principle stated differently in his book? Is there an example that shows how this leads to the server being dependant on the client? [I'm pretty sure that isn't Uncle Bob's intent ]

    Any thoughts on how to chose which way to turn your dependencies? Less stable depends on more stable?


    I know I've seen that stated somewhere but I don't remember if it was in one of the articles on the Object Mentor site or in discussing a tool like JDepend.
     
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Originally posted by Richard Jensen:

    I know I've seen that stated somewhere but I don't remember if it was in one of the articles on the Object Mentor site or in discussing a tool like JDepend.


    Probably both!
    See also http://c2.com/cgi/wiki?StableDependenciesPrinciple
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Originally posted by Stan James:
    For example, in architectural layers we usually think of services making interfaces available to clients. Clients have compile-time dependency on services, never the other way around. The theory is that many clients can use a service. So in MVC, many views can use a model.


    I would in fact think of MVC as a good example of the DIP!

    With DIP, the client publishes an interface which the server must implement. The theory is that the client contains high level policies, the core business rules that define the company. The services are details, like how to persist data.


    Or how to view it. That is, the model is using a view to present the data, but doesn't depend on the details of how exactly the data is represented to the user.
    Another example from practice: we recently put a thin abstraction layer between log4j and our business classes. It contains interfaces defining how logging is used in our application and an implementation of those interfaces delegating to log4j. This approach not only makes it possible to use a different implementation if log4j isn't available, it also significantly simplifies unit testing of logging messages.
     
    Ranch Hand
    Posts: 264
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Is this like the "extreme" approach of unit testing? Instead of generate unit test cases after you finish your code, generate unit test before you even start coding.
    Thus, clients requirements will direct how the server interface will be implemented...
     
    Stan James
    (instanceof Sidekick)
    Posts: 8791
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I missed an important line in my reading, that both layers should depend on abstractions. You can put an adapter between two layers that depends on both. Then neither layer has a dependency on the other.
    Compile-time dependency comes from who defines the abstraction. It could go either way. Say a view has an event listener to be notified when the model changes. The model might say: if you want events, implement my model-specific interface and register for events. Now the view cannot be compiled without the model, and model interface changes can break the view. This is probably better than the other way around, as we expect the model be more stable than the view.
    Here is another good Martin paper about stability, reuse and the direction of dependency. Also shows DIP very nicely. Compile- time dependencies are a big part of the "copy" example.
    To nit pick: I don't think I agreed with Ilja's notion of the model "using the view" to display itself. The model has no incentive to be viewed. It's just chugging along doing the business. It has a facility to let any interested party - view or other - know when things change but doesn't know or care if anyone is listening.
    Or am I wrong - do you have MVC implementations where the view defines the APIs and the model must know the view to compile?
     
    Stan James
    (instanceof Sidekick)
    Posts: 8791
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I skipped right over Edy's excellent point that with TDD the client requirements define the service's API. I think that's right on the money for the first client or first test. XP folks do the simplest thing that can possibly work, and that does not include introducing abstractions BEFORE you need them. See the "copy" example in the link I put above. Not until requirements for more sources and destinations came along was there a need for any abstractions. It would be overengineering to put them in at first. Well, so say the agile folk.
    There's a principle I like that cardinality should be zero, one or infinity. As soon as the solution calls for more than one of something, don't make a cludge that handles two, make something that will support any number. That's the jump from the simple copy program to the full DIP version - support any number of details without recompiling the "policy" code.
     
    He baked a muffin that stole my car! And this tiny ad:
    Java file APIs (DOC, XLS, PDF, and many more)
    https://products.aspose.com/total/java
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!