Author: Jud

Technologist interested in building both systems and organizations that are secure, scaleable, cost-effective, and most of all, good for humanity.
Reap The Whirlwind

Reap The Whirlwind

This summer my family and I went on a two week European vacation. Six cities in fourteen days is no joke, but we had a blast, saw a ton, and stayed healthy throughout. For something different, I thought I’d catalog our activities here.

Day 1 – Rome

  • Land at Leonardi da Vinci International Airport
  • Taxi ride to the hotel (aggressive driver kept us on our toes)
  • Jetlag recovery nap (essential)
  • Pizza at Taverna Rossini
  • Pico Gelato for dessert (tears of joy were shed)

Day 2 – Rome

  • Trevi Fountain
  • Colosseum
  • Piazza del Campidoglio
  • Pantheon
  • Lunch at La Soffitta Renovatio
  • The Vatican, including the Sistine Chapel and St Peter’s Basilica
  • More gelato at Pico
  • Quick dinner at the hotel before crashing in bed

Day 3 – Rome

  • Temple of Asclepius
  • Walk through Villa Borghese
  • Piazza di Spagna (the Spanish Steps)
  • Trevi Fountain (again)
  • Vicus Caprarius (ruins under Trevi)
  • Life-changing carbonara at Al Simeto (no one spoke English, a good sign)
  • Even more gelato at Pico

Day 4 – Florence

  • Morning train to Florence, and walk to our Airbnb that was right on the square
  • Accademia Gallery to see Michelangelo’s David (breathtaking)
  • Uffizi Gallery (Birth of Venus, amongst other masterpieces)
  • Life-changing chianti at La Buchetta, and the steak was pretty good too
  • Evening walk at the Piazza della Signoria

Day 5 – Florence

  • Climb to the top of the Brunelleschi Dome
  • Tour of the Duomo cathedral
  • Cappelle Medicee
  • Basilica di San Lorenzo
  • Trattoria Sergio Gozzi for lunch with an old friend (and killer truffles)
  • Battistero di San Giovanni
  • Palazzo Strozzi
  • Ponte Vecchio
  • Gelateria Edoardo il gelato biologico (obviously)
  • Quick pizza from a grab and go

Day 6 – Alps

  • Walk to the Florence train station
  • Train through Bologna, Bolzano, Innsbruck
  • Arrived in Munich in the afternoon
  • Dinner at Haxnbauer im Scholastikahaus (pork knuckles FTW!)

Day 7 – Munich

  • Bus ride to Bavaria
  • Neuschwanstein Castle
  • Quick lunch (sausages and beer)
  • Oberammergau
  • Linderhof Castle

Day 8 – Munich

  • Morning run in the Englischer Garten
  • Tour of Dachau (a sobering and essential experience)
  • Shopping in Marienplatz
  • Walkthrough of Peterskirche (including a climb of the tower)
  • Stroll through the Englischer Garten in the rain
  • Dinner at Hofbräuhaus
  • Midnight sleeper train to Paris

Day 9 – Paris

  • Taxi to the hotel to freshen up
  • Walk through Jardin des Plantes
  • Brunch at Clint (poached eggs, yummy)
  • Recovery nap (absolutely essential)
  • Shopping in Le Marais
  • Dinner at Robert et Louise (beef cooked over an open fire plus a Bordeaux)
  • Walk through Place des Vosges and Place de la Bastille
  • Cards in the hotel lobby

Day 10 – Paris

  • Stroll through Montmartre
  • The Basilica of the Sacred Heart of Paris
  • Eglise Saint-Pierre de Montmartre
  • Cheese sampling from a local shop
  • Walk past Moulin Rouge
  • Arc de Triomphe (only a couple quick photos)
  • Eiffel Tower (didn’t go up though)
  • Pont Alexandre III Bridge
  • Eglise de Saint Germain des Pres
  • Macarons from Boutique Pierre Hermé
  • Le Jardin du Luxembourg
  • Panthéon (photo from afar)
  • Cathédrale Notre-Dame (just an outside view)
  • Ile de la Cité
  • Sainte-Chapelle (beautiful stained glass)
  • Lunch at Brasserie Les Deux Palais
  • Quick walk past Musée du Louvre
  • Tried to tour the Catacombs, but alas they were booked out
  • Crepes from Au Beurre Salé
  • Well-earned sleep

Day 11 – London

  • Eurostar through the Chunnel (delightful train and fast!)
  • Tube to Pimlico station
  • Bit of recuperation at the Westminster Hotel
  • Tour of the Churchill War Rooms
  • Dinner at The Admiralty (Trafalgar Square)
  • Walk past Westminster Abbey, Big Ben, and Parliament

Day 12 – London

  • Several hours of exploration at the National History Museum (Dippy!)
  • Nap on the lawn at Hyde Park
  • Princess Diana Memorial Fountain
  • Science Afternoon Tea at The Drawing Rooms
  • Stroll over Westminster Bridge

Day 13 – Oxford

  • Morning train to Oxford
  • Fish and chips at Wig & Pen
  • Photos at The Eagle and Child (sadly closed due to COVID)
  • Shopping on Cornmarket Street
  • The Sheldonian Theatre
  • The Hertford Bridge (most photographed spot in Oxford)
  • Bodleian Library
  • Blackwell’s Bookshop (bought a rare Isaac Asimov book: The Clock We Live On)
  • Radcliffe Camera
  • University Church of St Mary the Virgin
  • The Bear Inn (serving Oxford since 1242)
  • Christ Church College
  • Merton College
  • Martyrs’ Cross

Day 14 – Journeying

  • Sleep in late
  • Depart Heathrow in the early afternoon
  • And land in San Diego in the late afternoon (hooray for timezones)

And there you have it. Not a bad way to spend a fortnight.

That Lovin’ Feeling

That Lovin’ Feeling

I’ve done a fair share of production debugging in my career. There’s a heroic Dopamine rush that comes with it, that feeling of diving deep on a problem in a critical situation, finding the solution, and then implementing it to the delight of your customers and teammates (well, either delight or they graciously allow you to live another day).

A similar feeling is experienced any time you build something with your own two hands and see it come to life; that joy is why this blog is named what it is, because I love to build. But as a manager of a technical team, I don’t get the chance to directly build solutions as often as I might like, and when I do, it often represents a failure of some kind. To be successful as a leader, one needs to learn to let the joy of building go, at least the hands-on kind.

Instead, what a manager must cultivate is the joy of watching others succeed, especially those to whom they are charged to mentor as direct reports. Being thrilled when a person shares a difficult problem they solved; rejoicing when a struggling individual responds to your coaching with positive growth. Giving others the spotlight and serving their needs while hidden from view. Learn to get a Dopamine hit from such experiences, and you’ll do well.

And here’s the real kicker: when you achieve it, you’ll have scaled your ability to enjoy your job beyond what was possible before, because you now have a whole team of people whose successes are a source of happiness, versus just your own. Ultimately you’re still building, but now it’s through others.

It’s Not Personal

It’s Not Personal

I love Raising Cain’s. Their chicken fingers melt in your mouth, their sauce is top-notch, and the Texas Toast is a perfect bonus. I give it the edge over Chick-fil-A for best fast-foot chicken joint (though it’s close).

A few days ago I stopped by to get my typical 3 Finger Combo (with a lemonade and extra sauce, natch). It was pretty crowded and noisy, with many folks waiting for food, either to eat there, take with them, or to deliver on behalf of another (thanks to services like DoorDash, GrubHub, and UberEats, one can no longer make assumptions about how busy a restaurant is by the line at the counter, which is another customer experience post worth writing, but I digress). After saying what I wanted, I was asked to provide my name for the order. I did so, carefully pronouncing the short u in Jud which I’m regularly doing (it’s not a reference to the 2nd greatest Beatles song of all time, instead it’s pronounced like the country singing mother-daughter duet from the 90s, though only spelled with one d). I think they heard it right, but I couldn’t be sure.

While waiting for my food, I reflected a bit on this experience. I get the objective: make the experience more personal, so that when my order is ready I’m called by name and I thus feel like it was specially prepared. But that approach is flawed, because it fails to work backwards from actual customer desires. I suspect I’m not alone in that I don’t want a “personalized experience” at Raising Cain’s like I do at my job; I want to get the delicious chicken that I ordered quickly and accurately. An order number not only suffices, it does the job better than a name, for numerous reasons:

  • A number guarantees uniqueness in a way names do not, decreasing likelihood of an order mix-up.
  • Numbers are more easily distinguishable audibly compared to names. My name is often misheard, and it’s not nearly as tricky as many others.
  • Gathering a name requires an extra step in the ordering process, slowing it down. A number can simply be assigned.

These benefits have analogs in computer science, for example the advantages of searching a database using a unique identifier vs free text fields. Which someday when I need to explain the latter to someone who’s less familiar with the technology, I might just use the former as a metaphor: the act of ordering is adding a row to a data table of “customers waiting for orders”, and the person calling out the order once it’s ready is querying that table. A good database design seeks to make such queries unique and performant.

Further, the model of indicating a parking space number when getting curbside delivery is remarkably similar to hash-based lookups. Hmm, I probably need to turn this into a larger talk someday.

But in the meantime, when I’m asked for my name at a restaurant checkout counter? Call me “three one four” thank you very much.

That Personal Touch

That Personal Touch

Meeting regularly with your direct manager is an important mechanism for ensuring your work stays customer focused, getting actionable feedback and advice, and ultimately helping you achieve your career goals. This page captures a few of my thoughts on making them effective.

Firstly, you as an individual should own these conversations. Take the lead in setting an agenda, and come prepared with discussion topics. Your leadership has limited time, so use it wisely. Frequency and duration are up to you as well, though generally I’d say more frequent and shorter is better than one marathon session per month. However, there are times when longer discussions are needed, especially when goal setting and discussing performance.

Discussion topics can vary, though generally as a manager I’m less interested in discussing status on your day-to-day tasks and projects, unless you need advice or guidance on a specific issue you’re facing. I have other mechanisms to keep tabs on project health, so I’d much rather focus on personal development and goals. That being said, if you really want to give your manager a dump of what you’re working on (or just vent) that’s fine, but be careful not to use up all your time in this way.

Finally, I recommend taking notes during all 1-on-1 discussions, and especially having a mechanism for tracking action items for both yourself and your manager. I do that on my end for all my team, and share these notes in an email after each meeting, but using something more rigorous (like a ticketing system or task board) might be even better

Possible Agendas

Here is an example agenda I’ve used successfully:

  • Highlight / lowlight since we last talked
  • How can I help you this upcoming week?
  • What’s the status of your current annual goals?
  • Open discussion (you pick the topic)

And another agenda that also works well:

  • Personal check-in: how are you feeling?
  • Quick updates
    • Previous 1-on-1 action items
    • Tasks and projects
    • Current goals
  • Discuss current challenges and potential solutions
  • Recognize successes with gratitude
  • Create and review action items

And a third one:

  • Personal check-in
  • Task/project/goal progress
  • Review of priorities
  • Workload and expectations
  • Blockers
  • Feedback
  • Concerns

Discussion Questions

These are some questions I like to ask during a first 1-on-1 to learn more about how a person prefers to be managed:

  • What do you most need from me as a manager?
  • How do you prefer to receive feedback? In writing? In person? Another way?
  • How can I know when you’re struggling and need help?
  • Are there any manager behaviors that particularly bother you? If so, how can I avoid them?
  • What ongoing 1-on-1 cadence would be most helpful for you?

More generally, these are question I ask to help me as a manger how to make work more enjoyable:

  • What motivates you to perform at your best?
  • What do you wish you could spend more (or less) time doing?
  • At the end of the month/quarter/year, what would you like to say you’ve accomplished?
  • At the end of your career, what would you like to say you’ve accomplished?
  • If you could change one thing about work that would improve your life, what would it be?

These questions help me ascertain and guide someone’s career growth:

  • What impact do you think you’ve had so far? What additional impact would you like to have?
  • What aspects of your role do you love (or hate) and why?
  • What are you learning, and how are you growing here?
  • Is there a new project you’d like to work on? Or new goal you’d like to work towards?
  • What do you need training on? What do you need experience in?

Finally, these are question I ask to get feedback on my own performance as a manager:

  • How can the team improve its communication?
  • How can I help you be more successful?
  • How can we help you do more of what you enjoy?
  • How am I doing? What can I be doing better?
Expect The Unexpected

Expect The Unexpected

Like many other languages, Python has the notion of default values for function parameters, for example:

def compute_final_price(cost, sales_tax_rate=0.08):
    return cost * (1.0 + sales_tax_rate)

This code behaves as you would expect:

compute_final_price(10.0, 0.07)  # returns 10.7
compute_final_price(10.0)  # returns 10.8

However, interesting things happen in more complex cases, because the default value is evaluated once, at the time the function is defined, and not when it’s executed.

my_rate = 0.05

def compute_final_price(cost, sales_tax_rate=my_rate):
    return cost * (1.0 + sales_tax_rate)

compute_final_price(10.0)  # returns 10.5
my_rate = 0.06
compute_final_price(10.0)  # still returns 10.5

You can prove to yourself the value is evaluated at definition time by running help(compute_final_price), and you’ll notice the default value has already been computed:

Help on function compute_final_price in module __main__:

compute_final_price(cost, sales_tax_rate=0.05)

The above can be pernicious if the default value is an object that’s modified inside the function:

def add_to_list(item, my_list=[]):
    my_list.append(item)
    return my_list

add_to_list(4, [1, 2, 3])  # returns [1, 2, 3, 4]
add_to_list(1)  # returns [1]
add_to_list(1)  # returns [1, 1]

A common workaround for the above is to do the following:

def add_to_list(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list

add_to_list(1)  # returns [1]
add_to_list(1)  # returns [1]

I’ve encountered folks that insist one should never use default values except for None and the above pattern, but I’ve found most of the time I’m not mutating such defaults, and the behavior described here is fine. But still, the more you know.

Into The Sunset

Into The Sunset

I’ve mentioned before my penchant for minimalism, which is why for the past 8 years my code editor of choice has been Atom (in fact, I may have been a beta tester for it, my memory’s a bit fuzzy on that point). Which is why it bummed me out a bit to read it’s being shut down at the end of this year. Technology marches on, I suppose. I can’t blame GitHub Microsoft for wanting to consolidate development effort in their fully-featured IDEs, especially integrated cloud-based solutions like Codespaces.

Still, I’m going to miss Atom’s simplicity and customizability (I’d even contributed to a few plugins). It was robust enough to be a complete development environment (for my coding style, at least), yet snappy enough for quick one-off text file editor. For the former case I’ll probably get back into VSCode, and Sublime Text ought to do the trick latter. Though maybe I can use it for both?

Crossing The Rubicon

Crossing The Rubicon

There are a plethora of resources for those just getting started with software development, and best I can tell, most of them will do the job adequately well. But there isn’t nearly as much on what is needed next: guidance on how to get from “early intermediate coder” to “seasoned software engineer”. In brief, here are some suggestions:

  1. Study existing high-quality code; if you don’t know what good looks like, it’s nearly impossible to produce it.
  2. Write a lot of code. There’s no substitute for practice and putting in your time.
  3. Find someone who can give you feedback on the code you write, and humbly iterate per the guidance.

In my experience, an efficient way to do all three is to find a couple open source projects that need support, dig into their code, and submit contributions. You start from a base of quality code, get to write more, and you’ll get feedback through pull requests. And the icing on the cake is that it’s all done in public.

Spend a few years of doing the above and you’ll be well on your way to next-level programming expertise. It’ll also teach you how to code with a distributed and decentralized community of stakeholders, and that’s no small thing.

Public Service Announcement

Public Service Announcement

This is a slash: /

This is a backslash: \

Website URLs have slashes. If you say “backslash” or “forward slash” when describing a URL, I will judge you.

That is all.

Automatic For The People

Automatic For The People

When I quit my first job after nearly 12 years, it was a shock to lose access to all the software I’d spent years developing. While I believe strongly in Egoless Programming, and resisting the notion of “my code”, so much reference material I’d built up was suddenly lost to me. I decided in that moment I needed to build up a portfolio that could not be taken away.

A few weeks ago I published Chrome Local Storage, a Python package that can read from and write to the Chrome’s browser’s internal storage, either one running locally or on an Android mobile device. The first draft didn’t have any CI/CD automation in place, but this weekend I fixed that.

It now automatically sets the version according to the git tag, runs some limited automated tests, runs a linter, scans both the code and dependencies for security vulnerabilities, and publishes builds to PyPI. All via Github Actions.

Did this project really need a complete pipeline? Not really, I doubt I’ll see much reason to modify it in the future. But I wanted to learn Github Actions, and I’d wanted to learn Poetry. Now I’ve done both, and have a publicly available reference to which I’ll always have access for when I need to build Python packages in the future. And if others need the same, they can use it as well.

Throwing In The Towel

Throwing In The Towel

I’ve said before that I enjoy thinking about organizations, continuously optimizing them to give the highest probability of the desired outcomes. Organizational ergonomics, if you will. I’m also a mathematician by training and a nerd, which is what made Applying the Universal Scalability Law to organizations such a fascinating read, because it puts statistical weight behind its arguments.

In the same vein, I thoroughly enjoyed the following two articles that take a mathematical approach to understanding variability in project estimation (a perniciously difficult problem in all technical work):

The latter’s provocative title hopefully piques your interest enough to read further. You won’t regret it!