<feed
    xmlns="http://www.w3.org/2005/Atom"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xml:lang="en">
  <link rel="self"      type="application/atom+xml" href="https://euandre.org/en/blog/feed.presentation.xml" />
  <link rel="alternate" type="text/html"            href="https://euandre.org/en/blog/" hreflang="en" />
  <title>EuAndreh&apos;s website</title>
  <subtitle>Blog</subtitle>
  <id>https://euandre.org/en/blog/feed.presentation.xml</id>
  <updated>2026-09-13T12:14:51+00:00</updated>
  <author>
    <name>EuAndreh</name>
    <email>eu@euandre.org</email>
  </author>
  <entry xml:lang="en">
    <title type="html">
      Local-First Software: article review
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/11/14/local-first-review.html" title="Local-First Software: article review" />
    <published>
      2020-11-14T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2020/11/14/local-first-review.html
    </id>
    <author>
      <name>
        EuAndreh
      </name>
      <email>
        eu@euandre.org
      </email>
    </author>
    <summary type="html">
        &lt;div id=&quot;preamble&quot;&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;&lt;em&gt;This article is derived from a &lt;a href=
              &quot;../../../../slide/2020/11/14/local-first-hype.pdf&quot;&gt;presentation&lt;/a&gt; given at a Papers We Love meetup on
    </summary>
    <content type="html" xml:base="en/blog/2020/11/14/local-first-review.html">
        &lt;div id=&quot;preamble&quot;&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;&lt;em&gt;This article is derived from a &lt;a href=
              &quot;../../../../slide/2020/11/14/local-first-hype.pdf&quot;&gt;presentation&lt;/a&gt; given at a Papers We Love meetup on
              the same subject.&lt;/em&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is a review of the article &quot;&lt;a href=
              &quot;https://martin.kleppmann.com/papers/local-first.pdf&quot;&gt;Local-First Software: You Own Your Data, in spite
              of the Cloud&lt;/a&gt;&quot;, by M. Kleppmann, A. Wiggins, P. Van Hardenberg and M. F. McGranaghan.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;offline-first-local-first&quot;&gt;Offline-first, local-first&lt;a class=&quot;anchor&quot;
             href=&quot;#offline-first-local-first&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The &quot;local-first&quot; term they use isn’t new, and I have used it myself in the past to refer to this
              types of application, where the data lives primarily on the client, and there are conflict resolution
              algorithms that reconcile data created on different instances.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Sometimes I see confusion with this idea and &quot;client-side&quot;, &quot;offline-friendly&quot;, &quot;syncable&quot;, etc. I
              have myself used this terms, also.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There exists, however, already the &quot;offline-first&quot; term, which conveys almost all of that meaning. In
              my view, &quot;local-first&quot; doesn’t extend &quot;offline-first&quot; in any aspect, rather it gives a well-defined
              meaning to it instead. I could say that &quot;local-first&quot; is just &quot;offline-first&quot;, but with 7 well-defined
              ideals instead of community best practices.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It is a step forward, and given the number of times I’ve seen the paper shared around I think there’s
              a chance people will prefer saying &quot;local-first&quot; in &lt;em&gt;lieu&lt;/em&gt; of &quot;offline-first&quot; from now on.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;software-licenses&quot;&gt;Software licenses&lt;a class=&quot;anchor&quot;
             href=&quot;#software-licenses&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On a footnote of the 7th ideal (&quot;You Retain Ultimate Ownership and Control&quot;), the authors say:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;In our opinion, maintaining control and ownership of data does not mean that the software must
                  necessarily be open source. (…​) as long as it does not artificially restrict what users can do with
                  their files.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They give examples of artificial restrictions, like this artificial restriction I’ve come up with:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
              &lt;div class=&quot;content&quot;&gt;
                &lt;table&gt;
                  &lt;tbody&gt;
                    &lt;tr&gt;
                      &lt;td&gt;
                        &lt;pre class=&quot;lineno&quot;&gt;&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L1&quot;
     href=&quot;#B1-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L2&quot;
     href=&quot;#B1-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L3&quot;
     href=&quot;#B1-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L4&quot;
     href=&quot;#B1-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L5&quot;
     href=&quot;#B1-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L6&quot;
     href=&quot;#B1-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L7&quot;
     href=&quot;#B1-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L8&quot;
     href=&quot;#B1-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L9&quot;
     href=&quot;#B1-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L10&quot;
     href=&quot;#B1-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L11&quot;
     href=&quot;#B1-L11&quot;&gt;11&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;#!/bin/sh

TODAY=$(date +%s)
LICENSE_EXPIRATION=$(date -d 2020-11-15 +%s)

if [ $TODAY -ge $LICENSE_EXPIRATION ]; then
  echo &apos;License expired!&apos;
  exit 1
fi

echo $((2 + 2))&lt;/pre&gt;
                      &lt;/td&gt;
                    &lt;/tr&gt;
                  &lt;/tbody&gt;
                &lt;/table&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph plaintext&quot;&gt;
              &lt;p&gt;&lt;a href=&quot;local-first-review.html.0.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Now when using this very useful program:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
              &lt;div class=&quot;content&quot;&gt;
                &lt;table&gt;
                  &lt;tbody&gt;
                    &lt;tr&gt;
                      &lt;td&gt;
                        &lt;pre class=&quot;lineno&quot;&gt;&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L1&quot;
     href=&quot;#B2-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L2&quot;
     href=&quot;#B2-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L3&quot;
     href=&quot;#B2-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L4&quot;
     href=&quot;#B2-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L5&quot;
     href=&quot;#B2-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L6&quot;
     href=&quot;#B2-L6&quot;&gt;6&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;# today
$ ./useful-adder.sh
4
# tomorrow
$ ./useful-adder.sh
License expired!&lt;/pre&gt;
                      &lt;/td&gt;
                    &lt;/tr&gt;
                  &lt;/tbody&gt;
                &lt;/table&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph plaintext&quot;&gt;
              &lt;p&gt;&lt;a href=&quot;local-first-review.html.1.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is obviously an intentional restriction, and it goes against the 5th ideal (&quot;The Long Now&quot;). This
              software would only be useful as long as the embedded license expiration allowed. Sure you could change
              the clock on the computer, but there are many other ways that this type of intentional restriction is in
              conflict with that ideal.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;However, what about unintentional restrictions? What if a software had an equal or similar
              restriction, and stopped working after days pass? Or what if the programmer added a constant to make the
              development simpler, and this led to unintentionally restricting the user?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
              &lt;div class=&quot;content&quot;&gt;
                &lt;table&gt;
                  &lt;tbody&gt;
                    &lt;tr&gt;
                      &lt;td&gt;
                        &lt;pre class=&quot;lineno&quot;&gt;&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L1&quot;
     href=&quot;#B3-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L2&quot;
     href=&quot;#B3-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L3&quot;
     href=&quot;#B3-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L4&quot;
     href=&quot;#B3-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L5&quot;
     href=&quot;#B3-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L6&quot;
     href=&quot;#B3-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L7&quot;
     href=&quot;#B3-L7&quot;&gt;7&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;# today
$ useful-program
# ...useful output...

# tomorrow, with more data
$ useful-program
ERROR: Panic! Stack overflow!&lt;/pre&gt;
                      &lt;/td&gt;
                    &lt;/tr&gt;
                  &lt;/tbody&gt;
                &lt;/table&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph plaintext&quot;&gt;
              &lt;p&gt;&lt;a href=&quot;local-first-review.html.2.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Just as easily as I can come up with ways to intentionally restrict users, I can do the same for
              unintentionally restrictions. A program can stop working for a variety of reasons.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If it stops working due do, say, data growth, what are the options? Reverting to an earlier backup,
              and making it read-only? That isn’t really a &quot;Long Now&quot;, but rather a &quot;Long Now as long as the software
              keeps working as expected&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The point is: if the software isn’t free, &quot;The Long Now&quot; isn’t achievable without a lot of wishful
              thinking. Maybe the authors were trying to be more friendly towards business who don’t like free
              software, but in doing so they’ve proposed a contradiction by reconciling &quot;The Long Now&quot; with proprietary
              software.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It isn’t the same as saying that any free software achieves that ideal, either. The license can still
              be free, but the source code can become unavailable due to cloud rot. Or maybe the build is undocumented,
              or the build tools had specific configuration that one has to guess. A piece of free software can still
              fail to achieve &quot;The Long Now&quot;. Being free doesn’t guarantee it, just makes it possible.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;A colleague has challenged my view, arguing that the software doesn’t really need to be free, as long
              as there is an specification of the file format. This way if the software stops working, the format can
              still be processed by other programs. But this doesn’t apply in practice: if you have a document that you
              write to, and software stops working, you still want to write to the document. An external tool that
              navigates the content and shows it to you won’t allow you to keep writing, and when it does that tool is
              now starting to re-implement the software.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;An open specification could serve as a blueprint to other implementations, making the data format more
              friendly to reverse-engineering. But the re-implementation still has to exist, at which point the
              original software failed to achieve &quot;The Long Now&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It is less bad, but still not quite there yet.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;denial-of-existing-solutions&quot;&gt;Denial of existing solutions&lt;a class=&quot;anchor&quot;
             href=&quot;#denial-of-existing-solutions&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When describing &quot;Existing Data Storage and Sharing Models&quot;, on a footnotefootnote:devil[ This is the
              second aspect that I’m picking on the article from a footnote. I guess the devil really is on the
              details. ] the authors say:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;In principle it is possible to collaborate without a repository service, e.g. by sending patch
                  files by email, but the majority of Git users rely on GitHub.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The authors go to a great length to talk about usability of cloud apps, and even point to research
              they’ve done on it, but they’ve missed learning more from local-first solutions that already exist.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Say the automerge CRDT proves to be even more useful than what everybody imagined. Say someone builds
              a local-first repository service using it. How will it change anything of the Git/GitHub model? What is
              different about it that prevents people in the future writing a paper saying:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;In principle it is possible to collaborate without a repository service, e.g. by using automerge
                  and platform X, but the majority of Git users rely on GitHub.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;How is this any better?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If it is already &lt;a href=
              &quot;https://drewdevault.com/2018/07/23/Git-is-already-distributed.html&quot;&gt;possible&lt;/a&gt; to have a local-first
              development workflow, why don’t people use it? Is it just fashion, or there’s a fundamental problem with
              it? If so, what is it, and how to avoid it?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If sending patches by emails is perfectly possible but out of fashion, why even talk about Git/GitHub?
              Isn’t this a problem that people are putting themselves in? How can CRDTs possibly prevent people from
              doing that?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;My impression is that the authors envision a better future, where development is fully decentralized
              unlike today, and somehow CRDTs will make that happen. If more people think this way, &quot;CRDT&quot; is next in
              line to the buzzword list that solves everything, like &quot;containers&quot;, &quot;blockchain&quot; or &quot;machine
              learning&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Rather than picturing an imaginary service that could be described like &quot;GitHub+CRDTs&quot; and people
              would adopt it, I’d rather better understand why people don’t do it already, since Git is built to work
              like that.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;ditching-of-web-applications&quot;&gt;Ditching of web applications&lt;a class=&quot;anchor&quot;
             href=&quot;#ditching-of-web-applications&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The authors put web application in a worse position for building local-first application, claiming
              that:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;(…​) the architecture of web apps remains fundamentally server-centric. Offline support is an
                  afterthought in most web apps, and the result is accordingly fragile.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Well, I disagree.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The problem isn’t inherit to the web platform, but instead how people use it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I have myself built offline-first applications, leveraging IndexedDB, App Cache, &lt;em&gt;etc&lt;/em&gt;. I
              wanted to build an offline-first application on the web, and so I did.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In fact, many people choose &lt;a href=&quot;https://pouchdb.com/&quot;&gt;PouchDB&lt;/a&gt; &lt;em&gt;because&lt;/em&gt; of that, since
              it is a good tool for offline-first web applications. The problem isn’t really the technology, but how
              much people want their application to be local-first.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Contrast it with Android &lt;a href=&quot;https://developer.android.com/topic/google-play-instant&quot;&gt;Instant
              Apps&lt;/a&gt;, where applications are sent to the phone in small parts. Since this requires an internet
              connection to move from a part of the app bundle to another, a subset of the app isn’t local-first,
              despite being an app.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The point isn’t the technology, but how people are using it. Local-first web applications are
              perfectly possible, just like non-local-first native applications are possible.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;costs-are-underrated&quot;&gt;Costs are underrated&lt;a class=&quot;anchor&quot;
             href=&quot;#costs-are-underrated&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I think the costs of &quot;old-fashioned apps&quot; over &quot;cloud apps&quot; are underrated, mainly regarding storage,
              and that this costs can vary a lot by application.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Say a person writes online articles for their personal website, and puts everything into Git. Since
              there isn’t supposed to be any collaboration, all of the relevant ideals of local-first are achieved.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Now another person creates videos instead of articles. They could try keeping everything local, but
              after some time the storage usage fills the entire disk. This person’s local-first setup would be much
              more complex, and would cost much more on maintenance, backup and storage.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though both have similar needs, a local-first video repository is much more demanding. So the
              local-first thinking here isn’t &quot;just keep everything local&quot;, but &quot;how much time and money am I willing
              to spend to keep everything local&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The convenience of &quot;cloud apps&quot; becomes so attractive that many don’t even have a local copy of their
              videos, and rely exclusively on service providers to maintain, backup and store their content.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The dial measuring &quot;cloud apps&quot; and &quot;old-fashioned apps&quot; needs to be specific to use-cases.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;real-time-collaboration-is-optional&quot;&gt;Real-time collaboration is optional&lt;a class=&quot;anchor&quot;
             href=&quot;#real-time-collaboration-is-optional&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If I were the one making the list of ideals, I wouldn’t focus so much on real-time collaboration.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though seamless collaboration is desired, it being real-time depends on the network being
              available for that. But ideal 3 states that &quot;The Network is Optional&quot;, so real-time collaboration is also
              optional.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The fundamentals of a local-first system should enable real-time collaboration when network is
              available, but shouldn’t focus on it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On many places when discussing applications being offline, it is common for me to find people saying
              that their application works &quot;even on a plane, subway or elevator&quot;. That is a reflection of when said
              developers have to deal with networks being unavailable.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But this leaves out a big chunk of the world where internet connection is intermittent, or only works
              every other day or only once a week, or stops working when it rains, &lt;em&gt;etc&lt;/em&gt;. For this audience,
              living without network connectivity isn’t such a discrete moment in time, but part of every day life. I
              like the fact that the authors acknowledge that.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When discussing &quot;working offline&quot;, I’d rather keep this type of person in mind, then the subset of
              people who are offline when on the elevator will naturally be included.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;on-crdts-and-developer-experience&quot;&gt;On CRDTs and developer experience&lt;a class=&quot;anchor&quot;
             href=&quot;#on-crdts-and-developer-experience&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When discussing developer experience, the authors bring up some questions to be answered further,
              like:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;For an app developer, how does the use of a CRDT-based data layer compare to existing storage
                  layers like a SQL database, a filesystem, or CoreData? Is a distributed system harder to write
                  software for?&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;That is an easy one: yes.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;A distributed system &lt;em&gt;is&lt;/em&gt; harder to write software for, being a distributed system.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Adding a large layer of data structures and algorithms will make it more complex to write software
              for, naturally. And if trying to make this layer transparent to the programmer, so they can pretend that
              layer doesn’t exist is a bad idea, as RPC frameworks have tried, and failed.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;See &quot;&lt;a href=
              &quot;https://web.archive.org/web/20130116163535/https://labs.oracle.com/techrep/1994/smli_tr-94-29.pdf&quot;&gt;A
              Note on Distributed Computing&lt;/a&gt;&quot; for a critique on RPC frameworks trying to make the network invisible,
              which I think also applies in equivalence for making the CRDTs layer invisible.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;anchor&quot;
             href=&quot;#conclusion&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I liked a lot the article, as it took the &quot;offline-first&quot; philosophy and ran with it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But I think the authors’ view of adding CRDTs and things becoming local-first is a bit too
              magical.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This particular area is one that I have large interest on, and I wish to see more being done on the
              &quot;local-first&quot; space.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      Feature flags: differences between backend, frontend and mobile
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/10/19/feature-flags.html" title="Feature flags: differences between backend, frontend and mobile" />
    <published>
      2020-10-19T00:00:00+00:00
    </published>
    <updated>
      2020-11-03T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2020/10/19/feature-flags.html
    </id>
    <author>
      <name>
        EuAndreh
      </name>
      <email>
        eu@euandre.org
      </email>
    </author>
    <summary type="html">
        &lt;div id=&quot;preamble&quot;&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;&lt;em&gt;This article is derived from a &lt;a href=
              &quot;../../../../slide/2020/10/19/feature-flags.pdf&quot;&gt;presentation&lt;/a&gt; on the same subject.&lt;/em&gt;&lt;/p&gt;
    </summary>
    <content type="html" xml:base="en/blog/2020/10/19/feature-flags.html">
        &lt;div id=&quot;preamble&quot;&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;&lt;em&gt;This article is derived from a &lt;a href=
              &quot;../../../../slide/2020/10/19/feature-flags.pdf&quot;&gt;presentation&lt;/a&gt; on the same subject.&lt;/em&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When discussing about feature flags, I find that their costs and benefits are often well exposed and
              addressed. Online articles like &quot;&lt;a href=&quot;https://martinfowler.com/articles/feature-toggles.html&quot;&gt;Feature
              Toggle (aka Feature Flags)&lt;/a&gt;&quot; do a great job of explaining them in detail, giving great general
              guidance of how to apply techniques to adopt it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;However the weight of those costs and benefits apply differently on backend, frontend or mobile, and
              those differences aren’t covered. In fact, many of them stop making sense, or the decision of adopting a
              feature flag or not may change depending on the environment.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In this article I try to make the distinction between environments and how feature flags apply to
              them, with some final best practices I’ve acquired when using them in production.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;why-feature-flags&quot;&gt;Why feature flags&lt;a class=&quot;anchor&quot;
             href=&quot;#why-feature-flags&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Feature flags in general tend to be cited on the context of &lt;a href=
              &quot;https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment&quot;&gt;
              continuous deployment&lt;/a&gt;:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;A: With continuous deployment, you deploy to production automatically&lt;/p&gt;
                &lt;/div&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;B: But how do I handle deployment failures, partial features, &lt;em&gt;etc.&lt;/em&gt;?&lt;/p&gt;
                &lt;/div&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;A: With techniques like canary, monitoring and alarms, feature flags, &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Though adopting continuous deployment doesn’t force you to use feature flags, it creates a demand for
              it. The inverse is also true: using feature flags on the code points you more obviously to continuous
              deployment. Take the following code sample for example, that we will reference later on the article:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
              &lt;div class=&quot;content&quot;&gt;
                &lt;table&gt;
                  &lt;tbody&gt;
                    &lt;tr&gt;
                      &lt;td&gt;
                        &lt;pre class=&quot;lineno&quot;&gt;&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L1&quot;
     href=&quot;#B1-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L2&quot;
     href=&quot;#B1-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L3&quot;
     href=&quot;#B1-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L4&quot;
     href=&quot;#B1-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L5&quot;
     href=&quot;#B1-L5&quot;&gt;5&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;function processTransaction() {
        validate();
        persist();
        // TODO: add call to notifyListeners()
}&lt;/pre&gt;
                      &lt;/td&gt;
                    &lt;/tr&gt;
                  &lt;/tbody&gt;
                &lt;/table&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph plaintext&quot;&gt;
              &lt;p&gt;&lt;a href=&quot;feature-flags.html.0.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;While being developed, being tested for suitability or something similar,
              &lt;code&gt;notifyListeners()&lt;/code&gt; may not be included in the code at once. So instead of keeping it on a
              separate, long-lived branch, a feature flag can decide when the new, partially implemented function will
              be called:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;listingblock&quot;&gt;
              &lt;div class=&quot;content&quot;&gt;
                &lt;table&gt;
                  &lt;tbody&gt;
                    &lt;tr&gt;
                      &lt;td&gt;
                        &lt;pre class=&quot;lineno&quot;&gt;&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L1&quot;
     href=&quot;#B2-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L2&quot;
     href=&quot;#B2-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L3&quot;
     href=&quot;#B2-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L4&quot;
     href=&quot;#B2-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L5&quot;
     href=&quot;#B2-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L6&quot;
     href=&quot;#B2-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L7&quot;
     href=&quot;#B2-L7&quot;&gt;7&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;function processTransaction() {
        validate();
        persist();
        if (featureIsEnabled(&quot;activate-notify-listeners&quot;)) {
                notifyListeners();
        }
}&lt;/pre&gt;
                      &lt;/td&gt;
                    &lt;/tr&gt;
                  &lt;/tbody&gt;
                &lt;/table&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph plaintext&quot;&gt;
              &lt;p&gt;&lt;a href=&quot;feature-flags.html.1.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This allows your code to include &lt;code&gt;notifyListeners()&lt;/code&gt;, and decide when to call it at
              runtime. For the price of extra things around the code, you get more dynamicity.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So the fundamental question to ask yourself when considering adding a feature flag should be:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;Am I willing to pay with code complexity to get dynamicity?&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It is true that you can make the management of feature flags as straightforward as possible, but
              having no feature flags is simpler than having any. What you get in return is the ability to parameterize
              the behaviour of the application at runtime, without doing any code changes.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Sometimes this added complexity may tilt the balance towards not using a feature flag, and sometimes
              the flexibility of changing behaviour at runtime is absolutely worth the added complexity. This can vary
              a lot by code base, feature, but fundamentally by environment: its much cheaper to deploy a new version
              of a service than to release a new version of an app.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So the question of which environment is being targeted is key when reasoning about costs and benefits
              of feature flags.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;control-over-the-environment&quot;&gt;Control over the environment&lt;a class=&quot;anchor&quot;
             href=&quot;#control-over-the-environment&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The key differentiator that makes the trade-offs apply differently is how much control you have over
              the environment.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When running a &lt;strong&gt;backend&lt;/strong&gt; service, you usually are paying for the servers themselves,
              and can tweak them as you wish. This means you have full control do to code changes as you wish. Not only
              that, you decide when to do it, and for how long the transition will last.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;frontend&lt;/strong&gt; you have less control: even though you can choose to make a new
              version available any time you wish, you can’t forcefootnote:force[ Technically you could force a reload
              with JavaScript using &lt;code&gt;window.location.reload()&lt;/code&gt;, but that not only is invasive and impolite,
              but also gives you the illusion that you have control over the client when you actually don’t: clients
              with disabled JavaScript would be immune to such tactics. ] clients to immediately switch to the new
              version. That means that a) clients could skip upgrades at any time and b) you always have to keep
              backward and forward compatibility in mind.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though I’m mentioning frontend directly, it applies to other environment with similar
              characteristics: desktop applications, command-line programs, &lt;em&gt;etc&lt;/em&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On &lt;strong&gt;mobile&lt;/strong&gt; you have even less control: app stores need to allow your app to be
              updated, which could bite you when least desired. Theoretically you could make you APK available on third
              party stores like &lt;a href=&quot;https://f-droid.org/&quot;&gt;F-Droid&lt;/a&gt;, or even make the APK itself available for
              direct download, which would give you the same characteristics of a frontend application, but that
              happens less often.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On iOS you can’t even do that. You have to get Apple’s blessing on every single update. Even though we
              already know that is a &lt;a href=&quot;https://www.paulgraham.com/apple.html&quot;&gt;bad idea&lt;/a&gt; for over a decade
              now, there isn’t a way around it. This is where you have the least control.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In practice, the amount of control you have will change how much you value dynamicity: the less
              control you have, the more valuable it is. In other words, having a dynamic flag on the backend may or
              may not be worth it since you could always update the code immediately after, but on iOS it is basically
              always worth it.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;rollout&quot;&gt;Rollout&lt;a class=&quot;anchor&quot;
             href=&quot;#rollout&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;A rollout is used to &lt;em&gt;roll out&lt;/em&gt; a new version of software.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They are usually short-lived, being relevant as long as the new code is being deployed. The most
              common rule is percentages.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;backend&lt;/strong&gt;, it is common to find it on the deployment infrastructure itself, like
              canary servers, blue/green deployments, &lt;a href=
              &quot;https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment&quot;&gt;a
              kubernetes deployment rollout&lt;/a&gt;, &lt;em&gt;etc&lt;/em&gt;. You could do those manually, by having a dynamic control
              on the code itself, but rollbacks are cheap enough that people usually do a normal deployment and just
              give some extra attention to the metrics dashboard.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Any time you see a blue/green deployment, there is a rollout happening: most likely a load balancer is
              starting to direct traffic to the new server, until reaching 100% of the traffic. Effectively, that is a
              rollout.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;frontend&lt;/strong&gt;, you can selectively pick which user’s will be able to download the
              new version of a page. You could use geographical region, IP, cookie or something similar to make this
              decision.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;CDN propagation delays and people not refreshing their web pages are also rollouts by themselves,
              since old and new versions of the software will coexist.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On &lt;strong&gt;mobile&lt;/strong&gt;, the Play Store allows you to perform fine-grained &lt;a href=
              &quot;https://support.google.com/googleplay/android-developer/answer/6346149?hl=en&quot;&gt;staged rollouts&lt;/a&gt;, and
              the App Store allows you to perform limited &lt;a href=
              &quot;https://help.apple.com/app-store-connect/#/dev3d65fcee1&quot;&gt;phased releases&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Both for Android and iOS, the user plays the role of making the download.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In summary: since you control the servers on the backend, you can do rollouts at will, and those are
              often found automated away in base infrastructure. On the frontend and on mobile, there are ways to make
              new versions available, but users may not download them immediately, and many different versions of the
              software end up coexisting.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;feature-flag&quot;&gt;Feature flag&lt;a class=&quot;anchor&quot;
             href=&quot;#feature-flag&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;A feature flag is a &lt;em&gt;flag&lt;/em&gt; that tells the application on runtime to turn on or off a given
              &lt;em&gt;feature&lt;/em&gt;. That means that the actual production code will have more than one possible code paths
              to go through, and that a new version of a feature coexists with the old version. The feature flag tells
              which part of the code to go through.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They are usually medium-lived, being relevant as long as the new code is being developed. The most
              common rules are percentages, allow/deny lists, A/B groups and client version.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;backend&lt;/strong&gt;, those are useful for things that have a long development cycle, or
              that needs to done by steps. Consider loading the feature flag rules in memory when the application
              starts, so that you avoid querying a database or an external service for applying a feature flag rule and
              avoid flakiness on the result due to intermittent network failures.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Since on the &lt;strong&gt;frontend&lt;/strong&gt; you don’t control when to update the client software, you’re
              left with applying the feature flag rule on the server, and exposing the value through an API for maximum
              dynamicity. This could be in the frontend code itself, and fallback to a &quot;just refresh the page&quot;/&quot;just
              update to the latest version&quot; strategy for less dynamic scenarios.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On &lt;strong&gt;mobile&lt;/strong&gt; you can’t even rely on a &quot;just update to the latest version&quot; strategy,
              since the code for the app could be updated to a new feature and be blocked on the store. Those cases
              aren’t recurrent, but you should always assume the store will deny updates on critical moments so you
              don’t find yourself with no cards to play. That means the only control you actually have is via the
              backend, by parameterizing the runtime of the application using the API. In practice, you should always
              have a feature flag to control any relevant piece of code. There is no such thing as &quot;too small code
              change for a feature flag&quot;. What you should ask yourself is:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;quoteblock&quot;&gt;
              &lt;blockquote&gt;
                &lt;div class=&quot;paragraph&quot;&gt;
                  &lt;p&gt;If the code I’m writing breaks and stays broken for around a month, do I care?&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If you’re doing an experimental screen, or something that will have a very small impact you might
              answer &quot;no&quot; to the above question. For everything else, the answer will be &quot;yes&quot;: bug fixes, layout
              changes, refactoring, new screen, filesystem/database changes, &lt;em&gt;etc&lt;/em&gt;.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;experiment&quot;&gt;Experiment&lt;a class=&quot;anchor&quot;
             href=&quot;#experiment&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;An experiment is a feature flag where you care about analytical value of the flag, and how it might
              impact user’s behaviour. A feature flag with analytics.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They are also usually medium-lived, being relevant as long as the new code is being developed. The
              most common rule is A/B test.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;backend&lt;/strong&gt;, an experiment rely on an analytical environment that will pick the
              A/B test groups and distributions, which means those can’t be held in memory easily. That also means that
              you’ll need a fallback value in case fetching the group for a given customer fails.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;frontend&lt;/strong&gt; and on &lt;strong&gt;mobile&lt;/strong&gt; they are no different from feature
              flags.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;operational-toggle&quot;&gt;Operational toggle&lt;a class=&quot;anchor&quot;
             href=&quot;#operational-toggle&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;An operational toggle is like a system-level manual circuit breaker, where you turn on/off a feature,
              fail over the load to a different server, &lt;em&gt;etc&lt;/em&gt;. They are useful switches to have during an
              incident.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They are usually long-lived, being relevant as long as the code is in production. The most common rule
              is percentages.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They can be feature flags that are promoted to operational toggles on the &lt;strong&gt;backend&lt;/strong&gt;, or
              may be purposefully put in place preventively or after a postmortem analysis.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;On the &lt;strong&gt;frontend&lt;/strong&gt; and on &lt;strong&gt;mobile&lt;/strong&gt; they are similar to feature flags,
              where the &quot;feature&quot; is being turned on and off, and the client interprets this value to show if the
              &quot;feature&quot; is available or unavailable.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;best-practices&quot;&gt;Best practices&lt;a class=&quot;anchor&quot;
             href=&quot;#best-practices&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
          &lt;div class=&quot;sectionbody&quot;&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;prefer-dynamic-content&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#prefer-dynamic-content&quot;&gt;&lt;/a&gt;Prefer dynamic content&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Even though feature flags give you more dynamicity, they’re still somewhat manual: you have to
                create one for a specific feature and change it by hand.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;If you find yourself manually updating a feature flags every other day, or tweaking the percentages
                frequently, consider making it fully dynamic. Try using a dataset that is generated automatically, or
                computing the content on the fly.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Say you have a configuration screen with a list of options and sub-options, and you’re trying to
                find how to better structure this list. Instead of using a feature flag for switching between 3 and 5
                options, make it fully dynamic. This way you’ll be able to perform other tests that you didn’t plan,
                and get more flexibility out of it.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;use-the-client-version-to-negotiate-feature-flags&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#use-the-client-version-to-negotiate-feature-flags&quot;&gt;&lt;/a&gt;Use the client version to negotiate
                 feature flags&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;After effectively finishing a feature, the old code that coexisted with the new one will be deleted,
                and all traces of the transition will vanish from the code base. However if you just remove the feature
                flags from the API, all of the old versions of clients that relied on that value to show the new
                feature will go downgrade to the old feature.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This means that you should avoid deleting client-facing feature flags, and retire them instead: use
                the client version to decide when the feature is stable, and return &lt;code&gt;true&lt;/code&gt; for every client
                with a version greater or equal to that. This way you can stop thinking about the feature flag, and you
                don’t break or downgrade clients that didn’t upgrade past the transition.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;beware-of-many-nested-feature-flags&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#beware-of-many-nested-feature-flags&quot;&gt;&lt;/a&gt;Beware of many nested feature flags&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Nested flags combine exponentially.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Pick strategic entry points or transitions eligible for feature flags, and beware of their
                nesting.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;include-feature-flags-in-the-development-workflow&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#include-feature-flags-in-the-development-workflow&quot;&gt;&lt;/a&gt;Include feature flags in the development
                 workflow&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Add feature flags to the list of things to think about during whiteboarding, and deleting/retiring a
                feature flags at the end of the development.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;always-rely-on-a-feature-flag-on-the-app&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#always-rely-on-a-feature-flag-on-the-app&quot;&gt;&lt;/a&gt;Always rely on a feature flag on the app&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Again, there is no such thing &quot;too small for a feature flag&quot;. Too many feature flags is a good
                problem to have, not the opposite. Automate the process of creating a feature flag to lower its
                cost.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
</feed>
