<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrea</title>
    <description>The latest articles on DEV Community by Andrea (@gurghet).</description>
    <link>https://dev.to/gurghet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F35389%2F6350978b-322c-4e29-9115-e0dff5e99ebe.jpeg</url>
      <title>DEV Community: Andrea</title>
      <link>https://dev.to/gurghet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gurghet"/>
    <language>en</language>
    <item>
      <title>RTO, Return To On-premise</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sun, 21 Dec 2025 19:42:39 +0000</pubDate>
      <link>https://dev.to/gurghet/rto-return-to-on-premise-25f9</link>
      <guid>https://dev.to/gurghet/rto-return-to-on-premise-25f9</guid>
      <description>&lt;h3&gt;
  
  
  How we got there
&lt;/h3&gt;

&lt;p&gt;The advantage of moving to the cloud was always clear: no big CAPEX, just a monthly fee and someone else will provide the compute, the network and everything else. As CTOs began to propose “lift and shift” strategies with an almost Pavlovian response, cloud adoption became the default setting, turning into a buzzword that eventually numbed us. We forgot that, at the end of the day, we were simply running our businesses on someone else's computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agency &amp;amp; Fate Sharing
&lt;/h3&gt;

&lt;p&gt;This numbness is usually interrupted when the “shared” nature of that computer becomes painfully obvious. In 2017, a single bug in a Cloudflare HTML parser leaked the private memory of thousands of unrelated companies into public search engine caches. But if that was a warning regarding privacy, the recent outage was a definitive lesson on availability. When a firewall adjustment intended to mitigate a vulnerability in the React framework was deployed, half of the internet went down because of another parser bug. Why should my shop go down because someone else is using React? There is nothing that any technical leader could have done to prevent that. And don't get me started about the guarantee that your customer data is going to be leaked (but you can blame someone else, right?)&lt;/p&gt;

&lt;h3&gt;
  
  
  What Changed?
&lt;/h3&gt;

&lt;p&gt;In a centralized model, you trade the hassle of hardware for the risk of a blast radius that you cannot control. Luckily, the landscape has fundamentally changed since the early days of cloud migration.  Today, technologies like Kubernetes, Terraform and declarative provisioning principles allow us to treat physical racks exactly like cloud regions. We are no longer managing servers; we are managing manifests. This shift allows us to pack a fully automated, self-healing cloud cluster into an on-premise environment that remains virtually untouched by human hands, controlled entirely by the same gitops workflows used by the big guys.&lt;/p&gt;

&lt;p&gt;We finally have the technical maturity to reject the awkwardness of opening our digital shops in the house of our biggest competitor, as is the case with AWS and e-commerce.&lt;/p&gt;

&lt;p&gt;RTO (Return to On-premise) is a little bit about nostalgia for server racks, but mostly it is about the ability to claim the right to go down because &lt;em&gt;I&lt;/em&gt; fucked up.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>terraform</category>
      <category>self</category>
      <category>hosted</category>
    </item>
    <item>
      <title>Software Engineering for Xenophorms</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Tue, 24 Jun 2025 07:26:38 +0000</pubDate>
      <link>https://dev.to/gurghet/software-engineering-for-xenophorms-40e3</link>
      <guid>https://dev.to/gurghet/software-engineering-for-xenophorms-40e3</guid>
      <description>&lt;p&gt;This is not a guide on how to build xenophorm software, it's just a description of how they do it.&lt;/p&gt;

&lt;p&gt;Every solar cycle this creature awakens and positions itself before a foldable object made of very dense artificial material. It consists of two solid parts joined by a metallic hinge mechanism that allows expansion and collapse. When expanded, the upper section displays pulsating illumination with continuously shifting patterns, while the lower section is covered with small square buttons arranged in orderly rows.&lt;/p&gt;

&lt;p&gt;The being presses these buttons in seemingly random sequences, causing alterations in the luminous patterns above. Its appendage movements are swift and precise - it appears to intuitively know which button to press to achieve specific photon emission configurations. This process continues for many consecutive hours.&lt;/p&gt;

&lt;p&gt;Periodically the being ingests a dark liquid from a cylindrical vessel, after which its movements become more frantic and the luminous patterns shift more rapidly. The substance appears to have pseudoscientific properties that enhance the ritual's intensity.&lt;/p&gt;

&lt;p&gt;The medicine induces loud vocalization such as "compiling," "git push," and "deployment failed" - apparently formulas necessary for proper process execution.&lt;/p&gt;

&lt;p&gt;The surrounding environment contains numerous other rectangular devices, serpentine colored cables, and objects that emit constant humming sounds - likely auxiliary tools for this primitive software creation ritual.&lt;/p&gt;

&lt;p&gt;Well, primitive by our standards, yet surprisingly effective for their level of technological development. They would probably be surprised to discover our much more efficient, yet basic, chorus-driven software engineering, where 300 individuals collectively sing code to a lazy snail, modifying its swaying patterns such that surfaces are imbued with binary saliva trails which, licked by herbivores, cause venom-induced paranoia, leading to Darwinian evolution towards engineering creatures capable of writing the chanted software.&lt;/p&gt;

</description>
      <category>software</category>
      <category>engineering</category>
      <category>satire</category>
    </item>
    <item>
      <title>Tilt: Improving Local Development with Production-Like Environments</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sun, 06 Apr 2025 22:48:11 +0000</pubDate>
      <link>https://dev.to/gurghet/improving-local-development-with-production-like-environments-hhh</link>
      <guid>https://dev.to/gurghet/improving-local-development-with-production-like-environments-hhh</guid>
      <description>&lt;p&gt;After reading about Tilt in "Optimizing Cloud Native Java" by Benjamin Evans, I decided to try it out. Tilt promises to reproduce production stacks for local development with hot reloading capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem Tilt Solves
&lt;/h3&gt;

&lt;p&gt;Local development environments are &lt;strong&gt;often broken&lt;/strong&gt; because they're not part of CI. Despite attempts to include local development setup in CI, it's difficult to maintain. This leads to waiting for CI pipelines to finish or cobbling together commands and port-forwards to test services locally.&lt;/p&gt;

&lt;p&gt;As a developer who relies on &lt;strong&gt;tight feedback loops&lt;/strong&gt; for TDD, having a reliable local environment is &lt;strong&gt;crucial for productivity&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation Example
&lt;/h3&gt;

&lt;p&gt;I tried Tilt with a Node.js project that remotely controls my doorbell. Here's the Tiltfile I created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ext://secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret_create_generic&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Build Docker image from local directory
&lt;/span&gt;&lt;span class="nf"&gt;docker_build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ghcr.io/gurghet/domobot&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Deploy Kubernetes resources
&lt;/span&gt;&lt;span class="nf"&gt;k8s_yaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;infra/namespace.yaml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;k8s_yaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;infra/deployment.yaml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Deploy Mosquitto MQTT broker for local development
&lt;/span&gt;&lt;span class="nf"&gt;k8s_yaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;infra/local/mosquitto.yaml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create Kubernetes secret from local environment variables
&lt;/span&gt;&lt;span class="nf"&gt;secret_create_generic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;domobot-secrets&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;domobot&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;from_env_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.env.local&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configure Mosquitto MQTT broker resource and port forwarding
&lt;/span&gt;&lt;span class="nf"&gt;k8s_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mosquitto&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;port_forwards&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1883:1883&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configure the domobot deployment resource
&lt;/span&gt;&lt;span class="nf"&gt;k8s_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;domobot&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port_forwards&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this single configuration file, I was able to launch a dockerized Node.js app alongside an MQTT broker service with the necessary secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Key Advantage: Instant Updates
&lt;/h3&gt;

&lt;p&gt;The most impressive feature was the &lt;strong&gt;hot reload capability&lt;/strong&gt;. When I fixed a bug in my application code and &lt;strong&gt;simply saved the file&lt;/strong&gt;, Tilt automatically rebuilt the Docker image and updated the Kubernetes deployment &lt;strong&gt;instantly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rjwfv9zef30zdkfbpp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rjwfv9zef30zdkfbpp5.png" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The UI clearly showed all components of the deployment, with warnings for any issues. Being able to see errors and fix them &lt;strong&gt;without manual rebuilding or redeploying&lt;/strong&gt; dramatically improved my workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisqgt294gd74wgkn7u9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisqgt294gd74wgkn7u9m.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Tilt effectively bridges the gap between local development and production environments. While implementing it for complex microservice architectures will require initial setup effort, the benefits of a reliable, self-healing local environment outweigh the investment.&lt;/p&gt;

&lt;p&gt;The tool provides what Docker Compose alone cannot: &lt;strong&gt;truly seamless hot reloading&lt;/strong&gt; of containerized applications in a Kubernetes context, creating a much &lt;strong&gt;tighter feedback loop&lt;/strong&gt; for development.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>productivity</category>
      <category>docker</category>
    </item>
    <item>
      <title>Webhooks: A New Approach to an Old Problem</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Fri, 30 Aug 2024 07:25:12 +0000</pubDate>
      <link>https://dev.to/gurghet/webhooks-a-new-approach-to-an-old-problem-9oe</link>
      <guid>https://dev.to/gurghet/webhooks-a-new-approach-to-an-old-problem-9oe</guid>
      <description>&lt;p&gt;As developers, we've all been there: knee-deep in a project, trying to integrate real-time data from a third-party service. Webhooks seem like the perfect solution... until they're not.&lt;/p&gt;

&lt;p&gt;I once lost 800 euros because of a webhook. Sounds ridiculous, right? But it happened, and it taught me a valuable lesson about the pitfalls of real-time data integration.&lt;/p&gt;

&lt;p&gt;I was working on a project to integrate Airbnb bookings with a property management system. The damn system was not idempotent on reads! So I could not use the API to read the latest booking because it will disappear the next time. So I choose to use webhooks.&lt;/p&gt;

&lt;p&gt;A small error in the webhook documentation—a field that sometime was missing—meant that booking notifications weren't coming through because of a parsing error. We missed a reservation, and a guest showed up to a double-booked apartment. Sorting out alternative accommodation at the last minute cost us 800 euros and a fair bit of stress.&lt;/p&gt;

&lt;p&gt;It wasn't just about the money. It was the realization that our entire system was vulnerable to such a simple mistake. One missed webhook, and everything falls apart.&lt;/p&gt;

&lt;p&gt;This experience got me thinking: there has to be a better way to handle real-time data without the constant anxiety of missing a beat. And that's exactly what I want to share with you today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://webhook.passaglia.it/" rel="noopener noreferrer"&gt;Webhook-to-API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter a new service that's changing the game. It's simple: you get a unique URL like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://webhook.passaglia.it/&amp;lt;your-prefix&amp;gt;/webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point your webhook-happy services here, and the magic begins. All that real-time data gets collected and stored. The best part? You can access it anytime with a simple API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://webhook.passaglia.it/&amp;lt;your-prefix&amp;gt;/api/data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's like having a personal assistant for your webhooks. They collect all the messages, organize them, and give you a neat summary whenever you ask.&lt;/p&gt;

&lt;p&gt;Think about the possibilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Managing team projects on OneDrive? No more sifting through individual file upload notifications. One API call gives you a list of all uploads in the last 24 hours.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tracking GitHub commits for your team? Forget about processing each webhook in real-time. Collect the data and analyze it on your terms. "Most active contributors this week" report? Easy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Running an online store? Instead of reacting to every single order webhook, aggregate that data. Analyze order patterns, identify peak hours, track product popularity - all with simple API calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Working on an IoT project? Let this service be your data aggregator. All those sensor readings collected in one place, ready for analysis when you need it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't about replacing webhooks. It's about giving us, the developers, more control. It's about saying, "Yes, I want that real-time data, but I'll process it when I'm good and ready."&lt;/p&gt;

&lt;p&gt;In my years of coding, I've learned that flexibility is key. This service offers just that - the immediacy of webhooks with the control of traditional APIs. It's a safety net that could have saved me 800 euros and a lot of headaches.&lt;/p&gt;

&lt;p&gt;So the next time you're starting a project and webhooks come up, remember: you have options. You don't have to be at the mercy of real-time data. Take control, simplify your architecture, and focus on what really matters - building great software.&lt;/p&gt;

&lt;p&gt;After all, isn't that why we got into this game in the first place?&lt;/p&gt;

</description>
      <category>saas</category>
      <category>webhooks</category>
      <category>rest</category>
    </item>
    <item>
      <title>I Accidentally The Whole Cloud... And It Didn't Matter</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sun, 16 Jun 2024 10:36:56 +0000</pubDate>
      <link>https://dev.to/gurghet/create-your-self-hosted-wordpress-for-eu5-a-month-in-30-seconds-1kap</link>
      <guid>https://dev.to/gurghet/create-your-self-hosted-wordpress-for-eu5-a-month-in-30-seconds-1kap</guid>
      <description>&lt;p&gt;Want to build a Wordpress from scratch in 30 seconds? Ok, start the timer now!&lt;/p&gt;

&lt;p&gt;So, I wanted my Wordpress website, but, being a software engineer, I didn't want to pay for it, not anything except the little more than the electricity needed to run a machine. Also, in the past I accidentally the whole website (more than once 🥲). To be clear, I did have the backup, but was too lazy to set up the whole system from scratch. Create the server, spin up the database, run the migration, and all that jazz.&lt;br&gt;
I don't want this to happen ever again 😡!&lt;br&gt;
So I set to myself the rule that whatever I build, even the most innocent Telegram bot to randomly choose the pizza for me (by the way why it doesn't have AI yet to understand my tastes?)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmku2eypvy6ty8vc9bujx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmku2eypvy6ty8vc9bujx.jpeg" alt="My non-AI pizza bot" width="591" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whatever I build from now on will be IaC, so that if I accidentally the whole cloud account again, I would be able to recreate it with the push of a button (preferably Enter, after issuing the &lt;code&gt;terraform plan&lt;/code&gt; command).&lt;/p&gt;
&lt;h3&gt;
  
  
  The machines
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o78adl2upuokqovwb73.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o78adl2upuokqovwb73.png" alt="Hetzner thrifty prices" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hetzner is a thrifty hosting, I don't know what that means, let me check the dictionary... oh makes sense. Well you can have the cheapest server for just a few euros a month, I always choose ARM because it seems cooler (figuratively and literally). But Intel has the same prices more or less.&lt;/p&gt;

&lt;p&gt;This is the bulk of the expense for our new Wordpress website. Good.&lt;/p&gt;

&lt;p&gt;From the hetzner cloud get your read/write API token.&lt;/p&gt;
&lt;h3&gt;
  
  
  The machines, as code
&lt;/h3&gt;

&lt;p&gt;We’re going to use Terraform to automate everything. Terraform is an open-source IaC tool that lets you define and provision your infrastructure with code. No more manual setup or hoping you didn’t screw up a step. With Terraform, you get consistency, fewer errors, and version control. Plus, if you need to wipe everything and start fresh, it’s just a couple of commands away. It’s the perfect tool to make sure your infrastructure is always up and running exactly how you want it.&lt;/p&gt;

&lt;p&gt;We are going to use some free cloud services, but none of them are necessary, we'll use them for their power to streamline workflow:&lt;br&gt;
I would highly suggest to get a Terraform Cloud account, the free plan can manage 500 resources which is plenty.&lt;br&gt;
Get an account at Doppler.com, it's basically a vault and will be useful to let the secret survive a total wipeout event. It also has a free tier. Get the API token for that as well (read only is fine for now).&lt;/p&gt;

&lt;p&gt;Once you have these two create a new folder for this project and make it a git repository. For simplicity I'm going to assume we have a GitHub repo called &lt;code&gt;wordpress-in-a-jar&lt;/code&gt; (in theory could be GitLab, BitBucket or even hosted on-premise). Yes, get an API token for that too, we'll need that to read/write the repository content.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;main.tf&lt;/code&gt; with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;hcloud&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hetznercloud/hcloud"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"hcloud"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hcloud_token&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"hcloud_token"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"github_token"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"hcloud_server"&lt;/span&gt; &lt;span class="s2"&gt;"master_node"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"geppetto"&lt;/span&gt;
  &lt;span class="nx"&gt;image&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu-20.04"&lt;/span&gt;
  &lt;span class="nx"&gt;server_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cax11"&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"fsn1"&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;module}&lt;/span&gt;&lt;span class="s2"&gt;/cloud-init.tpl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;github_token&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;github_token&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;ssh_keys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hcloud_ssh_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gaia_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"ip_address"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hcloud_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;master_node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ipv4_address&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"hcloud_ssh_key"&lt;/span&gt; &lt;span class="s2"&gt;"gaia_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Public key of my MacBook Pro (Gaia)"&lt;/span&gt;
  &lt;span class="nx"&gt;public_key&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDUAl/qrUV1Nkcd7fPbYAahOAg7p4Nn5+Gkv5Y1lQ/Hm7DqSJki9mmxhtuB/HHV3pZuriAzVJKpee8q8p55EnWhv9xw04oHBXYuJYzkU0kNMiZGMgh/Z8BNkY7QBqitDLOeCNk8gKpKYY0kbINvUaWUNy/JQdmLUu9erCzbkkC0k3KLTlVRr6ZyKuJ6yHX9zYHDJRw9iO+SKA7V/fFVBZtxfYXNN0GaDw6+33z7A7pxbt4wlCuFir2AYTUcU6E2jwrtpq9gwJ0dXiiOW5H/RRGJ1D3VDIcag+Zy7p54K3fH2KOgjujbPq6SS8zJ8/GE+iHCCVxhLnXLin66rRUOIbYVzxPtryX+f4fAxfxTWKLMNWWIVFa11/FOJ792j9MIuYvV/dn3nICsBSQToGQ94A7LoN6W0j4INViHbkzEZVaXQth2urFQ/1NmJGnQkbRR8/XU4ej06WUtie9oGjNY2SXOKVahjBWoybunbtKuv4gtz/XEQKjQDU4T1qXJ6k11jEM= gurghet@Gaia.local"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's my actual public key of my laptop, you have to put your own key there, otherwise I'll be able to access your machine :D&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F944v9cwtxylh910ieso4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F944v9cwtxylh910ieso4.png" alt="Here is a meme for the people who didn't read the above paragraph" width="500" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Cloud-init
&lt;/h4&gt;

&lt;p&gt;The line referring to the &lt;code&gt;cloud-init.tpl&lt;/code&gt; is calling built-in facility (in most server operating systems) for initializing and configuring cloud instances. It's very complicated how it works, has many modules and functionalities but we'll only use a few.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#cloud-config&lt;/span&gt;
&lt;span class="na"&gt;runcmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export GITHUB_TOKEN=${github_token}&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export HOME=/root&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export XDG_CONFIG_HOME=/root/.config&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -sfL https://get.k3s.io | sh -&lt;/span&gt; &lt;span class="c1"&gt;# install k8s&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export KUBECONFIG=/etc/rancher/k3s/k3s.yaml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;until nc -z localhost 6443; do sleep 1; done&lt;/span&gt; &lt;span class="c1"&gt;# wait until k8s is live&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash&lt;/span&gt; &lt;span class="c1"&gt;# get helm&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -s https://fluxcd.io/install.sh | sudo bash&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kubectl apply -f https://github.com/fluxcd/flux2/releases/latest/download/install.yaml --validate=false&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;flux bootstrap github --owner=gurghet --repository=wordpress-in-a-jar --branch=master --path=./flux/manifests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the last command we are provisioning the node with flux CD, which will watch every our step in the git repository and reconciliate until the cluster looks exactly like our code.&lt;/p&gt;

&lt;p&gt;Similarly here, you should use your github handle instead of &lt;code&gt;gurghet&lt;/code&gt; and possibly other parameters accordingly. They should all correspond to a real GitHub repository that you created and uploaded, with the above two files inside basically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing the stuff
&lt;/h2&gt;

&lt;p&gt;Now that your repository is accessible on GitHub, you should actually tell terraform to create all this on Hetzner. You should use the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init
terraform apply -var 'hcloud_token=&amp;lt;your hetzner token&amp;gt;' -var 'github_token=&amp;lt;your github token&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The firt command prepares the terraform environment and initializes the state, the second actually executes the code we wrote. We are manually passing the secrets now, but we will move them away later. We want a push-button experience, no manual secret management required.&lt;/p&gt;

&lt;p&gt;The plan will spit out the ip address of your new master node Geppetto, you should then be able to log in with ssh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh root@&amp;lt;Geppetto's ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once inside you can check that the provisioning was succcessful by tailing the logs, I got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@geppetto:~# tail -f /var/log/cloud-init-output.log
✔ GitRepository reconciled successfully
◎ waiting for Kustomization "flux-system/flux-system" to be reconciled
✔ Kustomization reconciled successfully
► confirming components are healthy
✔ helm-controller: deployment ready
✔ kustomize-controller: deployment ready
✔ notification-controller: deployment ready
✔ source-controller: deployment ready
✔ all components are healthy
Cloud-init v. 24.1.3-0ubuntu1~20.04.1 finished at Sat, 15 Jun 2024 21:24:35 +0000. Datasource DataSourceHetzner.  Up 113.81 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this worked you should find a new commit to your flux. This initial commit contains all the necessary files for Flux to manage your cluster state.&lt;/p&gt;

&lt;p&gt;Congratulations! You have a master node waiting for your commands. But let's say you want to call it a day and continue building this tomorrow. You don't need to keep your machine running and spending all your money. You can use &lt;code&gt;terraform destroy&lt;/code&gt; and then, tomorrow after a coffee, &lt;code&gt;terraform apply&lt;/code&gt; like above to instantly recreate your cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faq5xainkaq70ny1q8t1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faq5xainkaq70ny1q8t1z.png" alt="Saving money you would have not spent if you didn't read this article" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Spinning up the wordpress
&lt;/h2&gt;

&lt;p&gt;Everything you write in the &lt;code&gt;manifests&lt;/code&gt; folder will become true. So let's create a new folder for our Wordpress website: we'll call it "bot-buffet" an all-you-can-click Telegram bot marketplace. We'll use the excellent bitnami helm. This is how the directory structure is looking now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffskuxqbadkbxp27w0j7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffskuxqbadkbxp27w0j7b.png" alt="dir tree" width="392" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to need 4 charts here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bitnami helm repository&lt;/li&gt;
&lt;li&gt;A namespace for &lt;code&gt;bot-buffet&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The HelmRelease itself with Wordpress&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;An Ingress to instruct Traefik to route to it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I said charts but let's actually but everything inside &lt;code&gt;wordpress-helm.yaml&lt;/code&gt; because doing like this increase coesion and makes it easier to read the code.&lt;/p&gt;

&lt;p&gt;The first 2 are straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source.toolkit.fluxcd.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HelmRepository&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flux-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10m&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://charts.bitnami.com/bitnami&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-buffet&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bitnami chart needs some value, in particular we can choose name and email, but importantly we must disable the built-in loadbalancer (we don't want to spend money, remember?) and let's instead use Traefik.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helm.toolkit.fluxcd.io/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HelmRelease&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-buffet-wordpress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-buffet&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
  &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wordpress&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22.4.5"&lt;/span&gt;
      &lt;span class="na"&gt;sourceRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HelmRepository&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami&lt;/span&gt;
        &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flux-system&lt;/span&gt;
  &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;wordpressUsername&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gurghet"&lt;/span&gt;
    &lt;span class="na"&gt;wordpressEmail&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gurghet@proton.me"&lt;/span&gt;
    &lt;span class="na"&gt;wordpressBlogName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bot&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Buffet"&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
    &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect! The last think will be the Ingress entry to tell Traefik to actually send in all the customers that come from port 80.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-buffet-wordpress-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-buffet&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;traefik.ingress.kubernetes.io/router.entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
        &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
        &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bot-buffet-wordpress&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service &lt;code&gt;bot-buffet-wordpress&lt;/code&gt; is hardcoded because this is what the helm chart above will create.&lt;/p&gt;

&lt;p&gt;At this point you just need to commit and push to github this new file. The flux will pick it up and magically create your Wordpress! Try it by pointing your browser to the ip of the machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjrt9ym5h4hu4dz03ooq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjrt9ym5h4hu4dz03ooq.png" alt="Our new Wordpress website" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course there is a bunch of things that we still need to do: where is my domain with TLS certificate? Where are all the password to access my Wordpress and Database? How do I debug if something goes wrong? Where are my Telegram bots? I'm going to tell you next time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw0z01231qvu2h5075qw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw0z01231qvu2h5075qw.png" alt="chuck norris once kicked a server to build a Wordpress site" width="638" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did you check the timer? Are we over 30 seconds? Oh crap, ok let's start from scratch. Do the &lt;code&gt;terraform destroy&lt;/code&gt;. Ok, Ready?&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform apply&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Done!&lt;/p&gt;

&lt;p&gt;References: &lt;a href="https://github.com/gurghet/wordpress-in-a-jar" rel="noopener noreferrer"&gt;https://github.com/gurghet/wordpress-in-a-jar&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Bidirectional topic mirroring</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sun, 25 Feb 2024 23:03:44 +0000</pubDate>
      <link>https://dev.to/gurghet/bidirectional-topic-mirroring-14ck</link>
      <guid>https://dev.to/gurghet/bidirectional-topic-mirroring-14ck</guid>
      <description>&lt;p&gt;The tool of choice when it comes to disaster recovery in Kafka, is Mirror Maker. It's often configured to keep a stand-by cluster full of the latest data to take over just in case something happens to the main cluster.&lt;/p&gt;

&lt;p&gt;The same tool is also used for geo-replication. In this case some selected topics are sent to another region to have consistency of data between the clusters and deliver an updated state.&lt;/p&gt;

&lt;p&gt;This last setup however only works in one direction normally and, while Mirror Maker does support bidirectional replication, it does so in an asymmetric way by appending the name of the originating cluster to the topic, this is done to avoid the infinite mirror effect of a message being replicated back and forth. Consumers and producers have to be &lt;a href="https://aiven.io/docs/products/kafka/kafka-mirrormaker/concepts/replication-flow-topics-regex"&gt;aware of this asymmetry&lt;/a&gt; and the topology has to be more complex than necessary.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4grpzw28cs5utd7ev6ng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4grpzw28cs5utd7ev6ng.png" alt="Image description" width="681" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This spurred in a few cases where the setups used custom code to manage aggregating the events. Complexity is still lurking because of the inherent manual setup of Mirror Maker to manage these bidirectional flows effectively. The main challenge is the duplication and potential loss of messages due to network issues or misconfigurations. These complexities are not only operational but also introduce a high risk of data inconsistency between clusters.&lt;/p&gt;

&lt;p&gt;An alternative approach to Mirror Maker for bidirectional topic mirroring in Kafka is to use more advanced replication tools or services that are designed with bidirectionality in mind from the start. Tools like Confluent Replicator offer enhanced features over Mirror Maker, including improved fault tolerance, easier configuration, and better support for bidirectional replication. However, these are usually part of a cloud offering and have a price tag associated.&lt;/p&gt;

&lt;p&gt;Today I tried some alternatives with Apache Pulsar and have prepared a &lt;a href="https://github.com/gurghet/pulsar-geo-replication/"&gt;quick PoC&lt;/a&gt; you can try yourself.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Setting Up Bidirectional Mirroring with Pulsar&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Quick Guide:&lt;/strong&gt; Follow these streamlined steps to configure bidirectional topic mirroring using Apache Pulsar.&lt;/p&gt;

&lt;p&gt;Following the setup outlined in the README from the &lt;code&gt;pulsar-geo-replication&lt;/code&gt; GitHub project linked above, let's walk through the commands necessary to set up bidirectional topic mirroring using Apache Pulsar. This guide assumes you have already cloned the project and have Docker and Docker-compose installed on your system.&lt;/p&gt;
&lt;h3&gt;
  
  
  Start the Pulsar Clusters
&lt;/h3&gt;

&lt;p&gt;Navigate to the project directory where the &lt;code&gt;docker-compose.yml&lt;/code&gt; file is located. Initiate the clusters by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command starts two Pulsar clusters, named &lt;code&gt;cluster-a&lt;/code&gt; and &lt;code&gt;cluster-b&lt;/code&gt;, running in Docker containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect the Clusters
&lt;/h3&gt;

&lt;p&gt;After the clusters are up, you need to establish a connection between them. Execute the following commands to link &lt;code&gt;cluster-a&lt;/code&gt; to &lt;code&gt;cluster-b&lt;/code&gt; and vice versa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8080 clusters create cluster-b &lt;span class="nt"&gt;--broker-url&lt;/span&gt; pulsar://broker-edge1:6650 &lt;span class="nt"&gt;--url&lt;/span&gt; http://broker-edge1:8080
./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8081 clusters create cluster-a &lt;span class="nt"&gt;--broker-url&lt;/span&gt; pulsar://broker:6650 &lt;span class="nt"&gt;--url&lt;/span&gt; http://broker:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands configure each cluster to recognize the other, enabling them to replicate data between each other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Tenants and Namespaces
&lt;/h3&gt;

&lt;p&gt;Next, set up tenants and namespaces in both clusters to facilitate the replication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8080 tenants create edge1 &lt;span class="nt"&gt;--allowed-clusters&lt;/span&gt; cluster-a,cluster-b
./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8081 tenants create edge1 &lt;span class="nt"&gt;--allowed-clusters&lt;/span&gt; cluster-a,cluster-b
./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8080 namespaces create edge1/replicated &lt;span class="nt"&gt;--clusters&lt;/span&gt; cluster-a,cluster-b
./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8081 namespaces create edge1/replicated &lt;span class="nt"&gt;--clusters&lt;/span&gt; cluster-a,cluster-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration ensures that any topic created in the &lt;code&gt;edge1/replicated&lt;/code&gt; namespace will automatically be replicated across both clusters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Topic Creation
&lt;/h3&gt;

&lt;p&gt;Now, let's create a topic in the replicated namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-admin &lt;span class="nt"&gt;--admin-url&lt;/span&gt; http://localhost:8080 topics create persistent://edge1/replicated/events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This topic will serve as the conduit for messages meant to be mirrored between the clusters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the Setup
&lt;/h3&gt;

&lt;p&gt;Open a consumer for both cluster to check if the messages will come through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-client &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:8080 &lt;span class="nt"&gt;--listener-name&lt;/span&gt; external consume &lt;span class="nt"&gt;--subscription-name&lt;/span&gt; &lt;span class="s2"&gt;"sub-a"&lt;/span&gt; persistent://edge1/replicated/events &lt;span class="nt"&gt;-n&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The listener name is imporant because we can't access the Docker DNS from the host machine, so we configured in the &lt;code&gt;docker-compose.yaml&lt;/code&gt; an external listener that is advertised from the broker to the pulsar client, which the pulsar client will then use to connect to the broker after the first connection.&lt;br&gt;
Open a second terminal and start listening for messages on cluster b:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-client &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:8081 &lt;span class="nt"&gt;--listener-name&lt;/span&gt; external consume &lt;span class="nt"&gt;--subscription-name&lt;/span&gt; &lt;span class="s2"&gt;"sub-b"&lt;/span&gt; persistent://edge1/replicated/events &lt;span class="nt"&gt;-n&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in a third terminal you produce a message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-client &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:8080 &lt;span class="nt"&gt;--listener-name&lt;/span&gt; external produce persistent://edge1/replicated/events &lt;span class="nt"&gt;--messages&lt;/span&gt; &lt;span class="s2"&gt;"Hello world produced to cluster a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the same message in both clusters.&lt;/p&gt;

&lt;h4&gt;
  
  
  Extra
&lt;/h4&gt;

&lt;p&gt;It's also possible to avoid replicating on a per-message basis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./pulsar-client &lt;span class="nt"&gt;--url&lt;/span&gt; http://localhost:8081 &lt;span class="nt"&gt;--listener-name&lt;/span&gt; external produce &lt;span class="nt"&gt;--disable-replication&lt;/span&gt; persistent://edge1/replicated/events &lt;span class="nt"&gt;--messages&lt;/span&gt; &lt;span class="s2"&gt;"Hello world produced to cluster b not replicated"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you will see the message only on cluster b, while it will never appear on cluster a.&lt;/p&gt;

&lt;p&gt;By following these steps, you've successfully set up bidirectional topic mirroring with Apache Pulsar. This method offers a more straightforward and reliable approach to data replication across clusters, ensuring high availability and consistency for distributed systems.&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>pulsar</category>
      <category>mirroring</category>
      <category>multicloud</category>
    </item>
    <item>
      <title>A closer look at the lifecycle of a send block in the Nano network</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sun, 28 Mar 2021 19:58:54 +0000</pubDate>
      <link>https://dev.to/gurghet/a-closer-look-at-the-lifecycle-of-a-send-block-in-the-nano-network-1925</link>
      <guid>https://dev.to/gurghet/a-closer-look-at-the-lifecycle-of-a-send-block-in-the-nano-network-1925</guid>
      <description>&lt;h1&gt;
  
  
  How does a send block get memorized in the Nano network
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;A bystander look at the C++ reference implementation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've spent some time looking at the Nano current reference implementation. The codebase is huge so it wasn't an easy task. I wanted to focus on a precise question: what is the lifecycle of a send block? These are my findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conception
&lt;/h2&gt;

&lt;p&gt;Since this piece will be about a send block, everything about creating a new chain is out of scope. Let's imagine a user wants to send some raws. My node will create a message with a header similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
network: live
protocol version: 19
message type: publish
extensions:
  block type: send
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will pretend a random user with a balance of 700 raw wants to send 10 raw.&lt;br&gt;
If we drill into the block information we'll find something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;previous: BBE55A35F79F887...
link/destination: 9A2726664A18FE5...
balance: 690
work: 14b3bc748f2c8e93
signature: B421B88AFBEDFC...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The balance is 690 raw because it was 700 and I'm sending 10 raw.&lt;br&gt;
The node then will send this message to its peers. &lt;/p&gt;
&lt;h2&gt;
  
  
  Another node receive the message
&lt;/h2&gt;

&lt;p&gt;For each peer there is an already established TCP connection and after a message is processed a new message listener is created.&lt;br&gt;
This is how the listener is installed in &lt;code&gt;bootstrap_server.cpp:151&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bootstrap_server&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;receive&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;async_read&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receive_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_l&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="c1"&gt;// Receive header&lt;/span&gt;
        &lt;span class="n"&gt;this_l&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;receive_header_action&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will put whatever we receive through the TCP connection into the &lt;code&gt;receive_buffer&lt;/code&gt;.&lt;br&gt;
The function &lt;code&gt;receive_header_action&lt;/code&gt; is immediately after and reads like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bootstrap_server&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;receive_header_action&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bufferstream&lt;/span&gt; &lt;span class="n"&gt;type_stream&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receive_buffer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;size_a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;message_header&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type_stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;this_l&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_from_this&lt;/span&gt; &lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// error management ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens above is that the head of the &lt;code&gt;receive_buffer&lt;/code&gt; is assigned to &lt;code&gt;type_stream&lt;/code&gt; and &lt;code&gt;type_stream&lt;/code&gt; is used to instanciate a &lt;code&gt;message_header&lt;/code&gt; class. The logic in the constructor will deserialize the stream and, in particular, will fill the &lt;code&gt;header.type&lt;/code&gt; attribute. This is because, provided no error happened, the next thing we do will depend on the &lt;code&gt;header.type&lt;/code&gt; (the switch construct). Let's see the case for a publish message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;message_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;async_read&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receive_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload_length_bytes&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;this_l&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;receive_publish_action&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's installing another listener, on the same buffer. The handler will call the &lt;code&gt;receive_publish_action&lt;/code&gt; function in the same file, which validates the work in the carried block. It then adds the message to the &lt;code&gt;requests&lt;/code&gt; deque. This will be ultimately processed by the &lt;code&gt;request_response_visitor&lt;/code&gt; which in turn puts the message into the &lt;code&gt;entries&lt;/code&gt; deque of the &lt;code&gt;tcp_message_manager&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Processing message entries
&lt;/h2&gt;

&lt;p&gt;At this point the &lt;code&gt;network&lt;/code&gt; class enters the stage. When initialized, this class runs the &lt;code&gt;process_messages&lt;/code&gt; loop at &lt;code&gt;tcp.cpp:279&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tcp_channels&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;process_messages&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;stopped&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// while we are not shutting down the node&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tcp_message_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_message&lt;/span&gt; &lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;process_message&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally the &lt;code&gt;process_message&lt;/code&gt;, makes sure we have a channel open with the message originator. Then it creates a &lt;code&gt;network_message_visitor&lt;/code&gt; relative to the channel and processes the publish message according to the following function in &lt;code&gt;network.cpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;message_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... logging and monitoring logic ...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block_processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_active&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;process_active&lt;/code&gt; adds the block inside the message to both the &lt;code&gt;block_arrival&lt;/code&gt; and the &lt;code&gt;block_processor&lt;/code&gt;. The latter is responsible for putting the block into the &lt;code&gt;block&lt;/code&gt; dequeue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block processing
&lt;/h2&gt;

&lt;p&gt;Whenever a &lt;code&gt;node&lt;/code&gt; class is instanciated it spawns a block processor thread. This thread has an infinite loop in &lt;code&gt;blockprocessor.cpp&lt;/code&gt; inside the function &lt;code&gt;process_blocks&lt;/code&gt;. This starts a transaction that, after acquiring various locks, processes a batch of blocks. The processing of a single block is defined in the &lt;code&gt;process_one&lt;/code&gt; function and relies on a &lt;code&gt;ledger_processor&lt;/code&gt; defined in &lt;code&gt;ledger.cpp&lt;/code&gt;, at least for the send block we're interested in.&lt;/p&gt;

&lt;p&gt;The full logic can be found in &lt;code&gt;ledger.cpp&lt;/code&gt; in the &lt;code&gt;send_block&lt;/code&gt; function. At its core it's a pyramid of ifs which try to account for all possible things that might go wrong. For example if the work of of the block is sufficient (note that we already checked this when we received the block from another node).&lt;/p&gt;

&lt;p&gt;At the top of the pyramid we finally execute the instruction&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;ledger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block_put&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block_a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which physically adds the block to the permanent storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is not the end of the life of this block. In fact it would terminate when the block is cemented. Cementing is a different process that involves consensus, thus the block could be even be deleted if, for example was detected as a double spend. I'll write about this in another article.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Composing complex programs with ZIO</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Mon, 01 Mar 2021 22:50:29 +0000</pubDate>
      <link>https://dev.to/gurghet/composing-complex-programs-with-zio-56a1</link>
      <guid>https://dev.to/gurghet/composing-complex-programs-with-zio-56a1</guid>
      <description>&lt;p&gt;There is a fundamental mental shift a procedural programmer must make when embracing functional programming. In this lesson we'll learn to visualize complex ZIO programs to compose them correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The art of type chasing
&lt;/h2&gt;

&lt;p&gt;Types in Scala give us confidence that the program is doing what we want and that the quality of the data is high enough. With ZIO they also help us catching nasty bugs at compile time instead of runtime.&lt;/p&gt;

&lt;p&gt;The canonical ZIO program has this type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nc"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;ExitCode&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our end game, every ZIO program we can possibly conceive, if we transform it into (chase) this type, then we can easily run it.&lt;/p&gt;

&lt;p&gt;Usually what we start with will be something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nc"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt; &lt;span class="kt"&gt;with&lt;/span&gt; &lt;span class="kt"&gt;MyDatabase&lt;/span&gt;, &lt;span class="kt"&gt;DomainSpecificErrors&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to make it coincide with our canonical ZIO, we need to act in two different directions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The environment type needs to become more generic (up to &lt;code&gt;ZEnv&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The error and return type need to become more specific (error down to &lt;code&gt;Nothing&lt;/code&gt; and return to &lt;code&gt;ExitCode&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using ZIO provided methods we can creatively chase the canonical types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cat and mouse chasing
&lt;/h3&gt;

&lt;p&gt;As fun example of type chasing we can create a program of a cat chasing a mouse.&lt;/p&gt;

&lt;p&gt;We will have a mouse program and a cat program that will run concurrently. Both programs will share a variable to track the mouse distance from the cat.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a variable
&lt;/h3&gt;

&lt;p&gt;Our variable, tracking the lead the mouse has on the cat, needs to be shared by both the cat and the mouse program.&lt;/p&gt;

&lt;p&gt;To create a variable that is safe to use concurrently we can write the following program&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.Ref&lt;/span&gt;

&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;makeMouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;make&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;code&gt;UIO&lt;/code&gt; program which expands to a &lt;code&gt;ZIO[Any, Nothing, Ref[Int]]&lt;/code&gt;. It can run in any environment, never fails, and returns a &lt;code&gt;Ref&lt;/code&gt; of an integer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Ref&lt;/code&gt; is a reference to an immutable variable that we can check and swap. You can picture a &lt;code&gt;Ref&lt;/code&gt; like a single place datum cradle. We will use it to read the distance between cat and mouse and update it whenever either of them advances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Digital mouse that runs away
&lt;/h3&gt;

&lt;p&gt;To represent the mouse getting away from the cat we can design a simple recursive program&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.clock.sleep&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.console.putStrLn&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.random.nextIntBounded&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.duration._&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio._&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cm&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;nextIntBounded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;  &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;  &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Mouse advances by $cm cm"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;  &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.&lt;/span&gt;&lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;  &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's dissect this automatic mouse:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are accepting the reference to an &lt;code&gt;Int&lt;/code&gt; variable, the mouse lead on the cat.&lt;/li&gt;
&lt;li&gt;A random number, less than 2, is drawn, representing how many centimeters the mouse advances.&lt;/li&gt;
&lt;li&gt;We add the above number to the current lead and put the sum in the &lt;code&gt;Ref&lt;/code&gt;. This will be the new mouse lead.&lt;/li&gt;
&lt;li&gt;Print on the screen the mouse progress&lt;/li&gt;
&lt;li&gt;We then wait 100 milliseconds&lt;/li&gt;
&lt;li&gt;Recursively call the mouse program&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that we are using functions coming from &lt;code&gt;zio.clock&lt;/code&gt;, &lt;code&gt;zio.console&lt;/code&gt; and &lt;code&gt;zio.random&lt;/code&gt;, all contained in &lt;code&gt;ZEnv&lt;/code&gt; so our final type is &lt;code&gt;URIO[ZEnv, Unit]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I wrote &lt;code&gt;ZEnv&lt;/code&gt; instead of &lt;code&gt;Clock with Console with Random&lt;/code&gt;. This is allowed because I can always pick a more specific type as environment. The opposite is true for error type and return type.&lt;/p&gt;

&lt;p&gt;This program is recursive, it will never return the &lt;code&gt;Unit&lt;/code&gt; we promised. To make the return type more expressive it would have to return &lt;code&gt;Nothing&lt;/code&gt; meaning it will never do. But, as said above we cannot put a more specific type for the return channel.&lt;/p&gt;

&lt;p&gt;The problem is that the compiler didn't detect our infinite recursion and assumed at some point we are going to return &lt;code&gt;Unit&lt;/code&gt;. There is a way we can explicitly say that the mouse will run forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cm&lt;/span&gt;    &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;nextIntBounded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;     &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;     &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Mouse advances by $cm cm"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;     &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.&lt;/span&gt;&lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;recur&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;recur&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By making the return type the mouse program itself we can force write &lt;code&gt;Nothing&lt;/code&gt; and the compiler will be happy.&lt;/p&gt;

&lt;p&gt;Thanks to the ZIO library we can actually do this by skipping the recursive step entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cm&lt;/span&gt;    &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;nextIntBounded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;     &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;     &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Mouse advances by $cm cm"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;     &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.&lt;/span&gt;&lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="py"&gt;forever&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we deleted the recursive call and wrapped the for comprehension in parenthesis. With &lt;code&gt;forever&lt;/code&gt; we created a new program that repeats the for comprehension forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Digital cat that chases
&lt;/h3&gt;

&lt;p&gt;The third program we are going to write is the dual of the mouse. The cat is very similar, but it runs faster and, for every centimeter it advances, the mouse lead diminishes instead of increasing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;catProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cm&lt;/span&gt;   &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;nextIntBounded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;updateAndGet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;    &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Cat advances by $cm cm, mouse is $lead cm away"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;    &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.&lt;/span&gt;&lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt;    &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;catchDetector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cat program will actually finish at some point: the last instruction uses a special program called &lt;code&gt;catchDetector&lt;/code&gt;. It considers two possible scenarios: either the mouse has still some lead or the cat is at or past the mouse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;catchDetector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;currentLead&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;catProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cat catches the mouse!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, if the mouse is not reached yet, the cat program is called (recursively), otherwise the &lt;code&gt;catchDetector&lt;/code&gt; returns with a program that prints "Cat catches the mouse!".&lt;/p&gt;

&lt;p&gt;We can make the program even more fun by including a third possibility: if the cat goes past the mouse, instead of declaring victory, we assume the mouse escaped. We can express this as an exception. From the point of view of the cat program, this is certainly not a welcome outcome.&lt;/p&gt;

&lt;p&gt;First, let's declare the exception as a case class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MouseEscapedException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;catLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;catLead&lt;/code&gt; will tell us how much the cat went past the mouse.&lt;/p&gt;

&lt;p&gt;Secondly, we need to add the third case in the &lt;code&gt;catchDetector&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;catchDetector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;MouseEscapedException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;currentLead&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;                 &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cat catches the mouse!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;catProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MouseEscapedException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if the &lt;code&gt;currentLead&lt;/code&gt; is strictly less than 0 we return a program that fails with &lt;code&gt;MouseEscapedException&lt;/code&gt;. This makes our program fail in turn.&lt;/p&gt;

&lt;p&gt;Since the cat program is calling this, we need to update the signature by adding the error modality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;catProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mouseLead&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;MouseEscapedException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;We have created a total of 4 ZIO programs. This is a good time to list them all.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;UIO[Ref[Int]]&lt;/code&gt; will give us an integer variable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;URIO[ZEnv, Nothing]&lt;/code&gt; programs the mouse to run&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ZIO[ZEnv, MouseEscapedException, Unit]&lt;/code&gt; programs the cat to chase&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ZIO[ZEnv, MouseEscapedException, Unit]&lt;/code&gt; subroutine of the cat that can either succeed with a &lt;code&gt;Unit&lt;/code&gt; or trigger failure with a &lt;code&gt;MouseEscapedException&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diagram below is another representation of these programs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwe3v5h6txwjzei279h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwe3v5h6txwjzei279h0.png" alt="Not connected diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice, at the center, our canonical ZIO program &lt;code&gt;URIO[ZEnv, ExitCode]&lt;/code&gt;. In green I represented the environment channel. The canonical ZIO program will provide you a perfectly good &lt;code&gt;ZEnv&lt;/code&gt; (filled green dot). The program that creates the mouse and also the cat, conversely, want the &lt;code&gt;ZEnv&lt;/code&gt; (hence the hollow green dot).&lt;/p&gt;

&lt;p&gt;In blue I represented the success channel. The mouse catch detector may return a unit when a capture happens, this gets transmitted upwards). The mouse program runs forever, and returns nothing, that's why it doesn't have any blue line going outwards. The canonical ZIO waits patiently for a &lt;code&gt;ExitCode&lt;/code&gt; and won't accept much else.&lt;/p&gt;

&lt;p&gt;In red we see the failures channel that, from the catch detectors propagate upwards. The cat, in turn, may propagate the error.&lt;/p&gt;

&lt;p&gt;We have to run the cat and the mouse program, to do that we have to chase the canonical ZIO types.&lt;/p&gt;

&lt;h4&gt;
  
  
  Environment channel
&lt;/h4&gt;

&lt;p&gt;There is not a lot to do for the green lines. &lt;code&gt;ZEnv&lt;/code&gt; with &lt;code&gt;ZEnv&lt;/code&gt;, everything matches. We won't worry about this.&lt;/p&gt;

&lt;h4&gt;
  
  
  Failure channel
&lt;/h4&gt;

&lt;p&gt;The canonical ZIO doesn't want to deal with errors we have to stop them before they reach the boundaries of our program. One way to do this is to turn the error into a program that never fails (a ZIO with &lt;code&gt;Nothing&lt;/code&gt; as error type); &lt;code&gt;putStrLn&lt;/code&gt; is one such a program. We could log the error to screen and this would return a success &lt;code&gt;Unit&lt;/code&gt; type. A message saying that the mouse escaped will be sufficient.&lt;/p&gt;

&lt;h4&gt;
  
  
  Success channel
&lt;/h4&gt;

&lt;p&gt;The only type accepted here by the canonical ZIO is &lt;code&gt;ExitCode&lt;/code&gt;. We said this before, but it's worth repeating that &lt;code&gt;ExitCode&lt;/code&gt; is just a puffed up integer we give to the operating system. We can always return &lt;code&gt;ExitCode.success&lt;/code&gt;, an alias for &lt;code&gt;0&lt;/code&gt;. This means we consider the cat both catching and missing the mouse a success.&lt;/p&gt;

&lt;p&gt;The above three conditions are satisfied by &lt;code&gt;compositeProgram&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;compositeProgram&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;zio.ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;ExitCode&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;makeMouseLead&lt;/span&gt;
    &lt;span class="n"&gt;exitCode&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;catProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;raceFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;catchAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Cat was ${-exc.catLead} cm ahead when it lost the mouse."&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;as&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ExitCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;success&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;exitCode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://scastie.scala-lang.org/bMhWYmaVSpGOQePmAKPHaQ" rel="noopener noreferrer"&gt;the complete code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Click "Run" a few times to see all possible outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explanation of &lt;code&gt;compositeProgram&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Our idea to chase types is a very small for comprehension. In the first place we map over the &lt;code&gt;makeMouseLead&lt;/code&gt; program to create the variable. Secondly we run both the mouse and the cat with &lt;code&gt;.raceFirst&lt;/code&gt; which will concurrently spin them up and wait for the first to terminate either with a success or a failure. We know that the mouse program doesn't terminate so we are basically waiting the cat program. This however leaves us with a &lt;code&gt;ZIO[ZEnv, MouseEscapedException, Unit]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To turn the error into a &lt;code&gt;Nothing&lt;/code&gt; we use &lt;code&gt;.catchAll&lt;/code&gt; and we pass an infallible program: &lt;code&gt;putStrLn&lt;/code&gt;. To turn the &lt;code&gt;Unit&lt;/code&gt; into an exit code we could simply &lt;code&gt;.flatMap&lt;/code&gt; it to an &lt;code&gt;ExitCode&lt;/code&gt; but when we are not interested in the result we can use &lt;code&gt;.as&lt;/code&gt; which is a &lt;code&gt;.flatMap&lt;/code&gt; that ignores the preceding result.&lt;/p&gt;

&lt;p&gt;All these transformations are summarized in the below diagram which now looks complete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v8z8h374kcrgk43ksi2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v8z8h374kcrgk43ksi2.png" alt="connected diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus section
&lt;/h2&gt;

&lt;p&gt;But wait, there is more. Instead of using the &lt;code&gt;.catchAll&lt;/code&gt; and &lt;code&gt;.as(ExitCode.success)&lt;/code&gt; functions, ZIO gives us a nice shortcut that does something very similar and that will work in the majority of cases. You can just add &lt;code&gt;.exitCode&lt;/code&gt; and this will either print an error (and exit with 1) or succeed (and exit with 0). Not precisely our behavior, we lose the nice error message and we exit with an error when the mouse escape, but good enough: our program is simpler and we save one line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;compositeProgram&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;zio.ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;ExitCode&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;makeMouseLead&lt;/span&gt;
      &lt;span class="n"&gt;exitCode&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;catProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;raceFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mouseProgram&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;exitCode&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;exitCode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>functional</category>
      <category>zio</category>
      <category>scala</category>
    </item>
    <item>
      <title>Building a Bitcoin price ticker</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sat, 09 Jan 2021 20:23:20 +0000</pubDate>
      <link>https://dev.to/gurghet/building-a-bitcoin-price-ticker-he0</link>
      <guid>https://dev.to/gurghet/building-a-bitcoin-price-ticker-he0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Learning functional programming&lt;/p&gt;

&lt;p&gt;Advanced track&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this series I want to explore fundamental concepts and tools of functional programming by building small applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Streams
&lt;/h1&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/sXYceYCLUZw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;A stream is a conceptual device that abstracts the way in wich we access and process data. A stream at its core is just a sequence of data. However, differently from an array or a list, a stream doesn't necessarily have a beginning or an end.&lt;/p&gt;

&lt;p&gt;In real life we have some example of streams. A ticker for the price of Bitcoin for example. It's a stream because it's clearly a timed sequence of data. It does have a beginning (when Bitcoin was created) but it never ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Bitcoin price ticker
&lt;/h2&gt;

&lt;p&gt;In this issue you'll build a BTC ticker that runs on your screen. This way you will always know when to buy and when to sell.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ipt-8_Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./img/design-draft-for-the-bitcoin-ticker.png" class="article-body-image-wrapper"&gt;&lt;img alt="Design draft for the BTC ticker" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ipt-8_Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./img/design-draft-for-the-bitcoin-ticker.png" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple design you can draft in two seconds is the one sketched above. We'll chose some API, parse the output, turn it into a number and finally print it on our screen (or physical ticker if you are retro).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yV6iBZYc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./img/gomez-examining-a-stock-ticker.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yV6iBZYc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./img/gomez-examining-a-stock-ticker.png" alt="Gomez Addams inspecting a stock ticker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Programming
&lt;/h3&gt;

&lt;p&gt;A very first draft of the program might be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nc"&gt;ZStream&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"100.000"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// generate some fake data&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;take&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// let's not overload&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// placeholder for parsing&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priceString&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priceString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foreach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"BTC-EUR: ${price.setScale(2, BigDecimal.RoundingMode.UP)}"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can go ahead and &lt;a href="https://scastie.scala-lang.org/hwQEk38eTOCfYYrEjhne2Q"&gt;launch this&lt;/a&gt;. In the first line we are getting a hold of the &lt;code&gt;ZStream&lt;/code&gt; object, it contains the &lt;code&gt;repeat&lt;/code&gt; method wich just infinitely produces whatever we pass: a string in this case. We limit it to 3 strings, otherwise it will just overload our machine and never stop. The parsing for now is impersonated by an identity function. We then leverage the &lt;code&gt;BigDecimal&lt;/code&gt; parsing capabilities to have a number to work with. Lastly the &lt;code&gt;foreach&lt;/code&gt; method is used, which is a terminal method. It will wrap up the stream by printing on the screen a well formatted price tick.&lt;/p&gt;

&lt;p&gt;We could have even skipped the conversion to &lt;code&gt;BigDecimal&lt;/code&gt; and back if we don't care about having control on rounding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nc"&gt;ZStream&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"100.000"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;take&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foreach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"BTC-EUR: $price"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we go hunting for a good API. Like in the cooking TV show I’ve already done this, but you can look for yourself and I recommend &lt;a href="https://www.programmableweb.com/"&gt;ProgrammableWeb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m going to use the &lt;a href="https://api.kraken.com/0/public/Ticker?pair=BTCEUR"&gt;Kraken public API&lt;/a&gt; which is very basic. It returns a json of this form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"XXBTZEUR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stuff&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"last trade price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stuff&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are interested in the current price which is the last trade price. We could (and should) use a json parser to extract this. However that would open a can of worms, so I’m going to use a regular expression:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parsePrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;regex&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="s"&gt;"""(?s).*"c":\["([0-9.]+).*"""&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;r&lt;/span&gt;
  &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;regex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we have our parsing step, we finally need to actually call the API. Again, there are super-cool http clients we could use; instead for simplicity's sake we'll use the scala built-in client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;tickerURLCall&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Source&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromURL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.kraken.com/0/public/Ticker?pair=BTCEUR"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;mkString&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now put everything together in the program. We will use &lt;code&gt;tickerURLCall&lt;/code&gt; instead of the fake data and the &lt;code&gt;priceParce&lt;/code&gt; instead of the identity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;program&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Console&lt;/span&gt; &lt;span class="kt"&gt;with&lt;/span&gt; &lt;span class="kt"&gt;Clock&lt;/span&gt;, &lt;span class="kt"&gt;Throwable&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ZStream&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;repeatEffect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tickerURLCall&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;throttleShape&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;5.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// let's slow down&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsePrice&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foreach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"BTC-EUR: $price"&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node the addition of the &lt;code&gt;throttleShape&lt;/code&gt; function. This is because we don't want to call the API as fast as we can, but we want a constant slow rate. The code says 1 call every 5 seconds. The function we supply in the second pair of brackets is a function to compute the weight of the result (to shape the throttle accordingly) we consider all responses equal to 1.&lt;/p&gt;

&lt;p&gt;This last feature is useful if you have pagination and you don't know how many items you have for each page. You could create a stream that outputs 10 items per minute and sometimes the calls to the source API return more (or less). Then the API would be called more slowly (or faster) to compensate.&lt;/p&gt;

&lt;p&gt;Also we don't need to limit the number of ticks with &lt;code&gt;take(3)&lt;/code&gt; now that we have throttling in place.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://scastie.scala-lang.org/8nRhWur0TEqgSbfayn3JOA"&gt;test the bitcoin ticker on Scastie&lt;/a&gt; remember to edit it to display your favourite currency pair and your favourite rounding.&lt;/p&gt;

</description>
      <category>bitcoin</category>
      <category>zio</category>
      <category>scala</category>
      <category>functional</category>
    </item>
    <item>
      <title>Imparare ad usare Array.map in JavaScript</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Sat, 09 Jan 2021 11:24:46 +0000</pubDate>
      <link>https://dev.to/gurghet/imparare-ad-usare-array-map-in-javascript-1cn9</link>
      <guid>https://dev.to/gurghet/imparare-ad-usare-array-map-in-javascript-1cn9</guid>
      <description>&lt;h1&gt;
  
  
  Imparare ad usare Array.map in JavaScript
&lt;/h1&gt;

&lt;p&gt;Il metodo &lt;code&gt;.map&lt;/code&gt; è disponibile in JavaScript per tutti i browser e Node.js da ormai un bel pezzo (ECMAScript 2015). Se l’hai visto in giro e non lo stai ancora usando, dopo aver letto questo articolo nessuno ne saprà più di te sull’argomento!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ma perché? Serve veramente?
&lt;/h2&gt;

&lt;p&gt;Per velocizzare l’apprendimento, niente è meglio di un esempio. Qualsiasi programmatore JavaScript avrà visto questo codice svariate volte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;giovanni@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;giova38&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;giangiorgio@toptech.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;giangi23&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;usersWithAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// vedi nota 1&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toptech.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;usersWithAdmin&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersWithAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// l’output sarà&lt;/span&gt;
&lt;span class="c1"&gt;// [ { email: 'giovanni@gmail.com', display: 'giova38', admin: false },&lt;/span&gt;
&lt;span class="c1"&gt;//   { email: 'giangiorgio@toptech.com', display: 'giangi23', admin: true } ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In questo codice creiamo un array vuoto, iteriamo tutti gli elementi di &lt;code&gt;users&lt;/code&gt; e per ognuno controlliamo se il dominio della mail è "toptech.com", in quel caso dichiariamo l’utente come admin (tralasciamo la sicurezza di tale codice 🤣).&lt;/p&gt;

&lt;p&gt;Una bella pappardella, lo stesso identico risultato si può ottenere con 4 leggibilissime righe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isUserAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toptech.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersWithAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isUserAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nella prima riga dichiariamo, in maniera un po’ più succinta, cosa significa essere admin. Nella seconda prendiamo un bel respiro. Infine, nelle ultime due "mappiamo" ogni elemento dell’array ad una copia con il nuovo campo &lt;code&gt;admin&lt;/code&gt; aggiunto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;(Semi)immutabilità&lt;/em&gt;&lt;br&gt;
Prima di spendere due parole su &lt;code&gt;.map&lt;/code&gt; si prega di notare che &lt;code&gt;usersWithAdmin&lt;/code&gt; prima era stato dichiarato &lt;code&gt;let&lt;/code&gt;, nel nuovo codice è &lt;code&gt;const&lt;/code&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. Questo ha implicazioni importanti: il nostro array nasce già inizializzato, non possiamo mai referenziare, nemmeno facendolo apposta, il nostro array in fase di inizializzazione.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Come funziona map
&lt;/h2&gt;

&lt;p&gt;In due parole &lt;code&gt;.map&lt;/code&gt; è un metodo che permette di applicare la stessa funzione a tutti gli elementi dell’array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ciao&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mondo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maiuscolizza&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stringa&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;stringa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maiuscolizza&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// l’output sarà&lt;/span&gt;
&lt;span class="c1"&gt;// [ 'CIAO', 'MONDO' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nel caso sopra abbiamo usato la funzione &lt;code&gt;maiuscolizza&lt;/code&gt; che manda una stringa nella sua versione maiuscola.&lt;/p&gt;

&lt;p&gt;Guardiamo la segnatura della funzione che possiamo passare:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function callback(cursore[, indice[, array]])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Il &lt;code&gt;cursore&lt;/code&gt; che è l’unico parametro usato negli esempi è l’elemento corrente che vogliamo elaborare.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;indice&lt;/code&gt; è l’attuale indice associato al cursore. Il primo elemento avrà indice &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;array&lt;/code&gt; ci restituisce l’array su cui stiamo agendo. Utile nel caso in cui la nostra funzione deve combinare diversi elementi. Da notare che si tratta dell’array originale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Estrarre proprietà di un oggetto con map
&lt;/h3&gt;

&lt;p&gt;Supponiamo di avere oggetti con molte proprietà e di volere un nuovo array con solo una di queste, l’equivalente di una colonna. Potremmo fare così:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;esperimenti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Large Hadron Collider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;costo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000000000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Vulcano di bicarbonato&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;costo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.50&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;International Space Station&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;costo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150000000000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nomiEsperimenti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;esperimenti&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;esperimento&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;esperimento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nomiEsperimenti&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// l’output sarà&lt;/span&gt;
&lt;span class="c1"&gt;// [ 'Large Hadron Collider', &lt;/span&gt;
&lt;span class="c1"&gt;//   'Vulcano di bicarbonato',&lt;/span&gt;
&lt;span class="c1"&gt;//   'International Space Station' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Reduce&lt;/em&gt;&lt;br&gt;
Di solito si estrae una colonna per effettuare dei calcoli, ad esempio se vogliamo calcolare il costo totale degli esperimenti potremmo scrivere&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;esperimenti&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;costo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prec&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// output: 155000000003.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Abbiamo usato &lt;code&gt;reduce&lt;/code&gt; che agisce come accumulatore di valori ed effettua la somma. Piu informazioni sul &lt;a href="https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce"&gt;sito di MDN&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;a href="https://www.linkedin.com/in/gurghet/?locale=it_ITs"&gt;&lt;em&gt;Andrea Passaglia&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Ad essere perfettamente onesti, &lt;code&gt;const&lt;/code&gt; viene qui usato solo in maniera convenzionale a dire "ehy questo array non dovrebbe più essere mutato". La verità tuttavia è che, anche se non possiamo più riassegnare la variabile, l’array può benissimo essere mutato tramite assegnamento dei suoi elementi. Nei prossimi articoli risolveremo anche questo problema. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>map</category>
      <category>functional</category>
    </item>
    <item>
      <title>10 days with the ZIO 2/10</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Mon, 27 Jan 2020 14:29:23 +0000</pubDate>
      <link>https://dev.to/gurghet/10-days-with-the-zio-2-10-4jpg</link>
      <guid>https://dev.to/gurghet/10-days-with-the-zio-2-10-4jpg</guid>
      <description>&lt;p&gt;This miniseries aims at teaching how to use the ZIO at a very relaxed pace. Today we are going to build a word count app.&lt;/p&gt;

&lt;p&gt;This means that given a text we want to know how many times each word appears.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sneak Peek
&lt;/h3&gt;

&lt;p&gt;Suppose you have the text&lt;/p&gt;

&lt;p&gt;&lt;code&gt;How much wood would a woodpecker peck if a woodpecker would peck wood?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The program should output&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(a,2), (peck,2), (woodpecker,2), (would,2), (if,1), (wood,1), (much,1), (How,1), (wood?,1)&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Like &lt;a href="https://dev.to/gurghet/10-days-with-the-zio-1-10-1oom"&gt;last time&lt;/a&gt; we are going to use Mill instead of SBT. Why? because it’s easier and takes 5 seconds.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a folder &lt;code&gt;zio-word-counter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inside it create a &lt;code&gt;build.sc&lt;/code&gt; file with the following content
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;mill._&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;scalalib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;_&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;WordCounter&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ScalaModule&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scalaVersion&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2.13.0"&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;zioVersion&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.0-RC17"&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ivyDeps&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agg&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ivy&lt;/span&gt;&lt;span class="s"&gt;"dev.zio::zio:$zioVersion"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ivy&lt;/span&gt;&lt;span class="s"&gt;"dev.zio::zio-streams:$zioVersion"&lt;/span&gt;
  &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And we are done. We will need &lt;code&gt;zio-streams&lt;/code&gt; as well since we are going to treat our text like a stream of words.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple stream of words
&lt;/h2&gt;

&lt;p&gt;Create a folder named &lt;code&gt;WordCounter&lt;/code&gt; (it has to match the object name we defined earlier) and a &lt;code&gt;src&lt;/code&gt; folder nested inside. From there we can create a file named &lt;code&gt;Main.scala&lt;/code&gt; with the following empty canvas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// WordCounter/src/Main.scala&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio._&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.console._&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.stream._&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first thing that we want is to have a decent text source. A string variable will do.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val someText = "How much wood would a woodpecker peck if a woodpecker would peck wood?"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And the run function can become like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someText&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;splitOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;mkString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can run this with the command &lt;code&gt;mill --watch WordCounter&lt;/code&gt; (the watch will recompile and run when you save the file).&lt;/p&gt;

&lt;p&gt;You should see the output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How, much, wood, would, a, woodpecker, peck, if, a, woodpecker, would, peck
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The last word &lt;code&gt;wood?&lt;/code&gt; is not printed because it doesn’t end with a space. You can add a space at the end to include it if you want; I will add one before the question mark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Counting the words
&lt;/h2&gt;

&lt;p&gt;We have our stream of words we need now to do two simple operations. The first operation is to pair words that are the same, the second is to count them.&lt;/p&gt;

&lt;p&gt;The plan is to create one stream per word, since new streams are created and tracked by their key, setting their key to the word itself will work.&lt;/p&gt;

&lt;p&gt;Counting the words will be done by collecting all the words in a list per stream. At the end we can just count the length of the list that will tell the number of words for that particular word.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;streamOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;groupByKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;case&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;collectAll&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]).&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;identity&lt;/code&gt; function tells the &lt;code&gt;groupByKey&lt;/code&gt; to use the word itself as the key. Then, for every stream we create a tuple of type&lt;code&gt;(Int, String)&lt;/code&gt; that contains the count of the word and the word itself.&lt;/p&gt;

&lt;p&gt;The complete &lt;code&gt;run&lt;/code&gt; function looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someText&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;splitOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromChunk&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;groupByKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;case&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;collectAll&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]).&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;}.&lt;/span&gt;&lt;span class="py"&gt;runCollect&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;counts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;mkString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The only differnte being that we created a stream from the chunk of words and printed the count instead.&lt;br&gt;
Running this will print&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(2,would), (2,woodpecker), (2,peck), (1,How), (2,a), (2,wood), (1,much), (1,if)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple to Complex
&lt;/h3&gt;

&lt;p&gt;Admittedly we didn’t accomplish a lot. Just counting a few words is not really impressive. How about a word count of a sizeable file like the Divina Commedia? Let’s stash it in our &lt;code&gt;tmp&lt;/code&gt; folder for later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget http://www.gutenberg.org/files/1012/1012-0.txt --output-document /tmp/divina.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First we need to read the file. To do it correctly we will take the name of the file from the command line like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;headOption&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;getOrElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No file specified"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This means that if the argument is not passed the entire program will fail with an error that is represented by the string &lt;code&gt;No file specified&lt;/code&gt;. We are not printing the error anywhere now. To do it we need to adapt the code after the yield.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;headOption&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;getOrElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No file specified"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other code ...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that we turned the &lt;code&gt;map&lt;/code&gt; into a &lt;code&gt;fold&lt;/code&gt; that will return &lt;code&gt;1&lt;/code&gt; to the operating system in case of failure.&lt;/p&gt;

&lt;p&gt;After getting the file we create a new &lt;code&gt;InputStream&lt;/code&gt; which is the preferred way to read binary files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;newInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But this is a text file! 😱&lt;/p&gt;

&lt;p&gt;We will have to turn the pesky bytes into utf8 character.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;ZStream&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;chunks&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;utf8DecodeChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Notes on the notes on the code
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Warning&lt;/em&gt; From version &lt;code&gt;1.0.0-RC19&lt;/code&gt; on all streams work by chunk so the above code and below notes are outdated. Just delete &lt;code&gt;chunks&lt;/code&gt; and use a &lt;code&gt;ZTransducer&lt;/code&gt; insted of a &lt;code&gt;ZSink&lt;/code&gt; and it should just work.&lt;/p&gt;

&lt;h4&gt;
  
  
  Notes on the code
&lt;/h4&gt;

&lt;p&gt;Now I need your attention for a second as it’s not completely clear what is happening in the above code. The &lt;code&gt;ZStream.fromInputStream&lt;/code&gt; returns a &lt;code&gt;StreamEffectChunk&lt;/code&gt; type. This means that it’s a stream (the &lt;code&gt;Stream&lt;/code&gt; part, duh! 🤪) that it emits thunks (the &lt;code&gt;Effect&lt;/code&gt; part) and works with chunks of bytes instead of single bytes. By default the size of the chunks is 4096 but it can be set manually.&lt;/p&gt;

&lt;p&gt;The reason it emit thunks (lazily evaluated functions) is because it will read the next chunk of bytes only when the downstream is requesting them. This allows to read files that are bigger than the computer memory by doing it chunk by chunk.&lt;/p&gt;

&lt;p&gt;Finally, the reason it uses chunks instead of single bytes is because of speed. Reading 4096 bytes all at once is order of magnitudes faster than reading them one by one. (Why 4096? Usually the file systems can’t access &lt;em&gt;less&lt;/em&gt; than that, so if you set it to 1 for example, you are really accessing 4096 bytes and throwing away 4095 of them).&lt;/p&gt;

&lt;p&gt;Next we have a choice to make, we can either work with the chunks or with the single bytes. By writing &lt;code&gt;.chunks&lt;/code&gt; we cast to &lt;code&gt;StreamEffect&lt;/code&gt; with &lt;code&gt;Chunk[Byte]&lt;/code&gt; as emitted type. The alternative is &lt;code&gt;.flattenChunks&lt;/code&gt; which casts as well to &lt;code&gt;StreamEffect&lt;/code&gt; but now the emitted type is &lt;code&gt;Byte&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We go with &lt;code&gt;.chunks&lt;/code&gt; both for performance reasons and because there are some built-in functions that only work on chunks. The first one is aggregation with &lt;code&gt;ZSink.utf8DecodeChunk&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Counting Words for serial now!
&lt;/h3&gt;

&lt;p&gt;So we now are at a point in which we can generate &lt;code&gt;String&lt;/code&gt;s from the chunks of bytes. The next step is to separate the words. To do it we write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;ZStream&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;chunks&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;utf8DecodeChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;splitOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[\\w]+"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;splitOn&lt;/code&gt; unfortunately returns chunks so we “unchunk” them with &lt;code&gt;.flatMap(ZStream.fromChunk)&lt;/code&gt;. What this does is concatenating all the  chunks in strict order and emitting the strings inside them one by one.&lt;/p&gt;

&lt;p&gt;Next we filter the strings to make sure they are actual words. The &lt;code&gt;[\w]+&lt;/code&gt; regex basically means “letters of the alphabet and nothing else”.&lt;/p&gt;

&lt;p&gt;The last thing we need to do is count the words! By recycling the previous code we get the following program&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;headOption&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;getOrElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No file specified"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;inputStream&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;newInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;ZStream&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;chunks&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;utf8DecodeChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;splitOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[\\w]+"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;groupByKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;case&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="n"&gt;stream&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;collectAll&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;runCollect&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;counts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;_1&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;mkString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The only thing I did is sorting the results by occurrence.&lt;br&gt;
Launching this (&lt;code&gt;mill --watch WordCounter /tmp/divina.txt&lt;/code&gt;) will take about a minute ☕️ and will print something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(3616,e), (3535,che), (2260,la), (1859,a), (1826,di), (1339,non), (1319,per), (1123,in), (1042,si), (777,le), (752,li), (736,mi), (652,il), (623,con), ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Yes it’s a lot of work but a minute seems really long. I couldn’t figure out why it was so slow but I suspect the &lt;code&gt;groupByKey&lt;/code&gt; is optimized to work with a few of streams, not thousands.&lt;/p&gt;

&lt;h3&gt;
  
  
  A faster alternative
&lt;/h3&gt;

&lt;p&gt;A small modification will yield a much faster result (⚡️about 50x faster⚡️)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ZEnv&lt;/span&gt;, &lt;span class="kt"&gt;Nothing&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;headOption&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;getOrElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No file specified"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;inputStream&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;newInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nc"&gt;ZStream&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;chunks&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;utf8DecodeChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;aggregate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZSink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;splitOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ZStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fromChunk&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[\\w]+"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;])(&lt;/span&gt;
        &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;updatedWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;
            &lt;span class="n"&gt;maybeCounter&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;maybeCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
          &lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;counts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;_2&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;mkString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I swapped the &lt;code&gt;groupByKey&lt;/code&gt; with a fold and sorted by occurrence (which is now &lt;code&gt;_2&lt;/code&gt;).&lt;br&gt;
Maybe with older versions of scala it would be even faster with &lt;em&gt;mutable&lt;/em&gt; hash maps, but that would not be functional and thus not cool nor hip. I’m not even gonna try.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This was a short journey in very simple streaming applications. The &lt;code&gt;zio-stream&lt;/code&gt; code is still a bit clunky in my opinion but it clearly shows a lot of potential and will surely be more powerful than both &lt;code&gt;fs2&lt;/code&gt; and Akka Streams. In the next tutorial we are going to do some concurrent functional programming.&lt;/p&gt;

</description>
      <category>zio</category>
      <category>functional</category>
      <category>scala</category>
    </item>
    <item>
      <title>10 days with the ZIO 1/10</title>
      <dc:creator>Andrea</dc:creator>
      <pubDate>Fri, 13 Dec 2019 13:09:59 +0000</pubDate>
      <link>https://dev.to/gurghet/10-days-with-the-zio-1-10-1oom</link>
      <guid>https://dev.to/gurghet/10-days-with-the-zio-1-10-1oom</guid>
      <description>&lt;p&gt;I’m always in pursue in ways to scale down software development. Why? Because to scale up you need to scale down!&lt;/p&gt;

&lt;p&gt;When the size of the software system you are building goes up it becomes critical to have fast feedback loop, to be able to prototype new features and to debug quickly. You therefore need scalable tools in both ways.&lt;/p&gt;

&lt;h1&gt;
  
  
  Say Hello World to the ZIO
&lt;/h1&gt;

&lt;p&gt;The ZIO is a functional library to program in Scala that scales very well in both directions. In this mini series we are going to spend some time with the ZIO building 10 small projects. We will start with a Hello World program, but first a digression on Mill.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1vbluwhn1wn8ch5wqxbd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1vbluwhn1wn8ch5wqxbd.png" alt="Mill logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mill vs SBT
&lt;/h2&gt;

&lt;p&gt;I like SBT, I think it’s much better than Maven and Gradle. But I think it’s common opinion that it’s a fairly complex machine. It’s the poster child of an era in which everyone was coming up with his own DSL and exploiting all the most powerful scala features. Since you have to basically learn another language to build a scala project, it means you have to spend a lot of time coming up with the right solution for your particular problem with specialized SBT knowledge. Lastly it’s quite slow.&lt;br&gt;
Mill it’s an underrated build tool which resembles regular scala programming. It’s fairly easy to write a &lt;code&gt;build.sc&lt;/code&gt; (equivalent to &lt;code&gt;build.sbt&lt;/code&gt;) off the top of your head.&lt;br&gt;
To install it just &lt;code&gt;brew install mill&lt;/code&gt; or the equivalent for your operating system. &lt;/p&gt;
&lt;h3&gt;
  
  
  A blank slate
&lt;/h3&gt;

&lt;p&gt;Let’s create a new folder &lt;code&gt;hello-world-zio&lt;/code&gt; and inside it create a &lt;code&gt;build.sc&lt;/code&gt; file with the following content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// hello-world-zio/build.sc&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;mill._&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;scalalib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;_&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;zioHelloWorld&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ScalaModule&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scalaVersion&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2.13.0"&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;zioVersion&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.3"&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ivyDeps&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agg&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ivy&lt;/span&gt;&lt;span class="s"&gt;"dev.zio::zio:${zioVersion}"&lt;/span&gt;
  &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that we are creating a scala module called zioHelloWorld with the ZIO as dependency. The expected folder structure is very easy to remember&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello-world-zio/zioHelloWorld/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hello World from the ZIO
&lt;/h3&gt;

&lt;p&gt;We can create the expected file at the above folder &lt;code&gt;Hello.scala&lt;/code&gt;. We can put inside the simplest ZIO app I can think of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio._&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;zio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;console&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;_&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;putStrLn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;exitCode&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the &lt;code&gt;App&lt;/code&gt; is really &lt;code&gt;zio.App&lt;/code&gt; not the &lt;code&gt;App&lt;/code&gt; provided with scala. The &lt;code&gt;run&lt;/code&gt; has a slightly different signature. &lt;code&gt;putStrLn&lt;/code&gt; comes from the &lt;code&gt;Console&lt;/code&gt; module and by default it just prints to standard output. The final &lt;code&gt;exitCode&lt;/code&gt; is a convenience method that maps a success of the program to a &lt;code&gt;0&lt;/code&gt; to the operating system or a &lt;code&gt;1&lt;/code&gt; in case of an error. Many number correspond to a different error, here is a link to a &lt;a href="https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html" rel="noopener noreferrer"&gt;comprehensive list of errors&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Run, run. Click on run!
&lt;/h3&gt;

&lt;p&gt;To run our program you can use the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mill zioHelloWorld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;Hello World&lt;/code&gt; printed at the end of what seems to be some logging by &lt;code&gt;mill&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;Here is a working version on &lt;a href="https://scastie.scala-lang.org/4UFFrto4S9msPQWwil89eg" rel="noopener noreferrer"&gt;Scastie&lt;/a&gt; if you didn't follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;We have demonstrated how to the ZIO (with Mill) can easily scale down to a Hello World. We are going to use this minimalist template to build on top of it. Next up will be a word counter application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/gurghet/10-days-with-the-zio-2-10-4jpg"&gt;Go to day 2&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zio</category>
      <category>functional</category>
      <category>scala</category>
    </item>
  </channel>
</rss>
