3

I've just started studying coupling metrics and I'm having a hard time understanding instability. I find the term quite misleading and I don't understand how it can really help me develop better software.

If I understand correctly, "instability" itself is not a bad thing: a package that is totally instable has no afferent connections and can change often without impacting other packages. On the other hand, it is particularly impacted by changes in its efferent packages.

But the point is, "How do I determine how much a package depends on others?" The given formula (Ce / (Ce + Ca)) does not make sense to me. Let's say I have an instability value of 0.5: I can have 1 efferent and 1 afferent connection (1 / (1 + 1)) but also 100 efferent and 100 afferent connections (100 / (100 + 100)). What does it mean that the instability is 0.5 in both cases?

In the case of 100 efferent connections instead of 1, I have many more chances that my package will break because I depend on many more packages. And with 100 afferent connections instead of 1, I have many more chances to break some other package that depends on my package.

Why seems to be usefult to know if a package is totally instable or totally stable, seems to me that any value between 0 and 1 does not give me a real sense of how much that code is coupled. I should have some "absolute" number, not something relative.

Am I wrong? Is there anything I'm not considering?

Update 24/11/2024

What confuses me is the apparent conflict between the common meaning of "instability" (changing often) and its meaning as a metric (depending on others). It seems that this metric measures the "desired" instability/stability, not the actual one. For instance, a domain package in a hexagonal architecture should have instability 0. However, even if I achieve this, it doesn't mean that it is truly stable! Ideally, I can change external adapters without impacting the domain, but if I'm in the early phase of a project or if my domain is evolving due to new business requirements, it will change often, breaking the external layers.

This situation is not ideal, but I wouldn't reverse the relationship (with the adapter being stable and the domain unstable) because it's the domain that dictates the changes to others, even if these changes happen frequently.

It seems to me that a more appropriate term could be propagability: how much a change in the component can propagate to others. This term does not suggest that the package is stable (not changing); rather, it indicates that if I change the package, I am willing to propagate those changes to its dependents.

2
  • Do software engineers really use the words efferent and afferent? I had to look them up just now. Commented Nov 24 at 2:46
  • I do when i want to look more cleverer!! :)
    – Ewan
    Commented Nov 24 at 8:16

2 Answers 2

2

Well, no metric is perfect. A metric is a relatively simple way to get a handle on some property of a complicated thing - for instability, think of it as of a normalized/relative metric (a value between 0 and 1, or alternatively, a percentage), that allows you to think in a more general way about the coupling structure of the package. It's a sort of a high level way to express the idea of instability regardless of package size/complexity, so that you can consider it within a context of a small group of collaborating modules/packages/classes. If you want the "absolute" version of the metric, just multiply it with Ce + Ca, but there's little value in comparing random software modules across the project.

What you want for a group of collaborating classes (or other software modules) is to organize the dependencies so that the less stable things depend on the more stable things. This is a property of a robust design. You want your abstractions (interfaces, base classes, core data structures, conventions used, etc.) to be relatively stable compared to anything that relies on them (this is expressed as the idealized "abstractness + instability = 1", and this is sort of what you're striving for). Otherwise the project becomes ... not fun, and the instability metric is one way to get a some kind of estimate or indication of this, to get a sense of where things are off in the design. In order to achieve an improved design, you might end up doing things like breaking some classes apart, extracting code into a utility class, introducing a new concept/data structure/interface, applying dependency inversion, moving the "guts" of components around to improve cohesion, etc.

The goal here is not to follow some abstract notion of "good design" but to make the code easier to work with, and better reflect what's actually going on in the domain. But it's a pretty simple metric that doesn't take anything about the domain into account, so it's not something to follow blindly. Your domain knowledge is going to play a role when it comes to actually achieving this, because what is going to be stable vs what isn't ultimately depends on the problem domain.

1
  • You say basically: I expect that i have this dependency chain: A - B - C - D. So I should expect an Instability progression like 1 - 0.7 - 0.4 - 0. If, instead, I obtain 1 - 0.4 - 0.7 - 0, something "could be" wrong. Am I right? Commented Nov 24 at 9:27
1

The thing to realise is that any given system has a fixed number of packages.

So the instability is just a measure of where a given package is in the dependency chain.

Root packages, say your Models, with no dependencies will have zero instability.

UI packages at the top of the stack will have no afferent, dependant packages and have all the other packages as efferent dependencies. and will have an instability of 1

middle packages with both dependants and dependencies will have an instability value which reflects how close the the root or top layer they are

3
  • It make sense to me. Still, seems that the useful values are 0 or 1. With useful I mean "I want this package to have I=0". I cannot Imagine a scenario in which I want to set a target in the middle, like "ok, let's reach 0.57 for this package". I usually only need to know if it's a "bridge" package Commented Nov 24 at 8:57
  • To explain better my concern: I have two services structured around a layered architecture. I have in both services a persistence package with classes wrapping db calls. In service A I need to wrap postgres and mongodb: 2 efferent packages. In service B I need to wrap only postgres: 1 efferent package. So I have the same exact architecture but different instabilities that are just a natural consequences of my service needs. Does it make sense to say that one instability is better or worse than the other? Is the 0.6 value instead of 0.5 giving me any real sense of a better or worse choice? Commented Nov 24 at 9:22
  • Its not absolute measure of instability, so you cant use it to say "would it be better to swap out this package?" If your entire system consists of the two services (0.5, 0.6) the two persistence libs (0,0) and an application (1) then giving them instability numbers show you where they are in the overall system, and it make sense that B is more stable than A
    – Ewan
    Commented Nov 24 at 11:33

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.