Udi Dahan on Physical Design

| 2 Comments

Udi Dahan writes about managing dependencies in code at the 'package' level in "So many Dlls, so little time".

"Sloppiness with dependencies. If two classes are independent of each other, and do not provide different implementations of the same interface, think twice about putting them in the same project/dll. Minimizing dependencies is the bread and butter of loose coupling. Break dependence on implementations by introducing interfaces in a separate project/dll."

His suggestion of refactoring at the physical design level and moving groups of classes from one package (dll or static library) to another to ensure that your project only depends on things that it actually uses is sound advice. Unfortunately it's one of those really important things that many developers simply do not ever even consider.

If you're working in C++ and you haven't read Large-Scale C++ Software Design (APC) by John Lakos then you really should. It covers all of this kind of stuff. Failure to understand the things that you need to do to build large systems in C++ is one of the things that leads people to ask questions like: "Is C++ still needed?". Yes you can build horrible messes with C++ but no, it doesn't have to be that way.

As Udi says, "design is about managing dependencies between classes and dlls". Personally I'd replace 'dlls' with 'packages' but that's a minor nit-pick. I often prefer my packages to be static libraries and what Udi says is equally relevant to all other forms of code packaging. You have to actively manage your dependencies all the time, no matter what language you're working in. If you don't do it in C++ you can end up in a hell of slow compiles and horribly entwined code that all needs to be rebuilt if you ever change one class. If you do it right you rebuild just what needs to be built and you depend on just what you need, and no more. As always, easier to use languages remove much of the easy to remove pain of uncontrolled dependencies. Compile times may be better which often stops developers realising that their dependencies need managing at all...

2 Comments

Continuous Integration, or at least frequent builds, plays a role here too. If you're not rebuilding every file at every build, you have to at least make sure that every DLL affected by a change in a header file is rebuilt when the header file changes. How is that best managed in C++ ?

The usual rules of forward declaring everything you can and only including headers for things you must work pretty well at both class and package level; you just apply the same rules to the headers that the package exposes that you do normally to classes.

I agree that frequent builds expose these issues pretty quickly. If your build is starts to take too long then you notice it quicker if you're building regularly. Precompiled headers, at least in VC, are a bit of a pain here unless used "properly" as they can hide all kinds of coupling nastiness.

I find that you need to stay focussed on this all the time, right from the start of the project as it's very difficult to restructure later once everything has been allowed to go wrong.

Since I tend to work mainly with static libraries and I include all of the lib projects into the exe project I find that the IDE manages the actual dependencies quite nicely and it allows me to work across all the libraries as needed.

Leave a comment