home

Why is Simple Code So Often Bad?

Jan 30, 2024

I recently wrote a Prometheus client library for Zig. I had to write a custom hash map context (what Zig calls the eql and hash functions) which led to my last couple blog posts exploring Zig's hash maps in more details. The last topic covered was the getOrPut method which returns a pointer to the key and value arrays of where the entry is or should be. getOrPut is great because you can do an upsert operation with a single lookup (but, like all things in GC-free language, don't hold on to that reference else you risk a dangling pointer).

While writing the library, I used the Go client as a reference. I also looked through a Node.js implementation. There I saw:

updateExemplar(exemplarLabels, value, hash) {
  if (!isObject(this.hashMap[hash].exemplar)) {
    this.hashMap[hash].exemplar = new Exemplar();
  }
  this.hashMap[hash].exemplar.validateExemplarLabelSet(exemplarLabels);
  this.hashMap[hash].exemplar.labelSet = exemplarLabels;
  this.hashMap[hash].exemplar.value = value ? value : 1;
  this.hashMap[hash].exemplar.timestamp = nowTimestamp();
}

To me, this code is problematic for two reasons. While I know nothing about V8 optimization, I assume 5 or 6 hash lookups is going to be slower than 1 or 2. The other issue is that, as it's written, you need to parse each line to understand that a single object is being mutated. A local would solve both issues:

updateExemplar(exemplarLabels, value, hash) {
  let exemplar = this.hashMap[hash].exemplar;

  if (!isObject(exemplar)) {
    exemplar = new Exemplar();
    this.hashMap[hash].exemplar = exemplar;
  }

  exemplar.validateExemplarLabelSet(exemplarLabels);
  exemplar.labelSet = exemplarLabels;
  exemplar.value = value ? value : 1;
  exemplar.timestamp = nowTimestamp();
}

The original code isn't awful. But it is a simple function and it seems to almost go out of its way to be inefficient to run, read and maintain. It honestly makes me wonder how it happens. I wonder how often I've done something like it, or worse, without realizing. I just finished writing a multipart/form-data parser, and it's awful. I don't mean to pick on this one example, even though I know I am. It just happens to be the most recent example I've seen. The real issue is how commonplace this is.

I'm skeptical about our ability to improve, and wonder how close we are to hitting a limit on the complexity of software that can be written and maintained?