Some Photos of The Yarra Trail

Went for a very short walk of the Yarra Trail around Heidelberg on Saturday. The evening light was really lovely so I though I’d take some photos.

Milestone

For a while, I’ve been trying to maintain a writing streak. I need to write at least one blog post or journal entry a day. Today that streak has been maintained for a full year.

I will admit that the streak was not completely continuous: I had to go back a few times and retroactively add a post. But even so, I’m quite please with reaching this milestone. Onward to the next one.

It could be that I’m just an old fogie that doesn’t like whimsy, but chalk me up as someone who doesn’t like the wiggling seek bar in Android’s playback notification.

Currently reading: On Writing Well, 30th Anniversary Edition by William Zinsser ๐Ÿ“š

Only a few chapters in, but so far a great read.

Via Rec Diffs #188

I make something and not share it with anyone, I become frustrated.

I make something, share it with others, and they donโ€™t use it, I become disappointed.

I make something, share it with others, and they do use it, I become terrified.

Thereโ€™s no middle ground here, is there?

Knocked off some merge requests from my inbox and about to start work on a nicely sized development task. Looking to be a good Friday for coding. ๐Ÿง‘โ€๐Ÿ’ป

I’ve been using Dynamo-Browse all morning and I think I’ll make some notes about how the experience went. In short: the command line needs some quality of life improvements. Changing the values of two attributes on two different items, while putting them to the DynamoDB table each time, currently results in too many keystrokes, especially given that I was simply going back and forth between two different values for these attributes.

So, in no particular order, here is what I think needs to be improved with the Dynamo-Browse command line:

  • It needs command line completion. Typing out a full attribute name is so annoying, especially considering that you need to be a little careful you got the attribute name right, lest you actually add a new one.
  • It needs command line history. Pressing up a few times is so much better than typing out the full command again and again. Such a history could be something that lives in the workspace, preserving it across restarts.
  • The set-attr and del-attr commands need a switch to take the value directly, rather than by prompting the user to supply it after entering the command (it can still do that, but have an option to take it as a switch as well). I think having a -set switch after the attribute names would suffice.

Finally, I think it might be time to consider adding more language features to the command line. At the moment the commands are just made up of tokens, coming from a split on whitespace characters (while supporting quotes). But I think it may be necessary to convert this into a proper language grammar, and add some basic control structures to it, such as entering multiple commands in a single line. It doesn’t need to be a super sophisticated language: something similar to the like TCL or shell would be enough at first.

It might be that writing a script would have solved this problem, and it would (to a degree at least). But not everything needs to be a script. I tried writing a script this morning to do the thing I was working on and it felt just so overkill, especially considering how short-lived this script would actually be. Having something that you can whip up in a few minutes can be a great help. It would have probably taken me 15-30 minutes to write the script (plus the whole item update thing hasn’t been fully implemented yet).

Anyway, we’ll see which of the above improvements I’ll get to soon. I’m kinda thinking of putting this project on hold for a little while, so I could work on something different. But if this becomes too annoying, I may get to one or two of these.

Found a service this morning which was sending HTTP requests with a timeout of 1 second. This was causing problems in the service it was calling, which was unable to satisfy the request in that time. Who sets the HTTP request timeout to 1 second? Seems pretty low to me.

You can tell I’m bored at work when I spend time building stupid little utilities for myself instead of actually doing the task I should be doing. Today’s stupid little utility: a TUI tool to list merge requests I’ve posted for review. Saves a trip to the browser.

Thinking About Scripting In Dynamo-Browse

I’ve been using the scripting facilities of dynamo-browse for a little while now. So far they’ve been working reasonably well, but I think there’s room for improvement, especially in how scripts are structured.

At the moment, scripts look a bit like this:

const db = require("audax:dynamo-browse");
const exec = require("audax:x/exec");

db.session.registerCommand("cust", () => {
    db.ui.prompt("Enter UserID: ").then((userId) => {
        return exec.system("/Users/lmika/projects/accounts/lookup-customer-id.sh", userId);
    }).then((customerId) => {
        let userId = output.replace(/\s/g, "");        
        return db.session.query(`pk="CUSTOMER#${customerId}"`, {
            table: `account-service-dev`
        });
    }).then((custResultSet) => {
        if (custResultSet.rows.length == 0) {
            db.ui.print("No such user found");
            return;            
        }
        db.session.resultSet = custResultSet;
    });
});

This example script โ€” modified from one that I’m actually using โ€” will create a new cust command which will prompt the user for a user ID, run a shell script to return an associated customer ID for that user ID, run a query for that customer ID in the “account-service-dev”, and if there are any results, set that as the displayed result set.

This is all working fine, but there are a few things that I’m a little unhappy about. For example, I don’t really like the idea of scripts creating new commands off the session willy-nilly. Commands feel like they should be associated with the script that are implementing them, and this is sort of done internally but I’d like it to be explicit to the script writer as well.

At the same time, I’m not too keen of requiring the script writer to do things like define a manifest. That would dissuade “casual” script writers from writing scripts to perform one-off tasks.

So, I’m thinking of adding an plugin global object, which provides the hooks that the script writer can use to extend dynamo-browse. This will kinda be like the window global object in browser-based JavaScript environments.

Another thing that I’d like to do is split out the various services of dynamo-browse into separate pseudo packages. In the script above, calling require("audax:dynamo-browse") will return a single dynamo-browse proxy object, which provides access to the various services like running queries or displaying things to the user. This results in a lot of db.session.this or db.ui.that, which is a little unwieldily. Separating these into different packages will allow the script writer to associate them to different package aliases at the top-level.

With these changes, the script above will look a little like this:

const session = require("audax:dynamo-browse/session");
const ui = require("audax:dynamo-browse/ui");
const exec = require("audax:x/exec");

plugin.registerCommand("cust", () => {
    ui.prompt("Enter UserID: ").then((userId) => {
        return exec.system("/Users/lmika/projects/accounts/lookup-customer-id.sh", userId);
    }).then((customerId) => {
        let userId = output.replace(/\s/g, "");        
        return session.query(`pk="CUSTOMER#${customerId}"`, {
            table: `account-service-dev`
        });
    }).then((custResultSet) => {
        if (custResultSet.rows.length == 0) {
            ui.print("No such user found");
            return;            
        }
        session.resultSet = custResultSet;
    });
});

Is this better? Worse? I’ll give it a try and see how this goes.

Some Things I Found Out While Browsing a Substack Newsletter in The Wayback Machine

I did a quick search for that blog post in the the Wayback Machine. I couldn’t find the post but the Substack newsletter was there. I guess Substack does allows archiving of newsletters with the “substack.com” domain after all (if it’s something that they can even control).

Anyway, here are a few things I’ve found out while browsing through a Substack newsletter in the Wayback Machine:

  • Clicking “Let me read it first” works: it slides away and the most recent posts show up. Guess it’s just a simple HTML overlay blocking the home page.
  • Open all links in a new tab. Just clicking them will run some JavaScript which, I guess, tries to load the post directly from Substack, resulting in an error if the newsletter is taken offline. Opening the link in a new tab will get the post directly from the Wayback Machine.
  • Clicking the archive tab seems to bring up the blog archive briefly, but then some JavaScript โ€” which I guess is trying to load the archive from Substack? โ€” replaces it with an error (why does everything need to be JavaScript?!) I’m guessing that the actual HTML is still there so it might be possible to get it if you disable JavaScript. I haven’t tried this though, so this is only a hypothesis.

As for the post itself, it turns out that it was in my Feedbin archive all along, so the search in Wayback Machine wasn’t actually necessary. Now the trick is to find a way to prevent Feedbin from purging old posts. ๐Ÿ˜ณ

Over the weekend, I wanted to revisit a Substack post I read several months ago. Unfortunately, the newsletter was shutdown and the post is no longer available. With a bit of luck it will be available in the Wayback Machine. I’m hoping that works for Substack domain.

Can’t believe it took me this long to get a headset. Knowing that a mic is only a couple of centimetres from my lips makes a huge difference in how I speak. Saved me from killing my voice today after 4.5 hours of online meetings.

Follow-up on my phone issue. I think the problem relates to 5G connections. The drop-outs seem to have stopped after I’ve switched 5G off. Still not sure if the problem is the phone or the SIM, but I’m not sure if I’ll pursue it further. 4G seems to be fast enough for now.

Rebinding Keys For Quickly Resolving Conflicts in GoLand

I’m dealing with a lot of conflicts today as I try to clear a backlog of Git rebases in my to-do pile. I’ve been using GoLand to do this, as my current Git “mergetool” is configured to Vimdiff for some reason1 and I’m not really bothered to find some other tool, at least not yet. GoLand does a pretty good job.

Unfortunately, the default key-bindings for resolving conflicts in GoLand is far from good. About the quarter of actions are bound to keys that make sense. Half the actions, like ignoring hunks, are not bound to anything, while the last quarter are bound to keys that result in a suboptimal experience. For example, the key to accept changes for a delta use the arrow keys, whereas the key to go to the next delta is F7. What a strange default. I’d have to constantly move my hand off the arrow keys over to the Fn row if I want to go through and fix each delta. This, plus moving over to the mouse to select an action not bound to a key, makes resolving conflicts really slow.

Fortunately GoLand allows remapping keys to pretty much anything, so I’d figured it’s time to fix this problem. I set about coming up with a nicer key-mapping scheme for resolving conflicts. I wanted to come up with one that adhered to these principals as best it can:

  1. My hands must not move from where they rest on the keyboard for almost the entire time a file is being worked upon. The only exception are actions that are invoked less frequently and have a large radius of change โ€” such as the accepting all changes from the left or the right. I’d figured it’s still okay to use the mouse for those.
  2. The arrow keys should be used for navigation (go here) and for addressing (this one).
  3. The modifier keys should be used for choosing the operation, such as going to the next delta, or choosing or ignoring a change.

Here’s the key-map I’ve come up with. The actions marked with an asterisk were the one’s that I needed to change. All these actions are within the “Version Control Systems > Diff & Merge” group within the “Keymap” section in preferences.

Action Key Binding
Previous Difference * ^โŒ˜โ†‘
Next Difference * ^โŒ˜โ†“
Previous Conflict * ^โŒฅโŒ˜โ†“
Next Conflict * ^โŒฅโŒ˜โ†“
Accept Left Side ^โŒ˜โ†’
Accept Right Side ^โŒ˜โ†
Ignore Left Side * โ‡งโŒ˜โ†
Ignore Right Side * โ‡งโŒ˜โ†’
Confirm Merge โŒ˜Enter

I’ve only tried this out as part of a single rebasing session, but already it feels so much faster. It’s taken me probably half the time to go through each file now, maybe even better. I also like the fact that most of the time I only need to hold down Ctrl and Cmd key, and use the arrows to move to and accept changes. Ignoring a change involves moving my left pinky to the Shift key, adding a bit of resistance to indicate an action that requires just that little bit more care.

We’ll see how this goes as I deal with future conflicts, and I may make a change or to. But this is looking really promising.

One last note: this was done in GoLand but I’d imagine it’s possible to set this key-mapping up in most, if not all, of JetBrain’s other IDEs.


  1. It was previously something else, and I have no idea how it got changed. ↩︎

Those “Accept Yours” & “Accept Theirs” buttons in GoLand’s conflicts dialog are a bit of a tease. Might be that I’m missing something (which is possible) but I though a file appearing here means that I manually need to review it. Would anyone blindly accept changes like this?

Accept Yours, Accept Theirs & Merge buttons in Conflict resolution dialog

Oof, spent all morning updating and rebasing out-of-date pull requests. Only got through half of them so far. This project is pretty fast pace at the moment, so conflicts are expected. But many of these are PRs I been neglecting until now, so it’s still mostly my own doing. ๐Ÿ˜ฎโ€๐Ÿ’จ

Here’s today’s instalment of Why Didn’t I Think of This Soonerโ„ข.

I’ve got into the habit of squashing commits before I push them as part of a pull request. In order to run the command I use to do this โ€” git rebase -i HEAD~n โ€” I need to know the number of commits I want to squash (this will be the value of n).

Fortunately, I’ve got into the habit of prefixing each commit message with the Jira task number. For example, I may write a commit message with the first line being ABC-123: fixed a bug in the thing, followed by a more detailed list of changes. I do for every commit, even for those “checkpoint commits” I make before changing branches.

So all I need to do to get the number of commits I need to squash is to simply count up all the commits that start with the Jira task number. For all this time, the way I do this is to run git log to open up the history in Vim, and manually count the number of commit messages that began with the particular Jira task number.

Today, I remembered that I could use a shell pipeline to do the same thing:

git log | grep ABC-123 | wc -l

which would save me stack-loads of time and potential mistakes.

Wish I thought of this sooner. ๐Ÿคฆ

I’m moving the posts I had on my wiki to this blog and I’m shutting the wiki down.

I never really used the wiki a lot โ€” in fact, the last two posts were the only pages that were on there (the rest were all links). This was partly because I never got around to setting up backups (this was a pretty big reason why I didn’t put anything I wanted to keep there), but also because I found other places to document things. Anything related to software development I found myself just posting it here. Things that related to projects that I wanted to keep private, I wrote in Day One. So nothing really went into the wiki at all.

I did use the wiki a lot to keep bookmarks to guides and resources I occasionally need to lookup. I think, going forward, I’ll just keep these links as a page on this site. I’m in Micro.blog almost every day so I imagine the amount of extra effort needed to keep this page up-to-date will be low. One less site to visit and maintain. ๐Ÿ™‚

๐Ÿ”— A delightful reference for HTML Symbols, Entities and ASCII Character Codes

A great reference site I stumbled along when I was trying to find the perfect arrow to include in a webpage. Nice, clean, and quite comprehensive. No awful ads either, which is a breath of fresh air.