On Sacrificing Goats

musings by Bast on Saturday July 29th, 2023

I have noticed that Developers, especially in this newer, modern era filled with powerful programming languages, expressive dependency trees, and voluminous databases full of information, have had a tendency to return to their roots.

They believe in magic, mystical beings, and the power of sacrificing goats to affect the weather.

There are many splinter religions burgeoning from this phenomenon, festering beneath the surface with their honeyed promises of impossible solutions, of magical success, of "web scale."

The reality, of course, is that computing is cold, hard, and unforgiving. No matter how many goats you sacrifice on the altar of Technology the same void of Information Theory gazes back at you, it's madness swirling in half-lidded, unseeing eyes.

The endless churn of social media networks is just one aspect of this many-faceted, cthulian monstrosity that has been birthed from the depths of the hells where the human spirit of adventure delved too deep. Amazon Web Services is yet another. Java is a third.

It is an endless chase to get more for less, to have your cake and eat it too. To see the inflexible, businesslike demeanour of the Java Language and yet also pretending, one eye closed, not to see it's glaring faults. The endless churn of complex objects, of Just One More Layer of abstraction to hide the inflexibility built into the specification itself.

The most blatant of such is the Builder pattern. The Builder pattern is an abomination borne of red tape, a refusal to cross arbitrary syntactical and structural lines enforced by the compiler. Statements such as Thou Shalt Have One Constructor And One Only, or Optional Arguments Are Forbidden By Syntax inevitably give rise to it, as can be seen slathered over rusty codebases or packed into the depths of Jar files.

But one who has gazed into their abyss knows the truth, for the Builder is an accessory of the Class, a constructor that is not permitted to rest upon the creation itself but has been bound by the structure of it's universe to independent suffering. To awkward invocation and complex, confusing usage. An abuse of return values and typing to turn chained method invocations into a simple method call that could, in more sane worlds, gone with just a whisper of request.

person = Person(name="Bob", age=50)
Person person = new Person.Builder().Name("Bob").age(50);
person: Person = Person::builder().name("Bob").age(50);

But the builder pattern is not the only echo of lovecraftian-born tyranny of the machine, no. Worse, is the prevalence of the getter and the setter, heirs to Frankenstein, a cobbled-together (and in C#, heavily autogenerated) disaster borne as endless cancer from the inflexibility of method access and the withering deficiency of "modern" static typing, it's mechanisms as slow and stunted as those of it's elders.

For, after all, how are you to enforce an age must be greater than zero in a language that doesn't have typing support? Why, by intercepting every set call, of course. There is no other way, except trusting others, and in the depths of this abyss there is no trust to be found.

public Integer getAge() {
    return this.age;
}

public void setAge(Integer age) {
    if (age <= 0) {
        throw new Exception("Age must be greater than zero");
    }
    this.age = age;
}

But the insidiousness of this failing spreads almost immediately. After all, once you've hardcoded accesses to Person.age all throughout your codebase you cannot simply remove them. That would cost time, effort, and money, enforced by the cold, still, lifeless bits sitting there on your machine, refusing to read your mind and solve the problem for you. Thus, you must deduce (you have no choice, after all! What are you going to do, write your own java?) that All Properties Must Be Encapsulated. And then year or two goes by, and you have a list of reasons for Why Things Must Be This Way. After all, imagine having to trust that another system doesn't feed you invalid data. The horror!

And, of course, the compiler will never help you. After all, to it, -27 is a perfectly normal age. It is an Integer, after all, which permits all signed 32 bit values. Even rust, in it's vaunted Hunt For Correctness, does not let you limit the acceptable input values for a variable. And lo, within those hallowed halls doth the cancer too spread, the getters and setters digging their tendrils into your codebases from within.

In python, at least, the cancer is contained. The type system is weaker and chained to it's boulder more effectively, but it is no less poor for it. An int() is an int() is an int(), and thus you must still write the accessor.. but at least the syntax, the universe within you move your wooden blocks and shave your yaks permits the one blessing.. you do not have to pre-emptively spread the toxicity to every access ever. Through the power of Descriptors the ancient arts of Attributes-Having-Classes is made oh so slightly manifest, and like a gift from the divine it is the savior of many, carefully packaged in bite-size increments with the @property decorator.

class Person:
    _age: int

    @property
    def age(self):
        return self._age

    @property.setter
    def age(self, value: int):
        assert value > 0
        self._age = value

And you never have to call a getter again.

But!

The danger of the memetic virus of authoritarian constriction is not constrained to just your codebase.

After all, why should you have to write all your code yourself? Why, your dependencies, of course, are a chain as binding as any other! A cold shackle around your own writings that ensures they may never escape them or their shackles in turn.

Why shouldn't you import left-pad? You cannot rely on any sanity, after all, in javascript's Holy Trinity of Truths. Someone else can deal with it. Or not. And lo, they may choose not to deal with the evens or the odds, and another, then, shall deal with the evens in turn for them to be lazy with the odds, and the odds as well. And then node_packages was large, and the complexity heavy, and it's weight a stain on your soul. And in it's dark shadow of risk we thrust the great Vulnerability Scanner, trusting to Law to decide what is Evil. But the Law see's not Good or Evil, only shades of Chaos and deems them poor. And thus the shackles grow ever tighter.

To relieve the shackles you turn to the tools. Those eponymous aids, your buffer between you and the cold hard truth of your actions. And so you ask them "compress for me!" "Store for me!" and you steadfastly ignore that you have Written a Filesystem once more, ignore the tried and true history of the Zip for the latest fancy because the more distracting, the less you can feel the chill crawling up your spine. Complexity Death's fingers getting ever tighter, it's claws ever sharper, until your skin parts and you scream and your project dies a fiery death to the endless chattering of the orange website going "Just spend the few days to learn the tooling and set up the compiler to your liking" in their endless obliviousness to their gibbering insanity and the blood running from their eyes as tears.

As if mucking about through the primordial filth of JSON config files was a blessing from on high.

A language, standardized less than a decade ago, that does not support such luxuries as trailing commas. Or dates. Or numbers beyond 9_007_199_254_740_992. 2^53. A dreg from the endless abyssal ocean of insanity where storing whole numbers as floating point fractions is the least of your concerns.

A language used so widely that there is not only a proliferation of cursed attachments to interface with it linewise, but also to stream it, supporting conglomerations of many-eyed terror into the terabytes of length.

Because to admit that you are using your hammer on screws is to admit defeat. To acknowledge the insanity of the goats blood spattered on your hands and the blackened altar-stone beneath your feet. To suggest that perhaps you were not a good person. That you could have chosen another path. To open your ears to the screaming in your soul that says that there are no magical solutions to distributed data. That you cannot have schema-less data and efficient querying. That all Data is Data and it goes in the same place. To see the disorganization, the eldritch chaos that has taken hold and torn down your walls and exposed you to the warm gaze of the sun, but also the cruel chill of winter storms.

To know you should build of stone, and not wood.

And to know that trust is given, not earned, and certainly not deserved.

That by eschewing comments you have not moved forwards a little bit, but, despite all screaming, all the crying, all the prayers and admonishments and soul-searching and standups backwards.

After all, the only way to stifle eight orders of magnitude of computational power improvements, from the 1/8th of a flop of the 80486, to the 32 in a Zen3 chip, is by invoking The Ones Behind the Stars. Nothing less could bring such insanity to bear.