<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Galaxy brain]]></title><description><![CDATA[I am a software engineer. Put me at the center of a Venn diagram with functional programming, product development, and open-source]]></description><link>https://etorreborre.blog</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 09:02:15 GMT</lastBuildDate><atom:link href="https://etorreborre.blog/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Partial and unfair tour of Gleam]]></title><description><![CDATA[I keep hearing people praising systems built on top of the BEAM virtual machine. Unfortunately programming with dynamically typed languages like Erlang or Elixir is really not my thing for production ]]></description><link>https://etorreborre.blog/partial-and-unfair-tour-of-gleam</link><guid isPermaLink="true">https://etorreborre.blog/partial-and-unfair-tour-of-gleam</guid><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Thu, 12 Mar 2026 23:34:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/64f4b99d59bd4f9516c3c854/4dc2177e-fb3d-4d5c-bc1d-1e239795e314.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I keep hearing people praising systems built on top of <a href="https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)">the BEAM virtual machine</a>. Unfortunately programming with dynamically typed languages like Erlang or Elixir is really not my thing for production code. But it doesn't have to be so! <a href="https://gleam.run/">Gleam</a> is a statically-typed functional programming language that targets both BEAM and JavaScript (it also has its own runtime).</p>
<p>After listening to the <a href="https://open.spotify.com/episode/44boPkZ5xaFzH1fo9V78I0">excellent interview of Giacomo Cavalieri on the FuncProg podcast</a> (hi Christoffer!) I thought I would do the <a href="https://tour.gleam.run">online tour of Gleam</a> to get a better taste of it.</p>
<p>Here are my first impressions in three convenient buckets: "noice", "hmmm...", "hell no!".</p>
<h3><strong>Noice</strong></h3>
<ul>
<li><p>FP language with familiar constructs for lists, options, results, partial application, etc...</p>
</li>
<li><p>Pattern matching with reasonable machinery: named values, catch-all, guards, elided values, alternatives, etc...</p>
</li>
<li><p>Records with record getters / updates, enums, variants.</p>
</li>
<li><p>Type aliases, opaque types.</p>
</li>
<li><p>Simple language, easy to learn, nice error messages.</p>
</li>
<li><p>Interop story with JavaScript and Erlang (with the <code>@external</code> annotation)</p>
</li>
<li><p>The <code>gleam</code> build tool seems to be inspired by <a href="https://doc.rust-lang.org/cargo/">cargo</a>:</p>
<ul>
<li><p>Using a TOML file</p>
</li>
<li><p><code>build</code>, <code>test</code>, <code>fmt</code> out of the box.</p>
</li>
<li><p>With nice dependencies management (from <a href="https://hexdocs.pm/">Hex</a>, local paths, or a git repository)</p>
</li>
</ul>
</li>
<li><p>Did I mention statically-typed?</p>
</li>
</ul>
<h3><strong>Hmmm...</strong></h3>
<ul>
<li><p>The <code>&lt;&lt;&gt;&gt;</code> syntax for bit arrays with tags like <code>utf-8</code>. Just hmmm, because I'm not familiar but could be noice.</p>
</li>
<li><p>No exceptions but 3 keywords that can panic: <code>todo</code>, <code>panic</code>, <code>assert</code>.</p>
</li>
<li><p><code>//</code> (expression), <code>///</code> (function) <em>and</em> <code>////</code> (module) as a way to start comments.</p>
</li>
<li><p>No macros but 3 predefined annotations: <code>@deprecated</code>, <code>@external</code>, <code>@target</code>.</p>
</li>
<li><p>Function syntax with <code>fn(a) -&gt; b</code>. Why not the simpler <code>a -&gt; b</code>? Hard to beat Haskell there.</p>
</li>
<li><p>Generics syntax with parentheses <code>List(Int)</code>. Why does everyone insist on doing that differently 😫?</p>
<ul>
<li><p>Haskell: <code>List a</code></p>
</li>
<li><p>Scala: <code>List[A]</code></p>
</li>
<li><p>Rust: <code>List&lt;A&gt;</code></p>
</li>
<li><p>OCaml: <code>'a list</code></p>
</li>
</ul>
</li>
<li><p>The <code>gleam</code> build tool creates a new project with a Github workflow + <code>.gitignore</code> out of the box. Can this be customized?</p>
</li>
</ul>
<h3><strong>Hell no!</strong></h3>
<ul>
<li><p>Division by 0 is equal to 0.</p>
</li>
<li><p>No syntax for early return of results, like <code>?</code> in Rust.</p>
</li>
<li><p><code>|&gt;</code> can apply a value as the first parameter of a function (like <code>f(a: Int, b: Int)</code>) or as the argument to a 1-argument function (like <code>fn(Int) -&gt; Int</code>). That looks troublesome.</p>
</li>
<li><p>A <s>brand new concept</s> [1] for named parameters: <code>fn all(in list: List(a), satisfying predicate: fn(a) -&gt; Bool) -&gt; Bool</code>. <code>in</code> and <code>satisfying</code> are "labels" and can be used to passed named values: <code>all(in: [1, 2], satisfying: fn(x) { x &gt; 3 })</code>.</p>
</li>
<li><p><a href="https://tour.gleam.run/functions/label-shorthand-syntax/">Short-hand syntax for named parameters</a> do we really special support for this?</p>
</li>
<li><p>Expressions have to be grouped with <code>{}</code> , like <code>{ 1 + 2 } * 3</code> and not with regular parentheses. I <em>thought</em> it was to parse more easily tuples, but they have their own ugly syntax <code>#(1, 2, 3)</code>. What's wrong with <code>(1, 2, 3)</code>? Good thing that lists are just <code>[1, 2, 3]</code>.</p>
</li>
<li><p><code>Nil</code> value representing a "unit/void" type. <a href="https://www.scala-lang.org/api/3.x/scala/collection/immutable/Nil$.html">That hurts me as a Scala programmer</a>.</p>
</li>
<li><p><code>as</code> as a keyword just to pass a message to <code>todo</code> / <code>panic</code> / <code>assert</code>.</p>
</li>
<li><p>A keyword, <code>echo</code> just to output debug statements.</p>
</li>
</ul>
<h3><strong>Conclusion</strong></h3>
<p>I am definitely happy that a statically-typed programming language exists in the BEAM ecosystem and would love to use Gleam if I had to use BEAM. My main concerns are:</p>
<ul>
<li><p>The syntax is designed to be lightweight but feels a bit ad-hoc. I feel we could have done better here.</p>
</li>
<li><p>The type system looks minimal (no type classes for examples) but this might be the price to pay for an easy interop story with BEAM and Javascript.</p>
</li>
<li><p>The OTP story is supposed to be a strong selling point (systems with great uptime!) but <a href="https://github.com/gleam-lang/otp">the OTP library seems to be still in infancy</a> and easy concurrency could sold better on the front page IMO.</p>
</li>
<li><p><code>gleam</code> seems to follow the path of <code>cargo</code> but with less power (workspaces, plugins, etc...)</p>
</li>
</ul>
<p>I apologize in advance to Gleam authors and fans for writing possibly inaccurate or unfair comments on this post. I hope I can come back and write some more serious code with Gleam to get a more informed opinion in the future!</p>
<p>[1]: Brand new to me! Swift also has <a href="https://www.hackingwithswift.com/sixty/5/4/parameter-labels">parameter labels</a>.</p>
]]></content:encoded></item><item><title><![CDATA[My first Unison Cloud service]]></title><description><![CDATA[I already mentioned on this blog how amazing it feels to program with Unison. Since I started using Unison, I have created several libraries, but I never deployed and used a Unison Cloud service that wasn't just an experiment. Not anymore!
Scratching...]]></description><link>https://etorreborre.blog/my-first-unison-cloud-service</link><guid isPermaLink="true">https://etorreborre.blog/my-first-unison-cloud-service</guid><category><![CDATA[Unison]]></category><category><![CDATA[programming]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Tue, 11 Nov 2025 22:28:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/hgO1wFPXl3I/upload/c1f9639b210e17714a8e6aa59e6ce58a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I already mentioned on this blog <a target="_blank" href="https://etorreborre.blog/what-is-so-unique-about-unison">how amazing it feels to program with Unison</a>. Since I started using Unison, I have created several libraries, but I never deployed and used a <a target="_blank" href="https://unison.cloud">Unison Cloud</a> service that wasn't just an experiment. Not anymore!</p>
<h1 id="heading-scratching-an-itch">Scratching an itch</h1>
<p>When you create Unison programs, your code is type-checked and then saved to a database. You don’t exchange files with others but use Unison terms. Revolutionary. Perhaps a bit too much, since a full ecosystem had to be built from scratch to support this approach. GitHub becomes unusable. In its place, there is <a target="_blank" href="https://share.unison-lang.org/">Unison Share</a> where you can browse projects and collaborate with others. Unfortunately, Github is the portfolio of many developers, and as a Unison developer, all your frantic activity is invisible to most of the development world.</p>
<p>Fortunately Unison Share provides an API and a system of webhooks. You can install webhooks that will be notified every time an event related to your project occurs: a new push, a new ticket, etc… Hence the straightforward idea to use a webhook to <strong>mirror the Unison Share project activity to a Github repository</strong>.</p>
<h1 id="heading-designing-it">Designing it</h1>
<p>The most direct way to implement this system is to deploy an HTTP server that will listen to webhook payloads and create commits to a Github repository. This is exactly what Unison Cloud supports out of the box!</p>
<p>However, the details matter. At first, I wanted to deploy and operate a service that any Unison developer could use. They would register, configure their webhooks to send payloads to my server, and I would create commits. But this requires trusting <em>me</em> with a very sensitive resource, <em>their</em> Github API token. After looking carefully into the configuration of Github tokens, I concluded that there was no way to make the system trustworthy. Instead of me deploying a service and operating for multiple users, I preferred to let everyone start their own server with their own secrets. It’s a bit sad because I was looking forward to operating a Unison service supporting many users.</p>
<p>The whole system is eventually composed of:</p>
<ul>
<li>A HTTP service listening to webhook payloads.</li>
</ul>
<p>A CLI application to:</p>
<ul>
<li><p>Deploy the service.</p>
</li>
<li><p>Synchronize a Unison Share project and a Github repository (or all of your projects at once).</p>
</li>
<li><p>Get some status information.</p>
</li>
</ul>
<p>You notice that the CLI gives you the possibility to deploy the service with one command. This is, after all, one of the strength of Unison Cloud, <strong>the deployment code is still Unison code</strong>!</p>
<h1 id="heading-implementing-it">Implementing it</h1>
<p>That was actually the fun part! I have, for the past year, created a few Unison libraries and this was finally the opportunity to use many of them in the same project:</p>
<ul>
<li><p><a target="_blank" href="https://share.unison-lang.org/@etorreborre/potions">potions</a> a CLI library.</p>
</li>
<li><p><a target="_blank" href="https://share.unison-lang.org/@etorreborre/registry">registry</a> a dependency injection library.</p>
</li>
<li><p><a target="_blank" href="https://share.unison-lang.org/@etorreborre/json-encoder">json-encoder</a> / <a target="_blank" href="https://share.unison-lang.org/@etorreborre/json-decoder">json-decoder</a> two libraries to create encoders / decoders for a given data model.</p>
</li>
<li><p><a target="_blank" href="https://share.unison-lang.org/@etorreborre/to-text">to-text</a> a library to create flexible <code>ToText</code> instances for a data model.</p>
</li>
</ul>
<p>Since eating your own dog food is the best way to improve your projects, I made a few improvements and fixes:</p>
<ul>
<li><p><code>potions</code></p>
<ul>
<li><p>Improv the display of enum flags.</p>
</li>
<li><p>Add the possibility to specify command name aliases.</p>
</li>
<li><p>Fix the missing item in a numbered list.</p>
</li>
<li><p>Better error message in the case of an incorrect subcommand.</p>
</li>
<li><p>Render colored text as <code>Word</code> and not <code>Paragraph</code>.</p>
</li>
<li><p>Add grey color style.</p>
</li>
<li><p>Upgrade the <a target="_blank" href="https://share.unison-lang.org/@runarorama/terminus">terminus</a> library (I found an issue with the latest release in the process which was promptly fixed by Runàr)</p>
</li>
</ul>
</li>
<li><p><code>registry</code></p>
<ul>
<li><p>Expand the API for overriding components (<code>setValueFrom</code>, <code>overrideValue</code> but I’m still not satisfied with this API).</p>
</li>
<li><p>Add a <code>makeDiagram</code> function to produce a Mermaid diagram for an application.</p>
</li>
</ul>
</li>
</ul>
<p>Talking about that last feature, I can now display a diagram of the application!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762898245633/8c412ab9-e517-40cc-9bdb-1c98d7f96b1c.png" alt class="image--center mx-auto" /></p>
<p>The diagram is directly derived from the declaration of the components of the application (and pasted to <a target="_blank" href="https://mermaid.live/edit#pako:eNqdVU1v1DAQ_SsrX5DQttjj76hUqloJDj0g0RMsB3-MdwPZZJVmK9qq_53JFlYILtn4FNvz3jw_TzzPLHUZWcXWfdhtFnc3q3ZBAyArW3yWOSinMEVVjDUeAqqgfA5FAkpt9dcVu-3Wt_iAzUWuHxahqdft-zcNluHNZTMuVwvs-66_eEfblyv27ZVfW1-k0xl84lY4HzSnhEbKGKTiHnlJ1sRkiP-6x4ztUIfm_gi3mgMPGCAVnbQpjqJJoOO-RGNBcUEioYQR3rX3XYNHqM-JxEcQLpdirfNRcstTcsKEzKUyOTpuiyLo1X7YdH39FIa6a--6H9j-f8ZhXK4Wb8fxzxljthkiUQYXtTZGFKUyN3QaShCtLDYooTBSpk999x3TcLWrj-ikZYrkNkdS5YwqQK5IhZi8jFYYrUCBwNGhq92uqdNB5RGeKUM2hkdZuPGCQ9EgcgqBxyQyaBcB0EZB8A_1sNnHv3PnaLQwoDlSoFZSR8hjFSQIHiOic5iN4JbAH4dhd93UdEFHdMnJeTAmCYkuh6Skd1Y5I0uKApNyAbDwGF5rZ439AXmaZ4uzs8vJRTSDeqoDM6in2nNaGcww5CTqqX_cDOqp7s2gnvoXzKA-7RqnCplRfCdRn6h6opAD9dSHdQb1aaqnRh-opzY6tmRb7LehztQrn8dEKzZscEuNpaLPjCXsG3oDV-0LhYb90H1-bBOrhn6PS9Z3-_WGVYV6GM32uxwGvKkD9dztcXXdj9y_Jz22Gfvrbt8OrBJyyXah_dJ12z-ENGXVM_vJKuD63HtrgUwE48C6JXskDIhzZbTlgvwFa5R6WbKnAwM_N-S304Tk1tH-yy9yTDzy">Mermaid Live</a>).</p>
<p>This diagram reveals some interesting points about the use of dependency injection:</p>
<ul>
<li><p>An <code>HttpClient</code> gets an <code>AuthorizationToken</code> that is automatically provided to make queries to both Unison Share and Github.</p>
</li>
<li><p>However this token must be different when the <code>HttpClient</code> is used by the <code>ProjectApi</code> than when it is used by the <code>GithubApi</code>, and the <code>registry</code> library supports this use case.</p>
</li>
<li><p>Since the <code>Application</code> uses APIs to communicate with other systems, it is possible to implement in-memory versions of those APIs to write purely in-memory tests for the <code>Application</code>. There are still some integration tests against those APIs, actually creating / deleting repositories for example, to check that everything works ok.</p>
</li>
<li><p>You can also notice a difference between the <code>Console</code> and the <code>Logger</code>. The <code>Console</code> is used to display user messages on screen (with the help of the excellent <code>terminus</code> library) while the <code>Logger</code> is only activated on demand or when there are errors.</p>
</li>
</ul>
<h1 id="heading-using-it">Using it</h1>
<p>Finally, I can use the application for my own needs! I used <code>tiles deploy</code> to deploy the service:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762898901473/2acc233d-52ff-4d97-bf93-25476af0975f.png" alt class="image--center mx-auto" /></p>
<p>I can even tail it directly from the Unison Command Manager, <code>ucm</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762899049922/dd3dd102-c928-4145-9375-e4cee85c0415.png" alt class="image--center mx-auto" /></p>
<p>Now, let’s have a look at all the synchronized projects:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762899297193/a8868541-0d24-4f27-9d27-8ac46970e4e3.png" alt class="image--center mx-auto" /></p>
<p>They are all synchronized but you will notice that some of them are private. In that case the corresponding Github repository, created when using the <code>sync</code> command, is private too.</p>
<p>Finally, what does it look like on Github?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762899410865/e8607268-033e-46b7-8848-62e0150c5c39.png" alt class="image--center mx-auto" /></p>
<p>For now I’m only creating one commit per push, with the full payload updating the <code>README</code> file of the project.</p>
<p>I hope to be able to use the newly announced history <code>comments</code> of <code>ucm-0.5.50</code> to produce specific commit messages when possible.</p>
<h1 id="heading-whats-next">What’s next?</h1>
<p>This was the perfect chance to create and deploy a simple Unison service. Next, I want to deploy something that will attract more users, include <a target="_blank" href="https://x.com/unisonweb/status/1848821333288747020">some storage</a>, and offer <a target="_blank" href="https://www.unison-lang.org/blog/volturno-design">meaningful analytics</a> so I can enjoy more of the Unison ecosystem. 😊</p>
]]></content:encoded></item><item><title><![CDATA[Don't look down! Look at the data instead!]]></title><description><![CDATA[Story time
When I was working at Macquarie Bank in Sydney, I would implement new features for the bonds trading back-office. Then, I would sit down with a business analyst, Greg (if I remember correctly) and he would test various cases with me. One t...]]></description><link>https://etorreborre.blog/dont-look-down-look-at-the-data-instead</link><guid isPermaLink="true">https://etorreborre.blog/dont-look-down-look-at-the-data-instead</guid><category><![CDATA[programming]]></category><category><![CDATA[data]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Tue, 04 Nov 2025 12:07:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zCD4mW7vm2c/upload/faf0f89126aa95d8bb264f436346e8e9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-story-time">Story time</h1>
<p>When I was working at Macquarie Bank in Sydney, I would implement new features for the bonds trading back-office. Then, I would sit down with a business analyst, Greg (if I remember correctly) and he would test various cases with me. One thing that struck me was how meticulously he would select a specific bond name, expiry date, and price. I thought, "It doesn't matter if the price is 1099.94 AUD or 100 AUD! Why is he spending so much time on this?"</p>
<p>Still, that made me think. I realized (much later) that I was wrong for at least two reasons. First, I was missing a good testing opportunity to use the system in conditions closer to reality. From a testing perspective, this had a better chance of revealing interesting bugs, where a business analyst might say, "Huh, that withholding tax amount doesn't make sense <em>at all</em>."</p>
<p>The second reason is a bit more subtle. I was not really <em>caring</em> about the service I was building, I was not living and breathing “bonds back-office”. The purpose of this post isn't to focus on this aspect, but I've often noticed the difference it makes when you genuinely care about <em>what</em> you are building, not just <em>how</em> you are building it.</p>
<h1 id="heading-real-world-data-ingestion">Real-world data ingestion</h1>
<p>The next step in my “data journey” was running ingestion pipelines. <em>Every single time</em> I ingested some large amounts of data I found some data that didn’t have the shape / properties I was expecting: “Oh, there could be no associated product metadata?”, “Yes, of course, because some products were created before the Big Migration”.</p>
<h1 id="heading-property-based-testing">Property-based testing</h1>
<p>Then came <a target="_blank" href="https://scalacheck.org">property-based testing</a> (PBT). Wow, I can write properties that test my code in many different conditions! And I would find bugs. But also sometimes realize that my nicely crafted property would not catch a specific bug. Why? Well, looking at the generated data I would realize for example that I was generating lists of strings that were mostly rubbish and not really suited to my domain. Hmm, I really needed to have a look at that data…</p>
<p>This can be an interesting exercise. Take a moderately complex domain model and create data generators for it. Now, examine the data and ask yourself: “How good is the coverage?” and “Am I really generating interesting cases?” Then, do a quick calculation on how many possible combinations exist for that model. You'll likely reach millions quite fast. What is the chance of hitting an interesting case when you run your property test only 100 times? What if you even run it 100000 times? Just, a drop in the ocean. As useful as PBT is, we cannot generated data <em>mindlessly</em>.</p>
<p>For a while I was interested by “enumeration testing”. The idea is to start enumerating exhaustively all the possible shapes of a given data model with <a target="_blank" href="https://hackage.haskell.org/package/smallcheck">the assumption that most bugs can be found with small examples</a>. Then my idea was to randomly sample that enumeration when it becomes too large to explore.</p>
<p>When I got the chance to discuss this idea with <a target="_blank" href="https://en.wikipedia.org/wiki/John_Hughes_\(computer_scientist\)">John Hughes</a> (of <a target="_blank" href="https://hackage.haskell.org/package/QuickCheck">QuickCheck</a> fame), he quickly dispelled my illusions. First of all, some bugs only show up after a rather complicated set of steps. John has an example of an issue in a stateful system that only shows up after 17 steps, but that counter-example was shrunk from an original failing test case of more than 100 steps! Then he told me that in his experience business knowledge is <em>indispensable</em> when driving your data generation strategy.  </p>
<p>That shouldn’t be surprising to any seasoned QA or test-minded person but the consequence is that we can’t consider data as a purely randomly generated artefact. The more we know its business meaning and edge cases, the better it is.</p>
<h1 id="heading-serialization">Serialization</h1>
<p>The next example comes from serialization. I previously worked on a project where a "Ledger" (think of it as an immutable list of transactions) was shared across nodes. The data was serialized using <a target="_blank" href="https://cbor.io">CBOR</a> to keep it compact. Serialization was a major concern because, as the system evolved, the data types changed, new data was stored differently, and we still needed to read data from the very beginning.</p>
<p>So, I began examining different pieces of data, both before and after changes: which fields were serialized and in what way. Then, I noticed we were quite inefficient in how we stored data. For example, we would allocate an array nested three times: <code>[[[a]]]</code> when <code>[a]</code> would have been sufficient.</p>
<p>Why? Because of the power (or curse) of macro annotations. Many languages now support serialization where you simply annotate the fields of a data type to automatically get serialize/deserialize instances. This is very useful, especially for prototyping when you want to quickly import or export data. However, I have come to dislike this feature in production code for two reasons:</p>
<ol>
<li><p>Serialization requirements are not “one size fits all”. For example I had issues with <code>serde</code> in Rust where some annotations were incompatible depending on the target format <code>bare</code> or <code>JSON</code>.</p>
</li>
<li><p>It becomes impractical to implement data model evolutions on large models.</p>
</li>
</ol>
<p>I'm going off-topic a bit, but my point is this: I only realized how inefficient our data serialization strategy was once I took a close look at the data.</p>
<h1 id="heading-visualizing-data">Visualizing data</h1>
<p>Over time, I've realized how helpful it is to display data clearly. This starts with logs. Sure, we can dump a <code>Debug</code> instance of some data type and get <code>created: Node { name: Name("n1"), peers: std::Vec(Peer { peerName: "p1" }, Peer { peerName: "p2" }) }</code>. But it would be much nicer to read something like <code>created node n1 [p1, p2]</code> instead. When you're reading hundreds of lines of logs, this can make a big difference and help you spot discrepancies faster.</p>
<p>Another situation is when data, whether it's incoming messages or your system state, is somewhat complex. In such cases, being able to visualize it over time is very helpful. Here is a recent example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762255857705/55de6019-7d6d-472c-b9ca-dc72214bd66d.png" alt class="image--center mx-auto" /></p>
<p>I created a simple HTML page that helps us visualize the main stages of a simulation trace for <a target="_blank" href="https://github.com/pragma-org/amaru">the system I'm currently working on</a>. While running the simulation and observing messages move from stage to stage, I noticed that the final stage, <code>forward_chain</code>, was receiving some duplicate messages. This should <em>not</em> happen! It means our node is sending unnecessary information to other nodes.</p>
<p>This isn't really a correctness issue—the data is still accurate. However, in a distributed system, this could mean that our node might get evicted due to its spammy behavior.</p>
<p>The great thing is that I only noticed this issue <strong>because I closely examined the data</strong>. The code was compiling, and all our tests were passing. It's important to note that I probably wouldn't have discovered this issue just by looking at the logs.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I am increasingly convinced that it's worthwhile to carefully examine the data, whether it's:</p>
<ul>
<li><p>Test data</p>
</li>
<li><p>Incoming data</p>
</li>
<li><p>System state</p>
</li>
<li><p>Outgoing data</p>
</li>
</ul>
<p>But data is quickly messy and too voluminous so it can really pay off to build small visualization tools to abstract the relevant parts and skim the rest. The good news is that we don’t have to be UI wizards anymore, LLMs can create these tools for us 😊.</p>
]]></content:encoded></item><item><title><![CDATA[We can do much better]]></title><description><![CDATA[I was really taken aback the other day by this piece of Terraform file:
variable "db_username" {
  description = "Postgres username"
  type  = string
}

The Terraform motto is “infrastructure as code”, but what I see above is a configuration file mas...]]></description><link>https://etorreborre.blog/we-can-do-much-better</link><guid isPermaLink="true">https://etorreborre.blog/we-can-do-much-better</guid><category><![CDATA[AWS]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[YAML]]></category><category><![CDATA[programming languages]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Tue, 28 Jan 2025 07:26:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737708653614/b89df30c-6e67-4f74-9cd0-89b6654ca451.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was really taken aback the other day by this piece of <a target="_blank" href="https://www.terraform.io/">Terraform</a> file:</p>
<pre><code class="lang-json">variable <span class="hljs-string">"db_username"</span> {
  description = <span class="hljs-attr">"Postgres username"</span>
  type  = string
}
</code></pre>
<p>The Terraform motto is <a target="_blank" href="https://www.terraform.io/use-cases/infrastructure-as-code">“infrastructure as code”</a>, but what I see above is a configuration file masquerading as a programming language!</p>
<p>Later on, at work, I got into a fight with the AWS Secret Manager and our EKS Cluster. The problem is simple:</p>
<ul>
<li><p>The <a target="_blank" href="https://aws.amazon.com/secrets-manager/">AWS Secret Manager</a> holds our Postgres database password, and is in charge of rotating it. Wonderful.</p>
</li>
<li><p>The <a target="_blank" href="https://aws.amazon.com/eks/">EKS Cluster</a> starts a pod where one container uses an environment variable expecting the database password. Great.</p>
</li>
</ul>
<p>Question: how do we pass this piece of information between those 2 systems?</p>
<h1 id="heading-the-path-to-madness">The path to madness</h1>
<p>The current solution consists in aligning precisely several pieces of text:</p>
<ul>
<li><p>The name of the secret created in the Secrets Manager.</p>
</li>
<li><p>The “secrets provider” resource in Kubernetes.</p>
</li>
<li><p>The “volumes” section of the Kubernetes pod.</p>
</li>
<li><p>The “mounted volume” for a given container.</p>
</li>
<li><p>The environment variable with a “secret reference”.</p>
</li>
</ul>
<p>Let’s have a look at those pieces.</p>
<h2 id="heading-the-secrets-provider">The secrets provider</h2>
<p>First the secrets provider:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">secrets-store.csi.x-k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">SecretProviderClass</span>
<span class="hljs-attr">metadata:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">database-secrets</span>
<span class="hljs-attr">spec:</span>
    <span class="hljs-attr">provider:</span> <span class="hljs-string">aws</span>
    <span class="hljs-attr">parameters:</span>
        <span class="hljs-attr">objects:</span> <span class="hljs-string">|
            - objectName: "rds!db-63dfcfd8-9b62-482a-ac60-faad5f806344"
              objectType: "secretsmanager"
</span>    <span class="hljs-attr">secretObjects:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">secretName:</span> <span class="hljs-string">database-username-and-password</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">Opaque</span>
      <span class="hljs-attr">data:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">objectName:</span> <span class="hljs-string">"rds!db-63dfcfd8-9b62-482a-ac60-faad5f806344"</span>
        <span class="hljs-attr">key:</span> <span class="hljs-string">DATABASE_USERNAME_AND_PASSWORD</span>
</code></pre>
<p>This piece of configuration maps a secret name in the AWS Secret Manager to a Kubernetes Secret. It actually does more than just a mapping. It also guarantees that both will be synchronized when the secret is rotated.</p>
<p>That’s great, but why does the secret name have to be repeated twice? That name now lives in 3 places: the Secrets Manager, the <code>parameters</code> definition, the <code>secretObjects</code> definition. Since everything is a string, there was also nothing to force us to use a secret name for the <code>objectName</code> field. We could have passed <code>rds!db-63dfcfd8-9b62-482a-ac60-faad5f80634</code> only to discover much later that a digit was missing.</p>
<p>We also have just introduced 3 new strings!</p>
<ul>
<li><p>The name of the secrets provider: <code>database-secrets</code>.</p>
</li>
<li><p>The <code>secretName</code> and the <code>key</code> of the secret because Kubernetes secrets are effectively maps of maps of strings.</p>
</li>
</ul>
<h2 id="heading-the-volumes-section">The volumes section</h2>
<p>In the pod deployment file we need a section declaring which volumes are mounted:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">volumes:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">secrets-provider-volume</span>
  <span class="hljs-attr">csi:</span>
  <span class="hljs-attr">driver:</span> <span class="hljs-string">secrets-store.csi.k8s.io</span>
  <span class="hljs-attr">readOnly:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">volumeAttributes:</span>
    <span class="hljs-attr">secretProviderClass:</span> <span class="hljs-string">"database-secrets"</span>
</code></pre>
<p>There, we need to make sure that we use the right name for the <code>secretProviderClass</code>, by using a string defined in another file. But look, we are introducing yet another string for the volume name: <code>secrets-provider-volume</code>!</p>
<h2 id="heading-mounting-a-volume">Mounting a volume</h2>
<p>Next we need to mount that volume inside the container that will use the secret:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">volumeMounts:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">secrets-provider-volume</span>
    <span class="hljs-attr">mountPath:</span> <span class="hljs-string">/mnt/secrets/database</span>
    <span class="hljs-attr">readOnly:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>Once more we need to be careful to match the volume name and we add yet another string for the <code>mountPath</code>.</p>
<h2 id="heading-the-environment-variable">The environment variable</h2>
<p>Finally we can declare an environment variable that will hold the secret:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">OCKAM_DATABASE_USERNAME_AND_PASSWORD</span>
  <span class="hljs-attr">valueFrom:</span>
    <span class="hljs-attr">secretKeyRef:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">database-username-and-password</span>
      <span class="hljs-attr">key:</span> <span class="hljs-string">DATABASE_USERNAME_AND_PASSWORD</span>
</code></pre>
<p>Like before we need to make sure to reuse the same names that we declared in the secret provider, <code>secretName</code> and <code>key</code>, except that they are now called <code>name</code> and <code>key</code>.</p>
<p>Note that nothing tells us that the volume <code>secrets-provider-volume</code> needed to be mounted and if the <code>mountPath</code>, <code>/mnt/secrets/database</code>, was relevant.</p>
<h2 id="heading-in-summary">In summary</h2>
<p>In order to use <strong><em>one</em></strong> AWS Secrets Manager secret in a Kubernetes pod we have to carefully align:</p>
<ul>
<li><p>One generated string (the secret name).</p>
</li>
<li><p>4 user defined strings.</p>
</li>
<li><p>In 10 different spots.</p>
</li>
</ul>
<p>This is the definition of <a target="_blank" href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/">programming by coincidence</a>!</p>
<h1 id="heading-can-we-have-a-real-programming-language-please">Can we have a real programming language, please?</h1>
<p>This short video is funny:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=WcdoC0KBCSU">https://www.youtube.com/watch?v=WcdoC0KBCSU</a></div>
<p> </p>
<p>It basically says “We made all this YAML so that you don’t have to do it“.</p>
<p>One objective of the Unison programming language is to have <a target="_blank" href="https://www.unison.cloud/">a cloud offering</a> where declaring services and all sorts of resources can be done programmatically. This has numerous advantages:</p>
<ol>
<li><p>We can name variables that hold values, and refer to those names everywhere.</p>
</li>
<li><p>We can type those variables to prevent runtime errors.</p>
</li>
<li><p>We can use abstractions to isolate from implementation details.</p>
</li>
</ol>
<p>What would it look like for our “secret” example to use a programming language?</p>
<h2 id="heading-the-secret-sauce">The secret sauce</h2>
<p>If we had a programming language at our fingertips we could start by defining the concept of “secret source”, that can be implemented by an <code>AwsManagedSecret</code> (all the code that follows is pseudo-Haskell-like code):</p>
<pre><code class="lang-haskell">
<span class="hljs-title">databaseManagedSecret</span> : <span class="hljs-type">IO</span> <span class="hljs-type">AwsManagedSecret</span>
<span class="hljs-title">databaseManagedSecret</span> = getOrCreateAwsManageSecret <span class="hljs-string">"prod-database"</span> <span class="hljs-type">RotationPolicy</span>.<span class="hljs-type">MONTHLY</span>
<span class="hljs-class">
<span class="hljs-keyword">class</span> <span class="hljs-type">SecretSource</span> s <span class="hljs-keyword">where</span></span>
  getSecret : s -&gt; <span class="hljs-type">IO</span> <span class="hljs-type">Secret</span>
<span class="hljs-class">
<span class="hljs-keyword">instance</span> <span class="hljs-type">SecretSource</span> <span class="hljs-type">AwsManagedSecret</span> <span class="hljs-keyword">where</span></span>
  getSecret = todo
</code></pre>
<p>The purpose of a <code>SecretSource</code> is to give us the most recent secret when we ask for it. The real thing would actually give us more, like the frequency of the rotation, or how to access it via the network.</p>
<p>The implementation is using the AWS secrets manager but it could an <a target="_blank" href="https://azure.microsoft.com/en-us/products/key-vault">Azure Key Vault</a>. You will notice that we give the managed secret a name but it is not relevant for the rest of the code.</p>
<p>Next, we need to define a Kubernetes Secret that uses the <code>SecretSource</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-comment">-- A KubernetesSecretFromSource takes care of synchronizing </span>
<span class="hljs-comment">-- the secret from the source, including</span>
<span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">KubernetesSecretFromSource</span> = todo</span>

<span class="hljs-title">makeKubernetesSecret</span> : <span class="hljs-type">SecretSource</span> s =&gt; s -&gt; <span class="hljs-type">IO</span> <span class="hljs-type">KubernetesSecretFromSource</span>
<span class="hljs-title">makeKubernetesSecret</span> s = todo
<span class="hljs-class">
<span class="hljs-keyword">class</span> <span class="hljs-type">KubernetesSecret</span> s <span class="hljs-keyword">where</span></span>
  getSecretMap : s -&gt; <span class="hljs-type">IO</span> <span class="hljs-type">SecretMap</span>
<span class="hljs-class">
<span class="hljs-keyword">instance</span> <span class="hljs-type">KubernetesSecret</span> <span class="hljs-type">KubernetesSecretFromSource</span> <span class="hljs-keyword">where</span></span> ...
</code></pre>
<p>Now, we define an environment variable from a <code>KubernetesSecret</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-comment">-- An environment variable getting its value from a KubernetesSecret</span>
<span class="hljs-comment">-- It is responsible to mounting the right volume when used for creating a Pod</span>
<span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">EnvVarFromKubernetesSecret</span> = todo</span>

<span class="hljs-title">makeEnvVarFromKubernetesSecret</span> : <span class="hljs-type">KuberneteSecret</span> s =&gt; s -&gt; <span class="hljs-type">IO</span> <span class="hljs-type">EnvVarFromKubernetesSecret</span>
<span class="hljs-title">makeEnvVarFromKubernetesSecret</span> s = todo
<span class="hljs-class">
<span class="hljs-keyword">class</span> <span class="hljs-type">EnvironmentVariable</span> v <span class="hljs-keyword">where</span></span>
  getName : v -&gt; <span class="hljs-type">Text</span>
  getValue : v -&gt; <span class="hljs-type">IO</span> <span class="hljs-type">Text</span>
<span class="hljs-class">
<span class="hljs-keyword">instance</span> <span class="hljs-type">EnvironmentVariable</span> <span class="hljs-type">EnvVarFromKubernetesSecret</span> <span class="hljs-keyword">where</span></span> ...
</code></pre>
<p>Finally we can create a <code>Pod</code>, using an <code>EnvironmentVariable</code> which abstracts the details of how the value is retrieved:</p>
<pre><code class="lang-haskell"><span class="hljs-title">createPod</span> : <span class="hljs-type">EnvironmentVariable</span> v =&gt; v -&gt; ... -&gt; <span class="hljs-type">IO</span> <span class="hljs-type">Pod</span>
<span class="hljs-title">createPod</span> variable ... = <span class="hljs-keyword">do</span>
  <span class="hljs-comment">-- this mounts the right volume for the pod</span>
  setEnvironmentVariable variable

<span class="hljs-comment">-- The full configuration</span>
<span class="hljs-title">databaseClientPod</span> :: <span class="hljs-type">IO</span> <span class="hljs-type">Pod</span>
<span class="hljs-title">databaseClientPod</span> = <span class="hljs-keyword">do</span>
  managedSecret &lt;- databaseManagedSecret
  k8sSecret &lt;- makeKubernetesSecret managedSecret
  envVar &lt;- makeEnvVarFromKubernetesSecret k8sSecret
  createPod envVar
</code></pre>
<p>All of this is just a sketch, and the important points are:</p>
<ol>
<li><p>We use typed variables to pass information around.</p>
</li>
<li><p>We use interfaces / typeclasses to hide implementation details.</p>
</li>
<li><p>We have library functions that declare exactly what is necessary to build:</p>
<ol>
<li><p>A <code>Pod</code>,</p>
</li>
<li><p>An <code>EnvironmentVariable</code> backed by a <code>KubernetesSecret</code>,</p>
</li>
<li><p>A <code>KubernetSecret</code> from a <code>SecretSource</code>.</p>
</li>
</ol>
</li>
</ol>
<p>This is just good old software engineering practices! With huge benefits:</p>
<ul>
<li><p>Less possibilities to make mistakes,</p>
</li>
<li><p>More discoverability of how things work,</p>
</li>
<li><p>A lot more fun programming our resources!</p>
</li>
</ul>
<h1 id="heading-lets-do-it">Let’s do it?</h1>
<p>If we wanted to go that route there would be a number of obstacles:</p>
<ol>
<li><p>I am not sure a mainstream programming languages can support that approach if, at some stage, we need some fancy types. However, if we just need type-safe heterogeneous maps <a target="_blank" href="https://gist.github.com/cakoose/39b13ab9b323b0573f55638c3dc6baec">we should be covered</a>.</p>
</li>
<li><p>There would be a need for dependency injection in order to be able to easily define a configuration based off another configuration (what “<a target="_blank" href="https://developer.hashicorp.com/terraform/language/files/override">override files</a>” are attempting to do).</p>
</li>
<li><p>The sheer size of the project! The number of data structures and APIs to cover is enormous. I suspect that only a company-backed project (like <a target="_blank" href="https://www.pulumi.com/">Pulumi</a>) could sustain this kind of effort.</p>
</li>
</ol>
<p>So, what do you all think? Can we do better? Can we do <strong><em>much</em></strong> better?</p>
]]></content:encoded></item><item><title><![CDATA[2024 in review]]></title><description><![CDATA[This year I decided to do a quick professional retrospective. It’s easier to plan the road ahead when you also have an eye on the rear-view mirror!
I can group most of my highlights of 2024 in 3 categories:

Becoming a technologist

Unison

The small...]]></description><link>https://etorreborre.blog/2024-in-review</link><guid isPermaLink="true">https://etorreborre.blog/2024-in-review</guid><category><![CDATA[ockam]]></category><category><![CDATA[2024]]></category><category><![CDATA[technology]]></category><category><![CDATA[Unison]]></category><category><![CDATA[Elixir]]></category><category><![CDATA[AWS]]></category><category><![CDATA[snowflake]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Tue, 31 Dec 2024 22:57:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735685764013/ed386b36-b059-4efd-8e02-33ebc9055829.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This year I decided to do a quick professional retrospective. It’s easier to plan the road ahead when you also have an eye on the rear-view mirror!</p>
<p>I can group most of my highlights of 2024 in 3 categories:</p>
<ol>
<li><p>Becoming a technologist</p>
</li>
<li><p>Unison</p>
</li>
<li><p>The small stuff</p>
</li>
</ol>
<h1 id="heading-becoming-a-technologist">Becoming a technologist</h1>
<p>I have always thought about myself as a “Software Engineer”. My main activity was to produce <em>proper code</em> forming <em>reliable systems</em>, and culminating in <em>desirable products</em>. 2024 marks a shift where I learned to become a <em>technologist</em>. What do I mean by this?</p>
<p>It turns out that many issues pertaining to software have largely been solved:</p>
<ul>
<li><p>Provision machines to execute applications.</p>
</li>
<li><p>Persist vast amounts of data.</p>
</li>
<li><p>Run distributed systems reliably.</p>
</li>
<li><p>Identify users and control access.</p>
</li>
<li><p>Analyze data.</p>
</li>
<li><p>etc…</p>
</li>
</ul>
<p>Many of these solutions are available as services, under the <a target="_blank" href="https://aws.amazon.com/">AWS umbrella</a> for example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735647659422/53ffb12e-23e9-47ed-bfe7-771fe95251bc.png" alt class="image--center mx-auto" /></p>
<p>When you build software products it would be foolish to not stand on the shoulder of giants and not reuse, or integrate with, those services. The consequence is that you spend a lot less time <em>programming</em>, and a lot more time <em>configuring</em>. I think that the right question to ask is “can we go back to programming?” and will try to give an answer after a few examples.</p>
<h2 id="heading-whats-going-on-with-my-users">What’s going on with my users?</h2>
<p>Getting proper feedback is essential to understanding if your product is going in the right direction. At <a target="_blank" href="https://www.ockam.io">Ockam</a>, we enable users to securely connect any system to any other system, without having to open any internet ports. Our command-line executable, <code>ockam</code>, supports many commands to establish what we call <em>portals</em> and manage them (by creating cryptographic identities, permissions, etc…).</p>
<p>We want this experience to be as seamless as possible and, if we can, be proactive in assisting users with any issue that they might face. We tried to leverage <a target="_blank" href="https://opentelemetry.io/">OpenTelemetry</a> traces in order to gather as much actionnable data as possible:</p>
<ul>
<li><p>Which command is invoked?</p>
</li>
<li><p>What are the response times in various parts of our pipeline?</p>
</li>
<li><p>What errors might be raised?</p>
</li>
<li><p>Are there frequent command-line errors?</p>
</li>
<li><p>Are there some stuck users who can’t create a portal for some reason?</p>
</li>
</ul>
<p>My job has been to instrument our command-line tool to structure this data, collect it, and slice it to:</p>
<ul>
<li><p>Show the “journey” of a user.</p>
</li>
<li><p>Being able to track down issues to relevant traces and log messages.</p>
</li>
</ul>
<p>The “structure” / “collect” / “slice” parts were not entirely under my control: OpenTelemetry is a standard with a strict (and large!) specification, and there are many offerings for collecting and aggregating telemetry data. This is where the <em>technologist</em> part comes in. Most of the work consists in:</p>
<ul>
<li><p>Understanding the data model and behavior of a system that someone else built.</p>
</li>
<li><p>Put the right information at the right place.</p>
</li>
<li><p>Respect constraints established by someone else (maximum number of spans for a trace for example).</p>
</li>
<li><p>At a reasonable cost! Yes, this is also a dimension to optimize for and we’ve all heard of horror stories with software bills gone wrong.</p>
</li>
</ul>
<p>I could probably make quite a long blog post around this piece work but I am going summarize my learnings here:</p>
<ul>
<li><p>What we want to do is not really supported by any vendor. Many services focus on aggregating data and being able to drill down on an error. What we want to see is the most relevant events <em>for each user</em>.</p>
</li>
<li><p>OpenTelemetry is a bit of a bloated specification <a target="_blank" href="https://www.honeycomb.io/blog/time-to-version-observability-signs-point-to-yes">in need of a radical change</a> (tl;dr “wide structured events” instead of traces/logs/metrics).</p>
</li>
<li><p>I had <a target="_blank" href="https://en.wikipedia.org/wiki/Unified_Modeling_Language">UML</a> vibes from the past, realizing that the same standard was not supported in the same way by different vendors.</p>
</li>
<li><p>Testing and non-regression is difficult. How do you check that events are still properly sent and aggregated across your service and someone else’s?</p>
</li>
<li><p>Visualization of data is non-trivial and the complexity of the OpenTelemetry data model does not help.</p>
</li>
<li><p>The existence of a generic “collector” where you can send all the traces centrally, and then dispatch to the backend of your choice is a huge benefit. A good example of interface/implementation separation at the system level!</p>
</li>
<li><p>That being said, and despite the existence of the OpenTelemetry specification, each new vendor comes with its own configuration, project model, users model, visualization tools, query language, etc… It’s almost like starting from scratch every time.</p>
</li>
<li><p>Costs are definitely a factor. Are we getting the most out of a given service? (answer: not quite).</p>
</li>
</ul>
<h2 id="heading-were-all-snowflakes">We’re all snowflakes</h2>
<p>The other big piece of technology that I worked on this year is <a target="_blank" href="https://www.snowflake.com/">Snowflake</a>. In summary Snowflake is a platform allowing you to import huge amounts of data and process it without having to worry about dealing with any infrastructure. A giant database and application environment at your fingertips.</p>
<p><a target="_blank" href="https://ockam.io/">Ockam</a> is a particularly good fit for Snowflake since we allow users to import data from their private systems without exposing them on the internet, and then export analyses back. In order to help customers get started with instant connectivity to Snowflake we built <a target="_blank" href="https://app.snowflake.com/marketplace/data-products/search?search=ockam">a set of connectors</a> to import/export data from/to Kafka, Postgres, SFTP, WebDAV.</p>
<p>This is very much an exercise in assembling technologies:</p>
<ul>
<li><p>Learn about the <a target="_blank" href="https://docs.snowflake.com/en/guides">Snowflake model</a>: Warehouses, database, tables, streams, users, organizations, etc…</p>
</li>
<li><p>Learn about the deployment model of Snowflake: versions, patches, deployment directives, cloud regions, marketplace, accounts…</p>
</li>
<li><p>Assemble the software as docker images with specific restrictions on networking. Juggle security restrictions to configure our own service.</p>
</li>
<li><p>Use Python to develop small clients.</p>
</li>
<li><p>Use Javascript to implement some stored procedures.</p>
</li>
<li><p>Use SQL (Snowflake’s version of SQL) to write queries.</p>
</li>
<li><p>Configure a myriad of YAML files.</p>
</li>
<li><p>Use <a target="_blank" href="https://streamlit.io">Streamlit</a> to develop small configuration applications.</p>
</li>
<li><p>Deploy Kafka locally via a docker image. Use <a target="_blank" href="https://docs.docker.com/compose/">docker compose</a> to also deploy our own service.</p>
</li>
<li><p>Click on many buttons, many, many times.</p>
</li>
</ul>
<p>We eventually got those connectors to work after a lot of head-scratching but there is a stark contrast with traditional software development:</p>
<ul>
<li><p>You have to fit in the vendor’s model. That model contains a lot more information than you actually need for the specific job you have. It’s on you to sort it out.</p>
</li>
<li><p>Many attempts can be necessary to understand <em>exactly</em> how that model behaves. Many things are left unspecified and you discover them only by trying.</p>
</li>
<li><p>The user experience can be limited, and fixing it is out of your reach (we can’t get users table metadata to display source/target mappings in our connectors for example).</p>
</li>
<li><p>Automatic testing in general is out of question, that would be a massive project in itself.</p>
</li>
<li><p>There is almost no way to <em>compile</em> or <em>typecheck</em> anything:</p>
<ul>
<li><p>Configuration happens by accident. Not the right name is the right place? Wait 5 minutes to see your service crash after deployment.</p>
</li>
<li><p><a target="_blank" href="https://streamlit.io/">Streamlit</a> uses Python. Change some shared UI code somewhere and see silly and avoidable bugs somewhere else at runtime (if you happen to manually re-test <em>all</em> your applications…).</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-who-are-you-a-solved-problem">Who are you? A solved problem?</h2>
<p>The last piece concerns my use of <a target="_blank" href="https://auth0.com">Auth0</a>. Signing-up / Signing-in a service is such a ubiquitous and critical requirement that it makes sense to found a company around it (and it’s not a simple as it sounds).</p>
<p>At <a target="_blank" href="https://www.ockam.io/">Ockam</a>, we want to give the best onboarding experience to our users and, instead of re-inventing the proverbial wheel, we use Auth0. Once more my job was step away from the <em>programming mode,</em> to enter the <em>configuring mode</em>. At first glance, it’s not that bad:</p>
<ul>
<li><p>We can customize the sign-up / login screens.</p>
</li>
<li><p>We can add some pieces of code to intercept and act on parts of the process (deny some email domains for example from signing-up).</p>
</li>
<li><p>We can monitor major events and errors.</p>
</li>
</ul>
<p>Unfortunately, using Auth0 is not devoid of problems:</p>
<ul>
<li><p>A user trying to sign-in with the sign-up page will be rejected, even if their credentials are correct. There is no way so far to fix this UX issue.</p>
</li>
<li><p>There are many parameters to configure, the effect of some of them is not clear. One example: if you use a custom URL to present your Auth0 service, the URL domain will be automatically picked-up for some redirects. You can’t control that.</p>
</li>
<li><p>By default, there’s no version control of your configuration. Fortunately there is a <a target="_blank" href="https://github.com/auth0/terraform-provider-auth0">Terraform provider</a>, allowing you to save all your configuration as, horror,… more YAML files. But there’s no guarantee that the Auth0 UI uses the last version of your configuration.</p>
</li>
</ul>
<h2 id="heading-special-mention-chatgpt">Special mention: ChatGPT</h2>
<p>2024 is the year when I really started to use AI. While I haven’t used it much for coding, I have extensively used ChatGPT to solve all sort of issues when dealing with technologies new to me. And I am not the only one:</p>
<p><img src="https://media.licdn.com/dms/image/v2/D5622AQE7RTKxBI5Idw/feedshare-shrink_2048_1536/feedshare-shrink_2048_1536/0/1692583216291?e=2147483647&amp;v=beta&amp;t=oexhM7kKuOPxAv322Ea_GZTJSpii6sKQXpZ_CxPwmUw" alt="Tom Alder on LinkedIn: The irony is crushing. Stack Overflow's traffic  since ChatGPT went… | 387 comments" /></p>
<p>I must say that the ability to have a conversation with a knowledge base about a given problem is really a game-changer.</p>
<h2 id="heading-where-do-we-go-from-there">Where do we go from there?</h2>
<p>Don’t get me wrong, I think it’s <em>great</em> to be a technologist. More than ever, we have to possibility to create incredible systems by building on top of amazing services. My biggest complaint is that, when building <em>in the large</em>, we lose all the good tools we have when building <em>in the small</em>:</p>
<ul>
<li><p>Version control.</p>
</li>
<li><p>Typechecking.</p>
</li>
<li><p>Linting.</p>
</li>
<li><p>Unit / Integration tests.</p>
</li>
<li><p>Code completion / code navigation across libraries.</p>
</li>
<li><p>Specifications / models for our code.</p>
</li>
<li><p>Dependency injection.</p>
</li>
<li><p>Integrated documentation.</p>
</li>
<li><p>Rich development environments and terminals.</p>
</li>
<li><p>Dependency bots.</p>
</li>
<li><p>Hot reloading.</p>
</li>
<li><p>Notebooks.</p>
</li>
<li><p>Deployment as code.</p>
</li>
<li><p>CI / CD.</p>
</li>
</ul>
<p>Note that the situation above is far from perfect <em>in the small</em>! There’s no actual environment where all those features are available at the same time by default. We can get somewhere near this picture by, once more, becoming <em>technologists</em> and assemble all tools we need (with the same issues as before).</p>
<p>I think that we can massively improve the situation by fundamentally make everything look like <em>code</em>. Especially <em>code</em> that deals with <em>code</em>:</p>
<ul>
<li><p>Deployment code: to associate services with resources.</p>
</li>
<li><p>Observability code: to define how we want to monitor our systems.</p>
</li>
<li><p>Testing code: to assert properties of our code.</p>
</li>
<li><p>Documentation code: to give executable examples.</p>
</li>
<li><p>Configuration code: to describe how the code is assembled.</p>
</li>
<li><p>Graphical code: to represent and modify the configuration in a 1-1 correspondence.</p>
</li>
</ul>
<p>This leads me to my second highlight for 2024.</p>
<h1 id="heading-unison">Unison</h1>
<p>Around April I decided to take the plunge and learn more about the <a target="_blank" href="https://unison-lang.org/">Unison programming language and platform</a>. I explain some of my motivations in “<a target="_blank" href="https://etorreborre.blog/what-is-so-unique-about-unison">What is so unique about Unison?</a>”, but in retrospect a huge motivation is present in what I wrote above about “code everywhere”:</p>
<ul>
<li><p>Unison services are deployed using Unison code, monitored using Unison code.</p>
</li>
<li><p>The documentation is type-checked and executable.</p>
</li>
<li><p>Dependencies are tracked very finely so that tests can be cached.</p>
</li>
<li><p>There’s is not data to serialize / deserialize between services or persistent storage. It’s all just Unison terms.</p>
</li>
</ul>
<h2 id="heading-step-1">Step 1</h2>
<p>My overall goal for this year was to write and deploy a service to export some bank transactions from <a target="_blank" href="https://doc.bunq.com/">one of my bank accounts</a> and import them into <a target="_blank" href="https://api.ynab.com/">my accounting software</a>. I started by writing <a target="_blank" href="https://share.unison-lang.org/@etorreborre/multimap">a modest <code>MultiMap</code> library</a> to get a better feel for the development cycle.</p>
<h2 id="heading-step-2">Step 2</h2>
<p>When I first tried to connect to my bank, via HTTP, I quickly realized that Unison was missing some cryptography primitives (RSA) to sign some payloads. Time to re-open my Haskell toolbox and <a target="_blank" href="https://github.com/unisonweb/unison/pull/4932">contribute to the language itself</a>! (+ a bit of glue on the base library side).</p>
<h2 id="heading-step-3">Step 3</h2>
<p>I then realized that having a command-line parsing library would be nice in order to run my service with different arguments, in particular API keys and account numbers which I did not want to store as term.</p>
<p>That sounds antithetical with my “everything as code” objective and it is! Still, I took this huge detour to:</p>
<ul>
<li><p>Create the <a target="_blank" href="https://share.unison-lang.org/@etorreborre/potions">potions library</a> for parsing command-line options.</p>
</li>
<li><p>Talk about it at <a target="_blank" href="https://www.unison-lang.org/unison-forall-2024/">the Unison forall conference</a>, because this is an interesting problem to solve and a good example of how to use some Unison features to design a library.</p>
</li>
</ul>
<p>In retrospect, I think it would be a good idea to make a small library for embedding encrypted data, so that one key only can unlock the whole configuration of an application as Unison terms, and make that a secret in a <a target="_blank" href="https://share.unison-lang.org/@unison/cloud/code/main/latest/namespaces/Environment/;/types/@3j6045jl1ngsop8a3m7va0pib6lp67bq503b76rkb62f4ku38eiud1i7pi47aet1kiahgim16bu8dkcufv8s1de7rcoa761steht9p0">Unison Cloud <code>Environment</code></a>.</p>
<h2 id="heading-step-4">Step 4</h2>
<p>I was finally able to come back to my application, write some code to make HTTP queries, retrieve transactions, decode them from JSON (shocking, not everyone is using Unison yet!), write a bit of logic to create accounting transactions and post them to my favorite accounting software, <a target="_blank" href="https://www.ynab.com/">YNAB</a> (thanks for having an API!).</p>
<p>That led me to another pet peeve of mine. I think that we are plagued by the lack of dependency injection in our industry. We are sometimes lucky to have nice compositional software, thanks to functional programming, so we know how to <em>assemble</em> code. But when it comes to say “give me the same piece of code with one slightly different bit” we just don’t have the words.</p>
<p>Configuration is a good example of this. We use all sorts of tricks to say “I want the same configuration but change x and y for the development environment”: environment variables, “overlays”, scripts to write YAML, templating languages, etc…</p>
<p>I think that we should recognize this problem as a dependency injection problem, and have the possibility to replace <em>any piece</em> of a software system, from the billing component, to an API key. Ideally the language used should be the same as the programming language. This is not a big ask, in principle we just need a bit of meta-programming to do so. <a target="_blank" href="https://github.com/etorreborre/registry">Here</a> is an example on how to support DI in Haskell. An added benefit is that <a target="_blank" href="https://github.com/etorreborre/registry/blob/main/doc/dot.md">we automatically get a picture of the system structure</a> because we have “code about code” at our disposal.</p>
<p>Given that my application was starting to grow (with 13 components in different configurations for local our Cloud testing), I set out to write a library to support dependency injection in Unison. This is still <a target="_blank" href="https://share.unison-lang.org/@etorreborre/di">work in progress</a> (I use it but it’s undocumented for now) but I’ll have the opportunity to share more about it next year.</p>
<h2 id="heading-and-now">And now?</h2>
<p>My application is still not online, and I can only blame myself because I just took another detour (one more time against the spirit of “everything as code”, I’m not so consistent there) since I implemented a TOML parser (<a target="_blank" href="https://share.unison-lang.org/@etorreborre/toml">to be released soon</a>). That was a great exercise in parsing but also in exploring the complexity of what is supposed to be a simple configuration language (I hope to blog about that experience separately).</p>
<p>When that is done, I will finally deploy my application in “production” (I’ve only deployed it and made it run for a limited amount of time for now).</p>
<p>All in all, it was a great year for my use of Unison. I think that this language has both niche and tremendous potential, if that makes sense! And special mention to the Unison team, you’re all amazing!</p>
<h1 id="heading-tidbits">Tidbits</h1>
<p>In no specific order, here are some other thoughts about 2024 from a tech side.</p>
<h2 id="heading-flox">Flox</h2>
<p>I have been using <a target="_blank" href="https://flox.dev">flox</a>, <a target="_blank" href="https://etorreborre.blog/why-you-should-flox-every-day">my favorite package manager</a>, for 2 years now. I really like the peace of mind that Nix brings to the table for managing my environments, with the very reasonable set of command-line instructions that Flox provides. This year brought services, <a target="_blank" href="https://flox.dev/docs/tutorials/ci-cd/">easier CI/CD</a>, <a target="_blank" href="https://github.com/flox/flox/releases/tag/v1.2.1">installing from flakes</a>, <a target="_blank" href="https://github.com/flox/flox/releases/tag/v1.0.2">better support for shells</a>, and many, many fixes and improvements. Many thanks to the Flox team for their great support, even with my sometimes convoluted configuration!</p>
<h2 id="heading-elixir">Elixir</h2>
<p>I started using Elixir + Phoenix (Web framework) + Ecto (Persistence framework) at work. I really appreciate:</p>
<ul>
<li><p>The functional programming angle.</p>
</li>
<li><p>A working REPL with hot-reloading.</p>
</li>
<li><p>Hot-reloading also in Phoenix.</p>
</li>
</ul>
<p>On the other hand, I am still not a fan of dynamic languages:</p>
<ul>
<li><p>IMO they encourage sloppy data modeling (is this a string, an atom, a Map, a struct?).</p>
</li>
<li><p>They make the codebase harder to navigate and understand (especially when macros are involved).</p>
</li>
<li><p>They make refactoring harder and riskier.</p>
</li>
<li><p>Error can be hard to decipher.</p>
</li>
<li><p>Type signatures can be added but are only checked on demand, and not particularly quickly.</p>
</li>
</ul>
<p>I really hope that <a target="_blank" href="https://gleam.run/">Gleam</a> is going to replace Elixir in many applications but rewrites are expensive and risky so I wouldn’t bet on it.</p>
<h2 id="heading-blogging">Blogging</h2>
<p>I didn’t blog a lot this year, even if I wanted to. Only 3 posts, including this one, and one of the 3 is not even about tech, it’s about <a target="_blank" href="https://etorreborre.blog/we-have-no-free-will-and-this-is-not-a-big-deal">Free Will</a>!</p>
<h2 id="heading-conferences">Conferences</h2>
<p>I initially wanted to go to <a target="_blank" href="https://icfp24.sigplan.org/">ICFP Milan</a> but that eventually did not work out. I was however invited to give a presentation at the Philips Developer Days (Thanks Rodolfo!) and really enjoyed the afternoon over there because: 1. It was in the medical sector where lots of interesting software is being developed, 2. The talks were really excellent and somewhat connected to mine (about modularity), 3. The venue was <a target="_blank" href="https://en.wikipedia.org/wiki/Philips_Stadion">quite unusual</a>!</p>
<h2 id="heading-jj-zed-ocaml">jj, zed, ocaml</h2>
<p>No, I’m not falling asleep on my keyboard. Those are 3 things I tried this year but did not pursue:</p>
<ul>
<li><p><a target="_blank" href="https://ocaml.org/">OCaml</a>: I didn’t do much simply because I was taken aback by the syntax (yes, I know, it is a silly reason).</p>
</li>
<li><p><a target="_blank" href="https://zed.dev/">Zed</a>: I tried it (Helix also) but 2024 is still not the year when I will get super effective with an editor.</p>
</li>
<li><p><a target="_blank" href="https://jj-vcs.github.io/jj/latest/">jj (Jujutsu)</a>: I’m convinced that we can do better than Git, and <code>jj</code> seems to be it. I tried it a bit but did not quite understand how to work effectively with a Github workflow based on branches. I will probably give it another go next year.</p>
</li>
</ul>
<h1 id="heading-onwards-to-2025">Onwards to 2025!</h1>
<p>That’s it for 2024. If you have read so far, I hope that this post triggered some interesting thoughts for you (don’t hesitate to share!). It definitely helped me put some vague feelings into words.</p>
<p>I feel now ready for 2025 and I hope you are too, it’s gonna rock!</p>
]]></content:encoded></item><item><title><![CDATA[What is so unique about Unison?]]></title><description><![CDATA[I have recently started exploring the Unison programming language. Some programming languages are good because they improve the current state of affairs. For example Gleam brings type-safety to the Erlang platform. Other languages are game-changers:
...]]></description><link>https://etorreborre.blog/what-is-so-unique-about-unison</link><guid isPermaLink="true">https://etorreborre.blog/what-is-so-unique-about-unison</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[Unison]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Sat, 04 May 2024 21:20:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714728128026/5f89b485-4f94-4dfa-b000-4015d70c4c15.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have recently started exploring the <a target="_blank" href="https://www.unison-lang.org">Unison programming language</a>. Some programming languages are good because they improve the current state of affairs. For example <a target="_blank" href="https://gleam.run">Gleam</a> brings type-safety to the Erlang platform. Other languages are <em>game-changers</em>:</p>
<ul>
<li><p>When <a target="_blank" href="https://www.scala-lang.org/">Scala</a> was introduced, it brought an incredible amount of (statically-typed) functional programming features to the JVM. This changed the way we approached mutability, error management, concurrency, and structured our programs.</p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=OJv8rFap0Nw">Verse unifies functional-programming and logical programming</a>, where notions of failure, multiple-valued variables, and transactions, are baked into the language. This changes the way we think about control flow.</p>
</li>
<li><p><a target="_blank" href="https://www.unison-lang.org/">Unison</a> is a <em>frictionless language</em>. It builds on the idea of "immutable code" to give us a huge productivity boost for writing cloud applications.</p>
</li>
</ul>
<p>In this post, I am sharing my first steps with Unison. The parts where I was delighted but also the parts where I was confused. I will only talk about my experience of developing a small library for now. Part 2 will be about developing a full cloud application for my own needs.</p>
<h1 id="heading-first-steps">First steps</h1>
<p>I didn't need much to get started with Unison:</p>
<ul>
<li><p>An executable called the <code>Unison Code Manager</code> (<code>ucm</code> for short). It is available as <a target="_blank" href="https://search.nixos.org/packages?channel=23.11&amp;show=unison-ucm">a nix package</a>, so it was very easy for me to <a target="_blank" href="https://etorreborre.blog/why-you-should-flox-every-day">install it with <code>flox</code></a>.</p>
</li>
<li><p>VS Code with <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=unison-lang.unison">the Unison plugin</a>.</p>
</li>
</ul>
<p>I then created a <code>quickstart</code> project with <code>project.create quickstart</code> using <code>ucm</code>. With this project, I was all setup for coding. Here is a simple <code>hello</code> function:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714735559651/c5211234-784a-4573-92a9-60b5998ec982.png" alt class="image--center mx-auto" /></p>
<p>The first unusual thing with unison is that <em>files don't matter</em>. A convenient setup for your editor is a split screen as above with <em>just one file</em> on the left, and <code>ucm</code> on the right. Where is my code then? It is in a database:</p>
<pre><code class="lang-bash">ll <span class="hljs-variable">$HOME</span>/.unison/v2
Permissions Size User        Date Modified Name
.rw-r--r--@    0 etorreborre 14 Apr 12:48  unison.lockfile
.rw-r--r--@  13M etorreborre 14 Apr 12:55  unison.sqlite3
</code></pre>
<p>Then, I went through the <a target="_blank" href="https://www.unison-lang.org/docs/tour/">Unison language tour</a> and learned how to:</p>
<ul>
<li><p>Search for functions: by name, but also by type!</p>
</li>
<li><p>Create new functions and add them to my codebase.</p>
</li>
<li><p>Test my code by either running it or writing tests.</p>
</li>
</ul>
<p>Not impressed? Let's have a closer look!</p>
<h3 id="heading-search-by-type">Search by type</h3>
<p>Haskell users know the benefits of a tool like <a target="_blank" href="https://hoogle.haskell.org/">Hoogle</a>. With such a tool, you can search functions by type. This is soooooo convenient! "<em>How do I serialize</em> <code>Text</code> <em>to</em> <code>Bytes</code>?". <strong>Just type</strong> <code>find : Text -&gt; Bytes</code> and <code>ucm</code> returns all the functions with that signature:</p>
<pre><code class="lang-plaintext">  1. lib.base.Text.toUtf8 : Text -&gt; Bytes
  2. lib.base.IO.net.URI.Path.encode.segment : Text -&gt; Bytes
</code></pre>
<p>This even works when there are type parameters (Hoogle is better though because it will also show you functions where the order of parameters is slightly different).</p>
<h3 id="heading-add-a-function-to-the-project">Add a function to the project</h3>
<p>Once a function typechecks, you can <code>add</code> it to your project, or <code>update</code> it, if was added before. This has profound implications:</p>
<ul>
<li><p><strong>All the code added to your project <em>always</em> compiles</strong>. If an updated definition conflicts with the previous version, then all the conflicting code is brought up to be fixed.</p>
</li>
<li><p>Adding a function to your project <strong>is also the equivalent of committing it</strong>. No more <code>git add .; git commit -m "add some code"</code>. Later on, sharing the code with others is just a matter of running <code>push</code>.</p>
</li>
<li><p><strong>Codebase changes can be reversed</strong> by using the <code>reflog</code>, as you would do with git.</p>
</li>
<li><p>The project knows about functions, not just text. This means that:</p>
<ul>
<li><p>You can easily <strong>rename a function</strong>.</p>
</li>
<li><p><strong>You can give several aliases to the same function</strong>. Internally, a function is identified by the hash of its contents.</p>
</li>
<li><p>You can create patches that are selectively applied to part of the code, <strong>so that the result still typechecks</strong> (I haven't played too much with that though).</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-run-and-test-my-code">Run and test my code</h3>
<p>Veteran LISP programmers know the value of having a <a target="_blank" href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> at their fingertips. With Unison, it is as simple as writing a "watch expression", with <code>&gt;</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714738595370/5be79f94-d6c2-44bf-b4be-098f4b6c42ba.png" alt class="image--center mx-auto" /></p>
<p>That expression is automatically evaluated in <code>ucm</code> so you get immediate feedback on your code. Writing a test is no different, except that you give it a name, and use the <code>test</code> library functions:</p>
<pre><code class="lang-haskell"><span class="hljs-title">test</span>&gt; hi.test = verify <span class="hljs-keyword">do</span>
  ensureEqual (hi <span class="hljs-string">"Eric"</span>) <span class="hljs-string">"Hi, Eric!"</span>
</code></pre>
<p>This test is just another term that can be added to the code base to grow the test suite. If it passes of course! Two things to note:</p>
<ul>
<li><p>When you change code in your editor, all the tests are re-executed. If those tests don't depend on some changed code, t<strong>heir result is cached, they are not re-executed</strong>!</p>
</li>
<li><p>This also means that you can break previously added tests, which are present in your editor anymore, when updating a function. In that case, you can call <code>test</code> in <code>ucm</code> to re-run all the tests.</p>
</li>
</ul>
<h2 id="heading-some-feedback-from-my-first-steps">Some feedback from my first steps</h2>
<p>I don't want to give the impression that everything is perfect. The language tour and first experience could be improved:</p>
<ul>
<li><p>In <code>ucm,</code> typing <code>fn + ←</code> does not go to the beginning of the line as it does in my <code>zsh</code> terminal.</p>
</li>
<li><p>Hovering over a term shows its definition. It would be great to also be able to:</p>
<ul>
<li><p>Show the doc.</p>
</li>
<li><p>Show the code.</p>
</li>
<li><p>Open the term in the editor to modify it.</p>
</li>
</ul>
</li>
<li><p>This would reduce the amount of back and forth switching between the editor and <code>ucm</code>.</p>
</li>
<li><p>Selecting a term to edit it is a bit crude. The term to edit is added at the top of the current file and the rest of the file is commented out. In many cases, I want my existing code to stay in scope.</p>
</li>
<li><p>Some crucial aspects of the platform are still being polished! While I was going on the language tour, the Unison team realized that the functions used to do property-based testing were not so great and <a target="_blank" href="https://share.unison-lang.org/@unison/base/releases/3.0.0">revamped the whole thing</a>. This means that some of the documentation or blog post you read about Unison might not always reflect the latest and greatest.</p>
</li>
<li><p>Similarly, the concept of namespacing for terms (the <code>name1.name2.term</code> notation) is a bit in flux. There are still <a target="_blank" href="https://github.com/unisonweb/unison/issues?q=is%3Aissue+is%3Aopen+cd+">a number of issues</a> regarding the interactions of <code>ucm</code> commands for navigating/updating the code: <code>cd</code>, <code>up</code>, <code>ls</code>, <code>move</code>,... and the qualifiers that need to be written or not in the edited code.</p>
</li>
<li><p>The VS Code integration with <code>ucm</code> could be improved. Some specific windows would be nice to display:</p>
<ul>
<li><p>All the compilation errors (and being able to jump to one of them)</p>
</li>
<li><p>All the tests (in the current file, in the whole project)</p>
</li>
<li><p>All the watch expressions (in the current file, in the whole project)</p>
</li>
</ul>
</li>
<li><p>I think I had a few bugs with the editor:</p>
<ul>
<li><p>Sometimes <code>ucm</code> is happy with a function, yet the editor shows an error message.</p>
</li>
<li><p>If you define a <code>==</code> function, with its documentation, add it, and try to edit the documentation again, then the editor shows an "offset" error for <code>(Name.==.doc)</code>.</p>
</li>
</ul>
</li>
<li><p>Since we pay less attention to files, it's easy to delete terms that were not yet added, i.e. losing that code! In that case having an editor with a good <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=xyz.local-history">local history is important</a>.</p>
</li>
</ul>
<h1 id="heading-my-first-library">My first library</h1>
<p>I want to use Unison to develop a cloud application but I think that it is important to get comfortable first with a new programming language and the full lifecycle of: coding, testing, releasing. So I decided to implement a library that did not exist yet: <a target="_blank" href="https://share.unison-lang.org/@etorreborre/multimap">@etorreborre/multimap</a>.</p>
<p>This library provides a data type, a <code>MultiMap</code>. This is simply a wrapper for a <code>Map k vs</code> where <code>vs</code> is a list of values. <code>MultiMap</code>s can be useful in a variety of contexts. For example, in Unison we could have a <code>MultiMap</code> tracking all the existing names for a given term hash.</p>
<p>That led me to appreciate a few more cool things about Unison.</p>
<h3 id="heading-documentation-is-first-class">Documentation is first class</h3>
<p>Yes, in Unison, the documentation for a term is itself a term. It has a name, a namespace, can be added and edited. It can also be executed! This means that you can put both Markdown text in a block of documentation and some valid Unison code:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714810807780/4a0aaa19-7134-4de4-bd0b-bf2d3c2f14b0.png" alt class="image--center mx-auto" /></p>
<p>Then, the <code>docs</code> command executes and displays the result on the right. And eventually that documentation is published as some beautiful HTML:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714811172470/e31df60b-13a0-43ae-ab54-6c8062d389b2.png" alt class="image--center mx-auto" /></p>
<p>Why is this important? This matters a lot because now we have a much greater incentive to write great docs:</p>
<ul>
<li><p>They always typecheck.</p>
</li>
<li><p>They are refactored like the rest of the code when a name is updated.</p>
</li>
<li><p>Links to other terms are always working.</p>
</li>
<li><p>You can provide great examples inline.</p>
</li>
</ul>
<h2 id="heading-less-attention-to-files-more-focus">Less attention to files = more focus</h2>
<p>When writing Unison code we don't jump from file to file. We keep editing code in the same window. This means that it's perfectly ok to clear everything and just focus on one or two functions at the time, with the corresponding tests. This is strangely liberating.</p>
<h2 id="heading-less-attention-to-files-more-normalization">Less attention to files = more normalization</h2>
<p>Many people came to the idea that a good syntax formatter was the best way to put formatting discussions to rest. For example, <code>Go</code> came up with a default formatter from the start, and in Haskell, a "no-configuration" formatter like <a target="_blank" href="https://github.com/tweag/ormolu">ormolu</a>, won the hearts of many teams.</p>
<p>Unison goes one step further since no text is really stored, only an <a target="_blank" href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a>. This means that you don't really care if you prefix all your functions with their namespace, or add a bunch of <code>use</code> clause at the beginning of the file. Eventually the code will be stored and rendered in the same way. For example:</p>
<pre><code class="lang-haskell"><span class="hljs-title">use</span> <span class="hljs-type">MultiMap</span> empty size isEmpty
<span class="hljs-title">test</span>&gt; <span class="hljs-type">MultiMap</span>.tests.ex1 = verify <span class="hljs-keyword">do</span>
    size empty === <span class="hljs-number">0</span>
    isEmpty empty === true
</code></pre>
<p>is reformatted as:</p>
<pre><code class="lang-haskell"><span class="hljs-type">MultiMap</span>.tests.ex1 : [<span class="hljs-type">Result</span>]
<span class="hljs-type">MultiMap</span>.tests.ex1 = test.verify <span class="hljs-keyword">do</span>
  use <span class="hljs-type">MultiMap</span> empty
  <span class="hljs-type">MultiMap</span>.size empty === <span class="hljs-number">0</span>
  <span class="hljs-type">MultiMap</span>.isEmpty empty === true
</code></pre>
<h2 id="heading-todo">Todo</h2>
<p>This is a small but useful thing when you use types to design your code. For example, you know that you will need a function with a given type but you don't want to lose focus by implementing it right away. Just leave <code>todo</code> as its implementation. This is always a valid term!</p>
<h2 id="heading-testing">Testing</h2>
<p>Testing is great! Unison comes with an effect system, called <a target="_blank" href="https://www.unison-lang.org/docs/fundamentals/abilities/">abilities</a>, where a piece of code can interact with a handler to decide how the computation should be executed. This possibly sound nebulous, but you probably have already used something like this if you have:</p>
<ul>
<li><p>Thrown exceptions. Then, a handler knows what to do with the exception. "Resumable exceptions" are even better since the handler can provide a value to continue the computation.</p>
</li>
<li><p>Used <code>async</code> in Rust. The handler is an executor that puts the current code on hold, then resumes it when a thread is available.</p>
</li>
<li><p>Used a generator in Python with <code>yield</code>. In that case, the handler uses the yielded value then resumes the code, to get the next value.</p>
</li>
</ul>
<p>The abilities used for testing in Unison are:</p>
<ul>
<li><p><code>Random</code> to provide randomly generated values.</p>
</li>
<li><p><code>Each</code> to repeat a piece of code, possibly with a different value, taken from a list of values.</p>
</li>
<li><p><code>Exception</code> to abort the test in case of a failure.</p>
</li>
</ul>
<p>This means that you have a very convenient way to mix <a target="_blank" href="https://github.com/rudymatela/leancheck#readme"><em>enumeration testing</em></a>, where data is tested exhaustively, and <a target="_blank" href="https://en.wikipedia.org/wiki/Random_testing"><em>random testing</em></a>, where you let randomness explore the test data. You can read some examples on Paul Chiusano's <a target="_blank" href="https://pchiusano.blog/posts/mixing-random-and-exhaustive-testing">blog post on the subject</a>.</p>
<h2 id="heading-publishing-the-library">Publishing the library</h2>
<p>Publishing a library is very easy:</p>
<ul>
<li><p>Provide a README, in the form of a documentation term called,... <code>README</code>.</p>
</li>
<li><p>Use <a target="_blank" href="https://share.unison-lang.org/@unison/base/code/releases/3.2.0/latest/types/@7k7de5eej4eflq5h09kr5jno5dmdkepdhpd25r71nbh9a0cdpiisltoj8en3pe47ifgscuuvd19n9o1vluifeorj7gosn7b33m3vp5g">the <code>License</code> datatype</a> to provide a license for your project (and <a target="_blank" href="https://share.unison-lang.org/@unison/base/code/releases/3.2.0/latest/terms/@t1oajjddc10la9dlhlrp95m3th4ag3oj9tktdl4vokd1f9ljcq1969p37goqmlont7l2bjqdjusd0qqn85kc6oqpi4oakbn5q0kf29o"><code>mit</code> as a <code>LicenseType</code></a> for example).</p>
</li>
<li><p><code>push</code> and press the <code>Cut a new release</code> button <a target="_blank" href="https://share.unison-lang.org/@etorreborre/multimap/releases">on the project page</a>.</p>
</li>
</ul>
<h2 id="heading-some-question-marks">Some question marks</h2>
<p>The <code>MultiMap</code> library is not so small. It contains more than 200 terms and 2000 lines of code (counting the documentation. It's code, right 😊?).</p>
<p>With this library I could get a taste of what it meant to work with larger projects in Unison and ask myself a few questions.</p>
<h3 id="heading-namespaces">Namespaces</h3>
<p>Namespaces are mostly irrelevant for a library like <code>MultiMap</code> since everything is at the same level. But where do you put tests? Possibly, we want to separate the testing code from the "production" code. I opted for the <code>MultiMap.tests</code> namespace (Unison's base library does things a bit differently). This has the advantage of offering a clear separation, and if you want to have a look at all the tests you can <code>edit.namespace MultiMap.tests</code>.</p>
<p>There is also a bit of "convention over configuration". The <code>lib</code> namespace in a given project is treated specially. It contains all the project dependencies, including <a target="_blank" href="https://share.unison-lang.org/@unison/base">Unison's base library</a>. If you want to upgrade that library or add another library as a dependency you need to <code>pull</code> it, inside the <code>lib</code> namespace:</p>
<pre><code class="lang-haskell"><span class="hljs-title">pull</span> @unison/json-core/releases/<span class="hljs-number">1.0</span><span class="hljs-number">.3</span> lib.jsonCore_1_0_3
</code></pre>
<p>As you can see, there are no real constraints for going from <code>json-core/releases/1.0.3</code> to <code>lib.jsonCore_1_0_3</code>. I think I would have preferred a <code>pull dependency @unison/json-core/releases/1.0.3</code> command doing the right thing for me.</p>
<p>I also made the mistake of pulling the <em>full</em> Unison base library directly into my top-level namespace 😰. Then I <em>really</em> had to learn how to remove terms and namespaces 😁.</p>
<h3 id="heading-privacy">Privacy</h3>
<p>Closely related to namespaces is privacy. There's no notion of public/private in Unison and no notion of modules. Only namespaces. In <code>MultiMap</code> there are only 2 functions that are implementation functions. I decided to "hide" them in <a target="_blank" href="https://share.unison-lang.org/@etorreborre/multimap/code/releases/0.0.1/latest/namespaces/MultiMap/private">a <code>private</code> namespace</a>.</p>
<p>I think that having the ability to truly forbid some terms to be seen outside of their packages would help when scaling Unison programs to large programs.</p>
<h3 id="heading-no-typeclasses">No typeclasses</h3>
<p>I like to call <a target="_blank" href="https://typelevel.org/cats/typeclasses.html">typeclasses</a> "interfaces for data types", and as such, I think they play an important role for modularity. They also come with all sort of questions:</p>
<ul>
<li><p>How do you pass typeclass instances where needed?</p>
</li>
<li><p>How do create/resolve typeclass instances?</p>
</li>
</ul>
<p>Unison does <em>not</em> have typeclasses, and I can understand why. While they are incredibly convenient, they also make a programming language <a target="_blank" href="https://github.com/fsharp/fslang-suggestions/issues/243#issuecomment-916079347">a lot more complex</a>. OCaml, or Elm, for example, are two functional programming languages with no support for typeclasses.</p>
<p>As a matter of convenience, Unison has universal equality and universal ordering, which are both <em>structural</em>. What does that mean?</p>
<p>This means that when you define any data type, for example <code>Person</code>, equality and ordering are based on what is <em>inside</em> the data type:</p>
<pre><code class="lang-haskell"><span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-type">Person</span> = {
  <span class="hljs-title">name</span>: <span class="hljs-type">Text</span>,
  <span class="hljs-title">age</span>: <span class="hljs-type">Nat</span>,
}</span>
</code></pre>
<p>The <code>Universal.eq</code> and the <code>Universal.gt</code> functions compare 2 <code>Persons</code> first based on their <code>name</code>, <em>then</em> on their <code>age</code>. This even works with functions! Two functions are equal if the hash of their content is equal.</p>
<p>Structural equality is not controversial, but structural ordering is more questionable:</p>
<ul>
<li><p>We might want to define different orderings for the same data type.</p>
</li>
<li><p>I'd rather avoid breaking code if I simply swap two fields in my data type.</p>
</li>
</ul>
<p>As a result, some Unison APIs use a comparison function parameter to specify exactly how elements must be compared. But this is not the case for some data types like <code>Map</code> or <code>Set</code>.</p>
<h3 id="heading-large-refactorings">Large refactorings</h3>
<p>While developing the <code>MultiMap</code> library, I inadvertently set myself up for a large refactoring. I initially started with <code>MultiMap = Map k [v]</code> and later, much later, realized that a more correct definition was <code>MultiMap = Map k (List.Nonempty v)</code>.</p>
<p>Changing the datatype, and trying to <code>add</code> the new definition, triggered the typechecker, which was very unhappy with this change. <code>ucm</code> brought most of the definitions into scope and told me to fix them. This has been unfortunately a bit painful experience:</p>
<ul>
<li><p>Only some errors are displayed at the time. Fixing one issue triggers another issue in a different place and you don't really know when the whole process is going to stop.</p>
</li>
<li><p>Some names were replaced with their hash.</p>
</li>
<li><p>After fixing all issues in sight, I entered <code>update</code> but <code>ucm</code> told me that some code was still not compiling, commented out all the previous code, only to put another wall of text in front of me. Was it some new code, a bit of the old code that was still not compiling, some additional tests? Eventually, I had the <em>impression</em> of writing some fixes twice.</p>
</li>
</ul>
<p>That made me wonder if more tooling was needed for large codebases, in order to support deep refactorings.</p>
<h1 id="heading-my-first-contributions">My first contributions</h1>
<p>During the development of the <code>MultiMap</code> library, <a target="_blank" href="https://share.unison-lang.org/@etorreborre/p/contributions">I added a few functions that were missing from the <code>List</code> and <code>List.Nonempty</code> data types</a>. The whole process was really simple:</p>
<ul>
<li><p>Create a branch in @unison/base: <code>branche.create /mybranch</code>.</p>
</li>
<li><p>Add some new functions + doc + tests.</p>
</li>
<li><p><code>push</code>.</p>
</li>
<li><p><a target="_blank" href="https://share.unison-lang.org/@unison/base/contributions">Open a contribution</a> in the corresponding project (much like a pull request in Github).</p>
</li>
</ul>
<p>All of this, except the last step, is done in <code>ucm</code> and I can foresee a future where even the last step is supported in <code>ucm</code> so that you don't even have to leave your development environment to collaborate on projects.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Despite some of the shortcomings mentioned above, I can't wait to develop my first cloud application. This is going to be an application for importing bank data into my accounting software. My prediction is that most of the difficulty will come from the core of the application:</p>
<ul>
<li><p>Dealing with authentication on both systems.</p>
</li>
<li><p>Navigating both data models.</p>
</li>
<li><p>Determining what is "new" data and what is already imported data.</p>
</li>
</ul>
<p>I hope that, on the contrary, thanks to <a target="_blank" href="https://www.unison.cloud">Unison Cloud</a>, the technical aspects will be a breeze:</p>
<ul>
<li><p>Deploying the application.</p>
</li>
<li><p>Monitoring it.</p>
</li>
<li><p>Using secrets.</p>
</li>
<li><p>Interacting with HTTP APIs.</p>
</li>
<li><p>Maybe storing a bit of data.</p>
</li>
</ul>
<p>Stay tuned for part 2, and don't hesitate to give Unison a go, it is really a refreshing experience!</p>
]]></content:encoded></item><item><title><![CDATA[We have no free will, and this is not a big deal]]></title><description><![CDATA[I was introduced to the wonderful neuroscientist and primatologist, Robert Sapolsky, more than 10 years ago, via a colleague. He told me: "you should watch his lectures on the human behavioral biology at Stanford". Wow, mind blown. Highly recommended...]]></description><link>https://etorreborre.blog/we-have-no-free-will-and-this-is-not-a-big-deal</link><guid isPermaLink="true">https://etorreborre.blog/we-have-no-free-will-and-this-is-not-a-big-deal</guid><category><![CDATA[Science ]]></category><category><![CDATA[biology]]></category><category><![CDATA[Philosophy]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Mon, 01 Jan 2024 22:51:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1704111326019/3698dc98-601b-4ed6-bc22-ed4d531f6e2f.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was introduced to the wonderful neuroscientist and primatologist, Robert Sapolsky, more than 10 years ago, via a colleague. He told me: "you should watch <a target="_blank" href="https://www.youtube.com/watch?v=NNnIGh9g6fA&amp;list=PL848F2368C90DDC3D">his lectures on the human behavioral biology at Stanford</a>". Wow, mind blown. Highly recommended. Not only for the wealth of information presented but also for the way he approaches scientific reasoning. What are the proper questions, what are the insightful experiments that allow us to reach valid conclusions about human behavior? You can get a glimpse of his thinking by reading <a target="_blank" href="https://www.amazon.com/Trouble-Testosterone-Essays-Biology-Predicament/dp/0684838915">what are the effects of testosterone on the human body</a>. Spoiler alert: they are far more intricate than "it raises aggressiveness".</p>
<p>After watching the videos, I read "<a target="_blank" href="https://www.amazon.com/Why-Zebras-Dont-Ulcers-Third/dp/0805073698">Why zebras don't get ulcers</a>". That book made me think twice about the devastating effects of stress on the human body. I followed with "<a target="_blank" href="https://www.amazon.com/Behave-Robert-M-Sapolsky-audiobook/dp/B06XVYHXDV">Behave: the biology of humans at our best and worst</a>", which explores the biology of how nice or terrible we can be to each other. That book quite convincingly makes the case that our sense of ethics, and our actual actions, are determined by what happens in our body, from one second before, to one day before, to years ago (and even millennia if you account for evolution).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704134243384/0aba70b0-dc3e-41b7-80ef-976db3c646d8.png" alt class="image--center mx-auto" /></p>
<p>Robert Sapolsky's new book, "<a target="_blank" href="https://www.amazon.com/Determined-Science-Life-without-Free/dp/B0BVNSX4CQ">Determined, a science of life without free will</a>", follows the same thread to reach some troubling conclusions:</p>
<ul>
<li><p>There is no free will.</p>
</li>
<li><p>Yes, really, wherever you're looking for it, you can't find it.</p>
</li>
<li><p>This changes how we see the world in terms of responsibility, punishment, merit.</p>
</li>
</ul>
<h1 id="heading-the-revolting-biology-of-our-actions">The revolting biology of our actions</h1>
<p>The book is divided in two parts. The first part goes into the biology of our behavior and shows that there's no place to shoehorn free will. The second part tries to draw some social conclusions.</p>
<p>Robert Sapolsky was reluctant to write this book. Although he became convinced at an early age, just 14 years old, that free will does not exist, Robert Sapolsky is well aware that he represents a minority position. Most people, including scientists and philosophers are "compatibilists". They acknowledge that we are determined by all sort of influences, yet we still have have free will. We must have. Otherwise the world makes no sense. Don't even suggest it, this is revolting!</p>
<p>With this book, Robert Sapolsky proposes to avoid jumping to a conclusion that we would like to prove. He just asks: "ok, where is free will because I can't find it? The more I search, the more I see things over which we have no control".</p>
<h2 id="heading-who-is-really-pressing-our-buttons">Who is really pressing our buttons?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704141447353/2ca0927e-3848-4e20-85e8-d690a34e2654.png" alt /></p>
<p>Prof. Sapolsky starts with presenting the neuroscience behind our decisions. <a target="_blank" href="https://en.wikipedia.org/wiki/Neuroscience_of_free_will">A wildly debated series of experiments</a>, initiated by Libet more that 40 years ago, shows that actions are in motion in our brains well before we are conscious that we want to take those actions. Consciousness is an afterthought, after biology has triggered the right neurons.</p>
<p>Even our judgements are an afterthought. Put some people in a room with a fetid odor and ask people to judge if some behavior is moral or not. The experiment shows that subjects tend to be more conservative. Why? Because the neurons processing for physical disgust (in order to avoid food poisoning) are the same as the neurons processing for moral disgust! It even goes both ways. When people make bad actions, they want to clean-up!</p>
<p>What is fascinating is that we are not aware of those influences. Ask the subjects being tested and they will post-rationalize why they became more conservative.</p>
<p>This is however not enough to put the last nail in the coffin of free will. Let's consider another example. Our amygdala quickly triggers fear in us when we see faces of a different skin color. This works in under one tenth of a second and we don't have control over this. Fortunately, our pre-frontal cortex (PFC) comes-in next to reason about it: "it's ok, there's no reason to scared" (unless you are unabashedly racist 🙁).</p>
<p>The compatibilist rejoices: "Ha, you see, <em>I can decide</em> to not succumb to fear!". Well, not really. The amount of stress you have today, and over which you have no control, will make it hard to calm down your amygdala. Some genetic deficiency, or head concussion will also make it hard for the PFC to play its role. All of these causes have been thoroughly studied now, and there's little you can do about it. This shows for example when you have to decide if someone putting their hand under their jacket is going to draw a gun or their phone.</p>
<p>What exactly decides what happens in the PFC when it takes a decision? Sapolsky goes back in time to show that any activation now, is the result of:</p>
<ul>
<li><p>What happened a second before: are you under a sudden stress?</p>
</li>
<li><p>To hours before: are you hungry? Hungrier judges give harsher sentences.</p>
</li>
<li><p>To days before: do you have a lot more estrogens in your blood? Hormones have tremendous influence: give vasopresin to a polygamous mole and it becomes monogamous! Give oxytocin to people and they become more cooperative,... but only with US, not THEM!</p>
</li>
<li><p>To years before:</p>
<ul>
<li><p>Were you mobilized and came back with <a target="_blank" href="https://www.mayoclinic.org/diseases-conditions/post-traumatic-stress-disorder/symptoms-causes/syc-20355967">PTSD</a>?</p>
</li>
<li><p>Did you have traumas in your childhood? The "<a target="_blank" href="https://www.cdc.gov/violenceprevention/aces/index.html">Adverse Childhood Experiences</a>" score is a good predictor of future difficult behaviors.</p>
</li>
<li><p>How was your mother when you were in her womb? Economically stressed, depressed? We can see the impacts on your brain.</p>
</li>
<li><p>Did you grow up in a nice or in a terrible weather? Yes, it has a noticeable impact too.</p>
</li>
<li><p>Which genes did you inherit from your parents? How were they expressed or not?</p>
</li>
</ul>
</li>
<li><p>To centuries before: do you originate from a collectivist or an individualist culture?</p>
</li>
</ul>
<p>The more we look for biological explanations, the more we find them. They stack up, we find the causes that cause the causes. It's "<a target="_blank" href="https://en.wikipedia.org/wiki/Turtles_all_the_way_down">turtles all the way down</a>".</p>
<h1 id="heading-surely-there-must-be-some-space-for-free-will">Surely there must be some space for free will</h1>
<p>Free will advocates still want to prove that, beside all the biological explanations for our thoughts and actions, free will <em>has to exist</em>. Some common arguments are:</p>
<ol>
<li><p>We cannot predict everything, so there is something that allows us to make decisions, <em>our</em> decisions.</p>
</li>
<li><p>Physics is fundamentally quantic and this radical indeterminacy is the root for our free will.</p>
</li>
<li><p>Beyond basic biology, there is some high-level conscience / intelligence that cannot be explained via low-level mechanisms.</p>
</li>
</ol>
<p>What is Sapolsky's answer to those arguments?</p>
<h2 id="heading-determinism-vs-predictability">Determinism vs predictability</h2>
<p>The fact that we cannot predict the evolution of a system does not mean that it is not deterministic. The <a target="_blank" href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Game of Life</a> is a system with very few rules, which can be simulated on a computer:</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/e/e5/Gospers_glider_gun.gif" alt="A single Gosper's glider gun creating gliders" /></p>
<p>It is however <a target="_blank" href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Undecidability">undecidable</a>. There is no algorithm allowing us to say if a given pattern is going to appear once you start the game. The only way to know, is to run the game, possibly for an infinite amount of time. Very deterministic rules, unknown outcome.</p>
<p>Another example comes from <a target="_blank" href="https://en.wikipedia.org/wiki/Chaos_theory#history">Chaos Theory</a>. Take the equations for gravitation, apply them to 2 bodies (2 planets, 2 stars, etc...) and you will be able to predict their movement. Try to do the same with 3 bodies and all of a sudden the trajectories starts having fluctuations that are non-periodic and very dependent on the initial state of the system.</p>
<p>Not only it is hard to predict the future of some purely deterministic systems, but it can also be difficult to recover their past! A given position in the Game of Life can result from two completely different initial states. <a target="_blank" href="https://conwaylife.com/wiki/Garden_of_Eden">Some positions don't have any antecedents</a> (also an undecidable property).</p>
<p>Clearly, determinism does not mean predictability.</p>
<h2 id="heading-quantum-entanglement">Quantum entanglement</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704141620701/ea23adc1-d32a-4b1a-af62-abc3aab2024b.png" alt /></p>
<p>It is quite fascinating to see how science can be the perfect medium for pseudo-science. The discovery of electricity and magnetism generated all sorts of demonstrations that "magnetic waves", "energy flows", could heal you (provided that you shell a significant amount of your hard-earned cash of course). Similarly the development of quantum mechanics brought us <a target="_blank" href="https://www.integrativenutrition.com/blog/what-is-quantum-healing">quantum healing</a> and <a target="_blank" href="https://kilmanndiagnostics.com/books/quantum-organizations/">quantum organizations</a> (I just googled the terms, and, of course, got some results 😁).</p>
<p>Quantum physics is truly hard to grasp (in the words of Richard Feynman, "If you think you understand quantum mechanics, you don't understand quantum mechanics"). Maybe this is where we can break the diktat of "we are determined". Indeed, the theory presents some radical indeterminacy, some truly random variations. Could this be at the root of free will? This is very unlikely:</p>
<ul>
<li><p>Quantum physics happens at minuscule scales and <a target="_blank" href="https://en.wikipedia.org/wiki/Wave_function_collapse">collapses</a> at larger scales like the wet and warm environment that is the brain.</p>
</li>
<li><p>So far, no convincing mechanism has been shown, where the quantic states of particles would eventually, all together, have an influence on a motor neuron.</p>
</li>
<li><p>Same thing the other way around. We have not shown how our conscious thoughts could have an effect at the quantum level (and this would leave some kind of chicken and egg problem, on how this then generates an action).</p>
</li>
<li><p>Even if there was a quantum mechanism at the heart of free will, what does that say about it? That free will is fundamentally the result of a random process?</p>
</li>
</ul>
<h2 id="heading-intelligent-design">Intelligent design</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704141746859/2b60d7fc-2929-49d3-9aa1-9651c927b87b.png" alt /></p>
<p>Maybe we are being too reductionist? Maybe free will is more than just the sum of our hormones? Maybe it is something that emanates at a higher-level?</p>
<p>Indeed, Nature showcases many complex behaviors that are <em>emergent</em>:</p>
<ul>
<li><p>A few ants don't do much. An ant colony builds cathedrals.</p>
</li>
<li><p>Bees communicate to find where the best flower fields are.</p>
</li>
<li><p>Slime mold, a uni-cellular organism, <a target="_blank" href="https://www.mbl.edu/news/how-can-slime-mold-solve-maze-physiology-course-finding-out">solves a maze</a>.</p>
</li>
<li><p>Our blood system branches like fractals to cover our whole body.</p>
</li>
</ul>
<p>Amazing, but in each case, the overall behavior is still explained, and caused, by simple behaviors. In the case of the blood system for example, there is no central architect gene/hormone/brain region creating the full topology. Instead, one gene codes for the branching factor: when to branch vessels and when to stop. Not only that, but the same gene supports the notion of branching for other parts of our body, like neuron dendrites.</p>
<p>What is causing high-level, sophisticated, behaviors is eventually just a potent mixture of simple parts. There is no need to invoke another organizing principle.</p>
<h1 id="heading-where-to-go-from-there">Where to go from there?</h1>
<p>Robert Sapolsky is profoundly convinced that we are nothing more than the sum of our biology, which we can't control. This is also totally obvious to me, I see it as <a target="_blank" href="https://www.newscientist.com/definition/occams-razor">Occam's razor</a> in action. No need to invoke "free will", a "soul", some transcendent "self", to explain our behaviors. While this would answer one question, it would raise a lot more: where does it come from? How is it built? How long does it last? etc...</p>
<p>Yet, we are so used to the impression that <em>we</em> decide, that <em>we</em> act, that <em>we</em> take responsibility. Isn't that what we learn from the youngest age? Absolutely. The pre-frontal cortex is the last part of the brain to mature, around the age of 25, because we have to be taught: "<strong>what's the hard thing to do, when it is the right thing to do</strong>" (see what I did? Still biology at work).</p>
<p>Now, if we start telling people that there is no free will:</p>
<ol>
<li><p>Are they going to run amok?</p>
</li>
<li><p>Are we even capable of changing?</p>
</li>
<li><p>Does it still make sense to <em>punish</em> people?</p>
</li>
<li><p>Does it still make sense to <em>reward</em> people?</p>
</li>
</ol>
<h2 id="heading-no-free-will-headless-chickens">No free will = headless chickens?</h2>
<p><img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSUQGEIV14nK8SzISaujRmxfNJTqr2I48ZlLg&amp;usqp=CAU" alt="Running around like a headless chicken? Marketing trends in 2020!" /></p>
<p>This is a valid concern. It is also a concern frequently expressed by religious people when discussing with atheists: "If you don't have anything <em>objective</em> on which to base your ethics, what prevents you from going mad?".</p>
<p>Experimentally, the answer to that question has several layers. Religious people are more prosocial and give more to charity that secular people. But when you control for all factors: age, sex, wealth, then the results are less drastic. Even less so when you inquire about what people <em>say</em> they do and what they <em>really</em> do. You might eventually still find a little more prosociality in the religious group. With a catch, though. It is mostly for the in-group. It is mostly for the US, not THEM. Religious people are more charitable but mostly towards their co-religionists. Ultimately, it cannot be proven that atheists have lower ethical standards than religious individuals.</p>
<p>Similar kind of experiments can be performed with free will believers and non-free will believers. Subjects being told about the absence of free will are more likely to cheat in economic games. Yet, if you test people who have held this position for a long time, they are no less ethical than believers. Even better, the more they think that free will does not exist, that there's no wiggle room for it, the stronger their values will be.</p>
<p>Ultimately, it has been observed that, whatever your credo is, religious/atheist, free will believer/non-believer, what matters most is <strong>the time you have spent deeply thinking about it</strong>.</p>
<h2 id="heading-how-many-free-wills-does-it-take-to-change-oneself">How many free wills does it take to change oneself?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704142459812/d4d26c2c-3883-465c-809e-114e26aa3dac.png" alt /></p>
<p>Seeing the world as fully determined can be a bit terrifying. We can easily think that given the cards we are dealt, we will never change. This is far from being the case. In the book, <a target="_blank" href="https://en.wikipedia.org/wiki/Robert_Sapolsky#/media/File:Robert_Sapolsky_in_2023_A_16.jpg">our bearded friend</a>, explains in detail, at the neuronal level, how a sea slug, <a target="_blank" href="https://en.wikipedia.org/wiki/Aplysia">Aplysia</a>, adapts to external aggressions. Progressively, a feedback loop, made of neurons, learns that it should protect the slug gills for longer period of times, until it is possible to come back to normal.</p>
<p>Mind you, we share the same mechanisms for learning and adapting that this sea slug. Even though it is a very, very, distant cousin, sharing a common ancestor with us more than 2 billion years ago!</p>
<p>Another example. Your mum is stressed while pregnant with you. As a result, she feeds you a lot more glucocorticoids than necessary and your amygdala (a part of the brain dealing with stress and fear) grows larger. As a kid, your resting levels of glucocorticoids are higher than average and you tend to be more reactive to stressors. Fortunately, you start a talking therapy at the end of your adolescence. <a target="_blank" href="https://www.nature.com/articles/tp2015218">Progressively, your amygdala gets less active</a>. It has been more regulated by other parts of your brain.</p>
<p>The conclusion is that, it is not so much that <em>we change</em>, but <em>we are changed</em>. We are changed by our environment, by our interactions, and by the innate biology which allows for changes to occur.</p>
<h2 id="heading-bad-boy-bad-girl">Bad boy / bad girl</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704143435274/8e992d28-9ca4-491a-9ea9-804faa4c9069.png" alt /></p>
<p>Sapolsky presents several examples where we previously believed people were truly bad or weak before understanding the underlying biology at work.:</p>
<ul>
<li><p>Witches being burned because they were having epileptic seizures, or because villagers thought they were causing diseases.</p>
</li>
<li><p>Schizophrenia, which was attributed to bad parenting and "<a target="_blank" href="https://en.wikipedia.org/wiki/Double_bind">double-bind</a>", before we discovered its genetics origins.</p>
</li>
<li><p>Similarly, autism, attributed to cold, distant mothers ("Refrigerator mothers").</p>
</li>
<li><p><a target="_blank" href="https://www.psychiatry.org/patients-families/ptsd/what-is-ptsd">PTSD</a>, for Gulf War soldiers, who were described as "weak", before it was understood that <a target="_blank" href="https://www.bu.edu/sph/news/articles/2016/toxic-exposures-caused-illness-in-gulf-war-veterans/">prophylactic pills triggered it</a>.</p>
</li>
</ul>
<p>When we read about these examples, in the 21 century, we tend to think: "Of course, they were not witches", "Of course, <a target="_blank" href="https://en.wikipedia.org/wiki/John_Forbes_Nash_Jr.">John Nash</a> was not psychotic because his mother was a monster, but probably because his circuitry for <a target="_blank" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4032934/">dopamine was not well-regulated</a>". Etc... Yet, if we take the example of schizophrenia, it took years of concerted efforts, from family members, to lobby doctors and politicians to change the perception around that disease, even as we started to understand its causes.</p>
<p>This begs the question: what are the behaviors that we consider today as emanating from fully-responsible persons and which will be considered as having fully biological causes in 100 years? (if you've read so far, you should know. All of them 😀).</p>
<p>Still, what should we do when someone does something <strong>wrong</strong>? If we follow Sapolsky's reasoning, are we going to blame the car because the brakes are faulty? The author proposes a model similar to a medical quarantine:</p>
<ol>
<li><p>People have diseases, they have bad behaviors.</p>
</li>
<li><p>It's not their fault.</p>
</li>
<li><p>It is ok to protect others by constraining the freedom of infectious or dangerous people.</p>
</li>
<li><p>We should constrain these persons with the absolute minimum necessary to protect others. Nothing more.</p>
</li>
</ol>
<p>Wait, shouldn't we at least use punishment as a deterrent? What do studies say? <a target="_blank" href="https://www.ojp.gov/pdffiles1/nij/247350.pdf">This does</a> <a target="_blank" href="https://daily.jstor.org/rethinking-prison-as-a-deterrent-to-future-crime/">not work</a>. Ok, but maybe, bad persons <em>deserve</em> to be punished?</p>
<p>The need for punishment as the just retribution for crummy behavior is well-tested experimentally. It brings some measurable level of satisfaction. But, here again, there are some subtleties. For example, capital punishment can be <em>more</em> traumatic for families of victims. Furthermore, we have collectively evolved significantly in terms of the severity we expect from punishment. (I will let you read the horrific description of what happened to the assassin of Louis XV in the book).</p>
<p>A notable example is the case of Norway and the methodic crimes of <a target="_blank" href="https://en.wikipedia.org/wiki/Anders_Behring_Breivik">Anders Breivik</a>. Breivik was eventually not recognized as schizophrenic (yet, unsurprisingly, "[his mother] 'sexualised' the young Breivik, hit him, and frequently told him that she wished that he were dead". Surely that didn't help).</p>
<p>More or less, Norway adopted the quarantine approach: they put away the criminal for 21 years (the maximum sentence), in humane detention conditions, and even provided the possibility to study. One survivor said: "If he is not deemed dangerous any more after 21 years then he should be released ... That's how it should work. That's staying true to our principles and the best evidence that he hasn't changed our society". That is impressive. Many other societies would have considered Breivik's execution as a moment to celebrate.</p>
<h2 id="heading-good-boy-good-girl">Good boy / good girl</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704143553974/68c44af2-4343-46d9-95a0-b22deeee7d40.png" alt /></p>
<p>Another consequence of not having free will, is that we cannot be utterly smug for our achievements.</p>
<p>If you've had the right genes, the right emotional support as a kid, parents playing board games with you, a variety of experiences, a healthy body, a well-formed PFC supporting your will to pursue your objectives, and now you have a nice corner office, good for you. But you don't really <em>deserve</em> it, no more than a kid growing up with lead in his tap water <em>deserves</em> to have a low IQ.</p>
<p>Sapolsky says that some of his students get destabilized when they hear they don't get to be entitled for their brilliant future:</p>
<p>- "Hey, I worked hard for it!"</p>
<p>- "Yes, if you are here, you are among the really lucky, lucky ones"</p>
<h1 id="heading-are-we-wiser-now">Are we wiser now?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704127661332/7b6e4393-784e-4a9c-a92a-24684de3c299.jpeg" alt /></p>
<p>I think we are. First off because, on the road to recognize that we don't have any free will, we haven't deviated from science. We didn't need to invoke any supreme or transcendental principle at the core of our existence.</p>
<p>Secondly, nothing is lost! I still have a very strong sense of myself, and the belief that the actions I take today have significant consequences for my future, the future of my family, and society. (well, <em>that</em>'s debatable 😅). In a sense, me, my body, is playing the <em>real</em> Game of Life (™):</p>
<ul>
<li><p>With rules that I haven't decided.</p>
</li>
<li><p>With handicaps and strengths that have been dealt for me.</p>
</li>
<li><p>With tangible gains and losses at each turn..</p>
</li>
<li><p>With an objective that is not clear.</p>
</li>
<li><p>With the privilege of playing the game and simultaneously observing it being played.</p>
</li>
<li><p>With the certitude that the game will end!</p>
</li>
</ul>
<p>I have also gained the knowledge that:</p>
<ul>
<li><p>I can be gentle with myself. It is not just a matter of willpower if I cannot remember every fact that would be useful at work.</p>
</li>
<li><p>People can behave badly around me, and against me, but I don't have to blame them. Protecting myself is enough. Preventing them to do more harm is enough.</p>
</li>
<li><p>Maybe what I can do, with the remaining illusion of free will that remains, is to put myself in the conditions to be better influenced in the future: get good sleep, eat well, exercise, manage stress, do as much good I can around me, etc...</p>
</li>
<li><p>I can also position myself in the conditions to be changed for the better: read books challenging my thoughts, meet new people, share my interests,...</p>
</li>
</ul>
<p>In more philosophical terms, Robert Sapolsky's book places us, not as actors, but as <em>acted</em>, in the meaningless and glorious story of the Universe. I am fairly certain that some Greek philosophers would have smiled in approval.</p>
<p><strong>N.B</strong>: the summary above is a crude approximation of this wonderful 500+ pages book. All mistakes are mine, I hope you will kindly correct them by reading the book for yourself.</p>
]]></content:encoded></item><item><title><![CDATA[Typed Tagless Final, for real!]]></title><description><![CDATA[Every so often, a software technique takes the center stage of attention and becomes the source of countless articles, tutorials, and conference talks.
This is particularly true in the world of functional programming with techniques such as:

"failur...]]></description><link>https://etorreborre.blog/typed-tagless-final-for-real</link><guid isPermaLink="true">https://etorreborre.blog/typed-tagless-final-for-real</guid><category><![CDATA[Haskell]]></category><category><![CDATA[Scala]]></category><category><![CDATA[Functional Programming]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Wed, 27 Dec 2023 01:03:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703636466334/9f6fab11-870d-47f6-8fac-1ce4296f30bd.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every so often, a software technique takes the center stage of attention and becomes the source of countless articles, tutorials, and conference talks.</p>
<p>This is particularly true in the world of functional programming with techniques such as:</p>
<ul>
<li><p><a target="_blank" href="https://www.innoq.com/en/blog/2015/03/validate-your-domain-in-scala/">"failure" datatypes: <code>Option</code>, <code>Either</code>, <code>Validation</code></a></p>
</li>
<li><p><a target="_blank" href="https://hackage.haskell.org/package/optics-0.4.2.1/docs/Optics.html">lenses / optics</a></p>
</li>
<li><p><a target="_blank" href="https://blog.sumtypeofway.com/posts/introduction-to-recursion-schemes.html">recursion schemes</a></p>
</li>
<li><p><a target="_blank" href="https://blog.rockthejvm.com/type-level-programming-scala-3/">generics / type-level programming</a></p>
</li>
<li><p>effect libraries: <a target="_blank" href="https://hackage.haskell.org/package/effectful"><code>effectful</code></a>, <a target="_blank" href="https://typelevel.org/cats-effect/">cats-effect <code>IO</code></a>, <a target="_blank" href="https://zio.dev"><code>ZIO</code></a>,...</p>
</li>
<li><p><a target="_blank" href="https://www.baeldung.com/scala/tagless-final-pattern">the "typed tagless final" approach</a></p>
</li>
</ul>
<p>Today I want to give a proper, real-life, example of using the so-called "Typed tagless final" approach. Over the years I have become quite frustrated with how this topic was presented. In the eyes of many people this is mostly a way to create interfaces where the result of each operation has an effect abstracted as a type variable:</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">CustomerRepository</span>[<span class="hljs-type">F</span> : <span class="hljs-type">Monad</span>] </span>{
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">saveCustomer</span></span>(c: <span class="hljs-type">Customer</span>): <span class="hljs-type">F</span>[()]
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getCustomers</span></span>(): <span class="hljs-type">F</span>[<span class="hljs-type">List</span>[<span class="hljs-type">Customer</span>]]
}
</code></pre>
<p>In practice <code>F</code> ends up being a type permitting side-effects like <code>IO</code>. <code>F</code> might also end up being <code>State[RepositoryState, _]</code> in order to write tests purely in memory for example.</p>
<p>I generally argue that:</p>
<ol>
<li><p>This is merely using interfaces, parametrized with an effect.</p>
</li>
<li><p>In that case, this does not deserve a complicated and scary named such as "typed tagless final".</p>
</li>
<li><p>The "typed tagless final" approach is much more interesting and covers a different topic than building a system based on modules and interfaces.</p>
</li>
</ol>
<h1 id="heading-what-is-it-really">What is it really?</h1>
<p>You will find the best reference on the topic on <a target="_blank" href="https://okmij.org/ftp/tagless-final/">Oleg Kiselyov's website</a>:</p>
<ol>
<li><p>This is a way to create internal Domain Specific Languages (DSL). "Internal" means that terms are embedded directly in a "host" programming language.</p>
</li>
<li><p>The DSL terms can be well-typed. The type-checker of the host language guarantees it.</p>
</li>
<li><p>The DSL terms can be interpreted in a variety of ways: evaluation, printing, optimization (in a type-preserving way), etc...</p>
</li>
<li><p>The DSL is extensible: new term types can be introduced, existing interpreters can be reused.</p>
</li>
</ol>
<p>Why "Typed tagless final" then? In short:</p>
<ul>
<li><p><strong>Typed</strong> DSL terms can be typed</p>
</li>
<li><p><strong>Tagless</strong> DSL terms do not require to embed tags to keep track of their type</p>
</li>
<li><p><strong>Final</strong> DSL terms are not constructed as a specific data type but rather via functions</p>
</li>
</ul>
<p>This possibly looks quite interesting, but still very abstract. Moreover, if you look at examples, most of the time they are about creating a DSL for:</p>
<ul>
<li><p>A simplified arithmetic language, or</p>
</li>
<li><p>A version of the Lambda Calculus.</p>
</li>
</ul>
<p>Those are hardly real-life examples.</p>
<h1 id="heading-data-serialization-to-json">Data serialization to JSON</h1>
<p>Data serialization is (sadly) an essential part of many software projects, with many pitfalls in terms of correctness, performance, maintenance, and productivity.</p>
<p>For example the question on how to evolve serialization protocols, so that we can reuse most of our serialization code from one version to another, is not entirely trivial.</p>
<p>I have created a library <code>registry-aeson</code>, based on the <a target="_blank" href="https://hackage.haskell.org/package/aeson"><code>aeson</code></a> Haskell library, to propose a solution to this problem. That library is structured around two data types, <code>Decoder a</code>, to decode a value of type <code>a</code> from some JSON text, and <code>Encoder a</code> to encode a value of type <code>a</code> to a JSON value.</p>
<p>Encoding values seems a bit more straightforward than decoding them because there's no need for error management, but this is not the case! For performance reasons the <code>aeson</code> library proposes a <code>ToJSON</code> typeclass with 2 methods:</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToJSON</span> <span class="hljs-title">a</span> <span class="hljs-title">where</span></span>
  toJSON :: a -&gt; <span class="hljs-type">Value</span>
  toEncoding :: a -&gt; <span class="hljs-type">Encoding</span>
</code></pre>
<p><code>toJSON</code> creates a <code>Value</code> which can be a <code>String</code>, an <code>Object</code>, an <code>Array</code> etc... (all the types that we expect from a JSON data type). However, if we only had this method, we would spend time encoding to an intermediate data structure <em>then</em> transforming this structure to some bytes on wire. That is pretty ineffective.</p>
<p>This is why the <code>toEncoding</code> method exists. To transform the value <code>a</code> directly into bytes, using specific combinators. For example: <code>string "hello"</code> or <code>pairs (pair "name" value)</code>.</p>
<p>In the <code>registry-aeson</code> library, the first version of the <code>Encoder</code> data type was:</p>
<pre><code class="lang-haskell"><span class="hljs-class"><span class="hljs-keyword">newtype</span> <span class="hljs-type">Encoder</span> a = <span class="hljs-type">Encoder</span> { <span class="hljs-title">encode</span> :: <span class="hljs-title">a</span> -&gt; (<span class="hljs-type">Value</span>, <span class="hljs-type">Encoding</span>) }</span>
</code></pre>
<p>In order to define an <code>Encoder</code> you need to return both a <code>Value</code> <em>and</em> an <code>Encoding</code>, like the <code>ToJSON</code> typeclass does. But this is very tedious, in particular because the API to create values and encodings are very different in the <code>aeson</code> library.</p>
<p>For example if you want to serialize a data type with both field names and values:</p>
<ul>
<li><p>If you want to create a <code>Value</code>: you build an <code>Object</code> with a <code>KeyMap</code> from a list of keys and values.</p>
</li>
<li><p>if you want to go to <code>ByteString</code> directly: you make <code>pairs</code> with a <code>Series</code> of encoded values built with the <code>pair</code> combinator.</p>
</li>
</ul>
<p>What if we could have one expression and interpret it to either a <code>Value</code> or an <code>Encoding</code>? This is exactly what the Type Tagless Final approach gives us!</p>
<h1 id="heading-a-json-algebra">A JSON algebra</h1>
<p>We are going to define operations that allow us to build simple JSON terms, with only strings, ints and maps:</p>
<pre><code class="lang-haskell"><span class="hljs-comment">-- | Operations used to create JsonTerms</span>
<span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">JsonAlgebra</span> a = <span class="hljs-type">JsonAlgebra</span></span>
  { string_ :: <span class="hljs-type">Text</span> -&gt; a,
    int_ :: <span class="hljs-type">Int</span> -&gt; a,
    object_ :: [(<span class="hljs-type">Key</span>, a)] -&gt; a,
  }

<span class="hljs-comment">-- | Polymorphic JSON term. It can be interpreted later</span>
<span class="hljs-class"><span class="hljs-keyword">newtype</span> <span class="hljs-type">JsonTerm</span> = <span class="hljs-type">JsonTerm</span> {<span class="hljs-title">term</span> :: <span class="hljs-title">forall</span> <span class="hljs-title">a</span>. <span class="hljs-type">JsonAlgebra</span> <span class="hljs-title">a</span> -&gt; <span class="hljs-title">a</span>}</span>

<span class="hljs-comment">-- | Interpret a JsonTerm via a specific algebra</span>
<span class="hljs-title">interpret</span> :: <span class="hljs-type">JsonTerm</span> -&gt; <span class="hljs-type">JsonAlgebra</span> a -&gt; a
<span class="hljs-title">interpret</span> (<span class="hljs-type">JsonTerm</span> t) j = t j

<span class="hljs-comment">-- | Top-level JSON DSL operations</span>
<span class="hljs-title">string</span> :: <span class="hljs-type">Text</span> -&gt; <span class="hljs-type">JsonTerm</span>
<span class="hljs-title">string</span> t = <span class="hljs-type">JsonTerm</span> $ \ja -&gt; string_ ja t

<span class="hljs-title">int</span> :: <span class="hljs-type">Int</span> -&gt; <span class="hljs-type">JsonTerm</span>
<span class="hljs-title">int</span> b = <span class="hljs-type">JsonTerm</span> $ \ja -&gt; int_ ja b

<span class="hljs-title">object</span> :: [(<span class="hljs-type">Key</span>, <span class="hljs-keyword">forall</span> a. <span class="hljs-type">JsonAlgebra</span> a -&gt; <span class="hljs-type">Pair</span> a)] -&gt; <span class="hljs-type">JsonTerm</span>
<span class="hljs-title">object</span> vs = <span class="hljs-type">JsonTerm</span> $ \ja -&gt; 
  object_ ja ((\(k, v) -&gt; (k, interpret v ja)) &lt;$&gt; vs)
</code></pre>
<ul>
<li><p>A <code>JsonAlgebra a</code> defines operations to build a concrete type <code>a</code>. In our case we are eventually interested in <code>a = Value</code> and <code>a = Encoding</code>.</p>
</li>
<li><p>A <code>JsonTerm</code> is something that uses a concrete <code>JsonAlgebra a</code> and returns any <code>a</code> specified by that algebra.</p>
</li>
<li><p>The <code>string</code>, <code>int</code>, <code>object</code> functions are the top-level functions of our JSON DSL. They are the common API to build both <code>Values</code> and <code>Encodings</code>.</p>
</li>
</ul>
<p>Let's see an example of a <code>JsonTerm</code>. For example the JSON value:</p>
<pre><code class="lang-json">{ <span class="hljs-attr">"name"</span>: <span class="hljs-string">"eric"</span>, <span class="hljs-attr">"credits"</span>: <span class="hljs-number">100</span> }
</code></pre>
<p>can be represented with the <code>JsonTerm</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-title">let</span> term :: <span class="hljs-type">JsonTerm</span> = 
  object [(<span class="hljs-string">"name"</span>, string <span class="hljs-string">"eric"</span>), (<span class="hljs-string">"credits"</span>, int <span class="hljs-number">100</span>)]
</code></pre>
<p>This <code>JsonTerm</code> can be interpreted via concrete <code>JsonAlgebra</code> implementation. We can create such an algebra to build <code>Values</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-title">valueJsonAlgebra</span> :: <span class="hljs-type">JsonAlgebra</span> <span class="hljs-type">Value</span>
<span class="hljs-title">valueJsonAlgebra</span> = <span class="hljs-type">JsonAlgebra</span> {..}
  <span class="hljs-keyword">where</span>
    string_ :: <span class="hljs-type">Text</span> -&gt; <span class="hljs-type">Value</span>
    string_ = <span class="hljs-type">String</span>

    int_ :: <span class="hljs-type">Int</span> -&gt; <span class="hljs-type">Value</span>
    int_ = <span class="hljs-type">Number</span> . fromInteger . integerFromInt

    object_ :: [(<span class="hljs-type">Key</span>, <span class="hljs-type">Value</span>)] -&gt; <span class="hljs-type">Value</span>
    object_ = <span class="hljs-type">Object</span> . fromList
</code></pre>
<p>This algebra replaces each invocation of a function in a <code>JsonTerm</code> with an implementation building a <code>Value</code>. Hence, if we apply it to our <code>term</code> above we get a <code>Value</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-title">let</span> value :: <span class="hljs-type">Value</span> = interpret term valueJsonAlgebra

&gt; print value
&gt; <span class="hljs-type">Object</span> (fromList [(<span class="hljs-string">"name"</span>,<span class="hljs-type">String</span> <span class="hljs-string">"eric"</span>), (<span class="hljs-string">"credits"</span>,<span class="hljs-type">Number</span> <span class="hljs-number">100.0</span>)])
</code></pre>
<p>We can also define an implementation building an <code>aeson</code>'s <code>Encoding</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-keyword">import</span> Data.Aeson.Encoding <span class="hljs-keyword">as</span> E

<span class="hljs-title">encodingJsonAlgebra</span> :: <span class="hljs-type">JsonAlgebra</span> <span class="hljs-type">Encoding</span>
<span class="hljs-title">encodingJsonAlgebra</span> = <span class="hljs-type">JsonAlgebra</span> {..}
  <span class="hljs-keyword">where</span>
    string_ :: <span class="hljs-type">Text</span> -&gt; <span class="hljs-type">Encoding</span>
    string_ = <span class="hljs-type">E</span>.text

    int_ :: <span class="hljs-type">Int</span> -&gt; <span class="hljs-type">Encoding</span>
    int_ = <span class="hljs-type">E</span>.scientific . fromInteger . integerFromInt

    object_ :: [(<span class="hljs-type">Key</span>, <span class="hljs-type">Encoding</span>)] -&gt; <span class="hljs-type">Encoding</span>
    object_ = <span class="hljs-type">E</span>.pairs . foldMap identity . fmap (\(k, v) -&gt; <span class="hljs-type">E</span>.pair k v)
</code></pre>
<p>This time we can interpret our JSON term directly as an <code>Encoding</code> (more or less a <code>ByteString</code>):</p>
<pre><code class="lang-haskell"><span class="hljs-title">let</span> encoding :: <span class="hljs-type">Encoding</span> = interpret term encodingJsonAlgebra

&gt; print encoding
&gt; <span class="hljs-string">"{\"name\":\"eric\",\"credits\":100}"</span>
</code></pre>
<p>Two interpretations for the same term! Now, users of the <code>registry-aeson</code> library don't have to produce 2 expressions, with a different API, to generate efficient JSON 🤗.</p>
<h1 id="heading-putting-the-typed-in-typed-tagless-final">Putting the "typed" in "typed tagless final"</h1>
<p>Our DSL is well-typed. It is not possible to use its API to build terms which cannot be meaningfully interpreted. However, it is not quite optimal because we are missing the point of <code>aeson</code>'s <code>Encoding</code> a bit. Our <code>object</code> operation requires building tuples and putting them in a list instead of building a <code>ByteString</code> right away.</p>
<p>On the other hand, the documentation for <code>Encoding</code> shows this example:</p>
<pre><code class="lang-haskell"><span class="hljs-title">toEncoding</span> (<span class="hljs-type">Person</span> name age) = pairs (<span class="hljs-string">"name"</span> .= name &lt;&gt; <span class="hljs-string">"age"</span> .= age)
</code></pre>
<p>In the example above:</p>
<ul>
<li><p><code>"name" .= name</code> creates a <code>Series</code> which directly contains the serialized string <code>"name":"eric"</code></p>
</li>
<li><p>It is appended with <code>&lt;&gt;</code> to another <code>Series</code> to directly create the comma-separated string <code>"name":"eric","age":100</code></p>
</li>
</ul>
<p><strong>We need better operations and better types!</strong></p>
<p>Here is another version of the <code>JsonAlgebra</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">JsonAlgebra</span> r = <span class="hljs-type">JsonAlgebra</span></span>
  { string_ :: <span class="hljs-type">Text</span> -&gt; r (),
    int_ :: <span class="hljs-type">Int</span> -&gt; r (),
    pair_ :: <span class="hljs-type">Key</span> -&gt; r () -&gt; r <span class="hljs-type">Key</span>,
    empty_ :: r <span class="hljs-type">Key</span>,
    concatenate_ :: r <span class="hljs-type">Key</span> -&gt; r <span class="hljs-type">Key</span> -&gt; r <span class="hljs-type">Key</span>,
    object_ :: r <span class="hljs-type">Key</span> -&gt; r (),
  }
</code></pre>
<p>This time we introduce 3 new operations, almost as a sub-DSL:</p>
<ul>
<li><p><code>pairs_</code> to create a key/value pair, ready to be added to other key/value pairs</p>
</li>
<li><p><code>empty_</code> to denote the empty list of key/value pairs</p>
</li>
<li><p><code>concatenate_</code> to concat 2 lists of key/value pairs</p>
</li>
</ul>
<p>We also use another representation, <code>r</code>, parametrized by a type in order to track the type of term we are constructing:</p>
<ul>
<li><p><code>r ()</code> is for regular terms denoting normal JSON values</p>
</li>
<li><p><code>r Key</code> is for lists of key/value pairs being constructed before being passed to the <code>object_</code> function. We can choose any type that is different from <code>()</code>, I just chose to reuse an existing type.</p>
</li>
</ul>
<p>This new representation still guarantees that our DSL is type-safe, but with no need to introduce types like lists and pairs in the algebra operations.</p>
<p>If we add new top-level functions, we can see the new operations in action:</p>
<pre><code class="lang-haskell"><span class="hljs-title">pair</span> :: <span class="hljs-type">Key</span> -&gt; <span class="hljs-type">JsonTerm</span> () -&gt; (<span class="hljs-keyword">forall</span> r. <span class="hljs-type">JsonAlgebra</span> r -&gt; r <span class="hljs-type">Key</span>)
<span class="hljs-title">pair</span> k v ja = pair_ ja k (interpret v ja)

(&gt;&lt;) :: (<span class="hljs-keyword">forall</span> r. <span class="hljs-type">JsonAlgebra</span> r -&gt; r <span class="hljs-type">Key</span>) -&gt; (<span class="hljs-keyword">forall</span> r. <span class="hljs-type">JsonAlgebra</span> r -&gt; r <span class="hljs-type">Key</span>) -&gt; (<span class="hljs-keyword">forall</span> r. <span class="hljs-type">JsonAlgebra</span> r -&gt; r <span class="hljs-type">Key</span>)
(&gt;&lt;) = concatenate_ ja (v1 ja) (v2 ja)

<span class="hljs-title">object</span> :: (<span class="hljs-keyword">forall</span> r. <span class="hljs-type">JsonAlgebra</span> r -&gt; r <span class="hljs-type">A</span>.<span class="hljs-type">Key</span>) -&gt; <span class="hljs-type">JsonTerm</span> ()
<span class="hljs-title">object</span> vs = <span class="hljs-type">JsonTerm</span> $ \ja -&gt; object_ ja (vs ja)
</code></pre>
<p>Now we can build a term with:</p>
<pre><code class="lang-haskell"><span class="hljs-title">let</span> term :: <span class="hljs-type">JsonTerm</span> = 
  object $ (pair <span class="hljs-string">"name"</span> (string <span class="hljs-string">"eric"</span>) &gt;&lt; 
           (pair <span class="hljs-string">"credits"</span> (int <span class="hljs-number">100</span>))
</code></pre>
<p>In this example, we are really concatenating pairs of key/values, as we go, without having to build an intermediary list of tuples (this is very similar to what happens in the <code>Encoding</code> API of <code>aeson</code>).</p>
<p>Can we still get both <code>Values</code> and <code>Encodings</code> from such a term? Absolutely, we just need to find the right implementation and representation for each concrete algebra.</p>
<p>Our previous algebras were parametrized with <code>Value</code> and <code>Encoding</code>, now we will use <code>Values</code> and <code>Encoded</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">Values</span> k where</span>
  <span class="hljs-type">SingleValue</span> :: <span class="hljs-type">Value</span> -&gt; <span class="hljs-type">Values</span> ()
  <span class="hljs-type">ManyValues</span> :: [(<span class="hljs-type">A</span>.<span class="hljs-type">Key</span>, <span class="hljs-type">Value</span>)] -&gt; <span class="hljs-type">Values</span> <span class="hljs-type">A</span>.<span class="hljs-type">Key</span>

<span class="hljs-title">valueJsonAlgebra</span> :: <span class="hljs-type">JsonAlgebra</span> <span class="hljs-type">Values</span>
<span class="hljs-title">valueJsonAlgebra</span> = ...

<span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">Encoded</span> k where</span>
  <span class="hljs-type">Encoded</span> :: <span class="hljs-type">Encoding</span> -&gt; <span class="hljs-type">Encoded</span> ()
  <span class="hljs-type">CommaSeparated</span> :: <span class="hljs-type">E</span>.<span class="hljs-type">Series</span> -&gt; <span class="hljs-type">Encoded</span> <span class="hljs-type">A</span>.<span class="hljs-type">Key</span>

<span class="hljs-title">encodingJsonAlgebra</span> :: <span class="hljs-type">JsonAlgebra</span> <span class="hljs-type">Encoded</span>
<span class="hljs-title">encodingJsonAlgebra</span> = ...
</code></pre>
<p>It is not hard to implement each <code>JsonAlgebra</code> with those data types:</p>
<ul>
<li><p><code>Values</code> simply accumulates key/value pairs in a list when the <code>pair_</code> and <code>concatenate_</code> operations are called.</p>
</li>
<li><p><code>Encoded</code> re-uses the <code>Series</code> data type defined in <code>aeson</code>'s <code>Encoding</code> to efficiently create comma-separated string as key/value pairs are being added.</p>
</li>
</ul>
<p>Now interpreting a <code>JsonTerm</code> with a <code>JsonAlgebra</code> produces either a <code>Values</code> value or an <code>Encoded</code> value. We need 2 more functions to produce a <code>Value</code> or an <code>Encoding</code>:</p>
<pre><code class="lang-haskell"><span class="hljs-title">toValue</span> :: <span class="hljs-type">Values</span> k -&gt; <span class="hljs-type">Value</span>
<span class="hljs-title">toValue</span> (<span class="hljs-type">SingleValue</span> v) = v
<span class="hljs-title">toValue</span> (<span class="hljs-type">ManyValues</span> vs) = <span class="hljs-type">Object</span> . fromList $ vs

<span class="hljs-title">toEncoding</span> :: <span class="hljs-type">Encoded</span> k -&gt; <span class="hljs-type">Encoding</span>
<span class="hljs-title">toEncoding</span> (<span class="hljs-type">Encoded</span> e) = e
<span class="hljs-title">toEncoding</span> (<span class="hljs-type">CommaSeparated</span> s) = <span class="hljs-type">E</span>.pairs s
</code></pre>
<h1 id="heading-wrapping-up">Wrapping-up</h1>
<p>This whole post will probably look a bit scary if you have never read about the (proper) typed tagless final approach (or if you are new to Haskell and <code>aeson</code> 😄). Let me summarize:</p>
<ul>
<li><p>We have defined a DSL to create simple JSON terms with strings, ints and maps.</p>
</li>
<li><p>This DSL uses the operations:</p>
<ul>
<li><p><code>string</code></p>
</li>
<li><p><code>int</code></p>
</li>
<li><p><code>pair</code></p>
</li>
<li><p><code>object</code></p>
<pre><code class="lang-haskell">  <span class="hljs-keyword">let</span> term :: <span class="hljs-type">JsonTerm</span> = 
    object $ (pair <span class="hljs-string">"name"</span> (string <span class="hljs-string">"eric"</span>) &gt;&lt; 
             (pair <span class="hljs-string">"credits"</span> (int <span class="hljs-number">100</span>))
</code></pre>
</li>
</ul>
</li>
<li><p>We can eventually interpret a DSL term to either:</p>
<ul>
<li><p>a <code>Value</code> to do JSON manipulations</p>
</li>
<li><p>an <code>Encoding</code> to efficiently serialize data to binary</p>
</li>
</ul>
</li>
</ul>
<p>I hope that this blog post will encourage you to read more about this technique for creating DSLs, you never know when you might need it!</p>
]]></content:encoded></item><item><title><![CDATA[The application toolbox]]></title><description><![CDATA[What are the elements that make a huge difference in your productivity when you are developing an application? Are there features that you lament not having or that you spend time re-implementing again and again as you go to the next application, the...]]></description><link>https://etorreborre.blog/the-application-toolbox</link><guid isPermaLink="true">https://etorreborre.blog/the-application-toolbox</guid><category><![CDATA[programming languages]]></category><category><![CDATA[Scala]]></category><category><![CDATA[Haskell]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Mon, 06 Nov 2023 11:10:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1699109234227/d6232326-fb39-489c-af60-45b4f41b84e7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What are the elements that make a huge difference in your productivity when you are developing an application? Are there features that you lament not having or that you spend time re-implementing again and again as you go to the next application, the next programming language?</p>
<p>Today I want to talk about what makes a big difference for me when developing applications that are sufficiently large, both in terms of components and data model.</p>
<p>I hope you'll share your thoughts on this topic as well!</p>
<h1 id="heading-data-representation">Data representation</h1>
<p>Properly modeling the domain of an application is crucial. Think about it, the data types that we are defining are going to be used almost everywhere in our application!</p>
<h2 id="heading-what-can-go-wrong">What can go wrong?</h2>
<p>Here are some of the problems that arise when we fail to model our data correctly:</p>
<p><strong>Consistency</strong></p>
<p>If an <code>Order</code> and an <code>InventoryItem</code> reference the same <code>Product</code> but have a <code>product_id</code> field which can be set to disagreeing values.</p>
<p><strong>Meaning</strong></p>
<p>Imagine a field name with an ambiguous meaning: <code>expiry: Long</code>. Is it a <code>Date</code>, a <code>Duration</code>, what is the unit: <code>Minute</code>, <code>Seconds</code>?</p>
<p>Even if the field is well-typed: <code>expiry: Date</code>, what does this mean? Can I still create an <code>Order</code> for a <code>Product</code> with this <code>expiry</code> date? What if that field is also used to include the product or not in marketing campaigns? Now that field might have one value but 2 meanings.</p>
<p><strong>Precision</strong></p>
<p>How many times do we see <code>String</code> fields where restrictions should apply? For example, newlines are rarely allowed in a <code>name</code>. Accepting them at one end of the system might completely break the UI at the other end of the system, or another system for that matter.</p>
<p>The same goes for the use of <code>Int</code> in Scala for example:</p>
<pre><code class="lang-scala"><span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>(<span class="hljs-params">name: <span class="hljs-type">String</span>, age: <span class="hljs-type">Int</span></span>)</span>
</code></pre>
<p>Really, can a <code>Person</code> have <code>-20</code> as its age? One satisfying thing with Rust is that it knows the price of everything, so there are all sorts of <em>unsigned integers</em>. At least we have a way to represent (and calculate with) natural numbers:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Person</span></span> {
  name: <span class="hljs-built_in">String</span>,
  <span class="hljs-comment">// min value: 0, max value 255</span>
  age: <span class="hljs-built_in">u8</span>,
}
</code></pre>
<p><strong>Coupling</strong></p>
<p>It is very easy to model data that encompasses too many concerns:</p>
<pre><code class="lang-scala"><span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span>(<span class="hljs-params">
  name: <span class="hljs-type">Name</span>,
  age: <span class="hljs-type">Age</span>,
  address: <span class="hljs-type">Address</span>,
  occupation: <span class="hljs-type">Occupation</span>,
  currentBalance: <span class="hljs-type">Balance</span>,
  account: <span class="hljs-type">Account</span>,
  acquiredVia: <span class="hljs-type">MarketingCampaign</span>,
  openLitigations: <span class="hljs-type">List</span>[<span class="hljs-type">Litigation</span>],
</span>)</span>
</code></pre>
<p>You get the idea... When data mixes too many concerns it implicitly couples all the components that deal with these concerns. This is the recipe for a lot of code churn.</p>
<h2 id="heading-what-do-i-want">🧰 What do I want?</h2>
<h3 id="heading-data-definition">Data definition</h3>
<p>To be precise with data modeling I expect a few things from my programming language:</p>
<ul>
<li><p>Structs and enums (+ pattern matching on enums).</p>
</li>
<li><p>Non-verbose data declarations (Scala, Haskell, and Rust do this well), so I don't fear creating a <code>Name</code> data type if I need to.</p>
</li>
<li><p>Good libraries for common quantities: dates, times, money, memory size.</p>
</li>
</ul>
<h3 id="heading-data-input-and-parsing">Data input and parsing</h3>
<p>I give bonus points to languages giving me the ability to define well-typed literals at compile-time:</p>
<pre><code class="lang-scala"><span class="hljs-keyword">val</span> address = <span class="hljs-string">url"http://google.com"</span>
</code></pre>
<p>A more elaborate version for defining and parsing correct data is supported by <a target="_blank" href="https://github.com/fthomas/refined">the <code>refined</code> library</a> in Scala:</p>
<pre><code class="lang-scala">scala&gt; <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">ZeroToOne</span> </span>= <span class="hljs-type">Not</span>[<span class="hljs-type">Less</span>[<span class="hljs-number">0.0</span>]] <span class="hljs-type">And</span> <span class="hljs-type">Not</span>[<span class="hljs-type">Greater</span>[<span class="hljs-number">1.0</span>]]
defined <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">alias</span> <span class="hljs-title">ZeroToOne</span></span>

scala&gt; refineMV[<span class="hljs-type">ZeroToOne</span>](<span class="hljs-number">1.8</span>)
&gt; error: <span class="hljs-type">Right</span> predicate of (!(<span class="hljs-number">1.8</span> &lt; <span class="hljs-number">0.0</span>) &amp;&amp; !(<span class="hljs-number">1.8</span> &gt; <span class="hljs-number">1.0</span>)) failed
</code></pre>
<h3 id="heading-standard-type-classes">Standard type classes</h3>
<p>It should be completely trivial to add derived behavior to a data type for:</p>
<ul>
<li><p>Equality.</p>
</li>
<li><p>Optionally ordering or hashing.</p>
</li>
<li><p>Showing, debugging.</p>
</li>
</ul>
<p>Again, Scala / Haskell / Rust, make this very easy.</p>
<h3 id="heading-data-output">Data output</h3>
<p>One word about using <code>Show</code> / <code>Debug</code> instances. Those instances are fine to display data by default. However, I found it extremely useful to define a specific trait, say <code>Output</code>, dedicated to a domain representation of values. For example, if a <code>Warehouse</code> has a list of <code>loadedDocks</code> which are generally loaded in order, it is nicer to represent:</p>
<pre><code class="lang-scala"><span class="hljs-type">Warehouse</span>: <span class="hljs-type">East</span>-<span class="hljs-type">London</span><span class="hljs-number">-1</span>
  loaded docks: <span class="hljs-number">1.</span><span class="hljs-number">.7</span>
</code></pre>
<p>Rather than:</p>
<pre><code class="lang-scala"><span class="hljs-type">Warehouse</span>: <span class="hljs-type">East</span>-<span class="hljs-type">London</span><span class="hljs-number">-1</span>
  loaded docks: <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>
</code></pre>
<p>The ability to display things concisely pays off in the long run when writing tests and debugging. This is very domain-dependent but some utility functions around text can be useful:</p>
<ul>
<li><p>To pretty print lists.</p>
</li>
<li><p>To pretty print tables (with aligned columns, and/or wrapped text).</p>
</li>
<li><p>To create ranges.</p>
</li>
<li><p>To make a name plural based on a quantity: <code>n.times() == "3 times"</code> .</p>
</li>
</ul>
<h1 id="heading-serialization">Serialization</h1>
<p>Serialization is the unfortunate consequence of the fact that systems are rarely just isolated islands, they need to communicate with other systems.</p>
<p>Let's start with a 🌶️ take:</p>
<blockquote>
<p>Derived instances are an anti-pattern</p>
</blockquote>
<p>Now that I've made enemies with 90% of the profession I need to explain my viewpoint 😀. A derived instance for serialization is some code that the compiler generates automatically for a data type to serialize its values. For example:</p>
<pre><code class="lang-haskell"><span class="hljs-class"><span class="hljs-keyword">data</span> <span class="hljs-type">Employee</span> = <span class="hljs-type">Employee</span> {
  <span class="hljs-title">name</span> :: <span class="hljs-type">Name</span>,
  <span class="hljs-title">age</span> :: <span class="hljs-type">Age</span>, 
} <span class="hljs-keyword">deriving</span> (<span class="hljs-type">Eq</span>, <span class="hljs-type">Show</span>, <span class="hljs-type">Encode</span>)</span>
</code></pre>
<p>In the example above we simply annotate the <code>Employee</code> data type with <code>Encode</code> then we get the possibility to encode values:</p>
<pre><code class="lang-haskell"><span class="hljs-title">encode</span> (<span class="hljs-type">Employee</span> (<span class="hljs-type">Name</span> <span class="hljs-string">"eric"</span>) (<span class="hljs-type">Age</span> <span class="hljs-number">100</span>))) == 
  <span class="hljs-string">"{ 'name': 'eric', age: 100 }"</span>
</code></pre>
<p>I will keep the argument short but the main problem with this facility is that we couple our domain model too much with the <em>serialization concern</em>:</p>
<ul>
<li><p>We end up defining some attributes only so that it helps the serialization.</p>
</li>
<li><p>Serializing to different formats might place incompatible constraints on some attributes.</p>
</li>
<li><p>We cannot easily support several serialized versions representing the evolution of a protocol over time.</p>
</li>
<li><p>We hand over the serialization to a library that uses meta-programming to decide how to serialize data and might not do it most efficiently.</p>
</li>
</ul>
<p>In the end, serialization becomes a burden and slows down the evolution of an application.</p>
<h2 id="heading-what-do-i-want-1">🧰 What do I want?</h2>
<p>Rather than having to reconcile domain needs to serialization needs all the time I simply prefer to have the ability to write encoders and decoders manually.</p>
<h3 id="heading-defining-one-encoder">Defining one encoder</h3>
<p>That sounds horrible but not that much with a good programming language and some library support:</p>
<pre><code class="lang-haskell"><span class="hljs-title">makePersonEncoder</span> :: <span class="hljs-type">Encoder</span> <span class="hljs-type">Name</span> -&gt; <span class="hljs-type">Encoder</span> <span class="hljs-type">Age</span> -&gt; <span class="hljs-type">Encoder</span> <span class="hljs-type">Person</span>
<span class="hljs-title">makePersonEncoder</span> name age = \<span class="hljs-type">Person</span> { n, a } -&gt; 
  array [encrypt (encode name n), encode age a]
</code></pre>
<p>I can decide exactly how I want to encode the 2 fields here, as an array or a map, but I can also decide that I want to encrypt the name, with no impact on my domain model.</p>
<p>And if my data type is not fancy, I should be able to access some macros to do the simple, default, case:</p>
<pre><code class="lang-haskell"><span class="hljs-title">makePersonEncoder</span> = makeEncoder ''<span class="hljs-type">Person</span>
</code></pre>
<h3 id="heading-wiring-everything-together">Wiring everything together</h3>
<p>The other advantage of derived instances is the ability to wire all the instances together for a whole data model. Doing it manually is not much fun:</p>
<pre><code class="lang-haskell"><span class="hljs-title">orderEncoder</span> :: <span class="hljs-type">Encoder</span> <span class="hljs-type">Order</span>
<span class="hljs-title">orderEncoder</span> = 
  makeOrderEncoder 
    (makeCustomerEncoder (makeNameEncoder stringEncoder) 
                         (makeAgeEncoder intEncoder))
    (makeProductEncoder (makeProductIdEncoder stringEncoder) 
                        (makeDescriptionEncoder stringEncoder))
</code></pre>
<p>There is however one great advantage! We can now modify this wiring to evolve the serialization independently from the domain model. For example, if there is a new attribute for a <code>Customer,</code> we should still be able to serialize an old customer for the new data model, to communicate with a system that hasn't upgraded yet:</p>
<pre><code class="lang-haskell"><span class="hljs-comment">-- old version where the age of the customer was needed, now it's not)</span>
<span class="hljs-title">orderEncoderV1</span> :: <span class="hljs-type">Encoder</span> <span class="hljs-type">Order</span>
<span class="hljs-title">orderEncoderV1</span> = 
  makeOrderEncoder 
    (makeCustomerEncoderV1 (makeNameEncoder stringEncoder))
    (makeProductEncoder (makeProductIdEncoder stringEncoder) 
                        (makeDescriptionEncoder stringEncoder))
</code></pre>
<p>Even that part can be reduced to a minimum via <a target="_blank" href="https://github.com/etorreborre/registry-aeson">a library like <code>registry-aeson</code></a> in Haskell:</p>
<pre><code class="lang-haskell"><span class="hljs-comment">-- you just declare the change between the 2 versions</span>
<span class="hljs-comment">-- all the wiring is done automatically for each version</span>
<span class="hljs-title">decodersV1</span> = 
  &lt;: makeCustomerEncoderV1
  &lt;: decoders
</code></pre>
<h1 id="heading-persistence">Persistence</h1>
<p>Persistence presents mostly the same challenges as serialization in terms of data management with the added complexity of being able to represent and navigate relations:</p>
<ul>
<li><p>As pointers in a domain model.</p>
</li>
<li><p>As table relations in a relational model.</p>
</li>
</ul>
<p>My general inclination here is to use simple SQL libraries, not <a target="_blank" href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">ORMs</a>, or fancy <a target="_blank" href="https://haskell-beam.github.io/beam/tutorials/tutorial1">typed-SQL libraries</a>. This means that I have to write tests just to make sure that I don't have a typo in my SQL query but this is not a bad thing! Those tests are also important to check the semantics of my persistence layer:</p>
<ul>
<li><p>What should be the unique keys?</p>
</li>
<li><p>What are all the entities that must be deleted when one entity is deleted?</p>
</li>
<li><p>Should there be a failure if I try to insert the same item with different values?</p>
</li>
</ul>
<h2 id="heading-what-do-i-want-2">🧰 What do I want?</h2>
<p>I mostly want a database library (in combination with a test library) that lets me easily:</p>
<ul>
<li><p>Create queries, bind parameters, create database transactions</p>
</li>
<li><p>Manage schema migrations</p>
</li>
<li><p>Deserialize rows (see the section on Serialization)</p>
</li>
<li><p>Create an isolated database with the latest schema</p>
</li>
<li><p>Pinpoint syntax errors</p>
</li>
<li><p>Interact with actual test data</p>
</li>
</ul>
<h1 id="heading-data-generation">Data generation</h1>
<p><img src="https://i.imgflip.com/84wrh0.jpg" alt="Anakin Padme 4 Panel | I CREATED SO MANY DATA TYPES IN MY APPLICATION; AND YOU HAVE TESTS FOR EVERYTHING, RIGHT? RIGHT? | image tagged in anakin padme 4 panel | made w/ Imgflip meme maker" /></p>
<p>Once we start having a large and somewhat complex data model it is important to be able to easily create data of any shape to test the application features. The problem is that:</p>
<ul>
<li><p>This is tedious if there are many fields.</p>
</li>
<li><p>This leads to duplication of test code, when assembling large data structures from smaller ones.</p>
</li>
</ul>
<p>The result is that we tend to write less tests than we should.</p>
<h2 id="heading-what-do-i-want-3">🧰 What do I want?</h2>
<p>One excellent way to avoid these issues is to be able to create data generators for our data model:</p>
<pre><code class="lang-haskell"><span class="hljs-title">personGenerator</span> :: <span class="hljs-type">Gen</span> <span class="hljs-type">Name</span> -&gt; <span class="hljs-type">Gen</span> <span class="hljs-type">Age</span> -&gt; <span class="hljs-type">Gen</span> <span class="hljs-type">Person</span>
<span class="hljs-title">personGenerator</span> name age = <span class="hljs-type">Person</span> &lt;$&gt; name &lt;*&gt; age
</code></pre>
<p>In Haskell, if I have a generator for <code>Name</code>, a generator for <code>Age</code> I can easily have a generator of random data for <code>Person</code> using the wonderful <a target="_blank" href="http://learnyouahaskell.com/functors-applicative-functors-and-monoids">applicative notation</a>.</p>
<p>Then I can go:</p>
<pre><code class="lang-haskell"><span class="hljs-title">ghci</span>&gt; sample personGenerator
<span class="hljs-type">Person</span> { name: <span class="hljs-type">Name</span> <span class="hljs-string">"eric"</span>, age: <span class="hljs-type">Age</span> <span class="hljs-number">100</span> }
</code></pre>
<p>That's it. I have an example of a <code>Person</code> that I can reuse in many, many tests. If I take the habit of creating generators as I evolve my data model, I allow my coworkers to easily create test cases outside of the feature I was working on.</p>
<p>There are two difficulties with that approach:</p>
<ul>
<li><p>Creating a generator for a <code>Person</code> seems like it could be automated.</p>
</li>
<li><p>Wiring generators together is not fun</p>
</li>
<li><p>Changing just one generator for a given test is tedious</p>
</li>
</ul>
<p>Wait, that's the same problem as the serialization problem! And it has <a target="_blank" href="https://github.com/etorreborre/registry-hedgehog">a similar solution</a> 😊.</p>
<h1 id="heading-components">Components</h1>
<p>Once we nail our data model we still have to structure the functionalities of our application.</p>
<p>Great news! There's an excellent tool for this task, and it has been well-known <a target="_blank" href="https://en.wikipedia.org/wiki/Abstract_data_type">for quite some time</a>:</p>
<blockquote>
<p>Separate the interface from the implementation, Luke</p>
</blockquote>
<p>There are notions of interfaces in many programming languages but with all sorts of twists (I should do a distinct post just on that subject):</p>
<ul>
<li><p>Does it use <a target="_blank" href="https://en.wikipedia.org/wiki/Nominal_type_system">nominal typing</a> or <a target="_blank" href="https://en.wikipedia.org/wiki/Structural_type_system">structural typing</a>?</p>
</li>
<li><p>Does it have <a target="_blank" href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/generics/#Associated-Types">associated types</a>?</p>
</li>
<li><p>Can you specify <a target="_blank" href="https://v2.ocaml.org/manual/modtypes.html#sss:mty-exn">exception types separately</a>?</p>
</li>
</ul>
<p>Similarly, on the implementation side, there are many differences:</p>
<ul>
<li><p>Are modules <a target="_blank" href="https://softwareengineering.stackexchange.com/questions/326304/what-is-the-difference-between-applicative-and-generative-modules-and-type-clas">generative or applicative</a>?</p>
</li>
<li><p>Is the interface declaration part of the implementation type (Java), or separated (Haskell, Rust, Scala)?</p>
</li>
<li><p>Are modules first-class entities (Scala, not Haskell)?</p>
</li>
<li><p>Can we have an unlimited amount of implementations for a given interface (not in Haskell when using type classes)?</p>
</li>
</ul>
<h2 id="heading-what-do-i-want-4">🧰 What do I want?</h2>
<p>The bare minimum is the possibility of having interfaces and a way to check or declare that an implementation conforms to an interface.</p>
<p>Above this, I want a way to do <a target="_blank" href="https://en.wikipedia.org/wiki/Dependency_injection"><em>dependency injection</em></a>. We can think about components in an application as a graph where each component, as an implementation, depends on other components, as interfaces:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699206980960/66a345f6-3506-4ef4-8d16-03f55aa27c80.png" alt="Yes, this is a simplified real application..." class="image--center mx-auto" /></p>
<p>For any reasonably complex and deep graph, I want to be able to easily switch implementations anywhere in the graph:</p>
<ul>
<li><p>To change how logging is done.</p>
</li>
<li><p>To run entirely in memory.</p>
</li>
<li><p>To wrap a given component and make it return random errors to test the reliability of my system.</p>
</li>
<li><p>To run my system in different configurations: production, development, and demonstration.</p>
</li>
<li><p>To test a given sub-system in isolation from the rest (integration testing).</p>
</li>
</ul>
<p>The consequences of <em>not being able to easily do this</em> include:</p>
<ul>
<li><p>Time lost rewiring the system.</p>
</li>
<li><p>Not running some experiments because it is too tedious to do so.</p>
</li>
<li><p>Write fewer integration tests and only rely on top-level system tests.</p>
</li>
<li><p>Have fewer possibilities to test complex scenarios.</p>
</li>
<li><p>Spend more time adjusting the "wiring code" when refactoring.</p>
</li>
</ul>
<h1 id="heading-resources">Resources</h1>
<p>Back-end systems always end up dealing with limited resources:</p>
<ul>
<li><p>Files, sockets, database connections, memory.</p>
</li>
<li><p>Time, when waiting on IO operations.</p>
</li>
<li><p>Time, when executing computation-intensive calculations.</p>
</li>
</ul>
<p>There are good ways to deal with all these issues.</p>
<h2 id="heading-what-do-i-want-5">🧰 What do I want?</h2>
<h3 id="heading-safe-resources-closing">Safe resources closing</h3>
<p>Closing files, database connections, etc... should be done as soon as possible and be robust in the face of exceptions or concurrency. This is not <a target="_blank" href="https://www.fpcomplete.com/blog/resourcet-necessary-evil/">as easy</a> <a target="_blank" href="https://www.snoyman.com/blog/2018/10/raii-better-than-bracket-pattern/">as it seems</a>.</p>
<p>I like the work that has been done <a target="_blank" href="https://softwaremill.com/cats-effect-vs-zio/#resource-management">in Scala for resource management</a> and I am still on the fence on how the best way to deal with this in Rust. The <a target="_blank" href="https://doc.rust-lang.org/rust-by-example/scope/raii.html">pattern is called RAII</a> ("Resource acquisition is initialization") but I still wonder if we are abusing lifetimes and memory management to support resource management when:</p>
<ul>
<li><p>The scopes can be different.</p>
</li>
<li><p>The need for IO might require some async functionalities (an <code>async</code> <code>Drop</code> is <a target="_blank" href="https://sabrinajewson.org/blog/async-drop">still being debated</a>).</p>
</li>
</ul>
<h3 id="heading-asyncconcurrency">Async/concurrency</h3>
<p>There are different ways to support async programming:</p>
<ul>
<li><p>As a library: Scala</p>
</li>
<li><p>As a library + a runtime: Haskell</p>
</li>
<li><p>As a language construct + a runtime: Rust</p>
</li>
</ul>
<p>All those approaches have complexities and pitfalls. It seems to me that one way to keep our sanity when using concurrency is to use <em>structured concurrency</em>. This article, "<a target="_blank" href="https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/">Go statement considered harmful</a>", is widely recognized as a great resource to learn about it, so go read about it if you haven't!</p>
<p>Scala would also be <a target="_blank" href="https://zio.dev/reference/fiber/#structured-concurrency">my favorite choice</a> at this stage, with functional libraries like the <a target="_blank" href="https://typelevel.org/">Typelevel</a> libraries or the <a target="_blank" href="https://zio.dev">ZIO</a> ones.</p>
<h3 id="heading-streaming">Streaming</h3>
<p>Good streaming libraries allow us to iterate on infinite amounts of data without blowing up our memory:</p>
<ul>
<li><p>In Haskell, I liked <a target="_blank" href="https://hackage.haskell.org/package/streaming">streaming</a> for its simplicity and elegance.</p>
</li>
<li><p>In Scala, I would be tempted to use <a target="_blank" href="https://fs2.io/#/getstarted/example">fs2</a> or <a target="_blank" href="https://zio.dev/reference/stream/">zio-stream</a>.</p>
</li>
</ul>
<h1 id="heading-traverse">Traverse</h1>
<p><img src="https://imgur.com/c9IEZXn.png" alt="always traverse" /></p>
<p><a target="_blank" href="https://mmhaskell.com/blog/2022/4/28/traverse-fully-generalized-loops"><code>traverse</code> is such a useful function</a>. If you start learning functional programming and then discover the <code>traverse</code> function, there is no turning back. It makes me a bit sad that <code>traverse</code> in Rust comes in different forms and with a less than perfect type-inference:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// for a vector</span>
<span class="hljs-keyword">let</span> results: <span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;ValidValue&gt;&gt; = 
   values.iter().map(|v| check(v)).collect();

<span class="hljs-comment">// for an option</span>
<span class="hljs-keyword">let</span> result: <span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Option</span>&lt;ValidValue&gt;&gt; = 
   optionalValue.map(|v| check(v)).transpose()
</code></pre>
<p>In Haskell:</p>
<pre><code class="lang-haskell"><span class="hljs-title">results</span> = traverse check values <span class="hljs-comment">-- or: for values check</span>
<span class="hljs-title">result</span> = traverse check optionalValue <span class="hljs-comment">-- or: for value check</span>
</code></pre>
<p>In Haskell, this is the same concept, whatever the container, whatever the effect!</p>
<h2 id="heading-what-do-i-want-6">🧰 What do I want?</h2>
<p>A good functional programming library gives us an incredible vocabulary to work with data and effects. <code>map</code>, <code>traverse</code>, <code>foldMap</code>, <code>foldLeft</code>, <code>Monoid</code>, <code>Either</code>, <code>Option</code>, etc... are invaluable to write concise and correct code. This goes a bit against the grain of languages encouraging (controlled) mutation like Rust or which don't have great support for functions and type inference (Java).</p>
<h1 id="heading-what-about-you">What about you?</h1>
<p>I gave you my laundry list of language features and libraries that I like having at my fingertips to productively develop robust applications. You probably have your own list of features that I did not cover and I'm genuinely curious to know about them. Please share!</p>
]]></content:encoded></item><item><title><![CDATA[Why we need techno-realism]]></title><description><![CDATA[Marc Andreessen recently wrote a "Techno-optimist manifesto". I promptly reacted that I was a techno-pessimist, that I was not believing in technology to be the solution. Even worse, I am tempted to say that more technology will be our demise.
The ma...]]></description><link>https://etorreborre.blog/why-we-need-techno-realism</link><guid isPermaLink="true">https://etorreborre.blog/why-we-need-techno-realism</guid><category><![CDATA[technology]]></category><category><![CDATA[Environment]]></category><category><![CDATA[manifesto]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Tue, 24 Oct 2023 15:18:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698072888621/68cc6a8c-ef5a-4937-a5ca-56a8cb42b1d4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Marc Andreessen recently wrote a "<a target="_blank" href="https://a16z.com/the-techno-optimist-manifesto/">Techno-optimist manifesto</a>". I promptly reacted that I was a techno-pessimist, that I was not believing in technology to be <em>the</em> solution. Even worse, I am tempted to say that more technology will be our demise.</p>
<p>The manifesto still made me think. We are faced with inextricable issues, and being pessimistic is not helping. What kind of message am I conveying, especially to my children, "Well, good luck because we're all doomed"? That's not fair to them or to anyone else. Why not be optimistic instead? After all, technology has already brought so many improvements in our lives, from low infant mortality to food in large quantities. There are incredible technological breakthroughs still to be conquered. For example, could there be new sources of carbon-free energy that we can exploit at a minimal cost for the environment? There are so many things we still don't know in the very fabric of our Universe, like how to unify <a target="_blank" href="https://www.quantamagazine.org/quantum-gravitys-time-problem-20161201/">Quantum Mechanics and the Theory of General Relativity</a>. Let's discover them and rock our world!</p>
<h1 id="heading-delusion-of-grandeur">Delusion of grandeur</h1>
<p>Optimism is a much better position to solve problems because you start to postulate that solutions exist. On the other hand, what I don't want is to be <em>delusional</em>. That doesn't help. I cannot bet my future on the idea that anti-gravity devices will, one day, exist. The Techno-optimist Manifesto not only has a "can-do" attitude but also a "want-to" attitude. As if there was no reason for the Universe to not eventually grant all our wishes.</p>
<p>For example, we are very, very lucky, that on this planet, gravity is just low enough that loading a rocket with the best fuels we know of will allow it to go into orbit. Were the gravity slightly more important and <a target="_blank" href="https://churchman.nl/2014/10/30/escape-velocity-and-how-much-fuel-do-rockets-need/">the weight of the fuel itself would be too much for the rocket get to escape velocity</a>! Maybe we are not meant to get much farther than our solar system. The closest star after the Sun is already very far away. Maybe we won't ever be able to visit it. There is no reason why we couldn't but there is also no reason why we could.</p>
<p>If we look at the history of science we can see many things that we <em>cannot</em> do:</p>
<ul>
<li><p>There are limits to what we can prove with formal systems (Gödel's theorem)</p>
</li>
<li><p>There's no engine with perpetual motion (<a target="_blank" href="https://www.theguardian.com/science/2013/dec/01/what-is-the-second-law-of-thermodynamics">Laws of thermodynamics</a>)</p>
</li>
<li><p>We cannot know the speed and position of a particle with equal precision (<a target="_blank" href="https://scienceexchange.caltech.edu/topics/quantum-science-explained/uncertainty-principle">The Uncertainty Principle</a>)</p>
</li>
<li><p>Nothing can travel faster than the speed of light</p>
</li>
</ul>
<p>Those are some limits for how far we can go. This could still be a long way! Yet we first need to apply a critical eye to where we are <strong>now</strong>. This is where the word <em>delusion</em> comes to mind.</p>
<p>The Techno-optimist Manifesto makes a huge mistake, it forgets <strong>the materiality of technology</strong>. It sees technology as a final product, as a pure gain, devoid of any costs.</p>
<h1 id="heading-smartphone-really"><em>Smart</em>phone, really?</h1>
<p>The object representing the biggest technological prowess of our times is probably the Smartphone. It is indeed a smart combination of materials research, hardware design, and manufacturing processes.</p>
<p>I remember sincerely dreaming about such a product as a kid. Something that I could use to call my friends, read, listen to music, watch videos, all in one object.</p>
<p>But let's come back to the physical object. What is it made of? What did it take to produce this marvel of technology? Short answer:</p>
<ol>
<li><p>Making this object was incredibly destructive to our planet and some fellow humans</p>
</li>
<li><p>It is most likely destined to go to landfill and be wasted forever</p>
</li>
<li><p>Some resources it consumed can never be reclaimed</p>
</li>
</ol>
<p>We need to enjoy those phones now because there's no guarantee that our successors will be able to do the same. Not very <em>smart</em>.</p>
<h1 id="heading-minerals-and-metals">Minerals and metals</h1>
<p>In this post, I want to highlight how much our technology relies on some very concrete reality. Reality is messy. Messy <em>and</em> worrying since we are planning on increasing technology in our lives.</p>
<p>Let's just focus on minerals and metals. Without metals, there is no technology. We cannot make our beloved smartphones or computers to run ChatGPT. We cannot even produce the energy to power those devices!</p>
<p>What about metals then? Where do they come from? Let's enter the wonderful world of mines.</p>
<p><strong>Note</strong>: for what goes below I am relying on the various <a target="_blank" href="https://www.youtube.com/watch?v=i8RMX8ODWQs">presentations</a> and <a target="_blank" href="https://www.systext.org/sites/default/files/RP_SystExt_Thinkerview-2-Sources-Complements_Mai2023.pdf">sources</a> given by Aurore Stéphant, a French mining engineer and geologist.</p>
<h1 id="heading-whats-in-a-mine">What's in a mine?</h1>
<h2 id="heading-the-gold-needle-in-the-haystack">The gold needle in the haystack</h2>
<p>The first thing to understand is that there is nothing like a gold bar, or even nowadays a gold nugget, in the wild. If we want to collect gold, an amazing electrical conductor, we need to dig an enormous amount of land. There is only <strong>one gram of gold per 1 ton of ore</strong>. And when we go after that gram of gold we dig out many other metals:</p>
<ul>
<li><p>Iron (30 to 66%)</p>
</li>
<li><p>Aluminium (25 to 30%)</p>
</li>
<li><p>Zinc (4 to 20%)</p>
</li>
<li><p>Uranium (1 to 3%)</p>
</li>
<li><p>Indium (100 g / t)</p>
</li>
<li><p>and many more</p>
</li>
</ul>
<p>Some of those metals are harmful to our health. They end up disseminated in the environment when we mine for gold.</p>
<p>We don't have a gold bar yet, mining is just the first step.</p>
<h2 id="heading-steps-to-purity">Steps to purity</h2>
<p>Three more steps are necessary, depicted here for copper:</p>
<ul>
<li><p>concentration, mostly a physical operation to make a thin powder</p>
</li>
<li><p>extraction, a chemical or pyrometallurgy operation</p>
</li>
<li><p>refinement, via fire and electrolysis</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698080078416/eba021ff-0790-421b-8279-0b05ce818d3e.png" alt class="image--center mx-auto" /></p>
<p>All these operations require large amounts of energy, chemical products, and water.</p>
<p>This explains why the footprint necessary for mining operations is very large. We need to move heaven and earth to get reasonable amounts of purity! Let's have a look at some consequences.</p>
<h2 id="heading-the-dirty-secrets-of-mining">The dirty secrets of mining</h2>
<h3 id="heading-mining-sites-are-human-disasters">Mining sites are human disasters</h3>
<p>In many places in the World, mining sites have been created and have expanded, to the detriment of the local population. In Romania, a large copper has used a small nearby valley as its dumping site. See, that was a village there in the 80's:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698147030640/59f4f27b-d096-46ed-b8f9-e7bbc7bc60ea.png" alt class="image--center mx-auto" /></p>
<p>(photo taken in 2015, we can't almost see anything nowadays with 14000 tons dumped every year)</p>
<p>300 families have been moved out of the zone, <strong>with no compensation</strong>. Sadly, the mining and oil industries are responsible for the most number of murders, human violations and social/environmental conflicts in the World.</p>
<h3 id="heading-a-mining-site-is-irreversibly-damaged">A mining site is <strong>irreversibly damaged</strong></h3>
<p>Even when there are attempts to "rehabilitate" a mining site, soil and water sources stay polluted for years. Worse, in some cases like uranium mines in France, the site has been made "invisible", so that everyone forgets there was a mine but the source of pollution stays.</p>
<p>The UK Environment Agency writes (in 2023):</p>
<blockquote>
<p>Mining played a major part in Britain’s rich industrial history, but this also left thousands of abandoned mines scattered across our landscape. Almost all these mines had closed by the early 1900s but they are still releasing harmful metals including lead, cadmium and copper. This is one of the top 10 issues for water quality in England as it harms fish and river insects. […]. The worst river pollution by metals is caused by water flowing out of tunnels dug by miners. Rainfall also washes metals out of the millions of tonnes of highly contaminated wastes the miners left at the surface.</p>
</blockquote>
<p>Not only those mines do not provide any more value today, but they are actively, and for a long time, harmful.</p>
<h3 id="heading-a-mining-site-is-dangerous">A mining site is dangerous</h3>
<p>When a mine is active, all the residue goes to a "tailing dam":</p>
<p><img src="https://www.vmcdn.ca/f/files/nob/miningwatch-canada-photo-of-tailings-dam.jpg" alt="Tailings dam ruptures still happen even with industry standards, say  critics - Northern Ontario Business" /></p>
<p>In the last 10 years, there were from <strong>3 to 7 tailing dam failures per year</strong>. The two largest ones were:</p>
<ul>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Brumadinho_dam_disaster">The Mariana Dam disaster</a>, in 2015. It has been recognized as "the worst environmental disaster in Brazil's history". Entire fish populations were killed almost instantly, and the contamination went through the Rio Doce up to the Atlantic Ocean</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Brumadinho_dam_disaster">The Brumadihno Dam disaster</a>, 3 years later. It killed 270 persons, with a mud wave going at 120 km/h. Twelve million metric cubes of tailings were released and cadmium was found up to 302 km downstream of the mine site</p>
</li>
</ul>
<h1 id="heading-it-is-only-getting-worse">It is only getting worse</h1>
<p>It is getting worse for 2 reasons:</p>
<ol>
<li><p>There is less</p>
</li>
<li><p>We want more</p>
</li>
</ol>
<h2 id="heading-there-is-less"><strong>There is less</strong></h2>
<p>The good old mining days are over. The concentrations of all minerals are noticeably going down:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698148158871/4d76198d-69d7-4473-80cc-e1e9e1aa2174.png" alt class="image--center mx-auto" /></p>
<p>This means that, if we want to dig up the same quantities we need to move out a lot more soil, with a lot more energy, and environmental damage. This graph shows the correlation between the emitted CO2 and gold concentration for various mining sites around the world:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698148458029/a616a374-8027-4c5d-8a83-48cccec0ba10.png" alt class="image--center mx-auto" /></p>
<p>We have similar graphs for energy, water and cubic meters of moved land.</p>
<h2 id="heading-we-want-more"><strong>We want more</strong></h2>
<p>In our quest to fight climate change, we aim to transition to electric cars, electric trucks, electric foundries, and so on.</p>
<h3 id="heading-more-quantities">More quantities</h3>
<p>The copper demand is expected to grow <a target="_blank" href="https://www.dnv.com/article/the-role-of-copper-in-the-energy-transition">from 25 tons/year to 36 tons/year by 2031</a>. We need around 20 kgs of copper in a conventional, and 80 kgs in an electric car. Some of that copper comes from recycling (<a target="_blank" href="https://copperalliance.org/resource/copper-recycling">8.7 million tons/year</a>) but there are limits to what we can recycle:</p>
<ul>
<li><p>Many products using copper are still in use</p>
</li>
<li><p><a target="_blank" href="https://scholar.google.com/scholar_lookup?hl=en&amp;publication_year=1978&amp;author=C.+L.+Kusik&amp;author=C.+B.+Kenahan&amp;title=Energy+Use+Patterns+for+Metal+Recycling%3B+Information+circular">The complexity of products using copper can make them difficult to recycle, and much more energy-consuming</a></p>
</li>
</ul>
<p>The last point is interesting, we need lots of energy to produce and distribute energy, which itself is needed for mining and recycling. What makes us think that we can eventually get even?</p>
<h3 id="heading-more-qualities">More qualities</h3>
<p>Let's take an example where technology is improving things: LED lights. A LED lightbulb consumes 75% less energy than an incandescent lightbulb and lasts up to 5 times longer. That looks like a great technological win. But the downside is in the recycling. LED lightbulbs are more complex than incandescent lightbulbs. They involve more materials:</p>
<blockquote>
<p>They are bonded together, often with glues and foams that make separation of them using mechanical processes very difficult. You’ve got all types of materials in there from plastics, glass, ceramics, aluminum, copper. You have PCBs. It’s a complete mixture. We have a problem that’s going to come back and bite us</p>
</blockquote>
<p>(Nigel Harvey, CEO of UK Lamp recycler, in <a target="_blank" href="https://www.ledsmagazine.com/manufacturing-services-testing/article/16701726/led-lamp-waste-theres-good-news-and-bad">ledmagazine.com</a>. Yes, there is a magazine for everything 😄).</p>
<p><a target="_blank" href="https://www.sciencedirect.com/science/article/abs/pii/S0921344921005103">At least LED lamps are useful</a>.</p>
<h1 id="heading-still-optimistic-but-realism-wont-hurt">Still optimistic, but realism won't hurt</h1>
<p>We can still be optimistic. But we have to seriously revise our goals. The direction we are taking is simply not sustainable. Technological problems are multi-dimensional and we have become quite good at improving in some dimensions at the expense of other dimensions: our environment, our resources and our human population.</p>
<p>In many ways, we are acting like a 20-year-old who has inherited a large fortune and is squandering it. In 200 years we have burned a treasury that took millions of years to accumulate, without thinking about tomorrow.</p>
<h2 id="heading-its-a-difficult-multi-criteria-optimization-problem">It's a difficult multi-criteria optimization problem</h2>
<p>That's why I'm opposed to the Techno-optimist manifesto. It is very one-sided. It implicitly promotes going faster in the same direction without looking at all the problems that technology is creating <strong>at the same time</strong>.</p>
<p>This way of thinking is reflected in the Manifesto section about markets:</p>
<blockquote>
<p>We believe free markets are the most effective way to organize a technological economy. Willing buyer meets willing seller, a price is struck, both sides benefit from the exchange or it doesn’t happen. Profits are the incentive for producing supply that fulfills demand. Prices encode information about supply and demand</p>
</blockquote>
<p>As if prices, a one-dimensional quantity, could encode everything there is to know in an exchange. This is very naive and blatantly false. When you buy a TV, a car, or a phone, are you only looking at the price? No, you are generally agonizing over a zillion of other criteria.</p>
<p>As a society, we need to start considering our technology in all its dimensions. Maybe that means not having a flashlight on our phone, but hey water is drinkable!</p>
<h2 id="heading-i-still-want-to-play-with-my-toys-too">I still want to play with my toys too</h2>
<p>What I am writing is not necessarily very popular amongst my fellow software engineers. I understand that. I love programming. Each year, we are coming up with new programming languages, new models of computations, and new ways to dice and slice data. But maybe it is time to rethink my toys, to rethink <strong>our</strong> toys. As much as I appreciate my smartphone, I did not have one for the first 10 years of my adult life. I still had a good life.</p>
<p>ChatGPT can summarize a piece of text in seconds. Fantastic. How much is it worth in terms of <strong>irreversibly polluted</strong> land? We need to start thinking about our technological products from start to finish. How many times did you hear in a conversation between software engineers "Data is cheap"? Or "I can easily spin off 100 machines to do this if I want to"? Are they wondering what that means at the end of the line?</p>
<h1 id="heading-actual-recommendations">Actual recommendations</h1>
<p>What can we do then? Here are some recommendations <a target="_blank" href="https://youtu.be/LXuE0mg6NBQ?t=4381">from experts in the field</a>:</p>
<ol>
<li><p>Massively limit the amounts of metals used in products (favor recycled metal) and overall quantity (which means making fewer products).</p>
</li>
<li><p><strong>De-digitalize society</strong>. Remove unnecessary screens, stop making gizmos (Alexa etc...), and have an equivalent non-digital usage for every digital usage. Yes, that means that eventually fewer people like me are needed 😔.</p>
</li>
<li><p>Educate people about the resource consumption of our products.</p>
</li>
<li><p>Design for recycling.</p>
</li>
<li><p>Plan and collect the requirements in terms of resources based on human fundamental needs: water, food, heat, health, and education.</p>
</li>
</ol>
<p>This is where we need to be optimistic and innovative as humans. We need to believe that we can create a good life for ourselves, and the future generations, without burning everything to the ground.</p>
]]></content:encoded></item><item><title><![CDATA[Turning actors inside-out]]></title><description><![CDATA[The actor model, and its concrete incarnation in platforms like Erlang/OTP or Akka, has been presented as a great way to create scalable and resilient systems.
However, there is a dimension in which actor systems fall short in my experience. They don...]]></description><link>https://etorreborre.blog/turning-actors-inside-out</link><guid isPermaLink="true">https://etorreborre.blog/turning-actors-inside-out</guid><category><![CDATA[Rust]]></category><category><![CDATA[concurrency]]></category><category><![CDATA[async]]></category><category><![CDATA[Scala]]></category><category><![CDATA[Elixir]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Sun, 08 Oct 2023 15:37:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Hn3S90f6aak/upload/b8da514e21087e5f9ad879f4a8308f60.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The actor model, and its concrete incarnation in platforms like <a target="_blank" href="https://www.erlang.org/">Erlang/OTP</a> or <a target="_blank" href="https://akka.io">Akka</a>, has been presented as a great way to create scalable and resilient systems.</p>
<p>However, there is a dimension in which actor systems fall short in my experience. They don't scale in terms of complexity. Each time I've had to look at applications built with actors I found the overall behavior of the system pretty hard to reason about. Why?</p>
<h1 id="heading-the-original-sin">The original sin</h1>
<p>The reason is quite simple. As Paul Chiusano describes in "<a target="_blank" href="https://web.archive.org/web/20221130144427/http://pchiusano.blogspot.com/2010/01/actors-are-not-good-concurrency-model.html?m=1">Actors are not a Good Concurrency Model</a>" the fundamental signature of an Actor is <code>A =&gt; Unit</code>. You send it a message and ... something happens. This presents 2 major drawbacks:</p>
<ul>
<li><p>You need to look inside the implementation of an actor to have the faintest idea of what it is effectively doing</p>
</li>
<li><p>Since its behavior is a side-effect, any refactoring can have unintended consequences</p>
</li>
</ul>
<p>Despite these issues, proponents of the Actor model still claim that their approach is a great way to build concurrent and reliable systems. This is not an entirely baseless claim since a company like WhatsApp, using Erlang, was <a target="_blank" href="https://news.ycombinator.com/item?id=10225096">supporting 900 million users with 50 engineers in 2015</a>! Surely I must be very wrong. Or,... is it a question of context?</p>
<p>In this blog post, I want to examine:</p>
<ul>
<li><p>What are the properties that make actor systems attractive?</p>
</li>
<li><p>Are there ways to keep those desirable properties while still making the system as a whole a lot more amenable to navigating and reasoning?</p>
</li>
<li><p>What kind of systems are well-suited to the Actor model?</p>
</li>
</ul>
<h1 id="heading-what-is-so-good-then">What is so good then?</h1>
<p>For this post, I am going to ignore the use of actors for distributed systems and focus on actors used in local, concurrent systems.</p>
<p>There are 4 main advantages to actors:</p>
<ol>
<li><p>The sequential access to in-memory data to avoid data races</p>
</li>
<li><p>An inherently asynchronous programming model</p>
</li>
<li><p>The modeling of actors as state machines mapping 1-1 to some conceptual entity</p>
</li>
<li><p>The use of supervisors for error management</p>
</li>
</ol>
<h1 id="heading-taming-concurrency-with-actors">Taming concurrency with actors</h1>
<p>One major difficulty with concurrent programming is the necessity to keep our data consistent. If I keep a list of bank accounts and want to model a transfer of money between 2 accounts, I'd better make sure that the transfer happens atomically. It should not be possible to observe that money has left Alice's account without being credited to Bob's account. This kind of problem is compounded <a target="_blank" href="https://marabos.nl/atomics/">when multi-threading is involved and when the compiler can freely re-arrange your code</a>.</p>
<p>In that situation, an object like a <code>Bank</code> does not have a concurrency-safe interface</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Bank</span></span> {
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">withdraw</span></span>(amount: Amount, from: Account, to: Account) 
     -&gt; <span class="hljs-built_in">Result</span>&lt;(), WithdrawError&gt;;
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">credit</span></span>(amount: Amount, from: Account, to: Account);
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">balance</span></span>(account: Account) -&gt; <span class="hljs-built_in">Result</span>&lt;Amount&gt;;
}
</code></pre>
<p>Even if you combine <code>withdraw</code> and <code>credit</code> into one function, the implementation might not be thread-safe if we implement things naively:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Bank</span></span> {
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">transfer</span></span>(amount: Amount, from: Account, to: Account)
     -&gt; <span class="hljs-built_in">Result</span>&lt;(), WithdrawError&gt;;
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">balance</span></span>(account: Account) -&gt; <span class="hljs-built_in">Result</span>&lt;Amount&gt;;
}
</code></pre>
<p>The solution that actors propose is to "lift" the methods into data, as messages:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Message</span></span> {
  Transfer { 
    amount: Amount,
    from: Account,
    to: Account 
  },
  Balance(),
}

<span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Bank</span></span>: Actor {
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">handle_message</span></span>(message: Message);
}
</code></pre>
<p>Those messages can be sent to the message queue of an actor and become effectively serialized. The actor system of your choice then makes sure that the execution of each actor is single-threaded: problem solved!</p>
<h2 id="heading-problem-solved-at-a-massive-cost">Problem solved, at a massive cost</h2>
<blockquote>
<p>All the problems in computer science can be solved by another level of indirection</p>
<p><a target="_blank" href="https://www2.dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/Spi07g.html">https://www2.dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/Spi07g.html</a></p>
</blockquote>
<p>We solved this local, tactical, problem at the expense of a massive indirection. Now our program turns from:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(_) = bank.transfer(Amount(<span class="hljs-number">100</span>), alice, bob) {
  sms_system.send_message(bob, <span class="hljs-string">"transfer done!"</span>)
}
</code></pre>
<p>to:</p>
<pre><code class="lang-rust">bank.send_message(Transfer::new(Amount(<span class="hljs-number">100</span>), alice, bob));
</code></pre>
<p>This has many implications in terms of practical concerns:</p>
<ul>
<li><p>We cannot anymore click on the <code>transfer</code> call and have a look at the implementation. Instead, we need to go through the entire pattern match inside <code>handle_message</code> to see where the case for <code>Transfer</code> is handled. If there are several message variants, the actual code dealing with transfers is probably tucked away in an internal function somewhere else</p>
</li>
<li><p>How do we get back a result telling us that the transfer was successful? Now the <code>Bank</code> actor needs to get a reference to the sender and send a result back</p>
</li>
</ul>
<p>In general, specifying what happens next is not obvious. In the first example, with functions, we notify the SMS system that Bob's account has been credited. With actors, we would probably start the <code>Bank</code> actor with a reference to the <code>Sms</code> actor and send a <code>Credited</code> message from inside the actor implementation.</p>
<p>With actors, we have to read the code to understand what is the flow of data in our system. When reading the code is not enough <a target="_blank" href="https://letitcrash.com/post/30585282971/discovering-message-flows-in-actor-systems-with">we have to instrument the actors at runtime to get some insight about what's going on</a>.</p>
<h2 id="heading-its-not-a-magic-wand">It's not a magic wand</h2>
<p>Each actor has its own internal state, free of race conditions, great. Yet this does not solve all state-related issues. What if we try to model each <code>Account</code> as an actor? How can we implement a transfer scenario so that the transfer between two accounts becomes atomic?</p>
<p>We have to come up with other patterns and pieces of infrastructure to solve these problems. For example:</p>
<ul>
<li><p>"<a target="_blank" href="https://kar.kent.ac.uk/63834/1/agere13-de-koster-et-al-tanks-multiple-reader-single-writer-actors.pdf">Tanks, multiple readers, single writer actors</a>"</p>
</li>
<li><p>"<a target="_blank" href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;type=pdf&amp;doi=d6c5ff8a5e118fca4cefd7702b80d0d83de61d1f">Speculative Concurrent Processing with Transactional Memory in the Actor Model</a>"</p>
</li>
</ul>
<h1 id="heading-dont-await-for-me">Don't (a)wait for me!</h1>
<p>A system like Akka became quite popular at a time when <a target="_blank" href="https://doc.akka.io/docs/akka/current/typed/guide/actors-intro.html#usage-of-message-passing-avoids-locking-and-blocking">async programming was becoming an absolute requirement</a>. A web server dealing with thousands of requests could not allow its threads to be idly waiting for responses from other services or a database. On the contrary, an actor system can spin off millions of actors quietly waiting for an IO request to complete:</p>
<ul>
<li><p>The caller of the actor posts a message and doesn't have to block until that message is processed</p>
</li>
<li><p>It can be notified, via a message, when some data has arrived</p>
</li>
</ul>
<p>This is a great recipe for scalability: a few cores handling millions of requests!</p>
<p>But this is not the only solution to that problem, or, let's say, not the only way to package it. The heart of the solution is to have some sort of "continuation": what should I do when some data finally arrives?</p>
<p>Nowadays there are many other alternatives than actors for dealing with such continuations:</p>
<ul>
<li><p><a target="_blank" href="https://docs.scala-lang.org/overviews/core/futures.html#callbacks">Futures</a> in Scala</p>
</li>
<li><p><a target="_blank" href="https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html">async/await</a> in Rust</p>
</li>
<li><p><a target="_blank" href="https://hackage.haskell.org/package/async-2.2.4/docs/Control-Concurrent-Async.html">async and monads</a> in Haskell</p>
</li>
<li><p>async runtimes in Scala: <a target="_blank" href="https://typelevel.org/cats-effect/">cats effect</a> and <a target="_blank" href="https://zio.dev/">ZIO</a></p>
</li>
</ul>
<p>The major difference between these approaches and actors is the fact that they don't expose a programming model made of <code>A =&gt; Unit</code> functions. With a <code>Future</code> you make as if you already had the value you're waiting on and you <a target="_blank" href="https://docs.scala-lang.org/overviews/core/futures.html#functional-composition-and-for-comprehensions"><code>map</code> it to describe what to do next</a>. Now the flow of data between computations is obvious <em>and</em> computing resources are used wisely. We will come back to that later.</p>
<h1 id="heading-actors-as-top-models">Actors as top-models</h1>
<blockquote>
<p>According to <a target="_blank" href="https://en.wikipedia.org/wiki/Carl_Hewitt">Carl Hewitt</a>, unlike previous models of computation, the actor model was inspired by <a target="_blank" href="https://en.wikipedia.org/wiki/Physics">physics</a>, including <a target="_blank" href="https://en.wikipedia.org/wiki/General_relativity">general relativity</a> and <a target="_blank" href="https://en.wikipedia.org/wiki/Quantum_mechanics">quantum mechanics</a>.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Actor_model">https://en.wikipedia.org/wiki/Actor_model</a></p>
</blockquote>
<p>Actors are a tool of choice to represent independent entities when they have their own internal state and interfaces. For example, it seems quite natural to <a target="_blank" href="https://www.youtube.com/watch?v=FIVIviN-ets">model a game like Halo with an actor system</a> (using Microsoft's <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/orleans/">Orleans platform</a>).</p>
<p>Moreover, we can use state machines to represent:</p>
<ul>
<li><p>The internal state of an actor as some state variables</p>
</li>
<li><p>The received messages as state events</p>
</li>
<li><p>The processing of messages as transitions in the state machine</p>
</li>
</ul>
<p>This is wonderful because there exist a large number of tools to:</p>
<ul>
<li><p>Represent state machines</p>
</li>
<li><p>Reason about them: are there unreachable states? Will we always arrive at an end state? Are we missing some events?</p>
</li>
<li><p>Test states machines: what is the minimal number of tests covering each state?</p>
</li>
</ul>
<p>However, any time we have several independent systems collaborating, we also get a combinatorial explosion in complexity. Each local state might be well specified, but the overall combination of all states might exhibit some emergent behavior that we did not expect. Think about how the <a target="_blank" href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Game of Life</a> generates amazing behaviors out of very simple cells.</p>
<h2 id="heading-not-every-system-is-a-physics-simulation">Not every system is a physics simulation</h2>
<p>The thing is, many of our systems do not need to be represented as small individual processes. And the fewer states we need to maintain, the better off we are.</p>
<p>The least amount of state is a pure function. Look ma', no state:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute_taxes</span></span>(income: Amount) -&gt; Amount
</code></pre>
<p>Yet it is not always practical, or even possible, to compute only with non-stateful functions. It would be quite repetitive to pass around all the state required for computations:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute_taxes</span></span>(
   income: Amount, 
   tax_rules: TaxRules,
   previous_tax_paid: <span class="hljs-built_in">Vec</span>&lt;Amount&gt;) -&gt; Amount
</code></pre>
<p>Worse, it is not even desirable. There are implementation details that we wish to hide, like the fact that the tax algorithm is parameterized by rules or that it uses the amount of taxes paid in the previous year to calculate this year's taxes.</p>
<p>In any case, even if we end up with a function having some side effects, by enclosing some state, we are still in a better position than when using actors. Because <strong>functions give us a flow of data</strong>. "Something in, something out". And the "something out" is ready to become "something in" for another function.</p>
<p>It is not entirely by accident if <a target="_blank" href="https://doc.akka.io/docs/akka/current/stream/stream-introduction.html#motivation">an Actor system like Akka ended up proposing a <code>Stream</code> abstraction</a>:</p>
<blockquote>
<p>We have found it tedious and error-prone to implement all the proper measures in order to achieve stable streaming between actors, since in addition to sending and receiving we also need to take care to not overflow any buffers or mailboxes in the process. Another pitfall is that Actor messages can be lost and must be retransmitted in that case. Failure to do so would lead to holes at the receiving side</p>
</blockquote>
<p>For me, this is thinking backward:</p>
<ol>
<li><p>"Let's start with a general system where we can do everything"</p>
</li>
<li><p>"Let's constrain our system by adding another layer"</p>
</li>
</ol>
<p>In some ways you can see a similar issue with dynamic vs. static typing in programming languages:</p>
<ol>
<li><p>"Haha, no pesky compiler to prevent me from treating this variable as an <code>int</code> here and a <code>bool</code> there. It just works. Why would I care?"</p>
</li>
<li><p>"Oops my system is really hard to understand, give me types please":</p>
<ol>
<li><p>for Python: <a target="_blank" href="https://mypy-lang.org/">https://mypy-lang.org</a></p>
</li>
<li><p>for Javascript: <a target="_blank" href="https://www.typescriptlang.org/">https://www.typescriptlang.org</a></p>
</li>
<li><p>for Ruby: <a target="_blank" href="https://sorbet.org/">https://sorbet.org</a></p>
</li>
</ol>
</li>
</ol>
<p>In the words of Runàr Bjarnason</p>
<blockquote>
<p>Constraints liberate, liberties constraint</p>
<p>very relevant talk excerpt: <a target="_blank" href="https://youtu.be/GqmsQeSzMdw?t=1452">https://youtu.be/GqmsQeSzMdw?t=1452</a></p>
</blockquote>
<h1 id="heading-im-tolerant-to-a-fault">I'm tolerant. To a fault.</h1>
<p>One often-cited advantage of actor systems is the idea that those systems can be made fault-tolerant. How does that work?</p>
<p><img src="https://i0.wp.com/www.putertutor.co.uk/wp-content/uploads/2022/03/turn-it-off-and-on-again.jpg?fit=602%2C328&amp;ssl=1" alt="Turn it off and on again! | The PuterTutor Computer Repair Services" /></p>
<p>No really, that's it. If some state ends up being corrupted in an actor, a sensible strategy is to start afresh. And if several actors are cooperating to accomplish any task it makes sense to restart all of them to ensure that their global state is correct.</p>
<p>This is the role of <code>Supervisors</code> in a system like Erlang/OTP or Akka. Since actors can spawn other actors, an actor system defines a tree of actors in a parent/child relationship. At each level, we can associate a supervisor. In case of a failure of an actor at that level it can decide to:</p>
<ul>
<li><p>Restart that actor</p>
</li>
<li><p>Restart all the actors on that level</p>
</li>
<li><p>Propagate the failure one level up</p>
</li>
</ul>
<p>This way of dealing with faults is efficient for two reasons:</p>
<ol>
<li><p>It addresses some common reasons for failures: incorrect state, maxed-out internal queue, or unreachable resources.</p>
</li>
<li><p>It allows the definition of independent processes or sub-processes that can be restarted individually thus containing errors to a limited part of the system</p>
</li>
</ol>
<h2 id="heading-magic-wand-again">Magic wand again?</h2>
<p>I think we must not conflate the problem with the solution. Ideally, we want to</p>
<ol>
<li><p>Avoid inconsistent state</p>
</li>
<li><p>Isolate failures</p>
</li>
</ol>
<p>The first point should foremost be addressed by having a minimal amount of state and being able to reason about it. We don't want to end up with a database like Oracle where <a target="_blank" href="https://news.ycombinator.com/item?id=18442941">the fix to some combinatorial state issue is to add even more states</a>!</p>
<p>If an actor fails deterministically with some corrupted state, you might restart it 100 times, you will still get the same result. The "<a target="_blank" href="https://wiki.c2.com/?LetItCrash">Let it crash!</a>" motto seems to me to be a way of saying "Let us acknowledge that our system is so complex that we will enter some undefined states. Hopefully turning it off/on will work 🙏".</p>
<p>It is easy to understand that this cannot be the only strategy to tame the complexity related to state management. <strong>Yet, actors, as a network of interacting state machines, encourage a combinatorial explosion of state</strong>!</p>
<p>The second condition, "isolate failures", also does not come out magically from supervisors. Maybe a hundred actors represent individuals in a chat room but if one of them can make the whole chat room fail, the whole system fails. We need to carefully understand the functions of our system and their dependencies to be able to isolate them. <strong>Yet, actors, by being able to start other actors and communicate with them, hide the functional dependencies of our systems</strong>!</p>
<p>Eventually, it seems to me that the main benefit of supervisors is to force us to think about error modes and how to address them.</p>
<h1 id="heading-can-we-do-better">Can we do better?</h1>
<p>I think so. We don't have to reinvent the wheel. We have ways to program differently for a vast category of systems. I would describe those systems as "linear".</p>
<h2 id="heading-the-communication-graph-is-not-always-complete">The communication graph is not always complete</h2>
<p>A "Linear" system is a system where data flows almost exclusively in one direction (think "activity diagram" in UML). Such a system:</p>
<ul>
<li><p>Accepts a request, possibly after a round of negotiation, authentication, and authorization. Alternatively, they pull out some event from a queue</p>
</li>
<li><p>Process the request or event data in several steps, possibly incorporating some local persisted state</p>
</li>
<li><p>Update their local state</p>
</li>
<li><p>Publish events for other systems to consume</p>
</li>
<li><p>Send back a response</p>
</li>
</ul>
<p>In a linear system:</p>
<ul>
<li><p>There is a clear direction of data, which makes progress mostly in one direction</p>
</li>
<li><p>Data comes front and center, the identity of its processor is less important</p>
</li>
<li><p>There is some level of independence between each request and how they are processed</p>
</li>
<li><p>Concurrency or asynchronism is desirable, especially if IO is involved</p>
</li>
<li><p>Parallelism is desirable if some processes are CPU intensive (cryptographic operations, numerical computations)</p>
</li>
</ul>
<p>Examples of linear systems include many forms of web services, APIs, or even point-to-point communications. Non-linear systems are typically multi-player games like Halo4 or group chat applications like WhatsApp and Discord.</p>
<h2 id="heading-the-future-is-already-there">The <code>Future</code> is already there</h2>
<p>I hinted earlier that actors have been successful at a moment where asynchronous computing was sorely needed. Yet, actors are not the only solution to that problem. Case in point, the Actix web framework in Rust. It used to be built on an actor library, but:</p>
<blockquote>
<p>its usefulness as a general tool is diminishing as the futures and async/await ecosystem matures</p>
<p><a target="_blank" href="https://actix.rs/docs/whatis/">https://actix.rs/docs/whatis</a></p>
</blockquote>
<p>Indeed futures and <code>async</code> support in our programming languages and libraries give us all the support we need. We actually get a lot more:</p>
<ul>
<li><p>We get types. A computation <code>Future&lt;T&gt;</code> produces a value of type <code>T</code></p>
</li>
<li><p>We get combinators to process the value <code>future.map(f)</code>. We know what is the type of the resulting value!</p>
</li>
<li><p>We get combinators to run processes concurrently and, for example, take the first value that succeeds in being computed <code>give_me_first_available_quote</code></p>
</li>
<li><p>We get a lot closer to structured concurrency which allows us to reason about errors and resources in a concurrent setting. You can read more about this in the fabulous blog post "<a target="_blank" href="https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/#id1">go statement considered harmful</a>".</p>
</li>
</ul>
<h2 id="heading-theres-blocking-and-blocking">There's blocking and <em>blocking</em></h2>
<p>Great, it seems that we solve the question of blocking while still being able to read our code as a series of typed transformations of data. What solving the issues with inconsistent state that actors solve with their message queue?</p>
<p>One obvious solution is to introduce locks to protect resources and guarantee their atomic update:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Bank</span></span> {
  accounts: RwLock&lt;<span class="hljs-built_in">Vec</span>&lt;Account&gt;&gt;
}

<span class="hljs-keyword">impl</span> Bank {
  <span class="hljs-keyword">pub</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">transfer</span></span>(
    amount: Amount,
    from: Account,
    to: Account) -&gt; <span class="hljs-built_in">Result</span>&lt;(), TransferError&gt; {
    <span class="hljs-keyword">let</span> accounts = accounts.unlock();
    ...   
  }
}
</code></pre>
<p>Compared to the actor example:</p>
<ul>
<li><p>Calls to <code>transfer</code> are serialized so the data will be consistent</p>
</li>
<li><p>We don't have to reify the <code>transfer</code> function into a full data type</p>
</li>
<li><p>A caller waiting for its <code>transfer</code> action to be processed will not consume any major resource system, like a thread. The async runtime will park that computation until it is ready to proceed and continue</p>
</li>
<li><p>We lose the full asynchronicity. Maybe the caller was truly not interested in the result of the transfer.</p>
</li>
</ul>
<p>The last point seems to be a problem. Previously the caller of an actor was able to just leave a message and then could go away and process its own messages. Now, the caller of the <code>transfer</code> function has to block until the underlying resource is free to be updated. This might not block a thread but this will still prevent the function caller from doing anything else useful. I'll come back to that soon.</p>
<p><strong>Note</strong>: I am aware that locks come with <a target="_blank" href="https://en.wikipedia.org/wiki/Lock_(computer_science)#Granularity">their own set of pitfalls</a>!</p>
<h2 id="heading-stateful-components">Stateful components</h2>
<p>A set of <code>async</code> functions operating on some shared data can be regrouped in a component:</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">ReviewComittee</span></span> {
   <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">propose_talk</span></span>(name: Name, talk: Talk) -&gt; <span class="hljs-built_in">Result</span>&lt;Acceptance&gt;;
   <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">withdraw_talk</span></span>(name: Name, talk: Talk) -&gt; <span class="hljs-built_in">Result</span>&lt;()&gt;;
   <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_final_talks</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;Talk&gt;&gt;;
}
</code></pre>
<p>That component might be the source of data for another component:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> Accepted(talk) = committee.propose_talk(
    eric, 
    turning_actors_inside_out).<span class="hljs-keyword">await</span>?) {
    scheduler.schedule(talk).<span class="hljs-keyword">await</span>?   
}
</code></pre>
<p>If we lock the internal state of the <code>ReviewCommitee</code> and use <code>async</code> functions we don't need actors. Actually, <a target="_blank" href="https://github.com/WhiteRookPL/learn-elixir-the-hard-way/blob/master/docs/concurrency-and-actor-model.md#there-is-hope-enter-the-otp">this is not different from what <code>GenServer</code> is doing, on top of actors, in Elixir</a>!</p>
<pre><code class="lang-elixir"><span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">ReviewCommittee</span></span> <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">use</span> GenServer

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_call</span></span>({<span class="hljs-symbol">:propose_talk</span>, name, talk}, _from, talks) <span class="hljs-keyword">do</span>
    {<span class="hljs-symbol">:reply</span>, <span class="hljs-symbol">:accepted</span>, talk | talks}
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_call</span></span>(<span class="hljs-symbol">:get_final_talks</span>}, _from, talks) <span class="hljs-keyword">do</span>
    {<span class="hljs-symbol">:reply</span>, talks, talks}
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_cast</span></span>({<span class="hljs-symbol">:withdraw_talk</span>, name, talk}, state) <span class="hljs-keyword">do</span>
    {<span class="hljs-symbol">:noreply</span>, ...}
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>The documentation says:</p>
<blockquote>
<p>We can primarily interact with the server by sending two types of messages. call messages expect a reply from the server (and are therefore synchronous) while cast messages do not.</p>
</blockquote>
<p>With <code>GenServer</code> we get the same benefits as a stateful component in <code>async</code> languages and the same constraints. But we lose types and have to consider the fact that the implementation can spawn other <em>independent</em> processes that we won't know about.</p>
<h2 id="heading-turning-actors-inside-out">Turning actors inside-out</h2>
<p>One other interesting viewpoint for linear systems is to see them as stream-processing systems. I wrote earlier that actors have this non-blocking mode of interaction where an actor can just leave a message for another actor and go on with his day. This is a way of saying: "Here is a bit of information you might be interested in, do whatever you want to do with it, I don't care".</p>
<p>We can invert that pattern and have components that say: "I am producing a piece of information, take it if you want". Essentially have a producer-consumer pattern.</p>
<p>This pattern introduces a level of indirection, like actors do. We now need to create data types to encapsulate the kind of information we want to communicate between computations. But the intent is very different! Instead of creating a message that says "schedule this talk" we create a <em>fact</em> saying "this talk was approved".</p>
<p>We can now have streams of facts that we can transform, join, store, reuse etc... This idea is very well presented by the wonderful talk from Martin Kleppmann, "<a target="_blank" href="https://martin.kleppmann.com/2015/03/04/turning-the-database-inside-out.html">Turning the database inside-out</a>".</p>
<p>By turning actors inside out as publishers and subscribers we get amazing powers:</p>
<ul>
<li><p>We get back types: A <code>Subscriber&lt;T&gt;</code> can only subscribe to a <code>Producer&lt;T&gt;</code>. Our software components now come with a manual on how to assemble them!</p>
</li>
<li><p>We get combinators: I can <code>map</code> a <code>Producer&lt;T&gt;</code> with a function <code>T -&gt; S</code> to get a <code>Producer&lt;S&gt;</code> (and <code>contramap</code> a <code>Subscriber&lt;T&gt;</code> with a function <code>S -&gt; T</code> to get a <code>Subscriber&lt;S&gt;</code>)</p>
</li>
<li><p>We decouple our software: a <code>Producer</code> truly doesn't have to know about its <code>Subscriber</code>s. Whereas actors have to know about each other</p>
</li>
<li><p>We get <a target="_blank" href="https://www.reactive-streams.org">a full specification on how to deal with gnarly problems like cancellation and backpressure</a></p>
</li>
</ul>
<h1 id="heading-final-scene">Final scene</h1>
<p>I don't want to dismiss all the great work that has been done by Erlang/Elixir, and Akka users around the world. People have built large and successful systems with these technologies. Besides, the Erlang VM has some impressive features for distribution and hot code replacement, which are worth considering.</p>
<p>I believe however that the actor model is way too dynamic and untyped for many of the data-oriented systems that we are building every day. The same can be said, in my opinion, about dynamic programming languages. We can do amazing things with a language like <a target="_blank" href="https://racket-lang.org/">Racket</a>, but the safety net and discoverability of Haskell (cf. <a target="_blank" href="https://hoogle.haskell.org">Hoogle</a>) is preferable in many cases. <a target="_blank" href="https://twitter.com/newhoggy/status/1693835877489983750">In the words of John Ky</a>:</p>
<blockquote>
<p>Static typing is Lego, dynamic typing is playdough</p>
</blockquote>
<p>Which I would steal as</p>
<blockquote>
<p>Reactive streams are Lego, actors are playdough</p>
</blockquote>
<p>As far as I'm concerned, I prefer building with Legos 😊.</p>
]]></content:encoded></item><item><title><![CDATA[Why Rust does not need variance annotations]]></title><description><![CDATA[I have now heard twice (the last time was in that podcast) that Rust does not need variance annotations for generics because it has lifetime annotations.
This sentence can be quite puzzling for someone coming from a language like Scala, or for a Rust...]]></description><link>https://etorreborre.blog/why-rust-does-not-need-variance-annotations</link><guid isPermaLink="true">https://etorreborre.blog/why-rust-does-not-need-variance-annotations</guid><category><![CDATA[Scala]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Types]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Mon, 25 Sep 2023 09:37:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/hG26UoUfU9s/upload/b3d354c5c37c3866ae7cd364a0667199.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have now heard twice (the last time was in <a target="_blank" href="https://podcasts.apple.com/cz/podcast/85-scala-rust-and-durable-computing-with-john-de-goes/id1531666706?i=1000628044679">that podcast</a>) that Rust does not need variance annotations for generics because it has lifetime annotations.</p>
<p>This sentence can be quite puzzling for someone coming from a language like Scala, or for a Rust programmer wondering what the hell variance annotations are.</p>
<p>The thing that immediately came to my mind was "interesting, variance annotations in Scala are there to protect you from performing incorrect assignments when mutating values. On the other hand, Rust has a lifetime system to prevent you from making mistakes with mutations. Certainly, the variance annotations in Scala manifest as lifetimes in Rust then".</p>
<p>The actual situation is that the two situations present some similarities but are, in fact, different.</p>
<h1 id="heading-why-do-we-need-variance-annotations-in-scala">Why do we need variance annotations in Scala?</h1>
<p>Variance in Scala is introduced <a target="_blank" href="https://docs.scala-lang.org/tour/variances.html">here</a>. I will summarize the crux of it with the following code</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Animal</span></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span></span>

<span class="hljs-keyword">val</span> cat: <span class="hljs-type">Cat</span> = <span class="hljs-type">Cat</span>()
<span class="hljs-keyword">val</span> animal: <span class="hljs-type">Animal</span> = cat

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Box</span>[<span class="hljs-type">T</span>](<span class="hljs-params">t: <span class="hljs-type">T</span></span>)</span>

<span class="hljs-keyword">val</span> boxedCat: <span class="hljs-type">Box</span>[<span class="hljs-type">Cat</span>] = <span class="hljs-type">Box</span>(cat)
<span class="hljs-keyword">val</span> boxedAnimal: <span class="hljs-type">Box</span>[<span class="hljs-type">Animal</span>] = boxedCat
</code></pre>
<p>In the code above we are very tempted to say that a <code>Box[Cat]</code> is a <code>Box[Animal]</code> because a <code>Cat</code> is an <code>Animal</code>. But Scala, by default, <a target="_blank" href="https://scastie.scala-lang.org/3pvebS0YRvmOIHg5xQMC6A">will not allow it</a>. If we want to let a <code>Box[Cat]</code> be a <code>Box[Animal]</code> we have to declare <code>Box[T]</code> with a <code>+</code> annotation</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Box</span>[+<span class="hljs-type">T</span>](<span class="hljs-params">t: <span class="hljs-type">T</span></span>)</span>
</code></pre>
<p><code>+</code> means that <code>Box</code> is now "<strong>covariant</strong>" in <code>T</code>:</p>
<ul>
<li><p>if <code>S &lt;: T</code>, "S is a subtype of T"</p>
</li>
<li><p>then <code>Box[S] &lt; Box[T]</code>, "Box[S] is a subtype of Box[T]" or "everywhere a <code>Box[T]</code> is accepted, a <code>Box[S]</code> can be provided"</p>
</li>
</ul>
<p>But <strong>now</strong>, there is something else that we cannot do. We cannot mutate the content of <code>Box</code>. We cannot declare the following</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Box</span>[+<span class="hljs-type">T</span>](<span class="hljs-params">var t: <span class="hljs-type">T</span></span>)</span>
</code></pre>
<p>This would break type soundness as shown in this example:</p>
<pre><code class="lang-scala"><span class="hljs-keyword">val</span> boxedCat: <span class="hljs-type">Box</span>[<span class="hljs-type">Cat</span>] = <span class="hljs-type">Box</span>(cat)
<span class="hljs-keyword">val</span> boxedAnimal: <span class="hljs-type">Box</span>[<span class="hljs-type">Animal</span>] = boxedCat

<span class="hljs-comment">// why not, since a Dog is an Animal?</span>
boxedAnimal.t = <span class="hljs-type">Dog</span>()

<span class="hljs-comment">// Oh no the cat became a dog!</span>
<span class="hljs-keyword">val</span> cat: <span class="hljs-type">Cat</span> = boxedCat.t
</code></pre>
<p>So the point of variance annotations is to be able to declare the developer's intention concerning subtyping and rule out some possibilities that would not be typesafe.</p>
<p>Maybe as a Rust developer, you might have noticed that :</p>
<ul>
<li><p>the "bad" example involves mutation</p>
</li>
<li><p>it also involves maintaining a reference to a structure mutated "by someone else"</p>
</li>
</ul>
<p>Isn't there a whole type system in Rust devoted to making mutations safe? Is it what this is about here? Yes and no :-).</p>
<h1 id="heading-what-does-variance-mean-in-rust">What does variance mean in Rust?</h1>
<p>It is not entirely obvious to talk about variance in Rust when trying to come up with a similar example. For a simple reason: Rust does not have "<strong>a subtyping relationship for types</strong>". There is no way to declare a type <code>Animal</code>, a type <code>Cat</code> and declare that <code>Cat</code> is a subtype of <code>Animal</code>, allowing a <code>Cat</code> to be used anywhere an <code>Animal</code> is expected.</p>
<p>You can declare an <code>Animal</code> <strong>trait</strong>, a <code>Cat</code> <strong>struct</strong>, and have <code>Cat</code> <em>implements</em> <code>Animal</code>. But this is not a subtyping relationship.</p>
<p>In that sense it is meaningless to think that there could be variance annotations for collections in Rust because there is simply no subtyping relationship for types!</p>
<p>Why do I insist on "for types"? Because there <em>is</em> a subtyping relationship for lifetimes in Rust. If you consider a lifetime as "the section of the code for which a given value exists" it is easy to picture that some sections can be included in others.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695632165792/4eee9082-4688-4884-ad71-fc27c40b5dc5.png" alt class="image--center mx-auto" /></p>
<p>The subtyping relationship, <code>'a &lt;: 'b</code> means "everywhere you accept values with a lifetime <code>'b</code> then you should accept values with lifetime <code>'a</code>. For this to work it is not hard to see that the lifetime <code>'a</code> must be a code section containing the code section for the lifetime <code>'b</code>. If you think about types as being "sets of values" this is a <em>similar but inverted situation</em>:</p>
<ul>
<li><p>A type <code>A</code> is a subtype of a type <code>B</code> if its set of values is contained in the set of values for be =&gt; the subtype is the <strong>smaller</strong> set</p>
</li>
<li><p>A lifetime <code>'a</code> is a subtype of a lifetime <code>'b</code> if the active code section of <code>'b</code> is contained in the one for <code>'a</code> =&gt; the subtype is the <strong>greater</strong> set</p>
</li>
</ul>
<p>We can now use this notion of subtyping to reason about some of the possible substitutions in Rust. For example, if a parameter is of the form <code>&amp;'a T</code> then you can always pass a <code>&amp;'static T</code>. That's because:</p>
<ul>
<li><p>the Rust compiler knows that the declaration <code>&amp;'a T</code> is covariant in the lifetime <code>'a</code>. Any <code>&amp;'b T</code> can be accepted as long as <code>'b &lt;: 'a</code></p>
</li>
<li><p><code>'static &lt;: 'a</code> "the 'static lifetime is the largest one"</p>
</li>
</ul>
<p>It is easy to see what would happen if the compiler did not check those rules:</p>
<ul>
<li><p>you could pass a value with a more restricted lifetime than <code>'a</code></p>
</li>
<li><p>then free the value while it is still needed in the scope delimited by <code>'a</code></p>
</li>
</ul>
<p>There is a table <a target="_blank" href="https://doc.rust-lang.org/nomicon/subtyping.html">in the Rustonomicon describing all those rules</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695633124762/19418fff-f88f-4464-8c90-f6fe1007fffa.png" alt class="image--center mx-auto" /></p>
<p>That table is quite confusing though. It shows situations where <code>T</code> can be considered "covariant" or "contravariant", or "invariant". Didn't we say that variance is related to subtyping and that there's no subtyping relationship for types in Rust?</p>
<p>If you are confused, and I am too, this is normal, <a target="_blank" href="https://github.com/rust-lang/nomicon/issues?q=is%3Aissue+subtyping">you are not the first one</a> :-). What is not particularly well explained is the fact that types <em>can also be generic in terms of lifetimes</em>!</p>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MyBox</span></span>&lt;<span class="hljs-symbol">'a</span>, T&gt; { t: &amp;<span class="hljs-symbol">'a</span> T }
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MyHyperBox</span></span>&lt;<span class="hljs-symbol">'b</span>, T&gt; { t: &amp;<span class="hljs-symbol">'b</span> MyBox&lt;<span class="hljs-symbol">'b</span>, T&gt; }

<span class="hljs-keyword">let</span> my_box = MyBox { t: &amp;<span class="hljs-number">1</span> }; 

{
    <span class="hljs-keyword">let</span> my_hyperbox: MyHyperBox&lt;<span class="hljs-built_in">u32</span>&gt; = MyHyperBox { t: &amp;my_box };
}
</code></pre>
<p>In this example, <code>my_hyperbox</code> has a short lifetime but can still contain a value with a type annotated by a larger lifetime and the substitution works.</p>
<h1 id="heading-in-conclusion">In conclusion</h1>
<p>What we are seeing in Scala and Rust is not the exact same situation just translated from one language to another. We are observing:</p>
<ul>
<li><p>the possibility of subtyping relationships which make substituting expressions easier in our programs</p>
</li>
<li><p>the type-checking rules that have to be enforced by the compiler to make sure that types in our programs stay consistent</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Why you should flox every day]]></title><description><![CDATA[I want to share a very valuable tool that I have been using for almost a year now: flox.
How I avoided nix for so long
I never had a strong desire to completely control the software running on my machine. I was more focused on setting up an environme...]]></description><link>https://etorreborre.blog/why-you-should-flox-every-day</link><guid isPermaLink="true">https://etorreborre.blog/why-you-should-flox-every-day</guid><category><![CDATA[development]]></category><category><![CDATA[tools]]></category><category><![CDATA[package manager]]></category><category><![CDATA[flox ]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Sun, 17 Sep 2023 12:57:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/4SUyx4KQ5Ik/upload/f778aefaf2018c6c0780a727bf790ebf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I want to share a very valuable tool that I have been using for almost a year now: <code>flox</code>.</p>
<h1 id="heading-how-i-avoided-nix-for-so-long">How I avoided nix for so long</h1>
<p>I never had a strong desire to completely control the software running on my machine. I was more focused on setting up an environment quickly and then dedicating all my time to developing software. However, this approach came at a cost. Every time I switched companies, I had to set up a brand-new computer and reinstall all my software. Typically, this meant a few days of frustration, but it also allowed me to clear out all the accumulated clutter from my previous job.</p>
<p>I was envious though of those people who were re-installing their computer in a matter of minutes, dot files, system libraries, development environments, etc...</p>
<p>Some of them had a secret trick for this: <a target="_blank" href="https://nixos.org/">Nix</a>.</p>
<p>Nix should have been appealing to me as a functional programmer, given its features like immutable deployments, isolation, easy rollbacks, and more. However, Nix had a reputation for being difficult to understand, challenging to use, and constantly evolving.</p>
<p>Ian Henry's "<a target="_blank" href="https://ianthehenry.com/posts/how-to-learn-nix/">How to Learn Nix</a>" is an excellent rendition of some of those difficulties. I could <em>feel in my bones</em> the kind of rabbit hole that learning Nix would be. Is it worth the loss of a few days every few years?</p>
<p>If I'm being honest, it was more than that. In my previous job, we had a mixture of technologies: Haskell, Go, Python, Postgres, etc. Even using some cryptographic libraries in Python meant building Rust code! As a result, my development environment started breaking much more frequently. Every month or so, some system library would be missing, <code>python</code> wouldn't be the right version anymore, and my <code>PATH</code> would become a mess. Nix was becoming increasingly compelling...</p>
<h1 id="heading-it-doesnt-have-to-be-hard">It doesn't have to be hard</h1>
<p>With <code>flox</code> I can create several environments:</p>
<ul>
<li><p><code>dotfiles</code> for my <code>zsh</code> configuration</p>
</li>
<li><p><code>default</code> for my common day-to-day tools</p>
</li>
<li><p><code>scala</code> for my open-source Scala projects</p>
</li>
<li><p><code>haskell</code> for my open-source Haskell projects</p>
</li>
<li><p><code>rust</code> for my open-source Rust projects</p>
</li>
<li><p><code>ockam</code> for my project at work</p>
</li>
</ul>
<p>My <code>.zshrc</code> configuration file now is simply:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(flox activate -e flox/default)</span>"</span>
<span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(flox activate -e dotfiles)</span>"</span>
</code></pre>
<p>This starts the <code>flox/default</code> environment giving me access to the latest version of <code>flox</code>, then my <code>dotfiles</code> environment.</p>
<p>The <code>activate</code> command:</p>
<ul>
<li><p>grabs the packages defined in the environment from a nix packages repository, builds them, and caches them locally (so that it is only slow the first time)</p>
</li>
<li><p>puts the binaries included in those packages on the <code>PATH</code></p>
</li>
</ul>
<h1 id="heading-dot-files">Dot files</h1>
<p>What is in my <code>dotfiles</code> environment? We can have a look at it with the <code>edit</code> command:</p>
<pre><code class="lang-bash">&gt; flox edit -e dotfiles
{
  shell.hook = <span class="hljs-string">''</span>
    <span class="hljs-built_in">export</span> ZDOTDIR=<span class="hljs-variable">$HOME</span>/.dotfiles
    <span class="hljs-built_in">exec</span> zsh --no-globalrcs
  <span class="hljs-string">''</span>;
  packages.nixpkgs-flox.zsh = {};
  packages.nixpkgs-flox.starship = {};
}
</code></pre>
<p>The <code>dotfiles</code> environment exports the <code>ZDOTDIR</code> variable and starts <code>zsh</code>.</p>
<p>The <code>ZDOTDIR</code> variable points to <code>$HOME/.dotfiles</code> directory, which is versioned with Github. That directory contains all the files used in my <code>.zsh</code> configuration.</p>
<p>I am also fetching the fabulous <a target="_blank" href="https://starship.rs/"><code>starship</code> prompt</a>, which, with a bit of configuration, allows me to display the currently activated <code>flox</code> environments</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694947952890/b15f400e-54d3-41d5-85f4-8445ecba7343.png" alt class="image--center mx-auto" /></p>
<p>I now have:</p>
<ul>
<li><p>versioned dot files,</p>
</li>
<li><p>which can be easily reinstalled if I use a new computer</p>
</li>
</ul>
<h1 id="heading-the-many-tools-of-the-trade">The many tools of the trade</h1>
<p>Wait! Where does the additional <code>default</code> environment come from? This environment is activated by the <code>$HOME/.dotfiles/.zshrc</code> configuration file. It contains all the tools I rely on to be effective at my job. For example the ultra-fast versions of <code>grep</code> and <code>find</code> (<code>rg</code> and <code>fd</code>, implemented in Rust).</p>
<p><code>flox list -e default</code> provides the whole list:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694948415321/912ff515-e705-4581-ae0e-eb130e066541.png" alt class="image--center mx-auto" /></p>
<p>Several things to mention about this list:</p>
<ul>
<li><p>this is the 101st generation! I have frequently modified this list. <code>flox</code> can actually list all the modifications since it was created. I can also revert to any previous version if I want to</p>
</li>
<li><p>all the usual suspects can be found in that list: <code>git</code>, <code>rg</code>, <code>tree</code>, etc... There is a very high chance that if you need an executable, you will find it by searching <a target="_blank" href="https://search.nixos.org/packages">the nix packages</a></p>
</li>
<li><p>some packages come from my own repositories. I published what was missing, using, ... <code>flox</code></p>
</li>
</ul>
<h1 id="heading-publishing-the-rest">Publishing the rest</h1>
<p>For example, the excellent <a target="_blank" href="https://github.com/smallhadroncollider/cmt"><code>cmt</code> tool</a> allows you to use a template to format your commit messages (respecting the <a target="_blank" href="https://www.conventionalcommits.org/en/v1.0.0/">conventionalcommits standard</a> if you want to)</p>
<p><img src="https://github.com/smallhadroncollider/cmt/raw/master/docs/cmt-0.7.gif" alt="Demo" /></p>
<p>This is a tool that I use every day but it does not exist as a <code>nix</code> package. So I published it myself!</p>
<p>I forked the original repository and ran <code>flox init</code> to make it a flox project:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1694949284391/a680b81b-5974-4ca7-bc7c-db24735026f9.png" alt /></p>
<p>There is no pre-packaged project template for Haskell (which is how <code>cmt</code> is implemented), so I used <code>package-simple</code>.</p>
<p>This is where I had to learn more about Nix, so I could understand how to build the project. <code>cmt</code> is a small Haskell project so building it is not particularly involved</p>
<pre><code class="lang-bash">❯ cat pkgs/commit-tool/default.nix                                                                                                                                                                                                                                    dotfiles flox/default default
{ self, pkgs, stdenv, lib, haskellPackages }:
with haskellPackages;
  mkDerivation rec {
    pname = <span class="hljs-string">"cmt"</span>;
    version = <span class="hljs-string">"0.7.1.1"</span>;
    src = ../../.;
    isExecutable = <span class="hljs-literal">true</span>;
    libraryHaskellDepends = [
      ansi-terminal attoparsec base classy-prelude containers directory
      file-embed filepath process terminal-size text
    ];
    executableHaskellDepends = [ base classy-prelude ];

    doHaddock = <span class="hljs-literal">false</span>;
    doCheck = <span class="hljs-literal">false</span>;

    homepage = <span class="hljs-string">"https://github.com/smallhadroncollider/cmt#readme"</span>;
    description = <span class="hljs-string">"Write consistent git commit messages"</span>;
    license = lib.licenses.bsd3.spdxId;
    mainProgram = <span class="hljs-string">"cmt"</span>;
  }
</code></pre>
<p>The definition above declares that:</p>
<ul>
<li><p>we want to make an executable named <code>cmt</code></p>
</li>
<li><p>sources can be found at <code>../../.</code></p>
</li>
<li><p>the package depends on other Haskell libraries</p>
</li>
</ul>
<p>The next step is to use <code>flox publish</code> to make the package available to everyone. My teammates can subscribe to the repository containing the package and install it in their environment.</p>
<p>But they don't even have to do that!</p>
<h1 id="heading-sharing-is-caring">Sharing is caring</h1>
<p>One great benefit of creating a <code>flox</code> environment is the ability to save it to a Github repository with the <code>flox push</code> command.</p>
<p>This is useful for yourself because, the day you switch to another laptop, you can simply download the environment again with <code>flox pull</code> and be ready in minutes.</p>
<p>This is also particularly useful for teams working on the same project because you can make sure that everyone is always working with the same version of the same tools: <code>postgres</code>, <code>python</code>, <code>jq</code>, etc... thus reducing the risk of "But it works on my machine!".</p>
<p>Another significant benefit of using environments is <strong>their complete isolation</strong>. Activating an environment only adds the executables for that specific environment to the <code>PATH</code>. When you exit the environment, everything is removed. You have complete control over what is in scope.</p>
<p><strong>Note</strong>: I have been using <code>flox</code> mostly as a package manager to handle "<a target="_blank" href="https://flox.dev/docs/tutorials/managed-environments/">managed environments</a>". There is also a concept of "<a target="_blank" href="https://flox.dev/docs/tutorials/projects/">project environments</a>" where the <code>flox</code> configuration contains everything: how to build, test, release. The command used to enter a project environment is just <code>flox develop</code> in the project directory.</p>
<h1 id="heading-less-typing">Less typing</h1>
<p>One last tip. Having to type <code>flox activate -e scala</code> every time you want to work on a Scala project can become pretty tiresome. The solution to this problem is to use <a target="_blank" href="https://direnv.net/"><code>direnv</code></a>. With <code>direnv</code> you add a <code>.envrc</code> file to your project directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(flox activate -e scala)</span>"</span>
</code></pre>
<p>Every time you <code>cd</code> into the project directory, <code>direnv</code> runs the <code>.envrc</code> file and that activates the right environment. Neat!</p>
<h1 id="heading-getting-some-help">Getting some help</h1>
<p>I encourage you to explore Flox and see how it can assist you in managing all your environments effortlessly. However, when you venture into building and publishing packages you might have to better understand <code>flox</code>'s notion of catalog/channels and know your way around <code>nix</code>. Don't hesitate to leave a message on the <a target="_blank" href="https://discourse.flox.dev/">flox Discourse site</a>, the team is very responsive and friendly!</p>
]]></content:encoded></item><item><title><![CDATA[The pros and cons of listening to book summaries]]></title><description><![CDATA[I have started to listen to book summaries via the Headway app. After a month or so here is a list of the pros and cons.
The pros

The summaries are only 15 minutes long so you know that you can fit one or two book summaries in a short morning walk (...]]></description><link>https://etorreborre.blog/the-pros-and-cons-of-listening-to-book-summaries</link><guid isPermaLink="true">https://etorreborre.blog/the-pros-and-cons-of-listening-to-book-summaries</guid><category><![CDATA[books]]></category><category><![CDATA[book summary]]></category><category><![CDATA[reading]]></category><dc:creator><![CDATA[Eric Torreborre]]></dc:creator><pubDate>Sun, 10 Sep 2023 12:47:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/2JIvboGLeho/upload/f4cc026744f2b97e2420acaf8a486b11.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have started to listen to book summaries via the <a target="_blank" href="https://app.makeheadway.com/">Headway app</a>. After a month or so here is a list of the pros and cons.</p>
<h1 id="heading-the-pros">The pros</h1>
<ul>
<li><p>The summaries are only 15 minutes long so you know that you can fit one or two book summaries in a short morning walk (which is also something I decided to do, to <a target="_blank" href="https://www.nbcnews.com/health/health-news/daily-steps-to-lower-risk-of-death-rcna98754">limit the risks of working remotely</a>)</p>
</li>
<li><p>You get to know quite quickly if a book is worth it or not. Some books, when summarized to their main points, feel absolutely trivial. For example "<a target="_blank" href="https://www.amazon.com/Spys-Guide-Thinking-Kindle-Single-ebook">A Spy's Guide to Thinking</a>" gives you a "brilliant" method: collect data, analyze it, decide, and act. This is not the revelation I was hoping for</p>
</li>
<li><p>You can "read" numerous books on the same topic, which often serves to reinforce a particular point for you. For instance, there are several books centred around the idea that focusing intensely on one thing at a time can be advantageous: <a target="_blank" href="https://www.amazon.com/Focus-Hidden-Excellence-Daniel-Goleman-ebook">Focus</a>, <a target="_blank" href="https://www.amazon.com/ONE-Thing-Surprisingly-Extraordinary-Results-ebook">The One Thing</a>, <a target="_blank" href="https://www.amazon.com/Essentialism-Disciplined-Pursuit-Greg-McKeown-ebook">Essentialism</a>, etc. Similarly, there are many books about habits: <a target="_blank" href="https://www.amazon.com/Atomic-Habits-Proven-Build-Break-ebook">Atomic Habits</a>, <a target="_blank" href="https://www.amazon.com/Eat-That-Frog-Great-Procrastinating-ebook">Eat That Frog</a>, <a target="_blank" href="https://www.amazon.com/Power-Habit-What-Life-Business-ebook">The Power of Habit</a>, and so on.</p>
</li>
<li><p>You can finally get an idea about that "famous book that everyone is talking about": <a target="_blank" href="https://www.amazon.com/4-Hour-Workweek-Expanded-Updated-Cutting-Edge-ebook">The 4-hour Week</a>, <a target="_blank" href="https://www.amazon.com/Habits-Highly-Effective-People-Powerful">7 Habits of Highly Effective People</a>, <a target="_blank" href="https://www.amazon.com/Measure-What-Matters-Google-Foundation">Measure What Matters</a></p>
</li>
</ul>
<h1 id="heading-the-cons">The cons</h1>
<ul>
<li><p>The voice reading the books can be a bit monochord</p>
</li>
<li><p>The worth of certain books lies in the anecdotes they share. Skipping these to reach the main points robs you of the potent emotions that an anecdote can evoke.</p>
</li>
<li><p>Some books are just so dense that trying to summarize them is ridiculous. For example the summary of <a target="_blank" href="https://www.amazon.com/Behave-Biology-Humans-Best-Worst-ebook">Behave</a>, by Robert Sapolsky, which I have otherwise read entirely, is laughable. Not only Robert Sapolsky includes tons of insightful study results in his book but the way he confronts them is possibly the most important message of the book. This is what it means to use science to understand the world (If you want to get a glimpse of the process, go and watch his lectures on "<a target="_blank" href="https://www.youtube.com/watch?v=NNnIGh9g6fA">Introduction to human behaviour</a>")</p>
</li>
<li><p>The quality of the summaries can vary. I wish I could recall the precise example, but one summary stated, "Did you know that only 10,000 hydrogen cars are produced each year?" I'm fabricating this, as it was some not-so-interesting fact. However, what was truly intriguing was the reason behind it: "There isn't enough palladium, and there never will be" (again, making this up).</p>
</li>
<li><p>I tried to "read" a book like <a target="_blank" href="https://www.amazon.com/1984-George-Orwell-ebook">1984</a>. I know, I should have read it entirely before and I'm not proud. Reading the summary is not worth it. It's a bit like reading the plot of a movie on Wikipedia</p>
</li>
<li><p>Even summaries feel like they could be sometimes summarized. <a target="_blank" href="https://www.amazon.com/Ultralearning-Master-Outsmart-Competition-Accelerate">Ultralearning</a> spends 90% of the time telling how great it is to be an ultra-learner, how some people are ultra-learners, oh and wait, did you know that there are benefits to ultra-learning? And then there is one chapter with some real tips on how to do it</p>
</li>
</ul>
<p>In summary (ha! 😀), I believe that book summaries can serve as a helpful method for navigating the landscape of essays. However, they will never replace the time spent reading entire books, nor will they substitute the time dedicated to studying them thoroughly (taking notes, formulating your own questions or summaries, delving deeper into certain sections, etc.).</p>
]]></content:encoded></item></channel></rss>