Visting with My Cousin Murry

July 8th, 2023

Path

Today I traveled to Indy to have a nice get-together with my siblings and our cousin Murry, on our Dad's side of the family. He's my age, and has spent almost all his adult life in Finance - running a Hedge Fund for a while before he rolled it up in 2022. He's now in Miami and doing a lot of traveling, and this stop in Indy was part of his "Touch Base with Family 2023" Tour.

A few months ago, I reached out to Murry and added him to my Sunday Messages list, where I send a little message about the family and how we're doing, and it's nothing special, but it keeps us in touch. I've been doing this with family and friends for a few years, and it's something I really feel is important.

Well... Murry is doing fine, and everyone had a good time. I really think this is good - the reconnections. Someday soon, there will be fewer of us...

Nice Postgresql Trick

June 29th, 2023

PostgreSQL.jpg

This morning I really wanted to be able to set the psql prompt in my sessions because the system we have for creating databases doesn't really create nicely human-readable name, and even so, I'd like to have the name in the prompt match the branch of the code I'm working on... it just works out better.

So I started digging, and the -c parameter is OK, but the psql session terminates after that - so that's not going to work. And piping in the \set commands seemed to be problematic, and then I found this:

  $ psql --set=PROMPT1="${br}%R%#%x "

where br is the name of the branch I'm working on. This could then be obtained from git easily, and then put into a function, and it works great!

  #
  # "platter psql (postgres command line tool)" - start a psql session on
  # the provided branch in the PLATTER_INSTANCE in the .env file in the
  # current directory (a Node project repo). If no branch is provided, then
  # the current git branch will be used.
  #
  function ppsql() {
    if [ -f .env ]; then
      set -o allexport; source .env; set +o allexport
      local br=$1
      if [ ${#br} -eq 0 ]; then
        br=`cat .git/HEAD | sed -e 's:^.*/::'`
      fi
      local url="`npx platter postgres branch url ${br} \
           --instance $PLATTER_INSTANCE | tr -d '\n'`?sslmode=require"
      psql --set=PROMPT1="${br}%R%#%x " --set=PROMPT2="${br}%R%#%x " $url
    else
      echo "Not in a Node project directory!"
    fi
  }

With this, it's so easy now to be able to keep track of the database (branch) I'm on with Platter, and that makes a really big different to my peace of mind. 🙂

Ivory for Mastodon for macOS

May 23rd, 2023

Ivory

I just downloaded the Ivory for macOS app from the App Store, and upgraded my subscription to the Universal Subscription, so that it would cover all my devices. It's just an amazing app. This iOS/iPadOS version has been working really well for me since it was released, and now that I have the macOS version, I'll not have to worry about Ice Cubes and reading two streams.

I don't know that Mastodon will ever be popular enough to have some of the feeds from Twitter on it, but that's OK... I'm at about 95% complete, and I don't really need the last 5%. Plus, you just can't beat that it's not under the thumb of a capricious individual.

All in all... a nice bit of news for today. 🙂

Interesting Issues with Clearbit

April 24th, 2023

Alarm icon

This weekend we had an interesting issue with Clearbit's Logo Search interface - a free service they provide on their Business Information Service system. You can basically hit their endpoint with a query param of the name of a Company, and they will respond with something that looks like:

  {
    name: 'Flexbase',
    domain: 'flexbase.app',
    logo: 'https://logo.clearbit.com/flexbase.app'
  }

which is a nice little thumbnail logos of the Company. It's a very nice tool, and for the most part works flawlessly.

Until it doesn't.

The real issue was the Open Source Node client that was hitting the company's endpoint. It started with:

  topSuggestion(name){
    return new Promise((resolve, reject) => {
      resolve(getTopSuggestion(name));
    });
  }

which called:

  let getTopSuggestion = (query) => {
    return new Promise((resolve, reject) => {
      request(config.api.autocomplete + '?query=' + query, (err, response, body) => {
        resolve(JSON.parse(body)[0]);
      });
    });
  }

Now when everything is working as it should, this code is just fine. But on the weekend, the response from the endpoint in getTopSuggestion() was returning:

  Welcome to the Company API. For docs see https://clearbit.com/docs#company-api

which, of course, isn't JSON, and so the JSON.parse() was throwing an exception. But the function getTopSuggestion() was using the resolve() for the Promise, so it was creating an exception that could not be caught. This was bad news.

Now as it turned out, a coworker found that Clearbit was doing some maintenance, and that might have been the genesis of the issue, but it was made much worse because when we debugged this on our machines - several of us, the issue didn't present itself. Only in production.

Still, it was clear this wasn't the right code to use, and the library was 6 years old without an update, and the code was small. So a coworker suggested we just make the one call ourselves:

    let res = {}
    try {
      // Get the top URL Suggestion for a store name
      const url = new URL(config.api.autocomplete)
      url.searchParams.append('query', name)
      // ...now make the call, and parse the JSON payload
      const payload = await fetch(url).then(response => response.json())
      if (Array.isArray(payload) && payload.length > 0) {
        // ...pick off the top suggestion
        res = payload[0]
      }
    } catch (err) {
      log.error(`[logoFinder] ...message... Name: '${name}', Details: "${err.message}"`)
      return {
        success: false,
        error: errorMessages.badClearBitRequest,
        exception: err,
      }
    }
    return {
      success: true,
      ...res,
    }
  }

where the error message is really up to you, but the point was that this was something that would handle the simple text being returned by the endpoint and throw the exception on the JSON parsing without causing all the trouble of the library we were using.

There were a few things I liked about the new implementation we came up with:

  • Explicitly setting the query param on the URL - while it's possible that 90% of all name values would not lead to an issue, it's always nice to be safe and make sure that the proper encodings are done with the query params. It's two lines of code, but it makes sure that it's all handled properly.
  • The chaining of fetch() and then() - both fetch() and response.json() are async functions, so you might expect to see two await prependers on the functions, but there's only one. This is a nice feature of the then(), in that it unrolls the async nature of the fetch() so that the async nature of the .json() comes through - returning the value to the caller.

Sure, we still need to get the first element in the Array, but we also test that to make sure it's actually an array, and that there's something to get. It's just a lot more defensive coding than the original client had, and when we did this, we still got the good results on the dev machines, and at the same time, we got proper exception catching on the production instances.

Thankfully, the issues resided about the time we got the fix into the code, tested, and into production, so it wasn't long-lived, but it was a problem for a while, and we were able to recover the errors due to queues and retries, which is another saving grace that I was very thankful for.

Nothing like a little production outage to make the day exciting. 🙂

It’s been a Wild Month

March 28th, 2023

WallSt.jpg

Over the course of the last few weeks, we've seen the collapse of Silicon Valley Bank, and Signature Bank, and the Feds stepping in to reassure the depositors that everything will be OK, every deposit will be made whole, and the only losses will be to the stock holders of SVB. It's something that they didn't have to do, by regulation, but they did to return confidence to the smaller banks, and keep the deposits from being moved to the top-10 banks, and cause a real problem in all the smaller banks.

Still, it's faded from the headlines, and while The Journal is still covering it, it's not USA Today anymore, and that means that the bulk of the crisis is over - that of the lack of confidence in the system. People are no longer concerned, and that's really very good news.

The job market is still a mess... and it's going to take the financial markets to stabilize and start to head up, for the job market to return. It's confidence that drives good hires, not desperation. Still, this is just another cycle, and we'll weather it.

There are better days ahead. 🙂

Trip to the Dentist

February 28th, 2023

Path

Today is another trip to the dentist, and while I'm getting to the point that I can pretty much deal with these things, I won't be sorry when I don't have to. I know they mean well, and I know it's childhood trauma, but it's also the experience you have with the dentist, and therein lies a tale.

Today is two weeks after a procedure that was performed with such brutality, it set me back at least a decade in my comfort level with the dentist. It was a new guy, and he was brutal... just brutal. But it was done, and I counted my blessings that it was done. Now I have to go back for a post-op check, and get the stitches removed. I'm not looking forward to it.

I know it'll be over, and that's what I have to look forward towards, because thinking about what happened two weeks ago is mighty painful. But I'll survive.

Ivory for Mastodon by Tapbots

January 30th, 2023

Ivory

With the Early Release of Ivory by Tapbots, I think I've found the clear winner for a Mastodon client. This is very good - and it's got a lot more work that they want to do on it... so it's only going to get better.

Right now, it's got everything I used on Twitter, plus other nice features that are part of Mastodon natively. All in all, it's actually a nice upgrade.

I would still like to see the local town alerts (weather, service interruptions, etc.) come to Mastodon, but even if they don't, it's far better than whatever Twitter is turning into.

Moved to Mastodon

January 20th, 2023

Mastodon

With the recent demise of the Twitter API for third-party clients, it was time to move to Mastodon, all I really needed was a little push from a friend, and then off we went. I will say, the native client isn't bad, and Tapbots is creating Ivory, which sounds promising, but I'm pretty pleased with Ice Cubes - an Open Source Mastodon client using SwiftUI, available on the App Store. It's not bad at all on iPad, and on iOS it's really very nice.

I still will be very interested in seeing what Ivory looks like - as I really want one client that syncs on all my devices - as Twitterrific did, and I know the Tapbots guys will make that happen. But we'll see... who knows, given that it's SwiftUI, it's possible to imagine that Ice Cubes will be on macOS too... Could be interesting.

In any case, it was the people... the community, that made Twitter nice, and they're moving, and the place won't be worth a tenth of the purchase price in a few months.

Twitterrific is Silent

January 14th, 2023

Twitterrific.jpg

This morning, Twitterrific for iOS had problems logging in, and at first, I thought it was the 2FA I had applied to my account after a friend's account was hacked. The token on my iPhone expired, and I needed to re-authenticate my account with the 2FA, and yet when I tried to do that... nothing.

It was an hour later that I was still trying to find out what it might be, when I saw the news that Twitter had simply revoted the access tokens for some of the third-party iOS clients - while leaving the macOS clients alone. For example, Twitterrific for macOS is fine. This wasn't a mistake - it was intentional, and that's a shame. They chose to do this, and it's their company, so OK... but I can't imagine this standing - or maybe it's the beginning of the end?

I guess I'll see what Mastodon is all about...

Happy Birthday to Me!

December 31st, 2022

Cake.jpg

Another year in the books, and another year for me. As a kid, my birthday was way too close to Christmas, but as I've gotten older, it's nice to have them close together. I don't have to worry about people making a fuss on my birthday, and I can be assured that most everyone will be thinking about, and making plans for, their New Year's Eve activities, and so don't really think much about me. It's almost like stealth birthday - which is just fine with me.

Today, I'm heading down to Indy to visit my siblings, and just enjoy the day. I'll be back later, and that's OK. I've got The Talk Show to listen to on the way down and back - and Gruber is without a doubt, one of the more entertaining talk show personalities to me. It's always a good listen. So on my birthday I get to have good food, good company, and something good to listen to.

I am so very grateful for it all.