<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on Tom Phillips</title>
    <link>https://www.tomwphillips.co.uk/blog/</link>
    <description>Recent content in Posts on Tom Phillips</description>
    <generator>Hugo 0.124.0</generator>
    <language>en-GB</language>
    <lastBuildDate>Thu, 08 Jan 2026 06:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.tomwphillips.co.uk/blog/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Staging is a wasteful lie: the case for the mono-environment</title>
      <link>https://www.tomwphillips.co.uk/2026/01/staging-is-a-wasteful-lie-the-case-for-the-mono-environment/</link>
      <pubDate>Thu, 08 Jan 2026 06:00:00 +0000</pubDate>
      <guid>https://www.tomwphillips.co.uk/2026/01/staging-is-a-wasteful-lie-the-case-for-the-mono-environment/</guid>
      <description>&lt;p&gt;It is common for software engineering teams to deploy new versions of their software to staging environments before deploying it to users in production. In this post I argue that non-production environments are inherently wasteful and describe an alternative: the &lt;em&gt;mono-environment&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I was first introduced to the concept of a mono-environment in 2018 at a SaaS startup. We had a solid engineering team, but were frustrated by slow delivery. After examining all our options, we realised that the costs of a staging environment outweighed the benefits, so we got rid of it, doubled down on our effective practices, and focussed on production.&lt;/p&gt;&#xA;&lt;p&gt;Since then I&amp;rsquo;ve only worked in mono-environments, mostly at fintech startups, and even a bank. I now think it should be the default approach used by developers, especially at startups trying to achieve product-market fit.&lt;/p&gt;&#xA;&lt;p&gt;Some former colleagues published a &lt;a href=&#34;https://monoenv.tech/&#34;&gt;one-page website on mono-environments&lt;/a&gt;, but otherwise there is little to read about the case for a mono-environment and how to work safely in one. If anything, &amp;ldquo;testing in production&amp;rdquo; is a euphemism for sloppy and unprofessional practices. This article sets out to correct that.&lt;/p&gt;&#xA;&lt;h1 id=&#34;why-are-staging-environments-wasteful&#34;&gt;Why are staging environments wasteful?&lt;/h1&gt;&#xA;&lt;p&gt;Your users can only use and get value from production, therefore any effort that goes into delivering software to staging is inherently wasteful. For many developers staging is their primary deployment target, so staging also presents a misalignment of incentives between developers and users.&lt;/p&gt;&#xA;&lt;p&gt;You could argue that users &lt;em&gt;indirectly&lt;/em&gt; benefit from staging because it&amp;rsquo;s a tool for inspection, i.e. checking functionality and looking for bugs. But this is still problematic because you can&amp;rsquo;t inspect quality into the software development process.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; By the time a change reaches staging, if the quality isn&amp;rsquo;t there, then it&amp;rsquo;s a choice between shipping it anyway, re-working it, or binning it. All of these are wasteful. Instead, the quality needs to be there from the start.&lt;/p&gt;&#xA;&lt;p&gt;Using staging as a quality gate also reduces the throughput of changes to production, thereby lengthening user feedback cycles and delaying delivery of value to users.&lt;/p&gt;&#xA;&lt;p&gt;Staging environments are also unreliable quality gates because they are unrepresentative of production in two key ways. Firstly, staging is usually under lower load than production. Secondly, the data in staging is often unrepresentative of data in production, so a change might have the desired behaviour in staging but fail in production when the application processes real-world data. In my experience, this is particularly problematic with AI systems. So for staging to be a reliable indicator, it has to be very similar to production, but in practice each step towards parity gets progressively harder and more expensive.&lt;/p&gt;&#xA;&lt;p&gt;Long-lived non-production environments have extra infrastructure costs. Configuring smaller resources for staging adds complexity and further diverges staging from production, making it an even more unreliable indicator of change quality.&lt;/p&gt;&#xA;&lt;p&gt;Your developers also have the cognitive overhead of working with staging. What other changes are in staging? Has someone released my change to production? Of course, there are ways to manage this, but it is additional effort that could be spent on something your users care about.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s not forget the misery of restarting work you thought you had finished weeks ago, because it was finally deployed to production and someone found a bug.&lt;/p&gt;&#xA;&lt;p&gt;All the above is made much worse when you have multiple non-production environments. I once had a client where one team had &lt;em&gt;five&lt;/em&gt; environments for their application. Things didn&amp;rsquo;t go well for them.&lt;/p&gt;&#xA;&lt;p&gt;Overall, staging gives a false sense of security and creates a poor developer experience. It encourages large batch sizes, lowers throughput to users, and delays feedback. In a startup, all of this presents an existential threat because it reduces the rate of learning from users and increases cash burn.&lt;/p&gt;&#xA;&lt;h1 id=&#34;what-if-we-only-operate-production&#34;&gt;What if we only operate production?&lt;/h1&gt;&#xA;&lt;p&gt;If we get rid of staging and only operate a production environment – a mono-environment – then how can we do so safely? Specifically, we want to maintain quality, reduce risk, and minimise waste. We need to replace &lt;em&gt;environmental&lt;/em&gt; isolation with &lt;em&gt;logical&lt;/em&gt; isolation, which means moving safeguards into the code.&lt;/p&gt;&#xA;&lt;p&gt;Practically, we can do this by taking existing software development practices like testing, feature flagging and continuous deployment, and doing them well to work in fast feedback cycles. Here are five practices I think are key for a successful mono-environment.&lt;/p&gt;&#xA;&lt;h2 id=&#34;practice-1-testing&#34;&gt;Practice 1: testing&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;Use automated tests to ensure your change has the desired behaviour, and doesn&amp;rsquo;t break existing behaviour, before deploying to production.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;We need to be confident that a change has the expected behaviour. We can get that confidence with automated tests. At risk of alienating some of you: use &lt;a href=&#34;https://martinfowler.com/bliki/TestDrivenDevelopment.html&#34;&gt;test-driven development&lt;/a&gt; (TDD). It gives you rapid feedback, so you know you&amp;rsquo;re moving in the right direction. The test suite guards against regressions and is also a form of documentation.&lt;/p&gt;&#xA;&lt;p&gt;TDD is a skill. A common mistake doing TDD is &lt;a href=&#34;https://www.youtube.com/watch?v=EZ05e7EMOLM&#34;&gt;testing implementation instead of behaviour&lt;/a&gt;, which makes for brittle tests that fail en masse when you refactor code. Another mistake is writing &lt;a href=&#34;https://martinfowler.com/articles/nonDeterminism.html&#34;&gt;non-deterministic&lt;/a&gt; (&amp;ldquo;flaky&amp;rdquo;) or slow tests, which give you unreliable, slow feedback.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s also important to write tests of the right granularity: a &lt;a href=&#34;https://martinfowler.com/bliki/UnitTest.html&#34;&gt;unit test&lt;/a&gt; checks the behaviour of a single module, an &lt;a href=&#34;https://martinfowler.com/bliki/IntegrationTest.html&#34;&gt;integration test&lt;/a&gt; checks multiple modules function together correctly, and a smoke test checks basic functionality for a user (e.g. logging in and seeing the home page). The right mix will depend on your specific requirements and application architecture; further discussion is beyond the scope of this post.&lt;/p&gt;&#xA;&lt;h2 id=&#34;practice-2-local-environments&#34;&gt;Practice 2: local environments&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;Use ephemeral local environments to boost confidence in a change and get feedback via demos.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Even with TDD, you might miss an edge case or simply assert the wrong behaviour in your tests, so it&amp;rsquo;s useful to be able to do manual tests. It&amp;rsquo;s also useful to be able to demo a change to a colleague or customer for feedback as early as possible during development.&lt;/p&gt;&#xA;&lt;p&gt;Ephemeral local environments are useful for these situations. A local environment won&amp;rsquo;t tell you exactly how your change will behave in production, much like staging wouldn&amp;rsquo;t, but they are still a useful tool to increase your confidence in a change without all the downsides of a long-lived non-production environment. They&amp;rsquo;re great for debugging too.&lt;/p&gt;&#xA;&lt;p&gt;Set up a script to launch your local environment with one command. Check it into your repository so everyone can use it. The extent to which you can set up a complete local environment will likely depend on your architecture. If you&amp;rsquo;re using containers and have a monolithic backend and React frontend, then it&amp;rsquo;s trivial to bring up an entire app with a tool like Docker Compose. In a distributed system, it&amp;rsquo;s likely to be harder, so you might only bring up the service of interest and use stubs for everything else.&lt;/p&gt;&#xA;&lt;h2 id=&#34;practice-3-feature-flagging&#34;&gt;Practice 3: feature flagging&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;Use feature flags to test new functionality in production for a subset of users.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Feature flags allow you to turn on or off functionality in production based on some criteria, like the user making the request, without a deployment:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; featureFlags&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;canViewNewFeature&amp;#34;&lt;/span&gt;, user):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    newFeature()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is useful in a mono-environment because you can develop a feature in private behind a feature flag and find out how it behaves in production. I typically configure a new flag so that only colleagues can see the functionality, then when I&amp;rsquo;m happy with the change, I&amp;rsquo;ll either turn it on for everyone or do a gradual roll-out.&lt;/p&gt;&#xA;&lt;p&gt;Lots of companies offering feature flag software for reasonable prices. Pick one you like.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s tempting to feature flag every change, but I advise against it. In startups, iteration speed is key, and in a mono-environment, it&amp;rsquo;s easy and fast to revert a change or deploy another, so more often than not I tend not to bother with a flag since it gets me feedback from more users at lower cost (because no time is spent on flag management). But for incomplete features or uncertain changes, I&amp;rsquo;ll use one.&lt;/p&gt;&#xA;&lt;p&gt;In your tests, mock the feature flag provider so that you can specify the flag state for any given test.&lt;/p&gt;&#xA;&lt;h2 id=&#34;practice-4-continuous-deployment&#34;&gt;Practice 4: continuous deployment&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;Use continuous deployment to ship changes quickly and seamlessly.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Shipping software is a key activity in software development. Frictionless deployment means faster feedback and delivery of value.&lt;/p&gt;&#xA;&lt;p&gt;Continuous &lt;em&gt;integration&lt;/em&gt; is the practice of developers integrating their code changes into the main branch of the repository frequently (at least daily) and building and testing the software on every commit. Continuous &lt;em&gt;delivery&lt;/em&gt; is the practice of being able to deploy a new version of the software at a moment&amp;rsquo;s notice. (So continuous integration is a prerequisite for continuous delivery.) In a mono-environment, we use continuous &lt;em&gt;deployment&lt;/em&gt;, which is the practice of automatically deploying your software on every change.&lt;/p&gt;&#xA;&lt;p&gt;For continuous deployment, you typically need two pipelines. The first &lt;em&gt;build and test pipeline&lt;/em&gt; runs on every commit and builds the software and runs the unit and integration tests. On the main branch, after a successful build and test run, the second &lt;em&gt;deployment pipeline&lt;/em&gt; deploys the software.&lt;/p&gt;&#xA;&lt;p&gt;Both need to be fast and reliable. I find it hard to tolerate anything longer than a few minutes. It&amp;rsquo;s essential to keep the build and test pipeline green, otherwise your deployments are blocked, which delays feedback on new changes and fixes for issues.&lt;/p&gt;&#xA;&lt;p&gt;I also like to run smoke tests against production after every deployment to check I haven&amp;rsquo;t broken basic functionality like logging in and seeing the expected home page. These tests should use a dedicated test user/tenant.&lt;/p&gt;&#xA;&lt;p&gt;Overall, deployments should be business-as-usual and completely ordinary events.&lt;/p&gt;&#xA;&lt;h2 id=&#34;practice-5-monitor-production&#34;&gt;Practice 5: monitor production&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;Use monitoring and observability tools to know what&amp;rsquo;s happening to your users when they use your software.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;You need to know what&amp;rsquo;s happening in production because it&amp;rsquo;s what your users experience. It&amp;rsquo;s what actually matters. If they are getting errors or performance problems, then you need to fix it fast, or at least be able to proactively get in touch before they contact you. Think about problems like uncaught exceptions and unexpected 400/500 HTTP response codes in logs. If you have a small number of users, then you might fire alerts every time, otherwise only when errors cross thresholds. Also track application events, so you can understand what your users are doing.&lt;/p&gt;&#xA;&lt;p&gt;The technical approach to take depends on your particular situation. If you have a monolithic architecture and low number of users then you might be fine with log-based monitoring. On the other hand if you have a distributed system under high load, you might need more sophisticated observability tooling. I can&amp;rsquo;t really comment on the latter, as I&amp;rsquo;ve not worked on a distributed system with it set up (which caused me many headaches manually tracing requests through the logs of different services), so &lt;a href=&#34;https://newsletter.pragmaticengineer.com/p/observability-the-present-and-future&#34;&gt;listen to an expert like Charity Majors instead&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;p&gt;All the techniques so far are about incrementally increasing the confidence in your change by repeatedly running through feedback loops. During development, each practice enables lots of frequent and fast feedback cycles, thereby minimising risk and increasing confidence in delivering value for users.&lt;/p&gt;&#xA;&lt;h1 id=&#34;common-objections&#34;&gt;Common objections&lt;/h1&gt;&#xA;&lt;h2 id=&#34;compliance-requires-us-to-have-a-staging-environment&#34;&gt;Compliance requires us to have a staging environment&lt;/h2&gt;&#xA;&lt;p&gt;Verify this for yourself. On many occasions I&amp;rsquo;ve been told that a piece of legislation or regulation requires something specific, then when I&amp;rsquo;ve looked it up myself I&amp;rsquo;ve found the requirements to be much more flexible. Understand the regulations, work out how you can meet them, and discuss it with the relevant experts. For example, you might be able to argue that automated testing, continuous deployments, and comprehensive monitoring are more effective controls than infrequent manual checks in a staging environment.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-about-database-migrations&#34;&gt;What about database migrations?&lt;/h2&gt;&#xA;&lt;p&gt;Database migrations make people nervous in a mono-environment, but it&amp;rsquo;s worth remembering that a successful migration in staging doesn&amp;rsquo;t mean it will work in production. For example, a migration might run in tens of milliseconds in staging, but take much longer on a larger production database and cause an outage. Production databases often contain old, unusual data not present in staging, which could cause unexpected surprises.&lt;/p&gt;&#xA;&lt;p&gt;Work in a pair and write down a plan. Consider what could go wrong and work out how you would roll back. Look at the query plan. Ensure you know what to do to recover from a disaster. Migrations should also be part of your continuous deployment pipeline.&lt;/p&gt;&#xA;&lt;p&gt;Often, you need to use the &lt;a href=&#34;https://martinfowler.com/bliki/ParallelChange.html&#34;&gt;expand and contract pattern&lt;/a&gt;. For example, let&amp;rsquo;s say you want to rename a column:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Migration 1: add the new column (expand).&lt;/li&gt;&#xA;&lt;li&gt;Deploy a new version of your app that writes to the new column, and reads from the new and old columns, e.g. &lt;code&gt;coalesce(new_col, old_col)&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Migration 2: backfill any null values in the new column from the old column.&lt;/li&gt;&#xA;&lt;li&gt;Deploy a new version of your app that reads and writes only from the new column (contract).&lt;/li&gt;&#xA;&lt;li&gt;Migration 3: drop the old column. Optionally, make the new column &lt;code&gt;not null&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h1 id=&#34;incremental-delivery-goes-hand-in-hand-with-a-mono-environment&#34;&gt;Incremental delivery goes hand in hand with a mono-environment&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale.&lt;/p&gt;&#xA;&lt;p&gt;— &lt;a href=&#34;https://agilemanifesto.org/principles.html&#34;&gt;Agile Manifesto principle #3&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Big bang releases are high risk because you find out if you&amp;rsquo;re right or wrong &lt;a href=&#34;https://web.archive.org/web/20140329210405/http://alistair.cockburn.us/Trim+the+Tail&#34;&gt;late in the development process&lt;/a&gt;. In contrast, incremental delivery (small, frequent changes) enables early feedback before it is too late to change tack.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;a href=&#34;https://web.archive.org/web/20140329203040/http://alistair.cockburn.us/Elephant+carpaccio&#34;&gt;Elephant carpaccio&lt;/a&gt;&lt;/em&gt;, coined by Alistair Cockburn, is a useful tool for thinking about incremental delivery. Carpaccio is an Italian dish of meat sliced so thin you can almost see through it. (I&amp;rsquo;m a vegetarian, so I&amp;rsquo;ve never tried it.) In software carpaccio, developers take a user story – the elephant – and slice it so thin that they can deliver a slice each day or, even better, several slices each day. To get a feel for this, &lt;a href=&#34;https://www.youtube.com/watch?v=EKRD-2kiC10&#34;&gt;watch Douglas Squirrel talk about delivery of a colour picker using elephant carpaccio&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Elephant carpaccio, and incremental delivery, are a natural fit for a mono-environment, because a mono-environment enables seamless delivery of each slice into the hands of users, and creates a tight feedback loop.&lt;/p&gt;&#xA;&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;&#xA;&lt;p&gt;Staging and other non-production environments give a false sense of security. Time spent on them, instead of delivering value to users, is a waste of time and money.&lt;/p&gt;&#xA;&lt;p&gt;Instead of relying on environmental isolation, the mono-environment relies on logical isolation by moving safeguards into the code. It achieves safety through rigorous, automated software engineering practices and aligns all developer effort with the environment that generates value and revenue: production.&lt;/p&gt;&#xA;&lt;p&gt;Counterintuitively, the speed of delivery in a mono-environment is &lt;em&gt;safer&lt;/em&gt; than using a staging environment, because incremental delivery in a single environment leads to tighter feedback loops and more learning, and a higher chance of achieving product-market fit before cash runs out. A mono-environment creates a virtuous cycle of faster and more robust delivery.&lt;/p&gt;&#xA;&lt;p&gt;Lastly, I want to note how enjoyable it is to work in a mono-environment. It&amp;rsquo;s not unusual for my current team of 6 to have 30+ production deployments (including infrastructure changes and database migrations) and multiple customer conversations in a single day. Shipping so frequently can be hard to imagine if you&amp;rsquo;ve not done it before. I love technology, but what I love even more is shipping software people find useful, and a mono-environment helps me do that.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;https://www.linkedin.com/in/michael-hancock-6790a32/&#34;&gt;Mike Hancock&lt;/a&gt; for feedback on a draft of this post.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;I first heard the phrase &amp;ldquo;you can&amp;rsquo;t inspect quality into a process&amp;rdquo; from Dave Farley on his &lt;a href=&#34;https://www.youtube.com/channel/UCCfqyGl3nq_V0bo64CjZh8g&#34;&gt;Modern Software Engineering YouTube channel&lt;/a&gt;. I looked into its origin and apparently it is a &lt;a href=&#34;https://deming.org/inspection-is-too-late-the-quality-good-or-bad-is-already-in-the-product/&#34;&gt;quote from the statistician Harold F. Dodge&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA; &lt;p prefix=&#34;dct: http://purl.org/dc/terms/ cc: http://creativecommons.org/ns#&#34;&gt;&lt;a property=&#34;dct:title&#34; rel=&#34;cc:attributionURL&#34; href=&#34;https://www.tomwphillips.co.uk/2026/01/staging-is-a-wasteful-lie-the-case-for-the-mono-environment/&#34;&gt;Staging is a wasteful lie: the case for the mono-environment&lt;/a&gt; by &lt;a rel=&#34;cc:attributionURL dct:creator&#34; property=&#34;cc:attributionName&#34; href=&#34;https://www.tomwphillips.co.uk/&#34;&gt;Tom Phillips&lt;/a&gt; is licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1&#34; target=&#34;_blank&#34; rel=&#34;license noopener noreferrer&#34; style=&#34;display:inline-block;&#34;&gt;CC BY 4.0&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;</description>
    </item>
    <item>
      <title>AGI fantasy is a blocker to actual engineering</title>
      <link>https://www.tomwphillips.co.uk/2025/11/agi-fantasy-is-a-blocker-to-actual-engineering/</link>
      <pubDate>Fri, 14 Nov 2025 06:32:56 +0000</pubDate>
      <guid>https://www.tomwphillips.co.uk/2025/11/agi-fantasy-is-a-blocker-to-actual-engineering/</guid>
      <description>&lt;p&gt;Reading &lt;a href=&#34;https://www.penguin.co.uk/books/460331/empire-of-ai-by-hao-karen/9780241678923&#34;&gt;&lt;em&gt;Empire of AI&lt;/em&gt; by Karen Hao&lt;/a&gt;, I was struck by how people associated with OpenAI &lt;em&gt;believe&lt;/em&gt; in AGI. They really do think someone, perhaps them, will build AGI, and that it will lead to either the flourishing or destruction of humanity.&lt;/p&gt;&#xA;&lt;p&gt;Elon Musk founded OpenAI because he thought Demis Hassabis was an evil genius who would build AGI first:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&amp;hellip;Musk would regularly characterise Hassabis as a supervillain who needed to be stopped. Musk would make unequivocally clear that OpenAI was the good to DeepMind&amp;rsquo;s evil. &amp;hellip; &amp;ldquo;He literally made a video game where an evil genius tries to create AI to take over the world,&amp;rdquo; Musk shouted [at an OpenAI off-site], referring to Hassabis&amp;rsquo;s 2004 title &lt;em&gt;Evil Genius&lt;/em&gt;, &amp;ldquo;and fucking people don&amp;rsquo;t see it. Fucking people don&amp;rsquo;t see it! And Larry [Page]? Larry thinks he controls Demis but he&amp;rsquo;s too busy fucking windsurfing to realize that Demis is gathering the power.&amp;rdquo;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;OpenAI&amp;rsquo;s co-founder and chief scientist Ilya Sutskever regularly told audiences and employees to &amp;ldquo;feel the AGI&amp;rdquo;. At a company off-site in Yosemite in September 2022, employees gathered around a firepit:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;In the pit, [Sutskever] had placed a wooden effigy that he&amp;rsquo;d commissioned from a local artist, and began a dramatic performance. This effigy, he explained represented a good, aligned AGI that OpenAI had built, only to discover it was actually lying and deceitful. OpenAI&amp;rsquo;s duty, he said, was to destroy it. &amp;hellip; Sutskever doused the effigy in lighter fluid and lit on fire.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I think it&amp;rsquo;s remarkable that what was until recently sci-fi fantasy has become a mainstream view in Silicon Valley.&lt;/p&gt;&#xA;&lt;p&gt;Hao writes that GPT-2 was a bet on the &amp;ldquo;pure language&amp;rdquo; hypothesis, that asserts that since we communicate through language, then AGI should emerge from training a model solely on language. This is contrast to the &amp;ldquo;grounding&amp;rdquo; hypothesis, that asserts an AGI needs to perceive the world. Successfully scaling GPT to GPT-2 convinced enough people at OpenAI that the pure language hypothesis was valid. They just needed more data, more model parameters, and more compute.&lt;/p&gt;&#xA;&lt;p&gt;So the belief in AGI, plus the recent results from LLMs, necessitates scaling, and justifies building data centres that &lt;a href=&#34;https://restofworld.org/2024/data-centers-environmental-issues/&#34;&gt;consume hundreds of litres of water a second&lt;/a&gt;, &lt;a href=&#34;https://www.theregister.com/2025/05/08/xai_turbines_colossus/&#34;&gt;run on polluting gas generators because the grid can&amp;rsquo;t supply the power&lt;/a&gt; (&lt;a href=&#34;https://www.theregister.com/2024/04/01/microsoft_openai_5gw_dc/&#34;&gt;and might use as much power as entire cities&lt;/a&gt;), driving up CO2 emissions from manufacture and operation of new hardware, and &lt;a href=&#34;https://www.wsj.com/tech/chatgpt-openai-content-abusive-sexually-explicit-harassment-kenya-workers-on-human-workers-cf191483&#34;&gt;exploits and traumatises data workers&lt;/a&gt; to make sure ChatGPT doesn&amp;rsquo;t generate outputs like child sexual abuse material and hate speech or encourage users to self-harm. (The thirst for data is so great that they stopped curating training data and instead consume the internet, warts and all, and manage the model output using &lt;a href=&#34;https://en.wikipedia.org/wiki/Reinforcement_learning_from_human_feedback&#34;&gt;RLHF&lt;/a&gt;.)&lt;/p&gt;&#xA;&lt;p&gt;And this is all fine, because they&amp;rsquo;re going to make AGI and the &lt;a href=&#34;https://en.wikipedia.org/wiki/Expected_value&#34;&gt;expected value&lt;/a&gt; (EV) of it will be huge! (Briefly, the argument goes that if there is a 0.001% chance of AGI delivering an extremely large amount of value, and 99.999% chance of much less or zero value, then the EV is still extremely large because &lt;code&gt;(0.001% * very_large_value) + (99.999% * small_value) = very_large_value&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;But AGI arguments based on EV are nonsensical because the values and probabilities are made up and unfalsifiable. They also ignore externalities like environmental damage, which in contrast to AGI, have known negative value and certain probability: costs borne by everyone else right now.&lt;/p&gt;&#xA;&lt;p&gt;As a technologist I want to solve problems effectively (by bringing about the desired, correct result), efficiently (with minimal waste) and without harm (to people or the environment).&lt;/p&gt;&#xA;&lt;p&gt;LLMs-as-AGI fail on all three fronts. The computational profligacy of LLMs-as-AGI is dissatisfying, and the exploitation of data workers and the environment unacceptable. Instead, if we drop the AGI fantasy, we can evaluate LLMs and other generative models as solutions for specific problems, rather than &lt;em&gt;all&lt;/em&gt; problems, with proper cost benefit analysis. For example, by using smaller purpose-built generative models, or even discriminative (non-generative) models. In other words, make trade-offs and actually do engineering.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=45926469&#34;&gt;Discuss on Hacker News&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA; &lt;p prefix=&#34;dct: http://purl.org/dc/terms/ cc: http://creativecommons.org/ns#&#34;&gt;&lt;a property=&#34;dct:title&#34; rel=&#34;cc:attributionURL&#34; href=&#34;https://www.tomwphillips.co.uk/2025/11/agi-fantasy-is-a-blocker-to-actual-engineering/&#34;&gt;AGI fantasy is a blocker to actual engineering&lt;/a&gt; by &lt;a rel=&#34;cc:attributionURL dct:creator&#34; property=&#34;cc:attributionName&#34; href=&#34;https://www.tomwphillips.co.uk/&#34;&gt;Tom Phillips&lt;/a&gt; is licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1&#34; target=&#34;_blank&#34; rel=&#34;license noopener noreferrer&#34; style=&#34;display:inline-block;&#34;&gt;CC BY 4.0&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;</description>
    </item>
    <item>
      <title>Understanding Kotlin DSLs</title>
      <link>https://www.tomwphillips.co.uk/2025/03/understanding-kotlin-dsls/</link>
      <pubDate>Tue, 04 Mar 2025 10:02:35 +0000</pubDate>
      <guid>https://www.tomwphillips.co.uk/2025/03/understanding-kotlin-dsls/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m learning Kotlin for a new job and I was confused by &lt;a href=&#34;https://kotlinlang.org/docs/type-safe-builders.html&#34;&gt;type-safe builders&lt;/a&gt;. They&amp;rsquo;re used to create domain specific languages (DSLs) in Kotlin. Two common use cases are &lt;a href=&#34;https://ktor.io/docs/server-routing.html&#34;&gt;configuring routes in Ktor server&lt;/a&gt; or &lt;a href=&#34;https://github.com/Kotlin/kotlinx.html&#34;&gt;building HTML&lt;/a&gt;. I think they&amp;rsquo;re confusing because they combine a bunch of Kotlin concepts. Here&amp;rsquo;s how I broke it down to understand it.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s start with a data class to describe a pet. Note the member properties are mutable and have default values. I&amp;rsquo;ll come back to why at the end.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;data class Pet(var name: String? = null, var description: String? = null)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we need a &lt;em&gt;builder function&lt;/em&gt;. It takes one argument, &lt;code&gt;init&lt;/code&gt;, which is a &lt;a href=&#34;https://kotlinlang.org/docs/lambdas.html#function-types&#34;&gt;function type with receiver&lt;/a&gt;. In other words, &lt;code&gt;init&lt;/code&gt; takes no arguments, and operates in the context of a &lt;code&gt;Pet&lt;/code&gt; instance, and returns &lt;code&gt;Unit&lt;/code&gt;. The builder function returns an instance of &lt;code&gt;Pet&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fun pet(init: Pet.() -&amp;gt; Unit): Pet {  &#xA;    val pet = Pet()  &#xA;    pet.init()  &#xA;    return pet  &#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You use it to create an instance of &lt;code&gt;Pet&lt;/code&gt; like this:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;var jessica = pet {  &#xA;    name = &amp;#34;Jessica&amp;#34;  &#xA;    description = &amp;#34;Black and white cat&amp;#34;  &#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are two confusing things going on here.&lt;/p&gt;&#xA;&lt;p&gt;First, there&amp;rsquo;s no &lt;code&gt;()&lt;/code&gt; calling the pet function. Instead, there&amp;rsquo;s a &lt;em&gt;&lt;a href=&#34;https://kotlinlang.org/docs/lambdas.html#passing-trailing-lambdas&#34;&gt;trailing lambda&lt;/a&gt;&lt;/em&gt;. In Kotlin, when the last argument to a function is a function, then you can omit the parentheses and pass the function as a lambda expression in curly brackets.&lt;/p&gt;&#xA;&lt;p&gt;Second, how do the assignments to &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; end up as member properties of &lt;code&gt;jessica&lt;/code&gt;? Previously I said &lt;code&gt;init&lt;/code&gt; is a function type with receiver, and inside these types of function, the &lt;a href=&#34;https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver&#34;&gt;receiving object can be accessed via &lt;code&gt;this&lt;/code&gt;&lt;/a&gt;. But where&amp;rsquo;s the &lt;code&gt;this&lt;/code&gt;? You don&amp;rsquo;t need it because Kotlin infers that &lt;code&gt;name&lt;/code&gt; is actually &lt;code&gt;this.name&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We can then nest another class inside &lt;code&gt;Pet&lt;/code&gt;. Let&amp;rsquo;s add information about the &lt;code&gt;Owner&lt;/code&gt; of the pet.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;data class Owner(var name: String? = null)  &#xA;  &#xA;data class Pet(var name: String? = null, var description: String? = null, val owners: MutableList&amp;lt;Owner&amp;gt; = mutableListOf&amp;lt;Owner&amp;gt;()) {  &#xA;    fun owner(init: Owner.() -&amp;gt; Unit): Owner {  &#xA;        val owner = Owner()  &#xA;        owner.init()  &#xA;        owners.add(owner)  &#xA;        return owner  &#xA;    }  &#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;rsquo;ve added a member property called &lt;code&gt;owners&lt;/code&gt; and a member function called &lt;code&gt;owner&lt;/code&gt;. This is another builder, like &lt;code&gt;pet&lt;/code&gt;, that creates an instance of &lt;code&gt;Owner&lt;/code&gt;, calls &lt;code&gt;init&lt;/code&gt;, then adds the owner to the pet&amp;rsquo;s list of owners, and returns the &lt;code&gt;owner&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Put this altogether to get our DSL:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;var jessica = pet {  &#xA;    name = &amp;#34;Jessica&amp;#34;  &#xA;    description = &amp;#34;Black and white moggy&amp;#34;  &#xA;    owner {  &#xA;        name = &amp;#34;Tom&amp;#34;  &#xA;    }  &#xA;    owner {  &#xA;        name = &amp;#34;Kelly&amp;#34;  &#xA;    }  &#xA;}&#xA;&#xA;// println(jessica) returns:&#xA;// Pet(name=Jessica, description=Black and white moggy, owners=[Owner(name=Tom), Owner(name=Kelly)])&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When I defined &lt;code&gt;Pet&lt;/code&gt; I noted that the member properties must be mutable and have default values. You need defaults because the builder functions create an instance without passing any arguments to the constructor. Then because &lt;code&gt;init&lt;/code&gt; sets the member properties, they must be mutable too. The exception is &lt;code&gt;Pet.owners&lt;/code&gt;, because we don&amp;rsquo;t want to reassign the (mutable) list reference, just modify the contents of it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://pl.kotl.in/y_4JeGf44&#34;&gt;Here&amp;rsquo;s the code in Kotlin Playground&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA; &lt;p prefix=&#34;dct: http://purl.org/dc/terms/ cc: http://creativecommons.org/ns#&#34;&gt;&lt;a property=&#34;dct:title&#34; rel=&#34;cc:attributionURL&#34; href=&#34;https://www.tomwphillips.co.uk/2025/03/understanding-kotlin-dsls/&#34;&gt;Understanding Kotlin DSLs&lt;/a&gt; by &lt;a rel=&#34;cc:attributionURL dct:creator&#34; property=&#34;cc:attributionName&#34; href=&#34;https://www.tomwphillips.co.uk/&#34;&gt;Tom Phillips&lt;/a&gt; is licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1&#34; target=&#34;_blank&#34; rel=&#34;license noopener noreferrer&#34; style=&#34;display:inline-block;&#34;&gt;CC BY 4.0&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;</description>
    </item>
    <item>
      <title>Leaving iPhone after 16 years for Android</title>
      <link>https://www.tomwphillips.co.uk/2025/03/leaving-iphone-after-16-years-for-android/</link>
      <pubDate>Sun, 02 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://www.tomwphillips.co.uk/2025/03/leaving-iphone-after-16-years-for-android/</guid>
      <description>&lt;p&gt;For 16 years I&amp;rsquo;ve used an iPhone. I&amp;rsquo;ve owned maybe 4-5 models and my current one is an iPhone 11. The battery is knackered and I started to think what I&amp;rsquo;d do if I needed to replace it. iPhones are getting bigger and more expensive. The cheapest model, the iPhone 16e, starts at £599. I don&amp;rsquo;t want to spend that much money on a phone.&lt;/p&gt;&#xA;&lt;p&gt;Lately I&amp;rsquo;ve become uncomfortable with Apple&amp;rsquo;s control over what I can do on my phone. If it&amp;rsquo;s not on the App Store, then I can&amp;rsquo;t run it, despite having bought the hardware. I used to find genuinely useful apps, but I can&amp;rsquo;t remember the last time I downloaded something like that. Nowadays it&amp;rsquo;s full of low-quality apps designed to extract micro-transactions from users, including children. Apple makes a ton of money from their commission.&lt;/p&gt;&#xA;&lt;p&gt;Apple has the ability to remove apps from the App Store, including ones already purchased and downloaded, so &lt;a href=&#34;https://www.theguardian.com/world/2024/apr/19/apple-removes-whatsapp-and-threads-from-chinese-app-store&#34;&gt;oppressive regimes can force Apple to remove apps that they don&amp;rsquo;t like&lt;/a&gt;. In the UK, &lt;a href=&#34;https://www.bbc.co.uk/news/articles/cgj54eq4vejo&#34;&gt;Apple has disabled end-to-end encryption for iCloud data&lt;/a&gt;, so the government – or whoever manages to compromise Apple&amp;rsquo;s key management – can access the data of users in iCloud, including all device backups. This is hugely invasive. I can&amp;rsquo;t even switch to another provider because Apple locks iOS down.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s not forget Apple Intelligence: I don&amp;rsquo;t want generative AI crap on my phone or computer.&lt;/p&gt;&#xA;&lt;p&gt;Overall, I don&amp;rsquo;t trust American tech companies to do the right thing&#xA;anymore. They operate in an authoritarian regime. I can only see the situation getting worse.&lt;/p&gt;&#xA;&lt;p&gt;So a week ago I switched to a Pixel 8a running &lt;a href=&#34;https://grapheneos.org/&#34;&gt;GrapheneOS&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;GrapheneOS is a privacy and security focussed mobile operating system based on the &lt;a href=&#34;https://source.android.com/&#34;&gt;Android Open Source Project&lt;/a&gt;. One of its &lt;a href=&#34;https://grapheneos.org/features&#34;&gt;features&lt;/a&gt; is &lt;a href=&#34;https://grapheneos.org/features#sandboxed-google-play&#34;&gt;sandboxed Google Play&lt;/a&gt;, so you can download things like banking apps that don&amp;rsquo;t work or are unreliable on other Android OS like &lt;a href=&#34;https://e.foundation/e-os/&#34;&gt;/e/os&lt;/a&gt; and &lt;a href=&#34;https://lineageos.org/&#34;&gt;LineageOS&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I chose a Pixel 8a because it is a device &lt;a href=&#34;https://grapheneos.org/faq#recommended-devices&#34;&gt;recommended by GrapheneOS&lt;/a&gt; and comes with 7 years of support from launch (May 2024). &lt;a href=&#34;https://www.nytimes.com/wirecutter/reviews/best-android-phone/&#34;&gt;Wirecutter also recommends it as their budget pick&lt;/a&gt;. It&amp;rsquo;s also well-priced. I paid £349. I&amp;rsquo;d have preferred a &lt;a href=&#34;https://www.fairphone.com/&#34;&gt;Fairphone&lt;/a&gt; over a Google device, but they&amp;rsquo;re more expensive and unsupported by GrapheneOS.&lt;/p&gt;&#xA;&lt;p&gt;Installing &lt;a href=&#34;https://grapheneos.org/install/web&#34;&gt;GrapheneOS via WebUSB&lt;/a&gt; was easy (and really cool). Overall, I&amp;rsquo;ve found it intuitive and easy to use. Perhaps it&amp;rsquo;s slightly less polished than iOS, but it&amp;rsquo;s fine.&lt;/p&gt;&#xA;&lt;p&gt;It was easy to find replacement for apps. I already use &lt;a href=&#34;https://www.fastmail.com/&#34;&gt;Fastmail&lt;/a&gt;, so I downloaded their app for my email, calendars and contacts. I downloaded &lt;a href=&#34;https://www.davx5.com/&#34;&gt;DAVx5&lt;/a&gt; to sync my Fastmail contacts to the Contacts app. For now I have some calendars shared with my partner on iCloud. I&amp;rsquo;m accessing those &lt;a href=&#34;https://www.fastmail.help/hc/en-us/articles/360058752754-How-to-synchronize-a-calendar&#34;&gt;via Fastmail&lt;/a&gt; too.&lt;/p&gt;&#xA;&lt;p&gt;I simply stopped using iMessage. Everyone uses WhatsApp or, better, Signal anyway.&lt;/p&gt;&#xA;&lt;p&gt;I replaced iCloud Photos with &lt;a href=&#34;https://ente.io/&#34;&gt;Ente&lt;/a&gt;. It uses end-to-end encryption. I&amp;rsquo;ve not uploaded my whole library yet, but it&amp;rsquo;s working fine so far.&lt;/p&gt;&#xA;&lt;p&gt;I swapped &lt;a href=&#34;https://overcast.fm/&#34;&gt;Overcast&lt;/a&gt; for &lt;a href=&#34;https://antennapod.org/&#34;&gt;AntennaPod&lt;/a&gt;. I have noticed the absence of volume normalization, but I can live without it.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve used &lt;a href=&#34;https://culturedcode.com/things/&#34;&gt;Things&lt;/a&gt; to manage todo lists since ~2008. But really I have simple needs. So I&amp;rsquo;m trying out a plaintext todo list in &lt;a href=&#34;https://obsidian.md/&#34;&gt;Obsidian&lt;/a&gt;, with end-to-end encrypted sync via Obsidian Sync, and simply putting date-sensitive items in my calendar.&lt;/p&gt;&#xA;&lt;p&gt;The only niggle so far was some lag on the GrapheneOS camera app when pressing the shutter button. I downloaded the Google Camera app and disabled network access. It&amp;rsquo;s much faster.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve not tried out device backups yet, but since my data is either in Fastmail, Ente, 1Password or Obsidian, I feel comfortable with the risk. I might try backing up to a USB stick.&lt;/p&gt;&#xA;&lt;p&gt;I installed Obsidian and Tor via &lt;code&gt;.apk&lt;/code&gt; files. You just download and install it! I got &lt;a href=&#34;https://organicmaps.app/&#34;&gt;Organic Maps&lt;/a&gt; from the &lt;a href=&#34;https://accrescent.app&#34;&gt;Accrescent store&lt;/a&gt;. I might try out &lt;a href=&#34;https://github.com/ImranR98/Obtainium&#34;&gt;Obtainium&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Overall, I&amp;rsquo;m really happy. It&amp;rsquo;s been &lt;em&gt;much&lt;/em&gt; easier than I expected to switch. I&amp;rsquo;ve probably spent 3-4 hours on it in total. Go for it!&lt;/p&gt;&#xA;&#xA;&#xA;&#xA; &lt;p prefix=&#34;dct: http://purl.org/dc/terms/ cc: http://creativecommons.org/ns#&#34;&gt;&lt;a property=&#34;dct:title&#34; rel=&#34;cc:attributionURL&#34; href=&#34;https://www.tomwphillips.co.uk/2025/03/leaving-iphone-after-16-years-for-android/&#34;&gt;Leaving iPhone after 16 years for Android&lt;/a&gt; by &lt;a rel=&#34;cc:attributionURL dct:creator&#34; property=&#34;cc:attributionName&#34; href=&#34;https://www.tomwphillips.co.uk/&#34;&gt;Tom Phillips&lt;/a&gt; is licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1&#34; target=&#34;_blank&#34; rel=&#34;license noopener noreferrer&#34; style=&#34;display:inline-block;&#34;&gt;CC BY 4.0&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;</description>
    </item>
    <item>
      <title>What do you learn from your MVP?</title>
      <link>https://www.tomwphillips.co.uk/2024/06/what-do-you-learn-from-your-mvp/</link>
      <pubDate>Fri, 14 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.tomwphillips.co.uk/2024/06/what-do-you-learn-from-your-mvp/</guid>
      <description>&lt;p&gt;&lt;em&gt;Minimum viable product&lt;/em&gt; (MVP) has become meaningless business jargon.&lt;/p&gt;&#xA;&lt;p&gt;The problem with so-called MVPs is that no one learns anything from them. There is no hypothesis under test.&lt;/p&gt;&#xA;&lt;p&gt;If your MVP doesn’t unambiguously validate or invalidate a hypothesis, then it’s impossible to know whether you are succeeding or failing.&lt;/p&gt;&#xA;&lt;p&gt;What do you know about your customers? What problems do they have? How do they get value from your product? Will the answers to these questions change &lt;em&gt;if&lt;/em&gt; you build the MVP? If they don’t change, then whatever you’re building is a waste of time and money, and it&amp;rsquo;s not an MVP.&lt;/p&gt;&#xA;&lt;p&gt;In &lt;em&gt;The Lean Startup&lt;/em&gt; (first published in 2011!), Eric Ries writes that an MVP completes one cycle of the build, measure, learn loop.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://www.tomwphillips.co.uk/images/build-measure-learn.png&#34;&#xA;    alt=&#34;A hand drawn diagram showing the words build, measure, learn with connecting arrows to form a cycle. In the centre are the words &amp;#34;1 cycle = an MVP&amp;#34;.&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;If we&amp;rsquo;re honest, most faux MVPs are just collective agreement on what is a barely acceptable use of everyone’s time. Something to keep people busy. A minimum tolerable output.&lt;/p&gt;&#xA;&lt;p&gt;So next time someone says “it’s an MVP”, ask “what are we learning from it?”.&lt;/p&gt;&#xA;&#xA;&#xA; &lt;p prefix=&#34;dct: http://purl.org/dc/terms/ cc: http://creativecommons.org/ns#&#34;&gt;&lt;a property=&#34;dct:title&#34; rel=&#34;cc:attributionURL&#34; href=&#34;https://www.tomwphillips.co.uk/2024/06/what-do-you-learn-from-your-mvp/&#34;&gt;What do you learn from your MVP?&lt;/a&gt; by &lt;a rel=&#34;cc:attributionURL dct:creator&#34; property=&#34;cc:attributionName&#34; href=&#34;https://www.tomwphillips.co.uk/&#34;&gt;Tom Phillips&lt;/a&gt; is licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1&#34; target=&#34;_blank&#34; rel=&#34;license noopener noreferrer&#34; style=&#34;display:inline-block;&#34;&gt;CC BY-SA 4.0&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;</description>
    </item>
    <item>
      <title>Will dbt adopt a proprietary licence? I think so</title>
      <link>https://www.tomwphillips.co.uk/2024/04/dbt-proprietary-licence/</link>
      <pubDate>Tue, 02 Apr 2024 00:00:00 +0000</pubDate>
      <guid>https://www.tomwphillips.co.uk/2024/04/dbt-proprietary-licence/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.getdbt.com/&#34;&gt;Data build tool&lt;/a&gt; (dbt) changed the way many organisations transform data and do analytics. I think more change is afoot: I predict dbt Labs will adopt a proprietary licence for dbt Core and the project will fork.&lt;/p&gt;&#xA;&lt;p&gt;dbt Labs use the &lt;a href=&#34;https://sfosc.org/docs/business-models/loose-open-core/&#34;&gt;loose open core&lt;/a&gt; business model, where the primary functionality in &lt;a href=&#34;https://github.com/dbt-labs/dbt-core&#34;&gt;dbt Core&lt;/a&gt; is covered under an open source licence (&lt;a href=&#34;https://github.com/dbt-labs/dbt-core/blob/main/License.md&#34;&gt;Apache 2.0&lt;/a&gt;) with extra proprietary software wrapping around it, namely &lt;a href=&#34;https://www.getdbt.com/product/dbt-cloud&#34;&gt;dbt Cloud&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The open core creates a large funnel of potential customers for the proprietary product. The difficulty with the open core business model lies in deciding whether a feature goes in the open core or proprietary product. The company wants to add functionality to the proprietary product to drive conversion of users to customers, but this &lt;a href=&#34;https://medium.com/@adamhjk/goodbye-open-core-good-riddance-to-bad-rubbish-ae3355316494&#34;&gt;often conflicts with the interests of the users of the open core&lt;/a&gt;. Despite this conflict of interest, the open core depends on the success of the the proprietary product to fund its development.&lt;/p&gt;&#xA;&lt;p&gt;In dbt&amp;rsquo;s case, I think dbt Cloud isn&amp;rsquo;t a compelling product. Despite using dbt Core for years I have never bought dbt Cloud. I don&amp;rsquo;t know of any organisations who use it; I know of one who stopped.&lt;/p&gt;&#xA;&lt;p&gt;A recent &lt;a href=&#34;https://boards.greenhouse.io/dbtlabsinc/jobs/4343828005&#34;&gt;job advert&lt;/a&gt; says dbt Labs have over 4,100 dbt Cloud customers. At &lt;a href=&#34;https://www.getdbt.com/pricing&#34;&gt;$100/month&lt;/a&gt; that&amp;rsquo;s ~$5M/year. Maybe they have some big enterprise deals, but that revenue is probably dwarfed by payroll. LinkedIn lists 421 members associated with dbt Labs. A conservative estimate of 300 employees at $100k/year is $30M/year, which would be a loss of ~$25M/year. Not great for &lt;a href=&#34;https://www.prnewswire.com/news-releases/dbt-labs-raises-222m-in-series-d-funding-at-4-2b-valuation-led-by-altimeter-with-participation-from-databricks-and-snowflake-301489733.html&#34;&gt;an eight year old company valued at $4.2B&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;What can dbt Labs do? &lt;a href=&#34;https://www.getdbt.com/blog/consumption-based-pricing-and-the-future-of-dbt-cloud&#34;&gt;They already cut headcount by 15%&lt;/a&gt; and&#xA;&lt;a href=&#34;https://www.getdbt.com/blog/consumption-based-pricing-and-the-future-of-dbt-cloud&#34;&gt;switched to consumption-based pricing&lt;/a&gt;. Can they ship some compelling features? I&amp;rsquo;m not convinced. &lt;a href=&#34;https://www.glassdoor.co.uk/Reviews/dbt-Labs-Reviews-E2969503.htm&#34;&gt;Glassdoor reviews&lt;/a&gt; (taken with a large pinch of salt) complain about leadership and the product roadmap. In an &lt;a href=&#34;https://www.youtube.com/watch?v=cuLXwUypAC8&#34;&gt;interview&lt;/a&gt; last December, their CEO Tristan Handy said:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;[W]hat I want to do is increasingly make living in the dbt ecosystem feel like living in the Apple ecosystem, which is to say that the hard stuff [like CI, observability, data cataloging] just kind of vanishes into the background. And you forget that that was ever a problem and you spend all your time thinking about business value.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This is a nice idea but it will be hard to execute. He acknowledged that comparing dbt Labs with Apple is a stretch, but putting that aside, the revenue models are completely different: people pay Apple $1000 for an iPhone and then pay even more for services (to the EU&amp;rsquo;s chagrin). In contrast, entry into the dbt ecosystem is free and users spend money elsewhere (e.g. on a cloud data warehouse or managed data transfer services).&lt;/p&gt;&#xA;&lt;p&gt;By Tristan&amp;rsquo;s own admission, and unlike Apple, dbt Labs&amp;rsquo; products aren&amp;rsquo;t even best-in-class:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;So we just launched this thing called dbt Explorer. And you look at dbt Explorer and you compare it to a fully featured data catalogue &amp;hellip; and I mean, gosh, it&amp;rsquo;s like David and Goliath, like, our product is kind of a toy. But it does a lot of things, the basic things that you want, and it is automatically in the hands of everybody who is in the dbt ecosystem. And that&amp;rsquo;s really powerful. And so we want to continue to do that, we&amp;rsquo;re not going to try to build the most complex best-in-class orchestration tool or best-in-class observer. But when you have a huge user group, and you can say, hey, here&amp;rsquo;s a really useful thing, and it works with all these other things, then you get to kind of raise the bar on the set of tooling that everyone has access to.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I can’t see how this will lead to a sustainable open source business. Even if they do convert a fraction of their users to customers, these customers are then at risk of churning to a more sophisticated product in the future.&lt;/p&gt;&#xA;&lt;p&gt;What might happen next? dbt Labs coined &amp;ldquo;analytics engineering&amp;rdquo; and if you&amp;rsquo;re analytics engineer practicing what dbt Labs preach, you probably have a lot of models. What surprises me is that &lt;a href=&#34;https://www.getdbt.com/blog/analytics-engineering-next-step-forwards&#34;&gt;5% of the dbt install base has over 5000 models&lt;/a&gt;! These customers are sitting ducks, locked-in to dbt.&lt;/p&gt;&#xA;&lt;p&gt;How can dbt Labs get money from those users? By pulling the &lt;a href=&#34;https://www.hashicorp.com/blog/hashicorp-adopts-business-source-license&#34;&gt;same move as HashiCorp&lt;/a&gt; and switching new releases of dbt Core to the &lt;a href=&#34;https://mariadb.com/bsl11/&#34;&gt;Business Source License&lt;/a&gt; (BuSL), which would block competitors offering products based on it.&lt;/p&gt;&#xA;&lt;p&gt;dbt Labs then release new features to tame huge dbt projects now efficiency and cost optimisation are in vogue and perhaps they will start to see more customers.  Meanwhile, they can claim to be committed to open source, despite the BuSL not being an &lt;a href=&#34;https://opensource.org/licenses&#34;&gt;OSI-approved licence&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Coincidentally, &lt;a href=&#34;https://www.getdbt.com/blog/dbt-labs-appoints-tech-veteran-brandon-sweeney-as-president-and-chief-operating-officer&#34;&gt;HashiCorp&amp;rsquo;s former chief revenue officer Brandon Sweeney is now dbt Labs’ chief operating officer&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If this does happen, a fork of dbt core is in the interests of all the vendors selling &amp;ldquo;dbt compatible&amp;rdquo; products, much like businesses who got together to create the &lt;a href=&#34;https://opentofu.org/&#34;&gt;OpenTofu&lt;/a&gt; fork of Terraform. I think it would be good for users too. I am surprised by how long dbt has dominated the transformation part of the data stack. More competition and diversity of thought in the data industry is good for everyone.&lt;/p&gt;&#xA;&lt;p&gt;I think dbt Labs should have stuck with their original consultancy business Fishtown Analytics and made dbt a &lt;a href=&#34;https://sfosc.org/docs/business-models/free-software-product/&#34;&gt;free software product&lt;/a&gt;, charging their clients for a proprietary distribution. But that business model probably wouldn&amp;rsquo;t go down well with their investors. Unfortunately I see dbt ending up being yet another example of the consequences of choosing the wrong open source business model.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA; &lt;p prefix=&#34;dct: http://purl.org/dc/terms/ cc: http://creativecommons.org/ns#&#34;&gt;&lt;a property=&#34;dct:title&#34; rel=&#34;cc:attributionURL&#34; href=&#34;https://www.tomwphillips.co.uk/2024/04/dbt-proprietary-licence/&#34;&gt;Will dbt adopt a proprietary licence? I think so&lt;/a&gt; by &lt;a rel=&#34;cc:attributionURL dct:creator&#34; property=&#34;cc:attributionName&#34; href=&#34;https://www.tomwphillips.co.uk/&#34;&gt;Tom Phillips&lt;/a&gt; is licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1&#34; target=&#34;_blank&#34; rel=&#34;license noopener noreferrer&#34; style=&#34;display:inline-block;&#34;&gt;CC BY 4.0&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;img style=&#34;height:22px!important;margin-left:3px;vertical-align:text-bottom;&#34; src=&#34;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;</description>
    </item>
  </channel>
</rss>