1. 1

I thought the following statement should be entirely uncontroversial…. (but after a noisy disagreement I find it is…)

If class A depends on class B, then if at a later date a requirement arises for class C to use class B (as-is where-is), then if you have to alter a single bit of class A, your design was flawed.

What am I missing? I’m happy to generalize “class” in this statement to header file, module, package, service, …

Under what circumstances would this statement not be true?

  1.  

  2. 1

    I agree that it’s flawed… but I think it’s near impossible to get the design 100% correct on the first try in software anyway :)

    1. 1

      Oh I agree, but as a guide to what is good design, it’s a useful thought experiment.

      What would I have to change in my current dependencies if I add another client?

      • Maybe heap allocation instead of declaring statics in the service.
      • Maybe get the clients to do the per client resource allocation.
      • Do I have link time coupling? eg. A function that is declared in the service and linked to a function implemented in the (sole) client? Should I move to other techniques like run time registration? (I have curious trick to do link time allocation, but thats another (long story)).
      • When(and what) does the initialization of the service?
    2. 1

      t seems a lot of this would depend on how you define “depends”, “have to”, “design”, and “flawed”. Like you’re specifically looking for a case where you wouldn’t have to change A if either A or C didn’t use B, right? Here’s a couple that I think follow the spirit:

      1. B has some expensive computation. C is the straw that breaks the camel’s back- drops the performance of the system just enough to be annoying. You do some performance analysis and realize that A has an easily fixable bottleneck. You optimize A and performance raises to an acceptable level.
      2. B is a scheduler. Right now the only classes that use B are A and D. D is high priority, A is low priority. A should be higher than C. You make C low priority and bump A to med priority.
      1. 1

        Yup performance issues could be problematic.

        Threading is an interesting one.

        For example, it’s tempting to argue that this principle would mean you need to include synchronization primitives in the service “just in case” it is used by another thread.

        I’d say, no. I’d say rather that B wouldn’t be suited to be used “as-is where-is” by a second thread so the principle doesn’t quite apply, beyond suggesting a service that is reentrant is a better (more reusable) design. See the history of the *_r libc services for example.

        1. 1

          I’d say, no. I’d say rather that B wouldn’t be suited to be used “as-is where-is” by a second thread so the principle doesn’t quite apply, beyond suggesting a service that is reentrant is a better (more reusable) design.

          To clarify, I mean that B is the class that handles the scheduling. Priority is part of B’s API, a parameter that A, C, and D all pass in.

      2. 1

        I think its mostly correct, though I do think flawed designs are to an extent impossible to avoid forever.