Up there with naming, caching, concurrency, and off by one errors, I think versioning and dependency management are two aspects of software development that is difficult.

Picking version numbers; ensuring that versions are correct; ensuring that artefacts are in sync across everyone in the team; designing a branching structure that is flexible enough to produce releases quickly, while sane enough to know which branch has what, and where new work should come from.

Coming from a place that offloaded a lot of this to build servers to one in which this is done manually is a bit of a shock to the system. It’s an excellent reminder on how much work and coordination it takes to get all of this correct.

29 March 2021

I’ve started working on a small Go tool to quickly add bookmarks to this site from the command line. This Blot.im site uses Git as the sync engine, so in order to publish the updates, the tool will need to add the changed files to Git, commit the changes, and push them to Blot.im. It does this by shelling out” to the Git command line using the exec package.

For some reason, whenever the tool tries to run git add with the updated files, the error code that is returned is 128. Since the error code is not zero, the tool interprets this as an error and terminates the program. As far as I can tell, the files are being added to the repository without any issues. When I run the command from the terminal, it seems to work correctly, and the returning error code is zero. I do know some shells actually add something to the error code when they succeed properly, which may explain this odd behaviour.

Interestingly, this doesn’t happen with the other tool that I’ve written to quickly write and publish posts for this site. This one shells out to Git in the same way, and I have had zero trouble with it doing so. The only reason for this discrepancy that I can think of is that this other tool is written in Swift, and there might be some difference in how Core Foundation interprets error codes.

I guess further investigation is warranted.

26 March 2021 Projects

Google Still Don’t Understand Services

It’s been a little while since I’ve though of Steve Yeggie’s platform rant on the the state of Google’s services. But spending a few hours exploring the capabilities of Google Sites, that classic blog-post has been front of mind once again.

Google Sites allows you to build and publish web-sites using a WYSIWYG designer, similar to Microsoft Front-page (anyone remember that?). These can be viewable by anyone on the public web, but when created within a Google Workplace, they could also be restricted to those that are within the workspace they are created in. This makes it a suitable choice for publishing internal sites that live within an organisation, which is what I want to use it for.

The current version of Google Sites is actually a redesign of an older version of Sites that has been around since 2008. This new version has a few niceties over the classic” version — which is still around — like a nicer designer and better looking templates.

What it doesn’t have is an API.

Without giving too much away, I was hoping to dynamically modify the contents of the site without building something as involved like a web-app. A simple bot, or something glued together with Google App Script, would be perfect. This is possible to do with classic Google sites, but this functionality has not been ported to the redesigned version. This new version has been around since 2016, and yet the only way that the contents of the site can be changed is through the WYSIWYG editor.
If I really wanted to make the content dynamic, I’d either have to use the classic version — which is probably no longer maintain, and could be shutdown whenever Google feels like it — or take up the work to build a completely bespoke web-app.

This is a shame. It’s clear that in this instance Google has not only failed to internalise the message of Yeggie’s rant, they have actually gone backwards. It might be that they are OK with this: after all, Sites is a consumer offering and may not be targeted to those with needs that demand this feature. But this line of thinking does a disservice to their offerings. It limits what is possible with these services, and reduced the number of paths available to those that want to do just that bit more.

22 March 2021 Rants

It looks like Intel has released a series of ads that have a go at Apple’s M1 chips. From Ars Technica:

Chipmaker Intel has produced a series of ads mocking Apple’s M1 Macs, and it brought on actor Justin Long—famous for his role in Apple’s 2000s I’m a Mac” ads opposite comedian John Hodgman—to satirize Apple’s own ad campaign.

It’s noteworthy that Intel has released ads that reference Apple’s I’m a Mac” campaign. This is the second throwback to this campaign that I can recall: the first were a series of ads from Microsoft released shortly after Windows 8 Windows Vista1. It shows how good that particular ad campaign was.

It’s also noteworthy, after watching half of one of the ads (sorry, I couldn’t really watch the whole thing), that the comparison between the two machine don’t relate to chip performance. Attributes like the number of monitors that can be driven are fair game, although remember these are still early days for the M1 chip. But the lack of gaming on MacOS, and touchscreens Macs? I don’t see how that relates to chip performance.

This whole thing smells of desperation on Intel’s part. I think what we’re witnessing here is a classic case of disruption of Intel’s PC chip incumbency, and instead of doing what’s necessary to pivot and compete with Apple head on — something that may require dramatic changes to how the company operates — Intel is going for quick wins to reach the mind of buyers. I’m not sure it will be enough to save it, though.

  1. Previously I stated Windows 8, but made correction thanks to this post on Daring Fireball.↩︎

18 March 2021 Opinions

Web Platform Wish List: Single Tab Pages

I wonder if there should be a web-standard of some form to indicate that certain pages should not be open in more than one tab. This would be particularly useful for certain web-apps that are large enough, or complex enough, that it’s better to avoid having multiple copies of them opened at the same time.

Here’s how I’d see this working:

  • Open a web page at a specific URL in the browser.
  • The server returns the page content with either a specific header, or a meta-tag of some sort, indicating that there should only be one tab of this specific page opened at any one time.
  • While that tab is opened, clicking a link to that URL from another page will bring you to that tab that was already opened. This will also work for links that are found outside the browser, like in emails or a chat.

A classic use case for this would be something like Google Calendar. I have Google Calendar opened in a browser tab, but I get meeting invites sent to me in another app. Clicking the invite link will bring up Google Calendar in a brand new tab, instead of simply highlighting the proposed meeting slot in tab that I already have opened.

The usual practice around miss-use can be applied here, like only applying to TLD+1 or the domains of the actual page that is requesting this feature. This should also be something that the user can override: there should be nothing stopping the user from disabling this feature or explicitly creating a new tab and copying and pasting the URL in order to open the new the page in a new tab.

This is probably something that will only be useful in a limited number of circumstances. Web-pages with content, like news and blogs, will be better of not using this feature.

Anyway, one more idea for the already huge web platform 🙂.

17 March 2021

Something that would be nice to see in GitHub and Bitbucket is the ability to prevent merging of a pull request if a comment containing a particular regular expression is found in the diff. For example, if I were to add a comment that begins with XXX or TEMP in the code, and submit that code as a pull request, I would be unable to merge that pull request until that comment is removed.

This would be useful for protecting accidental merges of temporary changes. Usually I make a note of such changes when I’m working on the code, and I may forget about them when it comes time to merging the pull request.

An example of such a change that I make often is temporary release versions of libraries. I may have made a change to a library that’s sitting in another pull request. Until that pull request has been merged, I cannot make a release version of that library, but I can make a temporary release so that a dependant change I’m working on can be built. That temporary release is listed as a dependency, but I don’t want to merge the pull request until the change to the library has been merged and a proper release has been made.

Surrounding the temporary release version with comments that begin with TEMP make that clear the reviewers, but preventing the pull request from being merged until I change the version and remove the comments would be a nice safety feature.

11 March 2021

Buffalo New” and Missing Templates

I was working on a Buffalo app over the weekend, and I made a mistake which manifested in an interesting way. The Buffalo framework is a lot like Ruby on Rails: it’s a rapid development tool for web applications backed by a database, but it uses Go instead of Ruby. A lot of this development speed comes from using generators, of which Buffalo has two different types: one for creating new applications, which is executed when running buffalo new, and one for adding stuff to an existing application, which is executed when running buffalo generate <thing>. The trouble is I can never quite remember which one is which.

I wanted to create a new resource, which is effectively a new model to store in the database along with some screens to modify it. However, I accidentally ran buffalo new resource, instead of buffalo generate resource. I saw that Buffalo was starting to generate a new project, completely within my existing project. I quickly pressed Ctrl+C, hoping to stop it before it began destroying work. Once it stopped, I took a brief look to see if any files were changed or removed. There was a new resource” directory, but thinking that this was where working files went, I didn’t think much of it. Thinking that I caught it in time, I continue working on the project.

Then I started seeing weird things happen, like Buffalo being unable to find JS or CSS files, or being unable to find templates to generate HTML pages. This only happened intermittently: after a few restarts, the application started working again. I knew that it somehow related to the mistake I made, but going through my Git history, I didn’t see any files deleted or modified, so I was unsure as to what the problem actually was.

I finished the feature I was working on, and deployed it to my server. It started up properly and I did some quick testing before finding a few things I wanted to fix. I made the fix and deployed it again. I tried to go to the home screen, and I saw a system error. I tried again: system error. From the logs I looked like the same problem I saw in development: missing JS, CSS and template files. I started doing the things I did in development, like restarting or redeploying the app. I even started doing things like upgrading the version of libraries. No good. I was constantly seeing system error.

This morning, I decided to take a good look through the Git commits to see what actually changed. It was only then that I realised that new resource” directory was not part of the original app, but was instead a completely new Buffalo app, complete with templates, JS and CSS files. It turns out that running buffalo new didn’t modify any of my existing files, but it did go through with creating a brand new app.

I’ve removed the resource” directory completely and redeployed the app. The system errors disappeared and I saw the app run again.

So if there is anyone else using Buffalo that is experiencing intermittent issues with the app being unable to find JS, CSS or templates, check to see if you’ve accidentally run buffalo new instead of buffalo generate.

10 March 2021

On Go Libraries Authors Coding to Interfaces

One convention of the Java programming world that I really like is the encouragement of writing code to interfaces instead of concrete types. When deciding on a type for a new variable or field, you’re advised against choosing concrete types like ArrayList or HashMap, unless you have a specific need for them. Instead, you’re encouraged to use interface types, like List or Map, so if it’s necessary to change the specific implementation, you can do so without changing the type of that field or variable. This is especially useful when dealing with libraries, where you may not have full control over the source code.

It would be nice if this convention showed up a bit more often in Go, particularly in libraries. There have been two instances in the last week when I wished the developer of a third-party library used an interface instead of a concrete type. My needs deviated a bit from the concrete type they were using, and if the library author used an interface instead, I could have coded up a type that wrapped the concrete type with some custom logic that satisfied my use case.

Instead, I either need to look for another library, or consider submitting a pull request which changes that concrete type to an interface.

9 March 2021 Opinions

The Price of Bragging Rights

So it looks like Jack Dorsey is selling his first Tweet using NFT (via Platformer). Purchasing this NFT will get you digital certification of ownership” of the tweet, signed and verified by the creator. Last time I checked the article, the highest offer for this is $US 2.5 million.

I hope those bidding on this realised what they are actually paying for. So you’ve got a digital certificate verifying the ownership” of the tweet. So what? What can you actually do with it? Can you delete it? Modify it? Move it to your Twitter account? Move it off Twitter entirely?

My guess is that the tweet will remain on Twitter under Dorcey’s account. The fame of this tweet comes from who said it, and when. And unless Twitter is adding features that allows another person to modify this tweet without changing these two properties, I’m at a loss as to how this ownership can be exercised. The tweet will still be owned by Dorcey, as it exists in his account, on his service, as bytes stored on his database.

All the buyer gets in exchange for millions of dollars is the verifiable right to say I own a certificate saying that I own the Tweet.” It’s effectively paying for bragging rights. I’ll admit, I’m not one that fully understands the high-end luxury market, but this right doesn’t seem like it’s worth $2.5 million.

This whole activity is obscene, and looks like nothing more than a cash grab. There may, may, be a legitimate use case for NFTs in some circumstances — something that I’m skeptical of, and I’m not the only one — but this is not it. Let’s not forget, these things are not free to produce. It takes a significant amount of energy, and associated carbon dioxide emissions, to generate these tokens. Is this really the best use for them?

9 March 2021 Rants

Google, Stadia and the Petro State Curse

Google announced changes to Google Pay a few days ago. This is yet another service that Google is pivoting, with seemingly no awareness or care of how it will affect their users. The one before it, announced a month ago, was Google Stadia.

When Google first announce Stadia, there was some hesitancy on whether users or developers will actually sign up to it. Google has developed a bit of a reputation, particularly in the consumer space, of releasing a service only to shut it down a year or two later. Evidence of this is the myriad of other services that were shutdown by Google when they lost interested in them.

So naturally people were wondering whether this service will be different. Nothing to fear,” Google said. We’re committed to keeping this one alive, just like Gmail, Docs, Music, Movies and Photos1. So sign up, spend money, and don’t be afraid to commit to the service.”

Well, you could imagine what happened next.

I’ve often wondered why Google acts this way. Surely they must recognised that this is damaging to their brand. David Heinemeier Hansson, or DHH, one of the co-founders of Basecamp, has given a pretty compelling reason why this might be: that Google’s success as an advertising company is similar to that of a petrochemical state, with the associated lack of need to invest in anything else:

Why bother investing in other industries when you can make so much money from shit that’s literally spouting out the ground? You have to be extraordinarily disciplined and well-functioning prior to finding such riches, if you are to stand any chance. Google has never been either.

(I recommend that you read the entire post).

This makes total sense to me. The cash from search and advertising is so large that there is simply no need to seriously pursue other ventures. Sure there’s the human element, on wanting to be more than just a middle manager in a petro state”, but that’s not necessary for the success of the business. So why spend the money or effort on working on something that will in the end be just a distraction?

Certainly something to think about next time Google releases a service.

  1. It should be noted that Google Music was actually shutdown as well.↩︎

9 March 2021 Opinions

Random Thought Update: Showing New Windows

I’ve had a bit of trouble getting new windows in Random Thought to call methods on the window delegate when they were instantiated from the storyboard programatically. The particular scenario that I was having trouble with was implementing the New” menu item. Basically I wanted clicking the menu item to create a new post window. Each post window was to have a delegate that will notify the application when it’s closes, so that I can enable or disable other menu items based on whether a post window is active.

The way I was doing this was to have the New” menu item hooked up to the following method on the AppDelegate:

class AppDelegate: NSObject, NSApplicationDelegate {

    // ...

    @IBAction func newFileClicked(_ sender: Any) {
        let storyboard = NSStoryboard(name:"Main", bundle: nil)
        let mainWindow = storyboard
                .instantiateController(withIdentifier:"mainWindowController") as! PostWindowController
        NSApplication.shared.activate(ignoringOtherApps: true)

The PostWindowController was the following:

class PostWindowController: NSWindowController, NSWindowDelegate {
    override func windowDidLoad() {
        self.window?.delegate = self
        self.shouldCascadeWindows = true
    func windowWillClose(_ notification: Notification) {
        (NSApplication.shared.delegate as! AppDelegate).notifyOfClosedPostWindow()

The windowWillClose delegate method was being properly called for the post window first shown on launch, but not for posts window instantiated within the newFileClicked action. I have no idea why this is the case. The windowDidLoad method was being called, and as far as I could see, the delegate was being set properly, but it just will not call the delegate methods.

I’ve fixed” the problem by moving away from instantiating the main window from code, and replacing it with segues between the New” menu item and post window. This seemed to have fixed the problem: the delegate methods are being called properly now. I’m guessing that something in how segues work must be involved. Obviously there’s some gap here, either in how showing windows work, or in my knowledge of how it should work. Being relatively new to this, I’m happy to assume the latter.

6 March 2021 Projects

I like, and fully endorse, the idea from Dave Winer about all apps, both desktop and web, being fully scriptable. I know that it’s something that I keep back of mind whenever I evaluate an app. Questions like if I needed to automate this, how would I do it?” Or if there was some sort of feature missing, could I build it myself?” In fact, I like this idea so much that many of my personal apps — stuff that I just build for myself — include scriptable components, even if I’m the one using them.

6 March 2021 Opinions