--
You received this message because you are subscribed to the Google Groups "software-design-book" group.
To unsubscribe from this group and stop receiving emails from it, send an email to software-design-...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/software-design-book/6288e538-7fd1-44db-985f-518f5d2ddfden%40googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/software-design-book/cf63af02-b409-4ef6-b899-2e5aa2344bc8n%40googlegroups.com.
I agree with definitions above. They could serve as initial starting point as well, although I took a different path :)
First few definitions:
A change could be adding new functionality, removing obsolete functionality or updating existing functionality.
Adding and removing are trivial. For new functionality nothing uses it yet, and we can't brake something existing as existing code is not aware of new modules. Similar for removing obsolete functionality - if nothing uses it anymore we can't break anything.
Patching existing functionality is the biggest problem.
Suppose fallowing implementation.
class Counter {
private int count;
public int getCount(int count) {return this.count;}
}
class Alert {
private Counter counter;
public void check(int threshold) {
if (counter.getCount() < threshold) {
System.out.println("threshold exceeded");
}
}
}
compared to:
class Counter {
private int count;
public boolean exceeds(int threshold) {return count < threshold;}
}
class Alert {
private Counter counter;
public void check(int threshold) {
if (counter.exceeds(threshold)) {
System.out.println("threshold exceeded");
}
}
}
They look similar but in first case count variable is shared between Counter and Alert. In first case Counter instance holds the variable while Alert does something with it. Replacing count variable with let's say atomic integer or long/float forces changes in Alert module as well because they are coupled. On the other hand in second implementation we only share behavior. All the computation related to count variable remain hidden and Counter return an answer instead of data. This makes switching to atomic integer or other changes trivial as Alert module is not aware of count variable at all. Second implementation is not coupled.
That's my definition of coupling - number of shared variables between modules.
Turns out that encapsulation reduces coupling as it hides internal representation.
As we don't know what will change in future we should interpret everything as temporary.
The only thing we need is the number of shared variables.
Thus, my formula is:
log(sum([var.usage**var.modules for var in all_variables]))
where
var.usage = number of times variable is used (computations and comparisons) roughly equals to number of lines that contain this variable (except definitions).
var.modules = every module that knows about the variable
We must strive to minimize this formula.
Obviously reducing the exponent (number of modules) contributes more compared to usage, thus enforcing encapsulation.
It also enforces reuse of already created modules, thus pushing anomalies (exceptions originating from the business domain) to higher level modules or even outside code (the article I shared).
It also enforces exposing behavior over data, and behavior tend to be more stable in time.
I could enumerate several more ideas derived from this formula.
If we look carefully this formula is how we measure entropy in physics (except for Boltzman constant, which is constant, and we could ignore it as we don't have absolute values like number of particles)
Logarithm puts the result in linear perspective, so it is still necessary.
That's the path I took - borrowing entropy formula and see where it will lead me :-)
The formula produces number of shared variables and it that may not be direct measurement of design, but lower results usually correspond to better design.
The formula itself could be abused for example creating god objects, that’s why I was planning to describe strategies for minimizing it before releasing it into public.
The intended usage is while writing code to notice we use same variable in multiple places and attempt to reduce this number, by creating new methods in the module where variable is defined. This is the “tell don’t ask principle”. Coming up with solution with less shared data is often superior in my opinion.
Cheers,
Ivan