Do Not Use Cute Tricks

Tags: development, technology

I speak unapologetically: I’ve seen bad work from insistence on using “cute tricks.”

Abuse an integer overflow.

Rely on floating point weirdness.

Use JAVA- oh wait no, well …use Kotlin?

Be stupid about the code you write. Cute tricks weaken your craft, and sow regret. By focusing your mind on impactful code you build more and better software. Hopefully, you’ll write code so stupid that future you will be able to read it and know exactly what it does (and why).

Know thine Environment

Engineers are forced to decisions to meet constraints: the fast reverse square in Quake made it work. Embedded software may need integer overflows. Storing less data per transaction saves dollars on the cloud bill.

It’s a junior developer move to add in a constraint where there wasn’t one.

It’s an average developer move to resort to a hack when constrained.

It’s a senior developer move to write stupid code unbound by constraints.

Consider the following practices - these lead to problems when indiscriminately applied, either in knock-on effects or by making the code less comprehensible. You’ll have to be the judge for comprehensibility.

Saving Cycles

There are many excuses for “saving cycles” or otherwise optimizing. Code should strive to be efficient and there’s no reason to “pessimize” code as Casey says.

Adding a layer of complexity to not do work in software that doesn’t need to be optimized is being cute. Avoiding an allocation by reusing memory space that you know to be free is cute.

Games, embedded, and other realtime-adjacent apps do need rigorous optimization and often appears like magic. The effects of poor code are apparent. Engineers understand when this is a concern. Engineers do not overfit their code.

Adding a check to skip code when it’s not a bottleneck doesn’t help you. In The Goal) the optimization process requires first discovering bottlenecks. Bottlenecks are created when an unnecessary step is injected, not only because it creates more work but also dependencies and downstream effects follow.

Here are some examples of places that don’t need every CPU cycle to be saved:

  • Building Static Websites
  • Your app with 10 customers
  • Most forms of desktop apps
  • Reporting software

How does this Hurt?

Your process evokes the following reactions:

  • “Why does this take so long”
  • “I have to (Reload the page|wait 5 minutes|push a different button) before it actually works
  • “Sometimes this process immediately triggers this, sometimes it doesn’t”

But the upside is!

  • Maybe your code will work faster than LLVM, the JVM, or Node would have made the rest of the program work.

Later on if you decide to remove this optimization, you need to hunt down all the other parts of your code that rely on that assumption.

How Can you Avoid it?

Others will bang the drum of “Premature optimization” and then pat themselves on the back because they’ve saved yet another developer from evil.

This is not helpful advice, it is a truism. Bad code is bad.

The unfortunate truth is knowing takes experience.

Write bad code.

Write more code, and try more things. Get the experience by sucking first. Discover bottlenecks rather than anticipating them; when you understand what bottlenecks exist you must still be open to change.

Integer / Floating Point tricks

Numbers are power and there’s no way to avoid integers or floating point. You should not reach for the Quake fast square root code. Reaching for your favorite algorithm to solve something the library provides is cute. Implementing a new algorithm to Radix sort is cute.

  • Your team isn’t smart enough to know your favorite algorithm.
  • Today’s (2024) compilers and hardware is better equipped for the math that you’re doing. It will probably be faster to be dumb in most cases
  • When you find out that hardware / software isn’t up-to-snuff, congrats! You the cutting edge of computing (sincerely - good luck and I hope you write well: you’re the literal future)
  • -0 is a thing (in floating point); it should not be used as a signal for state.
  • see this article for more examples.

Not because they do not work, but how will you fix them?

You should learn how and why the fast inverse square root was implemented. You will not need to put it in your program, not only because better algorithms have been invented for your use-case.

Here’s an interesting writeup about the fast inverse square since I keep bringing it up.

How Does this hurt

Your code is putting along, and the following happens:

  • A number is suddenly flipped to (negative | positive)
  • A check that validates that something that should(n’t) happen now (always | never), (fails|passes)
  • Your customers start using excel to check your program’s work, or resort to pen and paper and a TI-84.
  • Sometimes things work, and sometimes they don’t.

But the upside is!

  • You save 2 cycles calculating the average on a job that runs in 15 seconds nightly on-prem
  • You can point out that this method is O(n log(n)), versus O(n^2), on a data set of a few thousand entries
  • You don’t need to allocate another 4 bytes of RAM one time when your runtime is about 100 Kb
  • You don’t have to call GetSorted()

How can you avoid it?

Repeat this mantra

apex predator of grug is complexity complexity bad say again: complexity very bad you say now: complexity very, very bad

https://grugbrain.dev/

If you are unconvinced, perhaps this quote from (Jeff Atwood)[https://blog.codinghorror.com/coding-for-violent-psychopaths/] may help:

Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live

If that does not convince you, then I hope you remember why you decided to write the code. Better yet, you can avoid this by never rewriting any of your code (this is sarcasm).

Learn the basic algorithms and RTFM of your language stack of choice. Then, you will know when you have to break out the magic.

JavaScript Form Jank

JavaScript does a lot behind the scenes. When it debuted it was helpful to automatically convert when using == from HTML form input.

=== is the mark of JavaScript’s original sin.

What most other languages have learned from this mistake is there should only be one form of consistent comparison. Some older languages never had this problem, and I commend their designers.

How does this hurt?

You are working your forms, when suddenly

  • (One | some | none) of the values flip from a (number| string) to a (string | number)
  • You get back a (4|5)00 error one day, and your entire (form | front end | back end) breaks down
  • Your server sends back a (4|5)00 error without an error message

But the upside is!

  • You don’t have to call (ParseInt | toString)
  • You don’t have to use TypeScript
  • You don’t have to catch (3|4|5)00 errors
  • You don’t have to learn a form library

How do you avoid it?

eslint

If there’s a good reason to use == in JavaScript, please @ me

You Copied This Code, and You Don’t Know Why

I’m tired of seeing this. I’m tired of Linus being right.

How does this hurt?

  • During a PR you are berated
  • When the code doesn’t work, you do not know how to fix code you “wrote”
  • During an IP lawsuit your (company|firm|group) is fined and you lose (money|your code|your job)

How do you avoid it?

You cannot - let’s be honest, you will take code that you do not understand and write something that follows what it does while changing it to suit your needs.

To avoid getting rebutted on a PR, you have to get good at coding, or make the reviewer avoid giving you advice against your PR. Do the first, and learn to have thick skin regarding code; neither is easy, but they are necessary.

The third is easy; do not copy-paste code. If you must copy-paste code, understand the license or IP law it is available under. There is no third (rule #4)

Do not be cute

You can ignore this advice, but it rings true. If it’s strictly not true, you’re not writing code with anyone else, or you’re not writing code for anyone else, or you’re already good at writing code (these are ordered roughly from most likely to least).

Take heart that everyone who’s good at their craft was bad when they started out.