Please just give me a programming language man
a.k.a. And why do I have to learn 5 new ways to write a for loop every year?
It’s the age old adage. People give us declarative languages, so we can configure their tools—declaratively, of course. Eventually those tools get popular and people have new usecases for it, and suddenly “declarative” isn’t enough anymore, which is when the languages will be retrofitted with if statements and for loops to get closer to turing-completeness.
I call this brand of languages “configuramming” languages because as soon as you add logic to configuration, you’re neither writing config, nor programs, but something in between.
What configuramming languages all have in common is that documentation is lacking and the languages are underspecified. Because obviously for example javascript has literal tens of millions of devs and a standards body that does nothing but specify the language, whereas the configuramming language designed in-house at atlassian is an expression of technical debt that accrued over time with no overarching design behind it.
How else could you explain these?
gitlab pipelines
We have no loops in gitlab pipelines but shoutout to crappy
conditionals. if
statements are called OnlyVariables here,
perhaps to encourage users to pay for premium.
nightly_test:
stage: test
script:
- npm run build
only:
variables:
- $NIGHTLY_TEST == "True"
If that sounds too silly we have the new and improved rules
configuramming construct which we can use to make if statements
even more convoluted.
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- when: always
I’m sure this made sense to someone when they designed it.
Terraform HCL
If you were to design terraform from scratch, would this be the loop syntax you come up with?
resource "azurerm_resource_group" "rg" {
for_each = tomap({
a_group = "eastus"
another_group = "westus2"
})
name = each.key
location = each.value
}
Make
I have love for a good old Makefile and most people are keeping it sane, but you can do extremely terrible things with it like generating steps dynamically.
STEPS := $(shell echo step1 step2 step3)
$(foreach step,$(STEPS), \
$(eval $(step): ; @echo "Running $(step)...") \
)
From the docs:
The
eval
function is very special. […] It’s important to realize that theeval
argument is expanded twice; first by theeval
function, then the results of that expansion are expanded again when they are parsed as makefile syntax. This means you may need to provide extra levels of escaping for “$” characters when usingeval
.
We love to hear it.
CloudFormation (AWS)
Parameters:
UseNAT:
Type: String
Default: false
Conditions:
ShouldCreateNAT: !Equals [!Ref UseNAT, true]
We love stringly typed variables aswell. CloudFormation has this absolutely insane feature where you can deploy a lambda and the YAML will call it to transform itself, which deserves special mention. You can deploy your for loop to AWS before running it; it’s configuramming-as-a-service!!
AWSTemplateFormatVersion: "2010-09-09"
Transform: MyForLoop
Resources:
RepeatExample:
Type: Repeat::Resource
Properties:
Count: 3
Template:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "repeat-bucket-${Index}"
Helm
Advice to all junior devs: If a manager or senior suggests using YAML for anything really please shit on their desk and show them this page.
toppings: |-
{{- range $.Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
Helm is configuramming at it’s peak: Full-blown turing completeness but terrible code editor support, terrible tooling to go along with it and the resulting code is unreadable as soon as you’ve written it. You spend 3/4ths of your time fixing indentation and quoting too because at the end of the day you’re using YAML to generate YAML.
Okay so that was enough ranting. What should we do instead?
Just use a programming language
Terraform has a CDK now for major programming languages, including typescript (cdktf). Pulumi looks like a cool alternative too though I have no experience with it.
Or handroll your own one-off scripts! Nobody is stopping you from generating yaml in vanilla typescript. It can be worth it if your config is complex enough—at least you have code editor support.
Use Nix?
Nix tries to solve the very hard problem of generating configuration in arbitrary formats, for every piece software you have installed, systemwide, from your vscode settings down to driver or file system configuration. It is a fully-blown functional programming language with a module system and while I think the compiler does need some work (error messages are cryptic), and documentation is not well structured, and the learning curve can be a bit steep, the language does an excellent job at tackling the challenge it has set out to do.
And if Nix is good at defining configuration.. we should be using it!
People in the Nix community are using nix to replace
dockerfiles (allowing for byte-for-byte reproducible builds), and
there is also the kubenix
project that lets you manage
kubernetes clusters in nix. Not having to touch Helm/Kustomize
configuramming and managing your multi-cluster setup in a nix
flake sounds like such a lovely time, I really wonder why not
more people are doing it.
Perhaps in a few years time.