It's very error prone to describe a hierarchy of versioned software packages and configuration with shell scripts and yaml. Or use text files in git as a database. Or use the CI system as a bad substitute for a proper service (in order to do a simple thing, you must first create the world from scratch). And so on. Mainstream industry knows types, programming languages, relational databases, graphs and you name it, but those have not yet penetrated sufficiently into the infrastructure world. The understanding of the value of having types has been paid in sweat and blood when developing software and databases. Even a basic CRUD application with a basic SQL database will run rings around these Frankenstein monsters: in safety, speed, and extendability.
The whole problem on the infrastructure side is that the APIs are slow and you don't have exclusive access. Building the CRUD app would be a million times harder if SQL calls took 100x longer to execute and other people could randomly reach into the database and change the schema and data at will - can your basic CRUD app gracefully handle somebody shoving newlines at the end of usernames? Odds are that the first time, no, not until you put a trim() call. And then you cry in pain at needing to put trim() calls everywhere. And then you gnash your teeth at people reporting performance problems because of all the defensive checks you put in because all trust has been thrown out. And then you find out that trim() was deprecated and will now be replaced by strim() that handles Unicode a little differently, and you need to port your code before End of Life to stay compliant.
A basic CRUD application with a basic SQL database doesn't solve the problem, because you don't seem to appreciate that there already is a database - however your vendor stores configuration - and it's your job to deal with it. Adding another database on top of it would make the problem worse.
If you are infrastructure software minded, you might store the data in files that are stored in git. For users to read the data, they can perhaps browse the repo or clone it. For some more complex questions you might have a document which tells the user how to fire a CI pipeline that runs some code over the data and the user has to read the pipeline logs to get the information. The CI pipeline will probably run in a container which will produce a large log and take a long time to start.
If you are software software minded, you store the values in a database, make a service with a REST or some other API and create a browser UI. User can browse the data in a table view and perform searches and perhaps there's some more complex business logic executed on the backend to get answers to some more complex questions.
In this case, both systems can easily do the job. But the solutions are very different.
We have a multitude of configuration/markup languages all doing the exact same thing.
We have solved this problem in the 60s: S-Expressions. Should have just used that for everything. Configuration, code, websites, you name it. Infinitely extendable, easy to parse.
And if you really love sexps, then writing a bunch of arrays in JSON is also viable. If you asked me 10 years ago I might've complained about JSON, but now I think we messed up by having a bunch of other formats, tbh. I have my own TUI JSON editor that can render in tree view, miller tree view, flat view, and inferred table view, and it makes editing JSON very easy too.
Oh and duckdb can query against compressed json and jsonl at GB/s
That seems to be everyone's initial goal, but then it inevitably gets leaky.
I think the dominant split here that forces everything into a weird mismash is that nobody really wants to have to understand arbitrary programming language configs for third-party stuff, they want to read config and know what's going on. BUT for their own stuff, they find reasons to want more power and expressibility...
This is very much true. And until they do get leaky, you have to wrap them in all sorts of weird templates or other forms of abstraction.
This is one of the reasons I used to really like Chef's config language. It was a Ruby DSL, which meant that anything the DSL couldn't do natively, you could just use Ruby right there.
Of course, this is easily misused, but if you were careful it was as powerful as it was elegant.
They say they don't want it but every configurmation format eventually ends up becoming turing complete at some point.
Cue also has a lot of schema validation which is better than dynamic languages.
If it compiles, it’s almost certainly correct.
A reliability engineer's nightmare, and a common one, is stepping into a company whose deployment pipeline is built in-house, with dynamic bespoke software. What happens when Jeff leaves to build his own startup and absolutely no one knows how that Node.js script shells out to SSH to call docker on a remote server? I can tell you what happens: everything works fine for awhile and then suddenly doesn't for awhile.
On the other hand, you join a company with K8s and plain-jane YAML and can instantly grok the entire system and fix prod on your first day while the S-team sweats behind you, watching every key stroke. The seconds I have to read some javascript or bash or perl are precious seconds the brand is suffering.
In software engineering, flexibility and abstraction is a benefit: the product must pivot and evolve. In reliability engineering we want dead simple, tried and true. You want to be able to step outside your SF office and say "Someone help me with EKS, my DevOps guy died last night in a car crash!" and have 4 people with wild hair take their weird off-brand not-air-pods out of their head and say "uhhh sure okay".
Does all of this change with AI? Yes. Did it make sense a year ago for business continuity reasons? Yes. Was it ever beautiful where the rubber hit the road? No.
Why aren't tires as complex as wiring harnesses?
The problem is that that's not true in practice. It's a myth, and always has been for all but the most trivial setups. Infrastructure is now highly dynamic and, like old cities, becomes more complex, calcified, and non-uniform with age.
Infrastructure configuration is an excellent example of the blurriness of code-vs-configuration. I'm now several decades into my career, and I'd rather have pure code generate my configurations than some Frankenstein's monster of "mostly config but lots of code in there when it gets too complicated" UX. Config file formats always evolve into this mess eventually, and a lot of my fellow practitioners don't seem to recognize this problem, leaving the cycle to continue.
I’ve done some NGO-related work and in that context, they talk about “appropriate technology” - technology that’s suited to the local population, among other things. I’ve started to see tools like Helm and languages like Go as appropriate technology for many teams, but that doesn’t mean I’m going to switch to a pedal-powered water pump in my own house.
But no one does that because it is significantly uglier. So I guess we don't deserve sanity because we don't want our programs to be ugly?
And plenty more exist today. But helm got popular first, so due to the collective action problem it's going to take the industry forever to switch off it.
Yes, but it might throw errors because the client library you're using is too old and attempts to define fields that no longer exist in your newer infrastructure API. You do not find these errors at compile-time, but rather at runtime, and only after both serialization and API request execution finish and you get an error from the API, in the best case, or a silent failure misconfiguring your infrastructure, at worst.
The only time an infra engineer would trust the types is if the vendor themself supplied them, or there's a mainstream community effort to keep them up to date, or they're maintained in-house with procedures to try to keep them up-to-date with new releases. At the end of the day, the API takes a string, not some protobuf or CORBA or God knows what binary serialized monster dujour...
Well. Don’t use a client library that is too old then? Like you do in any other kind of software deployment, where you update your client libraries together with the upstream API you talk to?
Yeah, sure, I'll file that away with the NPM "tens of thousands of tiny dependencies is OK" thinking. Constant dependency upgrades is a nightmare. There's a reason why shell + Helm is popular - they're stable.
Good news! The Kubernetes project has a documented compatibility strategy (https://kubernetes.io/docs/concepts/overview/kubernetes-api/...) and publishes new client library versions for every release. There's endpoints in the API to interrogate the API's versions and supported fields/features for every resource. Additionally, most API types will accept old versions and automatically convert them to the newer versions, wherever this is possible.
> At the end of the day, the API takes a string, not some protobuf or CORBA or God knows what binary serialized monster dujour...
This is not necessarily correct. Kubernetes API supports JSON, YAML, protobuf or CBOR over the wire, and all become in-memory structs on the server.