<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.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.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">
      A Relational Model of Data for Large Shared Data Banks - article-review
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2021/04/29/relational-review.html" title="A Relational Model of Data for Large Shared Data Banks - article-review" />
    <published>
      2021-04-29T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2021/04/29/relational-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;This is a review of the article &quot;&lt;a href=&quot;https://www.seas.upenn.edu/~zives/03f/cis550/codd.pdf&quot;&gt;A
              Relational Model of Data for Large Shared Data Banks&lt;/a&gt;&quot;, by E. F. Codd.&lt;/p&gt;
    </summary>
    <content type="html" xml:base="en/blog/2021/04/29/relational-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;This is a review of the article &quot;&lt;a href=&quot;https://www.seas.upenn.edu/~zives/03f/cis550/codd.pdf&quot;&gt;A
              Relational Model of Data for Large Shared Data Banks&lt;/a&gt;&quot;, by E. F. Codd.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;data-independence&quot;&gt;Data Independence&lt;a class=&quot;anchor&quot;
             href=&quot;#data-independence&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;Codd brings the idea of &lt;em&gt;data independence&lt;/em&gt; as a better approach to use on databases. This is
              contrast with the existing approaches, namely hierarquical (tree-based) and network-based.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;His main argument is that queries in applications shouldn’t depende and be coupled with how the data
              is represented internally by the database system. This key idea is very powerful, and something that we
              strive for in many other places: decoupling the interface from the implementation.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If the database system has this separation, it can kep the querying interface stable, while having the
              freedom to change its internal representation at will, for better performance, less storage, etc.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is true for most modern database systems. They can change from B-Trees with leafs containing
              pointers to data, to B-Trees with leafs containing the raw data , to hash tables. All that without
              changing the query interface, only its performance.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Codd mentions that, from an information representation standpoint, any index is a duplication, but
              useful for perfomance.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This data independence also impacts ordering (a &lt;em&gt;relation&lt;/em&gt; doesn’t rely on the insertion
              order).&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;duplicates&quot;&gt;Duplicates&lt;a class=&quot;anchor&quot;
             href=&quot;#duplicates&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;His definition of relational data is a bit differente from most modern database systems, namely
              &lt;strong&gt;no duplicate rows&lt;/strong&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I couldn’t find a reason behind this restriction, though. For practical purposes, I find it useful to
              have it.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;relational-data&quot;&gt;Relational Data&lt;a class=&quot;anchor&quot;
             href=&quot;#relational-data&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;In the article, Codd doesn’t try to define a language, and today’s most popular one is SQL.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;However, there is no restriction that says that &quot;SQL database&quot; and &quot;relational database&quot; are synonyms.
              One could have a relational database without using SQL at all, and it would still be a relational
              one.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The main one that I have in mind, and the reason that led me to reading this paper in the first place,
              is Datomic.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Is uses an &lt;a href=&quot;https://github.com/edn-format/edn&quot;&gt;edn&lt;/a&gt;-based representation for datalog
              queriesfootnote:edn-queries[ You can think of it as JSON, but with a Clojure taste. ], and a particular
              schema used to represent data.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though it looks very weird when coming from SQL, I’d argue that it ticks all the boxes (except
              for &quot;no duplicates&quot;) that defines a relational database, since building relations and applying operations
              on them is possible.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Compare and contrast a contrived example of possible representations of SQL and datalog of the same
              data:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L12&quot;
     href=&quot;#B1-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L13&quot;
     href=&quot;#B1-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L14&quot;
     href=&quot;#B1-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L15&quot;
     href=&quot;#B1-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L16&quot;
     href=&quot;#B1-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L17&quot;
     href=&quot;#B1-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L18&quot;
     href=&quot;#B1-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L19&quot;
     href=&quot;#B1-L19&quot;&gt;19&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;-- create schema
CREATE TABLE people (
  id UUID PRIMARY KEY,
  name TEXT NOT NULL,
  manager_id UUID,
  FOREIGN KEY (manager_id) REFERENCES people (id)
);

-- insert data
INSERT INTO people (id, name, manager_id) VALUES
  (&quot;d3f29960-ccf0-44e4-be66-1a1544677441&quot;, &quot;Foo&quot;, &quot;076356f4-1a0e-451c-b9c6-a6f56feec941&quot;),
  (&quot;076356f4-1a0e-451c-b9c6-a6f56feec941&quot;, &quot;Bar&quot;);

-- query data, make a relation

SELECT employees.name AS &apos;employee-name&apos;,
       managers.name AS &apos;manager-name&apos;
FROM people employees
INNER JOIN people managers ON employees.manager_id = managers.id;&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;relational-review.html.0.txt&quot;&gt;plaintext&lt;/a&gt;&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L8&quot;
     href=&quot;#B2-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L9&quot;
     href=&quot;#B2-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L10&quot;
     href=&quot;#B2-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L11&quot;
     href=&quot;#B2-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L12&quot;
     href=&quot;#B2-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L13&quot;
     href=&quot;#B2-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L14&quot;
     href=&quot;#B2-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L15&quot;
     href=&quot;#B2-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L16&quot;
     href=&quot;#B2-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L17&quot;
     href=&quot;#B2-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L18&quot;
     href=&quot;#B2-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L19&quot;
     href=&quot;#B2-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L20&quot;
     href=&quot;#B2-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L21&quot;
     href=&quot;#B2-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L22&quot;
     href=&quot;#B2-L22&quot;&gt;22&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L23&quot;
     href=&quot;#B2-L23&quot;&gt;23&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L24&quot;
     href=&quot;#B2-L24&quot;&gt;24&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;;; create schema
#{{:db/ident       :person/id
   :db/valueType   :db.type/uuid
   :db/cardinality :db.cardinality/one
   :db/unique      :db.unique/value}
  {:db/ident       :person/name
   :db/valueType   :db.type/string
   :db/cardinality :db.cardinality/one}
  {:db/ident       :person/manager
   :db/valueType   :db.type/ref
   :db/cardinality :db.cardinality/one}}

;; insert data
#{{:person/id      #uuid &quot;d3f29960-ccf0-44e4-be66-1a1544677441&quot;
   :person/name    &quot;Foo&quot;
   :person/manager [:person/id #uuid &quot;076356f4-1a0e-451c-b9c6-a6f56feec941&quot;]}
  {:person/id      #uuid &quot;076356f4-1a0e-451c-b9c6-a6f56feec941&quot;
   :person/name    &quot;Bar&quot;}}

;; query data, make a relation
{:find [?employee-name ?manager-name]
 :where [[?person  :person/name    ?employee-name]
         [?person  :person/manager ?manager]
         [?manager :person/name    ?manager-name]]}&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;relational-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;(forgive any errors on the above SQL and datalog code, I didn’t run them to check. Patches
              welcome!)&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This employee example comes from the paper, and both SQL and datalog representations match the paper
              definition of &quot;relational&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Both &quot;Foo&quot; and &quot;Bar&quot; are employees, and the data is normalized. SQL represents data as tables, and
              Datomic as datoms, but relations could be derived from both, which we could view as:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;employee_name | manager_name
----------------------------
&quot;Foo&quot;         | &quot;Bar&quot;&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;relational-review.html.2.txt&quot;&gt;plaintext&lt;/a&gt;&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;The article also talks about operators, consistency and normalization, which are now so widespread and
              well-known that it feels a bit weird seeing someone advocating for it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I also stablish that &lt;code&gt;relational != SQL&lt;/code&gt;, and other databases such as Datomic are also
              relational, following Codd’s original definition.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      ANN: fallible - Fault injection library for stress-testing failure scenarios
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2021/02/17/fallible.html" title="ANN: fallible - Fault injection library for stress-testing failure scenarios" />
    <published>
      2021-02-17T00:00:00+00:00
    </published>
    <updated>
      2022-03-06T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2021/02/17/fallible.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;Yesterday I pushed v0.1.0 of &lt;a href=&quot;https://euandreh.xyz/fallible/&quot;&gt;fallible&lt;/a&gt;, a miniscule
              library for fault-injection and stress-testing C programs.&lt;/p&gt;
    </summary>
    <content type="html" xml:base="en/blog/2021/02/17/fallible.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;Yesterday I pushed v0.1.0 of &lt;a href=&quot;https://euandreh.xyz/fallible/&quot;&gt;fallible&lt;/a&gt;, a miniscule
              library for fault-injection and stress-testing C programs.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;edit&quot;&gt;&lt;em&gt;EDIT&lt;/em&gt;&lt;a class=&quot;anchor&quot;
             href=&quot;#edit&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;2021-06-12: As of &lt;a href=&quot;https://euandreh.xyz/fallible/CHANGELOG.html&quot;&gt;0.3.0&lt;/a&gt; (and beyond), the
              macro interface improved and is a bit different from what is presented in this article. If you’re
              interested, I encourage you to take a look at it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;2022-03-06: I’ve &lt;a href=&quot;https://euandre.org/static/attachments/fallible.tar.gz&quot;&gt;archived&lt;/a&gt; the
              project for now. It still needs some maturing before being usable.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;existing-solutions&quot;&gt;Existing solutions&lt;a class=&quot;anchor&quot;
             href=&quot;#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;Writing robust code can be challenging, and tools like static analyzers, fuzzers and friends can help
              you get there with more certainty. As I would try to improve some of my C code and make it more robust,
              in order to handle system crashes, filled disks, out-of-memory and similar scenarios, I didn’t find
              existing tooling to help me get there as I expected to find. I couldn’t find existing tools to help me
              explicitly stress-test those failure scenarios.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Take the &quot;&lt;a href=&quot;https://www.gnu.org/prep/standards/standards.html#Semantics&quot;&gt;Writing Robust
              Programs&lt;/a&gt;&quot; section of the GNU Coding Standards:&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;Check every system call for an error return, unless you know you wish to ignore errors. (…​) Check
                  every call to malloc or realloc to see if it returned NULL.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;From a robustness standpoint, this is a reasonable stance: if you want to have a robust program that
              knows how to fail when you’re out of memory and &lt;code&gt;malloc&lt;/code&gt; returns &lt;code&gt;NULL&lt;/code&gt;, than you
              ought to check every call to &lt;code&gt;malloc&lt;/code&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Take a sample code snippet for clarity:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;void a_function() {
  char *s1 = malloc(A_NUMBER);
  strcpy(s1, &quot;some string&quot;);

  char *s2 = malloc(A_NUMBER);
  strcpy(s2, &quot;another string&quot;);
}&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;fallible.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;At a first glance, this code is unsafe: if any of the calls to &lt;code&gt;malloc&lt;/code&gt; returns
              &lt;code&gt;NULL&lt;/code&gt;, &lt;code&gt;strcpy&lt;/code&gt; will be given a &lt;code&gt;NULL&lt;/code&gt; pointer.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;My first instinct was to change this code to something like this:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L8&quot;
     href=&quot;#B2-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L9&quot;
     href=&quot;#B2-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L10&quot;
     href=&quot;#B2-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L11&quot;
     href=&quot;#B2-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L12&quot;
     href=&quot;#B2-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L13&quot;
     href=&quot;#B2-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L14&quot;
     href=&quot;#B2-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L15&quot;
     href=&quot;#B2-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L16&quot;
     href=&quot;#B2-L16&quot;&gt;16&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;@@ -1,7 +1,15 @@
 void a_function() {
   char *s1 = malloc(A_NUMBER);
+  if (!s1) {
+    fprintf(stderr, &quot;out of memory, exitting\n&quot;);
+    exit(1);
+  }
   strcpy(s1, &quot;some string&quot;);

   char *s2 = malloc(A_NUMBER);
+  if (!s2) {
+    fprintf(stderr, &quot;out of memory, exitting\n&quot;);
+    exit(1);
+  }
   strcpy(s2, &quot;another string&quot;);
 }&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;fallible.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;As I later found out, there are at least 2 problems with this approach:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;strong&gt;it doesn’t compose&lt;/strong&gt;: this could arguably work if &lt;code&gt;a_function&lt;/code&gt; was
                  &lt;code&gt;main&lt;/code&gt;. But if &lt;code&gt;a_function&lt;/code&gt; lives inside a library, an &lt;code&gt;exit(1);&lt;/code&gt; is
                  an inelegant way of handling failures, and will catch the top-level &lt;code&gt;main&lt;/code&gt; consuming the
                  library by surprise;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;strong&gt;it gives up instead of handling failures&lt;/strong&gt;: the actual handling goes a bit beyond
                  stopping. What about open file handles, in-memory caches, unflushed bytes, etc.?&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If you could force only the second call to &lt;code&gt;malloc&lt;/code&gt; to fail, &lt;a href=
              &quot;https://www.valgrind.org/&quot;&gt;Valgrind&lt;/a&gt; would correctly complain that the program exitted with unfreed
              memory.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So the last change to make the best version of the above code is:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L8&quot;
     href=&quot;#B3-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L9&quot;
     href=&quot;#B3-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L10&quot;
     href=&quot;#B3-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L11&quot;
     href=&quot;#B3-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L12&quot;
     href=&quot;#B3-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L13&quot;
     href=&quot;#B3-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L14&quot;
     href=&quot;#B3-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L15&quot;
     href=&quot;#B3-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L16&quot;
     href=&quot;#B3-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L17&quot;
     href=&quot;#B3-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L18&quot;
     href=&quot;#B3-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L19&quot;
     href=&quot;#B3-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L20&quot;
     href=&quot;#B3-L20&quot;&gt;20&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;@@ -1,15 +1,14 @@
-void a_function() {
+bool a_function() {
   char *s1 = malloc(A_NUMBER);
   if (!s1) {
-    fprintf(stderr, &quot;out of memory, exitting\n&quot;);
-    exit(1);
+    return false;
   }
   strcpy(s1, &quot;some string&quot;);

   char *s2 = malloc(A_NUMBER);
   if (!s2) {
-    fprintf(stderr, &quot;out of memory, exitting\n&quot;);
-    exit(1);
+    free(s1);
+    return false;
   }
   strcpy(s2, &quot;another string&quot;);
 }&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;fallible.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;Instead of returning &lt;code&gt;void&lt;/code&gt;, &lt;code&gt;a_function&lt;/code&gt; now returns &lt;code&gt;bool&lt;/code&gt; to
              indicate whether an error ocurred during its execution. If &lt;code&gt;a_function&lt;/code&gt; returned a pointer to
              something, the return value could be &lt;code&gt;NULL&lt;/code&gt;, or an &lt;code&gt;int&lt;/code&gt; that represents an error
              code.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The code is now a) safe and b) failing gracefully, returning the control to the caller to properly
              handle the error case.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;After seeing similar patterns on well designed APIs, I adopted this practice for my own code, but was
              still left with manually verifying the correctness and robustness of it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;How could I add assertions around my code that would help me make sure the &lt;code&gt;free(s1);&lt;/code&gt;
              exists, before getting an error report? How do other people and projects solve this?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;From what I could see, either people a) hope for the best, b) write safe code but don’t strees-test it
              or c) write ad-hoc code to stress it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The most proeminent case of c) is SQLite: it has a few wrappers around the familiar
              &lt;code&gt;malloc&lt;/code&gt; to do fault injection, check for memory limits, add warnings, create shim layers for
              other environments, etc. All of that, however, is tightly couple with SQLite itself, and couldn’t be
              easily pulled off for using somewhere else.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When searching for it online, an &lt;a href=
              &quot;https://stackoverflow.com/questions/1711170/unit-testing-for-failed-malloc&quot;&gt;interesting thread&lt;/a&gt;
              caught my atention: fail the call to &lt;code&gt;malloc&lt;/code&gt; for each time it is called, and when the same
              stacktrace appears again, allow it to proceed.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;a class=&quot;anchor&quot;
             href=&quot;#implementation&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 working implementation of that already exists: &lt;a href=
              &quot;https://github.com/ralight/mallocfail&quot;&gt;mallocfail&lt;/a&gt;. It uses &lt;code&gt;LD_PRELOAD&lt;/code&gt; to replace
              &lt;code&gt;malloc&lt;/code&gt; at run-time, computes the SHA of the stacktrace and fails once for each SHA.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I initially envisioned and started implementing something very similar to mallocfail. However I wanted
              it to go beyond out-of-memory scenarios, and using &lt;code&gt;LD_PRELOAD&lt;/code&gt; for every possible corner that
              could fail wasn’t a good idea on the long run.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Also, mallocfail won’t work together with tools such as Valgrind, who want to do their own override of
              &lt;code&gt;malloc&lt;/code&gt; with &lt;code&gt;LD_PRELOAD&lt;/code&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I instead went with less automatic things: starting with a &lt;code&gt;fallible_should_fail(char *filename,
              int lineno)&lt;/code&gt; function that fails once for each &lt;code&gt;filename&lt;/code&gt;+&lt;code&gt;lineno&lt;/code&gt;
              combination, I created macro wrappers around common functions such as &lt;code&gt;malloc&lt;/code&gt;:&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;B4-L1&quot;
     href=&quot;#B4-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L2&quot;
     href=&quot;#B4-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L3&quot;
     href=&quot;#B4-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L4&quot;
     href=&quot;#B4-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L5&quot;
     href=&quot;#B4-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L6&quot;
     href=&quot;#B4-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L7&quot;
     href=&quot;#B4-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L8&quot;
     href=&quot;#B4-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L9&quot;
     href=&quot;#B4-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L10&quot;
     href=&quot;#B4-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L11&quot;
     href=&quot;#B4-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L12&quot;
     href=&quot;#B4-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L13&quot;
     href=&quot;#B4-L13&quot;&gt;13&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;void *fallible_malloc(size_t size, const char *const filename, int lineno) {
#ifdef FALLIBLE
  if (fallible_should_fail(filename, lineno)) {
    return NULL;
  }
#else
  (void)filename;
  (void)lineno;
#endif
  return malloc(size);
}

#define MALLOC(size) fallible_malloc(size, __FILE__, __LINE__)&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;fallible.html.3.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;With this definition, I could replace the calls to &lt;code&gt;malloc&lt;/code&gt; with &lt;code&gt;MALLOC&lt;/code&gt; (or
              any other name that you want to &lt;code&gt;#define&lt;/code&gt;):&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;B5-L1&quot;
     href=&quot;#B5-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L2&quot;
     href=&quot;#B5-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L3&quot;
     href=&quot;#B5-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L4&quot;
     href=&quot;#B5-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L5&quot;
     href=&quot;#B5-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L6&quot;
     href=&quot;#B5-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L7&quot;
     href=&quot;#B5-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L8&quot;
     href=&quot;#B5-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L9&quot;
     href=&quot;#B5-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L10&quot;
     href=&quot;#B5-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L11&quot;
     href=&quot;#B5-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L12&quot;
     href=&quot;#B5-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L13&quot;
     href=&quot;#B5-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L14&quot;
     href=&quot;#B5-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L15&quot;
     href=&quot;#B5-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L16&quot;
     href=&quot;#B5-L16&quot;&gt;16&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;--- 3.c 2021-02-17 00:15:38.019706074 -0300
+++ 4.c 2021-02-17 00:44:32.306885590 -0300
@@ -1,11 +1,11 @@
 bool a_function() {
-  char *s1 = malloc(A_NUMBER);
+  char *s1 = MALLOC(A_NUMBER);
   if (!s1) {
     return false;
   }
   strcpy(s1, &quot;some string&quot;);

-  char *s2 = malloc(A_NUMBER);
+  char *s2 = MALLOC(A_NUMBER);
   if (!s2) {
     free(s1);
     return false;&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;fallible.html.4.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;With this change, if the program gets compiled with the &lt;code&gt;-DFALLIBLE&lt;/code&gt; flag the
              fault-injection mechanism will run, and &lt;code&gt;MALLOC&lt;/code&gt; will fail once for each
              &lt;code&gt;filename&lt;/code&gt;+&lt;code&gt;lineno&lt;/code&gt; combination. When the flag is missing, &lt;code&gt;MALLOC&lt;/code&gt; is a
              very thin wrapper around &lt;code&gt;malloc&lt;/code&gt;, which compilers could remove entirely, and the
              &lt;code&gt;-lfallible&lt;/code&gt; flags can be omitted.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This applies not only to &lt;code&gt;malloc&lt;/code&gt; or other &lt;code&gt;stdlib.h&lt;/code&gt; functions. If
              &lt;code&gt;a_function&lt;/code&gt; is important or relevant, I could add a wrapper around it too, that checks if
              &lt;code&gt;fallible_should_fail&lt;/code&gt; to exercise if its callers are also doing the proper clean-up.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The actual code is just this single function, &lt;a href=
              &quot;https://euandre.org/git/fallible/tree/src/fallible.c?id=v0.1.0#n16&quot;&gt;&lt;code&gt;fallible_should_fail&lt;/code&gt;&lt;/a&gt;,
              which ended-up taking only ~40 lines. In fact, there are more lines of either Makefile (111), README.md
              (82) or troff (306) on this first version.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The price for such fine-grained control is that this approach requires more manual work.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;usage-examples&quot;&gt;Usage examples&lt;a class=&quot;anchor&quot;
             href=&quot;#usage-examples&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;malloc-from-the-readme-md&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#malloc-from-the-readme-md&quot;&gt;&lt;/a&gt;&lt;code&gt;MALLOC&lt;/code&gt; from the &lt;code&gt;README.md&lt;/code&gt;&lt;/h3&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;B6-L1&quot;
     href=&quot;#B6-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L2&quot;
     href=&quot;#B6-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L3&quot;
     href=&quot;#B6-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L4&quot;
     href=&quot;#B6-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L5&quot;
     href=&quot;#B6-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L6&quot;
     href=&quot;#B6-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L7&quot;
     href=&quot;#B6-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L8&quot;
     href=&quot;#B6-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L9&quot;
     href=&quot;#B6-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L10&quot;
     href=&quot;#B6-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L11&quot;
     href=&quot;#B6-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L12&quot;
     href=&quot;#B6-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L13&quot;
     href=&quot;#B6-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L14&quot;
     href=&quot;#B6-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L15&quot;
     href=&quot;#B6-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L16&quot;
     href=&quot;#B6-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L17&quot;
     href=&quot;#B6-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L18&quot;
     href=&quot;#B6-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L19&quot;
     href=&quot;#B6-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L20&quot;
     href=&quot;#B6-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L21&quot;
     href=&quot;#B6-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L22&quot;
     href=&quot;#B6-L22&quot;&gt;22&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;// leaky.c
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;fallible_alloc.h&amp;gt;

int main() {
  char *aaa = MALLOC(100);
  if (!aaa) {
    return 1;
  }
  strcpy(aaa, &quot;a safe use of strcpy&quot;);

  char *bbb = MALLOC(100);
  if (!bbb) {
    // free(aaa);
    return 1;
  }
  strcpy(bbb, &quot;not unsafe, but aaa is leaking&quot;);

  free(bbb);
  free(aaa);
  return 0;
}&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;fallible.html.5.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Compile with &lt;code&gt;-DFALLIBLE&lt;/code&gt; and run &lt;a href=
                &quot;https://euandreh.xyz/fallible/fallible-check.1.html&quot;&gt;&lt;code&gt;fallible-check.1&lt;/code&gt;&lt;/a&gt;:&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;B7-L1&quot;
     href=&quot;#B7-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B7-L2&quot;
     href=&quot;#B7-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B7-L3&quot;
     href=&quot;#B7-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B7-L4&quot;
     href=&quot;#B7-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B7-L5&quot;
     href=&quot;#B7-L5&quot;&gt;5&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;$ c99 -DFALLIBLE -o leaky leaky.c -lfallible
$ fallible-check ./leaky
Valgrind failed when we did not expect it to:
(...suppressed output...)
# exit status is 1&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;fallible.html.6.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&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;For my personal use, I’ll &lt;a href=&quot;https://euandre.org/git/package-repository/&quot;&gt;package&lt;/a&gt; them for
              GNU Guix and Nix. Packaging it to any other distribution should be trivial, or just downloading the
              tarball and running &lt;code&gt;[sudo] make install&lt;/code&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Patches welcome!&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      ANN: remembering - Add memory to dmenu, fzf and similar tools
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2021/01/26/remembering-ann.html" title="ANN: remembering - Add memory to dmenu, fzf and similar tools" />
    <published>
      2021-01-26T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2021/01/26/remembering-ann.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;Today I pushed v0.1.0 of &lt;a href=&quot;https://euandreh.xyz/remembering/&quot;&gt;remembering&lt;/a&gt;, a tool to
              enhance the interactive usability of menu-like tools, such as &lt;a href=
    </summary>
    <content type="html" xml:base="en/blog/2021/01/26/remembering-ann.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;Today I pushed v0.1.0 of &lt;a href=&quot;https://euandreh.xyz/remembering/&quot;&gt;remembering&lt;/a&gt;, a tool to
              enhance the interactive usability of menu-like tools, such as &lt;a href=
              &quot;https://tools.suckless.org/dmenu/&quot;&gt;dmenu&lt;/a&gt; and &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;previous-solution&quot;&gt;Previous solution&lt;a class=&quot;anchor&quot;
             href=&quot;#previous-solution&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 previously used &lt;a href=&quot;https://dmwit.com/yeganesh/&quot;&gt;yeganesh&lt;/a&gt; to fill this gap, but as I
              started to rely less on Emacs, I added fzf as my go-to tool for doing fuzzy searching on the terminal.
              But I didn’t like that fzf always showed the same order of things, when I would only need 3 or 4 commonly
              used files.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;For those who don’t know: yeganesh is a wrapper around dmenu that will remember your most used
              programs and put them on the beginning of the list of executables. This is very convenient for
              interactive prolonged use, as with time the things you usually want are right at the very beginning.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But now I had this thing, yeganesh, that solved this problem for dmenu, but didn’t for fzf.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I initially considered patching yeganesh to support it, but I found it more coupled to dmenu than I
              would desire. I’d rather have something that knows nothing about dmenu, fzf or anything, but enhances
              tools like those in a useful way.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;a class=&quot;anchor&quot;
             href=&quot;#implementation&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;Other than being decoupled from dmenu, another improvement I though that could be made on top of
              yeganesh is the programming language choice. Instead of Haskell, I went with POSIX sh. Sticking to POSIX
              sh makes it require less build-time dependencies. There aren’t any, actually. Packaging is made much
              easier due to that.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The good thing is that the program itself is small enough (&lt;a href=
              &quot;https://euandre.org/git/remembering/tree/remembering?id=v0.1.0&quot;&gt;119 lines&lt;/a&gt; on v0.1.0) that POSIX sh
              does the job just fine, combined with other POSIX utilities such as &lt;a href=
              &quot;https://www.opengroup.org/onlinepubs/9699919799/utilities/getopts.html&quot;&gt;getopts&lt;/a&gt;, &lt;a href=
              &quot;https://www.opengroup.org/onlinepubs/9699919799/utilities/sort.html&quot;&gt;sort&lt;/a&gt; and &lt;a href=
              &quot;https://www.opengroup.org/onlinepubs/9699919799/utilities/awk.html&quot;&gt;awk&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The behaviour is: given a program that will read from STDIN and write a single entry to STDOUT,
              &lt;code&gt;remembering&lt;/code&gt; wraps that program, and rearranges STDIN so that previous choices appear at the
              beginning.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Where you would do:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;$ seq 5 | fzf

  5
  4
  3
  2
&amp;gt; 1
  5/5
&amp;gt;&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;remembering-ann.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;And every time get the same order of numbers, now you can write:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L8&quot;
     href=&quot;#B2-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L9&quot;
     href=&quot;#B2-L9&quot;&gt;9&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;$ seq 5 | remembering -p seq-fzf -c fzf

  5
  4
  3
  2
&amp;gt; 1
  5/5
&amp;gt;&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;remembering-ann.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;On the first run, everything is the same. If you picked 4 on the previous example, the following run
              would be different:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L8&quot;
     href=&quot;#B3-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L9&quot;
     href=&quot;#B3-L9&quot;&gt;9&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;$ seq 5 | remembering -p seq-fzf -c fzf

  5
  3
  2
  1
&amp;gt; 4
  5/5
&amp;gt;&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;remembering-ann.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;As time passes, the list would adjust based on the frequency of your choices.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I aimed for reusability, so that I could wrap diverse commands with &lt;code&gt;remembering&lt;/code&gt; and it
              would be able to work. To accomplish that, a &quot;profile&quot; (the &lt;code&gt;-p something&lt;/code&gt; part) stores data
              about different runs separately.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I took the idea of building something small with few dependencies to other places too: - the manpages
              are written in troff directly; - the tests are just more POSIX sh files; - and a POSIX Makefile to
              &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;install&lt;/code&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I was aware of the value of sticking to coding to standards, but I had past experience mostly with
              programming language standards, such as ECMAScript, Common Lisp, Scheme, or with IndexedDB or DOM APIs.
              It felt good to rediscover these nice POSIX tools, which makes me remember of a quote by &lt;a href=
              &quot;https://en.wikipedia.org/wiki/Henry_Spencer#cite_note-3&quot;&gt;Henry Spencer&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;Those who do not understand Unix are condemned to reinvent it, poorly.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;usage-examples&quot;&gt;Usage examples&lt;a class=&quot;anchor&quot;
             href=&quot;#usage-examples&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;Here are some functions I wrote myself that you may find useful:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;run-a-command-with-fzf-on-pwd&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#run-a-command-with-fzf-on-pwd&quot;&gt;&lt;/a&gt;Run a command with fzf on &lt;code&gt;$PWD&lt;/code&gt;&lt;/h3&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;B4-L1&quot;
     href=&quot;#B4-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L2&quot;
     href=&quot;#B4-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L3&quot;
     href=&quot;#B4-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L4&quot;
     href=&quot;#B4-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L5&quot;
     href=&quot;#B4-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L6&quot;
     href=&quot;#B4-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L7&quot;
     href=&quot;#B4-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L8&quot;
     href=&quot;#B4-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L9&quot;
     href=&quot;#B4-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L10&quot;
     href=&quot;#B4-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L11&quot;
     href=&quot;#B4-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L12&quot;
     href=&quot;#B4-L12&quot;&gt;12&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;f() {
  profile=&quot;$f-shell-function(pwd | sed -e &apos;s_/_-_g&apos;)&quot;
  file=&quot;$(git ls-files | \
            remembering -p &quot;$profile&quot; \
                        -c &quot;fzf --select-1 --exit -0 --query \&quot;$2\&quot; --preview &apos;cat {}&apos;&quot;)&quot;
  if [ -n &quot;$file&quot; ]; then
    # shellcheck disable=2068
    history -s f $@
    history -s &quot;$1&quot; &quot;$file&quot;
  &quot;$1&quot; &quot;$file&quot;
fi
}&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;remembering-ann.html.3.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This way I can run &lt;code&gt;f vi&lt;/code&gt; or &lt;code&gt;f vi config&lt;/code&gt; at the root of a repository, and
                the list of files will always appear on the most used order. Adding &lt;code&gt;pwd&lt;/code&gt; to the profile
                allows it to not mix data for different repositories.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;copy-password-to-clipboard&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#copy-password-to-clipboard&quot;&gt;&lt;/a&gt;Copy password to clipboard&lt;/h3&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;B5-L1&quot;
     href=&quot;#B5-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L2&quot;
     href=&quot;#B5-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L3&quot;
     href=&quot;#B5-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L4&quot;
     href=&quot;#B5-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L5&quot;
     href=&quot;#B5-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L6&quot;
     href=&quot;#B5-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L7&quot;
     href=&quot;#B5-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L8&quot;
     href=&quot;#B5-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L9&quot;
     href=&quot;#B5-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L10&quot;
     href=&quot;#B5-L10&quot;&gt;10&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;choice=&quot;$(find &quot;$HOME/.password-store&quot; -type f                  | \
            grep -Ev &apos;(.git|.gpg-id)&apos;                           | \
            sed -e &quot;s|$HOME/.password-store/||&quot; -e &apos;s/\.gpg$//&apos; | \
            remembering -p password-store \
                        -c &apos;dmenu -l 20 -i&apos;)&quot;


if [ -n &quot;$choice&quot; ]; then
  pass show &quot;$choice&quot; -c
fi&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;remembering-ann.html.4.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Adding the above to a file and binding it to a keyboard shortcut, I can access the contents of my
                &lt;a href=&quot;https://www.passwordstore.org/&quot;&gt;password store&lt;/a&gt;, with the entries ordered by usage.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;replacing-yeganesh&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#replacing-yeganesh&quot;&gt;&lt;/a&gt;Replacing yeganesh&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Where I previously had:&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;B6-L1&quot;
     href=&quot;#B6-L1&quot;&gt;1&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;exe=$(yeganesh -x) &amp;amp;&amp; exec $exe&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;remembering-ann.html.5.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Now I have:&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;B7-L1&quot;
     href=&quot;#B7-L1&quot;&gt;1&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;exe=$(dmenu_path | remembering -p dmenu-exec -c dmenu) &amp;amp;&amp; exec $exe&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;remembering-ann.html.6.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This way, the executables appear on order of usage.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;If you don’t have &lt;code&gt;dmenu_path&lt;/code&gt;, you can get just the underlying &lt;code&gt;stest&lt;/code&gt; tool
                that looks at the executables available in your &lt;code&gt;$PATH&lt;/code&gt;. Here’s a juicy one-liner to do
                it:&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;B8-L1&quot;
     href=&quot;#B8-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B8-L2&quot;
     href=&quot;#B8-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B8-L3&quot;
     href=&quot;#B8-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B8-L4&quot;
     href=&quot;#B8-L4&quot;&gt;4&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;$ wget -O- https://dl.suckless.org/tools/dmenu-5.0.tar.gz | \
    tar Ozxf - dmenu-5.0/arg.h dmenu-5.0/stest.c          | \
    sed &apos;s|^#include &quot;arg.h&quot;$|// #include &quot;arg.h&quot;|&apos;       | \
    cc -xc - -o stest&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;remembering-ann.html.7.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;With the &lt;code&gt;stest&lt;/code&gt; utility you’ll be able to list executables in your &lt;code&gt;$PATH&lt;/code&gt;
                and pipe them to dmenu or something else yourself:&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;B9-L1&quot;
     href=&quot;#B9-L1&quot;&gt;1&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;$ (IFS=:; ./stest -flx $PATH;) | sort -u | remembering -p another-dmenu-exec -c dmenu | sh&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;remembering-ann.html.8.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;In fact, the code for &lt;code&gt;dmenu_path&lt;/code&gt; is almost just like that.&lt;/p&gt;
              &lt;/div&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;For my personal use, I’ve &lt;a href=&quot;https://euandre.org/git/package-repository/&quot;&gt;packaged&lt;/a&gt;
              &lt;code&gt;remembering&lt;/code&gt; for GNU Guix and Nix. Packaging it to any other distribution should be trivial,
              or just downloading the tarball and running &lt;code&gt;[sudo] make install&lt;/code&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Patches welcome!&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <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">
      Durable persistent trees and parser combinators - building a database
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/11/12/database-parsers-trees.html" title="Durable persistent trees and parser combinators - building a database" />
    <published>
      2020-11-12T00:00:00+00:00
    </published>
    <updated>
      2021-02-09T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2020/11/12/database-parsers-trees.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;I’ve received with certain frequency messages from people wanting to know if I’ve made any progress on
              the database project &lt;a href=&quot;../../08/31/database-i-wish-i-had.html&quot;&gt;I’ve written about&lt;/a&gt;.&lt;/p&gt;
    </summary>
    <content type="html" xml:base="en/blog/2020/11/12/database-parsers-trees.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;I’ve received with certain frequency messages from people wanting to know if I’ve made any progress on
              the database project &lt;a href=&quot;../../08/31/database-i-wish-i-had.html&quot;&gt;I’ve written about&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There are a few areas where I’ve made progress, and here’s a public post on it.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;proof-of-concept-dag-log&quot;&gt;Proof-of-concept: DAG log&lt;a class=&quot;anchor&quot;
             href=&quot;#proof-of-concept-dag-log&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 main thing I wanted to validate with a concrete implementation was the concept of modeling a DAG
              on a sequence of datoms.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The notion of a &lt;em&gt;datom&lt;/em&gt; is a rip-off from Datomic, which models data with time aware
              &lt;em&gt;facts&lt;/em&gt;, which come from RDF. RDF’s fact is a triple of subject-predicate-object, and Datomic’s
              datoms add a time component to it: subject-predicate-object-time, A.K.A.
              entity-attribute-value-transaction:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;[[person :likes &quot;pizza&quot; 0 true]
 [person :likes &quot;bread&quot; 1 true]
 [person :likes &quot;pizza&quot; 1 false]]&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;database-parsers-trees.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;The above datoms say: - at time 0, &lt;code&gt;person&lt;/code&gt; like pizza; - at time 1, &lt;code&gt;person&lt;/code&gt;
              stopped liking pizza, and started to like bread.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Datomic ensures total consistency of this ever growing log by having a single writer, the transactor,
              that will enforce it when writing.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In order to support disconnected clients, I needed a way to allow multiple writers, and I chose to do
              it by making the log not a list, but a directed acyclic graph (DAG):&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;[[person :likes  &quot;pizza&quot;  0 true]
 [0      :parent :db/root 0 true]
 [person :likes  &quot;bread&quot;  1 true]
 [person :likes  &quot;pizza&quot;  1 false]
 [1      :parent 0        1 true]]&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;database-parsers-trees.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;The extra datoms above add more information to build the directionality to the log, and instead of a
              single consistent log, the DAG could have multiple leaves that coexist, much like how different Git
              branches can have different &quot;latest&quot; commits.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In order to validate this idea, I started with a Clojure implementation. The goal was not to write the
              actual final code, but to make a proof-of-concept that would allow me to test and stretch the idea
              itself.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This code &lt;a href=
              &quot;https://euandre.org/git/mediator/tree/src/core/clojure/src/mediator.clj?id=db4a727bc24b54b50158827b34502de21dbf8948#n1&quot;&gt;
              already exists&lt;/a&gt;, but is yet fairly incomplete:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;ulist&quot;&gt;
              &lt;ul&gt;
                &lt;li&gt;
                  &lt;p&gt;the building of the index isn’t done yet (with some &lt;a href=
                  &quot;https://euandre.org/git/mediator/tree/src/core/clojure/src/mediator.clj?id=db4a727bc24b54b50158827b34502de21dbf8948#n295&quot;&gt;
                  commented code&lt;/a&gt; on the next step to be implemented)&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;the indexing is extremely inefficient, with &lt;a href=
                  &quot;https://euandre.org/git/mediator/tree/src/core/clojure/src/mediator.clj?id=db4a727bc24b54b50158827b34502de21dbf8948#n130&quot;&gt;
                  more&lt;/a&gt; &lt;a href=
                  &quot;https://euandre.org/git/mediator/tree/src/core/clojure/src/mediator.clj?id=db4a727bc24b54b50158827b34502de21dbf8948#n146&quot;&gt;
                  than&lt;/a&gt; &lt;a href=
                  &quot;https://euandre.org/git/mediator/tree/src/core/clojure/src/mediator.clj?id=db4a727bc24b54b50158827b34502de21dbf8948#n253&quot;&gt;
                  one&lt;/a&gt; occurrence of &lt;code&gt;O²&lt;/code&gt; functions;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;no query support yet.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;top-down-and-bottom-up&quot;&gt;Top-down &lt;em&gt;and&lt;/em&gt; bottom-up&lt;a class=&quot;anchor&quot;
             href=&quot;#top-down-and-bottom-up&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;However, as time passed and I started looking at what the final implementation would look like, I
              started to consider keeping the PoC around.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The top-down approach (Clojure PoC) was in fact helping guide me with the bottom-up, and I now have
              &quot;promoted&quot; the Clojure PoC into a &quot;reference implementation&quot;. It should now be a finished implementation
              that says what the expected behaviour is, and the actual code should match the behaviour.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The good thing about a reference implementation is that it has no performance of resources boundary,
              so if it ends up being 1000× slower and using 500× more memory, it should be find. The code can be also
              10× or 100× simpler, too.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;top-down-durable-persistent-trees&quot;&gt;Top-down: durable persistent trees&lt;a class=&quot;anchor&quot;
             href=&quot;#top-down-durable-persistent-trees&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;In promoting the PoC into a reference implementation, this top-down approach now needs to go beyond
              doing everything in memory, and the index data structure now needs to be disk-based.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Roughly speaking, most storage engines out there are based either on B-Trees or LSM Trees, or some
              variations of those.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But when building an immutable database, update-in-place B-Trees aren’t an option, as it doesn’t
              accommodate keeping historical views of the tree. LSM Trees may seem a better alternative, but
              duplication on the files with compaction are also ways to delete old data which is indeed useful for a
              historical view.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I think the thing I’m after is a mix of a Copy-on-Write B-Tree, which would keep historical versions
              with the write IO cost amortization of memtables of LSM Trees. I don’t know of any B-Tree variant out
              there that resembles this, so I’ll call it &quot;Flushing Copy-on-Write B-Tree&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I haven’t written any code for this yet, so all I have is a high-level view of what it will look
              like:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;like Copy-on-Write B-Trees, changing a leaf involves creating a new leaf and building a new path
                  from root to the leaf. The upside is that writes a lock free, and no coordination is needed between
                  readers and writers, ever;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;the downside is that a single leaf update means at least &lt;code&gt;H&lt;/code&gt; new nodes that will have
                  to be flushed to disk, where &lt;code&gt;H&lt;/code&gt; is the height of the tree. To avoid that, the writer
                  creates these nodes exclusively on the in-memory memtable, to avoid flushing to disk on every leaf
                  update;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;a background job will consolidate the memtable data every time it hits X MB, and persist it to
                  disk, amortizing the cost of the Copy-on-Write B-Tree;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;readers than will have the extra job of getting the latest relevant disk-resident value and merge
                  it with the memtable data.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The key difference to existing Copy-on-Write B-Trees is that the new trees are only periodically
              written to disk, and the intermediate values are kept in memory. Since no node is ever updated, the page
              utilization is maximum as it doesn’t need to keep space for future inserts and updates.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;And the key difference to existing LSM Trees is that no compaction is run: intermediate values are
              still relevant as the database grows. So this leaves out tombstones and value duplication done for write
              performance.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;One can delete intermediate index values to reclaim space, but no data is lost on the process, only
              old B-Tree values. And if the database ever comes back to that point (like when doing a historical
              query), the B-Tree will have to be rebuilt from a previous value. After all, the database &lt;em&gt;is&lt;/em&gt; a
              set of datoms, and everything else is just derived data.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Right now I’m still reading about other data structures that storage engines use, and I’ll start
              implementing the &quot;Flushing Copy-on-Write B-Tree&quot; as I learn morefootnote:learn-more-db[ If you are
              interested in learning more about this too, the very best two resources on this subject are Andy Pavlo’s
              &quot;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLSE8ODhjZXjbohkNBWQs_otTrBTrjyohi&quot;&gt;Intro to Database
              Systems&lt;/a&gt;&quot; course and Alex Petrov’s &quot;&lt;a href=&quot;https://www.databass.dev/&quot;&gt;Database Internals&lt;/a&gt;&quot; book.
              ] and mature it more.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;bottom-up-parser-combinators-and-ffi&quot;&gt;Bottom-up: parser combinators and FFI&lt;a class=&quot;anchor&quot;
             href=&quot;#bottom-up-parser-combinators-and-ffi&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 chose Rust as it has the best WebAssembly tooling support.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;My goal is not to build a Rust database, but a database that happens to be in Rust. In order to reach
              client platforms, the primary API is the FFI one.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I’m not very happy with current tools for exposing Rust code via FFI to the external world: they
              either mix C with C++, which I don’t want to do, or provide no access to the intermediate representation
              of the FFI, which would be useful for generating binding for any language that speaks FFI.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I like better the path that the author of &lt;a href=&quot;https://github.com/eqrion/cbindgen&quot;&gt;cbindgen&lt;/a&gt;
              crate &lt;a href=&quot;https://blog.eqrion.net/future-directions-for-cbindgen/&quot;&gt;proposes&lt;/a&gt;: emitting an data
              representation of the Rust C API (the author calls is a &lt;code&gt;ffi.json&lt;/code&gt; file), and than building
              transformers from the data representation to the target language. This way you could generate a C API
              &lt;em&gt;and&lt;/em&gt; the node-ffi bindings for JavaScript automatically from the Rust code.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So the first thing to be done before moving on is an FFI exporter that doesn’t mix C and C++, and
              generates said &lt;code&gt;ffi.json&lt;/code&gt;, and than build a few transformers that take this
              &lt;code&gt;ffi.json&lt;/code&gt; and generate the language bindings, be it C, C++, JavaScript, TypeScript, Kotlin,
              Swift, Dart, _etc_footnote:ffi-langs[ Those are, specifically, the languages I’m more interested on. My
              goal is supporting client applications, and those languages are the most relevant for doing so: C for
              GTK, C++ for Qt, JavaScript and TypeScript for Node.js and browser, Kotlin for Android and Swing, Swift
              for iOS, and Dart for Flutter. ].&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I think the best way to get there is by taking the existing code for cbindgen, which uses the &lt;a href=
              &quot;https://github.com/dtolnay/syn&quot;&gt;syn&lt;/a&gt; crate to parse the Rust codefootnote:rust-syn[ The fact that syn
              is an external crate to the Rust compiler points to a big warning: procedural macros are not first class
              in Rust. They are just like Babel plugins in JavaScript land, with the extra shortcoming that there is no
              specification for the Rust syntax, unlike JavaScript.&lt;/p&gt;
              &lt;p&gt;As flawed as this may be, it seems to be generally acceptable and adopted, which works against
              building a solid ecosystem for Rust.&lt;/p&gt;
              &lt;p&gt;The alternative that rust-ffi implements relies on internals of the Rust compiler, which isn’t
              actually worst, just less common and less accepted. ], and adapt it to emit the metadata.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I’ve started a fork of cbindgen: &lt;span class=&quot;line-through&quot;&gt;x-bindgen&lt;/span&gt;footnote:x-bindgen[
              &lt;em&gt;EDIT&lt;/em&gt;: now archived, the experimentation was fun. I’ve started to move more towards C, so this
              effort became deprecated. ]. Right now it is just a copy of cbindgen verbatim, and I plan to remove all C
              and C++ emitting code from it, and add a IR emitting code instead.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When starting working on x-bindgen, I realized I didn’t know what to look for in a header file, as I
              haven’t written any C code in many years. So as I was writing &lt;a href=
              &quot;https://euandre.org/git/libedn/&quot;&gt;libedn&lt;/a&gt;, I didn’t know how to build a good C API to expose. So I
              tried porting the code to C, and right now I’m working on building a &lt;em&gt;good&lt;/em&gt; C API for a JSON
              parser using parser combinators: &lt;span class=&quot;line-through&quot;&gt;ParsecC&lt;/span&gt;footnote:parsecc[
              &lt;em&gt;EDIT&lt;/em&gt;: now also archived. ].&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;After &quot;finishing&quot; ParsecC I’ll have a good notion of what a good C API is, and I’ll have a better
              direction towards how to expose code from libedn to other languages, and work on x-bindgen then.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;What both libedn and ParsecC are missing right now are proper error reporting, and property-based
              testing for libedn.&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’ve learned a lot already, and I feel the journey I’m on is worth going through.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If any of those topics interest you, message me to discuss more or contribute! Patches welcome!&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      The Next Paradigm Shift in Programming - video review
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/11/08/paradigm-shift-review.html" title="The Next Paradigm Shift in Programming - video review" />
    <published>
      2020-11-08T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2020/11/08/paradigm-shift-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;This is a review with comments of &quot;&lt;a href=&quot;https://www.youtube.com/watch?v=6YbK8o9rZfI&quot;&gt;The Next
              Paradigm Shift in Programming&lt;/a&gt;&quot;, by Richard Feldman.&lt;/p&gt;
    </summary>
    <content type="html" xml:base="en/blog/2020/11/08/paradigm-shift-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;This is a review with comments of &quot;&lt;a href=&quot;https://www.youtube.com/watch?v=6YbK8o9rZfI&quot;&gt;The Next
              Paradigm Shift in Programming&lt;/a&gt;&quot;, by Richard Feldman.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This video was &lt;em&gt;strongly&lt;/em&gt; suggested to me by a colleague. I wanted to discuss it with her, and
              when drafting my response I figured I could publish it publicly instead.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Before anything else, let me just be clear: I really like the talk, and I think Richard is a great
              public speaker. I’ve watched several of his talks over the years, and I feel I’ve followed his career at
              a distance, with much respect. This isn’t a piece criticizing him personally, and I agree with almost
              everything he said. These are just some comments but also nitpicks on a few topics I think he missed, or
              that I view differently.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;structured-programming&quot;&gt;Structured programming&lt;a class=&quot;anchor&quot;
             href=&quot;#structured-programming&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 historical overview at the beginning is very good. In fact, the very video I watched previously
              was about structured programming!&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Kevlin Henney on &quot;&lt;a href=&quot;https://www.youtube.com/watch?v=SFv8Wm2HdNM&quot;&gt;The Forgotten Art of
              Structured Programming&lt;/a&gt;&quot; does a deep-dive on the topic of structured programming, and how on his view
              it is still hidden in our code, when we do a &lt;code&gt;continue&lt;/code&gt; or a &lt;code&gt;break&lt;/code&gt; in some ways.
              Even though it is less common to see an explicit &lt;code&gt;goto&lt;/code&gt; in code these days, many of the
              original arguments of Dijkstra against explicit `goto`s is applicable to other constructs, too.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is a very mature view, and I like how he goes beyond the &quot;don’t use `goto`s&quot; heuristic and
              proposes and a much more nuanced understanding of what &quot;structured programming&quot; means.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In a few minutes, Richard is able to condense most of the significant bits of Kevlin’s talk in a
              didactical way. Good job.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;oop-like-a-distributed-system&quot;&gt;OOP like a distributed system&lt;a class=&quot;anchor&quot;
             href=&quot;#oop-like-a-distributed-system&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;Richard extrapolates Alan Kay’s original vision of OOP, and he concludes that it is more like a
              distributed system that how people think about OOP these days. But he then states that this is a rather
              bad idea, and we shouldn’t pursue it, given that distributed systems are known to be hard.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;However, his extrapolation isn’t really impossible, bad or an absurd. In fact, it has been followed
              through by Erlang. Joe Armstrong used to say that &quot;&lt;a href=
              &quot;https://www.infoq.com/interviews/johnson-armstrong-oop/&quot;&gt;Erlang might the only OOP language&lt;/a&gt;&quot;, since
              it actually adopted this paradigm.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But Erlang is a functional language. So this &quot;OOP as a distributed system&quot; view is more about
              designing systems in the large than programs in the small.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There is a switch of levels in this comparison I’m making, as can be done with any language or
              paradigm: you can have a functional-like system that is built with an OOP language (like a compiler, that
              given the same input will produce the same output), or an OOP-like system that is built with a functional
              language (Rich Hickey calls it &quot;&lt;a href=&quot;https://www.youtube.com/watch?v=ROor6_NGIWU&quot;&gt;OOP in the
              large&lt;/a&gt;&quot;footnote:langsys[ From 24:05 to 27:45. ]).&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So this jump from in-process paradigm to distributed paradigm is rather a big one, and I don’t think
              you he can argue that OOP has anything to say about software distribution across nodes. You can still
              have Erlang actors that run independently and send messages to each other without a network between them.
              Any OTP application deployed on a single node effectively works like that.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I think he went a bit too far with this extrapolation. Even though I agree it is a logical a fair one,
              it isn’t evidently bad as he painted. I would be fine working with a single-node OTP application and
              seeing someone call it &quot;a &lt;em&gt;real&lt;/em&gt; OOP program&quot;.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;first-class-immutability&quot;&gt;First class immutability&lt;a class=&quot;anchor&quot;
             href=&quot;#first-class-immutability&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 agree with his view of languages moving towards the functional paradigm. But I think you can narrow
              down the &quot;first-class immutability&quot; feature he points out as present on modern functional programming
              languages to &quot;first-class immutable data structures&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I wouldn’t categorize a language as &quot;supporting functional programming style&quot; without a library for
              functional data structures it. By discipline you can avoid side-effects, write pure functions as much as
              possible, and pass functions as arguments around is almost every language these days, but if when
              changing an element of a vector mutates things in-place, that is still not functional programming.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;To avoid that, you end-up needing to make clones of objects to pass to a function, using freezes or
              other workarounds. All those cases are when the underlying mix of OOP and functional programming
              fail.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There are some languages with third-party libraries that provide functional data structures, like
              &lt;a href=&quot;https://sinusoid.es/immer/&quot;&gt;immer&lt;/a&gt; for C++, or &lt;a href=
              &quot;https://immutable-js.github.io/immutable-js/&quot;&gt;ImmutableJS&lt;/a&gt; for JavaScript.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But functional programming is more easily achievable in languages that have them built-in, like
              Erlang, Elm and Clojure.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;managed-side-effects&quot;&gt;Managed side-effects&lt;a class=&quot;anchor&quot;
             href=&quot;#managed-side-effects&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;His proposal of adopting managed side-effects as a first-class language concept is really
              intriguing.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is something you can achieve with a library, like &lt;a href=&quot;https://redux.js.org/&quot;&gt;Redux&lt;/a&gt; for
              JavaScript or &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt; for Clojure.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I haven’t worked with a language with managed side-effects at scale, and I don’t feel this is a
              problem with Clojure or Erlang. But is this me finding a flaw in his argument or not acknowledging a
              benefit unknown to me? This is a provocative question I ask myself.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Also all FP languages with managed side-effects I know are statically-typed, and all dynamically-typed
              FP languages I know don’t have managed side-effects baked in.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;what-about-declarative-programming&quot;&gt;What about declarative programming?&lt;a class=&quot;anchor&quot;
             href=&quot;#what-about-declarative-programming&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;In &quot;&lt;a href=&quot;https://curtclifton.net/papers/MoseleyMarks06a.pdf&quot;&gt;Out of the Tar Pit&lt;/a&gt;&quot;, B. Moseley
              and P. Marks go beyond his view of functional programming as the basis, and name a possible &quot;functional
              relational programming&quot; as an even better solution. They explicitly call out some flaws in most of the
              modern functional programming languages, and instead pick declarative programming as an even better
              starting paradigm.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If the next paradigm shift is towards functional programming, will the following shift be towards
              declarative programming?&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;Beyond all Richard said, I also hear often bring up functional programming when talking about
              utilizing all cores of a computer, and how FP can help with that.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Rich Hickey makes a great case for single-process FP on his famous talk &quot;&lt;a href=
              &quot;https://www.infoq.com/presentations/Simple-Made-Easy/&quot;&gt;Simple Made Easy&lt;/a&gt;&quot;.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      DIY an offline bug tracker with text files, Git and email
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/11/07/diy-bugs.html" title="DIY an offline bug tracker with text files, Git and email" />
    <published>
      2020-11-07T00:00:00+00:00
    </published>
    <updated>
      2021-08-14T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2020/11/07/diy-bugs.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;When &lt;a href=&quot;https://github.com/github/dmca/blob/master/2020/10/2020-10-23-RIAA.md&quot;&gt;push comes to
              shove&lt;/a&gt;, the operational aspects of governance of a software project matter a lot. And everybody likes
    </summary>
    <content type="html" xml:base="en/blog/2020/11/07/diy-bugs.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;When &lt;a href=&quot;https://github.com/github/dmca/blob/master/2020/10/2020-10-23-RIAA.md&quot;&gt;push comes to
              shove&lt;/a&gt;, the operational aspects of governance of a software project matter a lot. And everybody likes
              to chime in with their alternative of how to avoid single points of failure in project governance, just
              like I’m doing right now.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The most valuable assets of a project are:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;source code&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;discussions&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;documentation&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;builds&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;tasks and bugs&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;For &lt;strong&gt;source code&lt;/strong&gt;, Git and other DVCS solve that already: everybody gets a full copy of
              the entire source code.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If your code forge is compromised, moving it to a new one takes a couple of minutes, if there isn’t a
              secondary remote serving as mirror already. In this case, no action is required.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If you’re having your &lt;strong&gt;discussions&lt;/strong&gt; by email, &quot;&lt;a href=
              &quot;https://sourcehut.org/blog/2020-10-29-how-mailing-lists-prevent-censorship/&quot;&gt;taking this archive
              somewhere else and carrying on is effortless&lt;/a&gt;&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Besides, make sure to backup archives of past discussions so that the history is also preserved when
              this migration happens.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The &lt;strong&gt;documentation&lt;/strong&gt; should &lt;a href=
              &quot;https://podcast.writethedocs.org/2017/01/25/episode-3-trends/&quot;&gt;live inside the repository
              itself&lt;/a&gt;footnote:writethedocs-in-repo[ Described as &quot;the ultimate marriage of the two&quot;. Starts at time
              31:50. ], so that not only it gets first class treatment, but also gets distributed to everybody too.
              Migrating the code to a new forge already migrates the documentation with it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;As long as you keep the &lt;strong&gt;builds&lt;/strong&gt; vendor neutral, the migration should only involve
              adapting how you call your &lt;code&gt;tests.sh&lt;/code&gt; from the format of &lt;code&gt;provider-1.yml&lt;/code&gt; uses to
              the format that &lt;code&gt;provider-2.yml&lt;/code&gt; accepts. It isn’t valuable to carry the build history with
              the project, as this data quickly decays in value as weeks and months go by, but for simple text logs
              &lt;a href=&quot;../../../../til/2020/11/30/git-notes-ci.html&quot;&gt;using Git notes&lt;/a&gt; may be just enough, and they
              would be replicated with the rest of the repository.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But for &lt;strong&gt;tasks and bugs&lt;/strong&gt; many rely on a vendor-specific service, where you register and
              manage those issues via a web browser. Some provide an &lt;a href=
              &quot;https://man.sr.ht/todo.sr.ht/#email-access&quot;&gt;interface for interacting via email&lt;/a&gt; or an API for
              {git-bug-bridges[bridging local bugs with vendor-specific services]. But they’re all layers around the
              service, that disguises it as being a central point of failure, which when compromised would lead to data
              loss. When push comes to shove, you’d loose data.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;alternative-text-files-git-and-email&quot;&gt;Alternative: text files, Git and email&lt;a class=&quot;anchor&quot;
             href=&quot;#alternative-text-files-git-and-email&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;Why not do the same as documentation, and move tasks and bugs into the repository itself?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It requires no extra tool to be installed, and fits right in the already existing workflow for source
              code and documentation.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I like to keep a &lt;a href=
              &quot;https://euandre.org/git/remembering/tree/TODOs.md?id=3f727802cb73ab7aa139ca52e729fd106ea916d0&quot;&gt;&lt;code&gt;TODOs.md&lt;/code&gt;&lt;/a&gt;
              file at the repository top-level, with two relevant sections: &quot;tasks&quot; and &quot;bugs&quot;. Then when building the
              documentation I’ll just &lt;a href=
              &quot;https://euandre.org/git/remembering/tree/aux/workflow/TODOs.sh?id=3f727802cb73ab7aa139ca52e729fd106ea916d0&quot;&gt;
              generate an HTML file from it&lt;/a&gt;, and &lt;a href=&quot;https://euandreh.xyz/remembering/TODOs.html&quot;&gt;publish&lt;/a&gt;
              it alongside the static website. All that is done on the main branch.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Any issues discussions are done in the mailing list, and a reference to a discussion could be added to
              the ticket itself later on. External contributors can file tickets by sending a patch.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The good thing about this solution is that it works for 99% of projects out there.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;For the other 1%, having Fossil’s &quot;&lt;a href=
              &quot;https://fossil-scm.org/home/doc/trunk/www/bugtheory.wiki&quot;&gt;tickets&lt;/a&gt;&quot; could be an alternative, but you
              may not want to migrate your project to Fossil to get those niceties.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though I keep a &lt;code&gt;TODOs.md&lt;/code&gt; file on the main branch, you can have a &lt;code&gt;tasks&lt;/code&gt;
              branch with a &lt;code&gt;task-n.md&lt;/code&gt; file for each task, or any other way you like.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;These tools are familiar enough that you can adjust it to fit your workflow.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      How not to interview engineers
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/10/20/wrong-interviewing.html" title="How not to interview engineers" />
    <published>
      2020-10-20T00:00:00+00:00
    </published>
    <updated>
      2020-10-24T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2020/10/20/wrong-interviewing.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;This is a response to Slava’s &quot;&lt;a href=
              &quot;https://defmacro.substack.com/p/how-to-interview-engineers&quot;&gt;How to interview engineers&lt;/a&gt;&quot; article. I
    </summary>
    <content type="html" xml:base="en/blog/2020/10/20/wrong-interviewing.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;This is a response to Slava’s &quot;&lt;a href=
              &quot;https://defmacro.substack.com/p/how-to-interview-engineers&quot;&gt;How to interview engineers&lt;/a&gt;&quot; article. I
              initially thought it was a satire, &lt;a href=
              &quot;https://defmacro.substack.com/p/how-to-interview-engineers/comments#comment-599996&quot;&gt;as have others&lt;/a&gt;,
              but he has [doubled down on it]:&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;(…​) Some parts are slightly exaggerated for sure, but the essay isn’t meant as a joke.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;That being true, he completely misses the point on how to improve hiring, and proposes a worse
              alternative on many aspects. It doesn’t qualify as provocative, it is just wrong.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I was comfortable taking it as a satire, and I would just ignore the whole thing if it wasn’t (except
              for the technical memo part), but friends of mine considered it to be somewhat reasonable. This is a
              adapted version of parts of the discussions we had, risking becoming a gigantic showcase of &lt;a href=
              &quot;https://en.wikipedia.org/wiki/Poe%27s_law&quot;&gt;Poe’s law&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In this piece, I will argument against his view, and propose an alternative approach to improve
              hiring.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It is common to find people saying how broken technical hiring is, as well put in words by a phrase on
              &lt;a href=&quot;https://news.ycombinator.com/item?id=24757511&quot;&gt;this comment&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;Everyone loves to read and write about how developer interviewing is flawed, but no one wants to
                  go out on a limb and make suggestions about how to improve it.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I guess Slava was trying to not fall on this trap, and make a suggestion on how to improve instead,
              which all went terribly wrong.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;what-not-to-do&quot;&gt;What not to do&lt;a class=&quot;anchor&quot;
             href=&quot;#what-not-to-do&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;time-candidates&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#time-candidates&quot;&gt;&lt;/a&gt;Time candidates&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Timing the candidate shows up on the &quot;talent&quot; and &quot;judgment&quot; sections, and they are both bad ideas
                for the same reason: programming is not a performance.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;What do e-sports, musicians, actors and athletes have in common: performance psychologists.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;For a pianist, their state of mind during concerts is crucial: they not only must be able to deal
                with stage anxiety, but to become really successful they will have to learn how to exploit it. The time
                window of the concert is what people practice thousands of hours for, and it is what defines one’s
                career, since how well all the practice went is irrelevant to the nature of the profession. Being able
                to leverage stage anxiety is an actual goal of them.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;That is also applicable to athletes, where the execution during a competition makes them sink or
                swim, regardless of how all the training was.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The same cannot be said about composers, though. They are more like book writers, where the value is
                not on very few moments with high adrenaline, but on the aggregate over hours, days, weeks, months and
                years. A composer may have a deadline to finish a song in five weeks, but it doesn’t really matter if
                it is done on a single night, every morning between 6 and 9, at the very last week, or any other way.
                No rigid time structure applies, only whatever fits best to the composer.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Programming is more like composing than doing a concert, which is another way of saying that
                programming is not a performance. People don’t practice algorithms for months to keep them at their
                fingertips, so that finally in a single afternoon they can sit down and write everything at once in a
                rigid 4 hours window, and launch it immediately after.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Instead software is built iteratively, by making small additions, than refactoring the
                implementation, fixing bugs, writing a lot at once, &lt;em&gt;etc&lt;/em&gt;. all while they get a firmer grasp of
                the problem, stop to think about it, come up with new ideas, &lt;em&gt;etc&lt;/em&gt;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Some specifically plan for including spaced pauses, and call it &quot;&lt;a href=
                &quot;https://www.youtube.com/watch?v=f84n5oFoZBc&quot;&gt;Hammock Driven Development&lt;/a&gt;&quot;, which is just artist’s
                &quot;creative idleness&quot; for hackers.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Unless you’re hiring for a live coding group, a competitive programming team, or a professional live
                demoer, timing the candidate that way is more harmful than useful. This type of timing doesn’t find
                good programmers, it finds performant programmers, which isn’t the same thing, and you’ll end up with
                people who can do great work on small problems but who might be unable to deal with big problems, and
                loose those who can very well handle huge problems, slowly. If you are lucky you’ll get performant
                people who can also handle big problems on the long term, but maybe not.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;An incident is the closest to a &quot;performance&quot; that it gets, and yet it is still dramatically
                different. Surely it is a high stress scenario, but while people are trying to find a root cause and
                solve the problem, only the downtime itself is visible to the exterior. It is like being part of the
                support staff backstage during a play: even though execution matters, you’re still not on the spot.
                During an incident you’re doing debugging in anger rather than live coding.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Although giving a candidate the task to write a &quot;technical memo&quot; has potential to get a measure of
                the written communication skills of someone, doing so in a hard time window also misses the point for
                the same reasons.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;pay-attention-to-typing-speed&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#pay-attention-to-typing-speed&quot;&gt;&lt;/a&gt;Pay attention to typing speed&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Typing is speed in never the bottleneck of a programmer, no matter how great they are.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;As &lt;a href=&quot;https://www.cs.utexas.edu/users/EWD/transcriptions/EWD05xx/EWD512.html&quot;&gt;Dijkstra
                said&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;But programming, when stripped of all its circumstantial irrelevancies, boils down to no more
                    and no less than very effective thinking so as to avoid unmastered complexity, to very vigorous
                    separation of your many different concerns.&lt;/p&gt;
                  &lt;/div&gt;
                &lt;/blockquote&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;In other words, programming is not about typing, it is about thinking.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Otherwise, the way to get those star programmers that can’t type fast enough a huge productivity
                boost is to give them a touch typing course. If they are so productive with typing speed being a
                limitation, imagine what they could accomplish if they had razor sharp touch typing skills?&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Also, why stop there? A good touch typist can do 90 WPM (words per minute), and a great one can do
                120 WPM, but with a stenography keyboard they get to 200 WPM+. That is double the productivity! Why not
                try &lt;a href=&quot;https://www.youtube.com/watch?v=Mz3JeYfBTcY&quot;&gt;speech-to-text&lt;/a&gt;? Make them all use
                &lt;a href=&quot;https://www.jsoftware.com/#/&quot;&gt;J&lt;/a&gt; so they all need to type less! How come nobody thought of
                that?&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;And if someone couldn’t solve the programming puzzle in the given time window, but could come back
                in the following day with an implementation that is not only faster, but uses less memory, was simpler
                to understand and easier to read than anybody else? You’d be losing that person too.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;iq&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#iq&quot;&gt;&lt;/a&gt;IQ&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;For &quot;building an extraordinary team at a hard technology startup&quot;, intelligence is not the most
                important, &lt;a href=&quot;https://www.paulgraham.com/determination.html&quot;&gt;determination is&lt;/a&gt;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;And talent isn’t &quot;IQ specialized for engineers&quot;. IQ itself isn’t a measure of how intelligent
                someone is. Ever since Alfred Binet with Théodore Simon started to formalize what would become IQ tests
                years later, they already acknowledged limitations of the technique for measuring intelligence, which
                is &lt;a href=&quot;https://sci-hub.do/https://psycnet.apa.org/doiLanding?doi=10.1037%2F1076-8971.6.1.33&quot;&gt;still
                true today&lt;/a&gt;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;So having a high IQ tells only how smart people are for a particular aspect of intelligence, which
                is not representative of programming. There are numerous aspects of programming that are covered by IQ
                measurement: how to name variables and functions, how to create models which are compatible with schema
                evolution, how to make the system dynamic for runtime parameterization without making it fragile, how
                to measure and observe performance and availability, how to pick between acquiring and paying technical
                debt, &lt;em&gt;etc&lt;/em&gt;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Not to say about everything else that a programmer does that is not purely programming. Saying high
                IQ correlates with great programming is a stretch, at best.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;ditch-hr&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#ditch-hr&quot;&gt;&lt;/a&gt;Ditch HR&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Slava tangentially picks on HR, and I will digress on that a bit:&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 good rule of thumb is that if a question could be asked by an intern in HR, it’s a
                    non-differential signaling question.&lt;/p&gt;
                  &lt;/div&gt;
                &lt;/blockquote&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Stretching it, this is a rather snobbish view of HR. Why is it that an intern in HR can’t make
                signaling questions? Could the same be said of an intern in engineering?&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;In other words: is the question not signaling because the one asking is from HR, or because the one
                asking is an intern? If the latter, than he’s just arguing that interns have no place in interviewing,
                but if the former than he was picking on HR.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Extrapolating that, it is common to find people who don’t value HR’s work, and only see them as
                inferiors doing unpleasant work, and who aren’t capable enough (or &lt;em&gt;smart&lt;/em&gt; enough) to learn
                programming.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This is equivalent to people who work primarily on backend, and see others working on frontend
                struggling and say: &quot;isn’t it just building views and showing them on the browser? How could it
                possibly be that hard? I bet I could do it better, with 20% of code&quot;. As you already know, the answer
                to it is &quot;well, why don’t you go do it, then?&quot;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This sense of superiority ignores the fact that HR have actual professionals doing actual hard work,
                not unlike programmers. If HR is inferior and so easy, why not automate everything away and get rid of
                a whole department?&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;I don’t attribute this world view to Slava, this is only an extrapolation of a snippet of the
                article.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;draconian-mistreating-of-candidates&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#draconian-mistreating-of-candidates&quot;&gt;&lt;/a&gt;Draconian mistreating of candidates&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;If I found out that people employed theatrics in my interview so that I could feel I’ve &quot;earned the
                privilege to work at your company&quot;, I would quit.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;If your moral compass is so broken that you are comfortable mistreating me while I’m a candidate, I
                immediately assume you will also mistreat me as an employee, and that the company is not a good place
                to work, as &lt;a href=&quot;https://www.paulgraham.com/apple.html&quot;&gt;evil begets stupidity&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;But the other reason programmers are fussy, I think, is that evil begets stupidity. An
                    organization that wins by exercising power starts to lose the ability to win by doing better work.
                    And it’s not fun for a smart person to work in a place where the best ideas aren’t the ones that
                    win. I think the reason Google embraced &quot;Don’t be evil&quot; so eagerly was not so much to impress the
                    outside world as to inoculate themselves against arrogance.&lt;/p&gt;
                  &lt;/div&gt;
                &lt;/blockquote&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Paul Graham goes beyond &quot;don’t be evil&quot; with a better motto: &quot;&lt;a href=
                &quot;https://www.paulgraham.com/good.html&quot;&gt;be good&lt;/a&gt;&quot;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Abusing the asymmetric nature of an interview to increase the chance that the candidate will accept
                the offer is, well, abusive. I doubt a solid team can actually be built on such poor foundations,
                surrounded by such evil measures.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;And if you really want to give engineers &quot;the measure of whoever they’re going to be working with&quot;,
                there are plenty of reasonable ways of doing it that don’t include performing fake interviews.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;personality-tests&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#personality-tests&quot;&gt;&lt;/a&gt;Personality tests&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Personality tests around the world need to be a) translated, b) adapted and c) validated. Even
                though a given test may be applicable and useful in a country, this doesn’t imply it will work for
                other countries.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Not only tests usually come with translation guidelines, but also its applicability needs to be
                validated again after the translation and adaptation is done to see if the test still measures what it
                is supposed to.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;That is also true within the same language. If a test is shown to work in England, it may not work
                in New Zealand, in spite of both speaking english. The cultural context difference is influent to the
                point of invalidating a test and making it be no longer valid.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Irregardless of the validity of the proposed &quot;big five&quot; personality test, saying &quot;just use
                attributes x, y and z this test and you’ll be fine&quot; is a rough simplification, much like saying &quot;just
                use Raft for distributed systems, after all it has been proven to work&quot; shows he throws all of that
                background away.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;So much as applying personality tests themselves is not a trivial task, and psychologists do need
                special training to become able to effectively apply one.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;more-cargo-culting&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#more-cargo-culting&quot;&gt;&lt;/a&gt;More cargo culting&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;He calls the ill-defined &quot;industry standard&quot; to be cargo-culting, but his proposal isn’t sound
                enough to not become one.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Even if the ideas were good, they aren’t solid enough, or based on solid enough things to make them
                stand out by themselves. Why is it that talent, judgment and personality are required to determine the
                fitness of a good candidate? Why not 2, 5, or 20 things? Why those specific 3? Why is talent defined
                like that? Is it just because he found talent to be like that?&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Isn’t that definitionally also &lt;a href=
                &quot;https://calteches.library.caltech.edu/51/2/CargoCult.htm&quot;&gt;cargo-culting&lt;/a&gt;footnote:cargo-cult[
                &lt;a href=
                &quot;https://web.archive.org/web/20201003090303/https://calteches.library.caltech.edu/51/2/CargoCult.htm&quot;&gt;Archived
                version&lt;/a&gt;. ]? Isn’t he just repeating whatever he found to work form him, without understanding
                why?&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;What Feynman proposes is actually the opposite:&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 summary, the idea is to try to give &lt;strong&gt;all&lt;/strong&gt; of the information to help others to
                    judge the value of your contribution; not just the information that leads to judgment in one
                    particular direction or another.&lt;/p&gt;
                  &lt;/div&gt;
                &lt;/blockquote&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;What Slava did was just another form of cargo culting, but this was one that he believed to
                work.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;what-to-do&quot;&gt;What to do&lt;a class=&quot;anchor&quot;
             href=&quot;#what-to-do&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 will not give you a list of things that &quot;worked for me, thus they are correct&quot;. I won’t either
              critique the current &quot;industry standard&quot;, nor what I’ve learned from interviewing engineers.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Instead, I’d like to invite you to learn from history, and from what other professionals have to teach
              us.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Programming isn’t an odd profession, where everything about it is different from anything else. It is
              just another episode in the &quot;technology&quot; series, which has seasons since before recorded history. It may
              be an episode where things move a bit faster, but it is fundamentally the same.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So here is the key idea: what people did &lt;em&gt;before&lt;/em&gt; software engineering?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;What hiring is like for engineers in other areas? Don’t civil, electrical and other types of
              engineering exist for much, much longer than software engineering does? What have those centuries of
              accumulated experience thought the world about technical hiring?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;What studies were performed on the different success rate of interviewing strategies? What have they
              done right and what have they done wrong?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;What is the purpose of HR? Why do they even exist? Do we need them, and if so, what for? What is the
              value they bring, since everybody insist on building an HR department in their companies? Is the
              existence of HR another form of cargo culting?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;What is industrial and organizational psychology? What is that field of study? What do they specialize
              in? What have they learned since the discipline appeared? What have they done right and wrong over
              history? Is is the current academic consensus on that area? What is a hot debate topic in academia on
              that area? What is the current bleeding edge of research? What can they teach us about hiring? What can
              they teach us about technical hiring?&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;If all I’ve said makes me a &quot;no hire&quot; in the proposed framework, I’m really glad.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This says less about my programming skills, and more about the employer’s world view, and I hope not
              to be fooled into applying for a company that adopts this one.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Claiming to be selecting &quot;extraordinary engineers&quot; isn’t an excuse to reinvent the wheel, poorly.&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>
  <entry xml:lang="en">
    <title type="html">
      cargo2nix: Dramatically simpler Rust in Nix
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/10/05/cargo2nix.html" title="cargo2nix: Dramatically simpler Rust in Nix" />
    <published>
      2020-10-05T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2020/10/05/cargo2nix.html
    </id>
    <author>
      <name>
        EuAndreh
      </name>
      <email>
        eu@euandre.org
      </email>
    </author>
    <summary type="html">
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;In the same vein of my earlier post on &lt;a href=&quot;swift2nix.html&quot;&gt;swift2nix&lt;/a&gt;, I was able to quickly
          prototype a Rust and Cargo variation of it: &lt;a href=&quot;cargo2nix-demo.tar.gz&quot;&gt;cargo2nix&lt;/a&gt;.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
    </summary>
    <content type="html" xml:base="en/blog/2020/10/05/cargo2nix.html">
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;In the same vein of my earlier post on &lt;a href=&quot;swift2nix.html&quot;&gt;swift2nix&lt;/a&gt;, I was able to quickly
          prototype a Rust and Cargo variation of it: &lt;a href=&quot;cargo2nix-demo.tar.gz&quot;&gt;cargo2nix&lt;/a&gt;.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;The initial prototype is even smaller than swift2nix: it has only 37 lines of code.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;Here’s how to use it (snippet taken from the repo’s README):&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L12&quot;
     href=&quot;#B1-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L13&quot;
     href=&quot;#B1-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L14&quot;
     href=&quot;#B1-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L15&quot;
     href=&quot;#B1-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L16&quot;
     href=&quot;#B1-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L17&quot;
     href=&quot;#B1-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L18&quot;
     href=&quot;#B1-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L19&quot;
     href=&quot;#B1-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L20&quot;
     href=&quot;#B1-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L21&quot;
     href=&quot;#B1-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L22&quot;
     href=&quot;#B1-L22&quot;&gt;22&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L23&quot;
     href=&quot;#B1-L23&quot;&gt;23&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L24&quot;
     href=&quot;#B1-L24&quot;&gt;24&lt;/a&gt;&lt;/pre&gt;
                  &lt;/td&gt;
                  &lt;td&gt;
                    &lt;pre&gt;let
  niv-sources = import ./nix/sources.nix;
  mozilla-overlay = import niv-sources.nixpkgs-mozilla;
  pkgs = import niv-sources.nixpkgs { overlays = [ mozilla-overlay ]; };
  src = pkgs.nix-gitignore.gitignoreSource [ ] ./.;
  cargo2nix = pkgs.callPackage niv-sources.cargo2nix {
    lockfile = ./Cargo.lock;
  };
in pkgs.stdenv.mkDerivation {
  inherit src;
  name = &quot;cargo-test&quot;;
  buildInputs = [ pkgs.latest.rustChannels.nightly.rust ];
  phases = [ &quot;unpackPhase&quot; &quot;buildPhase&quot; ];
  buildPhase = &apos;&apos;
    # Setup dependencies path to satisfy Cargo
    mkdir .cargo/
    ln -s ${cargo2nix.env.cargo-config} .cargo/config
    ln -s ${cargo2nix.env.vendor} vendor

    # Run the tests
    cargo test
    touch $out
  &apos;&apos;;
}&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;cargo2nix.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;That &lt;code&gt;cargo test&lt;/code&gt; part on line 20 is what I have been fighting with every &quot;*2nix&quot; available for
          Rust out there. I don’t want to bash any of them. All I want is to have full control of what Cargo commands
          to run, and the &quot;*2nix&quot; tool should only setup the environment for me. Let me drive Cargo myself, no need to
          parameterize how the tool runs it for me, or even replicate its internal behaviour by calling the Rust
          compiler directly.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;Sure it doesn’t support private registries or Git dependencies, but how much bigger does it has to be to
          support them? Also, it doesn’t support those &lt;strong&gt;yet&lt;/strong&gt;, there’s no reason it can’t be extended. I
          just haven’t needed it yet, so I haven’t added. Patches welcome.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;The layout of the &lt;code&gt;vendor/&lt;/code&gt; directory is more explicit and public then what swift2nix does: it
          is whatever the command &lt;code&gt;cargo vendor&lt;/code&gt; returns. However I haven’t checked if the shape of the
          &lt;code&gt;.cargo-checksum.json&lt;/code&gt; is specified, or internal to Cargo.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;paragraph&quot;&gt;
          &lt;p&gt;Try out the demo (also taken from the repo’s README):&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;/pre&gt;
                  &lt;/td&gt;
                  &lt;td&gt;
                    &lt;pre&gt;pushd &quot;$(mktemp -d)&quot;
wget -O- https://euandre.org/static/attachments/cargo2nix-demo.tar.gz |
        tar -xv
cd cargo2nix-demo/
nix-build&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;cargo2nix.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;Report back if you wish.&lt;/p&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      swift2nix: Run Swift inside Nix builds
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/10/05/swift2nix.html" title="swift2nix: Run Swift inside Nix builds" />
    <published>
      2020-10-05T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2020/10/05/swift2nix.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;While working on a Swift project, I didn’t find any tool that would allow Swift to run inside &lt;a href=
              &quot;https://nixos.org/&quot;&gt;Nix&lt;/a&gt; builds. Even thought you &lt;em&gt;can&lt;/em&gt; run Swift, the real problem arises
    </summary>
    <content type="html" xml:base="en/blog/2020/10/05/swift2nix.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;While working on a Swift project, I didn’t find any tool that would allow Swift to run inside &lt;a href=
              &quot;https://nixos.org/&quot;&gt;Nix&lt;/a&gt; builds. Even thought you &lt;em&gt;can&lt;/em&gt; run Swift, the real problem arises
              when using the package manager. It has many of the same problems that other package managers have when
              trying to integrate with Nix, more on this below.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I wrote a simple little tool called &lt;a href=&quot;swift2nix.tar.gz&quot;&gt;swift2nix&lt;/a&gt; that allows you trick
              Swift’s package manager into assuming everything is set up. Here’s the example from swift2nix’s README
              file:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L12&quot;
     href=&quot;#B1-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L13&quot;
     href=&quot;#B1-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L14&quot;
     href=&quot;#B1-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L15&quot;
     href=&quot;#B1-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L16&quot;
     href=&quot;#B1-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L17&quot;
     href=&quot;#B1-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L18&quot;
     href=&quot;#B1-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L19&quot;
     href=&quot;#B1-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L20&quot;
     href=&quot;#B1-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L21&quot;
     href=&quot;#B1-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L22&quot;
     href=&quot;#B1-L22&quot;&gt;22&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L23&quot;
     href=&quot;#B1-L23&quot;&gt;23&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;let
  niv-sources = import ./nix/sources.nix;
  pkgs = import niv-sources.nixpkgs { };
  src = pkgs.nix-gitignore.gitignoreSource [ ] ./.;
  swift2nix = pkgs.callPackage niv-sources.swift2nix {
    package-resolved = ./Package.resolved;
  };
in pkgs.stdenv.mkDerivation {
  inherit src;
  name = &quot;swift-test&quot;;
  buildInputs = with pkgs; [ swift ];
  phases = [ &quot;unpackPhase&quot; &quot;buildPhase&quot; ];
  buildPhase = &apos;&apos;
    # Setup dependencies path to satisfy SwiftPM
    mkdir .build
    ln -s ${swift2nix.env.dependencies-state-json} .build/dependencies-state.json
    ln -s ${swift2nix.env.checkouts} .build/checkouts

    # Run the tests
    swift test
    touch $out
  &apos;&apos;;
}&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;swift2nix.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;The key parts are lines 15~17: we just fake enough files inside &lt;code&gt;.build/&lt;/code&gt; that Swift
              believes it has already downloaded and checked-out all dependencies, and just moves on to building
              them.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I’ve worked on it just enough to make it usable for myself, so beware of unimplemented cases.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;design&quot;&gt;Design&lt;a class=&quot;anchor&quot;
             href=&quot;#design&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;What swift2nix does is just provide you with the bare minimum that Swift requires, and readily get out
              of the way:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;I explicitly did not want to generated a &lt;code&gt;Package.nix&lt;/code&gt; file, since
                  &lt;code&gt;Package.resolved&lt;/code&gt; already exists and contains the required information;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;I didn’t want to have an &quot;easy&quot; interface right out of the gate, after fighting with &quot;*2nix&quot; tools
                  that focus too much on that.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The final actual code was so small (46 lines) that it made me think about package managers, &quot;*2nix&quot;
              tools and some problems with many of them.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;problems-with-package-managers&quot;&gt;Problems with package managers&lt;a class=&quot;anchor&quot;
             href=&quot;#problems-with-package-managers&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’m going to talk about solely language package managers. Think npm and cargo, not apt-get.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Package managers want to do too much, or assume too much, or just want to take control of the entire
              build of the dependencies.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is a recurrent problem in package managers, but I don’t see it as an intrinsic one. There’s
              nothing about a &quot;package manager&quot; that prevents it from &lt;em&gt;declaring&lt;/em&gt; what it expects to encounter
              and in which format. The &lt;em&gt;declaring&lt;/em&gt; part is important: it should be data, not code, otherwise
              you’re back in the same problem, just like lockfiles are just data. Those work in any language, and tools
              can cooperate happily.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There’s no need for this declarative expectation to be standardized, or be made compatible across
              languages. That would lead to a poor format that no package manager really likes. Instead, If every
              package manager could say out loud what it wants to see exactly, than more tools like swift2nix could
              exist, and they would be more reliable.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This could even work fully offline, and be simply a mapping from the lockfile (the
              &lt;code&gt;Package.resolved&lt;/code&gt; in Swift’s case) to the filesystem representation. For Swift, the
              &lt;code&gt;.build/dependencies-state.json&lt;/code&gt; comes very close, but it is internal to the package
              manager.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though this pain only exists when trying to use Swift inside Nix, it sheds light into this common
              implicit coupling that package managers have. They usually have fuzzy boundaries and tight coupling
              between:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;resolving the dependency tree and using some heuristic to pick a package version;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;generating a lockfile with the exact pinned versions;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;downloading the dependencies present on the lockfile into some local cache;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;arranging the dependencies from the cache in a meaningful way for itself inside the project;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;work using the dependencies while &lt;em&gt;assuming&lt;/em&gt; that step 4 was done.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;When you run &lt;code&gt;npm install&lt;/code&gt; in a repository with no lockfile, it does 1~4. If you do the
              same with &lt;code&gt;cargo build&lt;/code&gt;, it does 1~5. That’s too much: many of those assumptions are implicit
              and internal to the package manager, and if you ever need to rearrange them, you’re on your own. Even
              though you can perform some of those steps, you can’t compose or rearrange them.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Instead a much saner approach could be:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;this stays the same;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;this also stays the same;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;be able to generate some JSON/TOML/edn which represents the local expected filesystem layout with
                  dependencies (i.e. exposing what the package manager expects to find), let’s call it
                  &lt;code&gt;local-registry.json&lt;/code&gt;;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;if a &lt;code&gt;local-registry.json&lt;/code&gt; was provided, do a build using that. Otherwise generate its
                  own, by downloading the dependencies, arranging them, &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The point is just making what the package manager requires visible to the outside world via some
              declarative data. If this data wasn’t provided, it can move on to doing its own automatic things.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;By making the expectation explicit and public, one can plug tools &lt;em&gt;à la carte&lt;/em&gt; if desired, but
              doesn’t prevent the default code path of doing things the exact same way they are now.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;problems-with-2nix-tools&quot;&gt;Problems with &quot;*2nix&quot; tools&lt;a class=&quot;anchor&quot;
             href=&quot;#problems-with-2nix-tools&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 have to admit: I’m unhappy with most of they.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;They conflate &quot;using Nix&quot; with &quot;replicating every command of the package manager inside Nix&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The avoidance of an &quot;easy&quot; interface that I mentioned above comes from me fighting with some of the
              &quot;*2nix&quot; tools much like I have to fight with package managers: I don’t want to offload all build
              responsibilities to the &quot;*2nix&quot; tool, I just want to let it download some of the dependencies and get out
              of the way. I want to stick with &lt;code&gt;npm test&lt;/code&gt; or &lt;code&gt;cargo build&lt;/code&gt;, and Nix should only
              provide the environment.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This is something that &lt;a href=&quot;https://github.com/svanderburg/node2nix&quot;&gt;node2nix&lt;/a&gt; does right. It
              allows you to build the Node.js environment to satisfy NPM, and you can keep using NPM for everything
              else:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;ln -s ${node2nix-package.shell.nodeDependencies}/lib/node_modules ./node_modules
npm test&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;swift2nix.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;Its natural to want to put as much things into Nix as possible to benefit from Nix’s advantages. Isn’t
              that how NixOS itself was born?&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;But a &quot;*2nix&quot; tool should leverage Nix, not be coupled with it. The above example lets you run any
              arbitrary NPM command while profiting from isolation and reproducibility that Nix provides. It is even
              less brittle: any changes to how NPM runs some things will be future-compatible, since node2nix isn’t
              trying to replicate what NPM does, or fiddling with NPM’s internal.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;**A &quot;*2nix&quot; tool should build the environment, preferably from the lockfile directly and offload
              everything else to the package manager**. The rest is just nice-to-have.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;swift2nix itself could provide an &quot;easy&quot; interface, something that allows you to write:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;nix-build -A swift2nix.release
nix-build -A swift2nix.test&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;swift2nix.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;The implementation of those would be obvious: create a new &lt;code&gt;pkgs.stdenv.mkDerivation&lt;/code&gt; and
              call &lt;code&gt;swift build -c release&lt;/code&gt; and &lt;code&gt;swift test&lt;/code&gt; while using
              &lt;code&gt;swift2nix.env&lt;/code&gt; under the hood.&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;Package managers should provide exact dependencies via a data representation, i.e. lockfiles, and
              expose via another data representation how they expect those dependencies to appear on the filesystem,
              i.e. &lt;code&gt;local-registry.json&lt;/code&gt;. This allows package managers to provide an API so that external
              tools can create mirrors, offline builds, other registries, isolated builds, &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;&quot;*2nix&quot; tools should build simple functions that leverage that
              &lt;code&gt;local-registry.json&lt;/code&gt;footnote:local-registry[ This &lt;code&gt;local-registry.json&lt;/code&gt; file
              doesn’t have to be checked-in the repository at all. It could be always generated on the fly, much like
              how Swift’s &lt;code&gt;dependencies-state.json&lt;/code&gt; is. ] data and offload all the rest back to the package
              manager itself. This allows the &quot;*2nix&quot; to not keep chasing the package manager evolution, always trying
              to duplicate its behaviour.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      The database I wish I had
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/08/31/database-i-wish-i-had.html" title="The database I wish I had" />
    <published>
      2020-08-31T00:00:00+00:00
    </published>
    <updated>
      2020-09-03T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2020/08/31/database-i-wish-i-had.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;I watched the talk &quot;&lt;a href=&quot;https://vimeo.com/230142234&quot;&gt;Platform as a Reflection of Values: Joyent,
              Node.js and beyond&lt;/a&gt;&quot; by Bryan Cantrill, and I think he was able to put into words something I already
    </summary>
    <content type="html" xml:base="en/blog/2020/08/31/database-i-wish-i-had.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;I watched the talk &quot;&lt;a href=&quot;https://vimeo.com/230142234&quot;&gt;Platform as a Reflection of Values: Joyent,
              Node.js and beyond&lt;/a&gt;&quot; by Bryan Cantrill, and I think he was able to put into words something I already
              felt for some time: if there’s no piece of software out there that reflects your values, it’s time for
              you to build that softwarefootnote:talk-time[ At the very end, at time 29:49. When talking about the
              draft of this article with a friend, he noted that Bryan O’Sullivan (a different Bryan) says a similar
              thing on his talk &quot;&lt;a href=&quot;https://www.youtube.com/watch?v=ZR3Jirqk6W8&quot;&gt;Running a startup on
              Haskell&lt;/a&gt;&quot;, at time 4:15. ].&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I kind of agree with what he said, because this is already happening to me. I long for a database with
              a certain set of values, and for a few years I was just waiting for someone to finally write it. After
              watching his talk, Bryan is saying to me: &quot;time to stop waiting, and start writing it yourself&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;So let me try to give an overview of such database, and go over its values.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;overview&quot;&gt;Overview&lt;a class=&quot;anchor&quot;
             href=&quot;#overview&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 want a database that allows me to create decentralized client-side applications that can sync
              data.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The best one-line description I can give right now 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;It’s sort of like PouchDB, Git, Datomic, SQLite and Mentat.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;A more descriptive version could 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;An embedded, immutable, syncable relational database.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Let’s go over what I mean by each of those aspects one by one.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;embedded&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#embedded&quot;&gt;&lt;/a&gt;Embedded&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;I think the server-side database landscape is diverse and mature enough for my needs (even though I
                end up choosing SQLite most of the time), and what I’m after is a database to be embedded on
                client-side applications itself, be it desktop, browser, mobile, &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The purpose of such database is not to keep some local cache of data in case of lost connectivity:
                we have good solutions for that already. It should serve as the source of truth, and allow the
                application to work on top of it.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;https://sqlite.org/index.html&quot;&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/a&gt; is a great example of that: it
                is a very powerful relational database that runs &lt;a href=&quot;https://sqlite.org/whentouse.html&quot;&gt;almost
                anywhere&lt;/a&gt;. What I miss from it that SQLite doesn’t provide is the ability to run it on the browser:
                even though you could compile it to WebAssembly, &lt;span class=&quot;line-through&quot;&gt;it assumes a POSIX
                filesystem that would have to be emulated&lt;/span&gt;footnote:posix-sqlite[ It was &lt;a href=
                &quot;https://news.ycombinator.com/item?id=24338881&quot;&gt;pointed out to me&lt;/a&gt; that SQLite doesn’t assume the
                existence of a POSIX filesystem, as I wrongly stated. Thanks for the correction.&lt;/p&gt;
                &lt;p&gt;This makes me consider it as a storage backend all by itself. I initially considered having an
                SQLite storage backend as one implementation of the POSIX filesystem storage API that I mentioned. My
                goal was to rely on it so I could validate the correctness of the actual implementation, given SQLite’s
                robustness.&lt;/p&gt;
                &lt;p&gt;However it may even better to just use SQLite, and get an ACID backend without recreating a big part
                of SQLite from scratch. In fact, both Datomic and PouchDB didn’t create an storage backend for
                themselves, they just plugged on what already existed and already worked. I’m beginning to think that
                it would be wiser to just do the same, and drop entirely the from scratch implementation that I
                mentioned.&lt;/p&gt;
                &lt;p&gt;That’s not to say that adding an IndexedDB compatibility layer to SQLite would be enough to make it
                fit the other requirements I mention on this page. SQLite still is an implementation of a
                update-in-place, SQL, table-oriented database. It is probably true that cherry-picking the relevant
                parts of SQLite (like storage access, consistency, crash recovery, parser generator,
                &lt;strong&gt;etc.&lt;/strong&gt;) and leaving out the unwanted parts (SQL, tables, threading,
                &lt;strong&gt;etc.&lt;/strong&gt;) would be better than including the full SQLite stack, that’s simply an
                optimization. Both could even coexist, if desired.&lt;/p&gt;
                &lt;p&gt;SQLite would have to be treated similarly to how Datomic treats SQL databases: instead of having a
                table for each entities, spread attributes over the tables, &lt;strong&gt;etc.&lt;/strong&gt;, it treats SQL
                databases as a key-value storage so it doesn’t have to re-implement interacting with the disk that
                other databases do well.&lt;/p&gt;
                &lt;p&gt;The tables would contain blocks of binary data, so there isn’t a difference on how the SQLite
                storage backend behaves and how the IndexedDB storage backend behaves, much like how Datomic works the
                same regardless of the storage backend, same for PouchDB.&lt;/p&gt;
                &lt;p&gt;I welcome corrections on what I said above, too. ].&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;https://pouchdb.com/&quot;&gt;&lt;strong&gt;PouchDB&lt;/strong&gt;&lt;/a&gt; is another great example: it’s a full
                reimplementation of &lt;a href=&quot;https://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt; that targets JavaScript
                environments, mainly the browser and Node.js. However I want a tool that can be deployed anywhere, and
                not limit its applications to places that already have a JavaScript runtime environment, or force the
                developer to bundle a JavaScript runtime environment with their application. This is true for GTK+
                applications, command line programs, Android apps, &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;https://github.com/mozilla/mentat&quot;&gt;&lt;strong&gt;Mentat&lt;/strong&gt;&lt;/a&gt; was an interesting project,
                but its reliance on SQLite makes it inherit most of the downsides (and benefits too) of SQLite
                itself.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Having such a requirement imposes a different approach to storage: we have to decouple the knowledge
                about the intricacies of storage from the usage of storage itself, so that a module (say query
                processing) can access storage through an API without needing to know about its implementation. This
                allows the database to target a POSIX filesystems storage API and an IndexedDB storage API, and make
                the rest of the code agnostic about storage. PouchDB has such mechanism (called &lt;a href=
                &quot;https://pouchdb.com/adapters.html&quot;&gt;adapters&lt;/a&gt;) and Datomic has them too (called &lt;a href=
                &quot;https://docs.datomic.com/on-prem/storage.html&quot;&gt;storage services&lt;/a&gt;).&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This would allow the database to adapt to where it is embedded: when targeting the browser the
                IndexedDB storage API would provide the persistence layer that the database requires, and similarly the
                POSIX filesystem storage API would provide the persistence layer when targeting POSIX systems (like
                desktops, mobile, &lt;em&gt;etc.&lt;/em&gt;).&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;But there’s also an extra restriction that comes from by being embedded: it needs to provide and
                embeddable artifact, most likely a binary library object that exposes a C compatible FFI, similar to
                &lt;a href=&quot;https://www.sqlite.org/amalgamation.html&quot;&gt;how SQLite does&lt;/a&gt;. Bundling a full runtime
                environment is possible, but doesn’t make it a compelling solution for embedding. This rules out most
                languages, and leaves us with C, Rust, Zig, and similar options that can target POSIX systems and
                WebAssembly.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;immutable&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#immutable&quot;&gt;&lt;/a&gt;Immutable&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Being immutable means that only new information is added, no in-place update ever happens, and
                nothing is ever deleted.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Having an immutable database presents us with similar trade-offs found in persistent data
                structures, like lack of coordination when doing reads, caches being always coherent, and more usage of
                space.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;https://www.datomic.com/&quot;&gt;&lt;strong&gt;Datomic&lt;/strong&gt;&lt;/a&gt; is the go to database example of
                this: it will only add information (datoms) and allows you to query them in a multitude of ways. Stuart
                Halloway calls it &quot;accumulate-only&quot; over &quot;append-only&quot;footnote:accumulate-only[ Video &quot;&lt;a href=
                &quot;https://vimeo.com/116315075&quot;&gt;Day of Datomic Part 2&lt;/a&gt;&quot; on Datomic’s information model, at time 12:28.
                ]:&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;It’s accumulate-only, it is not append-only. So append-only, most people when they say that
                    they’re implying something physical about what happens.&lt;/p&gt;
                  &lt;/div&gt;
                &lt;/blockquote&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Also a database can be append-only and overwrite existing information with new information, by doing
                clean-ups of &quot;stale&quot; data. I prefer to adopt the &quot;accumulate-only&quot; naming and approach.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;https://git-scm.com/&quot;&gt;&lt;strong&gt;Git&lt;/strong&gt;&lt;/a&gt; is another example of this: new commits are
                always added on top of the previous data, and it grows by adding commits instead of replacing existing
                ones.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Git repositories can only grow in size, and that is not only an acceptable condition, but also one
                of the reasons to use it.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;All this means that no in-place updates happens on data, and the database will be much more
                concerned about how compact and efficiently it stores data than how fast it does writes to disk. Being
                embedded, the storage limitation is either a) how much storage the device has or b) how much storage
                was designed for the application to consume. So even though the database could theoretically operate
                with hundreds of TBs, a browser page or mobile application wouldn’t have access to this amount of
                storage. SQLite even &lt;a href=&quot;https://sqlite.org/limits.html&quot;&gt;says&lt;/a&gt; that it does support
                approximately 280 TBs of data, but those limits are untested.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The upside of keeping everything is that you can have historical views of your data, which is very
                powerful. This also means that applications should turn this off when not relevantfootnote:no-history[
                Similar to &lt;a href=&quot;https://docs.datomic.com/cloud/best.html#nohistory-for-high-churn&quot;&gt;Datomic’s
                &lt;code&gt;:db/noHistory&lt;/code&gt;&lt;/a&gt;. ].&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;syncable&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#syncable&quot;&gt;&lt;/a&gt;Syncable&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This is a frequent topic when talking about offline-first solutions. When building applications
                that:&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;ulist&quot;&gt;
                &lt;ul&gt;
                  &lt;li&gt;
                    &lt;p&gt;can fully work offline,&lt;/p&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;stores data,&lt;/p&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;propagates that data to other application instances,&lt;/p&gt;
                  &lt;/li&gt;
                &lt;/ul&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;then you’ll need a conflict resolution strategy to handle all the situations where different
                application instances disagree. Those application instances could be a desktop and a browser version of
                the same application, or the same mobile app in different devices.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;A three-way merge seems to be the best approach, on top of which you could add application specific
                conflict resolution functions, like:&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;ulist&quot;&gt;
                &lt;ul&gt;
                  &lt;li&gt;
                    &lt;p&gt;pick the change with higher timestamp;&lt;/p&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;if one change is a delete, pick it;&lt;/p&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;present the diff on the screen and allow the user to merge them.&lt;/p&gt;
                  &lt;/li&gt;
                &lt;/ul&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Some databases try to make this &quot;easy&quot;, by choosing a strategy for you, but I’ve found that
                different applications require different conflict resolution strategies. Instead, the database should
                leave this up to the user to decide, and provide tools for them to do it.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Merge_(version_control)&quot;&gt;&lt;strong&gt;Three-way merges in version
                control&lt;/strong&gt;&lt;/a&gt; are the best example, performing automatic merges when possible and asking the
                user to resolve conflicts when they appear.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The unit of conflict for a version control system is a line of text. The database equivalent would
                probably be a single attribute, not a full entity or a full row.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Making all the conflict resolution logic be local should allow the database to have encrypted
                remotes similar to how &lt;a href=
                &quot;https://spwhitton.name/tech/code/git-remote-gcrypt/&quot;&gt;git-remote-gcrypt&lt;/a&gt; adds this functionality to
                Git. This would enable users to sync the application data across devices using an untrusted
                intermediary.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;relational&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#relational&quot;&gt;&lt;/a&gt;Relational&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;I want the power of relational queries on the client applications.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Most of the arguments against traditional table-oriented relational databases are related to write
                performance, but those don’t apply here. The bottlenecks for client applications usually aren’t write
                throughput. Nobody is interested in differentiating between 1 MB/s or 10 MB/s when you’re limited to
                500 MB total.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The relational model of the database could either be based on SQL and tables like in SQLite, or
                maybe &lt;a href=&quot;https://docs.datomic.com/on-prem/query.html&quot;&gt;datalog&lt;/a&gt; and &lt;a href=
                &quot;https://docs.datomic.com/cloud/whatis/data-model.html#datoms&quot;&gt;datoms&lt;/a&gt; like in Datomic.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;from-aspects-to-values&quot;&gt;From aspects to values&lt;a class=&quot;anchor&quot;
             href=&quot;#from-aspects-to-values&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;Now let’s try to translate the aspects above into values, as suggested by Bryan Cantrill.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;portability&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#portability&quot;&gt;&lt;/a&gt;Portability&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;Being able to target so many different platforms is a bold goal, and the embedded nature of the
                database demands portability to be a core value.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;integrity&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#integrity&quot;&gt;&lt;/a&gt;Integrity&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;When the local database becomes the source of truth of the application, it must provide consistency
                guarantees that enables applications to rely on it.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;expressiveness&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#expressiveness&quot;&gt;&lt;/a&gt;Expressiveness&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The database should empower applications to slice and dice the data in any way it wants to.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;a class=&quot;anchor&quot;
             href=&quot;#next-steps&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;Since I can’t find any database that fits these requirements, I’ve finally come to terms with doing it
              myself.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;It’s probably going to take me a few years to do it, and making it portable between POSIX and
              IndexedDB will probably be the biggest challenge. I got myself a few books on databases to start.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I wonder if I’ll ever be able to get this done.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;external-links&quot;&gt;External links&lt;a class=&quot;anchor&quot;
             href=&quot;#external-links&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;See discussions on &lt;a href=
              &quot;https://old.reddit.com/r/programming/comments/ijwz5b/the_database_i_wish_i_had/&quot;&gt;Reddit&lt;/a&gt;, &lt;a href=
              &quot;https://lobste.rs/s/m9vkg4/database_i_wish_i_had&quot;&gt;lobsters&lt;/a&gt;, &lt;a href=
              &quot;https://news.ycombinator.com/item?id=24337244&quot;&gt;HN&lt;/a&gt; and &lt;a href=
              &quot;https://lists.sr.ht/~euandreh/public-inbox/%3C010101744a592b75-1dce9281-f0b8-4226-9d50-fd2c7901fa72-000000%40us-west-2.amazonses.com%3E&quot;&gt;
              a lengthy email exchange&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      Guix inside sourcehut builds.sr.ht CI
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2020/08/10/guix-srht.html" title="Guix inside sourcehut builds.sr.ht CI" />
    <published>
      2020-08-10T00:00:00+00:00
    </published>
    <updated>
      2020-08-19T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2020/08/10/guix-srht.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;After the release of the &lt;a href=&quot;https://man.sr.ht/builds.sr.ht/compatibility.md#nixos&quot;&gt;NixOS images
              in builds.sr.ht&lt;/a&gt; and much usage of it, I also started looking at &lt;a href=
    </summary>
    <content type="html" xml:base="en/blog/2020/08/10/guix-srht.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;After the release of the &lt;a href=&quot;https://man.sr.ht/builds.sr.ht/compatibility.md#nixos&quot;&gt;NixOS images
              in builds.sr.ht&lt;/a&gt; and much usage of it, I also started looking at &lt;a href=
              &quot;https://guix.gnu.org/&quot;&gt;Guix&lt;/a&gt; and wondered if I could get it on the awesome builds.sr.ht service.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The Guix manual section on the &lt;a href=
              &quot;https://guix.gnu.org/manual/en/guix.html#Binary-Installation&quot;&gt;binary installation&lt;/a&gt; is very thorough,
              and even a &lt;a href=&quot;https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh&quot;&gt;shell installer
              script&lt;/a&gt; is provided, but it is built towards someone installing Guix on their personal computer, and
              relies heavily on interactive input.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I developed the following set of scripts that I have been using for some time to run Guix tasks inside
              builds.sr.ht jobs. First, &lt;code&gt;install-guix.sh&lt;/code&gt;:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L12&quot;
     href=&quot;#B1-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L13&quot;
     href=&quot;#B1-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L14&quot;
     href=&quot;#B1-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L15&quot;
     href=&quot;#B1-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L16&quot;
     href=&quot;#B1-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L17&quot;
     href=&quot;#B1-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L18&quot;
     href=&quot;#B1-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L19&quot;
     href=&quot;#B1-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L20&quot;
     href=&quot;#B1-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L21&quot;
     href=&quot;#B1-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L22&quot;
     href=&quot;#B1-L22&quot;&gt;22&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L23&quot;
     href=&quot;#B1-L23&quot;&gt;23&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L24&quot;
     href=&quot;#B1-L24&quot;&gt;24&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L25&quot;
     href=&quot;#B1-L25&quot;&gt;25&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L26&quot;
     href=&quot;#B1-L26&quot;&gt;26&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L27&quot;
     href=&quot;#B1-L27&quot;&gt;27&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L28&quot;
     href=&quot;#B1-L28&quot;&gt;28&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L29&quot;
     href=&quot;#B1-L29&quot;&gt;29&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L30&quot;
     href=&quot;#B1-L30&quot;&gt;30&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L31&quot;
     href=&quot;#B1-L31&quot;&gt;31&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L32&quot;
     href=&quot;#B1-L32&quot;&gt;32&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L33&quot;
     href=&quot;#B1-L33&quot;&gt;33&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L34&quot;
     href=&quot;#B1-L34&quot;&gt;34&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L35&quot;
     href=&quot;#B1-L35&quot;&gt;35&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L36&quot;
     href=&quot;#B1-L36&quot;&gt;36&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B1-L37&quot;
     href=&quot;#B1-L37&quot;&gt;37&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;#!/usr/bin/env bash
set -x
set -Eeuo pipefail

VERSION=&apos;1.0.1&apos;
SYSTEM=&apos;x86_64-linux&apos;
BINARY=&quot;guix-binary-${VERSION}.${SYSTEM}.tar.xz&quot;

cd /tmp
wget &quot;https://ftp.gnu.org/gnu/guix/${BINARY}&quot;
tar -xf &quot;${BINARY}&quot;

sudo mv var/guix /var/
sudo mv gnu /
sudo mkdir -p ~root/.config/guix
sudo ln -fs /var/guix/profiles/per-user/root/current-guix ~root/.config/guix/current

GUIX_PROFILE=&quot;$(echo ~root)/.config/guix/current&quot;
source &quot;${GUIX_PROFILE}/etc/profile&quot;

groupadd --system guixbuild
for i in $(seq -w 1 10);
do
  useradd -g guixbuild                       \
          -G guixbuild                       \
          -d /var/empty                      \
          -s &quot;$(command -v nologin)&quot;         \
          -c &quot;Guix build user ${i}&quot; --system \
          &quot;guixbuilder${i}&quot;;
done

mkdir -p /usr/local/bin
cd /usr/local/bin
ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix .
ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix-daemon .

guix archive --authorize &amp;lt; ~root/.config/guix/current/share/guix/ci.guix.gnu.org.pub&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;guix-srht.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;Almost all of it is taken directly from the &lt;a href=
              &quot;https://guix.gnu.org/manual/en/guix.html#Binary-Installation&quot;&gt;binary installation&lt;/a&gt; section from the
              manual, with the interactive bits stripped out: after downloading and extracting the Guix tarball, we
              create some symlinks, add guixbuild users and authorize the &lt;code&gt;ci.guix.gnu.org.pub&lt;/code&gt; signing
              key.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;After installing Guix, we perform a &lt;code&gt;guix pull&lt;/code&gt; to update Guix inside
              &lt;code&gt;start-guix.sh&lt;/code&gt;:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L8&quot;
     href=&quot;#B2-L8&quot;&gt;8&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;#!/usr/bin/env bash
set -x
set -Eeuo pipefail

sudo guix-daemon --build-users-group=guixbuild &amp;
guix pull
guix package -u
guix --version&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;guix-srht.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;Then we can put it all together in a sample &lt;code&gt;.build.yml&lt;/code&gt; configuration file I’m using
              myself:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L8&quot;
     href=&quot;#B3-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L9&quot;
     href=&quot;#B3-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L10&quot;
     href=&quot;#B3-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L11&quot;
     href=&quot;#B3-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L12&quot;
     href=&quot;#B3-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L13&quot;
     href=&quot;#B3-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L14&quot;
     href=&quot;#B3-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L15&quot;
     href=&quot;#B3-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L16&quot;
     href=&quot;#B3-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L17&quot;
     href=&quot;#B3-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L18&quot;
     href=&quot;#B3-L18&quot;&gt;18&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;image: debian/stable
packages:
  - wget
sources:
  - https://git.sr.ht/~euandreh/songbooks
tasks:
  - install-guix: |
      cd ./songbooks/
      ./scripts/install-guix.sh
      ./scripts/start-guix.sh
      echo &apos;sudo guix-daemon --build-users-group=guixbuild &amp;amp;&apos; &amp;gt;&amp;gt; ~/.buildenv
      echo &apos;export PATH=&quot;${HOME}/.config/guix/current/bin${PATH:+:}$PATH&quot;&apos; &amp;gt;&amp;gt; ~/.buildenv
  - tests: |
      cd ./songbooks/
      guix environment -m build-aux/guix.scm -- make check
  - docs: |
      cd ./songbooks/
      guix environment -m build-aux/guix.scm -- make publish-dist&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;guix-srht.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;We have to add the &lt;code&gt;guix-daemon&lt;/code&gt; to &lt;code&gt;~/.buildenv&lt;/code&gt; so it can be started on every
              following task run. Also, since we used &lt;code&gt;wget&lt;/code&gt; inside &lt;code&gt;install-guix.sh&lt;/code&gt;, we had to
              add it to the images package list.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;After the &lt;code&gt;install-guix&lt;/code&gt; task, you can use Guix to build and test your project, or run any
              &lt;code&gt;guix environment --ad-hoc my-package – my script&lt;/code&gt; :)&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;improvements&quot;&gt;Improvements&lt;a class=&quot;anchor&quot;
             href=&quot;#improvements&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 I originally created this code I had a reason why to have both a &lt;code&gt;sudo&lt;/code&gt; call for
              &lt;code&gt;sudo ./scripts/install-guix.sh&lt;/code&gt; and &lt;code&gt;sudo&lt;/code&gt; usages inside
              &lt;code&gt;install-guix.sh&lt;/code&gt; itself. I couldn’t figure out why (it feels like my past self was a bit
              smarter 😬), but it feels ugly now. If it is truly required I could add an explanation for it, or remove
              this entirely in favor of a more elegant solution.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I could also contribute the Guix image upstream to builds.sr.ht, but there wasn’t any build or smoke
              tests in the original &lt;a href=&quot;https://git.sr.ht/~sircmpwn/builds.sr.ht&quot;&gt;repository&lt;/a&gt;, so I wasn’t
              inclined to make something that just “works on my machine” or add a maintainence burden to the author. I
              didn’t look at it again recently, though.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      Using NixOS as an stateless workstation
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2019/06/02/nixos-stateless-workstation.html" title="Using NixOS as an stateless workstation" />
    <published>
      2019-06-02T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2019/06/02/nixos-stateless-workstation.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;Last weekfootnote:last-week[ &quot;Last week&quot; as of the start of this writing, so around the end of May
              2019. ] I changed back to an oldfootnote:old-computer[ I was using a 32GB RAM, i7 and 250GB SSD Samsung
    </summary>
    <content type="html" xml:base="en/blog/2019/06/02/nixos-stateless-workstation.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;Last weekfootnote:last-week[ &quot;Last week&quot; as of the start of this writing, so around the end of May
              2019. ] I changed back to an oldfootnote:old-computer[ I was using a 32GB RAM, i7 and 250GB SSD Samsung
              laptop. The switch was back to a 8GB RAM, i5 and 500GB HDD Dell laptop. The biggest difference I noticed
              was on faster memory, both RAM availability and the disk speed, but I had 250GB less local storage space.
              ] Samsung laptop, and installed &lt;a href=&quot;https://nixos.org/&quot;&gt;NixOS&lt;/a&gt; on it.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;After using NixOS on another laptop for around two years, I wanted verify how reproducible was my
              desktop environment, and how far does NixOS actually can go on recreating my whole OS from my
              configuration files and personal data. I gravitated towards NixOS after trying (and failing) to create an
              &lt;code&gt;install.sh&lt;/code&gt; script that would imperatively install and configure my whole OS using apt-get.
              When I found a GNU/Linux distribution that was built on top of the idea of declaratively specifying the
              whole OS I was automatically convincedfootnote:convincend-by-declarative-aspect[ The declarative
              configuration aspect is something that I now completely take for granted, and wouldn’t consider using
              something which isn’t declarative. A good metric to show this is me realising that I can’t pinpoint the
              moment when I decided to switch to NixOS. It’s like I had a distant past when this wasn’t true. ].&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I was impressed. Even though I’ve been experiencing the benefits of Nix isolation daily, I always felt
              skeptical that something would be missing, because the devil is always on the details. But the result was
              much better than expected!&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There were only 2 missing configurations:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;tap-to-click on the touchpad wasn’t enabled by default;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;the default theme from the gnome-terminal is &quot;Black on white&quot; instead of &quot;White on black&quot;.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;That’s all.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I haven’t checked if I can configure those in NixOS GNOME module, but I guess both are scriptable and
              could be set in a fictional &lt;code&gt;setup.sh&lt;/code&gt; run.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This makes me really happy, actually. More happy than I anticipated.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Having such a powerful declarative OS makes me feel like my data is the really important stuff (as it
              should be), and I can interact with it on any workstation. All I need is an internet connection and a few
              hours to download everything. It feels like my physical workstation and the installed OS are serving me
              and my data, instead of me feeling as hostage to the specific OS configuration at the moment. Having a
              few backup copies of everything important extends such peacefulness.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;After this positive experience with recreating my OS from simple Nix expressions, I started to wonder
              how far I could go with this, and started considering other areas of improvements:&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;first-run-on-a-fresh-nixos-installation&quot;&gt;First run on a fresh NixOS installation&lt;a class=&quot;anchor&quot;
             href=&quot;#first-run-on-a-fresh-nixos-installation&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;Right now the initial setup relies on non-declarative manual tasks, like decrypting some credentials,
              or manually downloading &lt;strong&gt;this&lt;/strong&gt; git repository with specific configurations before
              &lt;strong&gt;that&lt;/strong&gt; one.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I wonder what some areas of improvements are on this topic, and if investing on it is worth it (both
              time-wise and happiness-wise).&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;emacs&quot;&gt;Emacs&lt;a class=&quot;anchor&quot;
             href=&quot;#emacs&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;Right now I’m using the &lt;a href=&quot;https://spacemacs.org/&quot;&gt;Spacemacs&lt;/a&gt;, which is a community package
              curation and configuration on top of &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Spacemacs does support the notion of &lt;a href=&quot;https://spacemacs.org/doc/LAYERS.html&quot;&gt;layers&lt;/a&gt;, which
              you can declaratively specify and let Spacemacs do the rest.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;However this solution isn’t nearly as robust as Nix: being purely functional, Nix does describe
              everything required to build a derivation, and knows how to do so. Spacemacs it closer to more
              traditional package managers: even though the layers list is declarative, the installation is still very
              much imperative. I’ve had trouble with Spacemacs not behaving the same on different computers, both with
              identical configurations, only brought to convergence back again after a &lt;code&gt;git clean -fdx&lt;/code&gt;
              inside &lt;code&gt;~/.emacs.d/&lt;/code&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The ideal solution would be managing Emacs packages with Nix itself. After a quick search I did found
              that &lt;a href=&quot;https://nixos.org/nixos/manual/index.html#module-services-emacs-adding-packages&quot;&gt;there is
              support for Emacs packages in Nix&lt;/a&gt;. So far I was only aware of &lt;a href=
              &quot;https://www.gnu.org/software/guix/manual/en/html_node/Application-Setup.html#Emacs-Packages&quot;&gt;Guix
              support for Emacs packages&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This isn’t a trivial change because Spacemacs does include extra curation and configuration on top of
              Emacs packages. I’m not sure the best way to improve this right now.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;myrepos&quot;&gt;myrepos&lt;a class=&quot;anchor&quot;
             href=&quot;#myrepos&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’m using &lt;a href=&quot;https://myrepos.branchable.com/&quot;&gt;myrepos&lt;/a&gt; to manage all my git repositories, and
              the general rule I apply is to add any repository specific configuration in myrepos’
              &lt;code&gt;checkout&lt;/code&gt; phase:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;# sample ~/.mrconfig file snippet
[dev/guix/guix]
checkout =
  git clone https://git.savannah.gnu.org/git/guix.git guix
  cd guix/
  git config sendemail.to guix-patches@gnu.org&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;nixos-stateless-workstation.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;This way when I clone this repo again the email sending is already pre-configured.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This works well enough, but the solution is too imperative, and my &lt;code&gt;checkout&lt;/code&gt; phases tend
              to become brittle over time if not enough care is taken.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;gnu-stow&quot;&gt;GNU Stow&lt;a class=&quot;anchor&quot;
             href=&quot;#gnu-stow&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;For my home profile and personal configuration I already have a few dozens of symlinks that I manage
              manually. This has worked so far, but the solution is sometimes fragile and &lt;a href=
              &quot;https://euandre.org/git/dotfiles/tree/bash/symlinks.sh?id=316939aa215181b1d22b69e94241eef757add98d&quot;&gt;not
              declarative at all&lt;/a&gt;. I wonder if something like &lt;a href=&quot;https://www.gnu.org/software/stow/&quot;&gt;GNU
              Stow&lt;/a&gt; can help me simplify this.&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’m really satisfied with NixOS, and I intend to keep using it. If what I’ve said interests you, maybe
              try tinkering with the &lt;a href=&quot;https://nixos.org/nix/&quot;&gt;Nix package manager&lt;/a&gt; (not the whole NixOS) on
              your current distribution (it can live alongside any other package manager).&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If you have experience with declarative Emacs package managements, GNU Stow or any similar tool,
              &lt;em&gt;etc.&lt;/em&gt;, mail me some tips]. If you don’t have any experience at all, I’d still love to hear from
              you.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      Using &quot;youtube-dl&quot; to manage YouTube subscriptions
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2018/12/21/ytdl-subs.html" title="Using &quot;youtube-dl&quot; to manage YouTube subscriptions" />
    <published>
      2018-12-21T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2018/12/21/ytdl-subs.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;I’ve recently read the &lt;a href=
              &quot;https://old.reddit.com/r/DataHoarder/comments/9sg8q5/i_built_a_selfhosted_youtube_subscription_manager/&quot;&gt;
    </summary>
    <content type="html" xml:base="en/blog/2018/12/21/ytdl-subs.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;I’ve recently read the &lt;a href=
              &quot;https://old.reddit.com/r/DataHoarder/comments/9sg8q5/i_built_a_selfhosted_youtube_subscription_manager/&quot;&gt;
              announcement&lt;/a&gt; of a very nice &lt;a href=&quot;https://github.com/chibicitiberiu/ytsm&quot;&gt;self-hosted YouTube
              subscription manager&lt;/a&gt;. I haven’t used YouTube’s built-in subscriptions for a while now, and haven’t
              missed it at all. When I saw the announcement, I considered writing about the solution I’ve built on top
              of &lt;a href=&quot;https://youtube-dl.org/&quot;&gt;youtube-dl&lt;/a&gt;.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;background-the-problem-with-youtube&quot;&gt;Background: the problem with YouTube&lt;a class=&quot;anchor&quot;
             href=&quot;#background-the-problem-with-youtube&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;In many ways, I agree with &lt;a href=
              &quot;https://staltz.com/what-happens-when-you-block-internet-giants.html&quot;&gt;André Staltz’s view on data
              ownership and privacy&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;I started with the basic premise that &quot;I want to be in control of my data&quot;. Sometimes that meant
                  choosing when to interact with an internet giant and how much I feel like revealing to them. Most of
                  times it meant not interacting with them at all. I don’t want to let them be in full control of how
                  much they can know about me. I don’t want to be in autopilot mode. (…​) Which leads us to YouTube.
                  While I was able to find alternatives to Gmail (Fastmail), Calendar (Fastmail), Translate (Yandex
                  Translate), &lt;em&gt;etc.&lt;/em&gt; YouTube remains as the most indispensable Google-owned web service. It is
                  really really hard to avoid consuming YouTube content. It was probably the smartest startup
                  acquisition ever. My privacy-oriented alternative is to watch YouTube videos through Tor, which is
                  technically feasible but not polite to use the Tor bandwidth for these purposes. I’m still scratching
                  my head with this issue.&lt;/p&gt;
                &lt;/div&gt;
              &lt;/blockquote&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Even though I don’t use most alternative services he mentions, I do watch videos from YouTube. But I
              also feel uncomfortable logging in to YouTube with a Google account, watching videos, creating playlists
              and similar things.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Using the mobile app is worse: you can’t even block ads in there. You’re in less control on what you
              share with YouTube and Google.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;youtube-dl&quot;&gt;youtube-dl&lt;a class=&quot;anchor&quot;
             href=&quot;#youtube-dl&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;youtube-dl is a command-line tool for downloading videos, from YouTube and &lt;a href=
              &quot;https://rg3.github.io/youtube-dl/supportedsites.html&quot;&gt;many other sites&lt;/a&gt;:&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;$ youtube-dl https://www.youtube.com/watch?v=rnMYZnY3uLA
[youtube] rnMYZnY3uLA: Downloading webpage
[youtube] rnMYZnY3uLA: Downloading video info webpage
[download] Destination: A Origem da Vida _ Nerdologia-rnMYZnY3uLA.mp4
[download] 100% of 32.11MiB in 00:12&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;ytdl-subs.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;It can be used to download individual videos as showed above, but it also has some interesting flags
              that we can use:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;ulist&quot;&gt;
              &lt;ul&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;code&gt;--output&lt;/code&gt;: use a custom template to create the name of the downloaded file;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;code&gt;--download-archive&lt;/code&gt;: use a text file for recording and remembering which videos were
                  already downloaded;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;code&gt;--prefer-free-formats&lt;/code&gt;: prefer free video formats, like &lt;code&gt;webm&lt;/code&gt;,
                  &lt;code&gt;ogv&lt;/code&gt; and Matroska &lt;code&gt;mkv&lt;/code&gt;;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;code&gt;--playlist-end&lt;/code&gt;: how many videos to download from a &quot;playlist&quot; (a channel, a user or
                  an actual playlist);&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;code&gt;--write-description&lt;/code&gt;: write the video description to a &lt;code&gt;.description&lt;/code&gt; file,
                  useful for accessing links and extra content.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Putting it all together:&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;$ youtube-dl &quot;https://www.youtube.com/channel/UClu474HMt895mVxZdlIHXEA&quot; \
        --download-archive ~/Nextcloud/cache/youtube-dl-seen.conf \
        --prefer-free-formats \
        --playlist-end 20 \
        --write-description \
        --output &quot;~/Downloads/yt-dl/%(uploader)s/%(upload_date)s - %(title)s.%(ext)s&quot;&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;ytdl-subs.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 will download the latest 20 videos from the selected channel, and write down the video IDs in the
              &lt;code&gt;youtube-dl-seen.conf&lt;/code&gt; file. Running it immediately after one more time won’t have any
              effect.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;If the channel posts one more video, running the same command again will download only the last video,
              since the other 19 were already downloaded.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;With this basic setup you have a minimal subscription system at work, and you can create some
              functions to help you manage that:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L8&quot;
     href=&quot;#B3-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L9&quot;
     href=&quot;#B3-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L10&quot;
     href=&quot;#B3-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L11&quot;
     href=&quot;#B3-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L12&quot;
     href=&quot;#B3-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L13&quot;
     href=&quot;#B3-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L14&quot;
     href=&quot;#B3-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L15&quot;
     href=&quot;#B3-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L16&quot;
     href=&quot;#B3-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L17&quot;
     href=&quot;#B3-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L18&quot;
     href=&quot;#B3-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L19&quot;
     href=&quot;#B3-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L20&quot;
     href=&quot;#B3-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L21&quot;
     href=&quot;#B3-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L22&quot;
     href=&quot;#B3-L22&quot;&gt;22&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L23&quot;
     href=&quot;#B3-L23&quot;&gt;23&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L24&quot;
     href=&quot;#B3-L24&quot;&gt;24&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L25&quot;
     href=&quot;#B3-L25&quot;&gt;25&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L26&quot;
     href=&quot;#B3-L26&quot;&gt;26&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L27&quot;
     href=&quot;#B3-L27&quot;&gt;27&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L28&quot;
     href=&quot;#B3-L28&quot;&gt;28&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L29&quot;
     href=&quot;#B3-L29&quot;&gt;29&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L30&quot;
     href=&quot;#B3-L30&quot;&gt;30&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L31&quot;
     href=&quot;#B3-L31&quot;&gt;31&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;#!/bin/sh

export DEFAULT_PLAYLIST_END=15

download() {
        youtube-dl &quot;$1&quot; \
                --download-archive ~/Nextcloud/cache/youtube-dl-seen.conf \
                --prefer-free-formats \
                --playlist-end &quot;$2&quot; \
                --write-description \
                --output &quot;~/Downloads/yt-dl/%(uploader)s/%(upload_date)s - %(title)s.%(ext)s&quot;
}
export -f download


download_user() {
        download &quot;https://www.youtube.com/user/$1&quot; &quot;${2-$DEFAULT_PLAYLIST_END}&quot;
}
export -f download_user


download_channel() {
        download &quot;https://www.youtube.com/channel/$1&quot; &quot;${2-$DEFAULT_PLAYLIST_END}&quot;
}
export -f download_channel


download_playlist() {
        download &quot;https://www.youtube.com/playlist?list=$1&quot; &quot;${2-$DEFAULT_PLAYLIST_END}&quot;
}
export -f download_playlist&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;ytdl-subs.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;With these functions, you now can have a subscription fetching script to download the latest videos
              from your favorite channels:&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;B4-L1&quot;
     href=&quot;#B4-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L2&quot;
     href=&quot;#B4-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L3&quot;
     href=&quot;#B4-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L4&quot;
     href=&quot;#B4-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L5&quot;
     href=&quot;#B4-L5&quot;&gt;5&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;#!/bin/sh

download_user     ClojureTV                            15
download_channel  &apos;UCmEClzCBDx-vrt0GuSKBd9g&apos;           100
download_playlist &apos;PLqG7fA3EaMRPzL5jzd83tWcjCUH9ZUsbX&apos; 15&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;ytdl-subs.html.3.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Now, whenever you want to watch the latest videos, just run the above script and you’ll get all of
              them in your local machine.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;tradeoffs&quot;&gt;Tradeoffs&lt;a class=&quot;anchor&quot;
             href=&quot;#tradeoffs&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;ive-made-it-for-myself-with-my-use-case-in-mind&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#ive-made-it-for-myself-with-my-use-case-in-mind&quot;&gt;&lt;/a&gt;I’ve made it for myself, with my use case
                 in mind&lt;/h3&gt;
              &lt;div class=&quot;qlist qanda&quot;&gt;
                &lt;ol&gt;
                  &lt;li&gt;
                    &lt;p&gt;&lt;em&gt;Offline&lt;/em&gt;&lt;/p&gt;
                    &lt;p&gt;My internet speed it somewhat reasonablefootnote:internet-speed[ Considering how expensive it is
                    and the many ways it could be better, but also how much it has improved over the last years, I say
                    it’s reasonable. ], but it is really unstable. Either at work or at home, it’s not uncommon to
                    loose internet access for 2 minutes 3~5 times every day, and stay completely offline for a couple
                    of hours once every week.&lt;/p&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;Working through the hassle of keeping a playlist on disk has payed off many, many times.
                      Sometimes I even not notice when the connection drops for some minutes, because I’m watching a
                      video and working on some document, all on my local computer.&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;There’s also no quality adjustment for YouTube’s web player, I always pick the higher quality
                      and it doesn’t change during the video. For some types of content, like a podcast with some tiny
                      visual resources, this doesn’t change much. For other types of content, like a keynote
                      presentation with text written on the slides, watching on 144p isn’t really an option.&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;If the internet connection drops during the video download, youtube-dl will resume from where
                      it stopped.&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;This is an offline first benefit that I really like, and works well for me.&lt;/p&gt;
                    &lt;/div&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;&lt;em&gt;Sync the &quot;seen&quot; file&lt;/em&gt;&lt;/p&gt;
                    &lt;p&gt;I already have a running instance of Nextcloud, so just dumping the
                    &lt;code&gt;youtube-dl-seen.conf&lt;/code&gt; file inside Nextcloud was a no-brainer.&lt;/p&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;You could try putting it in a dedicated git repository, and wrap the script with an autocommit
                      after every run. If you ever had a merge conflict, you’d simply accept all changes and then run
                      the following to tidy up the file:&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;B5-L1&quot;
     href=&quot;#B5-L1&quot;&gt;1&lt;/a&gt;&lt;/pre&gt;
                              &lt;/td&gt;
                              &lt;td&gt;
                                &lt;pre&gt;$ uniq youtube-dl-seen.conf &amp;gt; youtube-dl-seen.conf&lt;/pre&gt;
                              &lt;/td&gt;
                            &lt;/tr&gt;
                          &lt;/tbody&gt;
                        &lt;/table&gt;
                      &lt;/div&gt;
                    &lt;/div&gt;
                  &lt;/li&gt;
                &lt;/ol&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph plaintext&quot;&gt;
                &lt;p&gt;&lt;a href=&quot;ytdl-subs.html.4.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;dlist&quot;&gt;
                &lt;dl&gt;
                  &lt;dt class=&quot;hdlist1&quot;&gt;Doesn’t work on mobile&lt;/dt&gt;
                  &lt;dd&gt;
                    &lt;p&gt;My primary device that I use everyday is my laptop, not my phone. It works well for me this
                    way.&lt;/p&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;Also, it’s harder to add ad-blockers to mobile phones, and most mobile software still depends
                      on Google’s and Apple’s blessing.&lt;/p&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;If you wish, you can sync the videos to the SD card periodically, but that’s a bit of extra
                      manual work.&lt;/p&gt;
                    &lt;/div&gt;
                  &lt;/dd&gt;
                &lt;/dl&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;the-good&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#the-good&quot;&gt;&lt;/a&gt;The Good&lt;/h3&gt;
              &lt;div class=&quot;qlist qanda&quot;&gt;
                &lt;ol&gt;
                  &lt;li&gt;
                    &lt;p&gt;&lt;em&gt;Better privacy&lt;/em&gt;&lt;/p&gt;
                    &lt;p&gt;We don’t even have to configure the ad-blocker to keep ads and trackers away!&lt;/p&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;YouTube still has your IP address, so using a VPN is always a good idea. However, a timing
                      analysis would be able to identify you (considering the current implementation).&lt;/p&gt;
                    &lt;/div&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;&lt;em&gt;No need to self-host&lt;/em&gt;&lt;/p&gt;
                    &lt;p&gt;There’s no host that needs maintenance. Everything runs locally.&lt;/p&gt;
                    &lt;div class=&quot;paragraph&quot;&gt;
                      &lt;p&gt;As long as you keep youtube-dl itself up to date and sync your &quot;seen&quot; file, there’s little
                      extra work to do.&lt;/p&gt;
                    &lt;/div&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;&lt;em&gt;Track your subscriptions with git&lt;/em&gt;&lt;/p&gt;
                    &lt;p&gt;After creating a &lt;code&gt;subscriptions.sh&lt;/code&gt; executable that downloads all the videos, you can
                    add it to git and use it to track metadata about your subscriptions.&lt;/p&gt;
                  &lt;/li&gt;
                &lt;/ol&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;the-bad&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#the-bad&quot;&gt;&lt;/a&gt;The Bad&lt;/h3&gt;
              &lt;div class=&quot;qlist qanda&quot;&gt;
                &lt;ol&gt;
                  &lt;li&gt;
                    &lt;p&gt;&lt;em&gt;Maximum playlist size is your disk size&lt;/em&gt;&lt;/p&gt;
                    &lt;p&gt;This is a good thing for getting a realistic view on your actual &quot;watch later&quot; list. However
                    I’ve run out of disk space many times, and now I need to be more aware of how much is left.&lt;/p&gt;
                  &lt;/li&gt;
                &lt;/ol&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;the-ugly&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#the-ugly&quot;&gt;&lt;/a&gt;The Ugly&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;We can only avoid all the bad parts of YouTube with youtube-dl as long as YouTube keeps the videos
                public and programmatically accessible. If YouTube ever blocks that we’d loose the ability to consume
                content this way, but also loose confidence on considering YouTube a healthy repository of videos on
                the internet.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;going-beyond&quot;&gt;Going beyond&lt;a class=&quot;anchor&quot;
             href=&quot;#going-beyond&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;Since you’re running everything locally, here are some possibilities to be explored:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;a-playlist-that-is-too-long-for-being-downloaded-all-at-once&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#a-playlist-that-is-too-long-for-being-downloaded-all-at-once&quot;&gt;&lt;/a&gt;A playlist that is too long
                 for being downloaded all at once&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;You can wrap the &lt;code&gt;download_playlist&lt;/code&gt; function (let’s call the wrapper
                &lt;code&gt;inc_download&lt;/code&gt;) and instead of passing it a fixed number to the &lt;code&gt;--playlist-end&lt;/code&gt;
                parameter, you can store the &lt;code&gt;$n&lt;/code&gt; in a folder (something like
                &lt;code&gt;$HOME/.yt-db/$PLAYLIST_ID&lt;/code&gt;) and increment it by &lt;code&gt;$step&lt;/code&gt; every time you run
                &lt;code&gt;inc_download&lt;/code&gt;.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;This way you can incrementally download videos from a huge playlist without filling your disk with
                gigabytes of content all at once.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;multiple-computer-scenario&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#multiple-computer-scenario&quot;&gt;&lt;/a&gt;Multiple computer scenario&lt;/h3&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;The &lt;code&gt;download_playlist&lt;/code&gt; function could be aware of the specific machine that it is
                running on and apply specific policies depending on the machine: always download everything; only
                download videos that aren’t present anywhere else; &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;
              &lt;/div&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;youtube-dl is a great tool to keep at hand. It covers a really large range of video websites and works
              robustly.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Feel free to copy and modify this code, and send me suggestions of improvements or related
              content.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;edit&quot;&gt;&lt;em&gt;Edit&lt;/em&gt;&lt;a class=&quot;anchor&quot;
             href=&quot;#edit&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;2019-05-22: Fix spelling.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      Verifying &quot;npm ci&quot; reproducibility
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2018/08/01/npm-ci-reproducibility.html" title="Verifying &quot;npm ci&quot; reproducibility" />
    <published>
      2018-08-01T00:00:00+00:00
    </published>
    <updated>
      2019-05-22T00:00:00+00:00
    </updated>
    <id>
      https://euandre.org/en/blog/2018/08/01/npm-ci-reproducibility.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;When &lt;a href=&quot;https://blog.npmjs.org/post/161081169345/v500&quot;&gt;npm@5&lt;/a&gt; came bringing &lt;a href=
              &quot;https://docs.npmjs.com/files/package-locks&quot;&gt;package-locks&lt;/a&gt; with it, I was confused about the benefits
    </summary>
    <content type="html" xml:base="en/blog/2018/08/01/npm-ci-reproducibility.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;When &lt;a href=&quot;https://blog.npmjs.org/post/161081169345/v500&quot;&gt;npm@5&lt;/a&gt; came bringing &lt;a href=
              &quot;https://docs.npmjs.com/files/package-locks&quot;&gt;package-locks&lt;/a&gt; with it, I was confused about the benefits
              it provided, since running &lt;code&gt;npm install&lt;/code&gt; more than once could resolve all the dependencies
              again and yield yet another fresh &lt;code&gt;package-lock.json&lt;/code&gt; file. The message saying &quot;you should add
              this file to version control&quot; left me hesitant on what to dofootnote:package-lock-message[ &lt;a href=
              &quot;https://docs.npmjs.com/cli/install#description&quot;&gt;documentation&lt;/a&gt; claims &lt;code&gt;npm install&lt;/code&gt; is
              driven by the existing &lt;code&gt;package-lock.json&lt;/code&gt;, but that’s actually &lt;a href=
              &quot;https://github.com/npm/npm/issues/17979#issuecomment-332701215&quot;&gt;a little bit tricky&lt;/a&gt;. ].&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;However the &lt;a href=
              &quot;https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable&quot;&gt;addition of
              &lt;code&gt;npm ci&lt;/code&gt;&lt;/a&gt; filled this gap: it’s a stricter variation of &lt;code&gt;npm install&lt;/code&gt; which
              guarantees that &quot;&lt;a href=&quot;https://docs.npmjs.com/files/package-lock.json&quot;&gt;subsequent installs are able to
              generate identical trees&lt;/a&gt;&quot;. But are they really identical? I could see that I didn’t have the same
              problems of different installation outputs, but I didn’t know for &lt;strong&gt;sure&lt;/strong&gt; if it was really
              identical.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;computing-the-hash-of-a-directorys-content&quot;&gt;Computing the hash of a directory’s content&lt;a class=
          &quot;anchor&quot;
             href=&quot;#computing-the-hash-of-a-directorys-content&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 quickly searched for a way to check for the hash signature of an entire directory tree, but I
              couldn’t find one. I’ve made a poor man’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Merkle_tree&quot;&gt;Merkle
              tree&lt;/a&gt; implementation using &lt;code&gt;sha256sum&lt;/code&gt; and a few piped commands at the terminal:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;merkle-tree () {
        dirname=&quot;${1-.}&quot;
        pushd &quot;$dirname&quot;
        find . -type f |
                sort                      |
                xargs -I{} sha256sum &quot;{}&quot; |
                sha256sum                 |
                awk &apos;{print $1}&apos;
        popd
}&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;npm-ci-reproducibility.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;Going through it line by line:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;ulist&quot;&gt;
              &lt;ul&gt;
                &lt;li&gt;
                  &lt;p&gt;#1 we define a Bash function called &lt;code&gt;merkle-tree&lt;/code&gt;;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#2 it accepts a single argument: the directory to compute the merkle tree from If nothing is
                  given, it runs on the current directory (&lt;code&gt;.&lt;/code&gt;);&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#3 we go to the directory, so we don’t get different prefixes in &lt;code&gt;find&lt;/code&gt;’s output (like
                  &lt;code&gt;../a/b&lt;/code&gt;);&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#4 we get all files from the directory tree. Since we’re using &lt;code&gt;sha256sum&lt;/code&gt; to compute
                  the hash of the file contents, we need to filter out folders from it;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#5 we need to sort the output, since different file systems and &lt;code&gt;find&lt;/code&gt; implementations
                  may return files in different orders;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#6 we use &lt;code&gt;xargs&lt;/code&gt; to compute the hash of each file individually through
                  &lt;code&gt;sha256sum&lt;/code&gt;. Since a file may contain spaces we need to escape it with quotes;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#7 we compute the hash of the combined hashes. Since &lt;code&gt;sha256sum&lt;/code&gt; output is formatted
                  like &lt;code&gt;&amp;lt;hash&amp;gt; &amp;lt;filename&amp;gt;&lt;/code&gt;, it produces a different final hash if a file ever
                  changes name without changing it’s content;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;#8 we get the final hash output, excluding the &lt;code&gt;&amp;lt;filename&amp;gt;&lt;/code&gt; (which is
                  &lt;code&gt;-&lt;/code&gt; in this case, aka &lt;code&gt;stdin&lt;/code&gt;).&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;positive-points&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#positive-points&quot;&gt;&lt;/a&gt;Positive points:&lt;/h3&gt;
              &lt;div class=&quot;olist arabic&quot;&gt;
                &lt;ol class=&quot;arabic&quot;&gt;
                  &lt;li&gt;
                    &lt;p&gt;ignore timestamp: running more than once on different installation yields the same hash;&lt;/p&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;the name of the file is included in the final hash computation.&lt;/p&gt;
                  &lt;/li&gt;
                &lt;/ol&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;limitations&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#limitations&quot;&gt;&lt;/a&gt;Limitations:&lt;/h3&gt;
              &lt;div class=&quot;olist arabic&quot;&gt;
                &lt;ol class=&quot;arabic&quot;&gt;
                  &lt;li&gt;
                    &lt;p&gt;it ignores empty folders from the hash computation;&lt;/p&gt;
                  &lt;/li&gt;
                  &lt;li&gt;
                    &lt;p&gt;the implementation’s only goal is to represent using a digest whether the content of a given
                    directory is the same or not. Leaf presence checking is obviously missing from it.&lt;/p&gt;
                  &lt;/li&gt;
                &lt;/ol&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;sect2&quot;&gt;
              &lt;h3 id=&quot;testing-locally-with-sample-data&quot;&gt;&lt;a class=&quot;anchor&quot;
                 href=&quot;#testing-locally-with-sample-data&quot;&gt;&lt;/a&gt;Testing locally with sample data&lt;/h3&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L8&quot;
     href=&quot;#B2-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L9&quot;
     href=&quot;#B2-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L10&quot;
     href=&quot;#B2-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L11&quot;
     href=&quot;#B2-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L12&quot;
     href=&quot;#B2-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L13&quot;
     href=&quot;#B2-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L14&quot;
     href=&quot;#B2-L14&quot;&gt;14&lt;/a&gt;&lt;/pre&gt;
                        &lt;/td&gt;
                        &lt;td&gt;
                          &lt;pre&gt;mkdir /tmp/merkle-tree-test/
cd /tmp/merkle-tree-test/
mkdir -p a/b/ a/c/ d/
echo &quot;one&quot;   &amp;gt; a/b/one.txt
echo &quot;two&quot;   &amp;gt; a/c/two.txt
echo &quot;three&quot; &amp;gt; d/three.txt
merkle-tree . # output is       be343bb01fe00aeb8fef14a3e16b1c3d1dccbf86d7e41b4753e6ccb7dc3a57c3
merkle-tree . # output still is be343bb01fe00aeb8fef14a3e16b1c3d1dccbf86d7e41b4753e6ccb7dc3a57c3
echo &quot;four&quot;  &amp;gt; d/four.txt
merkle-tree . # output is now   b5464b958969ed81815641ace96b33f7fd52c20db71a7fccc45a36b3a2ae4d4c
rm d/four.txt
merkle-tree . # output back to  be343bb01fe00aeb8fef14a3e16b1c3d1dccbf86d7e41b4753e6ccb7dc3a57c3
echo &quot;hidden-five&quot; &amp;gt; a/b/one.txt
merkle-tree . # output changed  471fae0d074947e4955e9ac53e95b56e4bc08d263d89d82003fb58a0ffba66f5&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;npm-ci-reproducibility.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;It seems to work for this simple test case.&lt;/p&gt;
              &lt;/div&gt;
              &lt;div class=&quot;paragraph&quot;&gt;
                &lt;p&gt;You can try copying and pasting it to verify the hash signatures.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;using-merkle-tree-to-check-the-output-of-npm-ci&quot;&gt;Using &lt;code&gt;merkle-tree&lt;/code&gt; to check the output
          of &lt;code&gt;npm ci&lt;/code&gt;&lt;a class=&quot;anchor&quot;
             href=&quot;#using-merkle-tree-to-check-the-output-of-npm-ci&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;&lt;em&gt;I’ve done all of the following using Node.js v8.11.3 and npm@6.1.0&lt;/em&gt;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;In this test case I’ll take the main repo of &lt;a href=
              &quot;https://lernajs.io/&quot;&gt;Lerna&lt;/a&gt;footnote:lerna-package-lock[ Finding a big known repo that actually
              committed the &lt;code&gt;package-lock.json&lt;/code&gt; file was harder than I expected. ]:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L8&quot;
     href=&quot;#B3-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L9&quot;
     href=&quot;#B3-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L10&quot;
     href=&quot;#B3-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L11&quot;
     href=&quot;#B3-L11&quot;&gt;11&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;cd /tmp/
git clone https://github.com/lerna/lerna.git
cd lerna/
git checkout 57ff865c0839df75dbe1974971d7310f235e1109
npm ci
merkle-tree node_modules/ # outputs 11e218c4ac32fac8a9607a8da644fe870a25c99821167d21b607af45699afafa
rm -rf node_modules/
npm ci
merkle-tree node_modules/ # outputs 11e218c4ac32fac8a9607a8da644fe870a25c99821167d21b607af45699afafa
npm ci      # test if it also works with an existing node_modules/ folder
merkle-tree node_modules/ # outputs 11e218c4ac32fac8a9607a8da644fe870a25c99821167d21b607af45699afafa&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;npm-ci-reproducibility.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;Good job &lt;code&gt;npm ci&lt;/code&gt; :)&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;#6 and #9 take some time to run (21 seconds in my machine), but this specific use case isn’t
              performance sensitive. The slowest step is computing the hash of each individual file.&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;&lt;code&gt;npm ci&lt;/code&gt; really &quot;generates identical trees&quot;.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I’m not aware of any other existing solution for verifying the hash signature of a directory. If you
              know any, shoot me an email, as I’d like to know it.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;edit&quot;&gt;&lt;strong&gt;Edit&lt;/strong&gt;&lt;a class=&quot;anchor&quot;
             href=&quot;#edit&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;2019-05-22: Fix spelling.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
  <entry xml:lang="en">
    <title type="html">
      Running Guix on NixOS
    </title>
    <link type="text/html" rel="alternative" href="https://euandre.org/en/blog/2018/07/17/guix-nixos.html" title="Running Guix on NixOS" />
    <published>
      2018-07-17T00:00:00+00:00
    </published>
    <id>
      https://euandre.org/en/blog/2018/07/17/guix-nixos.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;I wanted to run Guix on a NixOS machine. Even though the Guix manual explains how to do it &lt;a href=
              &quot;https://www.gnu.org/software/guix/manual/en/html_node/Binary-Installation.html#Binary-Installation&quot;&gt;step
    </summary>
    <content type="html" xml:base="en/blog/2018/07/17/guix-nixos.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;I wanted to run Guix on a NixOS machine. Even though the Guix manual explains how to do it &lt;a href=
              &quot;https://www.gnu.org/software/guix/manual/en/html_node/Binary-Installation.html#Binary-Installation&quot;&gt;step
              by step&lt;/a&gt;, I needed a few extra ones to make it work properly.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;I couldn’t just install GuixSD because my wireless network card doesn’t have any free drivers
              (yet).&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;creating-guixbuilder-users&quot;&gt;Creating &lt;code&gt;guixbuilder&lt;/code&gt; users&lt;a class=&quot;anchor&quot;
             href=&quot;#creating-guixbuilder-users&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;Guix requires you to create non-root users that will be used to perform the builds in the isolated
              environments.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;The &lt;a href=
              &quot;https://www.gnu.org/software/guix/manual/en/html_node/Build-Environment-Setup.html#Build-Environment-Setup&quot;&gt;
              manual&lt;/a&gt; already provides you with a ready to run (as root) command for creating the build users:&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;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;groupadd --system guixbuild
for i in `seq -w 1 10`;
do
  useradd -g guixbuild -G guixbuild           \
          -d /var/empty -s `which nologin`    \
          -c &quot;Guix build user $i&quot; --system    \
          guixbuilder$i;
done&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;guix-nixos.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;However, In my personal NixOS I have disabled &lt;a href=
              &quot;https://nixos.org/nixos/manual/index.html#sec-user-management&quot;&gt;&lt;code&gt;users.mutableUsers&lt;/code&gt;&lt;/a&gt;,
              which means that even if I run the above command it means that they’ll be removed once I rebuild my
              OS:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L8&quot;
     href=&quot;#B2-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L9&quot;
     href=&quot;#B2-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L10&quot;
     href=&quot;#B2-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L11&quot;
     href=&quot;#B2-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L12&quot;
     href=&quot;#B2-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B2-L13&quot;
     href=&quot;#B2-L13&quot;&gt;13&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;$ sudo nixos-rebuild switch
(...)
removing user ‘guixbuilder7’
removing user ‘guixbuilder3’
removing user ‘guixbuilder10’
removing user ‘guixbuilder1’
removing user ‘guixbuilder6’
removing user ‘guixbuilder9’
removing user ‘guixbuilder4’
removing user ‘guixbuilder2’
removing user ‘guixbuilder8’
removing user ‘guixbuilder5’
(...)&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;guix-nixos.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;Instead of enabling &lt;code&gt;users.mutableUsers&lt;/code&gt; I could add the Guix users by adding them to my
              system configuration:&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;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L8&quot;
     href=&quot;#B3-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L9&quot;
     href=&quot;#B3-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L10&quot;
     href=&quot;#B3-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L11&quot;
     href=&quot;#B3-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L12&quot;
     href=&quot;#B3-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L13&quot;
     href=&quot;#B3-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L14&quot;
     href=&quot;#B3-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L15&quot;
     href=&quot;#B3-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L16&quot;
     href=&quot;#B3-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L17&quot;
     href=&quot;#B3-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L18&quot;
     href=&quot;#B3-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L19&quot;
     href=&quot;#B3-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L20&quot;
     href=&quot;#B3-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L21&quot;
     href=&quot;#B3-L21&quot;&gt;21&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L22&quot;
     href=&quot;#B3-L22&quot;&gt;22&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L23&quot;
     href=&quot;#B3-L23&quot;&gt;23&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L24&quot;
     href=&quot;#B3-L24&quot;&gt;24&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L25&quot;
     href=&quot;#B3-L25&quot;&gt;25&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L26&quot;
     href=&quot;#B3-L26&quot;&gt;26&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L27&quot;
     href=&quot;#B3-L27&quot;&gt;27&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L28&quot;
     href=&quot;#B3-L28&quot;&gt;28&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L29&quot;
     href=&quot;#B3-L29&quot;&gt;29&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L30&quot;
     href=&quot;#B3-L30&quot;&gt;30&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L31&quot;
     href=&quot;#B3-L31&quot;&gt;31&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L32&quot;
     href=&quot;#B3-L32&quot;&gt;32&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L33&quot;
     href=&quot;#B3-L33&quot;&gt;33&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L34&quot;
     href=&quot;#B3-L34&quot;&gt;34&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L35&quot;
     href=&quot;#B3-L35&quot;&gt;35&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L36&quot;
     href=&quot;#B3-L36&quot;&gt;36&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L37&quot;
     href=&quot;#B3-L37&quot;&gt;37&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L38&quot;
     href=&quot;#B3-L38&quot;&gt;38&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L39&quot;
     href=&quot;#B3-L39&quot;&gt;39&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B3-L40&quot;
     href=&quot;#B3-L40&quot;&gt;40&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;{ config, pkgs, ...}:

{

  # ... NixOS usual config ellided ...

  users = {
    mutableUsers = false;

    extraUsers =
      let
        andrehUser =  {
          andreh = {
            # my custom user config
          };
        };
        buildUser = (i:
          {
            &quot;guixbuilder${i}&quot; = {                   # guixbuilder$i
              group = &quot;guixbuild&quot;;                  # -g guixbuild
              extraGroups = [&quot;guixbuild&quot;];          # -G guixbuild
              home = &quot;/var/empty&quot;;                  # -d /var/empty
              shell = pkgs.nologin;                 # -s `which nologin`
              description = &quot;Guix build user ${i}&quot;; # -c &quot;Guix buid user $i&quot;
              isSystemUser = true;                  # --system
            };
          }
        );
      in
        # merge all users
        pkgs.lib.fold (str: acc: acc // buildUser str)
                      andrehUser
                      # for i in `seq -w 1 10`
                      (map (pkgs.lib.fixedWidthNumber 2) (builtins.genList (n: n+1) 10));

    extraGroups.guixbuild = {
      name = &quot;guixbuild&quot;;
    };
  };
}&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;guix-nixos.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;Here I used &lt;code&gt;fold&lt;/code&gt; and the &lt;code&gt;//&lt;/code&gt; operator to merge all of the configuration sets
              into a single &lt;code&gt;extraUsers&lt;/code&gt; value.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;sect1&quot;&gt;
          &lt;h2 id=&quot;creating-the-systemd-service&quot;&gt;Creating the &lt;code&gt;systemd&lt;/code&gt; service&lt;a class=&quot;anchor&quot;
             href=&quot;#creating-the-systemd-service&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;One other thing missing was the &lt;code&gt;systemd&lt;/code&gt; service.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;First I couldn’t just copy the &lt;code&gt;.service&lt;/code&gt; file to &lt;code&gt;/etc&lt;/code&gt; since in NixOS that
              folder isn’t writable. But also I wanted the service to be better integrated with the OS.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;That was a little easier than creating the users, all I had to do was translate the provided &lt;a href=
              &quot;https://git.savannah.gnu.org/cgit/guix.git/tree/etc/guix-daemon.service.in?id=00c86a888488b16ce30634d3a3a9d871ed6734a2&quot;&gt;
              &lt;code&gt;guix-daemon.service.in&lt;/code&gt;&lt;/a&gt; configuration to an equivalent Nix expression:&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;B4-L1&quot;
     href=&quot;#B4-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L2&quot;
     href=&quot;#B4-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L3&quot;
     href=&quot;#B4-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L4&quot;
     href=&quot;#B4-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L5&quot;
     href=&quot;#B4-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L6&quot;
     href=&quot;#B4-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L7&quot;
     href=&quot;#B4-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L8&quot;
     href=&quot;#B4-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L9&quot;
     href=&quot;#B4-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L10&quot;
     href=&quot;#B4-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L11&quot;
     href=&quot;#B4-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L12&quot;
     href=&quot;#B4-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L13&quot;
     href=&quot;#B4-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L14&quot;
     href=&quot;#B4-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L15&quot;
     href=&quot;#B4-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L16&quot;
     href=&quot;#B4-L16&quot;&gt;16&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L17&quot;
     href=&quot;#B4-L17&quot;&gt;17&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L18&quot;
     href=&quot;#B4-L18&quot;&gt;18&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L19&quot;
     href=&quot;#B4-L19&quot;&gt;19&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L20&quot;
     href=&quot;#B4-L20&quot;&gt;20&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B4-L21&quot;
     href=&quot;#B4-L21&quot;&gt;21&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;# This is a &quot;service unit file&quot; for the systemd init system to launch
# &apos;guix-daemon&apos;.  Drop it in /etc/systemd/system or similar to have
# &apos;guix-daemon&apos; automatically started.

[Unit]
Description=Build daemon for GNU Guix

[Service]
ExecStart=/var/guix/profiles/per-user/root/guix-profile/bin/guix-daemon --build-users-group=guixbuild
Environment=GUIX_LOCPATH=/root/.guix-profile/lib/locale
RemainAfterExit=yes
StandardOutput=syslog
StandardError=syslog

# See &amp;lt;https://lists.gnu.org/archive/html/guix-devel/2016-04/msg00608.html&amp;gt;.
# Some package builds (for example, go@1.8.1) may require even more than
# 1024 tasks.
TasksMax=8192

[Install]
WantedBy=multi-user.target&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;guix-nixos.html.3.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;This sample &lt;code&gt;systemd&lt;/code&gt; configuration file became:&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;B5-L1&quot;
     href=&quot;#B5-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L2&quot;
     href=&quot;#B5-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L3&quot;
     href=&quot;#B5-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L4&quot;
     href=&quot;#B5-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L5&quot;
     href=&quot;#B5-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L6&quot;
     href=&quot;#B5-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L7&quot;
     href=&quot;#B5-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L8&quot;
     href=&quot;#B5-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L9&quot;
     href=&quot;#B5-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L10&quot;
     href=&quot;#B5-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L11&quot;
     href=&quot;#B5-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L12&quot;
     href=&quot;#B5-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B5-L13&quot;
     href=&quot;#B5-L13&quot;&gt;13&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;guix-daemon = {
  enable = true;
  description = &quot;Build daemon for GNU Guix&quot;;
  serviceConfig = {
    ExecStart = &quot;/var/guix/profiles/per-user/root/guix-profile/bin/guix-daemon --build-users-group=guixbuild&quot;;
    Environment=&quot;GUIX_LOCPATH=/root/.guix-profile/lib/locale&quot;;
    RemainAfterExit=&quot;yes&quot;;
    StandardOutput=&quot;syslog&quot;;
    StandardError=&quot;syslog&quot;;
    TaskMax= &quot;8192&quot;;
  };
  wantedBy = [ &quot;multi-user.target&quot; ];
};&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;guix-nixos.html.4.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;There you go! After running &lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt; I could get Guix up and
              running:&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;B6-L1&quot;
     href=&quot;#B6-L1&quot;&gt;1&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L2&quot;
     href=&quot;#B6-L2&quot;&gt;2&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L3&quot;
     href=&quot;#B6-L3&quot;&gt;3&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L4&quot;
     href=&quot;#B6-L4&quot;&gt;4&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L5&quot;
     href=&quot;#B6-L5&quot;&gt;5&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L6&quot;
     href=&quot;#B6-L6&quot;&gt;6&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L7&quot;
     href=&quot;#B6-L7&quot;&gt;7&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L8&quot;
     href=&quot;#B6-L8&quot;&gt;8&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L9&quot;
     href=&quot;#B6-L9&quot;&gt;9&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L10&quot;
     href=&quot;#B6-L10&quot;&gt;10&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L11&quot;
     href=&quot;#B6-L11&quot;&gt;11&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L12&quot;
     href=&quot;#B6-L12&quot;&gt;12&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L13&quot;
     href=&quot;#B6-L13&quot;&gt;13&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L14&quot;
     href=&quot;#B6-L14&quot;&gt;14&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L15&quot;
     href=&quot;#B6-L15&quot;&gt;15&lt;/a&gt;
&lt;a class=&quot;code-line-anchor&quot;
     id=&quot;B6-L16&quot;
     href=&quot;#B6-L16&quot;&gt;16&lt;/a&gt;&lt;/pre&gt;
                      &lt;/td&gt;
                      &lt;td&gt;
                        &lt;pre&gt;$ guix package -i hello
The following package will be installed:
   hello        2.10    /gnu/store/bihfrh609gkxb9dp7n96wlpigiv3krfy-hello-2.10

substitute: updating substitutes from &apos;https://mirror.hydra.gnu.org&apos;... 100.0%
The following derivations will be built:
   /gnu/store/nznmdn6inpwxnlkrasydmda4s2vsp9hg-profile.drv
   /gnu/store/vibqrvw4c8lacxjrkqyzqsdrmckv77kq-fonts-dir.drv
   /gnu/store/hi8alg7wi0wgfdi3rn8cpp37zhx8ykf3-info-dir.drv
   /gnu/store/cvkbp378cvfjikz7mjymhrimv7j12p0i-ca-certificate-bundle.drv
   /gnu/store/d62fvxymnp95rzahhmhf456bsf0xg1c6-manual-database.drv
Creating manual page database...
1 entries processed in 0.0 s
2 packages in profile
$ hello
Hello, world!&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;guix-nixos.html.5.txt&quot;&gt;plaintext&lt;/a&gt;&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Some improvements to this approach are:&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class=&quot;olist arabic&quot;&gt;
              &lt;ol class=&quot;arabic&quot;&gt;
                &lt;li&gt;
                  &lt;p&gt;looking into &lt;a href=&quot;https://nixos.org/nixos/manual/index.html#sec-writing-modules&quot;&gt;NixOS
                  modules&lt;/a&gt; and trying to bundle everything together into a single logical unit;&lt;/p&gt;
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;p&gt;&lt;a href=
                  &quot;https://www.gnu.org/software/guix/manual/en/html_node/Requirements.html#Requirements&quot;&gt;build Guix
                  from source&lt;/a&gt; and share the Nix store and daemon with Guix.&lt;/p&gt;
                &lt;/li&gt;
              &lt;/ol&gt;
            &lt;/div&gt;
            &lt;div class=&quot;paragraph&quot;&gt;
              &lt;p&gt;Happy Guix/Nix hacking!&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    </content>
  </entry>
</feed>
