Tag: Bias For Action

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).

Can’t Fight This Feeling

Can’t Fight This Feeling

Yesterday I closed the book on my job with Amazon Web Services. It was a truly great gig; I was able to help numerous public sector customers advance their missions, grow both my technical and business skills, and work with some great people. But on Monday I start a new adventure as the Chief Technology Officer of Research Improving People’s Lives.

Officially, “RIPL is a tech-for-social-impact nonprofit that works with governments to help them use data, science, and technology to improve policy and lives.” But if you want a better sense of what I’ll be up to, these two opinion pieces by my colleagues are a great place to start:

I’ll have a lot more to say in the coming days about what led me to a new role, the emotions involved in transitioning from a job you love, and how to end your time at a company well. But since the cat’s out of the bag given my updated LinkedIn page, I wanted to get an announcement made here also.

Get In The Arena

Get In The Arena

Several months ago I had a need to cache function results across multiple executions of an API client. A quick web search revealed several solutions, the best fit being cachier. However, it was still missing a few important features I needed, and thinking it was the quickest solution, I wrote up a wrapper to implement these features and published it on PyPI.

One of the features was particularly tricky to get working without modifying cachier itself. Though I did get it working, I regretted not instead simply seeing if I could build my needed capabilities into that library itself and avoiding the wrapper altogether.

Turns out I had some additional free time, and took a crack at an integrated implementation of three key features, and turns out the maintainer of cachier was grateful for the contributions. I was also able to make additional improvements, which benefit all of cachier’s users, not just the one user (i.e. me) of a wrapper which is unlikely to get popular.

This experience was a good reminder that open source software is not built by a mysterious group of “other people” but by ordinary folks who graciously offer their limited time for the public good. Considering how much I’ve benefited from such generosity throughout my career, I’ve been thinking about what responsibility I have to the broader community. I’m not the only one. Do I have a professional obligation, or even a moral one, to contribute? Quite possibly, but either way, it’s something I’m going to do as long as I’m able.

On The Turning Away

On The Turning Away

I write this blog post sitting in my favorite coffee shop having begun yesterday a nearly three week micro-sabbatical. Not since I was laid off in early 2019 have I taken more than a few days of time off that didn’t involve travel or other busy-ness. I’m looking forward to spending some time relaxing, some time away from technology, and some time purposefully pursuing activities I haven’t had time to otherwise accomplish.

What sorts of activities? Well, for one I want to publish a new CDK construct, which I’ll talk about here once it’s published. Another is recording a podcast, which I’m happy to announce now has a brief trailer. Mostly it’s going to be similar to material covered on this blog, but perhaps with some conversations also. I’ve no idea if I’ll be able to keep it up, but I’m starting nonetheless.

I’ll also be reading quite a bit. Finished a book this morning, and started a second, the appropriately titled How To Do Nothing.

Finally, I’ll be drinking copious flat whites with the above view from my corner table. Life is good.

A Helpful Transmogrifier

A Helpful Transmogrifier

Have a large CSV file and want a quick way to query it? Consider transforming it into a SQLite database. It’s easy! One command will do it:

$ sqlite3 "$sqlite_filename" ".import $csv_filename $table_name --csv"

Here’s a concrete example using airtravel.csv:

$ sqlite3 air.db ".import airtravel.csv air --csv"
$ sqlite3 air.db "SELECT * FROM air WHERE air.Month = 'JAN'"
JAN|  340|  360|  417

Neato! Admittedly the handling of headers and column names isn’t great, but that can be solved with a bit more script-fu (which I’ll leave as an exercise for the reader).

That Last 20%

That Last 20%

I got an email this morning from a reader who asked if I had an email subscription feature on this blog. I didn’t then, but now I do! Want my writing to hit your inbox the moment I publish? Just add your email address into the widget at the top of the sidebar and hit subscribe. Easy!

You know what wasn’t easy? Trying to get that widget to match the rest of the site. At first it looked like this:

Gross. Luckily WordPress supports adding custom CSS. Unluckily, that means I had to fiddle with CSS, which is a special form of hell. I couldn’t get it perfect on all browsers, but it’s not bad now:

While I was at it, I made a few other visual tweaks to the site, primarily shrinking the masthead height, which has always bugged me. Here’s the final code snippet. Not the prettiest, especially with all those !important keywords (generally they’re a smell that your CSS is too complex), but it gets the job done.

.navbar {
    display: none;
}

.site-header {
    height: 300px;
    min-height: 300px;
}

.site-title::after {
    margin-top: 0.5em !important;
    margin: auto;
}

button.wp-block-button__link {
    height: 34px !important;
    margin-left: 0px !important;
    padding: 0px 5px !important;
    background: #fab526;
    font-weight: bold;
}

input#subscribe-field-1 {
    padding: 5px !important;
    border-bottom: 2px solid #ddd !important;
}

.search-field::placeholder {
    color: #B9B9B9;
}

If you happen to notice any weirdness on your device/browser of choice, do let me know, eh?

Progress Report

Progress Report

At the beginning of this year I made two resolutions:

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

For the first one, so far so good. For the second, not so much. I read a book on Clojure, but haven’t yet had a reason to use it beyond tutorial exercises, so can’t really say I’ve learned it. Maybe it’s just that these days I’m thinking more about systems than software, and thus language choices seem less important?

Speaking of book reading, though, I’m well on my way to achieving my meta resolution (to read the same number of books as my age, every year, for the rest of my life). According to Goodreads I’ve completed 39 books so far against a goal of 43 (seven books ahead of schedule). Should be no problem to get to the finish line and beyond.

Here are the five star highlights:

Honorable mention goes to Range, which I can’t recommend enough for anyone who feels like they’ve missed out on their calling by meandering through a number of life experiences. Generalists make the best leaders and problem solvers, so embrace the variety of perspectives you can bring to the table. Real life is not like golf or chess or programming only in assembly.

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.