James Crisp

Software dev, tech, mind hacks and the occasional personal bit

AI and Software Craftsmanship

I remember a decade or two ago, people were talking about the idea of software as a craft, with apprenticeships, journeymen etc. This always struck a chord with me. A lot of the time, software (for me) has been about talking with people, working out what they really need, and carefully and iteratively developing the UI, code and and infrastructure. Don’t get me wrong, there’s some Engineering as well, in designing the architectures, scalability, failover, backups, etc, as well as in every DB query and service call.

It’s been a good three decades where the coding itself was a craft. Object oriented (or functional) beauty, DRY, readability, good naming, etc were lofty goals and paid their own way in terms of software maintenance costs, extensibility and lifespan, and developers were rewarded highly for these skills. It’s been a good run, but I can only think this period is coming to an end.

With AI coding, the industry is in the throws of an industrial revolution of code – more volume, less care, factory style. Maybe this is not a bad thing, but it looks like the end of the age of coding craftsmanship. That being said, you get better results with an experienced developer at the helm of the coding machinery who understands things like modularity, encapsulation, interfaces, frameworks, on-going maintenance effort, security, etc.

Software development is by no means just coding. It encompasses talking with people to find out what they need, working out what to build, designing efficient humane user interfaces, designing the architecture and implementing the infrastructure, constant decisions and trade-offs, telling people about what you’ve built and getting them to use it, supporting the software and maintaining it over time. Most of these areas are still crafts that rely on the skills and experience of humans and not (yet? maybe ever?) well done by AIs.

I’ve always thought that being a generalist is the best course in software – being able to do a bit of everything from talking to people, to writing code and understanding the infrastructure and networking. I can only see this is ever more true with AI growing in its abilities. The wider the range of your skillset, the less risk a lot of it will be replaceable by AI.. and besides, it’s more fun to do a variety of different things.

So in conclusion, software development is not dead and replaced by AI. Though I feel the coding craftsmanship part of it is ending.

Matthias Alexander’s book: The Use of the Self

  • Current feelings are deceptive of use – get an objective view of use: (eg, mirror/camera). What “feel rights” is trained wrong.
  • Long habits of use will override any trying to do differently.
  • Whole body is interconnected; any isolated change causes other (likely bad) compensations.
  • Have to train new use over and over to become automatic habit, and pair with activity to link them.
  • When about to do an activity, start with inhibiting the activity – decide not to do it. Work through the “means whereby” stage by stage and all at once (keeping previous stages on as add the next). When ready, decide afresh: sometimes take the action, sometimes do something else with good use (eg, raise hand). This is to break the old habit of use.

Kayaking tips

Kayaking notes from Akaroa Crater tour.

Start stroke with:

  • Paddle as far forward as possible, tilt forward at hip, paddle right towards bow.
  • Paddle in as vertical as possible.
  • Keep arms straight and twist from core to pull back paddle. End stroke at your waist.
  • Punch with top arm as well as pull with bottom, but main drive from core twist.
  • Keep hips loose and able to pivot independent of body, which stays upright to keep balance. Can tilt kayak with hips (eg, for edging). Stay relaxed and loose.
  • Hold sides of kayak with knees.
  • Opposite foot press vs. paddle side, but minor, not important.

End result
Straight arms, rotating paddle going along sides of kayak, with power from core twist. Sitting up straight, or waist tilt forward, core on.

Sea cave
Amazing. Hear roar of waves, go in on kayak with wave, hold paddle along length of kayak and wash out. When low, bend forward or back to get under low part.

Talk: Generating QR Codes in pure Ruby

I’ll be presenting a short talk at the Sydney Ruby Group on Tuesday 8 Sept. Hope to see you there from 6pm!

Generating QR Codes in pure Ruby

QR Codes are useful and easy to generate in Ruby using the rqrcode gem. Generating one and rendering it in a Rails template only takes a few lines, but I’ll show you a few tips plus how to shave off the gem dependencies, and how to write simple tests to make sure your QR Codes keep generating safely into the future.

Event / RSVP on Meetup

Ubuntu on old iMac: Fixing screen dim/sleep

My old iMac (late 2015, retina 27 inch) sadly reached end of support on OSX a while back. It still has a beautiful screen and enough processor power to do most daily task. I brought it back out of storage to be a Claude co-work box. After a little dalliance with OpenCore (not bad as a Mac but unsafe through OS updates, some graphics driver issues, and a bit slow), it is now running Ubuntu 26.04.

The big problem with Ubuntu was power management. Once the machine went to sleep or screen dimmed it often didn’t wake up again, or if it did, it took just over 60 seconds to respond.

I’ve turned off sleep since I want the machine to be awake all the time to be ready to respond to dispatch commands from Claude co-work. However, I do want to have the screen dim (this really means screen off) happening so that the screen does not get burned in and also so that a password is required to access the machine.

After a quite a bit of debugging and help from Claude, here is the fix:

In /etc/default/grub
Find line like: GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

Add the two extra parameters to make it:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_backlight=native amdgpu.dpm=0"

sudo update-grub

<REBOOT>

amdgpu.dpm=0 disables broken power management (GPU then runs at fixed clocks). 
acpi_backlight=native switches on the native backlight driver, which helps the panel come back reliably.

If you have a similar old Apple machine, indicative of this problem / fix is repeated amdgpu error messages in kernel log:


sudo dmesg -w

amdgpu 0000:01:00.0: last message was failed ret is 0
[repeated many times]

AirTag 2nd Generation incompatibility

To see the location of an AirTag second generation, you need to have an Apple device running the latest OS. For some reason, Find My online (website) does not show AirTags. Furthermore, older Apple devices won’t even help you. Sequoia on Mac is unable to see the AirTag second generation location – despite it still being a supported OS version. You need a device running Tahoe. AirTags second generation are surprisingly and unhelpfully incompatible.

The window.beforeUnload event – a sad tale

Well now, gather around children…

Once upon a time, the good developers wanted to save their users from losing changes if they left a form before submitting it. And as sometimes happens, Browsers looked kindly on the world, and provided the beforeUnload event, which could be hooked in Javascript so that changes could be automatically saved or a confirm dialog could be shown. The developers and users were overjoyed, and a golden age ensued.

But then enter the evil developers! These developers hooked the beforeUnload event to make the user’s life miserable. They coded event handlers so that people could never leave pages, and were stuck in a hell of eternal dialogs and never-ending pop-up windows.

The Browsers realised that beforeUnload had been a mistake, and something had to be done. The event was still needed by the good developers, but the evil developers had to be contained. So the event was changed to something “special”, and uncontrollable!

Thus code like this was born:

window.addEventListener('beforeunload', function(e) {
  e.preventDefault();
  e.returnValue = ''; // Triggers the browser's generic warning confirm, cannot be customised
  } 
});

And it mainly worked. The evil developers were stopped, and the users were freed from the inescapable prisons of popups and alerts.

But the good developers wanted to write automated browser tests to ensure that the beforeUnload event worked, and that users would be saved from losing their changes forever. And this is where the tale becomes even sadder.

In Selenium / Firefox, no confirm dialog is shown from beforeUnload in tests, even though the confirm dialog shows during a usual interactive session.

In Cuprite / Chrome the story is more complicated. A message is shown on the console:

Modal window with text `` has been opened, but you didn't wrap your code into (`accept_prompt` | `dismiss_prompt` | `accept_confirm` | `dismiss_confirm` | `accept_alert`), accepting by default

But none of the ‘accept’ or ‘dismiss’ options work, or catch the dialog. They only work on normal JavaScript confirms and alerts. The only option is:

page.driver.browser.on(:dialog) do |dialog|
  # I DO GET CALLED! BUT ASYNCHRONOUSLY.
end

But the dialog object cannot be accepted or dismissed, unlike all other dialog objects. It also has an empty message. Alas, our story ends a testing tragedy. The console warning message is always shown, and no significant test can be written, as the Cancel (dismiss) button cannot be pressed.

And so, to this day, the good developers must test this code manually, like it was the 1990s.

PS – do let me know if this tale is wrong and there is a better way…

PPS – Chrome, Edge and Firefox support beforeUnload in this way. But Safari on iOS ignores it. Safari on Mac largely supports beforeUnload, but after a cancel in the dialog to stay on the page, it doesn’t seem like the page can do a programmatic redirect from JS later (which other browsers allow).

Todays take on the BEST AI for a task…

Coding: Claude 3.7 for front-end work, especially with the help of Claude Projects to upload supporting files, and Extended Thinking turned on. Remember to always ask Claude to explain its plan before doing anything as it can get carried away. Claude 3.7 paid responds much faster than the free version.

Mobile App – Voice: I do like to sometimes ask questions using my voice and have a conversation with an AI who speaks aloud. The ChatGPT app does a great job of this, and has good support for image/video uploads as well (eg, identify this spider please). The other AIs interact in a far less “human” way – more like just text-to-speech. Again, this requires the paid subscription.

Deep research: Yes, it is Gemini 2.5 Pro Deep Research. Requests are limited and it is slow to give you an answer, but quite comprehensive. It writes you a long report but also provides a good summary of findings.

Tomorrow is a new day, expect change!

Web Fonts built into all browsers (for sans-serif)

The fonts built into modern browsers are varied – it is hard to avoid loading your own fonts. Arial is the rare exception – it is well supported across all old and modern browsers. It looks a little different between Windows and Mac / iOS especially as a larger bold heading. On Android, it is substituted by Roboto. On Linux variants, Arial will likely fall back to the sans-serif system font.

Verdana is also well supported but looks a bit odd in this day and age.

You could instead go with the system font on each platform (eg, San Francisco for Mac/iOS, Segoe UI for Windows, Roboto for Android, etc). However, this means that every platform will look a little different, especially for larger and heavier font styles. Personally I like San Francisco and Roboto (and they look fairly similar). However, I find Segoe UI in large and heavy looks quite different and unsuitable for a “serious” website. If you could use Roboto on Windows reliability, this approach would be better.. but Roboto is only included with Edge but not Chrome on Windows.

So basically, if you want a “serious” looking sans-serif font that is similar across platforms, then it’s either Arial OR it’s time to load your own font and take the performance penalty in return for the look and consistency across platforms.

Google Fonts is a good place to get a font to self host. You can then convert the downloaded ttf with woff2compress (also available on brew) to make it a smaller download and host as a woff2. The woff2 format is now supported by all modern browsers.

“The Obstacle is the Way” by Ryan Holiday

After reading an interview with DHH where he mentioned this book, and to assuage a latent interest in stoicism, I decided to check out “The Obstacle is the Way”. I found it an invigorating read. It is in the usual self-help style with stories supporting the ideas and approaches proposed.

Here are my notes on the book:

Be tough, strong and resilient rather than entitled or precious.
Do not give in to adversity, this is true strength.

Observe without judgement or reaction. Maintain sang froid. Be intentional. There is always an action you can take to make it better or worse.

Break it down. Go step by step. Just do the next thing right now. Do it well and with enthusiasm.

An obstacle or set back is a chance to practice a skill, to learn or to get stronger. The obstacle is the path.
Every crisis is an opportunity to do something you couldn’t before.

Accept and acquiesce to what cannot be changed. It is so. Once you’ve done your best, it is up to fate/God. But remember you can still achieve your goals like water always finds its way downhill.

Love your fate. From hard times, there is always a benefit – learn, rebuild better, build character, etc. Maintain an unfailing cheerfulness.

Think: If it happened, it was meant to happen, and I’m glad that it happened when it did. I am meant to make the best of it.

Perseverance in key to grind down obstacles. Churchill’s acronym KBO: keep buggering on!

Even if your can’t help yourself, think how you can help others in a difficult situation. 

After each obstacle is another obstacle. The more you accomplish, the more things will stand in your way. Each one in a new opportunity to develop strength, wisdom and perspective. Be eager for the next round.

Page 1 of 21

Powered by WordPress & Theme by Anders Norén