I enjoyed reading this post by Rohan Ganapavarapu. It’s fascinating getting the perspective of someone born after the early internet yet wishing they were there to experience it. The ending’s quite illuminating:

There is neocites, and a small community of people who share this philosophy about the web (and that are relatively young), but I have not met anyone my age, in the real world, that would choose to do something like this.

The majority of people (my age [of 18]) today would think sites like those (and, by extension, their creators) are weird.

I guess, here’s to the weird ones. 🥂

Finished work and now I’m having a quick dinner before heading off to a meetup. And I can’t lie: I’ve been nervous all day. 😬

Kind of glad I don’t run a big, multinational corporation.

Scare with care. 🎃

A street pole features a sign with pedestrian crossing instructions, using humorous cartoon characters with jack-o'-lantern placed over their faces to indicate "Do Not Cross," "Cross With Care," and "Complete Crossing Do Not Start to Cross."

Try-Catch In UCL - Some Notes

Stared working on a try command to UCL, which can be used to trap errors that occur within a block. This is very much inspired by try-blocks in Java and Python, where the main block will run, and if any error occurs, it will fall through to the catch block:

try {
  echo "Something bad can happen here"
} catch {
  echo "It's all right. I'll run next"
}

This is all I’ve got working at the moment, but I want to quickly write some notes on how I’d like this to work, lest I forget it later.

First, much like everything in UCL, these blocks should return a value. So it should be possible to do something like this:

set myResults (try {
  result-of-something-that-can-fail
} catch {
  "My default"
})
--> (result of the thing)

This is kind of like using or in Lua to fallback to a default, just that if the result fails with an error, the default value can be returned from the catch block. In might even be possible to simply this further, and have catch just return a value in cases where an actual block of code is unnecessary:

set myResults (try { result-of-something-that-can-fail } catch "My default")

One other thing to consider is how to represent the error.  Errors are just treated out-of-band at the moment, and are represented as regular Go error types. It might be necessary to add a new error type to UCL, so that it can be passed through to the catch block for logging or switching:

try {
  do-something
} catch { |e|
  echo (cat "The error is " $e)
}

This could also be used as the return value if there is no catch block:

set myResult (try { error "my error" })
--> error: my error

Another idea I have is successive catch blocks, that would cascade one after the other if the one before it fails:

try {
  do-something
} catch {
  this-may-fail-also
} catch {
  echo "Always passes"
}

Unlike JavaScript or Python, I don’t think the idea of having catch blocks switching based on the error type would be suitable here. UCL is dynamic in nature, and having this static type checking feels a little wrong here. The catch blocks will only act as isolated blocks of execution, where an error would be caught and handled.

Finally, there’s finally, which would run regardless of which try or catch block was executed. I think, unlike the other two blocks, that the return value of a finally block will always be swallowed. I think this will work as the finally block should mainly be used for clean-up, and it’s the result of the try or catch blocks that are more important.

set res (try {
  "try"
} catch {
  "catch"
} finally {  
  "finally"
})
--> "try"

Anyway, this is the idea I have right now.

Update — I just realised that the idea of the last successful try block return an error, rather than letting it climb up the stack defeats the purpose of exceptions. So having something like the following:

try { error "this will fail" }

Should just unroll the stack and not return an error value. Although if there is a need to have an error value returned, then the following should work:

try { error "this will fail" } catch { |err| $err }
--> error: this will fail

I think Slack’s got an opportunity here to displace Confluence as the “system of record” for work documents. Their Canvas editor is quite good, much better than Confluence’s, and it’s one I really like using. Yet once a Canvas is written and published, they’re ridiculously hard to find again.

Having a central place to browse Canvases and arrange them into categories, much like someone would do in a wiki, would go a long way to making them useful as documents unto themselves, rather than simply “big messages” with short-to-medium-term lifespans.

That’s not to say there’s not a role for such documents. In fact, I wonder if that’s why wikis are always difficult to navigate: you’re mixing documents that have different expected lifespans. System designs sit alongside retrospectives from 2022, which sit alongside the agenda for a meeting next week.

Here Canvases in Slack could be created with the default expectation that the lifespan will be a couple or weeks, or a month, and it’s only those that you explicitly “keep” that would be browsable in this new system. These are the ones you expect to last years and be always kept up to date. The others will still be there — Slack can archive them — but they’ll slowly fade into the background much like the message history.

Anyway, just some random thoughts I had while starting to work on a design within a Canvas and wondering if it should actually go into Confluence.

Discovered that Enya is still releasing albums. Started listening to this one over the weekend. Quite good. 🎵

Weekly Update - 20 Oct 2024

Yeah, I know, it’s been a while… again. A lot has been happening in life and there’ve been many days that I haven’t done any work on anything. Things are starting to settle down now, although I am expecting a few more bumpy days ahead, so we’ll see how we go with project work.

Cyber Burger

Yeah, I’m getting pretty tired of this one. I’m right in the trough of despair here, where the initial excitement has worn off and I just want to finish it. All the remaining work for it has been defined, which I think helps, and now it’s just a matter of plowing through the tasks.

Recent work done on this is the addition of power-ups and power-downs, which does things like bump the remain time remaining, give the player a “tractor beam” weapon, and clearing the play-area of items, amongst other things. I’m about 2/3 through this one: most of the these power-ups have been implemented, including the tractor beam. After that, the remaining work on this project is adjusting the difficulty curve, improving the main menu, and finally finishing off the website.

Despite how fatigued I feel about this, it has been fun learning how to build for the Pico-8. The expect fidelity of the pixel art is within my skillset, and it’s quite impressive what it offers in terms of audio effects. I haven’t explored the music options, and I probably won’t for this game, but something to look at for the next one (if there will be a next one).

Coasters

This was a bit of a side tangent to get my mind off working on Cyber Burger. It was a long weekend, and I was passively scrolling through the sample of Vintage Logos when I thought about recreating a game that was published in the weekend newspaper we read while I was growing up. You’ll be presented with two images and a clue, and you’d have to guess the word or phrase these alluded to.  For example, if the clue was “insect” and the images were:

Then one possible answer would be “butterfly”.

The newspaper used stock photos, like the example above, but I was hoping to creates logos for fake companies as they would appear as if printed on cardboard coasters you’d find in pubs. The idea is that a new puzzle would be shown to the user a day, much like the word games you find online.

I coded up most of this in a single day and had a working version by the end of the weekend. I had a very simple Go server which served up a new puzzle every day at 00:00 UTC. The web frontend was mainly HTML, with some JavaScript for handling the player’s guesses. The puzzles themselves were defined in a CSV file which was imported into a Sqlite DB on server startup. This was a strange way of doing things, and was more of an accident as I was deploying this as a Docker container and I didn’t setup a persistent volume that survived restarts. I had plans of adding an admin section to the Go server so that I could design puzzles in advanced.

Fortunately I resisted this as I ended up only producing twelve puzzles. Once the original run was completed, I basically bundled them all on a static site. I was able to keep most of the original HTML and JavaScript as it was, with only the Go backend being junked. It’s still online, and maybe I’ll come back to it in the future, maybe using stock images in place of logos I have to create myself.

The new home page, made after the daily puzzles were at an end.
Example of one of the puzzles.

So although this was not a long lived side tangent, it was good to be able to get something finished. I was feeling quite dispirited with projects that I was just not finishing or releasing. Doing something small like this, and seeing it through, helped a lot. Maybe that’s the secret in how I can see through something from conception to completion: get the bulk of it done quickly, deploy it as soon as you can, and keep it small. That would limit the types of project I can deliver, but hey, at least I would deliver them.

Other Stuff

I added a few things to Ted, my terminal CSV editor, this past week. Like many of the other features of this project, this was driven mainly by needs that arise at work. I finally bit the bullet and embraced the support for headers. The first row of the CSV file is now treated as a header and is now fixed above the column, instead of the column numbers which were much less helpful. It should, in theory, be possible to read a CSV file without headers, but I hardly deal with those files that it’s probably just better to make headers the default.

TED with a very simple CSV file showing the headers.

I am also exploring ways to do more actions in bulk, such as add columns which are derived from the value of other columns. These are all quite experimental at the moment, and are more or less added in a quick and dirty fashion; just the bare minimum for what I’m trying to achieve. So not much to say here. A few other changes to other projects:

  • Nano Journal now keeps the current draft post in browser local storage, so that it’ll no longer get clobbered when you’re redirected to the login screen when trying to post an entry. This was a source of anxiety for me and meant I was less likely to write something off the cuff, so I’m glad this is now fixed.
  • Blogging Tool now has a new app which takes a clip videos produced by Pocketcasts — which is currently generated in an Instagram-style vertical video — and crops it as either a square or a letterbox.
The new "Post Podcast Clip" app in Blogging Tools.
Also, the app list has been styled a little better. Much more interesting than the bulleted list.

So, a lot of little things done this past month. Nothing worthy of a report on it’s own, but still, it’s something.

I was poking around Dave Winer’s Software Snacks — a brilliant name for those — and I stumbled across Little Card Editor. Decided to give it a try.

A cozy coffee table setup with a blue knitted item, blue headphones, and a smartphone displaying the time. The title ‘Morning Coffee Table’ is overlayed in the centre in a serif font.

Archie is no longer with us sadly, so my sister went out and got a new companion for Ivy. Say hello to Rico. 🦜

Auto-generated description: A cockatiel with yellow and gray plumage is perched near a wooden stand and a tray of assorted seeds.

So it looks like Squarespace has been acquired by a private equity firm. I wonder if the new owners will keep buying podcast ads, or if they’ll pull them like Akamai did when they acquired Linode. I get the feeling a lot of shows are relying on Squarespace’s consistent ad money to remain viable.

I’m going to a meetup surrounding a book that I haven’t read yet. I wanted to finish what I was reading at the time and I figured I’d have about a week to read this book before the meetup started. I thought I remembered buying it, so when it came time to start reading it, I was a little surprised to find it missing from the Kindle app.

Fearing that I was running out of time, I went to Amazon to buy it again, only to discover that I actually pre-ordered it and that it’s going to be released on the date of the meetup.

So, yeah, feeling releaved about that.

🔗 How to be confident

A great post by Annie Mueller. And pretty much spot on, based on my understanding of how to gain confidence.

🔗 Save the Web by Being Nice

Found this while browsing Dave Winer’s blog-roll on Scripting News. I enjoyed reading this post so I thought I’d take his advice and be nice by sharing a link to it.

Oof, it’s been quite the week! Almost over though: only around 30 minutes left, then it’s the weekend.

I’m officially a Zio today. 🙌

I’m generally not someone who likes to talk to people working on my hair. Even so, if silent cuts were offered to me, I not sure I would accept. The occasional “what do you do” and “how’s business”, enough to acknowledge each other, is fine. Not even having that would seem a little strange.

Don’t use access permissions to control what a user can and can’t do if the correct functionality of the system you’re building depends on it.

A user’s permission should dictate what a user has the right to do and see based on the policies of the resources themselves. But when it comes to the correct functionality of a system, it should be built such that if you were to disable all the permission checks, the user should be able to do whatever they can without breaking things. Relying on permissions to prevent this feels like a code smell to me, and can leave you with policies that have blanket denies for everyone that just can’t be taken out, and no one remembers why it was added there in the first place.

I don’t count myself a Safari fan, but full credit to Apple: they’ve made remote debugging for iPad Safari very easy. Plug the iPad in, tap “Trust the Device” a few times1, and Safari’s developer tools menu shows the iPad right there. It also works for SafariViewController sessions in modals, which is nice.


  1. There might be some setup stuff you’ll need to do on the iPad that I’ve forgotten about. ↩︎

Goland’s LLM-powered auto-complete is really good. It’s got to the point where it feels like Goland is broken when I’m using a version that doesn’t have it. I’m sure they hope to expand of this, and if I can make a request on what they could do next, it would be to add “auto-complete” suggestions in other areas of the code.

For example, I’m working on a function which uses AWS’s Golang SDK to send an SQS message. I started writing out the call to send a message, when I found out that I forgot to define both the context and queue name in the function I’m working in. Nothing too hard to fix, of course, but it would mean moving away from where I’m am now, and conducting a mini context-switch away from calling the SDK to fixing my function definition.

It would be nice for the LLM-based auto-completer to suggest adding the context as the first parameter of the function, as per the convention. The queue name is a little more ambiguous: it could either be suggested as another function parameter or as a field on the provider type. I suppose both are just as likely, but assuming that Goland is refining it’s model based on my trends, it could suggest adding the topic name as a field, along with adding it in as a parameter to the constructor function.

Anyway, something for them to look at when they run out of work.