Few thoughts on (de)composition

171 views
Skip to first unread message

Ivan Yordanov

unread,
Dec 15, 2025, 12:48:34 PM12/15/25
to software-design-book
Hello Mr. Ousterhout,

I stumbled upon your book few months ago from the pragmatic programmer podcast. I also work on few ideas related to software design for few years now. 
Although I took a different route. My goal was to define in math terms what a good piece of code means and to eliminate (or at least minimize) subjective opinions and religious arguing about software. After describing it in math terms I tried to find a formula that scores a particular class/module/system/etc. and then started to write some practical guides how to maximize the score of this formula. Then I stumbled upon your book and we have really high overlapping in terms of practical guides for software design. There are few differences as well. I just described one of them in a blog post.
I would like to hear your thoughts about it and I would like to put few links to your profile and book in the post as well. I'm going to put links to wikipedia article and page of the book in stanford.edu, but If you prefer other links let me know.
The article is not published yet, I would like to hear your thoughts before publishing it.

All the best,
Ivan Yordanov

John Ousterhout

unread,
Dec 26, 2025, 12:38:07 PM12/26/25
to Ivan Yordanov, software-design-book
Hi Ivan,

Sorry for my slow response to your posting. I haven't had a chance to read your draft article yet, but I'm somewhat skeptical about the possibility of a mathematical measure of complexity or good design. It would be a great thing if that were possible, but I think it will be hard to capture in a mathematical formula all of the aspects of good design and how to trade them off against each other.

One question for you to consider in your work is how you will know if you have succeeded: not only do you need to develop the right formula, but you'll need to demonstrate that it really does capture the essential elements of good design.

Good luck!

-John-


--
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.

Ivan Yordanov

unread,
Dec 26, 2025, 2:48:28 PM12/26/25
to software-design-book
Hi John,

Thank you for your response.
About the formula I have some evidence it correlates with good design (if not direct measurement, but even correlation is better than nothing :-) ). I measured few popular and supported open source projects (like lucene, numpy, android, django, spring, etc.) and the scores correlate with my personal understanding (which is certainly biased, but not completely wrong :-) I hope ) . Attempting to come up with strategies to maximize formula efficiency suggested really similar ideas like the one described in your book, which I interpret as positive sign. Every time when I ignore this formula in my daily work I end up rewriting the module, because initial design can not handle all the requirements that come up with time. All this gives me evidence that's the right direction.
Anyway the formula itself is not described in the shared post, just one of the derived ideas - about (de)composition.
I will share the formula in near future.

Walmyr Lima e Silva Filho

unread,
Dec 27, 2025, 12:41:34 PM12/27/25
to software-design-book
In Tidy First?, Kent Beck presents several interesting formulas for the cost of software, which cannot be calculated; nevertheless, they're worth considering.

He says that:

"The cost of software is approximately equal to the cost of changing it.

cost(software) ~= cost(change)

And the cost of change is approximately equal to the cost of the largest change.

cost(change) ~= cost(big change)

Then, he suggests that when changing the software, we should ask ourselves: what makes these changes so expensive?
It's that changing this element requires changing those two elements, each of which requires changing other elements, and so on.
And what propagates the changes? Coupling. Therefore, the cost of software is approximately equal to the coupling.

cost(big change) ~= coupling

Finally, he presents the complete Constantine Equivalence formula.

cost(software) ~= cost(change) ~= cost(big change) ~= coupling

Or to highlight the importance of software design:

cost(software) ~= coupling

He ends chapter 30, suggesting that to reduce the cost of software, we need to reduce coupling."

By the way, in the book's annotated reading list and references, he said that John Ousterhout's book (A Philosophy of Software Design) got him off his butt writing.

HQ K

unread,
Dec 27, 2025, 2:42:42 PM12/27/25
to Walmyr Lima e Silva Filho, software-design-book
Interestingly, coupling was the main target of many design theories. But do we ever think why it always happens in the first place? our brain likes coupling because of number of items it can hold at a time. In DCI, Trygve embraces good coupling in Context. Deep interface also embraces good coupling. In my design, I always start with high coupling but the good architecture allows me to transition from high to low coupling as needed.

Thanks and Regards,
KIM, Hai Quang (Kenvin)

Ivan Yordanov

unread,
Dec 28, 2025, 6:26:13 PM12/28/25
to software-design-book

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

Reply all
Reply to author
Forward
0 new messages