diary @ telent

Simple minds#

Thu 07 Dec 2023 09:52:36 PM UTC

Topics:

I responded to a Linkedin post about refactoring code the other day, referencing the J B Rainsberger "Simple Code Dynamo"", and I don't think I said all I wanted to say: specifically about why I like it.

A common refrain I hear when I talk with other developers about refactoring is that it has low or no value because it's subjective. You like the inlined code, I like the extracted method. He likes the loop with a repeated assignment, they like the map/reduce. Tomato/tomato. Who's to say which is better objectively? If you consult a catalog of refactoring techniques you'll see that approximately half of them are inverses of the other half, so technically you could be practicing "refactoring" all day and end up with the code in exactly the same place as where you started. And that's not delivering shareholder value/helping bring about the Starfleet future (delete as applicable).

What does the Simple Code Dynamo bring to this? We start with a definition of "Simple" (originally from Kent Beck):

  1. passes its tests
  2. minimises duplication
  3. reveals its intent
  4. has fewer classes/modules/packages

[Kent] mentioned that passing tests matters more than low duplication, that low duplication matters more than revealing intent, and that revealing intent matters more than having fewer classes, modules, and packages.

This is the first reason I like it: it gives us a definition of "good". It's not an appeal to authority ("I made it follow the 'Strategy' pattern, so it must be better now") or a long list of "code smells" that you can attempt to identify and fix, it's just four short principles. And actually for our purposes it can be made shorter. How?

Let's regard rule 1 ("Passes tests") as an invariant, pretty much: if the code is failing tests, you are in "fix the code" mode, not in "refactor" mode. So we put that to one side.

What about rules 2 and 3? There has been much debate over their relative order, and the contention in this article is that it turns out not to matter , because they reinforce each other.

You should read the article if you haven't, because this blog post is not to paraphrase it but to say why I like it, and this is the second - and in some ways, the more powerful - reason. It gives us a place to start. Instead of being reduced to looking despairingly at the code and saying where do I even begin? (often followed 15 minutes later with "I want to kill it with fire"), we have an in. Fix a poor name. Extract a method to remove some duplication. You aren't choosing to attack the wrong problem first, because they're both facets of the same problem.

For me this is, or was, liberatory, and I share it with you in case it works for you too.

(For completeness: yes, we have basically ignored rule 4 here - think of it as a tie breaker)

Yule boot#

Sun 31 Dec 2023 09:12:28 PM UTC

Topics: liminix

The Turris Omnia basically works. It looks a lot more like a grown-up computer than the other devices we've previously seen - for example, the storage is MMC not raw flash (so we can use block filesystems like btrfs, ext4fs etc), and the bus is PCI (meaning it's enumerable, we don't need to put the network devices in the device tree). The WiFi chipsets are both ones we've seen before. All in all, the port has been quite smooth so far.

Smooth except for the small but (some would say) crucial lacuna that there's not yet a sensible way to install it without a serial connection. This might be considered less of a problem for this device than some others, because opening the case doesn't void the warranty. But still, non-optimal.

Also since I last wrote, Liminix has gained (although not yet merged) a port to another MIPS device, the Zyxel NWA50AX. This is thanks to Raito Bezarius, and it brought to light that I'd broken the tftpboot memory reservation thing for MIPS in the course of enabling it for Aarch64. Oops. So, after only a week of wrestling with U-boot and QEMU this functionality is now under CI test on all architectures.

I mention that now because all that U-Boot wrangling gave me the idea for a case-closed install for the Omnia. The Omnia has a quite slick U-Boot config with eleventy different rescue/recovery modes, and also (unlike many cheap MIPS devices) has the U-Boot environment set up properly so that changes to environment variables persist from one boot to the next. This means we can boot the vendor rescue system, which is stored on a separate NOR flash, and then use fw_setenv to change the bootcmd variable so that it boots a recovery image from TFTP or from a USB stick. Once we're running Liminix we can do any needed repartioning/reformatting of the MMC, then mount the real root filesystem on /mnt and install the production system using min-copy-closure. If the device owner later decides they want to return to Turris OS, the multitudinous rescue modes are still available.

Well, that's the plan, at least. It needed a small change to min-copy-closure so that it can install to a non-root prefix (e.g /mnt) which necessitated yet another several-day bout of learning about QEMU, now I just have to create the recovery config and then test it and find all the ways it breaks. Happy New Year.