Irrational Exuberancehttps://lethain.com/Recent content on Irrational ExuberanceHugo -- gohugo.ioen-usWill LarsonFri, 23 May 2025 04:00:00 -0700Stuff I learned at Carta.https://lethain.com/stuff-learned-at-carta/Fri, 23 May 2025 04:00:00 -0700https://lethain.com/stuff-learned-at-carta/<p>Today&rsquo;s my last day at Carta, where I got the chance to serve as their CTO for the past two years. I&rsquo;ve learned <em>so much</em> working there, and I wanted to end my chapter there by collecting my thoughts on what I learned. (I am heading somewhere, and will share news in a week or two after firming up the communication plan with my new team there.)</p> <p>The most important things I learned at Carta were:</p> <ul> <li> <p><strong>Working in the details</strong> &ndash; if you took a critical lens towards my historical leadership style, I think the biggest issue you&rsquo;d point at is my being too comfortable operating at a high level of abstraction. Utilizing the expertise of others to fill in your gaps is a valuable skill, but&ndash;like any single approach&ndash;it&rsquo;s limiting when utilized too frequently.</p> <p>One of the strengths of Carta&rsquo;s &ldquo;house leadership style&rdquo; is expecting leaders to go deep into the details to get informed and push pace. What I practiced there turned into the pieces on <a href="https://lethain.com/testing-strategy-iterative-refinement/">strategy testing</a> and <a href="https://lethain.com/domain-expertise/">developing domain expertise</a>.</p> </li> <li> <p><strong>Refining my approach to engineering strategy</strong> &ndash; over the past 18 months, I&rsquo;ve written a book on engineering strategy (posts are all in <a href="https://lethain.com/tags/eng-strategy-book/">#eng-strategy-book</a>), with initial chapters coming available for early release with O&rsquo;Reilly next month. Fingers crossed, the book will be released in approximately October.</p> <p>Coming into Carta, I already had <em>much</em> of my core thesis about how to do engineering strategy, but Carta gave me a number of complex projects to practice on, and excellent people to practice with: thank you to Dan, Shawna and Vogl in particular! More on this project in the next few weeks.</p> </li> <li> <p><strong><a href="https://lethain.com/extract-the-kernel/">Extract the kernel</a></strong> &ndash; everywhere I&rsquo;ve ever worked, teams have struggled understanding executives. In every case, the executives <em>could be clearer</em>, but it&rsquo;s not particularly interesting to frame these problems as something the executives need to fix. Sure, that&rsquo;s true they could communicate better, but that framing makes you powerless, when you have a great deal of power to understand confusing communication. After all, even good communicators communicate poorly sometimes.</p> </li> <li> <p><strong>Meaningfully adopting LLMs</strong> &ndash; a year ago I wrote up <a href="https://lethain.com/mental-model-for-how-to-use-llms-in-products/">notes on adopting LLMs in your products</a>, based on what we&rsquo;d learned so far. Since then, we&rsquo;ve learned a lot more, and LLMs themselves have significantly improved. Carta has been using LLMs in real, business-impacting workflows for over a year. That&rsquo;s continuing to expand into solving more complex internal workflows, and even more interestingly into creating net-new product capabilities that ought to roll out more widely in the next few months (currently released to small beta groups).</p> <p>This is the first major technology transition that I&rsquo;ve experienced in a senior leadership role (since I was earlier in my career when mobile internet transitioned from novelty to commodity). The immense pressure to adopt faster, combined with the immense uncertainty if it&rsquo;s a meaningful change or a brief blip was a lot of fun, and <a href="https://lethain.com/llm-adoption-strategy/">was the inspiration for this strategy document around LLM adoption</a>.</p> </li> <li> <p><strong>Multi-dimensional tradeoffs</strong> &ndash; a phrase that Henry Ward uses frequent is that &ldquo;everyone&rsquo;s right, just at a different altitude.&rdquo; That idea resonates with me, and meshes well with the ideas of <a href="https://lethain.com/multi-dimensional-tradeoffs/">multi-dimensional tradeoffs</a> and <a href="https://lethain.com/layers-of-context/">layers of context</a> that I find improve decision making for folks in roles that require making numerous, complex decisions. Working at Carta, these ideas formalized from something I intuited into something I could explain clearly.</p> </li> <li> <p><strong><a href="https://lethain.com/navigators/">Navigators</a></strong> &ndash; I think our most successful engineering strategy at Carta was rolling out the Navigator program, which ensured senior-most engineers had context and direct representation, rather than relying exclusively on indirect representation via engineering management. Carta&rsquo;s engineering managers are excellent, but there&rsquo;s always something lost as discussions extend across layers. The Navigator program probably isn&rsquo;t a perfect fit for particularly small companies, but I think any company with more than 100-150 engineers would benefit from something along these lines.</p> </li> <li> <p><strong><a href="https://lethain.com/quality/">How to create software quality</a></strong> &ndash; I&rsquo;ve evolved my thinking about software quality quite a bit over time, but Carta was particularly helpful in distinguishing why some pieces of software are so hard to build despite having little-to-no scale from a data or concurrency perspective. These systems, which I label as &ldquo;high essential complexity&rdquo;, deserve more credit for their complexity, even if they have little in the way of complexity from infrastructure scaling.</p> </li> <li> <p><strong>Shaping eng org costs</strong> &ndash; a few years ago, I wrote about <a href="https://infraeng.dev/efficiency/">my mental model for managing infrastructure costs</a>. At Carta, I got to refine my thinking about engineering salary costs, with most of those ideas getting incorporated in the <a href="https://lethain.com/private-equity-strategy/">Navigating Private Equity ownership</a> strategy, and the <a href="https://lethain.com/engineering-cost-model/">eng org seniority mix model</a>.</p> <p>The three biggest levers are (1) &ldquo;N-1 backfills&rdquo;, (2) requiring a business rationale for promotions into senior-most levels, and (3) shifting hiring into cost efficient hiring regions. None of these are the sort of inspiring topics that excite folks, but they are all essential to the long term stability of your organization.</p> </li> <li> <p><strong>Explaining engineering costs to boards/execs</strong> &ndash; Similarly, I finally have a clear perspective on how to represent R&amp;D investment to boards in the same language that they speak in, <a href="https://lethain.com/public-company-comparables/">which I wrote up here</a>, and know how to do it quickly without relying on any manually curated internal datasets.</p> </li> <li> <p>Lots of smaller stuff, like the <a href="https://lethain.com/no-wrong-doors/">no wrong doors policy</a> for routing colleagues to appropriate channels, <a href="https://lethain.com/how-to-get-more-headcount/">how to request headcount</a> in a way that is convincing to executives, <a href="https://lethain.com/load-bearing-career-minded-act-two-rationales/">Act Two rationales</a> for how people&rsquo;s motivations evolve over the course of long careers (and my own personal career mission to <a href="https://lethain.com/advancing-the-industry/">advance the industry</a>, why <a href="https://lethain.com/friction-vs-velocity/">friction isn&rsquo;t velocity</a> even though many folks act like it is.</p> </li> </ul> <p>I&rsquo;ve also learned quite a bit about venture capital, fund administration, cap tables, non-social network products, operating a multi-business line company, and various operating models. Figuring out how to sanitize those learnings to share the interesting tidbits without leaking internal details is a bit too painful, so I&rsquo;m omitting them for now. Maybe some will be shareable in four or five years after my context goes sufficiently stale.</p> <p>As a closing thought, I just want to say how much I&rsquo;ve appreciated the folks I&rsquo;ve gotten to work with at Carta. From the executive team (Ali, April, Charly, Davis, Henry, Jeff, Nicole, Vrushali) to my directs (Adi, Ciera, Dan, Dave, Jasmine, Javier, Jayesh, Karen, Madhuri, Sam, Shawna) to the navigators (there&rsquo;s a bunch of y&rsquo;all). The people truly are always the best part, and that was certainly true at Carta.</p>systems-mcp: generate systems models via LLMhttps://lethain.com/systems-mcp/Sun, 11 May 2025 06:00:00 -0700https://lethain.com/systems-mcp/<p>Back in 2018, I wrote <a href="https://github.com/lethain/systems"><code>lethain/systems</code></a> as a domain-specific language for writing runnable systems models, and introduced it with <a href="https://lethain.com/modeling-hiring-funnel-systems/">this blog post modeling a hiring funnel</a>. While it&rsquo;s far from a perfect system, I&rsquo;ve gotten a lot of value out of it over the last seven years, because it allows me to maintain systems models in version control.</p> <p>As I&rsquo;ve been playing with writing <a href="https://modelcontextprotocol.io/introduction">Model Context Protocol</a> (MCP) servers, one I&rsquo;ve been thinking about frequently is one to help writing <code>systems</code> syntax, and I finally put that together in the <a href="https://github.com/lethain/systems-mcp/"><code>lethain/systems-mcp</code></a> repository.</p> <p>More detailed installation and usage instructions are in the GitHub repository, so I&rsquo;ll just share a couple of screenshots and comments here. Starting with the <code>load_systems_documentation</code> tool which loads a copy of <code>lethain/systems/README.md</code> and <a href="https://raw.githubusercontent.com/lethain/systems-mcp/refs/heads/main/docs/examples.md">a file with example systems</a> into the context window.</p> <p><img src="https://lethain.com/static/blog/strategy/sys-mcp-load-prompt.png" alt="The image contains text and code snippets related to creating a systems model for user acquisition in a social network. It includes a brief description of systems modeling tools and a specification for modeling user flow from initial discovery to active contribution within the network."></p> <p>The biggest challenge of properly writing DSLs with an LLM is providing enough in-context learning (ICL) examples, and I think the idea of providing tools that are specifically designed to provide that context is a very interesting idea. Eventually I imagine there will be generalized tools for this, e.g. a search index of the best ICL examples for a wide variety of DSLs. Until then, my guess is that this sort of tool is particularly valuable.</p> <p>The second tool is <code>run_systems_model</code> which passes the DSL (and an optional parameter for number of rounds) to the tool and then returns the result.</p> <p><img src="https://lethain.com/static/blog/strategy/sys-mcp-load-artifact.png" alt="The image shows an interactive chart and data selection interface for a social network user acquisition model, allowing the user to select and display various metrics such as user types and funnel stages. The chart visualizes data over simulation rounds, indicating trends among different user segments like AwareUsers, CasualUsers, PowerUsers, and EngagedUsers."></p> <p>I experimented with interface design here, initially trying to return a rendered chart of the results, but ultimately even multi-modal models are just much better at working with text than with images. This meant that I had the best results returning JSON of the results and then having the LLM build a tool for interacting with the results.</p> <p>Altogether, a fun little experiment, and another confirmation in my mind that the most interesting part of designing MCPs today is deciding where to introduce and eliminate complexity from the LLM. Introduce too little and the tool lacks power; eliminate too little and the combination rarely works.</p>How to provide feedback on documents.https://lethain.com/providing-feedback-on-writing/Sun, 11 May 2025 04:00:00 -0700https://lethain.com/providing-feedback-on-writing/<p>At Carta, we recently ran a reading group for <a href="https://www.amazon.com/Facilitating-Software-Architecture-Empowering-Architectural-ebook/dp/B0DMHGWCPN/"><em>Facilitating Software Architecture</em></a> by Andrew Harmel-Law. We already <em>loosely</em> followed the ideas of an architectural advice process (from this <a href="https://martinfowler.com/articles/scaling-architecture-conversationally.html">2021 article</a> by the same Andrew Harmel-Law), but in practice we found that internal tech spec and architecture decision record (ADR) authors tended to exclusively share their documents locally within their team rather than more widely.</p> <p>As we asked authors why they preferred sharing locally, the most common answer was that they got enough feedback from their team that they didn&rsquo;t want to pay the time overhead of sharing widely. The wider feedback wasn&rsquo;t necessarily bad or combative. It just wasn&rsquo;t good enough to compensate for the additional time it cost to process. This made sense from the authors&rsquo; perspectives, but didn&rsquo;t work well for me from the executive perspective, as I was seeing teams make misaligned decisions due to lack of cross-team communication.</p> <p>As one step in reducing the overhead of sharing documents widely, I wrote up and shared this recommended process for providing feedback on documents:</p> <ol> <li> <p>Before starting, remember that the goal of providing feedback on a document is to help the author. Optimizing for anything else, even if it&rsquo;s a worthy cause, discourages authors from sharing their future writing. If you prioritize something other than helping the author, you are discouraging them from sharing future work.</p> </li> <li> <p>Start by skimming the document to understand its structure and where various kinds of topics are addressed. Why? This helps avoid giving feedback on ways the document&rsquo;s actual structure diverges from how you imagined it would be structured. It also reduces questions about topics that are answered later in the document.</p> <p>Both of these sorts of feedback are a distraction during a discussion on a tech spec. In general, it&rsquo;s better to avoid them. If you notice an author making the same significant structural mistake over several ADRs, it&rsquo;s worth delivering that feedback separately.</p> </li> <li> <p>After skimming, reread the document, leaving comments with concerns. Each comment should include these details:</p> <ol> <li>What your suggested change or concern is</li> <li>Why you believe this is meaningful to address</li> <li>How important this seems (from ignorable nitpick to critical)</li> </ol> </li> <li> <p>If you find yourself leaving more than three or four issues, then you should either raise your threshold for commenting or you should schedule time with the individual to talk over the feedback. If the document is unreasonably weak, then it&rsquo;s appropriate to nudge their leadership to dig into what&rsquo;s happening on that team.</p> </li> </ol> <p>The most important idea behind these steps is that your goal as a feedback giver is to <em>help the document&rsquo;s author</em>. It is not to protect <em>your</em> team&rsquo;s strategy or platform. It is not to optimize for <em>your</em> goals. It&rsquo;s to help the author. This might feel wrong, but ultimately optimizing for anything else will lead to an environment where sharing widely is an irrational behavior.</p> <p>As a final aside, I think the user experience around commenting on documents is fundamentally wrong in most document editors. For example, Google Docs treats individual comments as first-order objects, similarly to how old version control systems like <a href="https://en.wikipedia.org/wiki/Concurrent_Versions_System">CVS</a> tracked changes to individual files without tracking an overall state of the project. Ultimately, you want to collect all your comments into a bundle, then review that bundle for consistency and duplicates, and then submit that bundle as commentary, but editors don&rsquo;t support that flow particularly well.</p>Public company comparables.https://lethain.com/public-company-comparables/Sat, 03 May 2025 07:00:00 -0700https://lethain.com/public-company-comparables/<p>A few years ago I wrote about <a href="https://lethain.com/profit-and-loss-statement/">reading a Profit &amp; Loss statement</a>, which is a foundational executive skill. I also subsequently wrote about <a href="https://lethain.com/measuring-engineering-organizations/">ways to measure your engineering organization</a>. Despite having written those, I still spend a lot of time wondering about effective ways to represent an engineering organization to your board of directors.</p> <p>Over the past few years, one of the most useful charts I&rsquo;ve found for explaining an R&amp;D organization is a scatterplot of R&amp;D spend as a % of margin versus YoY growth of last twelve months (LTM) revenue. Unlike so many other measures, this is an explicit measure of your R&amp;D organization value as an investment relative to peer organizations.</p> <p>Until recently, I assumed building this dataset required reading financial filings but my strategic finance partner at Carta, Tyler Braslow, pointed out that you can get all of this data for the tech section from <a href="https://meritechanalytics.com/">Meritech Analytics</a>, for free.</p> <p><img src="https://lethain.com/static/blog/2025/maritech-cover.png" alt="The image shows a webpage for Meritech Analytics, which offers a public software benchmarking solution with features for analyzing SaaS company metrics. It includes options to sign up or explore features, and provides tools like regression analysis for users."></p> <p>When you login to Meritech, you&rsquo;re dropped into a table of <a href="https://app.meritechanalytics.com/comps-table">public company comparables for tech companies</a>. This is the exact dataset I&rsquo;d been looking for to build this chart.</p> <p><img src="https://lethain.com/static/blog/2025/maritech-sheet.png" alt="The image displays a table from the Meritech Software Index showing various metrics such as market cap, enterprise value, and percentage price changes for different companies like Adobe and AppLovin. It also includes averages (mean and median) for these metrics over specified periods."></p> <p>After logging in, you can then copy the contents of that table into a Google Sheets spreadsheet or Excel, or whatever you&rsquo;re most comfortable with.</p> <p><img src="https://lethain.com/static/blog/2025/maritech-in-gsheets.png" alt="The image shows a spreadsheet from Google Sheets titled &ldquo;PublicComps,&rdquo; displaying financial data for various companies, including columns for price changes, market capitalization, enterprise value, and several valuation metrics. The data is presented with calculations for mean and median values across the companies listed."></p> <p>Within that sheet, the columns you care about are:</p> <ul> <li>% YoY Growth LTM Rev (column <code>Q</code> for me) &ndash; how much &ldquo;last twelve months revenue&rdquo; has grown year over year, as a percentage</li> <li>% LTM Margins for R&amp;D (column <code>U</code> for me) &ndash; how much R&amp;D spend is as a percentage of last twelve months margin</li> <li>LTM Revenue (column <code>O</code> for me) &ndash; although I don&rsquo;t show this in the scatterplot, I find this one useful for debugging outlier values</li> </ul> <p>Hiding the other columns gives you a much simpler table.</p> <p><img src="https://lethain.com/static/blog/2025/maritech-hidden-sheet.png" alt="The image is a table listing companies along with their Last Twelve Months (LTM) Revenue, Year-over-Year (YoY) Growth percentage, and LTM R&amp;D margins. Notably, Adobe has the highest LTM Revenue at $21,505 with an 11% YoY growth and 14% R&amp;D margin."></p> <p>From that table, you&rsquo;re then able to build the scatterplot. Note that being &ldquo;higher&rdquo; means your R&amp;D spend as a percentage of LTM margin is higher, which is a bad thing. The best companies are to the bottom and to the right; the worst companies are to the top and to the left.</p> <p><img src="https://lethain.com/static/blog/2025/maritech-rd-spend-rev.png" alt="The scatter plot displays the relationship between R&amp;D Spend as a percentage of margin and Year-over-Year Revenue Growth, with data points clustered mostly in the 10%-30% range for both axes. Each point is labeled with a percentage representing the R&amp;D Spend as a percentage of margin."></p> <p>With this chart as a starting point, you can then plot your company in and show where you stand. You could also show how your company&rsquo;s position in the chart has evolved over time: hopefully improving. Finally, you might want to cull some of these data points to better determine your public company comparables. The Meritech dataset has 106 entries, but you might prefer a more representative thirty entries.</p>How to filter out old email from inboxhttps://lethain.com/filter-old-gmail-messages/Sat, 03 May 2025 06:00:00 -0700https://lethain.com/filter-old-gmail-messages/<p>Every few years I take a pass at reducing the chaos in my personal inboxes. There are simply too many emails to deal with, and that generally leads to me increasingly failing to follow up on important email.</p> <p>Up to this point, my strategy has largely been filtering out emails that I <em>never</em> want to read. But there&rsquo;s another category of email which is stuff I often want to read when it&rsquo;s fresh, but never want to read after it&rsquo;s fresh. For example, calendar reminders, <em>some</em> mailing lists, <em>some</em> news letters, etc.</p> <p>I decided to figure out how I could setup a system where I could mark a number of things as &ldquo;filter three days after receipt&rdquo;. This is a nice compromise, because I <em>do</em> want to see those things, but I <em>don&rsquo;t</em> want to have to remember to archive them after the fact.</p> <p>You can write a search query for this in GMail:</p> <pre><code>from:(calendar-notification@google.com) older_than:3d </code></pre> <p>However, if you try to create a GMail filter using that, it turns the <code>older_than:3d</code> into a fixed point in time rather than doing what you want.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-filter.png" alt="The image shows a Gmail search filter setup, looking for emails from &ldquo;calendar-notification@google.com&rdquo; that are older than three days and have a size greater than a specified amount, dated within one day of May 3, 2025. Options to filter by attachments and exclude chats are available, with &ldquo;Create filter&rdquo; and &ldquo;Search&rdquo; buttons at the bottom."></p> <p>It seems that this is unsolvable within GMail itself. However, some quick searching suggested it was possible to create a Google App Script to solve this, and asked <a href="https://claude.ai/share/c87e3409-46f1-4389-9b60-dd3f1386fed3">Claude to write the script for me</a>.</p> <p>Following those instructions, I went to <a href="https://script.google.com/">script.google.com</a>, which I have not gone to in many years. I edited the generated script from Claude to use the tag &ldquo;TempMsg&rdquo;, to archive messages (as originally it had those commented out), and to limit itself to the first fifty items matching that tag. You can find the full code <a href="https://gist.github.com/lethain/b3766a24c77925f54b38345b9dd7f544">in this gist</a>.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-script-setup.png" alt="This image provides instructions on setting up a Google Apps Script to filter Gmail messages with a tag older than three days. It includes steps for opening Gmail settings and creating a new script project."></p> <p>I attempted to run this as is, and got an error message that I needed to grant permissions. That requires three clicks within the Google Scripts UI.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-permissions.png" alt="The image shows a Google Apps Script interface where a user is adding the Gmail API service to a project. Red arrows highlight the action of selecting the Gmail API from a list of services and the &ldquo;Add&rdquo; button."></p> <p>This also requires approving the somewhat scary message that I trust myself.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-auth.png" alt="The image displays a warning that Google hasn&rsquo;t verified a specific app, advising users not to use it until the developer verifies it with Google due to its request for sensitive account information. Users have the option to return to safety or proceed with caution if they trust the developer."></p> <p>From there I tried to run this script, and it failed because the <code>TempMsg</code> tag doesn&rsquo;t exist in my inbox.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-run-failed.png" alt="The image shows a script written in JavaScript for Google Apps Script, designed to filter Gmail messages older than three days with a specific label. The execution log indicates that the label &ldquo;TempMsg&rdquo; was not found during the script&rsquo;s execution."></p> <p>So I went ahead and created that tag, and setup some filters to assign that tag to certain email senders.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-add-filter.png" alt="This image shows the Gmail filter creation settings page, where emails from &ldquo;calendar-notification@google.com&rdquo; are set to be labeled as &ldquo;TempMsg.&rdquo; Options for other actions like skipping the inbox, marking as read, or forwarding are available but not selected."></p> <p>After that, I was able to run the script and it worked properly. Note that I convinced myself that it was failing for a bit, because it doesn&rsquo;t remove messages from the past three days. That is exactly how it&rsquo;s supposed to work, but I would run it and then see messages with the tag there and think it was failing. Woops.</p> <p>After convincing myself it was working, I added a periodic trigger to run this.</p> <p><img src="https://lethain.com/static/blog/2025/gmail-add-trigger.png" alt="This image shows a Google Cloud Platform interface for adding a time-driven trigger to run the function &ldquo;filterOldGmailMessages&rdquo; daily between midnight and 1am, with immediate failure notifications."></p> <p>I now have this running on a daily basis, and it&rsquo;s given me a nice new tool for managing my email a bit better. After verifying it, I also used the tag manager to &ldquo;hide&rdquo; this tag in the inbox, so I don&rsquo;t have to see the <code>TempMsg</code> tag everywhere. If I ever need to debug things, I can always make it visible again.</p>How should Stripe deprecate APIs? (~2016)https://lethain.com/api-deprecation-strategy/Thu, 24 Apr 2025 06:00:00 -0700https://lethain.com/api-deprecation-strategy/<p>While Stripe is a widely admired company for things like its creation of the <a href="https://lethain.com/stripe-sorbet/">Sorbet typer project</a>, I personally think that Stripe&rsquo;s most interesting strategy work is also among its most subtle: its willingness to significantly prioritize API stability.</p> <p>This strategy is almost invisible externally. Internally, discussions around it were frequent and detailed, but mostly confined to dedicated API design conversations. API stability isn&rsquo;t just a technical design quirk, it&rsquo;s a foundational decision in an API-driven business, and I believe it is one of the unsung heroes of Stripe&rsquo;s business success.</p> <div class="bg-light-gray br4 ph3 pv1"> <p><em>This is an exploratory, draft chapter for a book on engineering strategy that I&rsquo;m brainstorming in <a href="https://lethain.com/tags/eng-strategy-book/">#eng-strategy-book</a>.</em> <em>As such, some of the links go to other draft chapters, both published drafts and very early, unpublished drafts.</em></p> </div> <h2 id="reading-this-document">Reading this document</h2> <p>To apply this strategy, start at the top with <em>Policy</em>. To understand the thinking behind this strategy, read sections in reverse order, starting with <em>Explore</em>.</p> <p>More detail on this structure in <a href="https://lethain.com/readable-engineering-strategy-documents">Making a readable Engineering Strategy document</a>.</p> <h2 id="policy--operation">Policy &amp; Operation</h2> <p>Our policies for managing API changes are:</p> <ul> <li> <p><strong>Design for long API lifetime.</strong> APIs are not inherently durable. Instead we have to design thoughtfully to ensure they can support change. When designing a new API, build a test application that doesn&rsquo;t use this API, then migrate to the new API. Consider how integrations might evolve as applications change. Perform these migrations yourself to understand potential friction with your API. Then think about the future changes that <em>we</em> might want to implement on our end. How would those changes impact the API, and how would they impact the application you&rsquo;ve developed.</p> <p>At this point, take your API to API Review for initial approval as described below. Following that approval, identify a handful of early adopter companies who can place additional pressure on your API design, and test with them before releasing the final, stable API.</p> </li> <li> <p><strong>All new and modified APIs must be approved by API Review.</strong> API changes may not be enabled for customers prior to API Review approval. Change requests should be sent to <code>api-review</code> email group. For examples of prior art, review the <code>api-review</code> archive for prior requests and the feedback they received.</p> <p>All requests must include a written proposal. Most requests will be approved asynchronously by a member of API Review. Complex or controversial proposals will require live discussions to ensure API Review members have sufficient context before making a decision.</p> </li> <li> <p><strong>We never deprecate APIs without an unavoidable requirement to do so.</strong> Even if it&rsquo;s technically expensive to maintain support, we incur that support cost. To be explicit, we define API deprecation as <em>any</em> change that would require customers to modify an existing integration.</p> <p>If such a change were to be approved as an exception to this policy, it must first be approved by the API Review, followed by our CEO. One example where we granted an exception was the deprecation of TLS 1.2 support due to PCI compliance obligations.</p> </li> <li> <p><strong>When significant new functionality is required, we add a new API.</strong> For example, we created <a href="https://docs.stripe.com/api/subscriptions"><code>/v1/subscriptions</code></a> to support those workflows rather than extending <a href="https://docs.stripe.com/api/charges"><code>/v1/charges</code></a> to add subscriptions support.</p> </li> </ul> <div class="bg-light-gray br4 ph3 pv1"> <p>With the benefit of hindsight, a good example of this policy in action was the introduction of the Payment Intents APIs to maintain compliance with <a href="https://support.stripe.com/questions/payment-intents-api-requirement-for-strong-customer-authentication-%28sca%29-compliance">Europe&rsquo;s Strong Customer Authentication</a> requirements. Even in that case the <code>charge</code> API continued to work as it did previously, albeit only for non-European Union payments.</p> </div> <ul> <li> <p><strong>We manage this policy&rsquo;s implied technical debt via an API translation layer.</strong> We release changed APIs into versions, tracked in our <a href="https://docs.stripe.com/changelog">API version changelog</a>. However, we only maintain one implementation internally, which is the implementation of the latest version of the API. On top of that implementation, a series of version transformations are maintained, which allow us to support prior versions without maintaining them directly. While this approach doesn&rsquo;t <em>eliminate</em> the overhead of supporting multiple API versions, it significantly reduces complexity by enabling us to maintain just a single, modern implementation internally.</p> <p>All API modifications <em>must</em> also update the version transformation layers to allow the new version to coexist peacefully with prior versions.</p> </li> <li> <p><strong>In the future, SDKs may allow us to soften this policy.</strong> While a significant number of our customers have direct integrations with our APIs, that number has dropped significantly over time. Instead, most new integrations are performed via one of our official API SDKs.</p> <p>We believe that in the future, it may be possible for us to make more backwards incompatible changes because we can absorb the complexity of migrations into the SDKs we provide. That is certainly <em>not</em> the case yet today.</p> </li> </ul> <h2 id="diagnosis">Diagnosis</h2> <p>Our diagnosis of the impact on API changes and deprecation on our business is:</p> <ul> <li> <p>If you are a small startup composed of mostly engineers, integrating a new payments API seems easy. However, for a small business without dedicated engineers—or a larger enterprise involving numerous stakeholders—handling external API changes can be particularly challenging.</p> <p>Even if this is only marginally true, <a href="https://lethain.com/api-deprecation-model/">we&rsquo;ve modeled the impact of minimizing API changes</a> on long-term revenue growth, and it has a significant impact, unlocking our ability to benefit from other churn reduction work.</p> </li> <li> <p>While we believe API instability directly creates churn, we also believe that API stability directly retains customers by increasing the migration overhead even if they wanted to change providers. Without an API change forcing them to change their integration, we believe that hypergrowth customers are particularly unlikely to change payments API providers absent a concrete motivation like an API change or a payment plan change.</p> </li> <li> <p>We are aware of relatively few companies that provide long-term API stability in general, and particularly few for complex, dynamic areas like payments APIs. We can&rsquo;t assume that companies that make API changes are ill-informed. Rather it appears that they experience a meaningful technical debt tradeoff between the API provider and API consumers, and aren&rsquo;t willing to consistently absorb that technical debt internally.</p> </li> <li> <p>Future compliance or security requirements—along the lines of our upgrade from TLS 1.2 to TLS 1.3 for PCI—may necessitate API changes. There may also be new tradeoffs exposed as we enter new markets with their own compliance regimes. However, we have limited ability to predict these changes at this point.</p> </li> </ul>Systems model of API deprecationhttps://lethain.com/api-deprecation-model/Thu, 24 Apr 2025 05:00:00 -0700https://lethain.com/api-deprecation-model/<p>In <a href="https://lethain.com/api-deprecation-strategy/">How should Stripe deprecate APIs?</a>, the diagnosis depends on the claim that deprecating APIs is a significant cause of customer churn. While there is internal data that can be used to correlate deprecation with churn, it&rsquo;s also valuable to build a model to help us decide if we believe that correlation and causation are aligned in this case.</p> <p>In this chapter, we&rsquo;ll cover:</p> <ol> <li>What we learn from modeling API deprecation&rsquo;s impact on user retention</li> <li>Developing a system model using the <a href="https://github.com/lethain/systems">lethain/systems</a> package on GitHub. That model <a href="https://github.com/lethain/eng-strategy-models/blob/main/APIDeprecationModel.ipynb">is available in the lethain/eng-strategy-models</a> repository</li> <li>Exercising that model to learn from it</li> </ol> <p>Time to investigate whether it&rsquo;s reasonable to believe that API deprecation is a major influence on user retention and churn.</p> <div class="bg-light-gray br4 ph3 pv1"> <p><em>This is an exploratory, draft chapter for a book on engineering strategy that I’m brainstorming in</em> <em><a href="https://lethain.com/tags/eng-strategy-book/">#eng-strategy-book</a>.</em> <em>As such, some of the links go to other draft chapters, both published drafts and very early, unpublished drafts.</em></p> </div> <h2 id="learnings">Learnings</h2> <p>In an initial model that has 10% baseline for customer churn per round, reducing customers experiencing API deprecation from 50% to 10% per round only increases the steady state of integrated customers by about 5%.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-model-2.png" alt="Impact of 10% and 50% API deprecation on integrated customers"></p> <p>However, if we eliminate the baseline for customer churn entirely, then we see a massive difference between a 10% and 50% rate of API deprecation.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-model-4.png" alt="Impact of rates of API deprecation with zero baseline churn"></p> <p>The biggest takeaway from this model is that eliminating API-deprecation churn alone won&rsquo;t significantly increase the number of integrated customers. However, we also can&rsquo;t fully benefit from reducing baseline churn without simultaneously reducing API deprecations. Meaningfully increasing the number of integrated customers requires lowering both sorts of churn in tandem.</p> <h2 id="sketch">Sketch</h2> <p>We&rsquo;ll start by sketching the model&rsquo;s happiest path: potential customers flowing into engaged customers and then becoming integrated customers. This represents a customer who decides to integrate with Stripe&rsquo;s APIs, and successfully completes that integration process.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-simple.png" alt="Happiest path for Stripe API integration"></p> <p>Business would be good if that were the entire problem space. Unfortunately, customers do occasionally churn. This churn is represented in two ways:</p> <ol> <li><code>baseline churn</code> where integrated customers leave Stripe for any number of reasons, including things like dissolution of their company</li> <li><code>experience deprecation</code> followed by <code>deprecation-influenced churn</code>, which represent the scenario where a customer decides to leave after an API they use is deprecated</li> </ol> <p>There is also a flow for <code>reintegration</code>, where a customer impacted by API deprecation can choose to update their integration to comply with the API changes.</p> <p>Pulling things together, the final sketch shows five stocks and six flows.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-full.png" alt="Final version of systems model for API deprecation"></p> <p>You could imagine modeling additional dynamics, such as recovery of churned customers, but it seems unlikely that would significantly influence our understanding of how API deprecation impacts churn.</p> <h2 id="reason">Reason</h2> <p>In terms of acquiring customers, the most important flows are customer acquisition and initial integration with the API. Optimizing those flows will increase the number of existing integrations.</p> <p>The flows driving churn are baseline churn, and the combination of API deprecation and deprecation-influenced churn. It&rsquo;s difficult to move baseline churn for a payments API, as many churning customers leave due to company dissolution. From a revenue-weighted perspective, baseline churn is largely driven by non-technical factors, primarily pricing. In either case, it&rsquo;s challenging to impact this flow without significantly lowering margin.</p> <p>Engineering decisions, on the other hand, have a significant impact on both the number of API deprecations, and on the ease of reintegration after a migration. Because the same work to support reintegration also supports the initial integration experience, that&rsquo;s a promising opportunity for investment.</p> <h2 id="model">Model</h2> <p>You can find the <a href="https://github.com/lethain/eng-strategy-models/blob/main/APIDeprecationModel.ipynb">full implementation of this model on GitHub</a> if you want to see the full model rather than these emphasized snippets.</p> <p>Now that we have identified the most interesting avenues for experimentation, it&rsquo;s time to develop the model to evaluate which flows are most impactful.</p> <p>Our initial model specification is:</p> <pre><code># User Acquisition Flow [PotentialCustomers] &gt; EngagedCustomers @ 100 # Initial Integration Flow EngagedCustomers &gt; IntegratedCustomers @ Leak(0.5) # Baseline Churn Flow IntegratedCustomers &gt; ChurnedCustomers @ Leak(0.1) # Experience Deprecation Flow IntegratedCustomers &gt; DeprecationImpactedCustomers @ Leak(0.5) # Reintegrated Flow DeprecationImpactedCustomers &gt; IntegratedCustomers @ Leak(0.9) # Deprecation-Influenced Churn DeprecationImpactedCustomers &gt; ChurnedCustomers @ Leak(0.1) </code></pre> <p>Whether these are <em>reasonable</em> values depends largely on how we think about the length of each round. If a round was a month, then assuming half of integrated customers would experience an API deprecation would be quite extreme. If we assumed it was a year, then it would still be high, but there are certainly some API providers that routinely deprecate at that rate. (From my personal experience, I can say with confidence that Facebook&rsquo;s Ads API deprecated at least one important field on a quarterly basis in the 2012-2014 period.)</p> <p>Admittedly, for a payments API this would be a high rate, and is intended primarily as a contrast with more reasonable values in the exercise section below.</p> <h2 id="exercise">Exercise</h2> <p>Our goal with exercising this model is to understand how much API deprecation impacts customer churn. We&rsquo;ll start by charting the initial baseline, then move to compare it with a variety of scenarios until we build an intuition for how the lines move.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-model-1.png" alt="Initial model stabilizing integrated customers around 1,000 customers"></p> <p>The initial chart stabilizes in about forty rounds, maintaining about 1,000 integrated customers and 400 customers dealing with deprecated APIs. Now let&rsquo;s change the experience deprecation flow to impact significantly fewer customers:</p> <pre><code># Initial setting with 50% experiencing deprecation per round IntegratedCustomers &gt; DeprecationImpactedCustomers @ Leak(0.5) # Less deprecation, only 10% experiencing per round IntegratedCustomers &gt; DeprecationImpactedCustomers @ Leak(0.1) </code></pre> <p>After those changes, we can compare the two scenarios.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-model-2.png" alt="Impact of 10% and 50% API deprecation on integrated customers"></p> <p>Lowering the deprecation rate significantly reduces the number of companies dealing with deprecations at any given time, but it has a relatively small impact on increasing the steady state for integrated customers. This must mean that another flow is significantly impacting the size of the integrated customers stock.</p> <p>Since there&rsquo;s only one other flow impacting that stock, baseline churn, that&rsquo;s the one to exercise next. Let&rsquo;s set the baseline churn flow to zero to compare that with the initial model:</p> <pre><code># Initial Baseline Churn Flow IntegratedCustomers &gt; ChurnedCustomers @ Leak(0.1) # Zeroed out Baseline Churn Flow IntegratedCustomers &gt; ChurnedCustomers @ Leak(0.0) </code></pre> <p>These results make a compelling case that baseline churn is dominating the impact of deprecation. With no baseline churn, the number of integrated customers stabilizes at around 1,750, as opposed to around 1,000 for the initial model.</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-model-3.png" alt="Impact of eliminating baseline churn from model"></p> <p>Next, let&rsquo;s compare two scenarios without baseline churn, where one has high API deprecation (50%) and the other has low API deprecation (10%).</p> <p><img src="https://lethain.com/static/blog/strategy/api-deprecation-model-4.png" alt="Impact of rates of API deprecation with zero baseline churn"></p> <p>In the case of two scenarios without baseline churn, we can see having an API deprecation rate of 10% leads to about 6,000 integrated customers, as opposed to 1,750 for a 50% rate of API deprecation. More importantly, in the 10% scenario, the integrated customers line shows no sign of flattening, and continues to grow over time rather than stabilizing.</p> <p>The takeaway here is that significantly reducing either baseline churn or API deprecation magnifies the benefits of reducing the other. These results also reinforce the value of treating churn reduction as a system-level optimization, not merely a collection of discrete improvements.</p>