Future Reference

Future Reference

Sometimes certain bits of writing resonate in such fundamental ways that you come back to them time and time again. I have a couple of those in my personal brag document, for example. And these two articles, which I share regularly when describing my profession:

Programming Sucks

So You Want To Reform Democracy

I bet I read both of these at least 4 times a year. They do not get old.

Speaking of re-reading, it’s a pretty rare thing for me (for reasons). Off the top of my head, the only books I know for certain I’ve read more than once (and in all cases still only twice) are The Lord of the Rings trilogy, The Hobbit, The Chronicles of Narnia, the Foundation Trilogy, and (somewhat randomly) Thinking in the Future Tense.

Tautology

Tautology

Had to fill out an online form yesterday to register for the chance to upgrade my season tickets to the San Diego Wave. The first draft of this form had some issues…

Misunderstanding of checkboxes and radio buttons is a classic, but inadvertently applying phone number validation to what is definitely not a phone number field is a new one.

Testing is a thing, my friends! Do it.

Ticking Away The Moments

Ticking Away The Moments

Nine years ago today I started this blog with a post that laid out my intentions in creating it. It’s cliché, but true, that a lot has changed in the intervening (near) decade, but for the most part, I think I’ve hewn pretty closely to the original idea, even if my underlying motivations have shifted.

Like many things worth doing, it took some time to find a good rhythm. After two initial posts I went almost 2 years without writing anything. Had a great streak going in 2017, but sputtered out in 2018 and didn’t get going again until early 2020. Since then, though, I’ve been on a roll. Maybe it was turning 40? Maybe it was COVID? Can’t say for sure, but I’ve been happy with my consistency since then (and a growing readership is nice too).

In other wistful, “how time flies!” type subject matter, my youngest kid left for college this past weekend and my oldest starts her junior year with a new location and major. They’re both gonna crush it, I have no doubt.

Go With It

Go With It

Last week I finished The Principles of Product Development Flow, based on a recommendation from the article I wrote about in Fightin’ Words. To say it was relevant to my current line of work is an understatement; I immediately mailed a copy to our de facto development process person.

Luckily for us all, though, there’s an official TL;DR version online. It’s a plethora of pithy principles packed onto one page. Go check it out!

Story Time

Story Time

I’m hiring again, this time for a Director of Engineering. A requirement for application is submitting a cover letter, which apparently has fallen out of favor? Enough so that one candidate DM-ed me on the side to let me know our recruiting tool was misconfigured for having the field non-optional. Nope!

Personally, I enjoy reading cover letters, because they tell me something more than just what a resume can. It’s the same reason I want to hear real stories in interviews. They’re especially useful in revealing the “why” behind an application, which, in the line of work I do, is especially important.

Producing them does require some effort, which is a feature not a bug, but hopefully not too tough because you do document your work, right? And it’s getting even easier with AI, which I have no problem with a person using to get a cover letter started, given a thoughtful prompt that customizes the result to the job, the company to which you’re applying, and unique details about the applicant.

Speaking of “why” and AI, the other day I had a potential candidate ask me why I chose to join my current company. Great question! I put Claude to the test, again giving it my entire blog corpus as reference:

Based on the content of your blog, your reasons for leaving AWS to join RIPL as Chief Technology Officer can be summarized as follows:

1. Mission-driven work: You've expressed a strong interest in using technology to improve people's lives and promote human flourishing. RIPL's mission to work with governments to help them use data, science, and technology to improve policy and lives aligns well with this interest.

2. Intersection of technology and public policy: You mentioned that you've "doubled-down on situating myself at the intersection of tech and politics." RIPL's focus on working with governments to improve policy through technology is a perfect fit for this goal.

3. New challenges: You've indicated a desire for work that isn't a "solved problem." Moving to RIPL likely offers new and unique challenges that weren't present at AWS.

4. Leadership opportunity: The CTO role at RIPL allows you to have a more significant impact on the organization's direction and strategy, which aligns with your growing interest in leadership roles.

5. Building from the ground up: You've expressed enjoyment in creating and building things. A smaller, more focused organization like RIPL might offer more opportunities to build systems and processes from scratch.

6. Applying cloud expertise: Your extensive experience with AWS can be directly applied to help governments leverage cloud technologies for public good.

7. Ethical considerations: You've shown interest in the ethical implications of technology. RIPL's focus on improving government policies likely involves careful consideration of these ethical aspects.

8. Desire for meaningful impact: Your blog suggests a strong desire to make a significant positive impact. The role at RIPL seems to offer a more direct path to seeing the results of your work in terms of improved public policies and services.

While you didn't explicitly list these reasons in a single post, they can be inferred from your various writings about your interests, values, and career trajectory. The move appears to be a natural progression that combines your technical expertise with your interest in public service and desire for impactful work.

Like my request from the other day, that’s pretty accurate! I wonder what other uses I can find for an LLM whose context window is big enough for nearly 9 years of writing…

In A Nutshell

In A Nutshell

Of the various AI-powered chat tools out there, I’ve been leaning into Claude the most. I appreciate their stance on safety for one thing, and I also really like features like document uploads, shareable projects, and artifacts.

Yesterday I exported the entire contents of this blog, loaded it into Claude, and then asked it to summarize my career trajectory.

Based on your blog posts, your career trajectory can be summarized as follows:

1. Early Years (Ages 4-18):
   - Started programming at age 4 on a TI-99/4A computer
   - Self-taught BASIC, then learned C and Pascal
   - Developed various small projects and games

2. College Years (Ages 19-24):
   - Studied mathematics and computer science
   - Worked on academic projects, including computational mathematics

3. Early Career at Defense Contractor (Ages 22-34):
   - Started at TRW (later became Northrop Grumman) right after college
   - Worked primarily with Ada and C
   - Developed algorithms for terrain analysis and flight path optimization
   - Gained experience in mapping software and API design
   - Moved to San Diego and got first taste of technical leadership

4. Mid-Career Transition (Age 35):
   - After nearly 13 years at Northrop Grumman, moved to Everyone Counts
   - Transitioned to working with Java and Perl
   - Became technical lead for the company's voting application

5. Technical Growth Period (Ages 36-37):
   - Expanded skillset to include Angular, Node.js, and Docker
   - Focused on continuous learning and adapting to new technologies

6. AWS and Cloud Focus (Age 38 onwards):
   - Joined Amazon Web Services as a Senior Consultant in the public sector
   - Obtained multiple AWS certifications
   - Worked extensively with cloud technologies and services

7. Leadership Role (Recent):
   - Became a technical manager, leading a team of software engineers
   - Focused on both technical and people management aspects

8. Current Role (as of last blog post):
   - Chief Technology Officer at Research Improving People's Lives (RIPL)
   - Working at the intersection of technology and public policy

Throughout your career, you've consistently demonstrated a passion for learning new technologies, solving complex problems, and gradually taking on more leadership responsibilities. Your trajectory shows a progression from low-level programming to high-level system design and management, with a growing focus on cloud technologies and public sector applications in recent years.

That’s surprisingly accurate! Well done, Claude.

Failure To Communicate

Failure To Communicate

I’m a sucker for travel point programs (and gamification more broadly). I’ve achieved maximum status on American Airlines, and am almost there with Marriott. When you get to the upper tiers there are crossover benefits with other programs, but they require activation. Today I tried taking advantage linking my Marriott status to Hertz, but the website threw a delightful stack trace:

Error processing capillary request: Error converting value {null} to type 'System.DateTime'. Path 'profiles[0].fields.marriottstatusmatchd', line 1, position 792. - at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) at Brierley.HertzModules.Custom.CapillaryIntegration.CapillaryManager.d__8.MoveNext() in C:\devroot\htz-loyalty\code\Portals\CustomModules\CapillaryIntegration\CapillaryManager.cs:line 66 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Brierley.HertzModules.Custom.MemberStat.d__8.MoveNext() in C:\devroot\htz-loyalty\code\Portals\CustomModules\MemberStat.ascx.cs:line 305

Probably not a great thing to leak, because one can learn a lot from a stack trace. For example, I can see their webserver runs on Windows, that it’s based on C# and uses ASP.Net web user control files, and that it uses the Newtonsoft JSON framework. If I were nefarious, and hunting for vulnerabilities, that’s a treasure trove.

Also interesting is the namespace of the module: Brierley. A quick Google search tells me that The Brierley Group is “a recognized innovator in the design of Customer Loyalty programs” and is behind a number of the ones I use every time I travel. Who knew there were companies who specialize in this sort of thing? Learn something new every day I guess.

Time Traveling

Time Traveling

A common rhythm of my career is to catch-up on emails over the weekend. I’ve been appreciative of scheduled send, so that folks don’t get an email from me during non-working hours and assume they need to respond immediately.

However, this might be a new record: 14 emails queued up to go out first thing Monday.

That total may go up depending on how much progress I make on one additional task, which subsequently depends on what Olympic events are on TV this afternoon.

I get that weekend work isn’t for everyone, but I don’t mind it. It’s quiet. Usually no new tasks come up, so I can meaningfully shorten the queue. And finally, it helps alleviate pressure during the week. I’m much more comfortable signing off for the day come Friday afternoon knowing I can knock out a few lingering tasks before Monday ramps up.

Get The Win-Win

Get The Win-Win

I’ve done technical interviewing for more than 10 years now. And apparently I write about it a lot:

Add this post to the cacophony, I guess. Today I want to cover a number of common interview mistakes, and approaches both interviewees and interviewers can take to mitigate them. That’s right, it’s a both/and responsibility. I know there have been times I’ve come to an interview unprepared to give the candidate my best, and the result was possibly missing out on a good hire. Don’t do that.

Mistake 1: Regurgitating resume content

As an interviewee, if you’re asked to introduce yourself, give an overview of your background, or describe the projects you’ve worked on, be sure to bring something unique to your answer beyond what’s on your resume. Otherwise you’re just wasting time that’s better spend on other topics. One idea: have an elevator pitch for yourself.

And interviewers? Avoid this by 1) reviewing the candidate’s resume ahead of time, so you don’t feel the need to ask for an overview, 2) gently interrupting if an answer veers into rote regurgitation, or 3) avoid these kinds of questions altogether. Better to just jump into the meat of the conversation, because interview time is precious. Speaking of…

Mistake 2: Wasting too much time giving introductions

While there’s value in easing into a conversation that’s high-stakes, it does no one any favors if a big chunk of time is spent on introductions that are not data-rich. That goes both for the interviewee and the interviewer. When I led interviews at Amazon I had a script so that I could get through my boilerplate in a crisp 60 seconds. Say hello, set some ground rules, describe the objective of the interview, and then jump in.

Mistake 3: Too much “we” and not enough “I”

Interviews are not the time for false humility. We know doing anything of reasonable complexity requires a team, but what was your role specifically? It’s easy to fall into this trap; if you’re giving the interview, don’t let your candidate go too long before redirecting them to talk more about themselves. If they struggle to give details about their own actions, that’s a concern! Closely related to this next mistake:

Mistake 4: Talking in generalities

This is a fatal mistake of which I’ve written before. Twice. Seriously, tell real stories that actually happened. As an interviewee, this is where preparation is key. Stories are much easier to tell when you’ve captured the details ahead of time. The sorts of behaviors employers are going to ask about aren’t rocket science (unless you’re interviewing for NASA, I suppose). Do a bit of research on the company’s values and prep stories that align to them.

As an interviewer, this is another case where’s it’s totally okay to interrupt and redirect if you think a candidate is drifting into theory. But help them along by phrasing questions effectively (i.e. “tell me about a time when…”) and perhaps even setting expectations in your intro that you want real examples. If you actually do care about a theoretical answer, say so explicitly.

Mistake 5: Telling the same story twice

Good interview teams are going to talk about the stories they heard during a debrief, so there’s no reason to tell the same story to two different interviewers. This gets easier if you’ve done your prep work. At absolute worst, if a story is rich enough to answer multiple questions, make sure you tell it from different angles.

And interviewers, coordinate ahead of time on the questions you’re going to ask. It’s a waste of time for there to be duplication between interview sessions. It’s a completely avoidable but all too common error that doesn’t speak well of your company when it happens.

Mistake 6: Telling stories not aligned to the level of the role

Candidates should understand the requirements of the role, especially as it relates to the degree of seniority, and be able to give examples that illustrate the required complexity and significance. If you’re asked about a time you failed, and you’re interviewing for a leadership role, you better be able to share a situation that involved real consequences. And if you’re aiming to be a senior engineer, I need to hear about more than just the cool code you wrote… how did you lead?

Interviewers, you need to be familiar with expectations for the role as well, so you can identify these “weaksauce stories” when you hear them. Sometimes follow-up questions can save them, but often I find that it’s better to step in and ask if the candidate has another example.

My favorite way to suss out the significance of a story is to ask a candidate about the people they were talking to at the time: only other engineers at their level? Related roles like product managers or salespeople? Managers? Directors? What about people outside their company, were they interacting with customers directly? Vendors? Other stakeholders? Answers to these questions will tell you a lot about where a person fit in their prior organizations and if they’ll be suited for the role you’re offering.

Mistake 7: Focusing too much on technology

Obviously having the technical skills required of the role is important, but just as critical is the leadership you show in applying those skills. So be sure to talk about those parts of the job too. Keep your stories balanced.

Interviewers also have responsibility here, to keep the questions they ask balanced between technical and behavioral. Amazon did a great job of this; in my experience they put more weight on behaviors aligned to their Leadership Principles during their interviews than any other tech company. Having done over 150 interviews during my tenure there (about half as a Bar Raiser), it’s a lesson I won’t soon forget.

Mistake 8: Failing to discuss results

I love the STAR method for structuring stories: Situation, Task, Action, Result. But each of these parts of the story are not equally important: they grow in significance from left to right. Results are the most critical parts of a story to tell, so make sure you don’t spend too much time describing the situation alone. What was the outcome? If you can share specific numbers, even better (you did prepare your stories, right?)

Interviewers can easily help their candidates here by always asking about results if they’re not shared proactively. Don’t commit this next common error:

Mistake 9: Rushing too quickly to the next question

Stories have layers; take the time to dig into them (10 minutes per story is my rule of thumb) with good follow-ups before moving on to your next prepared question. Sometimes the perfect follow-up emerges organically, but if it doesn’t, keep these classics at the ready:

  • How did it work out?
  • What did you learn?
  • How would you do things differently next time?
  • Tell me more!

Also, don’t be afraid of a bit of silence to be sure the candidate is completely done with their story. In graduate school I was trained to pause for 8 full seconds, a practice I still use today. Especially don’t fill silence by doing the following:

Mistake 10: Leading the witness

Interviewers, keep your questions open-ended, and resist the urge to prompt candidates on the “correct” (from your perspective) answer. Let them give the answer they want to give, because that’s what you’re there to evaluate. I recognize this can be difficult, especially if a candidate is struggling; human nature is to want to help. Gentle nudges are okay, but it’s easy to give too much.

Full disclosure: I’m bad at this one. It goes against what are normally healthy collaborative impulses. At least be aware of the tendency. Speaking of fighting against otherwise healthy tendencies:

Mistake 11: Providing too much real-time feedback on answer quality

This last one might be controversial, but I stand by it. Candidates sometimes want to get feedback on how they’re doing, but doing so is tricky territory. For one, it’s not a good use of time. Second, off-the-cuff judgments on candidates are rarely as helpful as thoughtful consideration, so an answer given in real-time might not be a good one. Finally, you don’t want to give a false impression that you might have to go back on later if you decide not to proceed with them.

I’m not saying being completely stoic, nor am I saying not to give some gentle redirections if you’re not getting what you need (as I’ve said throughout this post), but if asked directly, keep judgments on answer quality to yourself. Depending on the situation, I either use some version of “I heard what I needed to” and move on, or ask a specific follow-up if I think there’s more to discover.

Fightin’ Words

Fightin’ Words

Well, this is fairly provocative: Story Points Are Pointless, Measure Queues.

I’ve advocated for story points plenty of times, but I do see the article’s point. Estimation is hard. And I like the notion that in absence of other data, just having a count of tasks yet to be completed is a decent approximation of remaining work.

And perhaps it rightly centers the definition of the tasks themselves as the important part of estimation, versus the assignment of a numeric value to said tasks? A question well-asked is half-answered, or something like that?

It also made me think of a tension I’ve seen for much of my career. Product folks tend to think in terms of features and user outcomes. As they should, for outcomes is what ultimately matters to a customer. But estimating “features” is a fool’s errand. Engineers need to think in terms of tasks: add X, build Y, modify Z, etc. The latter are (generally) easier to estimate. And, as the article argues, if sufficiently broken down, don’t really need to be estimated at all, just counted.

Making the above work, though, requires that engineers own that translation of user stories to tasks (and consequent planning thereof). That takes work, no doubt, but probably less work in the long-run than arguing about numbers.