Code First, Tests After

Still doing the code first, tests after at work and I’m really starting to see the benefits from it. Test driven development is fine, but most of our recent issues β€” excess logging or errors that are false positives β€” have nothing to do with buggy business logic. It’s true that you can catch these in unit tests (although I find them to be the worst possible tests to write) but I think you gain a lot more just from launching the application and seeing it run.

Now granted, it’s not always possible to do this with micro-services. There’s always some dependency you need, and setting all these up is a bit of a pain. That’s probably why I deferred all my manual testing to the end, when I’ve pushed my changes to get them reviewed and deployed it to the environment. Do a quick cursory test from the frontend just to make sure it hasn’t broken anything, then move on to the next task.

I think this way of working was a mistake. This is something frontend developments get right: you need to run your software while you’re working on it. It’s so important to see not just how well it works, but how it feels to work1: what goes to the log, how fast it performs, etc. You don’t get this feeling from just depending on unit tests.

Plus, there’s always a nice buzz to see the thing you’re working on run for the first time. That magic seems to decay the further you are from where it’s running. It just becomes another cog in the system. And maybe that’s what it’s destined to be, but it doesn’t need to be this way while you’re working on it.


  1. I don’t know of a better way to say this other than “how it feels to work”. I suppose I could use boring words like “tight iteration loop” but there are too many boring words on the blog already. ↩︎

A Lisp-based Evans Wrapper

I wanted an excuse to try out this Lisp-like embedded language Go library that was featured in Golang Weekly. Found one today when I was using Evans to test a gRPC endpoint and I wanted a way to automate it. Hacked up something in 30 minutes which takes a method name and a Lisp structure, converts it to JSON and uses Evans to send it as a gRPC message.

As the afternoon progressed, I added some facilities to send HTTP GET and POST methods with JSON request bodies, plus some facilities to set some global options.

Here’s a sample script:

// Set some global options
(set_opt %grpc_host "www.example.com")
(set_opt %grpc_port "8080")

// Make a gRPC call. This will use evans to perform the call
(call "my.fancy.Grpc.Method" (hash
    example: "body"
    message: "This will be serialised to JSON and sent as the body"))

Another script showing the HTTP methods

// The HTTP methods don't print out the response body by default,
// so add a post-request hook to pretty print out the JSON.
(defn hooks_after_response [resp]
    (print_json resp))

// Make a HTTP GET request to a JSON endpoint.
// The JSON body will be converted to a hash so that the data can be useful
(def user (rget "https://example.com/user/someone"))
(def userName (hget user %name))

// Make a HTTP POST with a JSON body.
(hpost "https://example.com/user/someone" (hash
    new_name: "another"))

It’s a total hack job but already it shows some promise. Evan’s REPL is nice but doesn’t make it easy to retest the same endpoint with the same data multiple times (there’s a lot of copying and pasting involved). For those purposes this is a little more satisfying to use.

Now that I had a chance to try Zygomys out, there are a few things I wish it did.

First, I wish it leaned more into the Lisp aspect of the language. The library supports infix notation for a few things, which I guess makes it easier for those who don’t particularly like Lisp, but I think it compromises some of the Lisp aspect of the languages.

For example, lists can be created using square brackets, but there’s no literal syntax for hashes. Not that there are any in Lisp either, but derivatives Clojure uses square brackets for arrays and curly brackets for hashes. Curly brackets are reserved for inline code blocks in Zygomys, so there’s no way to use them in a more functional context. I suppose something could be added β€” maybe square brackets with a prefix, #["key" "value"] β€” but feels like a missed opportunity.

Another is that there’s no way to use dashes in identifiers. This may have just been an oversight, but I’m wondering if the infix notation support complicates things here as well. It would be nice to use them instead of the underscore. I don’t personally like the underscore. I know it’s just a matter of pressing shift, but when writing identifiers in lowercase anyway, using the dash feels a lot more natural.

Finally, on the Go API front, it would be nice to have a way to call functions defined in Zygomys in Go, much like those hook functions in the sample above. I think this is just a matter of documentation or adding a method to the API to do this. I see no reason why the engine itself can’t support this. So I’m happy for this to come down the line.

But in general this library shows promise, and it was fun to build this tool that uses it. Of course, we’ll see if I use this tool a second time when I need to test a gRPC endpoint, and I don’t just hack up yet another one that does essentially the same thing.

πŸ”— Poor man’s team bonding: recurring Slack threads

Could be a nice idea for blogs as well. Maybe for someone who’s trying to post at least once a day, but occasionally can’t think of something to write about. Not that I know anyone like that.

I can’t say enough good things about using Dokku for deploying and running web-apps on a Linux VPS. Compared to the competition, it’s so refreshing to use. Makes deployments the easiest part of the exercise, as it should be.

A load of foraging lorikeets.

A group of fourteen rainbow lorikeets foraging amongst a few bushes.

πŸ”— Who killed Google Reader?

Interesting piece from the Verge about the rise and fall of Google Reader, which was killed 10 years ago. I wasn’t a big Google Reader user, and I still believe that the death of Google Reader was ultimately good for the RSS format. But I know how much people loved using it and how devastated they where when Google decided to pull the plug.

One thing that caught my eye was the executive’s comment about working on Google Reader being a waste of the engineers’ careers. Taking the comment at face value1, it doesn’t seem like a waste at all. Sure there were “only” 30 million users of Google Reader, but it’s obvious that they were passionate users of the service. And it would’ve been an honour working on something that elicit such a strong emotional response from your users, let alone being the one that started it all with the original prototype. I can’t imaging getting that same buzz by one of the thousands working on Google Search or Google+.


  1. I’m guessing the comment was slightly coloured by the fact that the person making it wasn’t too keen on Google Reader. ↩︎

Finished reading: Turning Pro by Steven Pressfield πŸ“š

I think this is one of those books you need to read a few times to internalise it, and this was my first pass. I’m also wondering to what degree this book applies to my ambitions: whether or not I really want to β€œturn pro”. Guess we’ll find out.

Just set up a reading goal in Micro.blog for 2023. I kinda like how a book only counts to your goal when you write a blog post about it. A good way to keep track of what you’ve read in public.

Anyway, let’s see if I can reach the ambitious goal of finishing 5 books this year. πŸ™„

Finished reading: The Song of Significance by Seth Godin πŸ“š

An enjoyable book to read, as I expected from Seth. Will need to look out for opportunities to apply these points in practice.

TIL you can enter a photo description in Google Photos. Select a photo, click the Info icon, and a free-text “description” field is revealed. Not super sure what the description is to be used for, but I’m hoping to use it for photo captions.

Screenshot of Google Photos in Safari with the info plane reveal and a sample description entered just above the photo metadata. The sample description reads: This is a description. I guess it can be used as a caption if you want it to.

caffeinate.me

A bit of nonsense I made while fighting off jet-lag. Built using mmm.page.

Tip for anyone traveling to Australia via Dubai: do not buy a bottle of water to drink on the plane. Drink it before you board, otherwise it will get confiscated at the gate.

And yeah, this just happened to me. And yeah, I’m kinda annoyed by this. πŸ™

Last day in Switzerland, and indeed Europe. Did little aside from seeing a bit of ZΓΌrich. I enjoyed my visit, but it’s good to be heading back home.

Nerding out at the Swiss Transport Museum, in Luzern. Super interesting! Can definitely recommend.

A collection of stem locomotives in an exhibition centre. Tail of a Swiss Air aeroplane Cross-section of the Gotthard Base Tunnel outside exhibit.

Mark one more off the bucket list: travelling through the Gotthard Base Tunnel.

A picture of a monitor inside a train carriage with some logos below it. The monitor has the following message: World Record! We are now travelling through the Gotthard Base Tunnel, which will take around 20 minutes. At 57 kilometres, this is the world's longest railway tunnel.

Hired a car and spent my last full day in Italy exploring a bit of the wider Veneto region. Visited the town my grandparents grew up in and also went on a small bush-walk up at Cansiglio Forest. The landscape was absolutely breathtaking. The photos I took do it no justice (and I took a lot of them).

An alpine forest track, with a paddock with a small building on the left side, and a pine forrest on the right and middle distance. In the background are some mountains, with bare peaks that have a little bit of snow.

I know Venice is known for its canals, and they’re certainly something to behold, but this single rail tram-line blew me away.

A red tram approaching tram-stop with the track consisting of a single rail.

Edit: it occurred to me that these β€œtrams” are running on regular tiers, and use this rail for the return current. That means they can get away with using just one overhead wire instead of two. I guess they can also use the rail for guiding the vehicle around curves as well? Seems like a bit of a disadvantage over other trolly-bus systems with trolly polls that can move around traffic.

Venice in the morning.

The grand canal of Venice with two boats and a Bastille in the background, with a slightly cloudy sky.

Vincent’s post about Tinylytics recognising www sub-domains is a welcome one. I’ve had a domain setup for a week in Tinylytics that was recording zero hits. I thought it was because I placed the script tag in the header. But, no: I naturally forgot the β€œwww” when registering the URL. 🀦

Dealing with the coin laundry driers suck. You buy more time by putting more money in, but the laundry points don’t make it clear that you’ve already paid for time and all you need to do is press start on the machine. I paid for drier time I didn’t want twice on this trip.