<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: xtofl</title>
    <description>The latest articles on DEV Community by xtofl (@xtofl).</description>
    <link>https://dev.to/xtofl</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%2F79706%2F6330561e-6050-4744-ae7a-857e62cd0b07.png</url>
      <title>DEV Community: xtofl</title>
      <link>https://dev.to/xtofl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xtofl"/>
    <language>en</language>
    <item>
      <title>Local functions to structure code</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Wed, 28 May 2025 08:25:44 +0000</pubDate>
      <link>https://dev.to/xtofl/local-functions-to-structure-code-3lmb</link>
      <guid>https://dev.to/xtofl/local-functions-to-structure-code-3lmb</guid>
      <description>&lt;p&gt;Oftentimes I encounter lengthy methods, structured into parts by comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;threaded_needle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# get the haystack
&lt;/span&gt;  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;...:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

  &lt;span class="c1"&gt;# find the needle
&lt;/span&gt;  &lt;span class="bp"&gt;...&lt;/span&gt;
  &lt;span class="c1"&gt;# thread the needle
&lt;/span&gt;  &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't work on me: I need visual hints, indentation, modular design, to understand the function's flow.&lt;/p&gt;

&lt;p&gt;Also, I'm a top-down thinker: details are wasted on me until I understand&lt;br&gt;
the structure.  So I prefer the highest level information first, i.e.&lt;br&gt;
the main functionality.&lt;/p&gt;

&lt;p&gt;Therefore my python modules are typically structured so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;  &lt;span class="c1"&gt;# will be called at the bottom of the file
&lt;/span&gt;  &lt;span class="nf"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;other_detail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;other_detail&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;# traditional unsurprising boilerplate at the bottom of the module
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things make it easier for me to understand the code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;high level structure (&lt;code&gt;main&lt;/code&gt;) first&lt;/li&gt;
&lt;li&gt;named functions to identify functional blocks of code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So we can apply this to (lengthy) functions, too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;threaded_needle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;threaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;threaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found_needle&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I agree the &lt;code&gt;def main()&lt;/code&gt; on top and the obligatory &lt;code&gt;main()&lt;/code&gt; call at the bottom look a bit unfamiliar at first.  It's just a convention - once you know it, you won't be surprised anymore.&lt;/p&gt;

&lt;p&gt;The other surprising thing: the function body does not get longer by this technique: the comment lines are replaced by function signatures.&lt;/p&gt;

&lt;p&gt;I like it.  Do you?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>That Arduino Pin Can't Interrupt</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Tue, 16 Aug 2022 06:18:07 +0000</pubDate>
      <link>https://dev.to/xtofl/that-arduino-pin-cant-interrupt-a4h</link>
      <guid>https://dev.to/xtofl/that-arduino-pin-cant-interrupt-a4h</guid>
      <description>&lt;p&gt;I thought it would be easy to couple a button to my Arduino Gemma.&lt;/p&gt;

&lt;p&gt;However, it just didn't work.  I've read the whole &lt;a href="https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/"&gt;page on &lt;code&gt;attachInterrupt&lt;/code&gt;&lt;/a&gt; but apart from a hunch that &lt;em&gt;maybe&lt;/em&gt; some pins can't be used for interrupts, I got nothing.&lt;/p&gt;

&lt;p&gt;So I had to dive into the code, where I found this little snippet (&lt;code&gt;Arduino.h&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define NOT_AN_INTERRUPT -1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;$HOME/.arduino15/packages/arduino/hardware/avr/1.8.5/variants/gemma/pins_arduino.h&lt;/code&gt;, I read this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define digitalPinToInterrupt(p) \
   ((p) == 2 ? 0 : NOT_AN_INTERRUPT)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So here's an idea for you: add a little snippet to your sketch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;PIN&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;interruptFor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;digitalPinToInterrupt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PIN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;static_assert&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="n"&gt;NOT_AN_INTERRUPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s"&gt;"board can't use this pin for an interrupt"&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;i&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;And use this function instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;my_wiring&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;BUTTON_PIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;BUTTON_INTERRUPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;interruptFor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;my_wiring&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BUTTON_PIN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, on my Gemma (with an ATtiny85), when I change my &lt;code&gt;BUTTON_PIN&lt;/code&gt; to e.g. 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sketch_aug14a.ino: In instantiation of
  &lt;span class="s1"&gt;'constexpr int interruptFor() [with int PIN = 1]'&lt;/span&gt;:
sketch_aug14a/sketch_aug14a.ino:19:70:   required from here
sketch_aug14a/sketch_aug14a.ino:11:3: error: static assertion failed:
   board can&lt;span class="s1"&gt;'t use this pin for an interrupt

   static_assert(i != NOT_AN_INTERRUPT,
   ^~~~~~~~~~~~~
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That would have been a time saver!  Maybe I'll propose to introduce this in the arduino headers, too.  When I have time.&lt;/p&gt;

</description>
      <category>interrupt</category>
      <category>staticassert</category>
      <category>arduino</category>
    </item>
    <item>
      <title>`tuple` Reveals Your Intent</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Sat, 25 Sep 2021 13:15:05 +0000</pubDate>
      <link>https://dev.to/xtofl/tuple-reveals-your-intent-19bc</link>
      <guid>https://dev.to/xtofl/tuple-reveals-your-intent-19bc</guid>
      <description>&lt;h2&gt;
  
  
  Brief
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tuple&lt;/code&gt; is framed as the less potent brother of &lt;code&gt;list&lt;/code&gt;.  In long-living code, however, limiting functionality is an asset.  This article shows where &lt;code&gt;list&lt;/code&gt;-ridden code would be better of using a tuple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Very often, I bump onto code that happens to work, by pure merit of the code author, but that doesn't give me an easy time to realize why.&lt;/p&gt;

&lt;p&gt;Very often, this has to do with over-achieving data types with many bells and whistles, that allow all sorts of things to go wrong: &lt;code&gt;dict&lt;/code&gt; objects passed around to convey data that has a fixed structure, &lt;code&gt;list&lt;/code&gt; objects that happen to not be appended to, inserted to, sliced from, sorted, &lt;code&gt;int&lt;/code&gt; objects that can be multiplied, added to, ... etc....&lt;/p&gt;

&lt;p&gt;In any professional project, code has to be reviewed, maintained and debugged.  This code is &lt;em&gt;read&lt;/em&gt; an order of magnitude more often than it is written.&lt;/p&gt;

&lt;p&gt;So in order to save the reader some time, we can tell them about the objects we create by choosing the proper type for them.  In this post, I want to make the case for using &lt;code&gt;tuple&lt;/code&gt; over other data structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Right Frame of Mind
&lt;/h2&gt;

&lt;p&gt;When &lt;a href="https://www.ecosia.org/search?q=python+why+list+over+tuple"&gt;looking for this&lt;/a&gt;, I bump on mostly discussions that say what you &lt;em&gt;cannot&lt;/em&gt; do with a &lt;code&gt;tuple&lt;/code&gt;, and most of the time this is seen as a liability (&lt;a href="https://towardsdatascience.com/python-tuples-when-to-use-them-over-lists-75e443f9dcd7"&gt;not always&lt;/a&gt;).  This is a frame rooted in the &lt;em&gt;comfort of the code author&lt;/em&gt; to choose a data type that can do everything they would ever need.&lt;/p&gt;

&lt;p&gt;I claim that &lt;em&gt;Not Allowing Unintended Stuff is an asset&lt;/em&gt; of the code: it makes it easy for the code reader to limit the possibilities where the program can go wrong.  I want you to look at &lt;code&gt;tuple&lt;/code&gt; from the frame of code reviewing and maintenance, and starts from the &lt;em&gt;comfort of the reader&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Shun &lt;code&gt;list&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Try to reason about this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="n"&gt;inputs&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="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;tabulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the example, you may conclude we're creating a sort of table that maps a list of input values onto a list of results.&lt;/p&gt;

&lt;p&gt;But what can you really tell about the correctness?&lt;/p&gt;

&lt;p&gt;How can you tell that &lt;code&gt;tabulate&lt;/code&gt; receives &lt;code&gt;[1, 2, 3, 4, 5]&lt;/code&gt; as its inputs argument?&lt;/p&gt;

&lt;p&gt;Yes: you'll need to check what the &lt;code&gt;process&lt;/code&gt; function does.  It may be implemented as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# all my inputs are mine!
&lt;/span&gt;  &lt;span class="n"&gt;originals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;multiprocess_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;more_itertools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chunked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;tuple&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="n"&gt;total&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;originals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not too far fetched, though this is a trivial example.  In production code, the functions would be larger, more complex, and farther apart.&lt;/p&gt;

&lt;p&gt;Now imagine this code would have used tuples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="n"&gt;inputs&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="p"&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;3&lt;/span&gt;&lt;span class="p"&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;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;tabulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, there is no way that the &lt;code&gt;tabulate&lt;/code&gt; function could receive anything but &lt;code&gt;(1, 2, 3, 4, 5)&lt;/code&gt;.  It becomes trivial to see that the &lt;code&gt;inputs&lt;/code&gt; object cannot be mutated.  How neat is that!?&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Shun &lt;code&gt;dict&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The idea of limiting the possible uses of a construct is not limited to array-like structures.  On the contrary: it is applicable to whatever code you're designing.&lt;/p&gt;

&lt;p&gt;Another trivial design decision, now we're at Python 3.9+, is to no longer use the overly versatile dictionaries that have hidden the true meaning of your program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_data&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="s"&gt;"temperature °C"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;"time (ms)"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tms&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csv_rows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"datapoints.csv"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# In a totally different module, we find the consumer:
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_location_temperature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;get_loc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;group_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_loc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sum_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;avg_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum_t&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"average temperature in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_t&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course there must be a bug.&lt;/p&gt;

&lt;p&gt;Can you spot it?  You know where I'm heading, right?  I'm nagging about dictionaries holding structured data.  The &lt;code&gt;s["temperature"]&lt;/code&gt; will surely raise &lt;code&gt;KeyError&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;So far for the review?  Nope.  But admit you were (or at least, I would have been) distracted by checking for key lookups.&lt;/p&gt;

&lt;p&gt;What if we could ask the static checker to do this for us?  Not with &lt;code&gt;dicts&lt;/code&gt;, it won't, but by giving it &lt;code&gt;dataclass&lt;/code&gt;es!  This totally makes sense, because we know the structure of the data upfront, and we want to have two pieces of code using the same structure - exactly what &lt;code&gt;dataclass&lt;/code&gt; is for!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# reap benefits of immutable data
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sample&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;temperature_C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
  &lt;span class="n"&gt;time_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
  &lt;span class="n"&gt;location_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Sample&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;Sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="n"&gt;temperature_C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;time_ms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tms&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;location_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csv_rows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"datapoints.csv"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# In a totally different module, we find the consumer:
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_location_temperature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Sample&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
  &lt;span class="n"&gt;get_loc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;location_id&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;group_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_loc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sum_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;temperature_C&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;avg_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum_t&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"average temperature in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_t&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you we can focus on the logic of the function, since tools like &lt;code&gt;mypy&lt;/code&gt; can check for attribute errors.  (I bet you're smarter than me and long spotted that the &lt;code&gt;len(data)&lt;/code&gt; should have been &lt;code&gt;len(samples)&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Generalizing the Idea
&lt;/h2&gt;

&lt;p&gt;The functionality we care about should be easy to verify.&lt;/p&gt;

&lt;p&gt;Using immutable data, and statically check-able constructs, can greatly help with that, because it gives the reader language-guaranteed certainties.&lt;/p&gt;

&lt;p&gt;I'm glad I did get this off my chest.  And I'm happy you agree ;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Want More?
&lt;/h2&gt;

&lt;p&gt;This post is mostly about the syntactic level; the ideas here can be lifted to the whole world of software design.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn about &lt;a href="https://www.fluentcpp.com/2016/12/05/named-constructors/"&gt;strong&lt;/a&gt;, meaningful objects as opposed to &lt;a href="https://blog.ploeh.dk/2015/01/19/from-primitive-obsession-to-domain-modelling/"&gt;primitive-obsession&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Learn about the &lt;a href="https://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/"&gt;Repository pattern&lt;/a&gt; in Domain Driven Design, I learned about the Repository pattern producing guaranteed-valid Domain Objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I might want to write some more about this, too.&lt;/p&gt;

</description>
      <category>tuple</category>
      <category>python</category>
      <category>correctness</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Just Glue</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Wed, 22 Sep 2021 08:50:46 +0000</pubDate>
      <link>https://dev.to/xtofl/just-glue-1kec</link>
      <guid>https://dev.to/xtofl/just-glue-1kec</guid>
      <description>&lt;p&gt;As a software developer, I have a tendency to get carried away with what I do.  It's a great place to be, this invisible palace of connected concepts.  It's addictive to build it, to polish it, even to look for cracks and repair them with all the love of the craft.&lt;/p&gt;

&lt;p&gt;It's a bit hard to admit, for I try to be a good and respectful person, but also, I feel a little disdain - which I properly hide - towards those unable to see this landscape I build.&lt;/p&gt;

&lt;p&gt;Users, testers, product managers.  Mechanical engineers, hardware engineers, ... name it.  None of these have the faintest idea of the glimmering, out-of-their-worlds fabric of the software I make for them.&lt;/p&gt;

&lt;p&gt;Without me, there would be no product to sell.  I'm doing the most important work in the company, and all shall know!&lt;/p&gt;

&lt;p&gt;The jewels would drop of the crown if it weren't for my glue!&lt;/p&gt;

&lt;p&gt;Wait -&lt;/p&gt;

&lt;p&gt;Am I actually creating glue, to sit between the gold and the ruby?  Must-be-kept-in-a-tube glue, fluid and shapeless first, hidden and rigid afterwards?&lt;/p&gt;

&lt;p&gt;Would glue engineers attribute the same glory to their glues?&lt;/p&gt;

&lt;p&gt;"As a glue engineer, I make it possible for people to build beauty by connecting valuable parts together."&lt;/p&gt;

&lt;p&gt;As a software engineer, I help bright people assemble their greatest ideas into wonderful products.&lt;/p&gt;

&lt;p&gt;I want to be grateful for that, proud to be of service, and content.  And I promise to do my best to stay humble.&lt;/p&gt;

</description>
      <category>brainfart</category>
      <category>pride</category>
      <category>humility</category>
    </item>
    <item>
      <title>Copyright Clutter Everywhere!</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Wed, 06 Jan 2021 11:04:07 +0000</pubDate>
      <link>https://dev.to/xtofl/copyright-clutter-everywhere-2139</link>
      <guid>https://dev.to/xtofl/copyright-clutter-everywhere-2139</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
# **********************************************/
#  Copyright (c) ThisCompany. All rights are
#  reserved.  Reproduction in whole or in part
#  is prohibited without the prior written
#  consent of the copyright owner.
#
#  This software and any compilation or derivative
#  thereof is and shall remain the proprietary
#  information of ThisCompany and is highly
#  confidential in nature.
# ***********************************************/
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;here_the_code_begins&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="s"&gt;"""but why isn't it at the top???"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only 10 lines of clutter.  &lt;em&gt;On Every Single Source File&lt;/em&gt;.  I've seen it in every company I worked in, even though the files are stored in a private repository behind seven firewalls, encrypted, password protected and are not intended for publication whatsoever.&lt;/p&gt;

&lt;p&gt;Only 10 lines of clutter.  &lt;em&gt;On Every Single Source File&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Am I the developer one outraged by this dead code in my code?  Who is fed up with having to scroll down half a page everytime they open up a file?&lt;/p&gt;

&lt;p&gt;Is a single LICENSE.txt file in the root of the project not enough?&lt;/p&gt;

&lt;p&gt;Does anyone know why we're doing this?  An old habit?&lt;/p&gt;

&lt;p&gt;Does anyone know a better way to protect intellectual property?&lt;/p&gt;

</description>
      <category>copyright</category>
      <category>habits</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I want my Bash Pipe</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Wed, 16 Sep 2020 11:14:49 +0000</pubDate>
      <link>https://dev.to/xtofl/i-want-my-bash-pipe-34i2</link>
      <guid>https://dev.to/xtofl/i-want-my-bash-pipe-34i2</guid>
      <description>&lt;h2&gt;
  
  
  TL; DR;
&lt;/h2&gt;

&lt;p&gt;Pipelines as we know them from shell scripts are a powerful&lt;br&gt;
mechanism to compose functionality.&lt;/p&gt;

&lt;p&gt;This same convenience can be achieved with most programming&lt;br&gt;
languages.  In this post, I'll show how you can introduce&lt;br&gt;
pipes into your favourite programming enviroment.&lt;/p&gt;
&lt;h2&gt;
  
  
  What?
&lt;/h2&gt;

&lt;p&gt;Lots of platforms come with a way to build programs out of small blocks.  In many contexts, there is a convenient way to do this functional composition.  We can call these 'pipelines'.&lt;/p&gt;

&lt;p&gt;This post came to being after a discussion on pipes in bash (slightly controversial analysis on why &lt;a href="https://dev.to/taikedz/your-bash-scripts-are-rubbish-use-another-language-5dh7"&gt;your bash scriptsare rubbish&lt;/a&gt;), but the domain is much larger than that.&lt;/p&gt;

&lt;p&gt;So this is what we're talking about: a bash script composed of small commands connected through pipes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;urls.txt | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s-http://--"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;.com&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="s2"&gt;/g"&lt;/span&gt;  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;".com$"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipe concept exists in different domains, too - sound processing is a nice example (image from &lt;a href="https://gstreamer.freedesktop.org" rel="noopener noreferrer"&gt;gstreamer website&lt;/a&gt;)&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%2Fgstreamer.freedesktop.org%2Fdocumentation%2Fapplication-development%2Fintroduction%2Fimages%2Fsimple-player.png" class="article-body-image-wrapper"&gt;&lt;img alt="gstreamer sound processing pipeline" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgstreamer.freedesktop.org%2Fdocumentation%2Fapplication-development%2Fintroduction%2Fimages%2Fsimple-player.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Composition is the main driving goal of most programming languages.  We chase some value through a function, and use its return value as input for another function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;report&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="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;read_lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"urls.txt"&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".com"&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
        &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&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;Clearly, the bash pipeline syntax is way easier to both write and read.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if...
&lt;/h2&gt;

&lt;p&gt;We could use the simplicity of the pipe syntax...&lt;/p&gt;

&lt;p&gt;In functional programming, and in math, this concept is known as point-free function composition.  You effectively define a pipeline of functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;read_lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urls.txt&lt;/span&gt;&lt;span class="sh"&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;explode_url&lt;/span&gt; \
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;tuple_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; \
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ends_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But... how?
&lt;/h2&gt;

&lt;p&gt;I'll be using Python for this demo, just for its succinctness.  I may add C++ examples later - C++ allows us to add just a little more syntactic sugar with function overload resolution.&lt;/p&gt;

&lt;p&gt;I'll start explaining what fluent interfaces are.  Adding operator overloading to the mix, we'll end up with a nice pipeline construction syntax.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluent Interfaces
&lt;/h3&gt;

&lt;p&gt;In most programming languages, you have a way to build &lt;a href="https://en.wikipedia.org/wiki/Fluent_interface" rel="noopener noreferrer"&gt;fluent interfaces&lt;/a&gt;, allowing you to chain operations to an object together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;ServerBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;\
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on_address&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;\
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1050&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;that_db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;that_handles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rq1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle_rq1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;that_quits_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works by creating methods that return builders again (spot the recursion).&lt;/p&gt;

&lt;h3&gt;
  
  
  Operators
&lt;/h3&gt;

&lt;p&gt;Now if your language allows you to override &lt;em&gt;operators&lt;/em&gt; as well, you're golden1 You can create a class &lt;code&gt;Pipeline&lt;/code&gt; and a pipe operator that extends a pipeline instance with an extra function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;functions&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__or__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&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;functools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# function
&lt;/span&gt;            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# iterable
&lt;/span&gt;            &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# initializer
&lt;/span&gt;
&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;pipeline starting element&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing it
&lt;/h3&gt;

&lt;p&gt;And that seems to be all.&lt;/p&gt;

&lt;p&gt;It can be demonstrated easily with e.g. &lt;code&gt;pytest&lt;/code&gt; .  For the sake of this article, let's assume the &lt;code&gt;inc&lt;/code&gt; and &lt;code&gt;double&lt;/code&gt; functions to respectively increase and double a value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_everything_starts_with_the_identity_function&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abcd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_pipeline_steps_are_applied_in_order&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;double&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&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;0&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But still... how???
&lt;/h2&gt;

&lt;p&gt;Now let's explain this step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Pipeline
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Pipeline&lt;/code&gt; class is our container of functions to be composed.  It does so by storing them in a tuple (&lt;code&gt;self.functions&lt;/code&gt;).  (As an aside, I prefer &lt;code&gt;tuple&lt;/code&gt; rather than &lt;code&gt;list&lt;/code&gt; for its immutability)&lt;/p&gt;

&lt;p&gt;The module also adds a very first object we can use as a starting point for our construction - a pipeline hat does nothing but returning the identical element it receives.  It is called &lt;code&gt;ID&lt;/code&gt;, just like in the functional programming world.&lt;/p&gt;

&lt;p&gt;Now our class has this special member &lt;code&gt;__or__(self, f)&lt;/code&gt;. Its sole purpose is to provide the 'pipe' syntax we know from shell scripting: &lt;code&gt;p | inc | double&lt;/code&gt;; and in Python, this is achieved through &lt;a href="https://docs.python.org/3/reference/datamodel.html#object.__or__" rel="noopener noreferrer"&gt;operator overloading&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We could have created a custom name ('and_then') to achieve the same functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;and_then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;

&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;and_then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But choosing &lt;code&gt;__or__&lt;/code&gt; as a member name tells Python we want this to be used when a &lt;code&gt;Pipeline&lt;/code&gt; object is or-ed/piped to a function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calling the Pipeline
&lt;/h3&gt;

&lt;p&gt;Again, another special member: the &lt;code&gt;__call__&lt;/code&gt; function.  You probably guessed it, but this is what makes objects behave like a function.&lt;/p&gt;

&lt;p&gt;I have implemented it using &lt;code&gt;functools.reduce&lt;/code&gt;, but you could just as well hand-code a loop feeding the first argument to tne first function, the return value to the next function, and so on.&lt;/p&gt;

&lt;p&gt;Here, too, we could have called it something else, like &lt;code&gt;invoke_with&lt;/code&gt;.  A non-special-member pipeline would have looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;and_then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;invoke_with&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But choosing &lt;code&gt;__call__&lt;/code&gt; tells Python to choose this method when the braces are used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;double&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Injecting the first argument
&lt;/h3&gt;

&lt;p&gt;What I would &lt;em&gt;really&lt;/em&gt; want to write is something this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="n"&gt;twentytwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;echo&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="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;double&lt;/span&gt;
&lt;span class="n"&gt;fourty_eight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0x18&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;from_hex&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;double&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we need another trick-helper class that reverses things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WithArg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;WithArg&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="n"&gt;ID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&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;10&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we're willing to give up the &lt;code&gt;|&lt;/code&gt; operator, we can drop the parentheses, too.  This is due to operator precedence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we can use e.g. the multiplication operator for composition, and e.g. right shift for argument injection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__mul__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&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;self&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WithArg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__rshift__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nc"&gt;WithArg&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="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;double&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Limitations
&lt;/h1&gt;

&lt;p&gt;The pipes you can build with the code in this article are nice, but lack still one important aspect of the ones you use on you shell.  It has to do with breaking structure.&lt;/p&gt;

&lt;p&gt;Take a look at &lt;a href="https://www.howtogeek.com/438882/how-to-use-pipes-on-linux/" rel="noopener noreferrer"&gt;this pipeline&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;top5 &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"page"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $5 " " $3 " " $9}'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we see here is a line-based &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt;.  But then comes &lt;code&gt;sort&lt;/code&gt;.  How is this different?  Wel, it will swallow all of its input before generating output.&lt;/p&gt;

&lt;p&gt;The python pipeline will allow us to compose functions that accept and return data in lock step. &lt;code&gt;ID | grep("page") | print_elements(5, 3, 9)&lt;/code&gt; is going to process a single argument to produce a single value.  How are we going to break free from that?  Parts of the pipe need to be able to 'buffer' their input to produce one output (or a stream?) when the input stops.&lt;/p&gt;

&lt;p&gt;Indeed, text based processing has two kinds of events: new-line, and end-of-file.  As a matter of fact, all of these command line stream-processing tools are composed of a buffering/chunking part and a chunk-processing part.  We just &lt;em&gt;may&lt;/em&gt; use this knowledge to make our pipeline smarter. But not in this post.&lt;/p&gt;

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

&lt;p&gt;Languages allow you to build your own set of constructs these days.  We can make use of this to mimic notations from a known domain.&lt;/p&gt;

&lt;p&gt;No language is perfect, though, but we can get close enough to be useful.&lt;/p&gt;

</description>
      <category>python</category>
      <category>pipe</category>
      <category>syntacticsugar</category>
    </item>
    <item>
      <title>Fixture Options for pytest</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Thu, 27 Aug 2020 09:17:00 +0000</pubDate>
      <link>https://dev.to/xtofl/fixture-options-for-pytest-4dh8</link>
      <guid>https://dev.to/xtofl/fixture-options-for-pytest-4dh8</guid>
      <description>&lt;h1&gt;
  
  
  The Context: Test Parameterization
&lt;/h1&gt;

&lt;p&gt;At a previous job, we built home gateway middleware, which had to be tested on a plethora of devices.  I advised to start using &lt;a href="https://docs.pytest.org"&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/a&gt; for its succinctness and extensibility.&lt;/p&gt;

&lt;p&gt;Now a typical use case was to upload new firmware to a device, boot it, and run a test suite against it.  The device's IP address and the firmware binary were variables.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_addoption"&gt;pytest's hook architecture&lt;/a&gt;, a test suite could be extended with a number of command line options.  Thanks to &lt;code&gt;pytest&lt;/code&gt; fixtures, it is possible to inject information into a test.&lt;/p&gt;

&lt;p&gt;If only we could combine those two nice features to retrieve command line options from within your test....&lt;/p&gt;

&lt;p&gt;So the idea grew to create a library to declare options, and make them available as test fixtures.  I named the library &lt;a href="https://gitlab.com/xtofl/fixtopt/"&gt;'fixtopt'&lt;/a&gt; because optfixt is so much harder to pronounce :).  It's out in the open, because I think it is useful for more than just that one case.&lt;/p&gt;

&lt;h1&gt;
  
  
  Action: let's code
&lt;/h1&gt;

&lt;p&gt;Let's start with an arbitrarily simple example piece of code we can test - and work our way up to the command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;format_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hi there, {recipient},&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;{body}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Simple Test Case
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_a_person_is_greeted_properly&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Dear Lisa, there is a hole in my bucket.  Regards, John"&lt;/span&gt;
    &lt;span class="n"&gt;recipient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Lisa"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;format_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dear {recipient}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... of course it's trivial.  But let's look at what we can do with the test input variables &lt;code&gt;message&lt;/code&gt; and &lt;code&gt;recipient&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extracting Test Fixtures
&lt;/h2&gt;

&lt;p&gt;Pytest lets you register &lt;a href="https://docs.pytest.org/en/stable/fixture.html#fixtures-as-function-arguments"&gt;functions as fixtures&lt;/a&gt;.  When executing a test function, it will take the test function's argument names, and call the test function with the results of the corresponding fixture functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Dear Lisa, there is a hole in my bucket.  Regards, John"&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Lisa"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_a_person_is_greeted_properly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;format_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dear {recipient}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Command Line Options
&lt;/h2&gt;

&lt;p&gt;Now, we would like these fixtures to become injected by the pytest command line, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"Nothing else to say"&lt;/span&gt; &lt;span class="nt"&gt;--recipient&lt;/span&gt; Lisa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's where this &lt;a href="https://pypi.org/project/fixtopt-xtofl/"&gt;&lt;code&gt;fixtopt-xtofl&lt;/code&gt;&lt;/a&gt; library comes in: add a file &lt;code&gt;conftest.py&lt;/code&gt; in your test directory, and declare the options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# conftest.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fixtopt&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pytest_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;

        &lt;span class="n"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Dear Lisa, there is a hole in my bucket.  Regards, John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"the message to send"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

        &lt;span class="n"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Olav"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"the one to adress"&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;And there you go!  &lt;code&gt;pytest&lt;/code&gt; picks it up, adds it to its own help text and you can just use the options as you like!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/path/to/testdir&amp;gt; pytest &lt;span class="nt"&gt;--help&lt;/span&gt;
...
custom options:
  &lt;span class="nt"&gt;--message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;MESSAGE     the message to send
  &lt;span class="nt"&gt;--recipient&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;RECIPIENT
                        the recipient
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the test (with a broken implementation):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
/path/to/testdir&amp;gt; pytest &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"whatever"&lt;/span&gt; &lt;span class="nt"&gt;--recipient&lt;/span&gt; &lt;span class="s2"&gt;"Lisaz"&lt;/span&gt;
&lt;span class="o"&gt;====&lt;/span&gt; &lt;span class="nb"&gt;test &lt;/span&gt;session starts &lt;span class="o"&gt;====&lt;/span&gt;
platform linux &lt;span class="nt"&gt;--&lt;/span&gt; Python 3.6.9, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: /path/to/testdir
collected 1 item

test_messageformat.py F                                                                                                             &lt;span class="o"&gt;[&lt;/span&gt;100%]

&lt;span class="o"&gt;====&lt;/span&gt; FAILURES &lt;span class="o"&gt;====&lt;/span&gt;
____ test_a_person_is_greeted_properly ____

message &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'whatever'&lt;/span&gt;, recipient &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Lisaz'&lt;/span&gt;

    def test_a_person_is_greeted_properly&lt;span class="o"&gt;(&lt;/span&gt;message, recipient&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;       assert format_message&lt;span class="o"&gt;(&lt;/span&gt;message, recipient&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
            .startswith&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Dear {recipient}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
E       AssertionError: assert False
E        +  where False &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;built-in method startswith of str object at 0x7f9a80faa670&amp;gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Dear {recipient}'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
E        +    where &amp;lt;built-in method startswith of str object at 0x7f9a80faa670&amp;gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Dear, {recipient},\n{body}'&lt;/span&gt;.startswith
E        +      where &lt;span class="s1"&gt;'Dear, {recipient},\n{body}'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; format_message&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'whatever'&lt;/span&gt;, &lt;span class="s1"&gt;'Lisaz'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

test_messageformat.py:5: AssertionError
&lt;span class="o"&gt;====&lt;/span&gt; short &lt;span class="nb"&gt;test &lt;/span&gt;summary info &lt;span class="o"&gt;====&lt;/span&gt;
FAILED test_messageformat.py::test_a_person_is_greeted_properly - AssertionError: assert False
&lt;span class="o"&gt;====&lt;/span&gt; 1 failed &lt;span class="k"&gt;in &lt;/span&gt;0.07s &lt;span class="o"&gt;====&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agreed, the resulting failure details are a bit painful to the eyes, but this has nothing to do with the command line arguments or the fixtures.&lt;/p&gt;

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

&lt;p&gt;Well... this is all.  A small and simple library to add command line parameters to your tests.  It's not feature-complete yet, but it gets the job done.  Do take a look, try it out, file an issue, add a pull request.  It can only get better.&lt;/p&gt;

</description>
      <category>pytest</category>
      <category>commandline</category>
      <category>unittest</category>
      <category>python</category>
    </item>
    <item>
      <title>Reservation mitigation application</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Sun, 14 Jun 2020 12:09:22 +0000</pubDate>
      <link>https://dev.to/xtofl/reservation-mitigation-application-pop</link>
      <guid>https://dev.to/xtofl/reservation-mitigation-application-pop</guid>
      <description>&lt;p&gt;Now countries are coming out of lock-down, COVID-19 still imposes limitations on the way we come together.  And I see a lot of places in need of a reservation system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; At work, we can't be more than 20 persons in the landscape office, and the lab doesn't allow more than 4, meeting room 1 is limited to 6 and meeting room 2 limited to 9 persons at a time.&lt;/li&gt;
&lt;li&gt;In the hospital, a patient can't have more than 2 visitors at a time, less than 3 visits per week; the whole wing can't have more than 16 visitors at any moment.  At the geriatric wing where my dad lies, they work with a hand brew spreadsheet managed by one nurse.&lt;/li&gt;
&lt;li&gt;Restaurants and pubs require reserving a spot to keep the number of people under 1/8m²; when a reservation is canceled, another family of 5 can be allowed in.  Some are very inventive and &lt;a href="https://www.tvoost.be/nieuws/coronavirus-verkeerslicht-regelt-toegang-in-cafe-de-smoutpot-in-melsele-99763"&gt;use an old traffic light&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Hotels need to adapt their systems, too&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a pity that everyone would have to invent this on their own.  So I went searching the web (open source, reservation, COVID, tools).  I bumped onto this &lt;a href="https://github.com/soroushchehresa/awesome-coronavirus"&gt;github overview&lt;/a&gt;.  I read through this &lt;a href="https://sgtechcentre.undp.org/content/sgtechcentre/en/home/digital-tools-for-covid-19.html"&gt;Singapore digital tools&lt;/a&gt; overview.&lt;/p&gt;

&lt;p&gt;But I couldn't find a tool to solve this very common and current problem.  Am I too optimistic, and can't this problem be generalized?  Or hasn't the need been urgent enough?  Something else?&lt;/p&gt;

&lt;p&gt;I wonder... could we join efforts solving this?  The result is certainly something that's going to last.  Experts expect new viruses coming along, and for sure, COVID isn't dead yet.&lt;/p&gt;

&lt;p&gt;In absence of something better, I start the &lt;a href="https://gitlab.com/xtofl/limityourpresence"&gt;LimitYourPresence&lt;/a&gt; project on GitLab.  There, we can gather requirements, do some planning, ...  It's all very premature, but who knows... what grows out of this!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>reservation</category>
      <category>socialdistancing</category>
      <category>covid</category>
    </item>
    <item>
      <title>Set up Trainig a Distributed Git Workflow on a Single Computer</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Thu, 19 Mar 2020 07:56:56 +0000</pubDate>
      <link>https://dev.to/xtofl/trainig-a-distributed-git-workflow-on-a-single-computer-1hae</link>
      <guid>https://dev.to/xtofl/trainig-a-distributed-git-workflow-on-a-single-computer-1hae</guid>
      <description>&lt;h1&gt;
  
  
  Context
&lt;/h1&gt;

&lt;p&gt;Imagine a pandemic.&lt;/p&gt;

&lt;p&gt;You're suddenly forced to work from home.  Network resources are scarse, but you want to be able to train your distributed git skills.&lt;/p&gt;

&lt;p&gt;There are a ton of resources out there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/jm7QsI-nNjk"&gt;the git parable&lt;/a&gt; (talk about &lt;a href="https://github.blog/2009-05-18-the-git-parable/"&gt;this post&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/praqma-training/git-katas/blob/master/Overview.md"&gt;extensive katas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learngitbranching.js.org/"&gt;learn git branching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But don't you need a git server and some separate computers to do all that?  &lt;/p&gt;

&lt;p&gt;Well, good news: for the bulk of the skills, you can go with &lt;em&gt;a setup on a single PC&lt;/em&gt; that allows a single person to mimic the real thing quite well.&lt;/p&gt;

&lt;p&gt;And here's a way you can create a disposable sandbox to start training.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git&lt;/code&gt; command line client is installed on your system&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I want to fake a central repository and two members in the team: me (Alice) and someone else (Bob).  (I don't mind role plays)&lt;/p&gt;

&lt;p&gt;We want an Authorative Repository to push to and pull from.  And we want to have some clones we can do some work in.&lt;/p&gt;

&lt;p&gt;And since this should be a sandbox, you want to be able to throw everything away and start from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instructions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a sandbox folder (&lt;code&gt;mkdir sandbox; cd sandbox&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Create an authorative repository (&lt;code&gt;git init --bare central.git&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Be Alice: clone the central (&lt;code&gt;git clone central.git alices-clone&lt;/code&gt;)

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git clone central.git alices-clone&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd alices-clone&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config user.name Alice; git config user.email alice@sandbox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd ..&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Be Bob: clone the central

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git clone central.git bobs-clone&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd bobs-clone&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config user.name Bob; git config user.email bob@sandbox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd ..&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There you go.  Now all is left: playing around.  And then, throwing all away and starting over.  That's what sandboxes are for.&lt;/p&gt;

&lt;p&gt;(Note: depending on the system, you may need to allow users to push to the central. TBI).&lt;/p&gt;

&lt;h2&gt;
  
  
  Playing Around
&lt;/h2&gt;

&lt;p&gt;Here's Bob.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\Users\krpi\sandbox&amp;gt; git clone .\central.git\ bobs-clone; cd bobs-clone
PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; git config user.name Bob; git config user.email bob@sandbox
PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; echo "Do read me" &amp;gt;&amp;gt; README.txt
PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; git add .\README.txt
PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; git commit -m "Add readme"
[master (root-commit) b29fe43] Add readme
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.txt
PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; git push
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 280 bytes | 140.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To C:/Users/krpi/sandbox/.\central.git\
 * [new branch]      master -&amp;gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there is Alice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\Users\krpi\sandbox&amp;gt; git clone .\central.git\ alices-clone; cd alices-clone
Cloning into 'alices-clone'...
done.
PS C:\Users\krpi\sandbox\alices-clone&amp;gt; git config user.name Alice; git config user.email alice@sandbox
PS C:\Users\krpi\sandbox\alices-clone&amp;gt; git checkout -b alices-branch
Switched to a new branch 'alices-branch'
PS C:\Users\krpi\sandbox\alices-clone&amp;gt; echo "I am Alice" &amp;gt;&amp;gt; hello.txt
PS C:\Users\krpi\sandbox\alices-clone&amp;gt; git add .\hello.txt; git commit -m "Say hello"
[alices-branch b66072d] Say hello
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 hello.txt
PS C:\Users\krpi\sandbox\alices-clone&amp;gt; git push -u origin alices-branch
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 372 bytes | 186.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To C:/Users/krpi/sandbox/.\central.git\
 * [new branch]      alices-branch -&amp;gt; alices-branch
Branch 'alices-branch' set up to track remote branch 'alices-branch' from 'origin'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hey!  There's Bob again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; git fetch
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From C:/Users/krpi/sandbox/.\central.git\
 * [new branch]      alices-branch -&amp;gt; origin/alices-branch
PS C:\Users\krpi\sandbox\bobs-clone&amp;gt; git log origin/alices-branch
commit b66072d91ad8b8d8869b1eb79021d3069e1b5f30 (origin/alices-branch)
Author: Alice &amp;lt;alice@sandbox&amp;gt;
Date:   Thu Mar 19 07:25:37 2020 +0100

    Say hello

commit b29fe434df968b17da2c10d58371f50bc7200b68 (HEAD -&amp;gt; master, origin/master)
Author: Bob &amp;lt;bob@sandbox&amp;gt;
Date:   Thu Mar 19 07:20:00 2020 +0100

    Add readme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;I surely hope this wasn't scary at all.  This should take away all excuses to do a little git training everyday.&lt;/p&gt;

</description>
      <category>corona</category>
      <category>git</category>
      <category>sandbox</category>
      <category>training</category>
    </item>
    <item>
      <title>money for computers</title>
      <dc:creator>xtofl</dc:creator>
      <pubDate>Sun, 21 Apr 2019 11:54:26 +0000</pubDate>
      <link>https://dev.to/xtofl/money-for-computers-1bb6</link>
      <guid>https://dev.to/xtofl/money-for-computers-1bb6</guid>
      <description>&lt;h1&gt;
  
  
  My Expense on Software Licenses
&lt;/h1&gt;

&lt;p&gt;"Dad, virtually everyone in my class has their own computer to do homework.  How come I have none?"&lt;/p&gt;

&lt;p&gt;Granted, we've postponed the cost.  I have bought a used computer from work, and we had a laptop of our own running slowly but fine.  Indeed, he's growing 16 this year, and needs a PC more and more - prepare slide shows, do some research, and what not.  He says he doesn't even care if it's not a game computer - just being able to write documents, a spreadsheet, ... and run his (windows based) chess engine.&lt;/p&gt;

&lt;p&gt;So off we went looking online for affordable laptops.  There were plenty of €500+ - but after a long search, we found that the German market has the cheapest ones, and that there is this Lenovo V110 for just below €300!&lt;/p&gt;

&lt;p&gt;That is... unless you want Windows.  And MS Office.  Those two requirements add €150 to the bill.&lt;/p&gt;

&lt;p&gt;--edit-- it's 2021, and an &lt;a href="https://www.microsoft.com/nl-be/microsoft-365/buy/compare-all-microsoft-365-products"&gt;Office365 license&lt;/a&gt; for a family of 5 now costs up to 20/year!&lt;/p&gt;

&lt;p&gt;So we were about to buy the laptop.  But I offered him a choice: I would install Linux+LibreOffice+Wine on it for free, or he buys the Microsoft licenses.  Given that he's not very computer-savvy, that's a hard choice to make.  But to my delight, he approved to go the free-as-in-free-beer way!&lt;/p&gt;

&lt;p&gt;Now the academic year has started and he's doing quite well with his Ubuntu 18.04.  The computer boots in under 30 seconds, his chromium is snappier than he's used to.&lt;/p&gt;

&lt;p&gt;And here comes the first hurdle.  A physics assignment mailed to him in a .docx.  And in class, obviously, they entered all their measurement data in... excel.  Opening these documents is not too hard - he has an Office 356 account from school.  Even creating a line chart of the measurements works alright.  But then comes the struggle - copy/pasting the line charts and the tabular measurement data into the Office Online document.&lt;/p&gt;

&lt;p&gt;Obviously, there's no way.&lt;/p&gt;

&lt;p&gt;So after some fuzz about 'everyone has MS Office', an hour of trying stuff out with tables, font sizes to make stuff match and so on, I come by and reproduce all of his effort in 5 minutes on Google Docs.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Nation's Expense
&lt;/h1&gt;

&lt;p&gt;That's a long story to come to this: why, o why does my nation spend a ton of money on software licenses?  A small calculation is in place.&lt;/p&gt;

&lt;p&gt;In Belgium, about 10'000 kids are born yearly.  That means that about the same number learn to work with computers every year.  They'll work with... Windows and Office.&lt;/p&gt;

&lt;p&gt;When they grow up, they'll want to buy a computer as they know it - with Windows and Office on it.  These licenses amount to approximately 1'500'000 €, yearly.&lt;/p&gt;

&lt;p&gt;Imagine we could spend these euro's on Linux laptops for kids in families on a tiny budget.  If we take 15% of the families are in a tight situation (&lt;a href="https://statbel.fgov.be/en/themes/households/poverty-and-living-conditions/risk-poverty-or-social-exclusion"&gt;cf. here&lt;/a&gt;), amounting to 1500 kids per year that need, but can't afford a laptop... the equation works!&lt;/p&gt;

&lt;p&gt;Or we could support open source software, making it better.&lt;/p&gt;

&lt;p&gt;Why is it that the educational system enforces the Microsoft monopoly?  Why doesn't it teach our kids make 'educated' choices when it comes to buying a tool essential to their life as a grownup?&lt;/p&gt;

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

&lt;p&gt;If you are able to support your kid in learning to use Linux, or better, to assist the school's IT department to support Linux laptops, you are in a position to help out the next generation's kids to get affordable computers.&lt;/p&gt;

&lt;p&gt;I hope we can do this!&lt;/p&gt;

</description>
      <category>education</category>
      <category>equality</category>
      <category>chances</category>
      <category>taxes</category>
    </item>
  </channel>
</rss>
