Software Calcification

Calcification: the gradual, almost imperceptible transformation of a soft, flexible body into a hard, brittle body. Software: The original computers were 100% hardware. Inputs were given via wheels, knobs, and cards. Outputs were generated by gears, wheels, transistors, and tubes. The computer had one, maybe two functions it could run. Creation and change were extremely expensive. But, when general purpose computers were invented, you could create and edit functions by merely arranging bits. Thus, "software" was easy and pliable by comparison. Software can calcify though. The bonds between parts of the software multiply and strengthen until movement ceases. Eventually, the software faces a stiff wind from an unexpected direction or heavy blow at the wrong place and crumbles, never to recover. Sometimes a little calcification is even a good thing. We all have bones, don't we? You don't want your femur fusing to your hip though. Objects in OO can be thought of as planned calcification in a way. We accept that some functions are tied together somehow and that it makes sense that they would move as one. How do you know your software is calcifying, even as a non-technical person? You start hearing more and more things like "We could do X, but then we need to change Y". Bugs are taking longer and longer to fix. Features are taking longer and longer to add. Engineers who used to be rising stars are mysteriously burning out and quitting despite no indication of your org being toxic. Coupling The main cause of calcification is a failure to keep coupling to a minimum. Engineering as a profession I think does not understand the threat of excess coupling. Plenty has been written about coupling, but because of the time that passes between when software is first written and when the pain starts getting felt, the coupling gets normalized within your engineering culture. "That function has always gone 5 methods deep into this object and it has never been a problem before." the engineers will say. "We have always used dozens of function mocks per test." they will say. Excessive coupling is normalized in your organization. Excessive coupling can be caused by poor: Domain Modeling Another cause of calcification is bad or out of date domain modeling. Changes are hard because the system does not make sense. This one also tends to be difficult to discover and then the pain gets normalized. "All my design documents have 30 different models, most of which have names only comprehensible to me, and the arrows are going every which way. But, this has worked so far." your architects will say. No one will dare to make a change to something complicated and only barely works for your business. Testing Willingness to change, adapt, and move are all facilitated by a feeling of security and nothing makes an engineer feel more secure than a good suite of tests. Signs that your test suite is not up to par. "We need to run a full manual UAT program before every deployment" your engineers will say. "We re-run the test suite several times in case of flaking tests" you will hear. Iteration duration Most software engineering requires some number of loops. There is the micro-loops of Red-Green-Refactor. There is the bigger loop of commit-push-merge. There is the bigger loop still of build-and-release. Slow-downs in these make changes harder. They stiffen and calcify your thinking. When your build time increases, your engineers become less willing to agree to comments on PRs because it will trigger more builds and more waiting. Reviewers will rubber stamp the PR rather than risk getting stuck waiting 30 minutes for their changes to be completed and built. More coupling, bad domain modeling, and bad testing get introduced. The downward spiral of calcification intensifies. Prevention There is no silver bullet here. There are dozens of tools and skills. To name a few: Test Driven Design TDD is great, but a common pitfall is letting the code dictate the tests, rather than letting tests dictate the code. This is closely related to: Minimal, well defined interfaces Know your interfaces. Know the levels of your application. Are you running a web app? Your primary interface is http requests. Do you have a job queue? That is another interface. Do you have both a web app and a job queue using the same code? Then you have business logic interfaces as well. Lastly, object and function interfaces. Utilize coherence to cut interface sizes down. If you are passing a ton of references or are reaching deep into a reference, there is probably poor coherence somewhere. Stop using so many mocks please Your tests are also part of the coupling. Every mock you make is increasing the coupling and causing calcification. For example: instead of writing a test that takes an http request, mocks out 50 things, and returns a result, write a test that takes an http request, mocks

Apr 16, 2025 - 18:54
 0
Software Calcification

Calcification: the gradual, almost imperceptible transformation of a soft, flexible body into a hard, brittle body.

Software: The original computers were 100% hardware. Inputs were given via wheels, knobs, and cards. Outputs were generated by gears, wheels, transistors, and tubes. The computer had one, maybe two functions it could run. Creation and change were extremely expensive. But, when general purpose computers were invented, you could create and edit functions by merely arranging bits. Thus, "software" was easy and pliable by comparison.

Software can calcify though. The bonds between parts of the software multiply and strengthen until movement ceases. Eventually, the software faces a stiff wind from an unexpected direction or heavy blow at the wrong place and crumbles, never to recover.

Sometimes a little calcification is even a good thing. We all have bones, don't we? You don't want your femur fusing to your hip though. Objects in OO can be thought of as planned calcification in a way. We accept that some functions are tied together somehow and that it makes sense that they would move as one.

How do you know your software is calcifying, even as a non-technical person? You start hearing more and more things like "We could do X, but then we need to change Y". Bugs are taking longer and longer to fix. Features are taking longer and longer to add. Engineers who used to be rising stars are mysteriously burning out and quitting despite no indication of your org being toxic.

Coupling

The main cause of calcification is a failure to keep coupling to a minimum. Engineering as a profession I think does not understand the threat of excess coupling. Plenty has been written about coupling, but because of the time that passes between when software is first written and when the pain starts getting felt, the coupling gets normalized within your engineering culture. "That function has always gone 5 methods deep into this object and it has never been a problem before." the engineers will say. "We have always used dozens of function mocks per test." they will say. Excessive coupling is normalized in your organization.

Excessive coupling can be caused by poor:

Domain Modeling

Another cause of calcification is bad or out of date domain modeling. Changes are hard because the system does not make sense. This one also tends to be difficult to discover and then the pain gets normalized. "All my design documents have 30 different models, most of which have names only comprehensible to me, and the arrows are going every which way. But, this has worked so far." your architects will say. No one will dare to make a change to something complicated and only barely works for your business.

Testing

Willingness to change, adapt, and move are all facilitated by a feeling of security and nothing makes an engineer feel more secure than a good suite of tests. Signs that your test suite is not up to par. "We need to run a full manual UAT program before every deployment" your engineers will say. "We re-run the test suite several times in case of flaking tests" you will hear.

Iteration duration

Most software engineering requires some number of loops. There is the micro-loops of Red-Green-Refactor. There is the bigger loop of commit-push-merge. There is the bigger loop still of build-and-release. Slow-downs in these make changes harder. They stiffen and calcify your thinking. When your build time increases, your engineers become less willing to agree to comments on PRs because it will trigger more builds and more waiting. Reviewers will rubber stamp the PR rather than risk getting stuck waiting 30 minutes for their changes to be completed and built. More coupling, bad domain modeling, and bad testing get introduced. The downward spiral of calcification intensifies.

Prevention

There is no silver bullet here. There are dozens of tools and skills. To name a few:

Test Driven Design

TDD is great, but a common pitfall is letting the code dictate the tests, rather than letting tests dictate the code. This is closely related to:

Minimal, well defined interfaces

Know your interfaces. Know the levels of your application. Are you running a web app? Your primary interface is http requests. Do you have a job queue? That is another interface. Do you have both a web app and a job queue using the same code? Then you have business logic interfaces as well. Lastly, object and function interfaces.

Utilize coherence to cut interface sizes down. If you are passing a ton of references or are reaching deep into a reference, there is probably poor coherence somewhere.

Stop using so many mocks please

Your tests are also part of the coupling. Every mock you make is increasing the coupling and causing calcification. For example: instead of writing a test that takes an http request, mocks out 50 things, and returns a result, write a test that takes an http request, mocks out any web requests to external services using something like WebMock, and returns a result. I promise you you will thank me when you realize the client library you were using is no longer maintained and you can swap it out without changing a line of tests.

Small refactorings

Little problems left to fester will often become very big problems given enough time. Normalize your engineers spending 5-15 minutes per day fixing little issues.