Best Laid Plans

Dead, Beat, Dad - Part 6

A new routine

We’re getting the hang of it. At least for the moment. Something new comes every day, but we’re rolling with it.

I’m back at work. Working from home has advantages. I help with feedings and changings and soothings, but Janice is taking on the larger share. I take Baby H as often as I can during the day. Fortunately, she sleeps in the front carrier.

Nights are difficult, but getting easier. We’re looking forward to her sleeping longer hours so we can cut back on the nighttime feedings. Getting her back down after a feeding lands squarely in my camp, and it’s hit or miss as to whether she goes down easily. Easy nights are appreciated with smaller bags under the eyes and fewer cups of coffee.

We’re appreciative of our support system and kind words from friends and family. It really does take a village.

Learnings on HTMX

I set some lofty goals for myself, given the situation. All in all, I’m please with the results. I built a toy application to track the same information as our paper log, and I learned a few things I’ll take with me.

Error Handling

For the most part, application errors are handled by returning the appropriate error messages or application states. In HTMX land, that means returning 200 OK status codes with the appropriate HTML response. It also means that errors need to be handled, and essentially “eaten” and replaced with contextual errors or at the very least a generic error dialog.

To make error handling easier, I split up the HTTP transport logic and business logic. api.go handles the HTTP request and response, parsing the inputs and writing the resulting HTML response. The parsed inputs are passed into methods in service.go, which make the DB and external requests needed to populate the templ HTML templates.

This separation simplifies error handling. Actionable errors are handled in the service, which has the information needed to contextualize error messages. If an error can’t be handled, the service method returns it to the transport, which displays a generic error.

Form Inputs

HTTP forms leave something to be desired. All the input values are string encoded, so the server has to do a fair amount of parsing, converting the strings to integers, or whatever format is desired.

Ideally, I could parse inputs directly into structs, with the fields automatically cast to the appropriate types. Why spend time writing parsing logic when I could work on application logic?

I tried using the json-enc HTMX extension, but it preserves the string-encodedness. I appreciated that it produced a more structured input than naked form values, but it doesn’t hit the mark either.

gorilla/schema gets closer. It parses typed values into structs, so you don’t have to worry about type conversions. It’s a great first step, but it doesn’t handle dynamic data well. You need to know the field names you’re parsing ahead of time, so you can define a struct with the appropriate struct tags. This covers most use cases, but there are situations where dynamic forms are useful.

It would be ideal to be able to gracefully handle forms with runtime-defined values. I’ll think more about it. There might be an opportunity for a library.

Timestamps

I should have seen this coming, but I didn’t. I needed to show timestamps on several pages. The trouble with timestamps on a server-side rendered application is that the server doesn’t know the user’s time zone.

As a safe rule of thumb, timestamps are usually stored in UTC time, which corresponds to Greenwich in the UK. For me, we’re at the -7 (or -8) offset. But the application server doesn’t know that.

There are a few options for timestamps:

  1. Ask the user what time zone they’d like to display timestamps in. Store their answer. Format timestamps appropriately when rendering. Pro: You’ll have the right timestamp. Con: The user has to take action, give potentially sensitive information, and remember to update their local offset if they move to another time zone.
  2. Use location services. Pro: Same as #1. Con: How many people actually accept when websites ask to use their timezone?
  3. Send the browser’s default timezone in HTMX requests using hx-headers. Pro: Same as #1, without being invasive like #2. Con: The initial load on the website won’t send the timestamp, as the HTMX headers are only sent on HTMX requests.

I went with option 3, but it needs a double request on initial load. It isn’t ideal, and there’s something funny about formatting timestamps based on the timezone provided in the request. After talking with Mike about the issue, I’m going to try doing all the formatting client side. It’ll require javascript, but so does HTMX, so there isn’t much to lose.