I loathe dynamic programming languages. This week, in a system that spans 3 microservices, I needed to add two new
fields to an object. I’ve spent at least two days tracking down references to said object and making notes on all the
functions that may be affected by this change. I wish I had a compiler to validate type information at function
boundaries. But I don’t, because the microservices are written in weakly-typed (aka dynamic) languages.
Because the services are written in dynamic languages, the only way to know what object is passed into a function is by
looking at all the parent functions in the callstack as well sibling functions that may have transformed relevant
data. The function that motivate this blog post has required me to look at six different functions so far. I have two
more functions to trace before I can create the desired patch.
There is a cultural problem at play that is reminiscent of Tragedy of the Commons. For one to make a change quickly
and confidently, the codebase needs high test coverage (shared resource). However, individuals are incentivized to avoid
writing tests: People are rewarded for completing tasks quickly. What exacerbates the problem is that when a change
results in a bug, it is frequently the person who made the last commit that gets the blame, rather than the past
decisions that led to poor test coverage in the first place. It is not a fully formed Tragedy of the Commons problem as
individuals are not rewarded for harming the shared resource, but is sufficiently similar.
Of course, one can use a combination of tooling and carrots-and-sticks to “ensure” the codebase has high enough code
coverage – to avoid requiring programmers to carefully scrutinize the entire call graph. At this point however, the
amount of work that goes into this is likely the equivalent of using a strongly typed programming language.