<?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: Juha-Matti Santala</title>
    <description>The latest articles on DEV Community by Juha-Matti Santala (@hamatti).</description>
    <link>https://dev.to/hamatti</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%2F1827%2Fcdd111bc-e087-4d91-afbc-8fe5d74925e2.png</url>
      <title>DEV Community: Juha-Matti Santala</title>
      <link>https://dev.to/hamatti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hamatti"/>
    <language>en</language>
    <item>
      <title>Learning Rust #4: Parsing JSON with strong types</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Wed, 12 May 2021 18:30:44 +0000</pubDate>
      <link>https://dev.to/hamatti/learning-rust-4-parsing-json-with-strong-types-575m</link>
      <guid>https://dev.to/hamatti/learning-rust-4-parsing-json-with-strong-types-575m</guid>
      <description>&lt;p&gt;&lt;em&gt;Last December I finally started learning Rust and last month I built and published my first app with Rust: &lt;a href="https://github.com/Hamatti/nhl-235"&gt;235&lt;/a&gt;. Learning Rust is my new monthly blog series that is definitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One big difference with Rust compared to Javascript and Python that I've been writing for most of my career is strong static typing. With JS and Python, I'd just call an API, get some data in JSON, parse that into a Python dict or Javascript object and then access different values directly.&lt;/p&gt;

&lt;p&gt;With Rust, I'm working with differently typed structures and while I understand the value of it, sometimes it feels very cumbersome to write.&lt;/p&gt;

&lt;h2&gt;
  
  
  I started with serde_json::Value
&lt;/h2&gt;

&lt;p&gt;When I started working with Rust to build 235, I decided to use &lt;a href="https://serde.rs/"&gt;Serde&lt;/a&gt; that seemed to be a popular library for serializing and deserializing data. While I was still learning the basics, it felt overwhelming to figure out the correct way of defining types for the entire API response. I decided to leave that as a refactoring exercise for a later day and started by using &lt;a href="https://docs.serde.rs/serde_json/value/enum.Value.html"&gt;&lt;code&gt;serde_json::Value&lt;/code&gt;&lt;/a&gt;, which is kinda a catch-all solution. It is an Enum that represents any valid JSON value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;fetch_games&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;serde_json&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;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;request_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://nhl-score-api.herokuapp.com/api/scores/latest"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;reqwest&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;request_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;serde_json&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;response&lt;/span&gt;&lt;span class="nf"&gt;.json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&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;Here's my original &lt;code&gt;fetch_games&lt;/code&gt; function that called the API and parsed the data into a &lt;code&gt;serde_json::Value&lt;/code&gt;. Nice and clean, easy to use.&lt;/p&gt;

&lt;p&gt;But it led to my code being full of code like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;games&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"games"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_array&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;home_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"abbreviation"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;all_goals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"goals"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_array&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had to code very defensively because any type conversion with &lt;code&gt;as_&lt;/code&gt; methods could have fail and thus needed to be unwrapped and in some cases, made sure the keys even existed in the beginning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="nf"&gt;.is_null&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;home_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"abbreviation"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;away_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"away"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"abbreviation"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;serde_json::Value&lt;/code&gt; did help me build the first functioning versions of my application but in the back of my head I had the knowledge that defining the structures as Rust structs would make my code better.&lt;/p&gt;

&lt;p&gt;One key thing that kept me from doing that in the beginning was I couldn't figure out how to deal with dynamic keys. The API I use uses team abbreviations as keys on certain places and I had no idea how to do it so I left the issue for months.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to define structs for JSON
&lt;/h2&gt;

&lt;p&gt;Using custom structs to define expected types with JSON is rather straight-forward if you're familiar with structs.&lt;/p&gt;

&lt;p&gt;I'll start with the example &lt;a href="https://docs.serde.rs/serde_json/"&gt;from the documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;phones&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Here we define a &lt;code&gt;Person&lt;/code&gt; that has name as &lt;code&gt;String&lt;/code&gt;, an age as &lt;code&gt;u8&lt;/code&gt; and a list of phone numbers as &lt;code&gt;Vec&amp;lt;String&amp;gt;&lt;/code&gt;. Once we have this definition, all we have to do is to use that as a type of the result and &lt;code&gt;serde_json&lt;/code&gt; and Rust will validate that the structure and types of data matches what we defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Parse the string of data into a Person object.&lt;/span&gt;
&lt;span class="k"&gt;let&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;Person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Do things just like with any other Rust data structure.&lt;/span&gt;
&lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please call {} at the number {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="py"&gt;.phones&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Then we draw the rest of the owl
&lt;/h2&gt;

&lt;p&gt;I found the base example very good and nice to follow. However, that wasn't all that I needed so next I needed to figure out how to &lt;a href="https://knowyourmeme.com/memes/how-to-draw-an-owl"&gt;draw the rest of the owl&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  snake_case of Rust with camelCase of JSON
&lt;/h3&gt;

&lt;p&gt;First, Rust likes to use &lt;a href="https://en.wikipedia.org/wiki/Snake_case"&gt;snake_case&lt;/a&gt; and gives you a warning by default if you don't. JSON keys are usually in &lt;a href="https://en.wikipedia.org/wiki/Camel_case"&gt;camelCase&lt;/a&gt; so my editor and my shell were full of warnings and that was annoying. I learned that I can silence them by defining an &lt;code&gt;allow&lt;/code&gt; attribute for each struct that needed it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="nd"&gt;#[allow(non_snake_case)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;TeamResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;abbreviation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;locationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;shortName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;teamName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;I haven't yet found out if there's a way to use snake case'd names and automatically map them to corresponding JSON values. (Raymond Hettinger from the Python community has &lt;a href="https://www.youtube.com/watch?v=wf-BqAjZb8M"&gt;a nice talk for why it's valuable to have your code in idiomatic Python&lt;/a&gt;; much of it is applicable to any language).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;edit&lt;/strong&gt;: Thanks to &lt;a href="https://github.com/Hamatti/nhl-235/pull/27#discussion_r626688198"&gt;PatatasDelPapa's comment in pull request&lt;/a&gt;, I was able to fix this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="nd"&gt;#[serde(rename_all&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"camelCase"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;TeamResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;abbreviation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;location_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;short_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;team_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;h3&gt;
  
  
  Code organizing API response types into a separate file
&lt;/h3&gt;

&lt;p&gt;Second, you'll see that in the snippet above, definitions start with pub. That's because I wanted to move my API response type definitions to its own file so they don't pollute my main.rs and it's easier to find and change them. So I made &lt;code&gt;api_types.rs&lt;/code&gt; file, moved them all there, added plenty of &lt;code&gt;pub&lt;/code&gt;s and imported them with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;api_types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;api_types&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;APIResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GameResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GoalResponse&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in main.rs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic keys
&lt;/h3&gt;

&lt;p&gt;Third, I needed some support for dynamic keys. I was expecting to have to jump through some hoops but this ended up being one of the easiest steps in the process. Thanks to &lt;a href="https://github.com/serde-rs/serde/issues/1387"&gt;this GitHub issue&lt;/a&gt;, I found the solution: use &lt;code&gt;HashMap&amp;lt;String, serde_json::Value&amp;gt;&lt;/code&gt; for any object that has dynamic keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="nd"&gt;#[allow(non_snake_case)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;GameResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StatusResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;goals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GoalResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;serde_json&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;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TeamsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;preGameStats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PreGameStatsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;currentStats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CurrentStatsResponse&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;In the documentation of the API, &lt;code&gt;scores&lt;/code&gt; field is defined as&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;scores&lt;/code&gt; object: each team’s goal count, plus one of these possible fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;overtime&lt;/code&gt;: set to &lt;code&gt;true&lt;/code&gt; if the game ended in overtime, absent if it didn’t&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shootout&lt;/code&gt;: set to &lt;code&gt;true&lt;/code&gt; if the game ended in shootout, absent if it didn’t&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;and looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scores"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"BOS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"CHI"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overtime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The keys for each team are gonna be dynamic so by using &lt;code&gt;HashMap&lt;/code&gt;. The downside of this that I wasn't able to figure out, is that I'd like to put &lt;code&gt;overtime&lt;/code&gt; and &lt;code&gt;shootout&lt;/code&gt; keys into the type definitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional keys
&lt;/h3&gt;

&lt;p&gt;And finally, fourth, some keys are optional – or to be specific in this case, they are dependent on the situation.&lt;/p&gt;

&lt;p&gt;I'm happy I already learned about &lt;code&gt;Option&lt;/code&gt; types earlier (check out &lt;a href="https://hamatti.org/posts/learning-rust-2-option-result/"&gt;Learning Rust #2&lt;/a&gt; if you haven't heard about them). And that's all you need with Rust and &lt;code&gt;serde_json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;APIResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DateResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;games&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GameResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;serde_json&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;&amp;gt;&amp;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;In this example, which is the top level definition of my API response type, I've defined &lt;code&gt;errors&lt;/code&gt; to be optional – it's only present if the API I use found some errors in the data it's using.&lt;/p&gt;

&lt;p&gt;By saying that the type of the data is &lt;code&gt;Option&lt;/code&gt;, we'll either get a &lt;code&gt;Some(value)&lt;/code&gt; if the key exists and &lt;code&gt;None&lt;/code&gt; if it doesn't. For most cases in this application, it's not random which keys are there and which are not. So if I'm already in a branch of logic where the prerequisite is being dealt with, I can trust that the value exists and can unwrap without dealing with potential &lt;code&gt;None&lt;/code&gt;s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result? Much cleaner code
&lt;/h2&gt;

&lt;p&gt;Refactoring the code with these definitions is not only an exercise of writing code for the sake of writing code. The result of this work is that we push the problems at the boundaries of parsing the data and we don't have to deal with them at the logic level anymore.&lt;/p&gt;

&lt;p&gt;I already showed some examples in the beginning about the code I wasn't happy about. Let's see how they look like now:&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="nf"&gt;.is_null&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;home_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"abbreviation"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;away_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"away"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"abbreviation"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;home_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="py"&gt;.teams.home.abbreviation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;away_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="py"&gt;.teams.away.abbreviation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;serde_json&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;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;all_goals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"goals"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.as_array&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;all_goals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game_json&lt;/span&gt;&lt;span class="py"&gt;.goals&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't know about you but I'm very happy to see my code being much more simpler and easier to read. I can also trust that once the data comes through from the API, it won't have any surprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anything I don't like?
&lt;/h2&gt;

&lt;p&gt;Writing type definitions for these kind of nested structures feels sometimes overly complicated. There are some definitions that I don't need anywhere outside one value in the structure and having to write a named struct to that feels bit annoying.&lt;/p&gt;

&lt;p&gt;One thing I did enjoy in Typescript is a way to write in-line nested types and interfaces like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IEndpoints&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;In Rust, I would have needed to make two structs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pull requests for all these changes
&lt;/h2&gt;

&lt;p&gt;If you wanna check out all the changes and how the codebase cleaned up during this process, you can find it in GitHub: &lt;a href="https://github.com/Hamatti/nhl-235/pull/27/"&gt;hamatti/nhl-235/pull/27&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>learning</category>
    </item>
    <item>
      <title>How Spice Program supported my creation of 235</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Mon, 19 Apr 2021 12:43:15 +0000</pubDate>
      <link>https://dev.to/futurice/how-spice-program-supported-my-creation-of-235-2cjj</link>
      <guid>https://dev.to/futurice/how-spice-program-supported-my-creation-of-235-2cjj</guid>
      <description>&lt;p&gt;At the end of 2020, I decided to finally start learning Rust. For over a year before that, I had been playing with the idea of it but it took me all the way until the end of 2020 to get started. Rust is an interesting language for me, as I have mostly programmed with languages like Python and Javascript. Rust is something quite different and from the outside looking in, its community looked great as well.&lt;/p&gt;

&lt;p&gt;After my initial steps with the language where I was solving &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt; puzzles, I decided to build my first software with &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;. I'm an active command-line user so for me the obvious first choice was building a CLI tool. Hence, on a dark wintery Friday evening, I started working on a hobby project that would become &lt;a href="https://hamatti.github.io/nhl-235/"&gt;235&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's 235?
&lt;/h2&gt;

&lt;p&gt;For the small subset of readers who live in Finland and have been fans of the &lt;a href="https://www.nhl.com/"&gt;National Hockey League (NHL)&lt;/a&gt; for a long time, the number 235 rings a bell. For decades, the Finnish broadcasting company Yle has provided NHL results on their &lt;a href="https://yle.fi/aihe/tekstitv"&gt;teletext service on the page 235&lt;/a&gt;. For me, and many others like me, it's a habit to start every day by checking the page 235 to see the results of previous night's games.&lt;/p&gt;

&lt;p&gt;Inspired by this cultural phenomenon, I decided to build a tool that combined the minimalist and iconic style of that teletext page with data from an API for NHL results.&lt;/p&gt;

&lt;p&gt;235 is my first Rust program and it provided me a great opportunity to learn a new language – the spec was small and well-defined - it didn't require complex advanced features of the language - I knew it would be useful for me and people like me on a daily basis.&lt;/p&gt;

&lt;p&gt;For learning &amp;amp; hobby projects, that combination of usability, simplicity and small scope is key. I know I'm not the only one with dozens of unfinished projects that grew too big from the original idea and with limited time to work on, personal projects never ended up being finished.&lt;/p&gt;

&lt;p&gt;235 is published with MIT license and &lt;a href="https://github.com/Hamatti/nhl-235"&gt;the code can be found on GitHub&lt;/a&gt;. &lt;em&gt;(The project is called nhl-235 because Rust doesn't allow project names to start with a digit.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributing executables is a very different world than web apps in browsers
&lt;/h2&gt;

&lt;p&gt;As I mentioned above, this is my first Rust project and coming from a background of really different languages, there has been a lot to learn. This is the first time I've been working with binary executables. For almost two decades, I've loved web for its distribution model — you write code, deploy to server and it's updated for everyone. With executables, people need to proactively update their versions which means I need to think about new ways to reach them and communicate.&lt;/p&gt;

&lt;p&gt;Certain things are also much slower for me to develop. One thing I really enjoy with Python and Javascript (both given their dynamic style and my experience writing them) is how I can focus much more into the content and domain, and much less on meta level things. I recently shared &lt;a href="https://hamatti.org/posts/learning-rust-2-option-result/"&gt;my thoughts about Option and Result types on my blog&lt;/a&gt;. Even though I have a theoretical understanding of how they work and what their benefits are, my development too often comes to a halt and I need to rethink and refactor things a lot more with Rust.&lt;/p&gt;

&lt;p&gt;Luckily, the Rust community is great and I've gotten so much help in my learning journey from local and global Rust developers who have been so helpful and compassionate when I've been stumbling around trying to understand the basics of the language and how to write it.&lt;/p&gt;

&lt;h2&gt;
  
  
  And my employer supports my work on 235
&lt;/h2&gt;

&lt;p&gt;In 2013, &lt;a href="https://futurice.com/blog/futurice-open-source-program-the-spice-program"&gt;Spice Program was born&lt;/a&gt; as our open source and social impact program. Part of it is the support for open-source contributions of Futuriceans. In a nutshell: when you work at Futurice and do open source work on your own time, we support that with a monetary bonus of 15 euros/hour, capped at 30 hours/month.&lt;/p&gt;

&lt;p&gt;In 2019, &lt;a href="https://futurice.com/blog/futurice-professional-volunteering-bonus-extended"&gt;we expanded it to be more inclusive to people in the company who don't code&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The key purpose of our volunteering bonus is to make use of and develop your professional skills for social impact. For us, open source is always considered social impact, but there are many other ways to achieve that impact.&lt;/p&gt;

&lt;p&gt;When a designer helps to create a beautiful web presence for a poor non-profit on an important mission, it should count, even if the graphical assets cannot be properly published as open source.&lt;/p&gt;

&lt;p&gt;When an HR specialist helps in organising and running code schools for kids, it should count, even if there are no digital deliverables.&lt;/p&gt;

&lt;p&gt;When a business advisory professional teaches principles of lean service creation to an NGO striving to make sure whales don't start smoking, it should count.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From a perspective of a developer, I'm happy that I get to build things that I want to see in the world and be appreciated for that with a small bonus.&lt;/p&gt;

&lt;p&gt;And even more, it enables and incentivises me to learn more and to contribute to the open source ecosystem. With its flexibility, I'm not forced to do anything or have to make choices between other things in live and coding: sometimes I spend a weekend on a personal passion project and sometimes it's months that I don't code anything on my free-time.&lt;/p&gt;

&lt;p&gt;One thing I realised only after I had built the first version of my 235: &lt;a href="https://github.com/peruukki/nhl-score-api"&gt;the API I decided to use&lt;/a&gt; was also developed with Spice support back in the day. That's the beauty of the open source ecosystem and community: &lt;strong&gt;things you build today can be fundamental in helping others build new things.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Over the past few months, we've been averaging at roughly 700 hours of Spice contributions per month. You can find more about the &lt;a href="https://spiceprogram.org/"&gt;Spice Program here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>rust</category>
      <category>commandline</category>
    </item>
    <item>
      <title>Learning Rust #3: crates.io &amp; publishing your package</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Thu, 15 Apr 2021 09:10:31 +0000</pubDate>
      <link>https://dev.to/hamatti/learning-rust-3-crates-io-publishing-your-package-3k7p</link>
      <guid>https://dev.to/hamatti/learning-rust-3-crates-io-publishing-your-package-3k7p</guid>
      <description>&lt;p&gt;&lt;em&gt;Last December I finally started learning Rust and last month I built and published my first app with Rust: &lt;a href="https://hamatti.org/posts/introducing-235/"&gt;235&lt;/a&gt;. &lt;strong&gt;Learning Rust&lt;/strong&gt; is my new monthly blog series that is defnitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This week I wanted to take a look at the publishing and distribution of Rust applications. It presents a major difference to what I'm used to and what I love in the web app world so I'll discuss that first and then look at the practicalities and the documentation of getting your application to the computers of your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I was young, we bought software from store
&lt;/h2&gt;

&lt;p&gt;I want to start this with a bit of a story. When we got our first family computer in the early 1990s, we'd buy software in floppy disks from a computer store. This was true a decade later with the small change that the software was distributed in CDs.&lt;/p&gt;

&lt;p&gt;The Internet was young and the connections and download speeds were not suitable for mass scale distribution of software as downloadables. In the early 2000s, I started to use some online services like forums and early versions of social media via browser.&lt;/p&gt;

&lt;p&gt;When I was 15, I knew I couldn't write my own software, get it to store shelves and have people buy it. I was just a beginner developer learning the first steps. So building things on the web, to be used with browsers was what I decided to go with. It probably wasn't as concious and thoughout decision as I see it through the goggles of nostalgy. However, the fact that I could build something, upload it (we used to deploy by moving PHP files with FTP client to the server) and it would available to anyone interested in using it was definitely a major reason for why I fell in love with the web as a medium.&lt;/p&gt;

&lt;p&gt;So, for 15 years, almost everything I built, was deployed to a webserver somewhere and accessed via browser. I did build some tools for myself that were run locally but they were never meant to be given to other people so distribution was not a factor.&lt;/p&gt;

&lt;p&gt;As the web development as a field progressed over the 15 years, distribution became even easier and instead of ftp'ing bunch of files to the server, we started to set up automatic deploys and working with version control. But the essence of distribution didn't change: I make a change and it's available to everyone without needing any action from them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I built my first Rust binaries
&lt;/h2&gt;

&lt;p&gt;This brings us back to 2021 and me learning Rust. When the end result of your work is a binary executable, everything in terms of distribution changes. No longer, can I fix an issue quickly and have it in front of every user within minutes.&lt;/p&gt;

&lt;p&gt;Thanks to the internet and Rust's package ecosystem, there's no need to burn the app on a CD, put into a beautiful cardboard box and sell in stores. Now people can download it in seconds, update it easily and get things rolling with the new version.&lt;/p&gt;

&lt;p&gt;But there's still one major difference: people need to update their app manually. There might be some ways to let people know that their application needs updating: first thing that comes to mind is making an API call to a server that returns the last version number and if it's newer than what the user has, print a "you should update" message. Thinking of it now, I might end up doing that before 235 hits version 1.0. &lt;em&gt;&lt;a href="https://twitter.com/hamatti"&gt;Let me know&lt;/a&gt; if there's a better way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But still, people may run your application for months or years without checking for updates, especially if it works. Or they might abandon it quickly if there are annoying bugs and when they notice it, there ain't no new version yet.&lt;/p&gt;

&lt;p&gt;The authority of updates moves from the developer to the user. And that changes so much.&lt;/p&gt;

&lt;h2&gt;
  
  
  crates.io
&lt;/h2&gt;

&lt;p&gt;Rust's package registry is called &lt;a href="https://crates.io/"&gt;crates.io&lt;/a&gt;. If you're a Javascript developer, it's similar to npm. For Python users, it's similar to PyPi. It's the place where you find the tools you need to write great Rust programs without reinventing the wheel. It's also where you can install 235 from.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cargo install nhl-235&lt;/code&gt; is the command line command that pulls the package and builds it.&lt;/p&gt;

&lt;p&gt;To publish Rust code in crates, you need two thing: account in crates.io and &lt;code&gt;Cargo.toml&lt;/code&gt; file with &lt;a href="https://doc.rust-lang.org/cargo/reference/publishing.html"&gt;certain information you can check from the docs&lt;/a&gt;. After those are correctly done, &lt;code&gt;cargo publish&lt;/code&gt; transfers your code via the highway of information to the package registry so others can install it and use it.&lt;/p&gt;

&lt;p&gt;I really enjoy the process. It's developer experience is fantastic and once I've gotten a new release version done, I just publish it and people can update it with &lt;code&gt;cargo install nhl-235&lt;/code&gt;. So good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building binaries
&lt;/h2&gt;

&lt;p&gt;You don't have to share your program in crates.io though. Since the result of the build process is a binary, you can just share that. I'm still learning how to use the &lt;a href="https://github.com/Hamatti/nhl-235/releases/tag/v0.2.5"&gt;Releases page of GitHub&lt;/a&gt; but whenever I publish to crates.io, I upload a new release build to GitHub to which I also link from &lt;a href="https://hamatti.github.io/nhl-235/"&gt;my website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This allows people to download and run your program without any need for the Rust language tooling installed.&lt;/p&gt;

&lt;p&gt;I develop 235 on a macos and I'm not 100% sure if my builds work on any machine. It's on my todo list to learn more and test it more thoroughly but so far, nobody has complained. If you wanna give me a hand and use Windows or Linux, download &lt;a href="https://github.com/Hamatti/nhl-235/releases/tag/v0.2.5"&gt;the latest release from here&lt;/a&gt; and run it from the command line and &lt;a href="https://twitter.com/hamatti"&gt;let me know in Twitter&lt;/a&gt; if it works or not.&lt;/p&gt;

&lt;p&gt;A huge benefit of the binaries compared to crates.io is that the end user doesn't need any Rust tools installed and I gain full control over distribution. And those updates? It's bit more of a hassle since people need to go and download the binaries again and replace the old ones.&lt;/p&gt;

&lt;p&gt;Eventually 235 will reach design and technical maturity where it won't be updated with new features and hopefully won't have breaking bugs anymore. At that point, the need to update constantly will thankfully disappear. Until I may have to do some changes to the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making a release is more deliberate
&lt;/h2&gt;

&lt;p&gt;One thing I've noticed is that when I can't just deploy a change or fix in a matter of minutes, I need to be much more deliberate, test things out more and figure out if the design of the program is correct. In the beginning, it's more okay to experiment especially as I'm learning the language but as I reach version 1.0, I'm looking to only make changes in larger chunks.&lt;/p&gt;

&lt;p&gt;All in all, publishing 235 via crates.io and as binaries has been a very educational process and a refreshing change of pace compared to my usual web development projects.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>learning</category>
    </item>
    <item>
      <title>Learning Rust #2: Option &amp; Result</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Fri, 19 Mar 2021 09:00:47 +0000</pubDate>
      <link>https://dev.to/hamatti/learning-rust-2-option-result-2bge</link>
      <guid>https://dev.to/hamatti/learning-rust-2-option-result-2bge</guid>
      <description>&lt;p&gt;&lt;em&gt;Last December I finally started learning Rust and last month I built and published my first app with Rust: &lt;a href="https://hamatti.org/posts/introducing-235/"&gt;235&lt;/a&gt;. Learning Rust is my new monthly blog series that is definitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last month I started this series by talking about something I really enjoyed: pattern matching. And while writing and after sharing that post, I did further refactoring on the codebase based on ideas and suggestions by the community. Special thanks to Juho F. for helping out!&lt;/p&gt;

&lt;p&gt;This month, I want to talk about something that made me struggle a lot and caused (and still causes) my code writing to slow down considerably: &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; types and how I constantly run into issues with them.&lt;/p&gt;

&lt;p&gt;Coming from Python and Javascript development, I'm used to values being most often just values (or &lt;code&gt;null&lt;/code&gt;). I can call a function and immediately continue with the return value.&lt;/p&gt;

&lt;p&gt;In Rust, things are done a bit differently. You can still write functions that take an input and return a value but in many cases, functions return an &lt;a href="https://doc.rust-lang.org/std/option/"&gt;&lt;code&gt;Option&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://doc.rust-lang.org/std/result/"&gt;&lt;code&gt;Result&lt;/code&gt;&lt;/a&gt; that are kind of wrappers around the actual values. The reason for this is to add safety over different kind of errors and missing values.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an &lt;code&gt;Option&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Option&lt;/code&gt; is a type that is always either &lt;code&gt;Some&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;denominator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;denominator&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numerator&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;denominator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example is from &lt;a href="https://doc.rust-lang.org/std/option/"&gt;Rust Option's documentation&lt;/a&gt; and is a good example of &lt;code&gt;Option&lt;/code&gt;'s usefulness: there's no defined value for dividing with zero so it returns &lt;code&gt;None&lt;/code&gt;. For all other inputs, it returns &lt;code&gt;Some(value)&lt;/code&gt; where the actual result of the division is wrapped inside a &lt;code&gt;Some&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;For me, it's easy to understand why it's implemented that way and I agree that it's a good way to make the code more explicit about the ways you treat different end cases. But it can be so frustrating especially when learning programming.&lt;/p&gt;

&lt;p&gt;There are a couple of ways to get the value from &lt;code&gt;Option&lt;/code&gt;s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pattern match to retrieve the value&lt;/span&gt;
&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The division was valid&lt;/span&gt;
    &lt;span class="nf"&gt;Some&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result: {}"&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="c1"&gt;// The division was invalid&lt;/span&gt;
    &lt;span class="nb"&gt;None&lt;/span&gt;    &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot divide by 0"&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;Continuing from previous example and &lt;a href="https://dev.to/hamatti/learning-rust-1-pattern-matching-mia"&gt;my previous blog post&lt;/a&gt; on the topic, pattern matching gives a clean interface for continuing with the data. I find this most useful when it's the end use case for the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;games&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.for_each&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print_game&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_colors&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;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;In &lt;a href="https://github.com/Hamatti/nhl-235"&gt;235&lt;/a&gt;, I use it for example to print games that have been parsed correctly and just ignore the ones that were not. Ignoring them is not a very good way in the long run but in this case, it's been good enough.&lt;/p&gt;

&lt;p&gt;Other way is to &lt;code&gt;unwrap&lt;/code&gt; the &lt;code&gt;Option&lt;/code&gt;. The way &lt;code&gt;unwrap&lt;/code&gt; method works is that it returns the value if &lt;code&gt;Option&lt;/code&gt; is &lt;code&gt;Some&lt;/code&gt; and panics if it's &lt;code&gt;None&lt;/code&gt;. So when using plain &lt;code&gt;unwrap&lt;/code&gt;, you need to figure out the error handling throughout.&lt;/p&gt;

&lt;p&gt;There are also other variants of &lt;code&gt;unwrap&lt;/code&gt;. You can &lt;code&gt;unwrap_or&lt;/code&gt; which takes a default value that it returns when &lt;code&gt;Option&lt;/code&gt; is &lt;code&gt;None&lt;/code&gt;. And &lt;code&gt;unwrap_or_else&lt;/code&gt; which functions like the previous but takes a function as a parameter and then runs that on the case of &lt;code&gt;None&lt;/code&gt;. Or you can rely on the type defaults by running &lt;code&gt;unwrap_or_default&lt;/code&gt; if all you need is a type default.&lt;/p&gt;

&lt;p&gt;But there's still more! For added variety, there's the &lt;code&gt;?&lt;/code&gt; operator. If the &lt;code&gt;Option&lt;/code&gt; it's used on is a &lt;code&gt;Some&lt;/code&gt;, it will return the value. If it's a &lt;code&gt;None&lt;/code&gt;, it will instead return out from the function it's called in and return &lt;code&gt;None&lt;/code&gt;. So to be able to use &lt;code&gt;?&lt;/code&gt; operator, you need to make your function's return type an &lt;code&gt;Option&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To create an &lt;code&gt;Option&lt;/code&gt; yourself, you need to use either &lt;code&gt;Some(value)&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt; when assigning to a variable or as a return value from a function.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a &lt;code&gt;Result&lt;/code&gt; then?
&lt;/h2&gt;

&lt;p&gt;The other "dual type" (I don't know what to call it) in Rust is &lt;a href="https://doc.rust-lang.org/rust-by-example/error/option_unwrap/question_mark.html"&gt;&lt;code&gt;Result&lt;/code&gt;&lt;/a&gt;. Similar to &lt;code&gt;Option&lt;/code&gt; above, &lt;code&gt;Result&lt;/code&gt; can be one of two things: it's either an &lt;code&gt;Ok&lt;/code&gt; or an &lt;code&gt;Error&lt;/code&gt;. To my understanding so far, &lt;code&gt;Ok&lt;/code&gt; basically functions the same than &lt;code&gt;Some&lt;/code&gt; that it just contains the value. &lt;code&gt;Error&lt;/code&gt; is more complex than &lt;code&gt;None&lt;/code&gt; in that it will carry the error out from the function so it can be taken care of elsewhere.&lt;/p&gt;

&lt;p&gt;Same kind of pattern matching can be used to deal with &lt;code&gt;Results&lt;/code&gt; than with &lt;code&gt;Options&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;fetch_games&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;parsed_games&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_games&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;print_games&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed_games&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_colors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;In &lt;a href="https://github.com/Hamatti/nhl-235"&gt;235&lt;/a&gt;, on the top level, I use above pattern match after fetching the scores from the API. If anything happens with the network request, the application will print out the error. One of the tasks on my todo list is to build a bit more user-friendly output depending on the different cases rather than just printing out raw Rust errors. I haven't figured out yet how to deal with errors in Rust in more detail yet though – once I do, I'll write a blog post in this series about it.&lt;/p&gt;

&lt;p&gt;Like with &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;unwrap&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt; also work for &lt;code&gt;Result&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why do I struggle?
&lt;/h2&gt;

&lt;p&gt;As I've been writing this blog post, everything seems so clear and straight-forward to me. Still, when actually writing the code, I stumble a lot. As I mentioned earlier, I come from Python and Javascript where none of this is used.&lt;/p&gt;

&lt;p&gt;One thing I've noticed to struggle is that I write some code, calling a function from standard library or some external library and forget it's using either &lt;code&gt;Option&lt;/code&gt; or &lt;code&gt;Result&lt;/code&gt;. Or I forget which one had which internals and thus, I'm still in a phase with Rust where I need to check so many things from the documentation all the time.&lt;/p&gt;

&lt;p&gt;It also feels like you need to take so many more things into consideration. If you want to use &lt;code&gt;?&lt;/code&gt;, you also need to change the way your function is defined and how the caller works and sometimes that can go on for a few levels. So my inexperience with the language leads to plenty of constantly making messy changes all around and occasionally ending up in a dead end I can't dig myself out of and I end up starting over.&lt;/p&gt;

&lt;p&gt;And while I know it's mostly about getting used to a different system, I sometimes feel so dumb when I struggle with making the code not take into account all different ways it can crash (which is a big reason &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; are built the way they are).&lt;/p&gt;

&lt;h2&gt;
  
  
  What's up with 235?
&lt;/h2&gt;

&lt;p&gt;I've been using 235 myself daily since the first developmental version and I'm loving it. It's the one piece of software I'm most proud of and it's been answering my needs very well – and from what I've heard of from others, their needs as well.&lt;/p&gt;

&lt;p&gt;235 is about to hit version 1.0. I'm getting confident that I've taken care of most of the major bugs conserning the basic usage and that gives me confidence in incrementing the version to 1.0.&lt;/p&gt;

&lt;p&gt;Two things still need to be taken care before that and I'll hopefully get them done early March once I get a couple of lectures and talks out of my plate. First thing is to fix a &lt;a href="https://github.com/Hamatti/nhl-235/issues/22"&gt;bug that has a slight chance to appear during the playoffs&lt;/a&gt;. Second one is to make the &lt;a href="https://github.com/Hamatti/nhl-235/issues/16"&gt;error handling bit better and provide more user-friendly outputs when things go wrong&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  If I wanna learn Rust, where should I go?
&lt;/h2&gt;

&lt;p&gt;Like I said, don't take these posts as gospel or tutorial. If you wanna learn Rust, my recommendation as a starting point (and one I started with) is &lt;a href="https://doc.rust-lang.org/book/"&gt;Rust Book&lt;/a&gt; and with it, &lt;a href="https://doc.rust-lang.org/rust-by-example/index.html"&gt;Rust by Example&lt;/a&gt;. Also, joining your local Rust communities and being active in Twitter by following &lt;a href="https://twitter.com/rustlang"&gt;@rustlang&lt;/a&gt; and taking part in discussions with #rustlang.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>learning</category>
    </item>
    <item>
      <title>Learning Rust #1: Pattern Matching</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Thu, 11 Mar 2021 09:38:40 +0000</pubDate>
      <link>https://dev.to/hamatti/learning-rust-1-pattern-matching-mia</link>
      <guid>https://dev.to/hamatti/learning-rust-1-pattern-matching-mia</guid>
      <description>&lt;p&gt;&lt;em&gt;Last December I finally started learning Rust and last month I built and published my first app with Rust: &lt;a href="https://hamatti.org/posts/introducing-235/" rel="noopener noreferrer"&gt;235&lt;/a&gt;. Learning Rust is my new monthly blog series that is definitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My process of learning is reading some guides and docs (with Rust, I started with &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;The Rust Book&lt;/a&gt; and &lt;a href="https://doc.rust-lang.org/rust-by-example/index.html" rel="noopener noreferrer"&gt;Rust by Example&lt;/a&gt;), then I try to make something that works, ask a lot of questions from the community, improve, fix bugs, read some more and now I'm writing blog posts which require me to do more research and help me futher improve my program.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first concept that I've really liked and that I have not used in other languages is the &lt;a href="https://doc.rust-lang.org/book/ch06-02-match.html" rel="noopener noreferrer"&gt;&lt;code&gt;match&lt;/code&gt;&lt;/a&gt; operator for pattern matching. In correct use cases, it can make the code nice and easy to read but it also can end up becoming a messy spaghetti. I'm currently still trying to figure out when it's best to use and when not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics of pattern matching
&lt;/h2&gt;

&lt;p&gt;First use case I have for match is to map team name abbreviations from the API into the city names I want to use in the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;str_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;abbr&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"BOS"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Boston"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"BUF"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Buffalo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"NJD"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"New Jersey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"NYI"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"NY Islanders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"NYR"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"NY Rangers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"PHI"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Philadelphia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"PIT"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Pittsburgh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"WSH"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Washington"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"CAR"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Carolina"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"CHI"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Chicago"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"CBJ"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Columbus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"DAL"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Dallas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"DET"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Detroit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"FLA"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Florida"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"NSH"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Nashville"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TBL"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Tampa Bay"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"ANA"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Anaheim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"ARI"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Arizona"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"COL"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Colorado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"LAK"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Los Angeles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MIN"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Minnesota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"SJS"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"San Jose"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"STL"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"St. Louis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"VGK"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Vegas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"CGY"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Calgary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"EDM"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Edmonton"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MTL"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Montreal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"OTT"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Ottawa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TOR"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Toronto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"VAN"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Vancouver"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"WPG"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Winnipeg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"[unknown]"&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;&lt;em&gt;(Editor's note: while writing this blog post, I'm exposing myself to how bad my variable naming is in this project. That's partially because so much mental energy is spent on figuring out how to write Rust that there's not much left for thinking about good names. I'll fix 'em little by little as I refactor so it might be that at the moment you're reading this, I have already renamed them in &lt;a href="https://github.com/Hamatti/nhl-235" rel="noopener noreferrer"&gt;the source&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another example of how I use &lt;code&gt;match&lt;/code&gt; in 235 is when deciding how to print lines of goals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;score_iter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;home_scores&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.zip_longest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;away_scores&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&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;pair&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;score_iter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Both&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print_full&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&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="nf"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Right&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print_right&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="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;Here, I have &lt;code&gt;score_iter&lt;/code&gt; (again, not the greatest name, I admit) which is a Zip that supports uneven lengths. For example, it could look something like this (this example is pseudo, the actual data is more complex. &lt;code&gt;_&lt;/code&gt; denotes a missing value):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  ((Appleton, 2), (Boeser, 0)),
  (_, (Hoglander, 8)),
  (_, (MacEwen, 26)),
  (_, (Boeser, 57))
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By matching these pairs, each line will either be (&lt;code&gt;itertools::EitherOrBoth::&lt;/code&gt;)&lt;code&gt;Both&lt;/code&gt; which means both values are there, &lt;code&gt;Left&lt;/code&gt; meaning only the left value exists and &lt;code&gt;Right&lt;/code&gt; for only right value existing. Matching these with &lt;code&gt;match pair&lt;/code&gt;, it's nice and clean to run the corresponding print function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs3n2ltf20vsx5apsz8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxs3n2ltf20vsx5apsz8z.png" alt="Text lined up in three columns with second column having 3 more rows than first and third"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This second &lt;code&gt;match&lt;/code&gt; example also showcases binding where we bind the values into variables &lt;code&gt;l&lt;/code&gt; and &lt;code&gt;r&lt;/code&gt; so we can refer to them inside the expressions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Options and Results
&lt;/h2&gt;

&lt;p&gt;Another very handy use case for &lt;code&gt;match&lt;/code&gt; is with &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt;. My main logic when running 235 on the command line is done within &lt;code&gt;api()&lt;/code&gt; function that returns &lt;code&gt;Result&amp;lt;(), reqwest::Error&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;Since &lt;code&gt;Result&lt;/code&gt; will either be &lt;code&gt;Ok&lt;/code&gt; or &lt;code&gt;Err&lt;/code&gt;, I'm matching &lt;code&gt;Ok&lt;/code&gt; with no-op and &lt;code&gt;Err&lt;/code&gt; with printing out the error into the console.&lt;/p&gt;

&lt;p&gt;Example with doing similar with &lt;code&gt;Option&lt;/code&gt; is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;games&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.for_each&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print_game&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;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;Here, if a game was parsed correctly, it will be &lt;code&gt;Some&lt;/code&gt; and if it didn't, it will be &lt;code&gt;None&lt;/code&gt; so we can just skip the &lt;code&gt;None&lt;/code&gt; case and only print the games that were parsed correctly from the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guards
&lt;/h2&gt;

&lt;p&gt;One thing I haven't used yet and only learned about it while doing research for this blog post is &lt;a href="https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#extra-conditionals-with-match-guards" rel="noopener noreferrer"&gt;guards&lt;/a&gt;. They are essentially additional if clauses combined with a pattern so you can differentiate similar values based on extra condition.&lt;/p&gt;

&lt;p&gt;The example in &lt;a href="https://doc.rust-lang.org/rust-by-example/flow_control/match/guard.html" rel="noopener noreferrer"&gt;Rust by Example&lt;/a&gt; is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pair&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="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="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="p"&gt;{&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="n"&gt;y&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;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"These are twins"&lt;/span&gt;&lt;span class="p"&gt;),&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="n"&gt;y&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;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Antimatter, kaboom!"&lt;/span&gt;&lt;span class="p"&gt;),&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="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&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;1&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The first one is odd"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No correlation..."&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;I haven't yet run into cases where I'd have use for the guards but wanted to record it here so you'll know it exists.&lt;/p&gt;

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

&lt;p&gt;All in all, &lt;code&gt;match&lt;/code&gt; might be my favorite syntactic thing in Rust so far. Sometimes it feels bit too much like a hammer (in sense of if all you have is a hammer, every problem starts to look like a nail) in that I tend to overuse it even when other means would make more sense. But I'm sure it's something that I'll find the right balance as I code more with Rust.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>learning</category>
    </item>
    <item>
      <title>Advent of Code #1: Getting Started</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Thu, 03 Dec 2020 16:11:48 +0000</pubDate>
      <link>https://dev.to/futurice/advent-of-code-1-getting-started-1b35</link>
      <guid>https://dev.to/futurice/advent-of-code-1-getting-started-1b35</guid>
      <description>&lt;p&gt;Every year I embark on a magical Christmas adventure with &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt;. Quite often, I end up working on the first few days' challenges and then it takes a backseat to other things in life. This year – like every other before it – I'm serious though and want to try to finish the entire challenge and document my learnings meanwhile.&lt;/p&gt;

&lt;p&gt;This series won't be a tutorial nor a "this is how you solve these challenges" guide but rather a journal of my progress with Advent of Code and Rust. If you're afraid of being spoiled on those challenges, try to solve them first before reading further as I'll show and talk about some code as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why am I so excited about code puzzles?
&lt;/h2&gt;

&lt;p&gt;When I was a kid, a chocolate advent calendar was the best way to get hyped for Christmas. Every morning, I started the day by opening a new window and find chocolate that was usually very sub-par in quality but it was never about the taste of chocolate. It was about the freedom to eat chocolate in the morning and the excitement of days leading towards the Christmas Eve (which is when we Finns celebrate).&lt;/p&gt;

&lt;p&gt;As a web developer occasionally working on client projects but mostly focusing on developer community building, I'm often looking to do something fun with code, experimenting with new technologies and keep learning but I don't want to start a multi-year project. Advent of Code is perfect for that. I can do snack-sized puzzles with some technology without any pressure of finishing or writing amazing code.&lt;/p&gt;

&lt;h2&gt;
  
  
  This year I'm using Rust
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcAt-RRy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/tjmv0hglsujst47v38dn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcAt-RRy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/tjmv0hglsujst47v38dn.png" alt="Rust, A language empowering everyone to build reliable and efficient software." width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have never really done any systems programming. I did one combined C &amp;amp; C++ course in university but that's pretty much it. Last year, when I was speaking at PyCon Estonia, I met &lt;a href="https://twitter.com/DomWeldon"&gt;Dom Weldon&lt;/a&gt; and saw his talk &lt;a href="https://www.youtube.com/watch?v=m1VCAp6hm0M"&gt;Oxidizing MyPy&lt;/a&gt; in which he talked about using Rust and Python together. That sparked an interest in me to get started with Rust.&lt;/p&gt;

&lt;p&gt;It took me a year to actually do anything with it. I was kinda saving Rust for another project but since I realized I might never make that happen, I'll start learning Rust with Advent of Code.&lt;/p&gt;

&lt;p&gt;One of the reasons I wanna learn Rust is to build command line tools. I have &lt;a href="https://hamatti.org/posts/why-i-love-command-line/"&gt;previously written about my love for CLI tools&lt;/a&gt; if you wanna know why. I've seen Rust becoming quite popular for CLI tools and I want to get into that groove.&lt;/p&gt;

&lt;h2&gt;
  
  
  Days 0 to 1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  First contact with Rust
&lt;/h3&gt;

&lt;p&gt;I wanted to get a good start with a new technology so I took a head start and spent the evening of Nov 30th to make sure I had a setup where I can start working on.&lt;/p&gt;

&lt;p&gt;So I started by installing Rust and Cargo, &lt;a href="https://doc.rust-lang.org/book/title-page.html"&gt;read the first few chapters of Rust docs&lt;/a&gt;, built the number guessing game in the documentation to make sure I know the very basics and built a template for unit tests.&lt;/p&gt;

&lt;p&gt;For me, Advent of Code is perfect place to use &lt;a href="https://en.wikipedia.org/wiki/Test-driven_development"&gt;Test-Driven Development&lt;/a&gt; and I've figured that if I learn how to write and run tests with new technology from the very first touchpoint, it's more likely I'll write good tests when I start using the language in more serious projects.&lt;/p&gt;

&lt;p&gt;Another thing I wanted to learn is the conventions of documentation in Rust. And Rust is great for that. Already on Day 0, I fell in love with &lt;a href="https://doc.rust-lang.org/cargo/commands/cargo-doc.html"&gt;&lt;code&gt;cargo doc&lt;/code&gt;&lt;/a&gt; that generates local documentation, not only from your own code but of your dependencies as well. How is that not a main feature in all languages and ecosystems? It is so smart. And it encourages good documentation of your own crates and functions as well. Rustdoc has &lt;a href="https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html"&gt;great documentation for how to write and build documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  December 1st
&lt;/h3&gt;

&lt;p&gt;First interesting thing I noticed with Rust is that it's recommended to keep unit tests in the same files as the functionality. Rust uses something called &lt;a href="https://doc.rust-lang.org/reference/conditional-compilation.html"&gt;&lt;em&gt;conditional compilation&lt;/em&gt;&lt;/a&gt; which means that you can define in source level, if you want something to be compiled to the final binary or in this case, only when running tests. That can be defined by annotating a function with &lt;code&gt;#[cfg(test)]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A bit similar functionality that I've used before is &lt;a href="https://docs.python.org/3/library/doctest.html"&gt;Python's doctest&lt;/a&gt; that allows tests to be included in docstrings of functions. Rust also has similar functionality but from a different perspective. Developers are encouraged to add an example or two into their documentation of functions so it's easier for readers to use the functionality. To make sure those documentation examples work, rustdoc runs those examples and tests them for you. &lt;em&gt;What a great way to keep documentation and code in sync.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iNKqMTGd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/7xssvovnhldy6cq63r95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iNKqMTGd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/7xssvovnhldy6cq63r95.png" alt="Hamatti 1*" width="244" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then it happened. I wrote my very first Rust code (by furiously googling and copy-pasting code together) and &lt;em&gt;IT WORKED&lt;/em&gt;. I got my very first star for this year. My code didn't look very beautiful and it probably wasn't the most idiomatic Rust. I'm guessing it looks like Python or Javascript developer's first Rust code.&lt;/p&gt;

&lt;p&gt;So I submitted it for code review to my colleagues at &lt;a href="https://futurice.com/"&gt;Futurice&lt;/a&gt; and fellow Rust developers at &lt;a href="https://koodiklinikka.fi/"&gt;Koodiklinikka&lt;/a&gt;. A great way to improve fast is to take a challenge, figure it out by reading docs and googling and then having a discussion about it with other developers. Thanks especially to &lt;a href="https://twitter.com/akx"&gt;Aarni&lt;/a&gt; and &lt;a href="https://github.com/Cadiac/"&gt;Jaakko&lt;/a&gt; for helping me improve my first bits of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning new is exhausting
&lt;/h2&gt;

&lt;p&gt;I've been coding more or less actively for a few decades since my teenage years. I noticed something very interesting (which reminded me it's been a while since I've been actively learning something new): even though I'm very familiar with basic concepts like reading input and looping and all that, when learning a new language like Rust, I keep completely forgetting all the basics.&lt;/p&gt;

&lt;p&gt;I decided to build my solution so that it reads the result from standard input rather than file and Jaakko did the opposite. After discussing our solutions and reviewing our code, I totally forgot I had done that, ran my code and waited for half a minute wondering why my code is so slow. I had forgotten to provide the input into standard input so the code wasn't doing anything.&lt;/p&gt;

&lt;p&gt;On the bright side, I love that kind of really intensive learning. It tickles my brain in just the right way and gets me excited with stuff.&lt;/p&gt;

&lt;p&gt;The first couple of days of Advent of Code are usually quite nice warmup challenges. They are helpful in making sure my setup works and my code is run correctly. This year was not an exception to that rule and I'm happy about that because there's always an extra added layer of complexity when setting new things up.&lt;/p&gt;

&lt;h2&gt;
  
  
  My solutions
&lt;/h2&gt;

&lt;p&gt;I update my solutions to my GitHub repository at &lt;a href="https://github.com/hamatti/adventofcode-2020"&gt;hamatti/adventofcode-2020&lt;/a&gt;. Since I'm a very beginner with Rust, I don't recommend taking them as example or you'll probably learn some bad habits.&lt;/p&gt;

&lt;p&gt;I won't probably solve those challenges every day but rather in batches of a few days at the time.&lt;/p&gt;

</description>
      <category>adventofcode</category>
      <category>rust</category>
    </item>
    <item>
      <title>How to ask help for technical problems?</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Tue, 24 Nov 2020 17:24:19 +0000</pubDate>
      <link>https://dev.to/hamatti/how-to-ask-help-for-technical-problems-29hg</link>
      <guid>https://dev.to/hamatti/how-to-ask-help-for-technical-problems-29hg</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally shared at my personal blog at &lt;a href="https://hamatti.org/posts/how-to-ask-help-for-technical-problems/"&gt;https://hamatti.org/posts/how-to-ask-help-for-technical-problems/&lt;/a&gt;. If you're interested in more posts like this, check out my other blog posts there and sign up for my monthly personal newsletter.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Over the years, I've been involved in a lot of different groups and communities where people ask for help for technical problems. I've seen some great questions and some where even just getting to the actual problem has taken a long time.&lt;/p&gt;

&lt;p&gt;In this post, I want to give some tips for anyone who wants to get help with their problems because the better your question covers different things and explains the problem and what you've done, easier it is for someone to help you. I do want to emphasise that for beginners, it's not easy to ask questions because there's so many unknowns. Hopefully these tips will help you on your journey to seek knowledge.&lt;/p&gt;

&lt;p&gt;Most of these are meant for &lt;em&gt;asynchronous communication&lt;/em&gt; like chat apps or forums or sites like Stack Overflow and focuses on programming related questions to narrow the scope of the post.&lt;/p&gt;

&lt;p&gt;The common thread in all these is to provide as much information and being as specific as possible up front so you and your helpers don't have to spend a day going back and forth before getting into the actual problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Ask your question, don't ask if someone can help
&lt;/h2&gt;

&lt;p&gt;Let's start with the first message you send. I often see people start by asking &lt;em&gt;"Is there anyone who can help me with XYZ?"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It sounds reasonable, right? However, it can hinder your ability to gain help a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's hard for the helper to know if they can help&lt;/li&gt;
&lt;li&gt;It lengthens the discussion loop unnecessarily long&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's say you are struggling with something in CSS. If you post a message on a proper chat room (like developer communities in Discord or Slack), there might be a lot of people who know CSS but they might not know the exact thing you're struggling with.&lt;/p&gt;

&lt;p&gt;Second, by asking that requires someone to say "Yes, what's your problem?" and it may take a day to even get into the discussion of the problem itself.&lt;/p&gt;

&lt;p&gt;Instead, just ask your question directly. "I'm trying to center align a &lt;code&gt;div&lt;/code&gt; inside another &lt;code&gt;div&lt;/code&gt; but can't figure out how?" is a much better start. We'll learn how to make it even better later in this post.&lt;/p&gt;

&lt;p&gt;When you ask the question like that, anyone at any point can take a look at it and have a better idea about if they can help you and they can start answering right away. You might get a solution to your problem even before you return to read the chat for the next time.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Explain what you are trying to achieve
&lt;/h2&gt;

&lt;p&gt;It might sound obvious but very often it's missing and can lead the people helping into a wild goose hunt to the wrong direction. This is especially relevant with new developers because you might be trying to do something with a bit wrong set of technical tools.&lt;/p&gt;

&lt;p&gt;The more specific you can be here also helps people grasp what you're aiming to do which helps them give you better answers.&lt;/p&gt;

&lt;p&gt;Rather than focusing on the technical implementation details, focus on what you want the effect of the code to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Include example input and output data
&lt;/h2&gt;

&lt;p&gt;If you're working on something that takes in data and outputs something else, provide both an example set of data to be used as an input and an expected output. Even better if you can provide multiple sets of different input/output pairs so your helper can test out that their implementation of the fix actually answers to your question.&lt;/p&gt;

&lt;p&gt;For example, if you're working on some regex or &lt;a href="https://joi.dev/"&gt;validation with Joi&lt;/a&gt;, offering a test input helps a long way in reducing back-and-forth between you and your helper.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Share the errors
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;"My code doesn't work, why?"&lt;/em&gt; isn't very helpful but often encountered question. The answer to that often is "I have no idea".&lt;/p&gt;

&lt;p&gt;So instead of being vague, be as specific as possible. One way to be specific is to share the error code you get (and share it every time when it changes during your process of figuring it out). For an experienced developer, errors reveal a lot so sometimes just looking at the error alone we might be able to figure out the problem – especially if it's a very common one.&lt;/p&gt;

&lt;p&gt;And please, always share those as copy-paste into code blocks (see next section for those) because that allows us to copy-paste further and search from Google if it's something we're unfamiliar with. Screenshots of errors are often just one more hinderance in trying to figure things out.&lt;/p&gt;

&lt;p&gt;If you're using some specific applications or libraries, share version numbers of those. For example, if you have a problem with Django, please tell the version of Django and version of Python that you're running. Programming languages and tools evolve and it might be that it's a specific issue to your version.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Show your code
&lt;/h2&gt;

&lt;p&gt;It's very important to show what you have tried to do for a couple of reasons.&lt;/p&gt;

&lt;p&gt;First, it's more motivating for someone to help you when they know you're not just asking someone to do the work for you but that you've actually tried solving the issue yourself and are genuinely stuck.&lt;/p&gt;

&lt;p&gt;As someone who teaches a lot, I try to avoid giving direct answers as much as possible and rather try to help people learn how to figure it out themselves and how to find the right information. That's impossible if you're only looking for direct complete answers.&lt;/p&gt;

&lt;p&gt;Secondly, it can be really difficult to give programming advice to a specific problem if the person giving advice doesn't know what your code looks like. This is especially important when you have an error or something's functioning incorrectly.&lt;/p&gt;

&lt;p&gt;There are different ways to share the code. For HTML/CSS/Javascript stuff, you can use &lt;a href="https://codepen.io/"&gt;Codepen&lt;/a&gt; or for more complex frontend code, use &lt;a href="https://codesandbox.io/"&gt;Codesandbox&lt;/a&gt;. The big benefit of these two is that you can run the code and see the result. Most problems are not solved by staring at the code and returning the answer but often require some tinkering and these platforms are great for that.&lt;/p&gt;

&lt;p&gt;For other code, there are tools like &lt;a href="https://pastebin.com/"&gt;Pastebin&lt;/a&gt; which allow you to paste anything, choose a syntax highlight and click submit. Or if your code is short, you can send it directly in Discord/Slack. For that, here are couple of tricks to make it easier for your helper to help you:&lt;/p&gt;

&lt;p&gt;To share code in these platforms, wrap it around three backticks:&lt;/p&gt;

&lt;pre&gt;

```
// your code here
```

&lt;/pre&gt;

&lt;p&gt;On Discord, you can also add a language definition after the first three ticks to add syntax highlighting:&lt;/p&gt;

&lt;pre&gt;

```js
// javascript code here gets highlighted
```

&lt;/pre&gt;

&lt;p&gt;On Slack, you can create a code snippet from the lightning menu which allows you to add syntax highlighting:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YvlJdSBV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/21td3xm9827wnrd7xjlg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YvlJdSBV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/21td3xm9827wnrd7xjlg.jpg" alt="Slack code snippet modal" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slack's Code Snippet modal with example Python code&lt;br&gt;
(thanks Juri for pointing this feature out)&lt;br&gt;
Reading code that is not shared inside these code blocks (created by triple backticks) is very difficult to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Create a Minimal, Complete, Reproducible Example
&lt;/h2&gt;

&lt;p&gt;Codebases are often large and complex and it's not beneficial to share all your code that exists.&lt;/p&gt;

&lt;p&gt;Quoting from &lt;a href="https://stackoverflow.com/help/minimal-reproducible-example"&gt;a great instruction post in Stack Overflow&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your code examples should be…&lt;/p&gt;

&lt;p&gt;…Minimal – Use as little code as possible that still produces the same problem&lt;/p&gt;

&lt;p&gt;…Complete – Provide all parts someone else needs to reproduce your problem in the question itself&lt;/p&gt;

&lt;p&gt;…Reproducible – Test the code you're about to provide to make sure it reproduces the problem&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I won't copy or rephrase everything from that post but rather advice you to read it with thought.&lt;/p&gt;

&lt;p&gt;This is one of those things where I think we need to be most lenient, especially with new developers. If you're new to software development and your code doesn't work, it's very likely you don't know why (that's why you're asking, after all) and it can be very difficult to create an example like that.&lt;/p&gt;

&lt;p&gt;But reading it through and understanding why it's a positive thing to thrive towards can help you a long way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;A good question is a combination of all the above: asking directly to get things started, stating what you're aiming to achieve, sharing the errors you're encountering, sharing the code is causing you these problems and making the shared examples minimal, complete and reproducible.&lt;/p&gt;

&lt;p&gt;By putting these advice into work, I can guarantee that your experience with seeking help will get much better. A side effect might be that you get less discussion going (less people asking for more info) but you also save your and other people's time when they don't have to ask a lot of things only to find out that they cannot help you that time.&lt;/p&gt;

&lt;p&gt;And finally, remember to say thanks when you get help. I didn't add it as its own point since I've never had the issue of people not saying thanks. But if you have gotten help and didn't say thanks – do so in the future.&lt;/p&gt;

&lt;p&gt;I know asking help can be a daunting task: exposing your imperfection to strangers can be scary. Despite making this long list of things you should do, I do want to encourage you to ask even if you are not perfect in all of these. This post is aimed mainly to provide you with some new ideas that you might not have thought about or known about.&lt;/p&gt;

&lt;p&gt;I wish you get help for your technical problems!&lt;/p&gt;

&lt;p&gt;(PS. If you're an experienced developer, you might notice that all of these translate very nicely into writing good bug reports. That's because a bug report is essentially asking for help in fixing something.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>5 key learnings from running a developer newsletter</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Thu, 30 Jan 2020 12:32:25 +0000</pubDate>
      <link>https://dev.to/hamatti/5-key-learnings-from-running-a-developer-newsletter-5a8g</link>
      <guid>https://dev.to/hamatti/5-key-learnings-from-running-a-developer-newsletter-5a8g</guid>
      <description>&lt;p&gt;For quite a while, I've been entertaining the idea of starting a developer newsletter. Personally I'm a big fan of newsletters and as I've been building communities for a while already, doing one of my own was a thing I wanted to try out. In August of last year, a great opportunity to do that arose and I took on the challenge.&lt;/p&gt;

&lt;p&gt;I started building &lt;a href="https://hello.futurice.com/dev-breakfast"&gt;Dev Breakfast&lt;/a&gt; in July and released the first issue in August. It's a monthly email into which I curate interesting articles, blog posts, talks and tools that are interesting to software developers. Our company has 300 developers who love to discuss topics in company internal Slack and I wanted to bring up those interesting articles discussed also to others.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Have a focused topic
&lt;/h2&gt;

&lt;p&gt;When I started building this newsletter with our team, the first question that needed an answer was the focus and topic. We decided to go with software development in general since we are interested in serving a larger audience. &lt;/p&gt;

&lt;p&gt;Software development is a huge field and right now I feel like we should have been bit more bold to go for a more narrow niche. It's difficult to build an audience for any content if it's all over the place and it's easier also to curate and author content the smaller the topic is.&lt;/p&gt;

&lt;p&gt;One way that we're tackling this moving forward is that starting from February, each month will have a theme based on interests of my colleagues who will start to curate the content.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Start with minimum viable newsletter
&lt;/h2&gt;

&lt;p&gt;There's a lot to do and optimize in newsletter publishing. You'll learn that as you go so my suggestion is to start by doing something and regularly reflecting on how it's working. Pick up a platform (like &lt;a href="https://mailchimp.com/"&gt;Mailchimp&lt;/a&gt; or &lt;a href="https://www.hubspot.com/"&gt;Hubspot&lt;/a&gt;, build a list and make a really simple signup page.&lt;/p&gt;

&lt;p&gt;After that, do marketing: share it in social media, your blog, your talks or just ask your friends and colleagues to sign up. Once you have people, start publishing and learn on the way.&lt;/p&gt;

&lt;p&gt;Our process of building the newsletter has evolved a lot during the first seven months. You'll learn what works, what's easy, what's hard and what pain points you encounter as you build your newsletter and grow your audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Focus on your readers
&lt;/h2&gt;

&lt;p&gt;Whether you're running your newsletter for your business, your personal brand, a non-profit or any other reason, put your needs on the backseat. Put every bit of focus on the people reading the newsletter (or potential subscribers from your audience).&lt;/p&gt;

&lt;p&gt;If your newsletter doesn't provide content that is interesting to people, you're wasting your time. Platforms like Mailchimp and Hubspot offer great analytics so you can see how many people open your emails, which links they click and if you're linking to your own content, using &lt;a href="https://blog.hubspot.com/marketing/what-are-utm-tracking-codes-ht"&gt;UTM tags&lt;/a&gt; allows you to analyze what your readers are doing after they reach your site.&lt;/p&gt;

&lt;p&gt;The number of subscribers is not a valuable metric so don't look at that too much. Pay more attention on how many people actually read your emails and interact with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Make it easy for people to unsubscribe
&lt;/h2&gt;

&lt;p&gt;Some marketing emails make this &lt;strong&gt;really&lt;/strong&gt; difficult and it's just silly. Many platforms will charge you based on the amount of emails sent so having people not interested in your emails to unsubscribe serves you well. Also having subscribers on your list who never open your emails doesn't serve any purpose for anyone.&lt;/p&gt;

&lt;p&gt;So don't try to hide the unsubscribe links. If you use existing services to run your list, they already have good setups for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Do things that you enjoy
&lt;/h2&gt;

&lt;p&gt;While your readers should be the main focus, running a newsletter where creating the content is a chore that you hate to do will not last. So pick a theme that you're excited about, use a format that makes you happy. I do a link curation but you could also write original content or spark discussion.&lt;/p&gt;

&lt;p&gt;When you enjoy the process and the content, it becomes visible to your users and the quality of your newsletter will improve. Don't be scared to experiment, change things around and see what works. Finding a good balance between things that excite you and things that are interesting to your audience is not an easy task but it's where we all should aim for.&lt;/p&gt;

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

&lt;p&gt;If you're interested in learning about interesting new things in the software development industry, check out &lt;a href="https://hello.futurice.com/dev-breakfast"&gt;Dev Breakfast&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I'd love to hear your opinions on both the content of the newsletter as well as the ideas presented in this post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image credit: Photo by &lt;a href="https://unsplash.com/@yannikm?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Yannik Mika&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/newsletter?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>newsletter</category>
      <category>community</category>
    </item>
    <item>
      <title>My journey in diversity and inclusion in tech</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Wed, 28 Aug 2019 18:42:59 +0000</pubDate>
      <link>https://dev.to/hamatti/my-journey-in-diversity-and-inclusion-in-tech-81b</link>
      <guid>https://dev.to/hamatti/my-journey-in-diversity-and-inclusion-in-tech-81b</guid>
      <description>&lt;p&gt;Some people who know me personally well and have been involved in my professional career for the past 4 years, know that I'm very passionate and increasingly vocal about diversity and inclusion in tech. Others, who have known me for longer, might see me as a hypocrite.&lt;/p&gt;

&lt;p&gt;I haven't always been so passionate about it and I want to share my story. It's not an easy one to share and quite frankly, publishing this post is little bit nervewrecking. But it's so much less that than what other people have to endure sometimes in this industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;Let me tell you little bit about me before 2014. I grew up little bit socially clueless, spending8 most of my time in online forums and IRC channels. Many aspects of my social behaviour were affected by culture where saying things like "There are no women in Internet" was a norm or the dominant way of thinking was that men were superior to women. I learned that culture.&lt;/p&gt;

&lt;p&gt;That obviously leaked into my real life. I would like to say I made inappropriate jokes but there was nothing joke-like there. I was an asshole. I didn't realize it back then. For me, it's was just witty banter. I can't remember if people pointed it out. Maybe they did and I just shrugged it off. Maybe they didn't because it's hard to say about those things that to a friend.&lt;/p&gt;

&lt;p&gt;I have always been very competitive in everything in life. In 2014, I moved to San Francisco to work in a small startup. In March, we hired our first developer who was a woman. I made stupid remarks in a group chat of some fellow startup people, something along the lines of "now I need to really start focusing on my work so I don't lose to her".&lt;/p&gt;

&lt;p&gt;Then the best thing happened. &lt;strong&gt;I got called out for it&lt;/strong&gt;. I didn't realize it then well enough. I tried to defend my position and explain my way out of it. I wasn't able to see how my thinking and actions could affect things outside me.&lt;/p&gt;

&lt;p&gt;None of my bullshit behaviour back then is excusable by anything.&lt;/p&gt;

&lt;p&gt;Living in San Francisco and being in the center of so much more discussion about diversity and inclusion problems in tech slowly started to make me understand things from another angle. And then, I started to do my best to make things better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why diversity and inclusion matter?
&lt;/h2&gt;

&lt;p&gt;There are many reasons to promote diversity and inclusion in technology industry. There are business reasons and studies that say how diverse teams are better performing ones. For me, one of the reasons (other than being a decent human being) is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are building products, tools and services for the humankind. There are so many different kinds of people in the world that if everyone in the team building these tools are too similar, we fail to build services that take into account different kind of people.&lt;/p&gt;

&lt;p&gt;Maybe 20 years ago, technology was an &lt;em&gt;opt-in&lt;/em&gt; - you could choose to use and interact with it. 2019, that's no longer the case. In many societies in the world, it's very difficult to even be a member of the society if you are not computer literate.&lt;/p&gt;

&lt;p&gt;That's why I think it's crucially important that we bring in people from different backgrounds, different life situations (I think career-changers into tech is a wonderful thing) and different ways of seeing the world.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You might not agree with the above and that's perfectly fine. I don't claim to know that I'm right. But I want to be clear on why it matters to me.&lt;/p&gt;

&lt;p&gt;I also keep fighting because I've been to the other side. I feel the pain in me when I see people treat others inappropriately. And I keep fighting because I hope that while I can never make my past actions acceptable, I can hopefully make the future a better place for many people.&lt;/p&gt;

&lt;p&gt;As an industry, we have so much work to do. And it all starts by realizing and accepting that it's not about "us good people" and "them bad people". Even the good companies, good events and good communities have issues. We cannot turn a blind eye on them. We need to all strive to make our culture more accessible and more inclusive to different people.&lt;/p&gt;

&lt;p&gt;I still have lot to learn and lot of work to do in my own networks. One of the developer communities I ran, Turku &amp;lt;3 Frontend, is quite homologous because I have been bringing in people from my limited networks. I want to expand those networks and make sure that we are a community that is a great platform for everyone to learn and grow, not just people who happen to be like me and hang out with me.&lt;/p&gt;

&lt;p&gt;And most importantly, I need to also be better at treating people with the respect that they deserve and to make sure that whenever mistakes are made, that I own up to them. Because I know I will make mistakes.&lt;/p&gt;

</description>
      <category>diversity</category>
      <category>inclusion</category>
    </item>
    <item>
      <title>Why I love using command line interface?</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Sat, 27 Jul 2019 07:51:16 +0000</pubDate>
      <link>https://dev.to/hamatti/why-i-love-using-command-line-interface-3558</link>
      <guid>https://dev.to/hamatti/why-i-love-using-command-line-interface-3558</guid>
      <description>&lt;p&gt;My Saturday started by waking up to a Twitter thread I was tagged into:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1154988415244472321-813" src="https://platform.twitter.com/embed/Tweet.html?id=1154988415244472321"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1154988415244472321-813');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1154988415244472321&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Tweeting out my answers, I started to come up with more and more reasons, so I figured I'll also document them down here in my blog and open up each point a little bit in detail. &lt;/p&gt;

&lt;h2&gt;
  
  
  1) You can replicate commands
&lt;/h2&gt;

&lt;p&gt;The first benefit that came to my mind when I started thinking about this, was replicating commands. If I use a GUI, to replicate some complex action, I need to do a lot of clicking around, whereas using command line, I can run the command with one copy-paste command (or using history feature) as many times as I want without having to do any more work.&lt;/p&gt;

&lt;p&gt;Replicating commands provides a way to upfront the amount of work that needs to be done. Sometimes it's bit more but quite often, if you run the command more than once, you start winning time and effort.&lt;/p&gt;

&lt;p&gt;Replication has other benefits too. Let's say I want to download 100 Youtube videos:&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a GUI
&lt;/h3&gt;

&lt;p&gt;With a GUI (of an imaginary downloader software), I have to copy-paste the urls one at the time, click Download, wait and repeat.&lt;/p&gt;

&lt;p&gt;Oh wait, what if I realize that the application downloaded all videos with default 240p quality? Maybe I go to settings, change a quality setting to 1080p and start pasting in those URLs again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a CLI
&lt;/h3&gt;

&lt;p&gt;With a CLI, I can dump all 100 URLs to a file and run a download command for each line in that file. With one command, I just downloaded 100 files.&lt;/p&gt;

&lt;p&gt;And if I need to change the quality option, I can just add an option flag to my loop, rerun that one command and wait as my videos are downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) History
&lt;/h2&gt;

&lt;p&gt;Second one of my favorite aspects about command line interfaces is that I get access to history of commands. I can easily repeat the previous command or search for any command I have run before.&lt;/p&gt;

&lt;p&gt;With most GUI applications, I have used, this is not possible. Some photo or video editing software has repeatable history but most software doesn't.&lt;/p&gt;

&lt;p&gt;I personally use &lt;a href="https://dev.to/hamatti/better-bash-history-search-with-mcfly-3kck"&gt;mcfly&lt;/a&gt; as my bash history search app. With it, I can quickly find and re-run commands that I have done before.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Chain commands
&lt;/h2&gt;

&lt;p&gt;If a CLI application is designed nicely, it takes input from stdin and outputs to stdout. Of course not all CLI apps do this and for some apps it doesn't even make sense really.&lt;/p&gt;

&lt;p&gt;But many do. And that design allows for chaining commands. You can take your toolbox of bash tools for example and mix-and-match them however you want.&lt;/p&gt;

&lt;p&gt;For example, let's say we are interested in Pokemon TCG cards (if you've been reading my blog, it should be quite obvious I'm a huge Pokemon fan). We want to know every unique card name that includes 'Charizard':&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.pokemontcg.io/v1/cards?name&lt;span class="o"&gt;=&lt;/span&gt;Charizard | jq &lt;span class="s1"&gt;'.cards | .[] | .name'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we curl'd an API, which returns a JSON into the stdout. We then pass that JSON to &lt;a href="https://shapeshed.com/jq-json/" rel="noopener noreferrer"&gt;jq&lt;/a&gt;, that reads JSON from stdin and allows us to do operations on it. In this case, we access the &lt;code&gt;cards&lt;/code&gt; property and get all the &lt;code&gt;name&lt;/code&gt; properties. Once again, we output that to stdout so that &lt;code&gt;sort&lt;/code&gt; can read it, sort alphabetically and finally &lt;code&gt;uniq&lt;/code&gt; removes duplicates.&lt;/p&gt;

&lt;p&gt;Some GUI software aimed for interacting with HTTP calls allows this kind of operation built-in. But the beautiful thing with the command line is that we can combine any tools we want. You don't have to plan for every possible use case when building the tool: as long as you read from stdin and print to stdout, your CLI app can be combined with any other.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Programmability
&lt;/h2&gt;

&lt;p&gt;An extension of the replicability in #1 is that we can alter conditions and parameters of calls programmatically. Let's expand on the downloading Youtube video examples from #1.&lt;/p&gt;

&lt;p&gt;Maybe this time we get a mix of different sources, not just Youtube. You can use basic conditionals within your script to call different applications based on the source or filetype.&lt;/p&gt;

&lt;p&gt;Maybe you pass Youtube links to Youtube downloader, image and txt file links to curl or wget and some other proprietary formats to specific software that allows extracting the information.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Share commands
&lt;/h2&gt;

&lt;p&gt;How many times have you helped someone remotely to use their computer for something? Maybe it's a friend who needs to install some software or maybe it's a colleague trying to setup their development environment. Or maybe you're writing a blog post teaching people how to use a software.&lt;/p&gt;

&lt;p&gt;With GUI apps, it's often bit vague "click on the blue button in the upper right corner that says Scan" verbal instructions or screenshots/screencasts. The instructions grow quite long and take a disproportional amount of time to write down.&lt;/p&gt;

&lt;p&gt;With CLI apps, you can just copy-paste the commands and send them to the one in need or add them to your blog. Please be careful though: running commands that someone else tells you to run is very dangerous. You should never blindly run commands anyone tells you to run without understanding what they do. I have seen some havoc that has been done to systems by misinformed users. &lt;/p&gt;

&lt;h2&gt;
  
  
  6) Automation / scheduling with cron
&lt;/h2&gt;

&lt;p&gt;The universality of these command line tools means that you don't have to build every feature to every application. If we continue with our example of downloading Youtube videos:&lt;/p&gt;

&lt;p&gt;You know that your favorite creator uploads a new video every Monday at 10.00. You could set yourself a reminder to download it with your GUI app manually or hope to find a GUI app that downloads Youtube videos &lt;strong&gt;and&lt;/strong&gt; allows scheduling.&lt;/p&gt;

&lt;p&gt;Or you can use the CLI downloader and combine that with &lt;a href="https://en.wikipedia.org/wiki/Cron" rel="noopener noreferrer"&gt;cron&lt;/a&gt;. Now you can use one app to find the URL to the latest video, feed that to the downloader and schedule it all to happen every Monday at 10.05.&lt;/p&gt;

&lt;p&gt;Cron is great for maintenance tasks that are essentially the same task run over and over again on regular intervals. Like doing backups, cleaning up some upload folders, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  7) Less change in interface
&lt;/h2&gt;

&lt;p&gt;I left this one for last because it's a bit different and less universally true. I have noticed that GUI applications quite more often make changes to their UIs than CLI applications to their API. That makes using history and written-down instructions much better at lasting time.&lt;/p&gt;

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

&lt;p&gt;In which situations you prefer CLI over GUI and why? Let me know in the comments and I can hopefully learn new tricks.&lt;/p&gt;




&lt;p&gt;I am starting a Youtube channel &lt;a href="https://www.youtube.com/channel/UCFTR0aya8Bhzf3WIT4VwLeA" rel="noopener noreferrer"&gt;Juhis Talks Tech&lt;/a&gt; to expand my knowledge sharing beyond these blog posts. The first episode will be out soon and in that, I'll be showing you how to debug Javascript effectively using my favorite tools and techniques.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>ux</category>
      <category>commandline</category>
    </item>
    <item>
      <title>Teaser: Twitch Stream Series on Software Development</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Tue, 23 Jul 2019 06:59:32 +0000</pubDate>
      <link>https://dev.to/hamatti/teaser-twitch-stream-series-on-software-development-3e1g</link>
      <guid>https://dev.to/hamatti/teaser-twitch-stream-series-on-software-development-3e1g</guid>
      <description>&lt;p&gt;Do you have a basic understanding and skills to write Python and/or Javascript but would like to get more into how to build full-stack web applications? Don't worry, I'm here to help!&lt;/p&gt;

&lt;p&gt;Starting in September 28th, I'll be doing Saturday streaming in Twitch to help you learn how to build a real web application with Django in the backend and React in the frontend. We'll build a single page app (SPA) for tracking personal expenses that communicates between React and Django using a REST API.&lt;/p&gt;




&lt;p&gt;You can find my streams at &lt;a href="https://twitch.tv/hamatti"&gt;twitch.tv/hamatti&lt;/a&gt; and my other upcoming programming videos in &lt;a href="https://www.youtube.com/channel/UCFTR0aya8Bhzf3WIT4VwLeA"&gt;Juhis Talks Tech Youtube channel&lt;/a&gt;. Clicking a Follow on both will make sure you won't miss the videos.&lt;/p&gt;

&lt;p&gt;I've been teaching programming for years but now I want to take it into the next level and start learning filming and editing videos to share my knowledge to an even larger audience.&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>django</category>
      <category>react</category>
    </item>
    <item>
      <title>What programming skills are you learning right now?</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Fri, 19 Jul 2019 16:25:13 +0000</pubDate>
      <link>https://dev.to/hamatti/what-programming-skills-are-you-learning-right-now-4b18</link>
      <guid>https://dev.to/hamatti/what-programming-skills-are-you-learning-right-now-4b18</guid>
      <description>&lt;p&gt;I guess the people on this site are quite eager in learning new things and improving. I'd love to know what skills (maybe it's building or consuming REST APIs, learning React Hooks or SQL) you are learning right now.&lt;/p&gt;

&lt;p&gt;In the comment section, let's work together to help each other learn these things by sharing good ideas, articles, learning materials and so on.&lt;/p&gt;

&lt;p&gt;I'm currently working on learning how Electron works and how sharing data between the main thread and renderers work. Mostly by trial-and-error.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
