Tag: Have Backbone

Spooky Season

Spooky Season

I don’t know what’s scarier, that I saw this when trying to use airplane WiFi…

… or that I know the technologies to which it refers.

Honestly, sounds like how a D&D character might meet their untimely demise, does it not?

That Kind Of Day

That Kind Of Day

You know when you’re trying to clean up a bunch of old AWS accounts but there’s no way to bulk close them so you have to click them one at a time and then click close and then copy and paste the account number to confirm and then there’s also a rate limit so you have to wait a minute between closures and then you hit a “10 account closures per 30 days” limit and no you can’t increase the quota says the documentation but you talk to support anyways and then they try to increase the quota but they can’t either so they suggest you log into each of them as root one at a time to close and you say “fine” but then the root email passwords are missing in your repository of credentials so you try to go through the forgot password flow but the root email address has two plus signs in it and no Exchange configuration you can think of to try seems to be able to accept such an email address and so you’re just outta luck…

ARGH!!!!!!!!!!!

UPDATE: So you finally get a shared mailbox set up with a carefully crafted alias that will receive email from the offending email address at least from your personal gmail account so in theory its working but then you retry the forgot password flow on the AWS login page and there’s a CAPTCHA and the first 4 times you try to solve it you get it wrong and then finally you get it right and the page claims it’s sent you password reset instructions to via email but you’ve waited 15 minutes and nothing has come through and yes you’ve checked the junk folder and what the hell am I doing with my life this is not what I dreamed a career in technology was going to be like and why can’t it involve more of the Property Brothers??

Jump The Line

Jump The Line

While it’s not an absolute guarantee, there are a few ways to get my attention when applying for an open role for which I’m responsible.

First, read the job description and the minimum requirements. If you don’t meet them but want to take a chance anyways, don’t shy away from where you fall short. Address any gaps head-on in your cover letter and how you can mitigate.

Speaking of a cover letter, you should absolutely write one. Yes, actual you, not an LLM. I value engineers who can communicate effectively, especially in writing, given the realities of remote work. This isn’t about nitpicking spelling or grammar (though in 2024 there’s little excuse for stumbles here, given the tooling available), nor is it about quantity. It’s about concisely communicating what you value in a job and what excites you about the role enough to apply.

When describing what you value, show don’t tell. I love to see an example of work you’re proud of in a cover letter, because the way you discuss what’s important really matters: are you enamored with technology as an end in itself, or do you value impact on a customer? And what kind of impact do you value?

Finally, be sure to follow the instructions in the application process. Employers may have specific reasons for their requests; deviation does you no favors. For example, RIPL asks for an email to a specific address that goes to a shared inbox. If you send your info directly to an individual it might be missed. And if you DM me in LinkedIn instead, well, I get a lot of DMs, so don’t expect a response.

The Struggle Is Real

The Struggle Is Real

This week I got into a friendly debate about developer onboarding in two different fora (the Rands Leadership Slack and an in-person CTO Lunches gathering). My hot take: technical onboarding documentation is at best over-rated, at worst counterproductive, and most organizations shouldn’t give it much thought.

Before you pick up stones, hear me out. My logic is based partly on experience, and partly on a theory. The experience is that writing detailed onboarding steps takes considerable time, usually from well-tenured developers whose attention is better spent elsewhere. Keeping said documentation up-to-date takes even more time and is nearly impossible to do with a fast moving product. And having half-baked or incorrect instructions is worse than nothing for a new team member. Putting in all this effort just to save a little bit of onboarding time doesn’t make sense. The juice isn’t worth the squeeze.

But there’s more. My theory is that having an onboarding process spelled out in painstaking details actually robs the newcomer of the chance to build muscle through struggle, shortcuts creative exploration of how things could be better, and sets an expectation that “getting up to speed” means following a mechanized set of steps instead of self-directed discovery of a codebase and getting to know fellow team-members and their institutional knowledge through asking excellent questions.

Sure, this might mean some initial frustration. That can be managed. And it might mean a new developer is slower to begin delivering value. But my hypothesis is that once they do, they’ll be better prepared to provide broader and deeper value in the long run.

And besides, it’s likely your system isn’t as complex as you think it is, and you should be looking for the kind of people that can do their own problem-solving. If it takes someone many days just to get an app running, you’ve got more serious problems. Which makes me think this could make for an interesting interview exercise: “Here’s our code repository. Get it running in a fresh environment.”

Two Things True

Two Things True

On the same day I wrote about radical responsiveness, I came upon this post that seems to contradict it. I really respect Ethan Evans and enjoy his writing (especially this bit about why you fail to get promoted). And I understand the point he’s making about fragmented attention. The temptation to conflate interruptions with importance is real, and amplified by modern communication technologies. But I’m not prepared to say he’s right and I’m wrong.

For one, I believe it’s possible to be both radically responsive while remaining reasonably non-fragmented. Some degree of interruption is inevitable, but using techniques such as pomodoro can help protect focus while still ensuring important messages don’t get missed for long. Good old-fashioned discipline is required to stick to a plan, but it can be done.

The discipline gets easier with a well-configured set of tools, which is where many folks fail. Learn your tools! And not just the basic features, but the myriad of options for managing notifications, filtering messages, scheduling reminders, etc. It’s not a badge of honor to be “bad at email” or “not understand Slack” if you’re a professional in 2024.

(If any of my coworkers are reading this, they may quickly point out that as recently as last month I didn’t know how to join cell phone calls into a conference. Which… is true. But I learned! And now I know for next time).

Finally, Evans makes an assumption about communication that I don’t believe holds true. It comes through most obviously in this statement:

“Allow chaos to build up within the trivial (the inbox) to accomplish the meaningful.”

Did you see it? The assumption that messages in an inbox are trivial? Tell that to your customer who is informing you of a serious issue with your latest release, or your team member whose employment status is in jeopardy if you don’t respond to their immigration lawyer. Yes, we all get spam, but sometimes interruptions truly are critical and need attention. To lump all of that into the category of “trivial” for the sake of personal flow is a leadership fail. Communication is part of the job; sometimes it’s all of the job.

Of course, I could be wrong. Read the posts and decide for yourself.

Forth Eorlingas

Forth Eorlingas

I once had a customer call me an “idea hamster” because of how easily I went down rabbit trails of ideation when discussing the project we were working on. We had a good laugh about that turn of phrase, and I do see the value in idea generation to some degree, but ideas are easy. I’m not impressed by someone who can come up with many of them (least of all myself). What impresses me is people and organizations that can execute on their ideas.

There might be “second half of life” factors at play as well in my desire to get better at finishing. In the last week I’ve added 10 draft ideas to my blog backlog, and this will be only the first one I’ve published. At the rate I’m going I’ll never get done, which perhaps is a good thing, but still, I want to get a few of these ideas out in the wild, and that means I need to power through the writing part.

Wants What It Wants

Wants What It Wants

(I seem to open a lot of blog posts with variations on “I’ve written before about X.” Here’s another one).

Back in 2017 I wrote three posts in a row about the tension between giving users what they want and guiding them to what is best. They came to mind this week when I ran up against on of terraform‘s more annoying (lack of) features: the inability to apply changes on a per file basis. I absolutely understand why it’s not supported, but sometimes it’s a quick and dirty way to keep moving forward, and dang it, I needed it!

After a day of annoyingly overspecifying --target flags in my commands, I rolled up my sleeves and built a wrapping script that would do the work for me, essentially adding a --file flag to the CLI. I share it here as a service to the Infrastructure-as-Code community. Usage is easy:

terraform-files apply --file my-infra.tf

It’s hacky as heck, so use at your own risk, your mileage may vary, etc etc. And if you want to make it better, revisions welcomed!

A Matter of Perspective

A Matter of Perspective

In the past several months I’ve been making efforts to do more networking with technologists. One avenue to do that has been joining a couple Slack workspaces (Rands Leadership and All Tech Is Human, specifically). A few days back a conversation topic was the difference between unit tests and integration tests; a topic on which I definitely have opinions.

As part of the discussion I came up with the following distinction, which I liked enough to codify here for posterity:

  • Unit Test: Tests one “thing” (function, module, service, system) in isolation
  • Integration Test: Tests multiple “things” (functions, modules, services, systems) in combination

Inherent to this definition is some ambiguity, because a single “thing” at one level is multiple “things” at another level. What matters definitionally is the spirit of a test: is it trying to test one thing or multiple things. If the former, it’s a unit test. Otherwise it’s an integration test.

For what it’s worth, I’m a much bigger fan of the test diamond than the test pyramid. The ratio of “amount of stuff tested” to “effort required to write tests” is so much higher when writing integration tests. And they (typically) test at the “actual business functionality” level, vs at the “does this code do the thing” level. And value is all that matters.

On a tangential note, I developed another type of test diamond a couple years back. It was initially designed when evaluating taco shops along Poway Road in San Diego, but it’s applicable to just about anything you want to rate. I leave the interpretation of the diagram as an exercise for the reader (the ambiguity is a feature, not a bug).

Jud Flow

Jud Flow

Keeping a nice and tidy code repository makes me happy. Here’s the typical process I use to avoid messes:

  1. Create my-sweet-new-feature branch from main
  2. Make some awesome code edits, then commit them
  3. Make some slightly less awesome edits, commit them also
  4. Run some tests, nothing works; debug and commit the fix
  5. Decide my originally awesome code isn’t so awesome; rewrite the whole feature and commit
  6. Tests pass locally, yay! Push my-sweet-new-feature to Github and create a pull request
  7. Hrm, tests fail in pipeline; whoops, forgot a file; commit and repush
  8. Okay, tests pass now, so message team for review
  9. That’s a reasonable request, change made and committed
  10. Fine, we’ll use your naming convention; change made and committed
  11. Ugh, made a spelling error; committed
  12. Fixed moar typos
  13. Uggggggh, one last commit to fix spacing; pushed to Github
  14. Wha? Tests failing? :facepalm: forgot a file again
  15. Commit that file and push one last time for realz
  16. Tests pass, team reviews and approves, we’re good to go
  17. Pull an update of the main branch
  18. Come back to my-sweet-new-feature and rewrite all the commits on top of updated main; group edits into a clean subset of logical changes, one per commit, that makes it look like I wrote the code perfectly the first time, with nicely crafted commit messages that will mean something to some poor future developer that has to maintain my code ten years from now
  19. Run tests to ensure everything still passes; it does
  20. Force push to the pull request, obliterating all those ugly prior commits with these nice clean ones
  21. Try to merge the branch to main with fast-forward only option, forget that Github doesn’t support it (curse you Github! even flipping CodeCommit supports fast-forward only merging)
  22. Fast-forward merge my-sweet-new-feature to main locally so my final commit signatures are preserved
  23. Try to push main to Github, but it fails because the branch is protected
  24. Unprotect main temporarily, repush
  25. Dang it, someone merged new changes since step 17; repull main and rebase my branch
  26. Re-push my final changes and re-protect main

See how easy that is? No excuses moving forward, my friends!

Resolute Comprehension

Resolute Comprehension

I really like New Year’s resolutions. As a lover of habit, the beginning of a year is perfect time to calibrate a new routine. This year I have two resolutions:

  1. Post on this blog at least once per month
  2. Learn a new programming language

The latter was inspired by this article, which is stupidly long but thoroughly enjoyable. As a non-fan of OOP I found myself nodding along quite frequently. He advocates pretty hard for functional languages; while I’m familiar with the paradigm having used it in Python, I haven’t done much with purer forms. In 2022 I intend to change that, probably by learning Clojure.

Erlang and Go are also on my to-learn shortlist, the former for its first-class support for concurrency, the latter because it’s the new hotness for performant APIs.

In other news, I’m working on publishing my first CDK construct, which I’ll share here when it’s ready. I do wish I didn’t have to write it in TypeScript, but sadly I’m at the mercy of the JSII compiler. Why TS doesn’t have first class support for comprehensions boggles my mind. This is the closest I could get:

Array.from(nodeProps.entries()).map(e => new HyperledgerFabricNode(scope, `Node${e[0]}`, e[1]));

Compare that with a Python equivalent:

[HyperledgerFabricNode(scope, f'Node{i}', p) for i, p in nodeProps.enumerate()]

For shame, TypeScript. For shame.