<?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>Forem: Rafik Naccache</title>
    <description>The latest articles on Forem by Rafik Naccache (@turbopape).</description>
    <link>https://forem.com/turbopape</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%2F20140%2F4cd9b280-757e-4f2f-beef-0935ee939fe0.jpg</url>
      <title>Forem: Rafik Naccache</title>
      <link>https://forem.com/turbopape</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/turbopape"/>
    <language>en</language>
    <item>
      <title>Building turbo-ledger: A Scalable Ledger with Go and Redis</title>
      <dc:creator>Rafik Naccache</dc:creator>
      <pubDate>Sat, 09 Jul 2022 09:58:37 +0000</pubDate>
      <link>https://forem.com/turbopape/building-a-scalable-ledger-with-go-on-rediscloud-mo</link>
      <guid>https://forem.com/turbopape/building-a-scalable-ledger-with-go-on-rediscloud-mo</guid>
      <description>&lt;h1&gt;
  
  
  turbo-ledger: Why and How
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What's a ledger and why should we bother?
&lt;/h2&gt;

&lt;p&gt;In a nutshell, a ledger is a register we use to keep track of transactions in which people trade goods and services for assets that represent equivalent value.&lt;/p&gt;

&lt;p&gt;In the physical world, an asset's value stems from its scarcity as a physical object(think banknotes, wheat, gold, collector guitars,...)&lt;/p&gt;

&lt;p&gt;But online, assets are digital - and digital isn't scarce. As such, any amount's worth will only make sense if correctly traced back - through a set of authentic transactions - to a legitimate origin. That origin will create that scarcity that made physical world assets valuable(think bitcoins, NFTs, digital tokens,...). So in digital, ledgers ARE the assets.&lt;/p&gt;

&lt;p&gt;Hence being able to keep secure and scalable ledgers is of crucial importance in today's eCommerce-fueled world, where nearly every service is becoming digital. Tomorrow's money (and a significant part of today's) will only flow through digital bookkeeping!&lt;/p&gt;

&lt;p&gt;Keeping in mind that, let's explore a minimal ledger implementation that will provide bookkeeping services. We'll call it turbo-ledger, and will implement it in Go and will be fueled by Redis. &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;you can find it here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;turbo-ledger will revolve around two main entities, wallets and transactions. First, let's study wallets. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wallets: where the assets lie
&lt;/h2&gt;

&lt;p&gt;A Wallet, as the name suggests, is a bucket containing some digital funds. Just like we explained, what we care about most in a digital wallet are transactions as they constitute the very online money, but for the sake of convenience, we can keep some sort of balance field up to date at the wallet's level. &lt;br&gt;
Moreover, some information about the wallet identity needs to be present. For this post, we'll just use a plain ID and owner fields. &lt;br&gt;
Finally, we can qualify wallets with some tags: VIP, Personal,...&lt;/p&gt;

&lt;p&gt;If we go on and model this, the following would be a JSON object representing a Wallet:&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;"wallet_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"my_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transactions"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"balance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;"vip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"personal"&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;In a full-fledged implementation, we'll need to somehow attach a wallet to a cryptographic signer entity and maybe enforce real-world user identity-checking like verifying phone numbers or emails, but we'll settle for our toy-ish implementation in this post.&lt;/p&gt;

&lt;p&gt;And that will be it for our wallet object. Let's look closer at transactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transactions: Assets movement tracking
&lt;/h2&gt;

&lt;p&gt;A transaction will describe a certain amount of assets being transferred between a source and a destination wallets. For every transaction, we'll need to keep a record of the date when it happened. We'll also attach textual descriptions to transactions so they're augmented with some explanation. Finally, transactions will have an ID field.&lt;/p&gt;

&lt;p&gt;Here is a JSON object representation of our toy transaction:&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;"transaction_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"some_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"destination_wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dst_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transaction_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"description 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2022-06-07T19:02:01.0Z"&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;In a real-world setup, transactions need to be signed by an authorized source wallet owner and must be logged as they flow through the system with mention of their status, like the reason why they might have been discarded, etc. We might also want to make sure one cannot tamper with the transactions history(a la blockchain). But we'll stay with this minimal implementation we exposed for this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving Assets Around
&lt;/h2&gt;

&lt;p&gt;The workflow for transferring an amount of &lt;em&gt;amount_assets&lt;/em&gt; assets from source wallet &lt;em&gt;src_wallet&lt;/em&gt; to destination wallet &lt;em&gt;dst_wallet&lt;/em&gt; would be as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transaction submitted&lt;/li&gt;
&lt;li&gt;turbo-ledger verifies &lt;em&gt;src_wallet&lt;/em&gt; exists&lt;/li&gt;
&lt;li&gt;turbo-ledger verifies &lt;em&gt;src_wallet&lt;/em&gt; has enough balance to transfer to &lt;em&gt;dst_wallet&lt;/em&gt; (i.e balance is equal or greater than amount_assets)&lt;/li&gt;
&lt;li&gt;turbo-ledger verifies &lt;em&gt;dst_wallet&lt;/em&gt; exists&lt;/li&gt;
&lt;li&gt;turbo-ledger writes transaction (with &lt;em&gt;amount_assets&lt;/em&gt; negated - to simplify balance recomputing if needed in the future) in &lt;em&gt;src_wallet&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;system deduces &lt;em&gt;amount_assets&lt;/em&gt; from &lt;em&gt;src_wallet&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;turbo-ledger does the exact inverted thing to &lt;em&gt;dst_wallet&lt;/em&gt;:&lt;/li&gt;
&lt;li&gt;writes transaction (with positive &lt;em&gt;amount_assets&lt;/em&gt; ) to &lt;em&gt;dst_wallet&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;increases &lt;em&gt;dst_wallet&lt;/em&gt;'s balance by &lt;em&gt;amount_assets&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;for example, after an assets transfer operation of 5, here's what &lt;em&gt;src_wallet&lt;/em&gt; will look like (assuming a starting balance of 10) :&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;"wallet_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"src_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transactions"&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="nl"&gt;"transaction_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"a7749032-7be9-4cc8-a1b0-a14701bc1208"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source_wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"src_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"destination_wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"dst_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;-5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"transaction_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"my cool transaction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2022-06-07T19:02:01Z"&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;"balance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;"vip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"personal"&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;for &lt;em&gt;dst_wallet&lt;/em&gt;, assuming an initial balance of 0, we'd get:&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;"wallet_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"dst_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transactions"&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="nl"&gt;"transaction_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"a7749032-7be9-4cc8-a1b0-a14701bc1208"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source_wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"src_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"destination_wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"dst_wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"transaction_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"my cool transaction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2022-06-07T19:02:01Z"&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;"balance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;"normal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"professional"&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;Now we've seen how turbo-ledger foundational entities -wallets, and transactions -  are modeled and how asset transfers function, you'd agree we need a solid JSON-aware datastore with fast I/O and search capabilities. &lt;br&gt;
With that in mind, let's dive into the implementation. (Spoiler alert: we'll use Redis!)&lt;/p&gt;
&lt;h1&gt;
  
  
  A Naive turbo-ledger Implementation with Redis
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Why Redis?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;(DISCLAIMER: I got to discover &lt;a href="https://redis.io/docs/stack/json/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; and &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt; when I applied to the "Write for Redis" promotional program, which sponsors this post - and I am glad I did because I discovered those two great modules!)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be honest, I would not have considered Redis to implement turbo-ledger: Though I highly value Redis as a high throughput key-value data store, I was not aware of its JSON and Search capabilities through the &lt;a href="https://redis.io/docs/stack/json/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; and &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt; modules. But when I learned about them I fell in love! &lt;br&gt;
With &lt;a href="https://redis.io/docs/stack/json/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; and &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt;, you have a  fully JSON-fueled and indexed datastore, all accessed through the blazing-fast key-value paradigm in which Redis shines. No more needed to be said for me, I jumped in.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prototyping quickly with RedisCloud and RedisInsights Desktop
&lt;/h2&gt;
&lt;h3&gt;
  
  
  RedisCloud
&lt;/h3&gt;

&lt;p&gt;I was planning to work on turbo-ledger as a side project and so was not willing to allocate much time and effort to it.&lt;br&gt;
As such, I was not going to bother about Installing Redis or having it set up as a Docker container either on my already overloaded Mac. &lt;/p&gt;

&lt;p&gt;This is how I chose &lt;a href="https://redis.info/3NBGJRT" rel="noopener noreferrer"&gt;Redis Cloud&lt;/a&gt;, A Managed Redis service made by the Redis Team. I could easily set up a database for free with a trial account (no credit cards needed) and verified the needed modules (&lt;a href="https://redis.io/docs/stack/json/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; and &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt;) were present in that database. I was all set in a couple of minutes.&lt;/p&gt;

&lt;p&gt;To learn more about &lt;a href="https://redis.info/3NBGJRT" rel="noopener noreferrer"&gt;Redis Cloud&lt;/a&gt;, you can watch it here:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/vyxdC1qK4NE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  RedisInsights Desktop
&lt;/h3&gt;

&lt;p&gt;As explained, turbo-ledger was a side project for me, one that was on a tight time and effort budget. But it presented nevertheless an opportunity to learn about Redis modules that were new to me, &lt;a href="https://redis.io/docs/stack/json/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; and &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt;. So I needed some tool to help me explore commands and query JSON keys while I was working, and Redis CLI was not going to assist me with that.&lt;/p&gt;

&lt;p&gt;This is how I discovered &lt;a href="https://redis.info/3wMR7PR" rel="noopener noreferrer"&gt;RedisInsight Desktop GUI&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;With a few mouse clicks, I connected to my &lt;a href="https://redis.info/3NBGJRT" rel="noopener noreferrer"&gt;Redis Cloud&lt;/a&gt; database and started to play. &lt;/p&gt;

&lt;p&gt;I particularly loved the workbench, which allowed me to try commands, before going to the Go IDE:&lt;br&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%2Fnlsnckmhdy3ldc4ch0tr.jpg" 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%2Fnlsnckmhdy3ldc4ch0tr.jpg" alt="Redis Workbench Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also could explore JSON keys using the browser interface:&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%2Fn2oa05l3et0r4jsnv2bs.jpg" 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%2Fn2oa05l3et0r4jsnv2bs.jpg" alt="Redis RedisInsights Browser JSON"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I could even change JSON Keys in place which is very helpful when prototyping turbo-ledger:&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%2Fby5bbizug0tjbt2rvizk.jpg" 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%2Fby5bbizug0tjbt2rvizk.jpg" alt="Redis RedisInsights Browser JSON"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With all these tools in hand, let's go on modeling and coding turbo-ledger in Go and Redis!&lt;/p&gt;
&lt;h2&gt;
  
  
  Representing our wallets' Objects
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Wallets as JSON Documents
&lt;/h3&gt;

&lt;p&gt;A Wallet will be represented as a JSON key at Redis' level. We'll observe the following key scheme for wallets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wallet:wallet_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Redis, for instance, to create a wallet, you'd set a key with the JSON, exposed above, as a value, using the &lt;em&gt;JSON.SET&lt;/em&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JSON.SET wallet:wallet_id $ "{....}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the $ sign, which denotes the &lt;a href="https://redis.io/docs/stack/json/path/" rel="noopener noreferrer"&gt;JSON path&lt;/a&gt; of the element you want to change inside the JSON Document. In the above, that just means that we want the Input JSON document to sit at the root of the key, which simply means setting its value to it. &lt;/p&gt;

&lt;p&gt;But we can change a nested part of the document just as easily. For example, assume we want to set some wallet's balance to 10. We'd have to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JSON.SET wallet:wallet_id  $.balance 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wallets in Go
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledger's Go implementation&lt;/a&gt;, to create a Wallet, we have the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;walletId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startingBalance&lt;/span&gt; &lt;span class="kt"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newWallet&lt;/span&gt; &lt;span class="n"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;walletId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not create Wallet with empty Wallet Id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;strNewWallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errStrNewWallet&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newWallet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errStrNewWallet&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not marshal Wallet into json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errStrNewWallet&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;errCreateVaultWallet&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"JSON.SET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"wallet:%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;strNewWallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errCreateVaultWallet&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not create Wallet %s with command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errCreateVaultWallet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errCreateVaultWallet&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"successfully created Wallet %s with starting balance %f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;startingBalance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should have noticed how we're using plain Redis commands through &lt;a href="https://github.com/go-redis/redis" rel="noopener noreferrer"&gt;go-redis&lt;/a&gt; - choosing not to use any third-party &lt;a href="https://redis.io/docs/stack/search/clients/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt; or &lt;a href="https://redis.io/docs/stack/json/clients/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; specialized clients. This way, we stay as close as possible to Redis commands, not using any abstractions or ORMs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Indexing and searching through wallets
&lt;/h3&gt;

&lt;p&gt;Indexing data through &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt; is a novelty for me.&lt;br&gt;
Before, I only knew to access values knowing keys they're associated with - there was no way to query data on particular conditions on values. This had the Redis developer design key schemes that would hold parts of data, which was limiting and cumbersome to say the least. To get a sense of how this works, see the &lt;em&gt;checkWalletExists&lt;/em&gt; function implementation in the &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledger go implementation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;checkWalletExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;walletId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;walletId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not check Wallet with empty Wallet Id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="n"&gt;searchWalletCmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"JSON.GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"wallet:"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// get the key with ID information&lt;/span&gt;
    &lt;span class="p"&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, with &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt;, it is possible to create search indexes on particular elements of the value. In turbo-ledger, we created an Index on wallet owners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FT.CREATE idx:wallet:owner ON JSON SCHEMA $.owner AS owner TEXT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we can search wallets that are owned by bob like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FT.SEARCH idx:wallet:owner "@owner:(bob)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, we created an index to search through the transactions tags array. Note the use of the JSON Path $.tags.*:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FT.CREATE idx:wallet:tags ON JSON SCHEMA $.tags.* AS tags TAG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can search through wallets using tags through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FT.SEARCH idx:wallet:tags "@tags:{rich}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledger's Go implementation&lt;/a&gt;, you'll see Redis plain commands creating those indices in the &lt;em&gt;Genesis&lt;/em&gt; function, and using search in the &lt;em&gt;SearchWallets&lt;/em&gt; function&lt;/p&gt;

&lt;h2&gt;
  
  
  Representing Our transaction Objects
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Transactions inside Arrays in Wallets
&lt;/h3&gt;

&lt;p&gt;In redis, you use the &lt;em&gt;JSON.ARRAPPEND&lt;/em&gt; command to add an element to an array situation under a particular JSON path. In our case, here is the command to add a transaction to a wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JSON.ARRAPPEND wallet:wallet_id $.transactions {...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  You want transactional transactions
&lt;/h3&gt;

&lt;p&gt;Writing a transaction to the ledger involves verifying the source wallet's balance. If there's enough assets, we decrease that source wallet balance by the transaction's amount then add a transaction object to this wallet's transactions array. We will then mirror this process to the destination wallet (without balance verification).&lt;/p&gt;

&lt;p&gt;As you see, the overall transaction writing process entails multiple steps that need to happen all - or not to happen at all - for the turbo-ledger state to stay consistent. Does this ring a bell?&lt;/p&gt;

&lt;p&gt;Yes. These operations need to happen in a transactional way. when they happen, we need:&lt;br&gt;
0- verify the source balance&lt;br&gt;
1- the balance in source is updated&lt;br&gt;
1'- transaction is appended to the source's array&lt;br&gt;
2- the balance in destination is updated&lt;br&gt;
2'- transaction is appended to the destination's array&lt;br&gt;
Be done as a whole or:&lt;br&gt;
3- ... Do nothing&lt;/p&gt;

&lt;p&gt;For 1-1',2-2' and 3 we'll use &lt;a href="https://redis.io/docs/manual/transactions/" rel="noopener noreferrer"&gt;transactions in Redis&lt;/a&gt;&lt;br&gt;
In Redis, you start a transaction using the &lt;em&gt;MULTI&lt;/em&gt; keyword, then you start to queue commands, which you'll execute using &lt;em&gt;EXEC&lt;/em&gt; or discard using &lt;em&gt;DISCARD&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Now while you're queuing your transaction commands, someone or something else might have changed the source or destination's wallet balance - your increment or decrement operations might not be working on a clean state no more.&lt;/p&gt;

&lt;p&gt;This is where Redis' feature: &lt;a href="https://redis.io/docs/manual/transactions/#optimistic-locking-using-check-and-set" rel="noopener noreferrer"&gt;optimistic locking using check-and-set&lt;/a&gt; might come handy. &lt;br&gt;
if you issue a &lt;em&gt;WATCH&lt;/em&gt; on certain keys before beginning a Redis transaction with &lt;em&gt;MULTI&lt;/em&gt;, you tell Redis to monitor those keys for changes, and if this happens this will make your transaction execution with &lt;em&gt;EXEC&lt;/em&gt; fail - so you might choose to retry it. &lt;/p&gt;

&lt;p&gt;This is the approach we follow in the &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledger's Go implementation&lt;/a&gt;. &lt;br&gt;
We watch on the source and destination wallets involved in any transaction. &lt;br&gt;
We then start a &lt;em&gt;MULTI&lt;/em&gt; session, after which we &lt;em&gt;QUEUE&lt;/em&gt; series of &lt;em&gt;JSON.ARRAPPEND&lt;/em&gt; and &lt;em&gt;JSON.NUMINCRBY&lt;/em&gt;  as we go through the different verification steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We &lt;em&gt;WATCH&lt;/em&gt; the source and destination wallets&lt;/li&gt;
&lt;li&gt;We start a transactional session with &lt;em&gt;MULTI&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We verify the existence of the source balance. If not there, we &lt;em&gt;DISCARD&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We verify source balance. If not enough, we &lt;em&gt;DISCARD&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We Queue source balance decrease using &lt;em&gt;JSON.NUMINCRBY&lt;/em&gt; (using a negative amount)&lt;/li&gt;
&lt;li&gt;We Queue adding the transaction object to the source wallet transactions array using &lt;em&gt;JSON.ARRAPPEND&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We verify the existence of the destination balance. If not there, we &lt;em&gt;DISCARD&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We Queue destination balance increase using &lt;em&gt;JSON.NUMINCRBY&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;We Queue adding the transaction object to the destination wallet transactions array using &lt;em&gt;JSON.ARRAPPEND&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;And we &lt;em&gt;EXEC&lt;/em&gt; - catching errors that would have been emitted by the &lt;em&gt;WATCH&lt;/em&gt; Above and retry for &lt;em&gt;max_tries&lt;/em&gt; times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's have a look how this is implemented in &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledgers's Go Implementation&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Transactions In Go
&lt;/h3&gt;

&lt;p&gt;The above process is bootstrapped in the &lt;em&gt;PostTransaction&lt;/em&gt; function, exposed as a &lt;em&gt;REST API&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;PostTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redsync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;receivedTransaction&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errBind&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;receivedTransaction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;errBind&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not process received Transaction, %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errBind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received Transaction:%+v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receivedTransaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errProcessTransaction&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;processTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receivedTransaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;errProcessTransaction&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IndentedJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receivedTransaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IndentedJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCreated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receivedTransaction&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;To keep this post short and not overload you with code, I suggest you follow along reading through the &lt;em&gt;processTransaction&lt;/em&gt; and &lt;em&gt;attemptTransaction&lt;/em&gt; functions in the &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledger's Go implementation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That was quite a ride! But as you may have suspected, something's missing, as we called this part "naive" implementation. It's about race conditions, every distributed system's designer nightmare. Read-on.&lt;/p&gt;

&lt;h1&gt;
  
  
  Making turbo-ledger turbo
&lt;/h1&gt;

&lt;p&gt;So now turbo-ledger naively but happily serves its clients. But do you remember that "transactional transactions" scheme ?&lt;br&gt;
0- verify the source balance&lt;br&gt;
1- the balance in source is updated&lt;br&gt;
1'- transaction is appended to the source's array&lt;br&gt;
2- the balance in destination is updated&lt;br&gt;
2'- transaction is appended to the destination's array&lt;br&gt;
Be done as a whole or:&lt;br&gt;
3- ... Do nothing&lt;/p&gt;

&lt;p&gt;We are using a &lt;em&gt;WATCH&lt;/em&gt; to halt a transaction if any of the involved wallets' state changed during operation 1-1' and 2-2'. &lt;/p&gt;

&lt;p&gt;But... What if, after we happily (and naively) verified the source wallet's balance in 0, found enough assets there, and just were about to proceed with steps starting from 1-1', someone else spends some assets from that same source wallet?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;WATCH&lt;/em&gt; can't help us here, as it begins monitoring from 1-1'!&lt;br&gt;
Indeed, concurrent processes are racing over the source wallet balance in this case, because our Redis' Optimistic Locking only protects the system's state AFTER the source balance check.&lt;/p&gt;

&lt;p&gt;The situation that would occur then is called &lt;em&gt;double-spend&lt;/em&gt;, as if allowed, we erroneously would have spent assets that should not exist, as they've been spent by someone else (or a same fraudulent person) - it's like you've spend twice the same money! &lt;br&gt;
In this case, locking can be the solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  Preventing the Double Spend Problem with local locks
&lt;/h2&gt;

&lt;p&gt;One approach would be to lock the code section posting transactions. Entering the function, you'd ask to acquire a lock, and you'd release it when you're out. If someone else acquired the lock, you'd have to wait for its release up until a certain time. This will look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ProcessTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transaction&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;maxAttempts&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errTransactionWrongAmount&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;//Acquire single thread lock&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;//Make sure to unlock on exiting transaction&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c"&gt;//....&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this solution would definitely do the trick, it will imply a scalability problem: a lock is only valid in the execution context of a single instance of the ledger. If multiple turbo-ledger instances are accessing the Redis Database, having Go manage local locks in each turbo-ledger process won't protect users calling through one instance getting data compromised by users accessing through another. As such, you can only have one single turbo-ledger instance running at anytime, for this locking mechanism to stay valid. Hence, no horizontal scalability would be possible here. &lt;/p&gt;

&lt;p&gt;To address this, we can use a distributed-lock based version. How does it work?&lt;/p&gt;

&lt;h2&gt;
  
  
  Addressing double-spend with a Redis-based distributed lock: RedLock
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://redis.com/redis-best-practices/communication-patterns/redlock/" rel="noopener noreferrer"&gt;Redlock&lt;/a&gt; follows the spirit of the previous solution, but as it relies on a central Redis database to store the locks, locking becomes instance-independent, which will allow us to have as many turbo-ledger sessions as we please. This behavior is exposed in the current commit at the &lt;a href="https://github.com/turbopape/turbo-ledger" rel="noopener noreferrer"&gt;turbo-ledger's Go implementation&lt;/a&gt;, and is coded like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Preparing redsync instance&lt;/span&gt;
   &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;goredis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;redsync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;mutexname&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"global-wallets-mutex"&lt;/span&gt;
   &lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMutex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutexname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;
 &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;processTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transaction&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;maxAttempts&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redsync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errTransactionWrongAmount&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"acquiring global lock..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not acquire global mutex, aborting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"releasing global lock..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not release global mutex, aborting"&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="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 we can argue that we don't need &lt;em&gt;WATCH&lt;/em&gt; anymore. But I left it in the current implementation, as I am still investigating a means to have Redis manage everything without having locking at Go level, distributed or not. Maybe through LUA scripting? Let's see what the future holds!&lt;/p&gt;

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

&lt;p&gt;Congratulations for making it thus far! &lt;br&gt;
In this post, we've seen how to implement a scalable ledger based on Redis thanks to the powerful &lt;a href="https://redis.io/docs/stack/json/" rel="noopener noreferrer"&gt;RedisJson&lt;/a&gt; and &lt;a href="https://redis.io/docs/stack/search/" rel="noopener noreferrer"&gt;RediSearch&lt;/a&gt; modules, how the development experience and exploration on Redis can be made smooth using &lt;a href="https://redis.info/3NBGJRT" rel="noopener noreferrer"&gt;Redis Cloud&lt;/a&gt; and &lt;a href="https://redis.info/3wMR7PR" rel="noopener noreferrer"&gt;RedisInsight Desktop GUI&lt;/a&gt;. We also discussed &lt;a href="https://redis.io/docs/manual/transactions" rel="noopener noreferrer"&gt;Redis Transactions&lt;/a&gt; and saw how we needed also to protect against race conditions over source wallets balances in transaction starts, using &lt;a href="https://redis.com/redis-best-practices/communication-patterns/redlock/" rel="noopener noreferrer"&gt;Redlock&lt;/a&gt;.&lt;br&gt;
One last thing needs to be taken into consideration: as you're storing non-volatile, sensitive data, be sure to to understand the different &lt;a href="https://redis.io/docs/manual/persistence/" rel="noopener noreferrer"&gt;Redis Persistence&lt;/a&gt; models and applications, so you can choose the most secure data persistence model you see fit!&lt;/p&gt;

&lt;p&gt;To learn more about Redis, RedisInsight Desktop, and RedisCloud head over to the following links:&lt;br&gt;
&lt;a href="https://redis.info/3NBGJRT" rel="noopener noreferrer"&gt;Redis Cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://redis.info/3Ga9YII" rel="noopener noreferrer"&gt;Redis Developer Hub - tools, guides, and tutorials about Redis&lt;/a&gt;&lt;br&gt;
&lt;a href="https://redis.info/3wMR7PR" rel="noopener noreferrer"&gt;RedisInsight Desktop GUI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is in collaboration with Redis&lt;/p&gt;

</description>
      <category>redis</category>
      <category>go</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Plan like a Pro with Automatic Scheduling in Taskjuggler</title>
      <dc:creator>Rafik Naccache</dc:creator>
      <pubDate>Fri, 03 Jul 2020 10:09:37 +0000</pubDate>
      <link>https://forem.com/turbopape/plan-like-a-pro-with-automatic-scheduling-in-taskjuggler-3a15</link>
      <guid>https://forem.com/turbopape/plan-like-a-pro-with-automatic-scheduling-in-taskjuggler-3a15</guid>
      <description>&lt;h1&gt;
  
  
  The Need for Automatic Project Scheduling?
&lt;/h1&gt;

&lt;p&gt;Every one of us has done some project planning in a way or another. Some people would have used fancy GANTT editing tools for that; others would just go ahead and dump their brains onto a backlog. But very few are those who follow an automatic approach to "schedule" their projects.&lt;/p&gt;

&lt;p&gt;More often than not, people would go manually about making decisions about the gameplay to adopt facing their daunting projects. They try to envision the best possible plan while mentally trying to sort what we call "precedence constraints," i.e., one can't work on Task A before Task B and C have been achieved. They do so all while finding feasible and commercially viable resource allocation schemes. Also, they need to contort to time-bound constraints, like deadlines and seasonal phenomena.&lt;/p&gt;

&lt;p&gt;All that makes a perfect case for an automatic scheduling tool, and &lt;a href="https://taskjuggler.org/"&gt;Taskjuggler&lt;/a&gt; might be the most powerful - if not the only - mature alternative you have at hand. But this is not a shiny Kanban-y drag-and-drop thingy: this is a full-fledged enterprise-grade automatic project planning and estimating solution, so much that it takes some learning curve to get fluent in it, but believe me, the effort is worth it. &lt;/p&gt;

&lt;h1&gt;
  
  
  Taskjuggler: Thinking in Work Breakdown Structure
&lt;/h1&gt;

&lt;p&gt;Without drowning too deep in detail, &lt;strong&gt;Taskjuggler&lt;/strong&gt; lets you focus on your project structure. &lt;br&gt;
Rather than giving you GANTT drawing tools and letting you figure the plan out yourself, &lt;strong&gt;Tasjkjuggler&lt;/strong&gt; asks that you give it your &lt;strong&gt;Work Breakdown Structure&lt;/strong&gt;, and it does the scheduling for you. Simply put, A Work Breakdown Structure is a graph depicting the tasks you need to achieve, along with the relationships between them and the resources necessary to make them happen. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taskjuggler&lt;/strong&gt; is also able to follow on the realization of the project and will adjust the plan according to the actual project roll-out. Besides, it offers you the possibility to simulate multiple scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taskjuggler&lt;/strong&gt; is also finance aware, and sports an accounting module that can track the costs inferred by the allocated resources against revenues that you'd record as you're working on your project. I have used this accounting module so many times as my secret weapon to come up with detailed financial quotes and win the commercial race!&lt;/p&gt;
&lt;h1&gt;
  
  
  Taskjuggler in action
&lt;/h1&gt;

&lt;p&gt;First of all, you'll need to install &lt;strong&gt;Taskjuggler&lt;/strong&gt; &lt;a href="https://taskjuggler.org/tj3/manual/Installation.html#Installation"&gt;following the instructions on its website.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taskjuggler&lt;/strong&gt; comes as a line command, &lt;em&gt;tj3&lt;/em&gt;, that compiles your project descriptions into the project reports you specify. Let's run through a simple example.&lt;/p&gt;

&lt;p&gt;Suppose you want to specify a Software Development project. We first need the data engineer to design the database, then have the web designers design the application, then have the Devops deploy it.&lt;/p&gt;

&lt;p&gt;Let's begin by creating a file for our project. We'll name it project.tjp.&lt;/p&gt;

&lt;p&gt;We'll begin by specifying our project name, plus some general information about it, like its start date, and what would be the deadline for it(1 month from the start, hence the +1m":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project softdev "Software Development"  2020-08-16 +1m {
 timezone "Europe/Paris"
 currency "USD"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's then declare the financial accounts we'll be using to track the finances of our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account cost "cost"
account rev "payments"
balance cost rev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now declare the resources we need for our tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource data_engineer "Data Engineer" {
    rate 200
}

resource web_engineer "Web Engineer" {
    rate 200
}

resource devops_engineer "Devops Engineer" {
    rate 200
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;rate&lt;/em&gt; will be used to give a financial estimate of our project. We are using the simplest form, but you can organize them into teams, flag them, assign managers...&lt;/p&gt;

&lt;p&gt;Let's now get into the actual business. Next, we'll describe our Work Breakdown Structure, that is, tasks, constraints, and resources. We'll organize our tasks into to categories. &lt;strong&gt;Work&lt;/strong&gt;, where we'll describe our actual tasks to be done, and &lt;strong&gt;Milestones&lt;/strong&gt;, to track important steps and deliveries of our project. For this, we'll use the possibility to nest Tasks in &lt;strong&gt;taskjuggler&lt;/strong&gt;. First, let's see the &lt;strong&gt;Work&lt;/strong&gt; part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task work "Work"{
  task data "Database Design" {
    chargeset cost
    allocate data_engineer
    effort 3d # This task takes 10 days effort
  }

  task web "Web App Design" {
      chargeset cost
      allocate web_engineer
      effort 3d # This task takes 10 days effort
      depends !data  # This task needs task data to be complete
  }

  task deploy "Deployment" {
      chargeset cost
      allocate devops_engineer
      effort 3d # This task takes 10 days effort
      depends !web # This task needs task web to be complete
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;chargeset&lt;/strong&gt; clause is used to add the costs inferred by a resource working on a task to a particular account, which is &lt;strong&gt;cost&lt;/strong&gt; here. We'll use this account to get a quote for the whole work needed for this project.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;depends&lt;/strong&gt; construct tells &lt;strong&gt;Taskjuggler&lt;/strong&gt; that a task can't be worked on BEFORE the referred task has been achieved. This is what we call &lt;em&gt;"Precedence Constraint"&lt;/em&gt; in Work Breakdown Speak.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;depends&lt;/em&gt; clause uses the exclamation mark &lt;strong&gt;'!'&lt;/strong&gt; to refer to tasks that are one level higher in the hierarchy. For example, &lt;strong&gt;&lt;em&gt;deploy&lt;/em&gt;&lt;/strong&gt; depends on &lt;strong&gt;&lt;em&gt;!web&lt;/em&gt;&lt;/strong&gt; means that it depends on the task &lt;strong&gt;web&lt;/strong&gt; under a direct parent(one level up), yielding its direct sibling &lt;strong&gt;web&lt;/strong&gt;(their common parent task being &lt;strong&gt;work&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;Now for the &lt;strong&gt;Milestones&lt;/strong&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task milestones "Milestones" {
  task db_milestone "Database Finish" {
      # A milestone has effort 0, it's represented as a little black square
      depends !!work.data
  }

  task web_milestone "Web Finish" {
      # A milestone has effort 0, it's represented as a little black square
      depends !!work.web
  }

  task deploy_milestone "Deploy Finish" {
      # A milestone has effort 0, it's represented as a little black square
      depends !!work.deploy
  }

  task project_end_milestone "Project End" {
    depends !!work.deploy
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how now &lt;strong&gt;depends&lt;/strong&gt; uses a double exclamation mark. Look at task &lt;strong&gt;deploy_milestone&lt;/strong&gt; for instance. It is meant to track the completion of the &lt;strong&gt;deploy&lt;/strong&gt; task under the &lt;strong&gt;work&lt;/strong&gt; container task. At this level, we are under &lt;strong&gt;milestones&lt;/strong&gt;, so we need one &lt;strong&gt;!&lt;/strong&gt; to get to the level of the direct parent &lt;strong&gt;milestones&lt;/strong&gt;, then another more to get the grand-parent level, under which we get to the aunt task &lt;strong&gt;work&lt;/strong&gt; and refer &lt;strong&gt;deploy&lt;/strong&gt; by using a familiar dotted syntax, hence the &lt;strong&gt;!!work.deploy&lt;/strong&gt; token.&lt;/p&gt;

&lt;p&gt;At this point, our project description is finished, but if you run it through the &lt;strong&gt;taskjuggler&lt;/strong&gt; compiler, you won't get any output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tj3 project.tjp
&lt;span class="c"&gt;#... Truncated Output&lt;/span&gt;
Warning: This project has no reports defined. No output data will be generated.
Warning: None of the reports has a &lt;span class="s1"&gt;'formats'&lt;/span&gt; attribute. No output data will be generated.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, you need to specify reports to get the &lt;strong&gt;Taskjuggler&lt;/strong&gt; engine to compile the results under the format you want. And this is presumably the most complicated part. Here we go.&lt;/p&gt;

&lt;p&gt;We'll generate a static website. The entry point to the reports is the &lt;strong&gt;Overview&lt;/strong&gt; report page, with a link to detailed resource allocation by task under the &lt;strong&gt;Development&lt;/strong&gt; subreport, and a link to a resource Utilization under the &lt;strong&gt;Resource Graph&lt;/strong&gt; subreport.&lt;/p&gt;

&lt;p&gt;This post won't dive into the &lt;strong&gt;Taskjuggler&lt;/strong&gt; report syntax, but if you're interested, you can check it &lt;a href="https://taskjuggler.org/manual/general_usage.html"&gt;here&lt;/a&gt;. This being said, you can use the following as a template to start your pro scheduling journey - this is actually the way I followed (without necessarily being fluent in the syntax).&lt;/p&gt;

&lt;p&gt;The main report &lt;strong&gt;Overview&lt;/strong&gt; is specified like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;navigator navbar {
  hidereport @none
}

macro TaskTip [
  tooltip istask() -8&amp;lt;-
    '''Start: ''' &amp;lt;-query attribute='start'-&amp;gt;
    '''End: ''' &amp;lt;-query attribute='end'-&amp;gt;
    ----
    '''Resources:'''

    &amp;lt;-query attribute='resources'-&amp;gt;
    ----
    '''Precursors: '''

    &amp;lt;-query attribute='precursors'-&amp;gt;
    ----
    '''Followers: '''

    &amp;lt;-query attribute='followers'-&amp;gt;
    -&amp;gt;8-
]

textreport frame "" {
  header -8&amp;lt;-
    == Toy Software Development Project ==
    &amp;lt;[navigator id="navbar"]&amp;gt;
  -&amp;gt;8-
  footer "----"
  textreport index "Overview" {
    formats html
    center '&amp;lt;[report id="overview"]&amp;gt;'
  }



  textreport development "Development" {
    formats html
    center '&amp;lt;[report id="development"]&amp;gt;'
  }

   textreport "ResourceGraph" {
    formats html
    title "Resource Graph"
    center '&amp;lt;[report id="resourceGraph"]&amp;gt;'
  }
}

taskreport overview "" {
  header -8&amp;lt;-
    === Project Overview ===

    The project is structured into 3 phases.


    # &amp;lt;-reportlink id='frame.development'-&amp;gt;


    === Original Project Plan ===
  -&amp;gt;8-
  columns bsi { title 'WBS' },
          name, start, end, effort, cost,
          revenue, chart { ${TaskTip} }
  # For this report we like to have the abbreviated weekday in front
  # of the date. %a is the tag for this.
  timeformat "%a %Y-%m-%d"
  loadunit days
  hideresource @all
  balance cost rev
  caption 'All effort values are in man days.'

footer -8&amp;lt;-
    === Staffing ===

    All project phases are properly staffed. See [[ResourceGraph]] for
    detailed resource allocations.
  -&amp;gt;8-
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Report for "Development" is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;taskreport development "" {
  headline "Development - Resource Allocation Report"
  columns bsi { title 'WBS' }, name, start, end, effort { title "Work" },
          duration, chart { ${TaskTip} scale day width 500 }
  timeformat "%Y-%m-%d"
  hideresource ~(isleaf() &amp;amp; isleaf_())
  sortresources name.up
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and finally, the Report for "Resource Graph" is like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resourcereport resourceGraph "" {
  headline "Resource Allocation Graph"
  columns no, name, effort, rate, weekly { ${TaskTip} }
  loadunit shortauto
  # We only like to show leaf tasks for leaf resources.
  hidetask ~(isleaf() &amp;amp; isleaf_())
  sorttasks plan.start.up
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, save the project definition and compile it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tj3 project.tjp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;after successful scheduling, you'll see a set of HTML files and other assets that have been created. Head over to &lt;strong&gt;Overview.html&lt;/strong&gt; in your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T5-2YiBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/4itzb55kh6ppc2a7x6b7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T5-2YiBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/4itzb55kh6ppc2a7x6b7.jpg" alt="Alt Text" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see &lt;strong&gt;Taskjuggler&lt;/strong&gt; has computed a schedule for you. Verify that &lt;strong&gt;precedence&lt;/strong&gt; has been respected. Note the cost by task and for the overall project (we have no revenue at this point). Also, see how the &lt;strong&gt;Work&lt;/strong&gt; and &lt;strong&gt;Milestones&lt;/strong&gt; umbrella tasks make our project schedule clearly presented by separating work to be done and the expected deliveries or milestones.&lt;/p&gt;

&lt;p&gt;Let's explore the detailed task description by clicking on the &lt;strong&gt;Development&lt;/strong&gt; link:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HxwwsMVx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/mespdqr2y2zwtgbmw2kr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HxwwsMVx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/mespdqr2y2zwtgbmw2kr.jpg" alt="Alt Text" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see in this Report how tasks are being worked on by each resource.&lt;/p&gt;

&lt;p&gt;Now head over to the &lt;strong&gt;Resource Graph&lt;/strong&gt; report to see how are resources being used overall in this project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WiXuqbHC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/5ign47qvhefpnskbu0qf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WiXuqbHC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/5ign47qvhefpnskbu0qf.jpg" alt="Alt Text" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can notice how this report shows how much is every resource being loaded during the execution of its assigned tasks.&lt;/p&gt;

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

&lt;p&gt;We just scratched the surface of what's possible with &lt;strong&gt;Taskjuggler&lt;/strong&gt;. It is really a unique scheduling beast; one that can accomplish so much, but which is unfortunately not well served by its looks.&lt;br&gt;
First, the only viable option to interact with it now is the proprietary syntax we've covered. This is showing its limits, as very poor tooling exists, and for large projects, with complex task hierarchies and report schemes, one can easily feel lost.&lt;br&gt;
Second, although it's possible to track the progress of projects, &lt;strong&gt;Taskjuggler&lt;/strong&gt; lacks advanced enterprise collaboration features. I think I've read somewhere it has a server or something, but I don't think it's of any practical use right now.&lt;/p&gt;

&lt;p&gt;All of these problems make this tool only fit for the vim-savvy engineer, unfortunately. But once mastered, this is a very sharp one to run accurate time and money estimates, and to effectively track costs, and I think it can perfectly sit next to other collaborative agile Trellos and Jiras.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>project</category>
      <category>management</category>
      <category>tasks</category>
    </item>
    <item>
      <title>Scripting Containers With No Daemons using Podman</title>
      <dc:creator>Rafik Naccache</dc:creator>
      <pubDate>Fri, 26 Jun 2020 10:54:10 +0000</pubDate>
      <link>https://forem.com/turbopape/scripting-containers-with-no-daemons-using-podman-2mha</link>
      <guid>https://forem.com/turbopape/scripting-containers-with-no-daemons-using-podman-2mha</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MHw_w5dU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://podman.io/images/podman.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MHw_w5dU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://podman.io/images/podman.svg" alt="Podman Logo" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Containers With No Daemons?
&lt;/h1&gt;

&lt;p&gt;Believe it or not, I had to check this whole story when I failed to find any trivial way to stop my crawlers from eating all of my CPU cycles. I had the intuition to containerize them, then let the container runtime make these uncontrollable gremlins behave: I would run the crawlers as containers, setting system usage limits for them upon creation. &lt;/p&gt;

&lt;p&gt;But I was held back by the way Docker relied on heavy daemons to work back then. Remember, my crawlers are supposed to be tiny un-noticeable anti-virus like programs - this is why we were bothering with this CPU story in the first place - so having Docker tooling and daemons as prerequisites was not an option.&lt;/p&gt;

&lt;p&gt;I then explored "docker-less" or "daemon-less" solutions, so I stumbled upon alternatives like &lt;a href="http://docs.podman.io/en/latest/index.html"&gt;podman&lt;/a&gt; which is a lib that runs your containers with no running servers, or &lt;a href="https://buildah.io/"&gt;buildah&lt;/a&gt; that can build your Dockerfiles under the same conditions - no daemons running. The prospect of these solutions was promising, but they could only run on Linux, and as we were writing desktop software, it had to run on Windows at least, so I ended up writing my own &lt;a href="https://dev.to/turbopape/the-chronicles-of-nowhere-man-in-systems-land-4fib"&gt;CPU limiting code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But these {docker,daemon}-less solutions are essential nonetheless: You'll be most probably facing more places where you need to leave docker comfort and work with alternative container runtimes (I am looking to you Kubernetes administrators). &lt;br&gt;
So how easy is it to switch?&lt;/p&gt;
&lt;h1&gt;
  
  
  The Benefits of Standardization and Libpod
&lt;/h1&gt;

&lt;p&gt;Docker, as a company, has made a great job making &lt;strong&gt;the Container&lt;/strong&gt; what it is now, at the center of nearly every software engineering breakthrough we've seen in the last couple of years. &lt;/p&gt;

&lt;p&gt;But they have contributed to an even more significant effort: the standardization of &lt;strong&gt;the Container&lt;/strong&gt; landscape, through the &lt;a href="https://www.opencontainers.org/"&gt;Open Container Initiative - the OCI&lt;/a&gt;, along with other industry players.&lt;/p&gt;

&lt;p&gt;Thanks to this standardization effort, it is possible for &lt;strong&gt;podman&lt;/strong&gt; to rely on an OCI compliant &lt;a href="https://developers.redhat.com/blog/2018/02/22/container-terminology-practical-introduction/#h.6yt1ex5wfo55"&gt;Container Runtime&lt;/a&gt; to run and manage &lt;em&gt;Containers&lt;/em&gt; on a Linux operating system. They're doing so under the form of a self-contained package &lt;a href="https://github.com/containers/libpod"&gt;libpod&lt;/a&gt;, thus providing us with a lightweight tool, with no servers to install at all, to run, monitor, stop, pull and tag our containers, just like you'd do with Docker. On their website, they say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Podman specializes in all of the commands and functions that help you to maintain and modify OCI container images, such as pulling and tagging. It allows you to create, run, and maintain those containers and container images in a production environment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Podman in action
&lt;/h1&gt;

&lt;p&gt;You begin by installing &lt;strong&gt;podman&lt;/strong&gt;. This will result in a binary that you'll use to create your Containers (on Linux. For Mac and Windows, it's another story). The installation instructions are &lt;a href="https://podman.io/getting-started/installation"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run a Container, you just use the &lt;strong&gt;podman&lt;/strong&gt; command to create one with a Docker (or any OCI Compliant) image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman run &lt;span class="c"&gt;#... your classical options as you'd do in Docker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As in Docker, you can list the running Containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Using &lt;strong&gt;podman&lt;/strong&gt;, on a Linux machine, you can easily express your scripts in terms of Containers. There will be no unnecessary daemons haunting your space.&lt;br&gt;
&lt;strong&gt;libpod&lt;/strong&gt;, along with other OCI Compliant Runtime engines, are becoming more commonplace in the Kubernetes landscape. So Kubernetes admins might want to skill up in these runtimes and understand the trade-offs they are making when choosing one runtime over another in terms of functionality, security, and performance. &lt;/p&gt;

&lt;h1&gt;
  
  
  Further Reding
&lt;/h1&gt;

&lt;p&gt;This post is heavily inspired by the following excellent piece: &lt;a href="https://mkdev.me/en/posts/dockerless-part-1-which-tools-to-replace-docker-with-and-why"&gt;Dockerless, part 1: Which tools to replace Docker with and why&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might also want to check these following canonical references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://docs.podman.io/en/latest/index.html"&gt;podman documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/containers/libpod"&gt;libpod Github Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencontainers.org/"&gt;Open Container Initiative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.redhat.com/blog/2018/02/22/container-terminology-practical-introduction/#h.6yt1ex5wfo55"&gt;A Practical Introduction to Container Terminology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.redhat.com/topics/containers/"&gt;Building containerized applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A mirror problem for daemonless Container Running is the daemonless container building. For this, you might want to check &lt;a href="https://buildah.io/"&gt;Buildah&lt;/a&gt;&lt;/p&gt;

</description>
      <category>containers</category>
      <category>podman</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>NuID: Trustless Authentication Using Zero-Knowledge Proofs on the Blockchain</title>
      <dc:creator>Rafik Naccache</dc:creator>
      <pubDate>Sun, 21 Jun 2020 21:24:14 +0000</pubDate>
      <link>https://forem.com/turbopape/nuid-trustless-authentication-using-zero-knowledge-proofs-on-the-blockchain-4cch</link>
      <guid>https://forem.com/turbopape/nuid-trustless-authentication-using-zero-knowledge-proofs-on-the-blockchain-4cch</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The Cover Image is taken from the &lt;a href="https://nuid.io/"&gt;NuID Website&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A while back, I got contacted by Locke Brown, the CEO of &lt;a href="https://nuid.io/"&gt;NuID Inc&lt;/a&gt; (read: New ID as in new identity management). He explained to me how his startup aspires to revolutionize the way we deal with identity and passwords in the world wild webs (pun intended). The promise of NuID is that they'd free us from the breaches leaking our passwords and the internet super-powers eavesdropping on us, by implementing a "Trustless Identity" solution on the Ethereum Blockchain Technology.&lt;/p&gt;

&lt;p&gt;They spotted I once starred an authentication library in Clojure, so they thought I would be interested in giving their API a try. Needless to say, this is a compelling story to a &lt;a href="https://dev.to/turbopape/the-chronicles-of-nowhere-man-in-systems-land-4fib"&gt;nowhere man&lt;/a&gt; like myself, with a refreshing mixture of Clojure, Blockchain, Distributed Shared-Nothing authentication mechanism, so I gave it a very light test drive. I thought you might be interested in my discoveries so here we go! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wrote this post on my very own initiative, I am not endorsing this company nor any of their products.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The Problem in Central Identity Management
&lt;/h1&gt;

&lt;p&gt;So what's wrong in Centrally Managed Identity? To prove you are who you are pretending to be, online services rely on "Identity and Authentication Providers": These are services that store your identity along with your presumably secret access token. Whenever you log to apps using their credentials, or your handle at Facebook, Google, Github, Whatever... You first authenticate yourself with a central authenticating tier to prove your identity. &lt;/p&gt;

&lt;p&gt;The problem lies in the very reliance on this central authority. You are "trusting" some internet being with your secret tokens - but you might be telling this "trustee" how you unlock other private stuff as well...Let's be honest, we pretty much use the same password for the twenty-something websites and email providers we access every day!&lt;/p&gt;

&lt;p&gt;And even if this authentication store is no maleficient, it might not be protected against security breaches, and your precious identity can be leaked (check the &lt;a href="https://monitor.firefox.com/"&gt;Firefox Monitor&lt;/a&gt; to see if your handles have been leaked). &lt;/p&gt;

&lt;h1&gt;
  
  
  Zero-knowledge proof: The solution
&lt;/h1&gt;

&lt;p&gt;So NuID suggests keeping your secrets well...secret. With their authentication mechanism, Called the "Zero-Knowledge Proof(ZKP)," No single central authority requires you to trust them with your access tokens. Instead, NuID uses ZKP to cryptographically derive from someone's secret a set of non-sensitive public tokens. It's not possible to tell the original password only knowing these tokens, yet they can be used to prove the knowledge of this very secret.&lt;/p&gt;

&lt;p&gt;These public tokens will be immutably stored on the Blockchain (I think I've read Ethereum's Rinkeby somewhere...), so there will be no single central point in the architecture, nor it will be possible to mess around with those tokens. I think this excerpt from the &lt;a href="https://nuid.io/pdf/solution-overview.pdf"&gt;Solution document&lt;/a&gt; describes it best:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The NuID protocol immutably stores public reference parameters on a blockchain, so that they can be shared but not tampered with. A blockchain provides a trustless infrastructure with no central point of failure. &lt;/p&gt;

&lt;p&gt;Combining these technologies allows users to own and manage their authentication credentials while enabling companies to authenticate without storing and protecting sensitive information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Developer Relations
&lt;/h1&gt;

&lt;p&gt;The solution evolves mainly around API, and as such, their primary customers will be developers. So how appealing do they look to them?&lt;/p&gt;

&lt;p&gt;First of all, I must confess I really appreciated the way they found me and personally reached out to me.  I think they care about building their community and are carefully picking up potential testers, which is a positive signal I for one was able to read from them.&lt;/p&gt;

&lt;p&gt;They also built a &lt;a href="https://portal.nuid.io/"&gt;developer portal&lt;/a&gt;, which lets you test-drive their platform. It comes with fairly comprehensive documentation, and you should write your first authentication queries with no issues. Here's what's working with NuID tastes like (Using Curl, but you can use any of their client libs)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-API-Key: my-api-key'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://auth.nuid.io/credential/gtgndTplbGxpcHRpYy5jdXJ2ZS9wb2ludHgsQStZelIvajZqdUxBS0pOWGJGaGw4UXczaXcrQ2ViWVJwa0RsN1hPQ2hETHM&lt;span class="se"&gt;\=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the result is:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pub&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;point&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="s2"&gt;A+YzR/j6juLAKJNXbFhl8Qw3iw+CebYRpkDl7XOChDLs&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="s2"&gt;curve&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&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="s2"&gt;secp256k1&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keyfn&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&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="s2"&gt;scrypt&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="s2"&gt;normalization-form&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="s2"&gt;NFKC&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="s2"&gt;salt&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="s2"&gt;TgbyOFik/5YxUl+TzufPnDoL6XZVgEq0f8cNr6qd9KY=&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="s2"&gt;key-length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addresses&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="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transaction-id&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="s2"&gt;0x17da3d71783be5b509abd713e983ddc1fd3698d39bc02feeae782d67ba12772a&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="s2"&gt;network&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="s2"&gt;rinkeby&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code of the platform can be found on &lt;a href="https://github.com/NuID"&gt;Github&lt;/a&gt;. This is done in Clojure, and in &lt;a href="https://www.youtube.com/watch?v=zdX-uUqPjqs"&gt;This talk&lt;/a&gt; the CTO explains their use of Clojure along with Datomic. &lt;/p&gt;

&lt;h1&gt;
  
  
  Further Reading
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nuid.io/#/docs"&gt;NuID platform docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.nuid.io/passwords-privacy-identity/"&gt;Privacy, Passwords and (Nu)Identity on the company's Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nuid.io/pdf/solution-overview.pdf"&gt;The Solution Overview Document&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nuid.io/pdf/data-sheet.pdf"&gt;The Solution Datasheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://theconsultingcto.com/posts/continuous-delivery-with-terraform/"&gt;A presentation about the company's software processes and their use of Terraform among other things &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cryptography</category>
      <category>authentication</category>
      <category>blockchain</category>
      <category>clojure</category>
    </item>
    <item>
      <title>Let's Play Checkers with AI and Clojure</title>
      <dc:creator>Rafik Naccache</dc:creator>
      <pubDate>Fri, 12 Jun 2020 13:06:47 +0000</pubDate>
      <link>https://forem.com/turbopape/let-s-play-checkers-with-ai-and-clojure-3jco</link>
      <guid>https://forem.com/turbopape/let-s-play-checkers-with-ai-and-clojure-3jco</guid>
      <description>&lt;h1&gt;
  
  
  Logic Programming: A forgotten Field in AI
&lt;/h1&gt;

&lt;p&gt;Nowadays, when you hear "AI," you are probably going to think about neural networks and model training, starting to reach for data sets and envisioning how to feed them into the learning machine. &lt;br&gt;
In this post, I will try to revive a more or less forgotten way to do things—the Logic programming way.&lt;/p&gt;

&lt;p&gt;Logic programming is an exciting paradigm, according to which one expresses programs in terms of relations involving some logic variables, and expects results reflecting what do these logical variables have to be so to make sure those relations are verified(Pfeww!). &lt;/p&gt;

&lt;p&gt;We are so talking about "goals" that we want to succeed: We want those relations to be actually occurring, and search for the values of our logic variables that would make that happen. &lt;/p&gt;

&lt;p&gt;You can see how this sort of programming - also known as relational programming - lays the foundation of an alternative way of approaching computing. It's a declarative method in which you don't explicitly specify how to process inputs into outputs, but where you instead express queries about logical variables arranged in a set of desired relations.&lt;/p&gt;

&lt;p&gt;For example, consider the following logical function :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;multiplio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&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;that stands for a goal (or a relation) succeeding if z equals x times y.&lt;br&gt;
It will succeed if you query for its result while you specify a relevant value for all of the three logical variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;multiplio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;;=&amp;gt;Success&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if you specify that you want to know for which values of z it will succeed, specifying actual, fixed values for x and y, you are sort of multiplying two numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;multiplio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;;=&amp;gt; Success for q = 6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More interestingly, you can ask what might the value of x be given that y is set to 2 and that the product z at 6&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;multiplio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;;=&amp;gt; Success for q = 2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous examples showed how you can write programs in terms of relations, or logic goals, and specify or ask for the values of the variables you please: No inputs, no outputs, just relations.&lt;/p&gt;

&lt;p&gt;Of course, when it is unable to make your goals succeed, the relational kernel will give you "nothing." On the other hand,  if it notices that the goals are achieved every time, it returns a particular value that says, well, everything.&lt;/p&gt;

&lt;p&gt;In the following, we will use relational programming to create an AI solving a round of checkers game. We will use a particular language for logic programming, &lt;a href="http://minikanren.org/"&gt;miniKanren&lt;/a&gt;, through its  Clojure implementation, &lt;a href="https://github.com/clojure/core.logic"&gt;core.logic&lt;/a&gt;. &lt;/p&gt;

&lt;h1&gt;
  
  
  A core.logic Primer
&lt;/h1&gt;

&lt;p&gt;In core.logic, you run your queries using a special interface, run like in the following simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&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="nb"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;That is, you're asking core.logic to run a query over the logical variable q, so that the goal (== q 1)  is verified. == is miniKanren's unification, that is, the mecanism that makes a goal who succeeds if the terms involved are the same, which sets q to (1) in our particular example. Unification is a very important operation in logical programming, and is implemented up to the level of nested Clojure datastructures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&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="nb"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;yields (1), as we must have q set at 1 so we have the first vector as [1 2] in order to have it unified with the second term.&lt;br&gt;
But the careful reader may wonder: why do we have results laid out in sequences? This is beause the logical variable we are querying over might happen to take multiple possible values; as a matter of fact, you can choose how many solution do you want core.logic to go up to. We did mention run* (star) in our query because we want all of the solutions. If we did only want to uncover first five of them, we could have emitted a query like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&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="nb"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;h1&gt;
  
  
  Playing a Checkers round
&lt;/h1&gt;

&lt;p&gt;Enough talk and let's play checkers. For this, we are going to implement an artificial intelligence kernel capable of analyzing some checkers' board, determining – under the game rules – where to move while staying out of the reach of its opponent's attacks, and spotting when it can capture some of the enemy's soldiers.&lt;br&gt;
Let's go through a little remainder of the game of checkers. You and your opponent evolve on a square chessboard, but you can only move on diagonals over black squares one step at a time. Also, you can only move forward. Both of you can capture an enemy piece if it is situated just one step away from one of your pieces, provided that when you jump over it following the diagonal, the black square where you're landing is empty. If, while doing so, from that new position, you can capture another piece, you may go on.&lt;/p&gt;
&lt;h1&gt;
  
  
  Modeling the Game
&lt;/h1&gt;

&lt;p&gt;To model the battle scene, we are going to consider three sets: one for the empty positions, one for the only piece that belongs to the checkers' solver engine, and one for the enemy's locations. To describe a particular situation, you may tell the solver what's in each of these sets. As far as the items that will be put in them are concerned, we will store in them coordinates of positions on the checker's board. For instance, to tell that the enemy has 3 pieces, we just throw the 3 vectors representing the positions where these pieces are in the enemy's set. &lt;/p&gt;

&lt;p&gt;The following figure explains how we are going to represent the different positions on a chessboard of 6 squares edges. Note that for its construction, to consider only the black squares, we are going to alternate a set of vectors crossing even with odd coordinates, then odd with even ones.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DdF1GdDS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vwgz7dgmp0k8slnqnl4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DdF1GdDS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vwgz7dgmp0k8slnqnl4g.png" alt="Alt Text" width="241" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solver is concerned about three significant matters when trying to figure out the action it must take: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where to put the checker, &lt;/li&gt;
&lt;li&gt;Will the moving piece be captured when it goes there, &lt;/li&gt;
&lt;li&gt;Whether it can win one or more of its opponent's pieces if after jumping, he has the opportunity to do so. Let's implement it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Building the Chessboard
&lt;/h2&gt;

&lt;p&gt;For starters, we are going to declare our ns. Note that we are using the finite domain constrains engine, clojure.core.logic.fd, to be able to derive goals where algebraic operations are involved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recipe19.core&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clojure.core.logic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logic&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="n"&gt;clojure.core.logic.fd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fd&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 now focus on constructing the chessboard. As we mentioned earlier, we will build a set of vectors, associating odd x coordinates with even y ones, then the other way around: even x coordinates with odd y ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;evenso&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&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="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;se&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="nf"&gt;fd/in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We construct a set of integers&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; going from 0 to half the size&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; using a core.logic finite domain&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; facility&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;se&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; we construct the even coords&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;se&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; and we output them by unifying them&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; with output&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oddso&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&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="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&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="nf"&gt;fd/in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;/&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; Same logic applies for odd part&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We generate an even number&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; Then we add 1 to it&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We ensure that we do not exceed&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; size&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; And we unify with output&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;boardo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&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="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&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="nf"&gt;oddso&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&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="nf"&gt;evenso&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; Then starting from even and odd numbers&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; We combine a first set of vectors&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; Crossing [even odd]&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;])])))&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; And crossing [odd even]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Moving the piece
&lt;/h2&gt;

&lt;p&gt;Let's build the goal function that determines where our piece shall go starting from a current position. This moves our piece up, incrementing the y part of the coordinates, and go to the left and to the right by adding or deducing 1 from the x component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;where-to-movo&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur-pos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&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="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;curx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cury&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="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;curx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cury&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur-pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We destructure the position into&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; x and y parts&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;curx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&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="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;curx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We go left or right,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; adding or substracting 1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; to x and storing it into -&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cury&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We can only move up, adding 1 to y&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; and storing it into -&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/membero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We verify that the target position&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; is empty by seeing if it is present&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; in the empty set&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; And we unify with the output&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Don't Get Captured!
&lt;/h2&gt;

&lt;p&gt;After the solver has determined where it can move its piece, it needs a goal function that tells if, at that position, that piece won't be captured by any of the opponent's pieces. That's the aim of the following goal function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isnt-capturedo&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mypos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&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="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="n"&gt;new-y&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="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemy&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="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mypos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We destructure enemy and our&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; position&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&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="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; As core.logic.fd can't handle&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; negative numbers, we must use&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; a conde so we can get the difference&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; between the coords, whether is enemy's x higher&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; than the solver's, or the other way around.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; We know that the opponent can only go down&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; so we are able to proceed with a single&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; substraction, that is the opponent's y minus the&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;;; solver's&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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="nf"&gt;fd/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; This enemy's piece is close&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; enough to the solver's, let's check&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; if it can capture it.&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conda&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; Where is the landing x coord had&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; the enemy captured the solver's&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; if it is at its left?&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;fd/+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; And where would it be if it did come&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; feom the right?&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; What would the landing position y be, after&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; capture of the solver's piece?&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/nafc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logic/membero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; If it is not empty, the solver's piece is&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; safe &lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&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="nf"&gt;fd/&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; The difference between coordinates&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; on the x axis is higher than 1,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; This piece isn't a threat to us&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)])))&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; Same logic for the Y axis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Catch'em all!
&lt;/h2&gt;

&lt;p&gt;Our artificial checkers' player needs a goal function to help him spot the opportunity of capturing some enemy pieces. This is a recursive process, as after jumping over the piece it captured, we need to check if there is something else to recapture. That's why we built a tabled goal, that ensures termination by "memoizing" the different values taken by the tabled logical variables and deciding to exit en execution whenever the same patterns are encountered over and over again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemy-piece-capturo&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/tabled&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c1"&gt;;; A tabled goal ensures that our&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c1"&gt;;; recursive goal terminates by&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c1"&gt;;; detecting recurrent patterns&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c1"&gt;;; among the values of the logical&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c1"&gt;;; variables&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pos-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;out&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="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="n"&gt;new-path&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="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pos-&amp;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="nf"&gt;logic/membero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; We destructure our piece's and&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; all of the enemies' positions&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&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="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; As negative numbers are considered&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; as failing goals, we yield a union&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; of both cases to be sure to get a&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; difference in x-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; We know that this is our piece,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; we can only go up&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;fd/&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;fd/-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-x&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="nf"&gt;fd/&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;fd/+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; the new-position's x after jumping,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; adding +1 or -1 to the captured piece's x&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; depending of whether&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; we are going right or left&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; New y can only be the enemy's piece incremented&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; by 1 as we go always up.&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/membero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; This landing position must be empty&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fd/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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="nf"&gt;fd/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; And we must be exactly one square away&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; from the opponent's captured piece&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                         &lt;/span&gt;&lt;span class="no"&gt;:capture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-&amp;gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                         &lt;/span&gt;&lt;span class="no"&gt;:then-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; At this point we have a new path:&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; Where we started, what did we capture&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="c1"&gt;;; and where we landed&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;new-path&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; we emit this new path,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; as if we were to stop here,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; this is considered a legal move.&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&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="nf"&gt;enemy-piece-capturo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt;
                              &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                              &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
                              &lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="c1"&gt;;; And we recursively check for another possible&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="c1"&gt;;; piece to capture, adding any new discovered&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="c1"&gt;;; path to what we've captured so far&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/conjo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:then-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&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;h2&gt;
  
  
  Sticking it all together
&lt;/h2&gt;

&lt;p&gt;With all the building blocks for the chessboard analyzer ready, we can design a goal function that plays a round of checkers, minding all of the three matters constituting the engine's life: moving, keeping away from being captured and capturing enemy's soldiers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;play-roundo&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/tabled&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="n"&gt;cur-pos&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="c1"&gt;;; This is a tabled goal so we can&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="c1"&gt;;; avoid some redundancy in the results&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="c1"&gt;;; caused by the unification engine&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-pos&lt;/span&gt;&lt;span class="w"&gt;
                               &lt;/span&gt;&lt;span class="n"&gt;new-empty&lt;/span&gt;&lt;span class="w"&gt;
                               &lt;/span&gt;&lt;span class="n"&gt;not-captured?&lt;/span&gt;&lt;span class="w"&gt;
                               &lt;/span&gt;&lt;span class="n"&gt;captured-them&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="nf"&gt;logic/conde&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="c1"&gt;;; A main conde combining two main moves:&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="c1"&gt;;; 1. Capturing and emitting what has been&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="c1"&gt;;; captured&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;enemy-piece-capturo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt;
                                          &lt;/span&gt;&lt;span class="n"&gt;cur-pos&lt;/span&gt;&lt;span class="w"&gt;
                                          &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
                                          &lt;/span&gt;&lt;span class="n"&gt;captured-them&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="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;captured-them&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="c1"&gt;;; 2. Moving while keeping safe.&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;where-to-movo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt;
                                    &lt;/span&gt;&lt;span class="n"&gt;cur-pos&lt;/span&gt;&lt;span class="w"&gt;
                                    &lt;/span&gt;&lt;span class="n"&gt;new-pos&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="nf"&gt;logic/conjo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur-pos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="c1"&gt;;; After moving, the piece former position&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="c1"&gt;;; is empty&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/everyg&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isnt-capturedo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-empty&lt;/span&gt;&lt;span class="w"&gt;
                                                     &lt;/span&gt;&lt;span class="n"&gt;new-pos&lt;/span&gt;&lt;span class="w"&gt;
                                                     &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt;
                                                     &lt;/span&gt;&lt;span class="n"&gt;not-captured?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="c1"&gt;;; All of the enemy's pieces must not be able to&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="c1"&gt;;; capture our piece once it moved to&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="c1"&gt;;; its new position&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:move-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-pos&lt;/span&gt;&lt;span class="p"&gt;])]))))&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="c1"&gt;;; and we emit the positions in which we are safe.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The Checkers player in Action
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Initializing the game
&lt;/h2&gt;

&lt;p&gt;To be able to give some checkers' puzzles to the solver, we need an initialization function, that takes one set of enemies, the engine's piece, and emits the right set of empty squares, that is, the whole board minus the two first set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prepare-board&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;board-size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;me&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="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initial-board&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logic/run*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&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="nf"&gt;boardo&lt;/span&gt;&lt;span class="w"&gt;
                                 &lt;/span&gt;&lt;span class="n"&gt;board-size&lt;/span&gt;&lt;span class="w"&gt;
                                 &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)))]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; We generate a board of size board-size&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&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="nf"&gt;clojure.set/difference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initial-board&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt;
                                                        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj&lt;/span&gt;&lt;span class="w"&gt;
                                                         &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
                                                         &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; and we emit empty pieces: the whole starting set minus&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;;; enemy and "me" pieces&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  First Challenge: Multi-Capture
&lt;/h2&gt;

&lt;p&gt;Consider the situation depicted by the following figure:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2nOVrxqv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/pk749v33gng7d9tu8jvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2nOVrxqv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/pk749v33gng7d9tu8jvf.png" alt="Alt Text" width="353" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solver can safely move left or capture one or two pieces. Let's submit this situation to the solver by issuing at your REPL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;;; positioning the enemies&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;empty-brd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;prepare-board&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;me&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="nf"&gt;logic/run*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&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="nf"&gt;play-roundo&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;empty-brd&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;q&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;The results are the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="no"&gt;:move-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; the simple move&lt;/span&gt;&lt;span class="w"&gt;

 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:capture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:then-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; one capture&lt;/span&gt;&lt;span class="w"&gt;

 &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="no"&gt;:from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:capture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:then-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; two captures&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:then-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:capture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:then-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&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;h2&gt;
  
  
  Second Challenge: Staying safe
&lt;/h2&gt;

&lt;p&gt;Consider the following situation:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cp3Voatp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/1jpzkm3s9x7ewz2z3voh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cp3Voatp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/1jpzkm3s9x7ewz2z3voh.png" alt="Alt Text" width="269" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although our piece can be moved left or right, the solver won't take the first choice as the enemy will capture the piece at [2 0]. To see it in action, type at the REPL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; positioning the enemies&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="n"&gt;empty-brd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;prepare-board&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;me&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="nf"&gt;logic/run*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&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="nf"&gt;play-roundo&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;empty-brd&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;enemies&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="n"&gt;q&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;And the solver chooses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="no"&gt;:move-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We've seen how it is possible to tackle the checkers' problem using the relational programming paradigm. We used a clojure based implementation of the minikanren relational programming framework. We saw how we could model three of the game constraints: moving, staying safe, and trying to take prisoners.&lt;/p&gt;

&lt;p&gt;On a final note, please be aware that this approach requires you to know what you're doing. As it is operating searches on deep forests of possible solution combinations, you must know how to model your program and be sure you don't hit resource limits if you throw in un-manageably sized problems. This been said, there's a significant body of knowledge concerned about mastering this kind of problem search. So, if you want to take this to production, you definitely need to do your homework and learn this art thoroughly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is inspired by a chapter of my Book &lt;a href="https://www.amazon.com/Clojure-Data-Structures-Algorithms-Cookbook-dp-1785281453/dp/1785281453/ref=mt_paperback?_encoding=UTF8&amp;amp;me=&amp;amp;qid=1591967006"&gt;Clojure Data Structures and Algorithms Cookbook&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>clojure</category>
      <category>logic</category>
      <category>games</category>
    </item>
    <item>
      <title>Generate, Monitor and Throttle CPU Load in Go</title>
      <dc:creator>Rafik Naccache</dc:creator>
      <pubDate>Mon, 08 Jun 2020 14:02:57 +0000</pubDate>
      <link>https://forem.com/turbopape/the-chronicles-of-nowhere-man-in-systems-land-4fib</link>
      <guid>https://forem.com/turbopape/the-chronicles-of-nowhere-man-in-systems-land-4fib</guid>
      <description>&lt;h2&gt;
  
  
  The Rise of Nowhere Man
&lt;/h2&gt;

&lt;p&gt;I originally wanted to write a Go vs. Rust vs. Python piece, shouted-out about it on Linkedin - But then saw in comments - and rightfully so - that there was already some prose dealing about it on the internets. I thought as I was going to focus on the "Systems" Programming abilities of these languages, my post was relevant. But then I realized I had a fresher, more personal, and presumably more vibrant story to share with the world.&lt;/p&gt;

&lt;p&gt;I am what we can modestly qualify as an "architect" (not the J2EE kind) in the IT world. I don't mean the previous statement to be a testimony of any merit of any type, just spelled out the closest corporate job title by which the engineer that has to make it all work together goes by. It is no honor badge; it's a nightmare-ish situation. But a quite enjoyable one, as long as you consider yourself a free, always willing to learn individual. A "Nowhere Man."&lt;/p&gt;

&lt;p&gt;By the very essence of this personal and professional trait, you can imagine my life as a succession of discoveries, akin to the Sinbad tales: At every stage of your journey, you'd be caught in the middle of a storm which will throw you into the shore of an unknown land. You know the story: you fight your way across an abundance of monsters and a scarcity of resources, only to set sails for the next storm. The "Chronicles of Nowhere Man" is following the same pattern: a stranded engineer (whom I prefer not to name) learning, and enjoying the shipwreck.&lt;/p&gt;

&lt;p&gt;The first installment of the "Chronicles of Nowhere Man" series will narrate our stay at "Systems" Land.  Let's explore it. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is a System?
&lt;/h2&gt;

&lt;p&gt;"System" is an umbrella term that means a lot of different things to many people. But I think we agree a decent definition for it would be "a concept, a design by which we deliberately make many smaller components interact  to achieve a greater purpose." In things ranging from the "Immune System" to the "Solar System" - passing by the "Operating System," you can see that definition in work.&lt;/p&gt;

&lt;p&gt;Keeping this definition in mind (and the keywords "design," "components," "interact," "greater purpose"), you can more or less guess what do I imply when using "systems programming." &lt;/p&gt;

&lt;p&gt;"System programming" goes beyond proudly affirming you can program in Go or Rust (or C for that matter), and it certainly involves threads inter-communication, asynchronous job execution, and global state management. It can even include architectural skills, especially in today's cloud-natively orchestrated world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Systems Land
&lt;/h2&gt;

&lt;p&gt;I was stranded in "Systems Land" when I was sailing with a US-based Cybersecurity solutions provider. Our solutions were shiningly promising to bring AI to the Cybersecurity world, detecting security holes in files (This part was NLP/Regexp), and identifying Cyber attackers attempting to sneak into your network (This part wasn't). &lt;/p&gt;

&lt;p&gt;As the architect on board, I was assigned the task of creating some "honey pot" mechanism. That is, I had to provide for lures that would look appealing to attackers, so when they try to break in, we would recognize and neutralize them.&lt;br&gt;
And then I've seen that there were many levels at which "Systems Designing" or "Programming can be approached." &lt;/p&gt;
&lt;h2&gt;
  
  
  The Architectural Systems Level
&lt;/h2&gt;

&lt;p&gt;At A Global or Architectural level,  we had to make a "System" of communicating honeypots, reporting malicious activity, so upstream firewalls can keep the attackers out. There was an orchestrator that could manage the pots and get back their findings. Locally, each honey pot had a local sate store and was empowered to react if it could not reach the orchestrator. We've designed an efficient and asynchronous message passing from the Honeypots and the orchestrator. We created the global "Architectural System" as a whole tolerant to network failures.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Systems Programming Level
&lt;/h2&gt;

&lt;p&gt;At a local level, these "honey pots" needed to look real. They had to act like actual software, showing actual "Systems usage" consumption, that is, a decently sized amount of memory, disk, and CPU usage, all parametrized by the domain experts. It is a reflection we had at the Systems Programming level. &lt;/p&gt;

&lt;p&gt;The honeypots were written in GO. The disk and memory usage generation was straight forward, so let's focus on the CPU part.&lt;/p&gt;

&lt;p&gt;We generate The CPU Load by running a tight infinite loop. At each iteration of this loop, we verify if we attained our target CPU load. When we hit the CPU Load threshold, we "relieve" this loop by parking the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// generate load on each of the cores&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NumCPU&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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="c"&gt;// The tight loop generates the Load like crazy !&lt;/span&gt;
                &lt;span class="n"&gt;cpuLoad&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;CpuUsagePercent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;samplingRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cpuLoad&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;targetCPU&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// If Load threshold attained&lt;/span&gt;
                  &lt;span class="n"&gt;waitTime&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WaitFactor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waitTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// We hit the brakes pedal&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;How does &lt;em&gt;CPUUsagePercent&lt;/em&gt; Work? In a nutshell, we use &lt;em&gt;time.h&lt;/em&gt; interface on Unices or the &lt;em&gt;"psapi.h"&lt;/em&gt; interface on Windows to compute the number of clock seconds spend on the current process (&lt;em&gt;cpu_time&lt;/em&gt;), which we divide by the whole time this process(&lt;em&gt;real_time&lt;/em&gt;) has been working. The gotcha here was that &lt;em&gt;time.h&lt;/em&gt; would compile on windows, but the results would not be relevant, so you have to watch out!&lt;br&gt;
I share a non copyrighted version &lt;a href="https://github.com/turbopape/cpu-load-generator"&gt;here&lt;/a&gt;, but the gist of it for *nix/macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="c"&gt;// #include &amp;lt;time.h&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startTicks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;WaitFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="c"&gt;// if samplingRate = 0 then we continue with initial startTime and startTicks&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CpuUsagePercent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;samplingRate&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;clockSeconds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;startTicks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOCKS_PER_SEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;realSeconds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" current clock  : %v, real seconds: %v, startTicks: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clockSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;realSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startTicks&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="n"&gt;samplingRate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;realSeconds&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;samplingRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;startTicks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Resetting starts !! startTime : %v, startTicks: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startTicks&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;return&lt;/span&gt; &lt;span class="n"&gt;clockSeconds&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;realSeconds&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="c"&gt;/*
#cgo LDFLAGS: -lpsapi
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;psapi.h&amp;gt;
#include &amp;lt;time.h&amp;gt;
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&amp;amp;a,&amp;amp;b,&amp;amp;c,&amp;amp;d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well (c).
        return
        (
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime &amp;lt;&amp;lt; 32)) // user time
        ) * 0.0000001;
    }else{
        //  Handle error
        return 0;
    }
}
*/&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startTicksTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_cpu_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;WaitFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOCKS_PER_SEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// if samplingRate = 0 then we continue with initial startTime and startTicks&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CpuUsagePercent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;samplingRate&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;clockSeconds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_cpu_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;startTicksTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;realSeconds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" current clock  : %v, real seconds: %v, startTicks: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clockSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;realSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startTicksTime&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="n"&gt;samplingRate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;realSeconds&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;samplingRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;startTicksTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_cpu_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Resetting starts !! startTime : %v, startTicks: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startTicksTime&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;return&lt;/span&gt; &lt;span class="n"&gt;clockSeconds&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;realSeconds&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You probably noticed the &lt;em&gt;WaitFactor&lt;/em&gt; Param. It was the best solution I found to my knowledge to let the program perform the closest to the target CPU threshold! I let the external honey pot orchestrator set this param after a manual or automatic trial and error feedback loops (mostly manual to be honest)&lt;/p&gt;

&lt;h2&gt;
  
  
  And in the End
&lt;/h2&gt;

&lt;p&gt;We've covered a lot of ground in this first adventure. First, we've seen what a "System" means, in terms of components, interaction, and a great purpose to achieve.&lt;br&gt;
Then, we've seen that "Systems"  includes two levels:&lt;br&gt;
A Global one, which we called "Architectural Systems Level" making it possible for the whole to collaborate and synchronize, providing for resiliency and scalability&lt;br&gt;
And a local one, which we called the "Systems Programming Level," where we might need to interact by code with low-level components as we've seen with the CPU piece.&lt;br&gt;
In the end, being an architect might involve you knowing, beyond architectural design patterns, how to interact with low-level systems components. This adventure made me learn more about CPU cycles counting and interacting with it by code surely added to my infrastructure and monitoring skills.&lt;br&gt;
Where we'll be wandering next? &lt;/p&gt;

</description>
      <category>go</category>
      <category>systems</category>
      <category>cpu</category>
      <category>monitoring</category>
    </item>
  </channel>
</rss>
