We’re All Just Folk Now

We’re All Just Folk Now

Back in 2014, I read The End of Men; having just been hired by a startup run by a woman, it felt like a good time to explore ideas about why men have traditionally dominated positions of power, and how and when that might change. I don’t remember many details about the book itself (and apparently it’s somewhat controversial in conservative and progressive circles alike), but I do remember coming away challenged to do my part in centering women as I moved forward in my career.

Fast-forward to this past week, during which I happened to have many interactions with female colleagues:

  • Two women presented a dashboard on team performance metrics to our team
  • I got career advice from the female founder of a major cloud consulting company
  • Three times I met with various female peers to discuss leadership transition opportunities
  • I provided coaching to a woman just beginning her career in technology
  • I partnered with a woman to conduct four back-to-back interview sessions

While there’s still more work to do to undo historic inertia, realizing that I’m surrounded by so many capable women from whom I can learn is an opportunity I hope only gets less rare.

Don’t Be Late

Don’t Be Late

I’ll be the first to say that UX is hard, but honestly now, do I really need to specify a dinner reservation time-of-arrival down to the second?

If I had to speculate, the implementor probably just copied an existing time input widget without consideration of the use case. Situations like this are a reminder of a downside of code reuse; yes it might save some development time, but is it best for the customer?

Left Hand, Meet Right Hand

Left Hand, Meet Right Hand

Earlier this week I got an email from a recruiter. In itself, that’s not a remarkable occurrence, I’ve gotten 263 such emails since I started tracking them back in 2015. What made this one funny is that it was from my current employer.

I’m regularly asked about the corporate culture at AWS, and a common way I’ve described it is being like a large collection of small startups. This decentralization has a number of benefits, not least of which it only rarely feels like I’m working for a curmudgeonly big business (especially when compared to my last large company gig). But every once in a while the disadvantages show.

Sharing Is Caring

Sharing Is Caring

Last week I recorded a Q&A video session with a colleague for an upcoming team all-hands meeting. Ostensibly we were there to speak on the benefits of a recently-deployed internal tool that’s become quite popular. But the value comes not from the tool itself, but from those whom it empowers to easily share their work.

https://stackoverflow.blog/2020/05/14/the-most-successful-developers-share-more-than-they-take/

Maybe it’s just the self-reflection inherent to middle age (I turned 43 a month ago), or the heartfelt email my team received this weekend from a recent customer, but in some small way I hope that when I’ve gone I’ll have contributed my portion to the ongoing corpus of human knowledge, and further, that I was able to utilize said knowledge for the greater good. The only way for that to happen is to maximally share what I build whenever possible, whether through open source code repositories, high-quality documentation, or even this blog (modest though it may be). It takes extra work, but the work is worth it.

Hooray For Heuristics

Hooray For Heuristics

Besides the two resolutions I made for 2022, I’ve decided to try out a meta-resolution: every year from here on out, I will resolve to read the same number of books as years I am old (inspired by the coincidence that I finished 42 books last year, which happened to match my age). I track all my reading on Goodreads, where you can follow along if you’d like.

Given the above challenge, I wanted to determine how much of a time investment was going to be involved, and especially wanted an easy way to break it into daily reading targets that would keep me on pace. To do so, I needed two pieces of data: an average book size in pages, and an average time spent per page. My gut feel for these values was 300 pages and 1 minute, which led to a nifty conclusion: if I let A be my age, and aim to read A pages per day, which takes roughly A minutes, I should be able to easily complete my goal of A books over the course of the year (365 > 300, but I expect I’ll miss days here and there). Plugging in my current age of 43, that means a modest investment of 43 minutes per day is all it takes to achieve what otherwise sounds like a difficult goal. Isn’t that neat?

Neat enough that I wanted to validate my assumptions. For average book size, I downloaded the last 10 years of my reading records from Goodreads (I’ve been doing this a while): 84218 pages divided by 288 books gives an average size of 292 pages. My guess was pretty dang close, cool!

To measure my reading speed, I timed how long it took me to read 10 pages of three representative books: Multipliers (business/engineering non-fiction), Lifting the Veil (religious non-fiction), and The End of Eternity (science fiction). Resultant times were 6.5, 10.5, and 10.5 minutes for 10 pages, respectively, which averages out to 0.9 minutes per page. Once again, my intuition was reasonable.

One final statistic worth pondering: if I can hold to this meta-resolution, how many more books can I expect to read before I shuffle off this mortal coil. Thanks to Google, I know average life expectancy for a male in the United States is 75, so we’ll say I’ve got 32 years left. Thanks to Gauss, I can easily compute a sum from 1 to N with the formula N * (N+1) / 2. The sum of 1 to 75 is thus 75 * 76 / 2 = 2850, and now we need to subtract off years 1 through 42, which sum to 42*43 = 903, for a final result of 2850-903 = 1947 books. My Goodreads backlog is only 99 books long, so I guess I better start adding to it. Any suggestions?

Off To The Races

Off To The Races

In my previous post I mentioned an issue I had when building a CDK construct. As promised, today I’ll go through the problem I found: a dreaded race condition, which anyone who’s spent much time debugging software knows is a pernicious type of situation where behavior varies depending on the order in which various parts of the system execute, causing intermittent failures.

For background, part of the power of CDK is that it provides a framework for executing raw AWS API calls as part of a larger deployment. This is useful in numerous circumstances. For my construct, it enabled me to output several Managed Blockchain parameters that are available via API call but not from CloudFormation.

Under the hood these API calls are executed in a Lambda function that is created just for this purpose. This function has an IAM role, to which various permission policies are applied. For efficiency, it is only created once during a deployment, and then shared across all the API calls in the stack.

In order to keep my code well-organized, I’ve broken out the API calls in several places: one to gather data on the network member, and another to gather data for each peer node. And as a security best practice I want the permissions to be scoped as narrowly as possible. That means at each point in my construct where I call the function, I attach a policy that allows access only to the specific member or node being queried, via an explicit identifier.

Here’s the problem: IAM is an eventually consistent service, and thus policy updates are not immediately effective. Typical propagation time is only a few seconds, but it can take longer in certain circumstances. For the first custom API call in a CDK stack this is not an issue. The policy and role is created, and then the Lambda is created, the latter taking over a minute to be fully instantiated because it upgrades its dependencies at launch. However, on subsequent calls, because the Lambda is already warmed up, it runs immediately after the preceding policy update, and about half the time said policy is not yet effective, and the function fails due to a permission error.

It’s the “sometimes it works, sometimes it doesn’t” nature of race conditions that make them so difficult to track down. Thankfully I was able to identify and document my experience and pass it along to the CDK team. Anyone want to take a crack at a solution? I described several possible approaches in my write-up, with the “simple retry logic” approach likely being the best.

Put A Bow On It

Put A Bow On It

Despite writing a bit about CDK nearly two years ago, it’s taken me some time to get a chance to really lean into it. Having now built out a couple real projects, I can confidently say that like it has its rough edges, like any technology, but overall it’s both powerful and fun.

If you’re so inclined, feel free to check out my most recent creation, a construct for deploying a Hyperledger Fabric network on Amazon Managed Blockchain.

# Easy as pie!
HyperledgerFabricNetwork(
    self, 'MyNetwork',
    network_name='MyNetwork',
    member_name='MyMember',
)

For my next trick post I’ll go through one of the aforementioned rough edges I discovered, and how it can hopefully be fixed.

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.

A Number Of Numbers

A Number Of Numbers

Back in my math major days in college, I was introduced to the Online Journal of Integer Sequences. It’s exactly what it says on the tin. As part of a class we were encouraged to contribute, which I did.

A few weeks ago I had another idea for a submission, and to my surprise no one else had added it, so once again I had opportunity to contribute a little piece of Internet history.

Here’s a complete list of the sequences I’ve authored over the years:

If the above isn’t enough online notoriety, check out my only published mathematical work, A Probabilistic View of Certain Weighted Fibonacci Sums. I was only a mild contributor, but still got an authorial credit, which is pretty cool.