Software development is all about dependency management

All substantial knowledge I’ve come across as a SW developer has been about dependencies, and particularly about managing dependencies to minimize their impact on design and its flexibility.

A thinking tool

By thinking of what I do as “dependency management” I have a tool that will guide me in any situation, including managing projects, servers, build automation, xml- and property files, database design, architecture and object design.
It may sound somewhat abstract, but it always manifests itself very clearly when getting down to work. I just keep the following quote in mind:

“What need this part NOT know about?”
-Joakim Ohlrogge

Good dependencies are the minimal set of vital dependencies on work organized to minimize the set of vital dependencies.

Circular proof?!?

Not really, but usually an iterative process.

The range of dependency management

Dependency management ranges from organisations and projects, down to the smallest piece of bit-coding:

“Hey, we cannot finish this piece of work because we need that
piece of work from that other project and they’re not ready”

or

“It would be so much easier to parse this stream protocol if the length information was in the beginning of the stream…”

There are ways around everything, but having the right dependencies will make all work flow.

Dependency smells and refactoring

Dependency management can also be used when refactoring, by trying to identify “dependency smells”. Here are some examples that will show you what I mean and how I think about dependency management in the software design space. The examples are basically design principles versus dependency smells:

Don’t repeat yourself (DRY) vs Degraded Dependency (DD)
DRY:
“Remove duplication” – One of the core principles of all software development.
DD:
The code modules that should be depending on one single module is actually depending on two identical modules that are not the same, hence degrading both dependencies. This does not increase the code management burden to the double, but rather one order of magnitude, since the knowledge of the duplication must be passed on to and remembered by everyone involved.

Single responsibility principle (SRP) vs Piggyback Dependency (PD)
SRP:
“Let each module have one responsibility”. This principle is also interpreted as “Let each module have only one reason to change”.
PD:
If a module A has a dependency on a two-responsibility module B(r1,r2), but it is only interested in one of the responsibilities (say r1), there is an implicit piggyback dependency A->r2. This piggyback dependency will actually tie the application down, and make it more and more difficult to change over time.

Liskow Substitution Principle (LSP) vs Obscured Dependency (OD)
LSP:
States that a if a base module A (class/interface) is accepted for execution, any module B that extends A should be accepted as well. This principle protects the dependency B has on A.
OD:
Often when extension is used only to make A’s functionality available in B, or when the chain of inheritage gets long, LSP is in danger as complexity makes it harder to manage the original B->A dependency and its meaning. The functionality of the code can be validated by tests, but the design has been obscured.

Abstraction (Abs) vs Hardwired Dependency (HD)
Abs:
An abstraction tells that a module only has a description of its access points, not of how those access points will execute.
With this design pattern there is an explicit anti-dependency on the implementation.
HD:
When not using abstractions in code, executing modules are depending directly on other executing modules. This hardwiring has a tendency to spaghettizie over time, making it virtually impossible to change a piece of code without breaking another.

Dependency management and TDD

Well used, and especially with a low threshold for akward tests, TDD tends to lead to good design regarding dependencies. However, good knowledge of dependency management will lead to even better tests. I personally started to understand the value of dependency management when I started to write tests for my code, but I write much better tests (and code) now that I think in terms of dependency management.

Conclusion

By abstracting your thinking to using dependencies it is often much easier to reach good, concrete design decisions that will stand the test of time.

2 Comments (+add yours?)

  1. Joakim Ohlrogge
    Oct 25, 2007 @ 13:33:46

    I did not really understand the “proof” in the beginning of the blog.

    But I really like the dependency names and how you map them to principles. What do you know, I had a piggyback dependency staring me right in may face and I didn’t even know what to call it until now!

    Reply

  2. danielbrolund
    Oct 25, 2007 @ 14:01:23

    I’m happy you liked the names, and I would be happy for more names on different problem dependencies, and suggestions for better names for the ones above.

    The “proof” wasn’t really meant as a proof, more that you want to incrementally move your responsibilities and dependencies to get compact, highly cohesive units, and that your dependencies between these modules are clear, few and strong.

    I believe it is basically what most design principles and patterns strive for, with the difference that I want to focus on the dependencies rather than the (code) modules.

    The opposite would be to have related parts scattered around, and tying those parts together with a lot of weak dependencies. That doesn’t sound too good in my ears…😉

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: