Speaking of bad UIs, volià: my first attempt at building something with Gio:

A screenshot of a window with the title Gio, a connection header, a left pane showing a NATS message to send, and a right pane showing messages that can be received

It doesn’t do anything now, but I’m hoping this will be something I can use to test NATS. I will say Gio shows promise. Not a huge range of controls to use, but having everything run in a single memory address is nice.

An Unfair Critique Of OS/2 UI Design From 30 Years Ago

A favourite YouTube channel of mine is Michael MJD, who likes to explore retro PC products and software from the 90s and early 2000s. Examples of these include videos on Windows 95, Windows 98, and the various consumer tech products designed to get people online. Can I just say how interesting those times were, where phrases such as “surfing the net” were thrown about, and where shopping centres were always used to explain visiting websites. I guess it was the best analogy one could use at the time.

A staple of Michael MJD’s channel is when he installs an old operating systems onto old hardware1. Yesterday, I watched the one where he installed OS/2 Warp 4 onto a 98 PC. We were an OS/2 household back when I was growing up, thanks to my dad using it for work, and I can remember using OS/2 2.1 and thinking it was actually pretty good. Better than Windows 95, in fact. I can’t remember if I ever used Warp 4, though.

Anyway, while watching this video, and I was taken aback on how bad the UI design of OS/2 Warp 4 was. And really, I probably shouldn’t be throwing stones here: I’m not a great UI designer myself. But I guess my exposure to later versions of Windows and macOS matured my tastes somewhat; where I got exposed to the idea of interaction systems and user experience design (and generally just growing up). Obviously given how new the GUI was back then, many of these concepts were still in their infancy, although if you were to compare these UIs to the classic Mac or even Windows 3.1, I do think there was something missing in IBM’s design acumen. Was it ability? Interest? Care? Not sure. But given that it’s been 30 years, I’m not expecting the OS/2 devs to be able to defend themselves now. That’s what makes this critique wholly unfair.

Anyway, I’d thought I share some of the stills from this video that I thought contained some of the more cringeworthy UI designs2, along with my remarks. Enjoy.

I found this video on the failure of the Star Wars Hotel by Jenny Nicholson to be absolutely fascinating. A great example of Disney enshittification and promising more then they can deliver. Many of her other videos are great as well (I actually went on a binge session over the weekend). 📺

👨‍💻 New post on Go over at Coding Bits: Disabling Parallel Test Runs In Go

My Pile-Up Poker result for today = $840.00. Decent result for a first game.

Pile-up poker result screen

Also, I’m not sure if sharing my actual “solution” is consider a spoiler, so click through to see that.

Some More Thoughts On Unit Testing

Kinda want to avoid this blog descending into a series of “this is wrong with unit testing” posts, but something did occur to me this morning. We’ve kicked off a new service at work recently. It’s just me and this other developer working on it at the moment, and it’s given us the opportunity to try out this “mockless” approach to testing, of which I ranted about a couple of weeks ago (in fact, the other developer is the person I had that discussion with). And it’s probably no surprise, but I’m finding writing tests this way to be a much nicer experience already.

And I think I’ve come to the realisation that the issue is not so much with mocking itself. Rather, it’s the style of testing that it encourages. When you’re testing against “real” services, you’ll left with treating them as a black box. There’s no real way to verify your code is working correctly other than letting it interact with these services as it would, and then “probing” them in some way — running queries, waiting for messages to arrive at topics, etc. — to know whether the interaction worked. You can’t just verify this by intercepting the various calls made by the service (well you can, but it would be difficult to do).

There’s nothing about mocking that inhibits this style of testing. You can use mocks to simulate a message broker by storing the messages in an in-memory list, for example. What it does do, however, is make it easier to write tests that simply intercept the calls of the service and verify that they were made. It’s less upfront work than setting up a real client, or simulating a message broker, but now you’ve tied your tests to your implementation. You may feel like you’ve saved time and effort now, but really you’ve just deferred it for later, when you need to fix your tests when you’ve change your implementation.

I know this is stuff I said before, so I’ll just stop here, and end by saying that I’m excited to seriously try out this approach to writing unit tests. Is it a better approach than using mocks? I guess time will tell. It’s been my experience that it’s when you need to refactor things in your service when you find out how good your tests are. So I guess we’ll check back in about six months or so.

I’m not on Threads but I do click through sometimes to post shared on Mastodon, and I’m a little confused by the web-based video player. It auto-plays, which is annoying enough, but it does so with the sound off and there’s no way to pause or scrub back to the beginning. Is that by design? Do I just have to always refresh the page whenever I want to watch something just so I don’t miss the beginning? Very strange.

Must say I’m really enjoying M. G. Siegler’s new blog Spyglass. I’ve liked pretty much every post I’ve read so far. Definitely worth subscribing to.

“What about your Savoys, Mrs. D?”

Auto generated description: A supermarket shelf displays various brands of crackers, including Arnott's Jatz, Ritz, and Clix, with a price tag indicating $5.50 for one of the products.

A black swan event.

(And yes, I took this photo just so I can use this caption).

Auto generated description: A black swan with a red beak is swimming in a body of water near a concrete step.

Returned to Tuggeranong this morning for breakfast and a walk around the lake. Really enjoy going to “Tuggers” when I’m in ACT. I can’t quite explain it, but I always get New Zealand vibes whenever I visit.

Auto generated description: A tranquil lakeside scene features autumnal trees, still waters reflecting the landscape, and a backdrop of rolling hills under a cloudy sky.

If Slack’s looking for features to add, my vote would be for personal “annotation” messages in threads, similar to what Hey mail has. Many a time I receive a support request as a Slack thread, and it’d be nice to add notes such as customer IDs as a message that only I can see.

Here’s a mockup:

A concept mock-up of a Slack thread showing interaction between a support person and the author, with the private note message highlighted in yellow with the disclosure 'only visible to you'

Edit: I knew I talked about this before. And looking through On This Day, I found this post, where I professed my wish for FastMail to add the same feature. Probably a good hint that such a feature should be table steaks for any system involving other people.

New offering at the Cockatiel Cafe: the “breakfast bar”. 🦜

Auto-generated description: Two cockatiels are standing on a kitchen bench scattered with seeds, with one bird near the edge and another closer to the middle.  Auto-generated description: Two cockatiels, the same two shown on the previous photo, are eating scattered seeds on the kitchen bench.

👨‍💻 New post on Databases over at Coding Bits: PostgreSQL, pgx, sqlc and bytea

Wish TLDraw offered a cylinder shape. I know my needs are quite niche, but I really like using this app for back-of-the-napkin architecture diagrams of software systems, and having a cylinder shape to represent a database or queue would really come in handy.

Playing around with Vintage Logo this morning. HT to @odd and @mandaris for posting a link to this iOS app. They’ve got some very nice logo templates here, including this art deco one featuring a bird in flight.

Used it to make this logo, which I call: lodgings for the evening.

An art deco inspired logo featuring a line drawing of a bird in flight in blue, and the name ‘the cockatiel cafe’ written along in cursive writing in red

I can’t for the life of me remember how to create a child page in Notion’s mobile app. Why do they hide that option with the bullets and headings? Couldn’t the New Page button be context specific, instead of creating a new top-level page wherever you press it?

Reliving my European trip through my posts here. They’ve started to appear on my On This Day page.

I sometimes wonder if I should’ve posted more at the time. I deliberately kept to my usual pace of one or two posts a day, mainly because others suggest that it’s usually not a great idea posting loads of photos of your trip on social media, lest you make people jealous about what you’re currently doing. Although, when they say “social media” they mean Instagram or TikTok and not Micro.blog, although one could make the case that’s still kinda, sorta, if-you-squint-and-tilt-your-head social media, maybe?

Ah well, doesn’t matter. I think I made to right call: living the moment instead of spending all my time working out whether something was post worthy. Plus, I’ve still got loads of photo and journal entries that I could turn into blog posts. Maybe one day I will.

Adjusting my SQL code formatting preferences at the moment, and it just feel so… byzantine. There’s probably close to 200 different settings here (I stopped counting after 100) and hunting through them trying to find the one that controls whether parenthesis should appear on the same line as the CREATE statement is so time-consuming.

It would be nice for editors to provide a way to “learn” a code formatting style. They can present you with some sample code and say to you, “format this the way you’d like to see it and we’ll learn from that.” There can be several of these samples, presented to you one at a time, each one intended to answer a particular question about how the style should be. For example: one might have a dramatically narrow page width, forcing the user to break long lines.

From that, they can build a profile that will be used to configure the formatter. The configuration will essentially be the same as what’s used by formatters today — and can be transferred or checked into source control like a regular config file. It’ll just come from this learning routine, rather than the user poking through piles of checkboxes and pickers spread across 8 different tabs (I counted those as well).

Could this be something an onboard LLMs can actually do? Not sure. But if code editors are looking for “AI” features to add to their product, this might be one worth considering.

Side Scroller 95

I haven’t been doing much work on new projects recently. Mainly, I’ve been perusing my archives looking for interesting things to play around with. Some of them needed some light work to get working again but really I just wanted to experience them.

I did come across one old projects which I’ll talk about here: a game I called Side Scroller 95.  And yes, the “95” refers to Windows 95.

This was a remake of Side Scroller, a QBasic game I made back in the day. Having played around with Delphi programming after a while, and finding a bunch of DirectX 7 components, I set about recreating this game.  I’m not sure why I decided to remake this game vs. making something new. Was it because it was simple enough to try, or I found the levels interesting? Maybe? I can’t really say.

SS95 showing level E2M2.

Anyway, there wasn’t much to this game from the beginning. All the movement was cell based, with the usual assortment of solid tiles, hazards, and keys and locks (no pickups though). I eventually added a simple enemy as well: a robot which just went from left to right.

Level set 2 has the more interesting levels. This is S2E7, showing the player loose breath while underwater.
Level S2E8, with a "gold" tile scheme and backdrop.
Level S2E10, with a rainbow scheme and lots of invisible laser emitters.
Level S2E11, with an "underwater" scheme, which is just blues and greens. Also note the only enemy of the game, which was a robot that moved from left to right.

This project really showcases my crappy art skills at the time (I wish I could say they improved, but that would be a lie). The tiles and sprites were creating using MSPaint. This was back in the day when MSPaint was actually quite usable for pixel art, where drawing a rectangle actually rendered a rectangle then and there, rather than product an object which could be moved around (it’s just not the same now). The backgrounds were made by making gradients in Microsoft Word, taking a screenshot, and cropping them. And the sound effects were taken from the PC version of Metal Gear Solid (the WAV files were just sitting there on the file system).

The level editor. Unfortunately, it doesn't render well in Crossover so here's how it looks in Delphi 7's form designer.
The "Level Properties" form in the level editor, showing how Sprites were configured. Adding sprites were an absolute nightmare.

The game itself is pretty unremarkable, although I would say that one attribute that I really enjoyed doing is adding level scripts. These were Pascel scripts — interpreted by a Delphi control I found — that intercepted events, such as triggers or timeouts, and modified the level in some way. This was done late in the project, so it wasn’t used much, but it did make for some unique level-specific elements in the later levels. An example of one of the level scripts is provided below. This added platforms which ascended one cell at a time when activated. I forget most of what the built-ins did but I believe the OnActivateX hooks fired when a switch was triggered and the OnTimedEventX fired when a timer elapsed. 

unit LevelScr;

uses SSUTIL;

const
  INT_STX  = 0;
  INT_STY  = 1;
  INT_EDX  = 2;
  INT_EDY  = 3;

  INT_CURX = 4;
  INT_CURY = 5;

procedure LevSetupMove(sx, sy, ex, ey: integer);
begin
  SetStackInteger(INT_STX, sx); 
  SetStackInteger(INT_STY, sy);
  SetStackInteger(INT_EDX, ex);
  SetStackInteger(INT_EDY, ey);

  SetStackInteger(INT_CURX, sx);
  SetStackInteger(INT_CURY, sy);
end;

procedure OnActivate1(tag: integer; ison: boolean);
begin
  case tag of
    1: LevSetupMove(6, 9, 6, 5);
    2: LevSetupMove(18, 9, 18, 4);
    3: begin
     LevSetupMove(20, 19, 20, 16);
     Level.SetTile(21, 18, 52);
       end;
    4: LevSetupMove(11, 23, 11, 19);
    5: LevSetupMove(10, 23, 10, 17);
    6: LevSetupMove(9, 17, 9, 15);
    7: LevSetupMove(9, 15, 9, 13);
    8: LevSetupMove(9, 13, 9, 11);
  end;
  SetupTimer(1, 2, 1, true); 
end;

procedure OnActivate2(tag: integer; ison: boolean);
begin
  case tag of
    1: LevSetupMove(20, 20, 20, 16);
  end;
  SetupTimer(2, 2, 1, true); 
end;

procedure OnTimedEvent1(event: integer);
var cx, cy: integer;
begin
    
  cx := StackInteger(INT_CURX);
  cy := StackInteger(INT_CURY);

  if ((cx = StackInteger(INT_EDX)) and
    (cy = StackInteger(INT_EDY))) then
  begin
    ResetTimer(1);
  end
  else
  begin
    Level.SetTile(cx, cy, 12);
    cy := cy - 1;
    Level.SetTile(cx, cy, 13);

    SetStackInteger(INT_CURX, cx);
    SetStackInteger(INT_CURY, cy);
    PlaySound(11, false);
  end;
end;

procedure OnTimedEvent2(event: integer);
var cx, cy: integer;
begin
    
  cx := StackInteger(INT_CURX);
  cy := StackInteger(INT_CURY);

  if ((cx = StackInteger(INT_EDX)) and
    (cy = StackInteger(INT_EDY))) then
  begin
    ResetTimer(2);
    Explode(cy, cx);
  end
  else
  begin
    cy := cy - 1;
    Level.SetTile(cx, cy, 0);

    SetStackInteger(INT_CURX, cx);
    SetStackInteger(INT_CURY, cy);
    PlaySound(11, false);
  end;
end;

end.

One other hallmark of this project was completely gutting all the hard-coded logic and moving it into a game definition file. I build a pretty simple “game designer” tool which managed all the artwork, tile and sprite definitions, and also had custom logic implemented using that same Pascal interpreter I was using for the level scripts. I never used it for anything than the “Side Scroller” game, apart from a recreation of the File Platform game I also built way back when.

The game definition editor, showing the image tab.
How tile logic was configured. This was modelled after the triggers used in Red Alert's map editor.
How sprite logic was configured.
Game logic scripts, which was used to extend the built-in actions.

Again, nothing about this was remarkable, and for a long time I had no way to get this working. But thanks to Whisky I managed to launch this for the first time in ages and have a play. I don’t know when I’ll be able to do so again, nor whether it’s a good use of my time to try, so I recorded some screencasts of the gameplay which you can see here:

The desire to move away from cell-based movement and physics continued my drive in making platform based games in Delphi. I eventually managed to build such a game, which I will talk about once I can get it working again.