7c0h

Latest Post

A eulogy for my Kindle DX

More than a decade ago on my first trip to the US I bought a Kindle DX, an almost-A4-sized e-book reader that followed me through multiple countries, homes, and commutes. We were off to a rocky start when I slipped on the ice and fell breaking the screen in the process, but I got a free replacement that I've been using ever since1.

I never used most of its functionalities - all I wanted was an e-book reader that I could load via USB with a big enough e-paper screen on which to read papers and comics in PDF format, and on that front my Kindle DX delivered like no other. I cannot speak to its audiobook-playing capacities nor 3G capabilities because, frankly, I never cared.

I kept the device in surprisingly good condition for a long time, with the only obvious problem being its micro USB port becoming progressively weaker as the years went by. So imagine my surprise when, about a month ago, my Kindle stopped working altogether regardless of a full battery and a still-working port. I tried all reset procedures I knew and I even exchanged its battery, but it is time for me to accept that the device is dead or, at least, beyond my skills to revive it. Whether its demise is related to me reading Careless people at the time remains an unanswered question.

I am currently deciding what to do with the remaining pieces. There seems to be exactly one project focused on controlling these screens and it's not precisely a friendly one, but I'm not in a rush to get it done. I will be needing a replacement, though, but whether it will be a second-hand Kindle DX or something else I cannot say. The smaller form factor of modern devices is mildly intriguing, but then I would also have to get a tablet for reading comics and that feels like a waste of money.

Goodbye, Martin's 2nd Kindle (as it was called). I wish you would have told me that you were close to the end so I could have saved, if not the books themselves, at least the bookmarks. And I would have had time to get replacement reading before my holidays, not to mention the 30€ I spent on a new battery. I guess now I'll never know whether it was MOBI or ePUB that I was supposed to use as ebook format, or at least not without consulting Wikipedia. I'm sure there's a lesson there somewhere.

Footnotes

  1. While the Ship of Theseus school of thought would argue that this is not the same device, the Japanese school would argue the opposite - if you haven't seen it, this anecdote from Douglas Adams' "Last Chance to See" gives a good summary.

Older Posts

I need a senior computer

After spending the holidays with my family I am once again reminded of the need for a computer with dedicated hardware for seniors. Whenever we talk about parents and tech we picture an old woman wearing a shawl trying to operate a computer that's turned off, and that's unfair: the problem is not that my mom doesn't understand how a mouse works (she does) but rather that her OS keeps moving things around, breaking the muscle memory on which she relies after losing her eyesight. And while a younger person would rely on accessibility software like the Orca screen reader, all my mom wants is to keep doing what she already knows.

My mom's computer needs are modest: listening to audiobooks, podcasts, voice notes, and getting reliable, repeatable answers to simple questions. Under her current setup only the first two are painless (relatively speaking) while the last two are impossible. Case in point: listening to an audiobook (that I download for her in a shared folder) requires turning on her computer, wait for the screen reader, press the Windows key, type "books", press Enter, Esc, Alt-Tab, scroll down to the right book, Enter, Ctrl+G, enter a page number, Enter, Esc, and finally Insert+Arrow Down, at which point the screen reader will finally read the book from the given page number.

One may think that a voice interface would be the solution, but our experiences have been mixed: while good for listening and replying to messages, asking Siri a question on her really-not-cheap iPhone ends up with Siri replying "I found this, take a look" (not the best phrasing, but whatever) and then performing an equally-complex series of swipes and clicks after which, more often than not, my mom gives up and asks whoever is around. Alexa isn't any better, alternating between misunderstanding our questions and trying to sell us premium apps.

The problem here is that my mom is expected to adapt to the technology instead of the other way around. What she needs is a simple device with roughly five customizable physical buttons (touchscreens are out for obvious reasons), two knobs, mic and speakers, and nothing else. One knob would select a function (list books, list audiobooks, list notes, etc), the other would control the volume, the buttons would depend on the current function (play and pause for podcasts, next page for audiobooks, and so on), and that's it. Connect the box to the WiFi (config provided via a file in the SD card) and we're good to go.

I know I can write the software for such a device, but the hardware is trickier. The input buttons are straightforward, the knobs less so, I have ideas for handling the mic, and the enclosure would be 3D printed. The OS would be Linux with remote access for troubleshooting, and all that's left is the two hundred unexpected tiny issues that always pop up. And then there's the question of whether a joystick wouldn't be a better choice...

I'm not saying I'll find the time to do it, but I'm definitely thinking about it.

Writer's block

I wrote my last post in November 2024, which is a lot. Unlike other dry spells (seven months in 2017 and six months in 2019), this one was not because I forgot about the blog but because I have a severe writing block due to, you guessed it, AI.

I receive lots of bot traffic every day — way more, I suspect, than actual human readers. That's usually not a problem because I think of this blog as a message in a bottle, drifting lazily through the oceans until one day someone finds it by chance, reads it and thinks "yeah, VGA cables are indeed cool". But AI changes the equation — if for every human I reach there are one hundred bots, then all I'm effectively doing is creating AI training data for free.

I used to think that the terms under which I release this content (Creative Commons BY-SA 4.0) would help: the "ShareAlike" terms give you permission to share and adapt my ideas, but only as long as you give proper attribution and distribute the result under the same license. This is all well and good until you learn that AI companies have decided that they can use all content ever created under a "fair use" policy, licenses be damned and sell you the results without even attributting the original author (let's not even think about compensation).

Much more talented people than me have given their reasons for why they think this whole situation is a travesty — Dorothy Gambrell, the creator Cat and Girl has made an eloquent case for why AI feels so much like theft and Mike Krahulik of Penny Arcade has made comics like this one, this other one and this third one. None of those texts include the word "fucking assholes", though, but that's understandable. My version does, though.

A cartoon of several artists put in a blender and being unhappy about it

Social problems cannot be solved with technology, but given the limited amount of power I have I will have to make do with the technology I have. I have decided to implement a three-step process:

  1. Add all known AI crawlers to my robots.txt file and restrict them to the PR part of this website (who I am, what I do, publications). Everything else is off-limits.
  2. Add some AI protection — I like the spirit behind Anubis but I may end up sticking to a combination of Apache's mod_evasive and Fail2Ban.
  3. If all that fails, a Tarpit for particularly misbehaved bots. How to generate an infinite maze of URLs for cheap is an interesting problem to think about, and one that I've started working on.

One of my personal goals has always been to make this website as quick to load as possible, which rules out captchas of any kind. A Proof-of-Work solution like the above-mentioned Anubis can work, but that remains to be seen. Other measures are less drastic, with the simplest one being that I'll try and get at least one curse per post. The reasons for this are complex enough that they deserve their own post, so stay tuned.

Adventures in making

There is a recurring joke about how the longer you work as a programmer, the stronger the urge to quit the industry and go live in a farm. I'm not at that point yet but I do have a soft spot for making physical things with my own two hands that, no matter how crooked, I can hold proudly and say "I did this". It is no surprise then that I'm a fan of the Maker Movement, the idea of figuring out how to do stuff on your own rather than purchasing it. I've been using my free time this year to build quite a lot of stuff, and yet 3D printing is the only one I wrote about.

Today's post is an attempt at remediating that. I don't expect you to like them all, but if you're looking for a new hobby then here's a list of hobbies a nerd can enjoy.

Drawing

I have a problem with drawing: I've been doing it for long enough that I'm objectively good at it (no just "good enough", but "good") and yet without a project at hand I just... don't. I had some success with small comics I drew during particularly depressing meetings and I've been chasing that high ever since.

A simple comic I drew about safety trainings.

A friend and I are currently looking into writing a comic together, so hopefully I'll have more to tell in the coming months. I would have liked to join a comic contest as our North star, but those are hard to come by when you're an adult.

I don't want to write much more about the topic because I already did it once.

Painting

I started taking painting classes about a year ago after realizing that you can learn from videos how to add purple shadows to portraits but you can't ask why you are adding purple shadows to pink skin. My drawing skills have helped with the first steps, but becoming the next Rembrandt will still take a while.

Painting of a crocodile.

My main shock about painting was the stark difference between me just "going with it" versus having a specific goal: I can get good results whenever I paint for fun (or, more accurately, when following the tasks my teacher gives me) but getting a precise result is still a lost cause - the least I care, the better the result. And while I understand why this happens, I don't yet have a working solution.

My current main challenge with painting is the cleanup: I still haven't processed the trauma of that one night when paint splashed everywhere and I spent the next hour on my knees chasing tiny paint spots on the floor of my rented apartment. I know I can't get better without practice, but sometimes the apprehension is just too much.

Sewing

I have a general rule: if I face the same problem three times, and the problem is salient enough that I remember all three occasions at once, then I need to figure out how to solve it for good. October found me in this specific situation when I realized that I had

  • One nice shirt that's too big for me,
  • One summer shirt that's too big for me, and
  • One summer hoodie design that I've been wanting to have for almost twenty years.

My first idea was to learn sewing by hand. I wouldn't recommend it as a long-time strategy, but hand-making my own sweatshirt taught me a lot about why a sewing machine does what it does and when is hand stitching the faster, simpler alternative.

The next natural step was to get a sewing machine. The one in my local library is eternally on loan, but luckily second-hand sewing machines in my area are surprisingly cheap. The difficult part was finding a good first project: I checked every beginner book in every library I know, and yet all of them start with projects like a skirt, a top or a dress, none of which would be very useful for me. In the end my hand-sewn sweatshirt had to be redone when the material failed to shrink as promised and having to redo all of that gave me some good practice.

Having now resized one shirt, one t-shirt, one sweatshirt and having made a summer hoodie from scratch I believe I'm ready to tackle the nice shirt. I've been toying with some stupid ideas after that, but whether they end up being fashion or cosplay I cannot say.

Music

I never really stopped playing music, but my piano skills have not evolved much in the last ten years. Fate put recently an old guitar into my hands for repair, and this gave me a good chance to give the habit a bit of a refresh - I learned how to play guitar when I was 12, and I am glad to report that I still keep the muscle memory.

The weird part was singing - I stopped playing guitar because I was really bad at singing, and yet I am now at the point of my life in which I get to understand two things:

  • Singing is not that difficult once you understand that your voice and the music have to follow each other
  • As long as your singing isn't atrocious, no one really cares

I tried to write an app for showing a song and its corresponding tab, but the problem is harder than I thought: the whole song doesn't fit in a phone screen, you cannot click the screen to move on (both your hands are busy), and coordinating the text and music automatically is a tough problem. I considered real-time speech detection, but I'm not sure there really is interest for that as guitar players are notoriously uninterested in formalizing their art. I'm currently sticking to the tried-and-tested hand-written booklet until I find a better solution.

Penmanship

On the summer of 2002 I stopped writing cursive - I was taking my first Math courses and realized that formulas only make sense in block letters. My block handwriting declined steadily until 2014 when I decided to do something about it, but cursive remained forgotten until last year.

It was quite shocking to realize that I no longer remembered how to write some uppercase letters, particularly one that's part of my own name. I therefore made a conscious effort to start writing cursive more often, I looked into different types of scripts, and nowadays my cursive is nicer than it ever was - I'm still not as good as some teenage girls I know, but I'm getting there.

Make-up

I have no interest in wearing make-up on my day-to-day - in fact I wish less people would do it. But during Halloween, Karneval or similar? If you think of it as "applied painting" it turns out to be a lot of fun.

Picture of me in skull makeup

I believe my skull makeup is on point (I really need to find a new tube of cracked-skin white base) and my Picasso was also not that bad, but where to go from there is harder. I tried checking in social media, but the most interesting ones are meant for the camera and fall apart the second you look away. Latex prosthetic seem promising, so I'll probably be trying that for next February.

The way forward

I have a couple ideas I want to try next year. Sculpting in wax seems fun (messy, though) and woodworking (even messier) has definitely made it through my "three problems" threshold. And if I had a backyard you can bet I'd have a project boat underway - did you know you can just download instructions to make one?

I won't pretend that I'm particularly good at most of these hobbies, but I am fine and that's what matters. Mastery is a life-long process, but making your own t-shirt takes a couple days (about a week if you want welt pockets).

So go ahead and give any of them a try. Write a comic on post-its, draw a bad portrait, play some chords on a guitar and make a wax tiki lamp. Programming is a lot of fun, but remember that specialization is for insects.

Therac-25, LLMs and the Zen of Python

If you are a professional software developer you probably heard at some point the cautionary tale of the Therac-25, a radiation therapy machine that gave massive overdoses of radiation to at least six patients in the 80s and killed at least three.

There are several layers of problems explaining how all of this came to be, but today I'd like to focus on a specific thread. The (in)famous race condition in the Therac-25 was caused by two simultaneous bugs, but these bugs were not new: the software for the Therac-25 was ported from a previous version of the machine (the Therac-20) and those bugs were already present there. The key difference being that, while the Therac-20 had hardware interlocks preventing those faults, the Therac-25 engineers decided to implement them exclusively in software.

I'm digging this story up because today I read yet again someone suggesting that using ChatGPT to rewrite code from one programming language to another is a great idea. I disagree: a programming language is an opinionated way on how to better achieve a certain task and switching between world views without understanding how and why they do things the way they do is a recipe for inefficient code at best and weird bugs at worse. Simple example: if you're a Python programmer who came from C then you probably wrote loops like this:

# C programmer version
for i in range(len(mylist)):
    item = mylist[i]
    f(item)

# Pythonic code
for item in mylist:
    f(item)

This is a very simple example that highlights a fundamental misunderstanding of the language. The first code will run just fine, but it's generally not the proper way of writing Python code. For a more "real-life" example you can read the introduction to Learn Rust With Entirely Too Many Linked Lists where the author points out that writing linked lists in Rust is, from a Rust point of view, overall a bad idea and something to avoid entirely.

Real-case LLM

I decided to test my theory with Google's Gemini - I've seen students using it in their actual coding (probably because it's free) making it a fair choice. I asked the following:

Convert the following code from Python to Elixir:
def change_eight(my_arr):
    my_arr[8] = None

And the answer was:

def change_eight(my_arr) do
  if length(my_arr) >= 9 do
    List.replace_at(my_arr, 8, nil)
  else
    my_arr
  end
end
# This Elixir code ensures that the index 8 exists in the list before
# attempting to replace the value with nil. If the index is out of bounds,
# the original list is returned unchanged.

In my original code passing a list with less than 9 elements would throw an IndexError exception, which is consistent with The Zen of Python principle "Errors should never pass silently". But if my code relies on the exception to detect that a precondition is not being met, this rewrite has now ensured that the error will not be detected because the exception won't be triggered.

I added more context to the prompt, passing this code instead:

def change_eight(my_arr):
    my_arr[8] = None

if __name__ == '__main__':
    mylist = list(range(10))
    try:
        change_eight(mylist)
    except IndexError:
        print("Precondition failed")

    mylist = list(range(20))
    try:
        change_eight(mylist)
    except IndexError:
        print("Second precondition failed")

which lead to this rewrite:

def change_eight(my_arr) do
  if length(my_arr) >= 9 do
    List.replace_at(my_arr, 8, nil)
  else
    raise RuntimeError, "Precondition failed"
  end
end

if __MODULE__ == __ENV__["__MODULE__"] do
  mylist = Enum.to_list(0..9)
  try do
    change_eight(mylist)
  rescue RuntimeError -> error
    IO.puts(error.message)
  end

  mylist = Enum.to_list(0..19)
  try do
    change_eight(mylist)
  rescue RuntimeError -> error
    IO.puts(error.message)
  end
end
# This Elixir code is similar to the previous response, but it includes two
# test cases to demonstrate how the RuntimeError is raised in different scenarios.

The new version of the function is marginally better: Gemini now throws exceptions where expected, but it has also hard-coded the first error message - if the code fails on the second call the user will be shown an error corresponding to the first. I later asked for a C version instead of Elixir, at which point the error messages where gone entirely.

This is how critical bugs are born: when your software depends on (reasonable!) assumptions about the world and you send it through a pipeline (be it human or automated) that has no idea about what those preconditions are. And if you send your code through a system that's been designed to understand code exclusively at a syntactic level then you don't get to be surprised when the resulting code is not semantically equivalent to your original one.

Final words

Software development is not just about writing code. Software development is about understanding the environment in which your code runs and the decisions that lead to it - some of them reasonable ("this condition can never happen, the hardware will catch it"), some of them arbitrary ("let's write it in Perl"). The Therac-25 incident was made possible because someone decided to use code on an unfamiliar environment without considering the repercussions, the same way that Gemini did not consider "The Zen of Python" nor my error reporting strategy while rewriting my code.

There is more to software development than "data comes in, data comes out". Thinking about systems in terms of the context in which they run (software, hardware and social) is the best way to avoid finding yourself one day unpleasantly surprised.

Or, perhaps more relevant, unpleasantly shocked.

Further reading

If you haven't already, consider giving the classical paper "Four dark corners of Software Engineering" a try.