<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Mike Zornek</title>
    <link>https://mikezornek.com/tags/software-craft/</link>
    <description>Recent content in software-craft on Mike Zornek</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>mike@mikezornek.com (Mike Zornek)</managingEditor>
    <webMaster>mike@mikezornek.com (Mike Zornek)</webMaster>
    <lastBuildDate>Wed, 29 Jan 2025 08:46:05 -0500</lastBuildDate>
    
	<atom:link href="https://mikezornek.com/tags/software-craft/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>A Few Good Memes</title>
      <link>https://mikezornek.com/posts/2025/1/a-few-good-memes/</link>
      <pubDate>Wed, 29 Jan 2025 08:46:05 -0500</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2025/1/a-few-good-memes/</guid>
      <description>&lt;figure&gt;
&lt;img src=&#34;code-reviews-too-harsh.png&#34; alt=&#34;A scene from the movie A Few Good Men. Base Commander Colonel Nathan Jessep is on the stand. The meme reads: CODE REVIEWS TOO HARSH? / YOU WANT ME ON THAT WALL, YOU NEED ME ON THAT WALL.&#34; data-action=&#34;zoom&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Yesterday I took to &lt;code&gt;r/ProgrammerHumor&lt;/code&gt; to reply to &lt;a href=&#34;https://www.reddit.com/r/ProgrammerHumor/comments/1ib4ifc/titleisdealingwithatoxicsenior/&#34;&gt;this post about code review&lt;/a&gt;. I used a meme I &lt;a href=&#34;https://jawns.club/@zorn/113194431261362116&#34;&gt;crafted back in September&lt;/a&gt; and posted this meme as I was preparing for quarterly performance review season. It since has gotten some replies that have me laughing out loud. Recording for prosperity.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.reddit.com/r/ProgrammerHumor/comments/1ich83t/comment/m9rixfv/&#34;&gt;Intelligent-Touch936 writes&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We live in a world that has code, and that code has to be perfect. Who&amp;rsquo;s going to ensure that? You? You, with your lenient comments? I have a greater responsibility than you can possibly fathom. You weep for your feelings and you curse the review process; you have that luxury. You have the luxury of not knowing what I know: that my critique, while harsh, probably saved the project. And my existence, while meticulous and unkind, brings us closer to a flawless system. You want me to be nicer? You can&amp;rsquo;t handle the nicest! Because deep down in places you don&amp;rsquo;t talk about at stand-ups, you want me on that review. You need me on that review.&lt;/p&gt;
&lt;p&gt;We use words like &amp;ldquo;optimize,&amp;rdquo; &amp;ldquo;refactor,&amp;rdquo; &amp;ldquo;debug.&amp;rdquo; These words are the backbone of our development process. I have neither the time nor the inclination to explain myself to someone who rises and sleeps under the very quality code that I provide and then questions the manner in which I provide it. I&amp;rsquo;d rather you just said &amp;ldquo;thank you&amp;rdquo; and went on your way. Otherwise, I suggest you grab an IDE and get to work. Either way, I don&amp;rsquo;t give a damn about what you think you&amp;rsquo;re entitled to!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prosecutor:&lt;/strong&gt; Did you force push main?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Defendant:&lt;/strong&gt; I did what I needed to do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prosecutor:&lt;/strong&gt; DID YOU FORCE PUSH MAIN?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Defendant:&lt;/strong&gt; YOU&amp;rsquo;RE GODDAMNED RIGHT I DID!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Personal Elixir Code Aesthetics</title>
      <link>https://mikezornek.com/posts/2024/9/elixir-code-aesthetic/</link>
      <pubDate>Sun, 29 Sep 2024 20:25:46 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2024/9/elixir-code-aesthetic/</guid>
      <description>&lt;p&gt;With my side project &lt;a href=&#34;https://github.com/zorn/flick&#34;&gt;Flick&lt;/a&gt; hitting an MVP milestone and inspired by some conversations during &lt;a href=&#34;https://elixirbookclub.github.io/website/&#34;&gt;Elixir Book Club&lt;/a&gt;, I thought I&amp;rsquo;d take a moment to document some code aesthetic choices I made in this project.&lt;/p&gt;
&lt;p&gt;The order below is not ranked in importance. In fact most of this is nitpicky, but still my preference.&lt;/p&gt;
&lt;h2 id=&#34;whitespace-between-import-and-alias&#34;&gt;Whitespace between import and alias.&lt;/h2&gt;
&lt;h2 id=&#34;alphabetically-ordered-alias-declarations&#34;&gt;Alphabetically ordered alias declarations.&lt;/h2&gt;
&lt;h2 id=&#34;avoiding-multi-alias-declarations&#34;&gt;Avoiding multi-alias declarations.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# lib/flick/ranked_voting.ex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ecto.Query&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting.Ballot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting.Vote&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.Repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Whitespace should be done with intention to separate distinct concepts; and for me, &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;alias&lt;/code&gt; are distinct concepts.&lt;/p&gt;
&lt;p&gt;I also list my &lt;code&gt;alias&lt;/code&gt; declarations in alphabetical order, enforced via &lt;a href=&#34;https://hexdocs.pm/credo/Credo.Check.Readability.AliasOrder.html&#34;&gt;&lt;code&gt;AliasOrder&lt;/code&gt;&lt;/a&gt; and use a preferred order across &lt;code&gt;use&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;alias&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; via &lt;a href=&#34;https://hexdocs.pm/credo/Credo.Check.Readability.StrictModuleLayout.html&#34;&gt;&lt;code&gt;StrictModuleLayout&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I prefer to avoid multi-&lt;code&gt;alias&lt;/code&gt; declarations like &lt;code&gt;alias Flick.RankedVoting.{Ballot, Vote}&lt;/code&gt; since it makes searching the code base for module names harder to do. This is enforced with &lt;a href=&#34;https://hexdocs.pm/credo/Credo.Check.Readability.MultiAlias.html&#34;&gt;&lt;code&gt;MultiAlias&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;generally-prefer-multiline-doend-functions&#34;&gt;(Generally) prefer multiline do/end functions.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;defp&lt;/span&gt; page_title(&lt;span style=&#34;color:#e6db74&#34;&gt;:edit&lt;/span&gt;), &lt;span style=&#34;color:#e6db74&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Edit Ballot&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;defp&lt;/span&gt; page_title(_), &lt;span style=&#34;color:#e6db74&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Create a Ballot&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unless I can express a group of functions in a simple stack (like the above code) I generally prefer multiline &lt;code&gt;do/end&lt;/code&gt; function declarations. One reason for this preference is that my code editor can collapse the whole module in a nice way, making during exploration easier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This could be one line, but I prefer multiline do/end.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; get_ballot!(ballot_id) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;Repo&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get!(&lt;span style=&#34;color:#a6e22e&#34;&gt;Ballot&lt;/span&gt;, ballot_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;use-consistent-dsl-layout-in-test-modules&#34;&gt;Use consistent DSL layout in test modules.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# test/flick/ranked_voting_test.exs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;describe &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update_ballot/1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  test &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;success: updates a ballot title and questions&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  test &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure: `question_title` is required&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  test &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure: can not update a published ballot&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test files can generally end up 2 or 3 times the line count of the module under test. To help keep this code organized and easy to navigate I use a style where I will list the function under test using &lt;code&gt;describe&lt;/code&gt; and then various &lt;code&gt;success&lt;/code&gt; and &lt;code&gt;failure&lt;/code&gt; expectations in each &lt;code&gt;test&lt;/code&gt;. For functions like &lt;code&gt;list_ballots/1&lt;/code&gt; that can&amp;rsquo;t fail, one might drop the &lt;code&gt;success&lt;/code&gt; label, but looking at my code as it stands today, it looks like I kept it. 🤷‍♂️&lt;/p&gt;
&lt;p&gt;I have far less consistency with my LiveView tests. Sometimes the &lt;code&gt;describe&lt;/code&gt; &lt;a href=&#34;https://github.com/zorn/flick/blob/main/test/flick_web/live/ballots/editor_live_test.exs&#34;&gt;breaks out new vs edit logic&lt;/a&gt;, other times it &lt;a href=&#34;https://github.com/zorn/flick/blob/main/test/flick_web/live/ballots/index_live_test.exs&#34;&gt;breaks out with or without authentication&lt;/a&gt; paths. I&amp;rsquo;m still evolving this and welcome ideas and good examples.&lt;/p&gt;
&lt;h2 id=&#34;invest-in-test-fixtures&#34;&gt;Invest in test fixtures&lt;/h2&gt;
&lt;p&gt;Arrange, Act, Assert. To help keep your arrange logic neat and tidy, invest in good test fixture tooling. These test fixtures should provide functions for entity creation in your test files as well as the known list of argument defaults (for tests that need to do something more custom but do not want to be burdened with a complete understanding of every argument).&lt;/p&gt;
&lt;p&gt;These fixtures should use the actual domain context paths for creation and not raw SQL injection unless absolutely needed for performance or edge cases.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# test/support/fixtures/ballot_fixture.ex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;defmodule&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Support.Fixtures.BallotFixture&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@moduledoc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Provides functions to allows tests to easily create and stage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  `Flick.RankedVoting.Ballot` entities for testing.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting.Ballot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@doc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Returns a map of valid attributes for a `Flick.RankedVoting.Ballot` entity,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  allowing for the passed in attributes to override defaults.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@spec&lt;/span&gt; valid_ballot_attributes(map()) &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; map()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; valid_ballot_attributes(attrs \\ %{}) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Enum&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;into(attrs, %{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;question_title&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;What day should have dinner?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;possible_answers&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Monday, Tuesday, Wednesday, Thursday, Friday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;url_slug&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dinner-day-&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;System&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;unique_integer()&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;published_at&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@doc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Creates a `Flick.RankedVoting.Ballot` entity in the `Flick.Repo` for the passed in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  optional attributes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  When not provided, all required attributes will be generated.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@spec&lt;/span&gt; ballot_fixture(map()) &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ballot&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; ballot_fixture(attrs \\ %{}) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    attrs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; valid_ballot_attributes(attrs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:ok&lt;/span&gt;, ballot} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;create_ballot(attrs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ballot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@doc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Creates a `Flick.RankedVoting.Ballot` entity in the `Flick.Repo` for the passed in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  optional attributes and then publishes the ballot.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  When not provided, all required attributes will be generated.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@spec&lt;/span&gt; published_ballot_fixture(map()) &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ballot&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; published_ballot_fixture(attrs \\ %{}) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    attrs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; valid_ballot_attributes(attrs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:ok&lt;/span&gt;, ballot} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;create_ballot(attrs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:ok&lt;/span&gt;, published_ballot} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;publish_ballot(ballot)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    published_ballot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aside: I hate how the typespecs here use &lt;code&gt;map()&lt;/code&gt; for the attribute map. I want to make that more detailed in the future, see &lt;a href=&#34;https://github.com/zorn/flick/issues/4&#34;&gt;issue #4&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;use-tiny_maps-to-save-horizontal-line-space-in-tests&#34;&gt;Use tiny_maps to save horizontal line space in tests.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;success: submitting valid form creates ballot and redirects&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;~M{view, ballot}&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When composing my test descriptions, I like to get the &lt;code&gt;test &amp;quot;...&amp;quot; do&lt;/code&gt; on a single line. To help achieve that, I use the &lt;a href=&#34;https://github.com/abshierjoel/tiny_maps&#34;&gt;tiny_maps&lt;/a&gt; library to help me express repetitive argument maps with a more concise syntax: &lt;code&gt;~M{view, ballot}&lt;/code&gt; expands to &lt;code&gt;%{view: view, ballot: ballot}&lt;/code&gt;. I generally limit this syntax sugar to test files but would not be against using it in the main source in the future.&lt;/p&gt;
&lt;h2 id=&#34;compose-code-to-prefer-clean-line-breaks&#34;&gt;Compose code to prefer clean line breaks&lt;/h2&gt;
&lt;p&gt;I love that Elixir ships with an opinionated formatter. However, even with the formatter, you still have a lot of influence on how your code is composed. I prefer it greatly when expressions are clean one-liners or otherwise avoid excessive indentation when breaking up complex terms.&lt;/p&gt;
&lt;p&gt;To help explain, let me walk you through a test from Flick.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;success: submitting valid form creates ballot and redirects&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;~M{view}&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  payload &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; %{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;question_title&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;What&amp;#39;s your favorite color?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;possible_answers&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Red, Green, Blue&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;url_slug&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;favorite-color&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    view
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; form(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;ballot&lt;/span&gt;: payload)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; render_submit()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Assert upon submit the page redirects, and the ballot was created.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  assert {&lt;span style=&#34;color:#e6db74&#34;&gt;:error&lt;/span&gt;, {&lt;span style=&#34;color:#e6db74&#34;&gt;:redirect&lt;/span&gt;, %{&lt;span style=&#34;color:#e6db74&#34;&gt;to&lt;/span&gt;: redirect_target}}} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; response
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  assert &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/ballot/favorite-color/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; secret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; redirect_target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  assert %&lt;span style=&#34;color:#a6e22e&#34;&gt;Ballot&lt;/span&gt;{} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RankedVoting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_ballot_by_url_slug_and_secret!(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;favorite-color&amp;#34;&lt;/span&gt;, secret)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, let&amp;rsquo;s take note that &lt;code&gt;response&lt;/code&gt; is captured in its own line group. Technically, you could compose &lt;code&gt;render_submit()&lt;/code&gt; to happen on the same line as &lt;code&gt;assert&lt;/code&gt;, but by capturing &lt;code&gt;response&lt;/code&gt; using its own line group, it helps separate the &lt;code&gt;act&lt;/code&gt; vs. &lt;code&gt;assert&lt;/code&gt; test concepts and avoids a very complex indentation variant.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# A complex multiline expression with lots of indentation, I am trying to avoid.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assert {&lt;span style=&#34;color:#e6db74&#34;&gt;:error&lt;/span&gt;, {&lt;span style=&#34;color:#e6db74&#34;&gt;:redirect&lt;/span&gt;, %{&lt;span style=&#34;color:#e6db74&#34;&gt;to&lt;/span&gt;: redirect_target}}} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         view
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; form(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;ballot&lt;/span&gt;: payload)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; render_submit()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, let&amp;rsquo;s look at the pipe feeding &lt;code&gt;response&lt;/code&gt;. You could compose the code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; form(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;ballot&lt;/span&gt;: %{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;question_title&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;What&amp;#39;s your favorite color?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;possible_answers&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Red, Green, Blue&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;url_slug&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;favorite-color&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; render_submit()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I dislike this composition since it breaks the pipe. By moving the &lt;code&gt;payload&lt;/code&gt; value assignment to its own line group, we end up with a cleaner pipe that, in my opinion, reads better.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;payload &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; %{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;question_title&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;What&amp;#39;s your favorite color?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;possible_answers&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Red, Green, Blue&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;url_slug&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;favorite-color&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; form(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;ballot&lt;/span&gt;: payload)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; render_submit()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;embrace-pipelines-with-custom-utility-functions&#34;&gt;Embrace pipelines with custom utility functions.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# lib/flick_web/live/ballots/index_live.ex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; mount(_params, _session, socket) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  socket
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; assign(&lt;span style=&#34;color:#e6db74&#34;&gt;:page_title&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Admin: Ballots&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; assign(&lt;span style=&#34;color:#e6db74&#34;&gt;:ballots&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Flick.RankedVoting&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;list_ballots())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; ok()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;defmodule&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FlickWeb.LiveViewPipes&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@moduledoc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  A collection of functions to help express pipes when processing live view responses.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Phoenix.LiveView.Socket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@spec&lt;/span&gt; ok(&lt;span style=&#34;color:#a6e22e&#34;&gt;Socket&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()) &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;:ok&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Socket&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; ok(%&lt;span style=&#34;color:#a6e22e&#34;&gt;Socket&lt;/span&gt;{} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; socket), &lt;span style=&#34;color:#e6db74&#34;&gt;do&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;:ok&lt;/span&gt;, socket}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@spec&lt;/span&gt; noreply(&lt;span style=&#34;color:#a6e22e&#34;&gt;Socket&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()) &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;:noreply&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Socket&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; noreply(%&lt;span style=&#34;color:#a6e22e&#34;&gt;Socket&lt;/span&gt;{} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; socket), &lt;span style=&#34;color:#e6db74&#34;&gt;do&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;:noreply&lt;/span&gt;, socket}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Many LiveView functions require tuple return values like &lt;code&gt;{:ok, socket}&lt;/code&gt; or &lt;code&gt;{:noreply, socket}&lt;/code&gt;. To help allow call sites to be composed as a single pipeline, I use some utility functions like &lt;code&gt;ok()&lt;/code&gt; and &lt;code&gt;noreply()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;be-consistent-between-module-names-and-filenames&#34;&gt;Be consistent between module names and filenames.&lt;/h2&gt;
&lt;p&gt;If I have a module called &lt;code&gt;Flick.RankedVoting.RankedAnswer&lt;/code&gt; it lives at the filepath &lt;code&gt;lib/flick/ranked_voting/ranked_answer.ex&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;While I have good consistency inside my core domain contexts, this consistency fails with various Phoenix things. For example, &lt;code&gt;FlickWeb.Ballots.EditorLive&lt;/code&gt; lives at &lt;code&gt;lib/flick_web/live/ballots/editor_live.ex&lt;/code&gt;. I dislike that Phoenix generators put these modules in a folder called &lt;code&gt;live&lt;/code&gt; that the module path does not express. I may fix that in the future.&lt;/p&gt;
&lt;p&gt;Related blog post: &lt;a href=&#34;https://mikezornek.com/posts/2024/9/liveview-modules-must-end-in-live/&#34;&gt;LiveView Modules Must End in &lt;code&gt;Live&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;write-professional-documentation&#34;&gt;Write professional documentation.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@doc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Publishes the given `Flick.RankedVoting.Ballot` entity.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Once a `Flick.RankedVoting.Ballot` entity is published, it can no longer be updated.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  Only a published ballot can be voted on.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All public functions, especially those that represent the formalized domain API for your system, should get documentation.&lt;/p&gt;
&lt;p&gt;Each documentation block should start with a single-line, terse summary, as those are used by &lt;code&gt;ex_doc&lt;/code&gt; and other developer tooling to summarize function indexes. Every so often, look at the collection of function summaries of a module and try to make them all use consistent phrasing like &amp;ldquo;Returns noun given thing&amp;hellip;&amp;rdquo; or &amp;ldquo;Raises &lt;code&gt;Blah&lt;/code&gt; when stuff&amp;hellip;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;If referencing another module, function, or callback, use backticks to help the documentation system generate hyperlinks.&lt;/p&gt;
&lt;p&gt;Use &lt;a href=&#34;https://github.com/stkb/Rewrap&#34;&gt;rewrap tools&lt;/a&gt; to hardwrap characters to 80 columns to help with GitHub diffing and more presentable Markdown.&lt;/p&gt;
&lt;h2 id=&#34;document-your-decisions&#34;&gt;Document your decisions.&lt;/h2&gt;
&lt;p&gt;Programming is all about tradeoffs. When making an intentional design or process decision with other valid approaches available, consider documenting what was considered and why you went with your approach. Your future self and peers will thank you.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve &lt;a href=&#34;https://github.com/zorn/flick/tree/main/docs/decisions&#34;&gt;documented some things&lt;/a&gt; related to timestamps, schema shape, and fixme/todo so far in Flick.&lt;/p&gt;
&lt;h2 id=&#34;make-sure-each-fixme-has-an-issue-url&#34;&gt;Make sure each FIXME has an issue URL.&lt;/h2&gt;
&lt;p&gt;Related to the above decisions, Flick &lt;a href=&#34;https://github.com/zorn/flick/blob/main/docs/decisions/3-fixme-and-todo.md&#34;&gt;allows FIXME comments&lt;/a&gt; but requests all &lt;code&gt;FIXME&lt;/code&gt;s include a link to a GitHub issue documenting the concern.&lt;/p&gt;
&lt;h2 id=&#34;avoid-abbreviations-and-prefer-expressiveness&#34;&gt;Avoid abbreviations and prefer expressiveness.&lt;/h2&gt;
&lt;p&gt;Prefer expressive variable names like &lt;code&gt;_ballot&lt;/code&gt; over &lt;code&gt;_&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Prefer expressive variable names like &lt;code&gt;ballot_params&lt;/code&gt; over &lt;code&gt;params&lt;/code&gt; when you think it helps improve clarity.&lt;/p&gt;
&lt;h2 id=&#34;words-matter&#34;&gt;Words matter.&lt;/h2&gt;
&lt;p&gt;Invest time in an expressive and consistent &lt;a href=&#34;https://github.com/zorn/flick/blob/main/docs/ubiquitous_language.md&#34;&gt;ubiquitous language&lt;/a&gt; for your project. Continue to edit it over time as the terms evolve.&lt;/p&gt;
&lt;p&gt;Find consistency in your project code regarding terms like &lt;code&gt;create&lt;/code&gt; vs. &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; vs. &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;submit&lt;/code&gt; vs. &lt;code&gt;save&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt; vs. &lt;code&gt;attributes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Do your best to align with existing Elixir community norms.&lt;/p&gt;
&lt;h2 id=&#34;craft-typespecs-to-express-your-domain&#34;&gt;Craft typespecs to express your domain.&lt;/h2&gt;
&lt;p&gt;All public functions should have a typespec. Private functions can also have typespecs, depending on whether they will help with code clarity or change confidence.&lt;/p&gt;
&lt;p&gt;Spend time and make those typespecs match the domain. For example, when accepting the identity of a &lt;code&gt;Ballot&lt;/code&gt; use the &lt;code&gt;Ballot.id()&lt;/code&gt; not a &lt;code&gt;Ecto.UUID.t()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# lib/flick/ranked_voting/ballot.ex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@type&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ecto.UUID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When building types for my main domain entities, I tend to build the main &lt;code&gt;t()&lt;/code&gt; around a persisted entity value that is brought into memory from a &lt;code&gt;Repo&lt;/code&gt;, and thus all post-creation values like &lt;code&gt;id&lt;/code&gt; or &lt;code&gt;updated_at&lt;/code&gt; are typed to their expected value, without the need for an &lt;code&gt;| nil&lt;/code&gt; addendum.&lt;/p&gt;
&lt;p&gt;To help write typespecs for non-persisted structs of this schema type, I make a &lt;code&gt;schema_t()&lt;/code&gt; variant.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@typedoc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  A type for a persisted `Flick.RankedVoting.Ballot` entity.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@type&lt;/span&gt; t &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;%&lt;/span&gt;__MODULE__{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;Ecto.UUID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;question_title&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;description&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t() &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;url_slug&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;secret&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;Ecto.UUID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;possible_answers&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;published_at&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;DateTime&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;t() &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@typedoc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  A type for the empty `Flick.RankedVoting.Ballot` struct.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  This type is helpful when you want to typespec a function that needs to accept
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  a non-persisted `Flick.RankedVoting.Ballot` struct value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@type&lt;/span&gt; struct_t &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;%&lt;/span&gt;__MODULE__{}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spend time writing &lt;code&gt;typedoc&lt;/code&gt; documentation, it can be a helpful space to talk out the reasoning behind some of the types.&lt;/p&gt;
&lt;p&gt;In addition to writing typespecs, when composing functions I also prefer pattern matching the struct and using guards to be explicit about incoming argument expectations.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; change_ballot(%&lt;span style=&#34;color:#a6e22e&#34;&gt;Ballot&lt;/span&gt;{} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ballot, attrs) &lt;span style=&#34;color:#f92672&#34;&gt;when&lt;/span&gt; is_map(attrs) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dialyzer is not a runtime enforcement tool, but these are. They help enforce expectations earlier in the call stack and thus help you become aware of when things are not as they seem sooner.&lt;/p&gt;
&lt;h2 id=&#34;document-your-dependencies&#34;&gt;Document your dependencies.&lt;/h2&gt;
&lt;p&gt;To help future you know why various dependencies were added to the project, add a minimal description before listing it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;defp&lt;/span&gt; deps &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# For Observability.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:appsignal_phoenix&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~&amp;gt; 2.5&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# To Render Markdown.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:earmark&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~&amp;gt; 1.4&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# For security scans.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:sobelow&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~&amp;gt; 0.13&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;only&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;:dev&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:test&lt;/span&gt;], &lt;span style=&#34;color:#e6db74&#34;&gt;runtime&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;document-and-validate-function-options&#34;&gt;Document and validate function options.&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# lib/flick/ranked_voting.ex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@doc&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;##&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; Options
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  * `:action` - An optional atom applied to the changeset, useful for forms that
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    look to a changeset&amp;#39;s action to influence form behavior.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; change_vote(%&lt;span style=&#34;color:#a6e22e&#34;&gt;Vote&lt;/span&gt;{} &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vote, attrs, opts \\ []) &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    opts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Keyword&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;validate!(opts, &lt;span style=&#34;color:#e6db74&#34;&gt;action&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you offer a function that accepts options as the final argument, document them and validate them.&lt;/p&gt;
&lt;p&gt;Validation helps ensure call sites do not include unexpected or typoed option keys and offers a clean space to provide a default value for the said option.&lt;/p&gt;
&lt;p&gt;Aside: Not currently demonstrable in Flick, but is in some of my work project, I usually write rich typespecs for my options as well.&lt;/p&gt;
&lt;h2 id=&#34;compose-pr-titles-for-clarity-and-consistency&#34;&gt;Compose PR titles for clarity and consistency.&lt;/h2&gt;
&lt;p&gt;With Flick, I work in focused PRs and have those PRs titled for clarity regarding what is changing. I like using prefixes like &lt;code&gt;fix&lt;/code&gt; &lt;code&gt;chore&lt;/code&gt; &lt;code&gt;feat&lt;/code&gt;. These PR titles are enforced with a specific &lt;a href=&#34;https://github.com/zorn/flick/blob/main/.github/workflows/lint-pr.yaml&#34;&gt;GitHub Action workflow&lt;/a&gt;. These PRs are squash merged and make for a (hopefully) readable &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;In the future, I might even be able to automate this to help with release notes.&lt;/p&gt;
&lt;h2 id=&#34;strive-for-database-precision&#34;&gt;Strive for database precision.&lt;/h2&gt;
&lt;p&gt;Be detail-oriented when building out your database tables.&lt;/p&gt;
&lt;p&gt;If something can not be null, be explicit &lt;code&gt;NOT NULL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If a string can be really long, use &lt;code&gt;:text&lt;/code&gt;. If you do use &lt;code&gt;:string&lt;/code&gt; (which has length limits), then enforce those length limitations in &lt;code&gt;Ecto.Changeset&lt;/code&gt; so the value is not trimmed quietly.&lt;/p&gt;
&lt;p&gt;Virtual fields on Ecto schemas are almost never the right answer.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;That was quite the hodgepodge of suggestions and tips. I had others, but they did not fit, or I don&amp;rsquo;t have good open source references yet.&lt;/p&gt;
&lt;p&gt;If you liked these or disagree, &lt;a href=&#34;https://mikezornek.com/contact&#34;&gt;let me know&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Notes about Technical Debt</title>
      <link>https://mikezornek.com/posts/2023/4/technical-debt/</link>
      <pubDate>Mon, 17 Apr 2023 10:42:07 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2023/4/technical-debt/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://elixirbookclub.github.io/website/&#34;&gt;Elixir Book Club&lt;/a&gt; is reading &lt;a href=&#34;https://pragprog.com/titles/atevol/software-design-x-rays/&#34;&gt;Software Design X-Rays:
Fix Technical Debt with Behavioral Code Analysis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This past Sunday, we had our first meeting, reviewing chapter one and sharing some interesting discussions on technical debt. I wanted to capture some thoughts while they were fresh in my head.&lt;/p&gt;
&lt;h2 id=&#34;what-is-technical-debt&#34;&gt;What is technical debt?&lt;/h2&gt;
&lt;p&gt;So the book starts by defining technical debt as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a metaphor that lets developers explain the need for refactorings and communicate technical trade-offs to business people. When we take on technical debt we choose to release our software faster but at the expense of future costs, as technical debt affects our ability to evolve a software system. Just like its financial counterpart, technical debt incurs interest payments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Personally, I would add the concept of decay and entropy in addition to mindful choice. Often, code that is eventually identified as technical debt was added to the system with a less perfect understanding of the requirements, or the requirements changed after the fact. Perhaps the developer leveled up their skills and has new ideas about approaching the problem and avoiding previously accepted trade-offs.&lt;/p&gt;
&lt;p&gt;Software libraries are also deprecated over time and need to be updated/replaced. Otherwise, you must deal with open security issues or the troublesome constraint of integrating old libraries with newer industry expectations.&lt;/p&gt;
&lt;h2 id=&#34;working-towards-a-tech-debt-framework&#34;&gt;Working towards a tech debt framework&lt;/h2&gt;
&lt;p&gt;The eventual goal of the book is to give you a framework to look at large codebases and understand what areas of the codebase would benefit from addressing technical debt the most. It uses git&amp;rsquo;s version history as a source and wants to provide statistical signals you can use in addition to (and in favor of) exclusive emotional reactions.&lt;/p&gt;
&lt;p&gt;Sounds like a reasonable start. It tracks the same way I want production observability signals to help me understand the system.&lt;/p&gt;
&lt;p&gt;What the book &lt;strong&gt;does not&lt;/strong&gt; get into is the discussions around getting time allocations in sprints to address technical debt. Depending on your circumstances, that is a more meaningful blocker than figuring out how to spend that technical debt time. The book club discussions ran on this for a while.&lt;/p&gt;
&lt;h2 id=&#34;selling&#34;&gt;Selling&lt;/h2&gt;
&lt;figure style=&#34;width: 50%; margin: 0 auto;&#34;&gt;
&lt;img src= &#34;tech-debt-meme.jpg&#34; alt= &#34;Construction worker in front of a very broken house being asked why it takes so long to add a new window.&#34; data-action=&#34; zoom&#34;/&gt;
&lt;figcaption&gt;Technical Debt Meme&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Saw this meme over the weekend, and it&amp;rsquo;s a good discussion starting point for the common perspective challenges of technical debt.&lt;/p&gt;
&lt;p&gt;You may see the house in that broken state, but the owner might see a working house and need help understanding what all the fuss is about. We don&amp;rsquo;t share the same vision of the system. We each have our own perspectives and biases.&lt;/p&gt;
&lt;p&gt;To continue the construction metaphor, yes, the inner wiring of the house might be decrepit and a fire hazard, but the owners are not electricians. They see and use abstractions like light switches and heat regularly without issue. They don&amp;rsquo;t see nor understand the system&amp;rsquo;s inner workings, and it&amp;rsquo;s your job to express your perspective: to help them understand how things work, why it might be a good idea to replace the wiring, and what failing to replace it looks like regarding managed risk.&lt;/p&gt;
&lt;p&gt;I suspect many programmers don&amp;rsquo;t like being a salesperson, but you need to do it to be a successful voice on behalf of the system.&lt;/p&gt;
&lt;p&gt;Last week, while attending Philly ETE, I saw a great talk on this topic titled &lt;a href=&#34;https://www.youtube.com/watch?v=q1KL4n1I5Fs&#34;&gt;Leading with the Platform: A Platform Engineering Approach to Tech Debt&lt;/a&gt; by Jess Mink.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Platform teams, SREs, tool teams, DevOps…we are the stage crew of a software company: we&amp;rsquo;re only noticed when we mess up.&lt;/p&gt;
&lt;p&gt;This talk is about how platform teams have the potential to be proactive and lead projects across engineering so that things can be addressed they break, thereby reducing tech debt before it&amp;rsquo;s accrued, and they can be noticed for something positive for a change.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll be talking about company objectives, data, thinking like a product manager, and how it benefits the company as a whole if other teams can get into the act and to pick up some of the platform team&amp;rsquo;s work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can also check out this article on &lt;a href=&#34;https://thoughtbot.com/blog/selling-technical-debt-to-the-business&#34;&gt;how to sell technical debt&lt;/a&gt; and why positioning the business value of technical debt is crucial to getting buy-in and approvals.&lt;/p&gt;
&lt;h2 id=&#34;sprint-planning-and-broken-glass&#34;&gt;Sprint planning and broken glass&lt;/h2&gt;
&lt;p&gt;While a product manager has the ultimate say and owns the sprint plan, various stakeholders still influence it. To simplify, let&amp;rsquo;s say we have one group representing the customers and the other representing the developers. Each group has their own short-term and long-term interests. A good sprint and roadmap will have a healthy mix of all four areas. If the weights of any of these four areas get too out of proportion for too long, things will get into a bad state.&lt;/p&gt;
&lt;p&gt;Specifically to the short-term interest of developers, I&amp;rsquo;m a big proponent of giving individuals &lt;strong&gt;timeboxed &amp;lsquo;broken glass&amp;rsquo; autonomy&lt;/strong&gt;. This is a metaphor that comes from theme parks. If you are an employee, and your job has you walking the park day in and day out, when you see broken glass on the floor, you should stop and clean it up for the serenity and safety of everyone else.&lt;/p&gt;
&lt;p&gt;A more strict and formal management style would have the employee report the observation, have it queued for review, and then (maybe) executed days or weeks later—a lot of overhead for a 20-minute clean-up job.&lt;/p&gt;
&lt;p&gt;Giving programmers autonomy to identify, timebox, and execute pain points they experience in the codebase is both efficient and satisfying for the programmer.&lt;/p&gt;
&lt;h2 id=&#34;trust&#34;&gt;Trust&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;All this sounds nice, but my product manager does not trust the development team. They never approve technical debt work.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Earning and having trust with coworkers is a foundational and challenging need. If the product manager does not have trust in the development team, ask those hard &lt;em&gt;why&lt;/em&gt; questions.&lt;/p&gt;
&lt;p&gt;For the developers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Work hard to empathize with the product manager and the million spinning plates they are trying to keep up.&lt;/li&gt;
&lt;li&gt;A common cause of friction is missed deadlines, so work with the product team to descope work and create small iterative loops with extreme priority. Always keep the system in a shippable state.&lt;/li&gt;
&lt;li&gt;Be expressive about progress, letting the product manager dig deep when needed, but have a high-level understanding at all times.&lt;/li&gt;
&lt;li&gt;Give them the information and choices, and when a choice is made, work to execute it professionally.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the product managers and owners:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Be transparent with your whole team about the company&amp;rsquo;s status and goals. Don&amp;rsquo;t consider these &amp;rsquo;non-programming status communications&amp;rsquo; as wasteful. Developers make hundreds of decisions on the company&amp;rsquo;s behalf, with or without this context. The more informed they are, the better decisions they can make.&lt;/li&gt;
&lt;li&gt;Create space for trust to be earned. Instead of assigning a sprint&amp;rsquo;s worth of tickets to a team, let the team choose the capacity.&lt;/li&gt;
&lt;li&gt;Create space for empathy to grow. Encourage pairing across multiple job titles so people better know what all corners of the company feel like.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more on trust, I recommend &lt;a href=&#34;https://bookshop.org/p/books/the-five-dysfunctions-of-a-team-a-leadership-fable-patrick-m-lencioni/9742373&#34;&gt;The Five Dysfunctions of a Team: A Leadership Fable by Patrick M. Lencioni&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;join-us&#34;&gt;Join us&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d enjoy discussing technical debt, join us for future book club discussions. We meet on Sundays every two weeks via our Discord. More info at: &lt;a href=&#34;https://elixirbookclub.github.io/website/&#34;&gt;https://elixirbookclub.github.io/website/&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Elixir Context Accessor Function: Which Return Type Do You Prefer?</title>
      <link>https://mikezornek.com/posts/2023/2/elixir-get-noun-return-type/</link>
      <pubDate>Sun, 12 Feb 2023 13:55:42 -0500</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2023/2/elixir-get-noun-return-type/</guid>
      <description>&lt;p&gt;During a recent &lt;a href=&#34;https://elixirbookclub.github.io/website/&#34;&gt;Elixir Book Club&lt;/a&gt; meeting we had a back and forth discussion on a simple code style question:&lt;/p&gt;
&lt;p&gt;When providing an accessor function inside your domain context, do you prefer a return type of &lt;code&gt;{:ok, noun} || {:error, :not_found}&lt;/code&gt; or &lt;code&gt;noun || nil&lt;/code&gt; ?&lt;/p&gt;
&lt;p&gt;In my own historical work I&amp;rsquo;ve generally followed along with common Phoenix generator style of building out functions like &lt;code&gt;get_noun/1&lt;/code&gt; that return the &lt;code&gt;noun&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt; but moving forward I think I&amp;rsquo;ll be preferring &lt;code&gt;fetch_noun/1&lt;/code&gt; functions that use an &lt;code&gt;:ok&lt;/code&gt; / &lt;code&gt;:error&lt;/code&gt; tuple style return type.&lt;/p&gt;
&lt;p&gt;The primary reason is expressiveness in the crash logs. Eventually there will be some crash and the stacktrace is going to show &lt;code&gt;nil&lt;/code&gt; being passed into some function, and the function having an expectation of a real value type. In those moments it can take some time to understand where the hell &lt;code&gt;nil&lt;/code&gt; is coming from. I think an error like &lt;code&gt;noun_not_found&lt;/code&gt; will be more helpful.&lt;/p&gt;
&lt;p&gt;I want to start keeping track of these personal preferences and so today I&amp;rsquo;ve also made a new guide for the Franklin project documenting &lt;a href=&#34;https://github.com/zorn/franklin/blob/main/guides/code_style/context_accessors.md&#34;&gt;Code Style: Context Accessors&lt;/a&gt;. There is some more background and reasoning about my preferences inside should you be interested.&lt;/p&gt;
&lt;p&gt;While that guide expresses a preference towards &lt;code&gt;fetch_noun/1&lt;/code&gt; and the &lt;code&gt;:ok&lt;/code&gt; / &lt;code&gt;:error&lt;/code&gt; tuple return type, it also acknowledges that it might be helpful and supportive for the context to offer &lt;strong&gt;multiple&lt;/strong&gt; accessor functions allowing the call sites to use whichever one is more appropriate.
`
How about yourself? What return type do you prefer and why? &lt;a href=&#34;https://mikezornek.com/contact&#34;&gt;Let me know.&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Curse of Test Fixtures</title>
      <link>https://mikezornek.com/posts/2022/10/fixture-rant/</link>
      <pubDate>Thu, 27 Oct 2022 20:10:37 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2022/10/fixture-rant/</guid>
      <description>&lt;p&gt;Please heed my warning or be cursed with coupled test code!&lt;/p&gt;
&lt;p&gt;The general use case for test fixtures usually involves impure functions. These functions rely on an external collaborator and not just the incoming arguments of the function. Before the test runs, you want to put the world in a particular state. A common case is a database, your app&amp;rsquo;s repository of entities.&lt;/p&gt;
&lt;p&gt;You have choices for how to make this happen.&lt;/p&gt;
&lt;p&gt;One choice/tool I observe many Elixir developers reaching for is &lt;a href=&#34;https://github.com/thoughtbot/ex_machina&#34;&gt;ex_machina&lt;/a&gt;, a fixture/factory tool. I&amp;rsquo;ve used it myself on many projects. It can be a productive addition.&lt;/p&gt;
&lt;p&gt;In short, &lt;code&gt;ex_machina&lt;/code&gt; lets you build a factory of fixtures, even fixtures with relationships to other fixtures. When the time comes, you invoke &lt;code&gt;insert(:user)&lt;/code&gt; in your test, and your database is populated with the generated data. The world is now set for you to test your &lt;code&gt;list_users/0&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;This is (usually) a poor choice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;chose-poorly.jpg&#34; alt=&#34;Test Fixtures: You Have Chosen Poorly&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem is coupling.&lt;/strong&gt; When you call &lt;code&gt;insert(:user)&lt;/code&gt;, you are hard injecting the database with an assumption of what it means in the domain to &amp;ldquo;create a user&amp;rdquo;. You probably have a real domain context that provides a &lt;code&gt;create_user/1&lt;/code&gt; function. Instead of using it, you couple this test, which needs a user already in the system, with assumed implementation details.&lt;/p&gt;
&lt;p&gt;In the early days of a project, this raw database injection will likely be pretty close to what you have going on in &lt;code&gt;create_user/1&lt;/code&gt;, but as the project evolves, these two paths can quickly diverge. The challenges and risks of maintaining parity between what it means to &amp;ldquo;create a user&amp;rdquo; through the domain context OR the factory&amp;rsquo;s raw database injection will become an expensive burden. Still worse, when you want to refactor &lt;code&gt;create_user/1&lt;/code&gt;, you can&amp;rsquo;t &amp;ndash; at least not without touching every part of the test suite that used fixtures and made assumptions about the database layout.&lt;/p&gt;
&lt;p&gt;The much better choice is to, when needed for impure tests, use your domain contexts to influence the world.&lt;/p&gt;
&lt;p&gt;Be extremely mindful of the API boundaries of your code. &lt;strong&gt;Test the boundaries and NOT the implementation.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using real domain contexts to populate the world state can sometimes be slower. My suggestion is to swallow this slowness up front and only fallback to direct fixture injection when the testing performance needs are a good tradeoff for the cost of coupling. Since coupling will hamper refactoring, I consider that and HUGE tradeoff, and so it would take a significant speed difference to make me reconsider.&lt;/p&gt;
&lt;p&gt;For more on this concern, check out Saša Jurić&amp;rsquo;s Clarity talk. He talks of helper methods he usually makes, like &lt;code&gt;register!/1&lt;/code&gt; at minute 38.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/6sNmJtoKDCo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

</description>
    </item>
    
    <item>
      <title>Elixir Style: Prefer Unnested Aliases</title>
      <link>https://mikezornek.com/posts/2022/4/style-aliases/</link>
      <pubDate>Fri, 01 Apr 2022 12:31:06 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2022/4/style-aliases/</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally written for my old ElixirFocus blog, and transfer here after its closure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In Elixir, &lt;code&gt;alias&lt;/code&gt; is a keyword we often use to create shorthand references to long-form module names allowing us to refer to &lt;code&gt;RetroTaxi.Boards.Board&lt;/code&gt; simply as &lt;code&gt;Board&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll often end up with a collection of &lt;code&gt;alias&lt;/code&gt; declarations at the top of a module, and Elixir offers two ways to format these.&lt;/p&gt;
&lt;p&gt;One way is simple list such as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RetroTaxi.Boards.Board&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RetroTaxi.Boards.Column&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RetroTaxi.Boards.TopicCard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The other way is an optional nested list like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RetroTaxi.Boards&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Board&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Column&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;TopicCard&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sometimes this nested list is broken across separate lines and presented like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RetroTaxi.Boards&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Board&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Column&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;TopicCard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;style-recommendation&#34;&gt;Style Recommendation&lt;/h2&gt;
&lt;p&gt;I highly recommend avoiding this nested presentation. The primary reason is to help keep the codebase plain-text searchable. By avoiding the nesting, you can quickly find which modules are referencing any module simply by searching for its name string like &lt;code&gt;RetroTaxi.Boards.Column&lt;/code&gt;. Finding nested aliases would require a more complex regular expression or language server tooling.&lt;/p&gt;
&lt;p&gt;If you want to enforce this style with a credo, check out &lt;a href=&#34;https://hexdocs.pm/credo/Credo.Check.Readability.MultiAlias.html&#34;&gt;Credo.Check.Readability.MultiAlias&lt;/a&gt; which is usually disabled on a default credo install.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Improve the Clarity of Your Elixir Code Through Expressive and Consistent Language</title>
      <link>https://mikezornek.com/posts/2021/6/programming-terminology/</link>
      <pubDate>Sun, 06 Jun 2021 12:00:00 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2021/6/programming-terminology/</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally written for my old ElixirFocus blog, and transfer here after its closure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of our primary day-to-day responsibilities as programmers is to communicate. We need to express our ideas, explain our work and document our code. Having a strong vocabulary and explicit intentions behind the words you (and your team) choose can greatly help avoid confusion.&lt;/p&gt;
&lt;p&gt;Take some time as a team to talk about how you name and describe things. Embrace productive confrontation when you identify inconsistencies and work towards creating (and documenting!) as much as a ubiquitous language as you can.&lt;/p&gt;
&lt;p&gt;The following is a collection of terms I try to be mindful of in my own work. Hopefully this list helps inspire some of your own terminology choices.&lt;/p&gt;
&lt;h2 id=&#34;programming-terminology&#34;&gt;Programming Terminology&lt;/h2&gt;
&lt;h3 id=&#34;entity-vs-value&#34;&gt;Entity vs Value&lt;/h3&gt;
&lt;p&gt;An &lt;strong&gt;entity&lt;/strong&gt; is a structure that has identity. An &lt;code&gt;Account&lt;/code&gt; in my application has a unique identifier and is thus is considered an entity.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;value&lt;/strong&gt; is a structure without identity. A &lt;code&gt;Color&lt;/code&gt; in my application might be made up of three scalars like red, green and blue. Collectively they make up the &lt;code&gt;Color&lt;/code&gt; value but there is no identity.&lt;/p&gt;
&lt;p&gt;Some people might prefer the term &lt;strong&gt;record&lt;/strong&gt; instead of entity in this context. I consider the terms fairly similar so would honor my team&amp;rsquo;s chosen preference.&lt;/p&gt;
&lt;h3 id=&#34;entity-vs-row&#34;&gt;Entity vs Row&lt;/h3&gt;
&lt;p&gt;Sometimes when we talk about entities we&amp;rsquo;ll get into the deeper discussions of how the entities are persisted, usually inside a database At that point I make a special case to change how I talk, being more explicit about the &lt;strong&gt;database row&lt;/strong&gt;. Entity is how I refer to the in-memory representation of the structure, but if we are talking about database storage or SQL-specific things I want to use the term &lt;strong&gt;row&lt;/strong&gt; to be more explicit.&lt;/p&gt;
&lt;h3 id=&#34;maps-vs-structs-vs-ecto-schemas&#34;&gt;Maps vs Structs vs (Ecto) Schemas&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Maps&lt;/strong&gt;, &lt;strong&gt;Structs&lt;/strong&gt; and &lt;strong&gt;(Ecto) Schemas&lt;/strong&gt; are all Elixir structure tools that we use to create entities and values. Each of these tools has their own purpose and constrains so I try to be explicit when talking about which tool we are using.&lt;/p&gt;
&lt;h3 id=&#34;create-vs-new-vs-insert-and-remove-vs-delete&#34;&gt;Create vs New vs Insert and Remove vs Delete&lt;/h3&gt;
&lt;p&gt;As you define the core domain nouns of your app you&amp;rsquo;ll inevitably start to build out a series of modules that help you manage these nouns. When designing the interfaces of these modules have an explicit pattern for how to name behaviors and try when possible to lean on community patterns. Ask yourself, &amp;ldquo;how does the Elixir language or popular frameworks use these terms?&amp;rdquo;&lt;/p&gt;
&lt;figure class=&#34;&#34;&gt;
 &lt;a href=&#34;delete-new-search.png&#34;&gt;
 &lt;img class=&#34;&#34; style=&#34;max-width: 50%; &#34;src=&#34;delete-new-search.png&#34; alt=&#34;Delete and New as used inside of Elixir.&#34;&gt;&lt;/a&gt;
 &lt;figcaption class=&#34;&#34;&gt;Delete and New as used inside of Elixir.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You can also take advantage of the various Phoenix/Ecto generates for a peek at some pattern recommendations from the framework authors. These are usually a great place to start, although I don&amp;rsquo;t consider the patterns to be gospel.&lt;/p&gt;
&lt;p&gt;In addition to the working on the names of the modules functions themselves, you may also be involved in the user experience of an app and its own terminology. Ideally the nouns and terms from the interface down through the code will align but this is not always possible. Sometimes the needs of the user experience design require the terminologies to deviate. While not ideal, I&amp;rsquo;m fine with this &amp;ndash; it just has to be done with intent and consistency. Write down the terms you have chosen and why.&lt;/p&gt;
&lt;h3 id=&#34;get-vs-fetch&#34;&gt;Get vs Fetch&lt;/h3&gt;
&lt;p&gt;There are a few notable Elixir patterns to be mindful of with the terms &lt;code&gt;get&lt;/code&gt; vs &lt;code&gt;fetch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First let&amp;rsquo;s check out &lt;a href=&#34;https://hexdocs.pm/elixir/Map.html#get/3&#34;&gt;Map.get/3&lt;/a&gt; which will return a value for the given key or a default value if the key is not found.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(%{}, &lt;span style=&#34;color:#e6db74&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(%{&lt;span style=&#34;color:#e6db74&#34;&gt;a&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}, &lt;span style=&#34;color:#e6db74&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(%{&lt;span style=&#34;color:#e6db74&#34;&gt;a&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}, &lt;span style=&#34;color:#e6db74&#34;&gt;:b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(%{&lt;span style=&#34;color:#e6db74&#34;&gt;a&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}, &lt;span style=&#34;color:#e6db74&#34;&gt;:b&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we have &lt;a href=&#34;https://hexdocs.pm/elixir/Map.html#fetch/2&#34;&gt;Map.fetch/2&lt;/a&gt; which will return an :ok tuple or :error if the key is not found.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fetch(%{&lt;span style=&#34;color:#e6db74&#34;&gt;a&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}, &lt;span style=&#34;color:#e6db74&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;:ok&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fetch(%{&lt;span style=&#34;color:#e6db74&#34;&gt;a&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}, &lt;span style=&#34;color:#e6db74&#34;&gt;:b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is also a bang version of fetch, &lt;a href=&#34;https://hexdocs.pm/elixir/Map.html#fetch!/2&#34;&gt;Map.fetch!/2&lt;/a&gt; which will return the value or raise an exception if the key is not found.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fetch!(%{&lt;span style=&#34;color:#e6db74&#34;&gt;a&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;}, &lt;span style=&#34;color:#e6db74&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The takeaways from these language patterns I take note of are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_noun&lt;/code&gt; should return the value or a default if not found.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch_noun&lt;/code&gt; should return a &lt;code&gt;:ok&lt;/code&gt; tuple or an &lt;code&gt;:error&lt;/code&gt; tuple.&lt;/li&gt;
&lt;li&gt;Any function with a bang (exclamation point) will throw an exception, and that exception should be documented inside the inline documentation.&lt;/li&gt;
&lt;li&gt;In general I try to avoid creating bang style functions as I feel like Elixir exceptions should be exceptional. You may notice that the there are Phoenix code generators out there that will create a &lt;code&gt;get!&lt;/code&gt; style functions in generated contexts. That is pattern I am aware of but question in newer code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;list-vs-array&#34;&gt;List vs Array&lt;/h3&gt;
&lt;p&gt;I do my best to be mindful of and embrace the terminology of the language I am working in, moment to moment. This means if we are dealing with a collection in Elixir I&amp;rsquo;ll say list and when we are dealing with a collection is JavaScript I&amp;rsquo;ll say array. In an Elixir context I&amp;rsquo;ll say map and in a JavaScript context I&amp;rsquo;ll say dictionary.&lt;/p&gt;
&lt;p&gt;For a junior programmer this might seem like symantec nonsense but I think its an important distinction. Related, I honor the styles of the host language, for example using camel case for variables in JavaScript and underscores in Elixir. With luck a linter of some kind can help remind me if I loose my place.&lt;/p&gt;
&lt;h3 id=&#34;behavior-vs-feature&#34;&gt;Behavior vs Feature&lt;/h3&gt;
&lt;p&gt;When talking about what my code does I use the term behavior. I describe the behaviors I want to build and I document the behaviors I observe.&lt;/p&gt;
&lt;p&gt;The term feature is more a product or marketing term, usually describing a collection of end user observable behaviors.&lt;/p&gt;
&lt;h2 id=&#34;app-and-business-domain-consistency&#34;&gt;App and Business Domain Consistency&lt;/h2&gt;
&lt;h3 id=&#34;document-your-apps-custom-terminology&#34;&gt;Document Your App&amp;rsquo;s Custom Terminology&lt;/h3&gt;
&lt;p&gt;While I have some personal preferences to share below, ultimately every app will have a custom vernacular for how they label things in the system. Spend some time getting team agreement on the meaning and intent behind these terms. Write them down. Review and evolve the glossary when needed. Having alignment on this language will be extremely helpful over time as you discuss what to code needs to do.&lt;/p&gt;
&lt;h3 id=&#34;authentication-vs-authorization&#34;&gt;Authentication vs Authorization&lt;/h3&gt;
&lt;p&gt;Many people simply talk about &amp;ldquo;auth&amp;rdquo; systems without being explicit but it&amp;rsquo;s important to distinguish between authentication, figuring out who you are talking to, and authorization, figuring out if someone should be allowed to do something.&lt;/p&gt;
&lt;h3 id=&#34;sign-in-vs-log-in&#34;&gt;Sign in vs Log in&lt;/h3&gt;
&lt;p&gt;My own preference here is to use Sign in, Sign out and Sign up. I&amp;rsquo;m also ok with other variants like &amp;ldquo;Create Account&amp;rdquo; in the user experience as long as we are consistent.&lt;/p&gt;
&lt;p&gt;I dislike log in since it is too easy to mix up the term &amp;ldquo;login&amp;rdquo; vs &amp;ldquo;log in&amp;rdquo;.&lt;/p&gt;
&lt;h3 id=&#34;account-vs-user-and-settings-vs-preferences&#34;&gt;Account vs User and Settings vs Preferences&lt;/h3&gt;
&lt;p&gt;No strong personal preferences here, would have to consider the application context &amp;ndash; but once again I am looking for consistency. If I were debating choices for a new app with my team I&amp;rsquo;d look at some industry competition to see what they do.&lt;/p&gt;
&lt;h2 id=&#34;language-i-try-to-avoid&#34;&gt;Language I Try to Avoid&lt;/h2&gt;
&lt;h3 id=&#34;bad-code-and-code-smell&#34;&gt;Bad Code and Code Smell&lt;/h3&gt;
&lt;p&gt;I do my best to follow the &lt;a href=&#34;https://easyretro.io/retrospective-prime-directive/&#34;&gt;retrospective prime directive&lt;/a&gt; which states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Believing this, I try to avoid saying something is &amp;ldquo;bad code&amp;rdquo; or has a &amp;ldquo;code smell&amp;rdquo;. Those phrases package a lot of negative judgement which is not very constructive. Instead let&amp;rsquo;s look for opportunities to improve testability, or documentation or abstractions. No one wrote this &amp;ldquo;bad code&amp;rdquo; intentionally to sabotage the system. We are all members of an extremely immature and fast moving industry with diverse backgrounds and levels of experience. It is messy out there and everyone is learning as we go.&lt;/p&gt;
&lt;p&gt;If you are doing a code review, instead of saying something has a &amp;ldquo;code smell&amp;rdquo;, kickstart a discussion around getting more context around the decisions and constrains that led to this code&amp;rsquo;s design. Ask if they considered an alternative or are aware of your concerns. These pull requests are opportunities for education and starting the process with judgement language is not going to result in many positive outcomes.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;You might also enjoy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=5MBGDM8xSQg&#34;&gt;Video: Building Beautiful Systems With Phoenix Contexts and Domain-Driven Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://devonburriss.me/ddd-glossary/&#34;&gt;Domain-Driven Design Glossary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;What did I miss? What terminology are you protective of in your own code? Let me know: &lt;a href=&#34;mailto:mike@mikezornek.com&#34;&gt;mike@mikezornek.com&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Video: Using Fixtures and Test Assets in Swift Unit Tests (9m)</title>
      <link>https://mikezornek.com/posts/2020/9/using-fixtures-and-test-assets-in-swift-unit-tests/</link>
      <pubDate>Wed, 02 Sep 2020 10:42:44 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2020/9/using-fixtures-and-test-assets-in-swift-unit-tests/</guid>
      <description>&lt;p&gt;In today&amp;rsquo;s video I&amp;rsquo;ll demonstrate how you can use the concept of fixtures in your Swift unit tests to quickly build business objects and validate scenarios.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll also show how you can add assets to a test target and then access them in code using &lt;code&gt;Bundle(for: SomeTypeInTheTestBundle.self)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code you see in the video is part of a demo project on GitHub:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/zorn/VersionedFilesDemo&#34;&gt;https://github.com/zorn/VersionedFilesDemo&lt;/a&gt;&lt;/p&gt;





&lt;video
  controls
  class=&#34;mb-0 w-full&#34;
  title=&#34;Using Fixtures and Test Assets in Swift Unit Tests&#34;
&gt;
  &lt;source src=&#34;https://f002.backblazeb2.com/file/mikezornek-com-media/using_fixtures_and_test_assets_in_swift_unit_tests.mp4&#34; type=&#34;video/mp4&#34;&gt;
  Your browser does not seem to support the video format. You can
  &lt;a href=&#34;https://f002.backblazeb2.com/file/mikezornek-com-media/using_fixtures_and_test_assets_in_swift_unit_tests.mp4&#34;&gt;download the MP4 file&lt;/a&gt;
  directly.
&lt;/video&gt;

&lt;div class=&#34;mt-2 flex justify-between&#34;&gt;
  &lt;a href=&#34;https://f002.backblazeb2.com/file/mikezornek-com-media/using_fixtures_and_test_assets_in_swift_unit_tests.mp4&#34;&gt;Download MP4&lt;/a&gt;
  
    &lt;a href=&#34;https://www.youtube.com/watch?v=VVdwOnBiWlU&#34;&gt;Watch on YouTube&lt;/a&gt;
  
&lt;/div&gt;

&lt;p&gt;Thanks for watching!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Renaissance Man</title>
      <link>https://mikezornek.com/posts/2020/3/renaissance-man/</link>
      <pubDate>Mon, 16 Mar 2020 15:39:04 -0400</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2020/3/renaissance-man/</guid>
      <description>&lt;p&gt;👨‍💻 Right now I&amp;rsquo;m on a client project that has me working on an iOS SDK codebase but still touching GoLang, C and Kotlin/Android as well. I&amp;rsquo;m doing the best I can but it is challenging jumping around, particularly into languages I don&amp;rsquo;t have a rich history with.&lt;/p&gt;
&lt;p&gt;This experience does however back up my opinion that good programers are better off being proficient in many languages.&lt;/p&gt;
&lt;p&gt;If you do find yourself with some extra time indoors over the next few weeks, consider giving yourself a distraction and try to learn something new. I recommend &lt;a href=&#34;https://exercism.io&#34;&gt;Exercism&lt;/a&gt; as a great starting point for many different languages. They even have mentors to help. I also like &lt;a href=&#34;https://pragprog.com/titles?f%5Bsort_by%5D=pubdate&amp;amp;f%5Bcategory%5D=all&amp;amp;f%5Bskill_level%5D=All&amp;amp;f%5Btitle_contains%5D=seven&#34;&gt;PragProg&amp;rsquo;s &amp;ldquo;Seven (Things) in Seven Weeks&amp;rdquo; series&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Good luck out there. Stay safe, stay sane. Make today count!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Code Documentation</title>
      <link>https://mikezornek.com/posts/2019/2/professional-ios-projects-code-documentation/</link>
      <pubDate>Tue, 19 Feb 2019 10:00:00 -0500</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2019/2/professional-ios-projects-code-documentation/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is part of a series, &lt;a href=&#34;https://mikezornek.com/professional-ios-projects/&#34;&gt;Professional iOS Projects&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Professional iOS projects have good code documentation.&lt;/p&gt;
&lt;h2 id=&#34;what-is-code-documentation&#34;&gt;What is code documentation?&lt;/h2&gt;
&lt;p&gt;When I talk of code documentation I generally mean two things. First is &lt;em&gt;inline code documentation&lt;/em&gt;, those triple slashed comments in a Swift file you use to describe types, properties and methods. Second, I mean &lt;em&gt;guides&lt;/em&gt;, which are articles that describe aspects of the code from a higher perspective, usually explaining expected interactions as well as the thinking behind the design.&lt;/p&gt;
&lt;p&gt;Documentation is great. It helps people who are new or returning to a code base learn how things work and like unit tests can help lead to better designs as documenting a poor design usually will help expose potential issues and misunderstandings.&lt;/p&gt;
&lt;h2 id=&#34;why-should-i-write-documentation&#34;&gt;Why should I write documentation?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;All that sounds great but how come no one writes any code documentation?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sadly it&amp;rsquo;s a victim of our current industry norms.&lt;/p&gt;
&lt;p&gt;You won&amp;rsquo;t find many &amp;ldquo;how to write great code documentation&amp;rdquo; classes in a computer science curriculum. Most &amp;ldquo;learning to program&amp;rdquo; books will overlook the topic entirely or limit coverage to a passing mention of the document syntax format for the given language.&lt;/p&gt;
&lt;p&gt;Even at work, when was the last time a pull request of yours was rejected for missing documentation? When was the last time your manager brought up code documentation during a sprint plan? Maybe you are getting pushed around for a quick delivery. Was documentation a requirement in the client contract? Has anyone suggested that if it&amp;rsquo;s not in the contract it’s not part of the deliverable?&lt;/p&gt;
&lt;p&gt;This is where we separate the coders from the professional programmers.&lt;/p&gt;
&lt;p&gt;Some, many in fact, work in this industry just to make a buck. Others like to consider themselves craftsman or professionals. These people constantly look for ways to improve themselves and the community around them. It is in these people I put my faith that over time, code documentation norms will get better, like other behaviors before it.&lt;/p&gt;
&lt;p&gt;When I first started programming very few people used version control day to day, leaving it for only the most complex of projects. A daily ZIP file of the source and passing around &lt;code&gt;.patch&lt;/code&gt; files worked just fine for many.&lt;/p&gt;
&lt;p&gt;Testing has also followed a similar path where back in the day only a few would consider testing helpful and tools were hard to find and integrate, but now test targets are part of the built-in project templates.&lt;/p&gt;
&lt;p&gt;Progress is being made.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: While I general feel the community norms around code documentation need to improve I did want to point out that open source is one ecosystem which is shown to highly value code documentation the tooling around it.&lt;/p&gt;
&lt;p&gt;If you are looking for good code documentation examples, try to find an active open source project to reference. You’ll usually find some helpful patterns to follow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;how-do-i-write-documentation&#34;&gt;How do I write documentation?&lt;/h2&gt;
&lt;p&gt;Swift inline documentation is easy enough to get started with.&lt;/p&gt;
&lt;p&gt;Example 1:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/// Describes a person whom we have met in real life.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Contact&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// The name of the person.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// Initialize new `Contact` instance.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;///&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// - Parameter name: The name of the contact we met.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(name: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.name = name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add documentation use three slashes &lt;code&gt;///&lt;/code&gt; to start a line of documentation. You’ll want to document the type, the properties and then methods. Also, notice for methods that take parameters there is a format to document them as well.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In Xcode you can also use &lt;code&gt;Option+Command+/&lt;/code&gt; to bulk paste a documentation line template. This template is particularly useful when documenting a method with lots of parameters and other parts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;img src=&#34;xcode-menu.png&#34; alt=&#34;Xcode Menu, Add Documentation&#34; data-action=&#34;zoom&#34;&gt;
&lt;img src=&#34;adding-documentation.gif&#34; alt=&#34;Inline Editor Adding Documentation&#34; data-action=&#34;zoom&#34;&gt;
&lt;p&gt;Swift documentation supports Markdown and if you backtick mentions of a type it often will generate a link to that type when the documentation is rendered in Xcode.&lt;/p&gt;
&lt;p&gt;Example 2:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/// A data store to hold `Contact`s of the user.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContactStore&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;MARK:&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; - Properties&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// The currently managed `Contact`s of the store.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; contacts: [Contact] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;MARK:&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; - Methods&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// Accepts a contact and adds it to the store.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// If the given contact was already a member of the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// store, the `contacts` collection is not changed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;///&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// - Parameter contact: a contact to be added to the store&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;addContact&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; contact: Contact) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; contains(contact) == &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        contacts.append(contact)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;MARK:&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; - Private&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// Will search the store for the given contact.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;///&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// - Parameter contact: the contact to look for&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/// - Returns: a bool value indicating if the contact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;///   was found in the store&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;contains&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; contact: Contact) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;FIXME:&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; To be implemented&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this second example we use &lt;code&gt;MARK: - SectionName&lt;/code&gt;. This helps split up our source file. In particular since we don’t have headers anymore I like how I can segregate &lt;code&gt;private&lt;/code&gt; methods to the bottom.&lt;/p&gt;
&lt;img src=&#34;method-popup.png&#34; alt=&#34;Xcode Method Popup&#34; data-action=&#34;zoom&#34;&gt;
&lt;p&gt;Another example here includes the use of &lt;code&gt;//FIXME&lt;/code&gt;. FIXME is not triple slashed so it’s not technically documentation but it will be showcased inside of Xcode’s editor.&lt;/p&gt;
&lt;p&gt;The main way you’ll encounter this documentation is through Xcode’s Quick Help. Option click a method and you’ll see:&lt;/p&gt;
&lt;img src=&#34;quickhelp.png&#34; alt=&#34;Xcode Quick Help&#34; data-action=&#34;zoom&#34;&gt;
&lt;p&gt;Sadly there is no official support for HTML generation but there are third party tools like &lt;a href=&#34;https://github.com/realm/jazzy&#34;&gt;Jazzy&lt;/a&gt; that can help.&lt;/p&gt;
&lt;h2 id=&#34;writing-guides&#34;&gt;Writing Guides&lt;/h2&gt;
&lt;p&gt;In addition to inline documentation you’ll want to write up some more high level guides. These can cover many things from code tutorials to design retrospectives to agreed upon code patterns and terminology.&lt;/p&gt;
&lt;p&gt;A great example of this can be found in the &lt;a href=&#34;https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes&#34;&gt;open source code base for NetNewsWire&lt;/a&gt;. Brent has written lots of helpful documents including &lt;a href=&#34;https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/CodingGuidelines.md&#34;&gt;Coding Guidelines&lt;/a&gt; and a &lt;a href=&#34;https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/Roadmap.md&#34;&gt;Roadmap&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;resources&#34;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/SymbolDocumentation.html#//apple_ref/doc/uid/TP40016497-CH51-SW1&#34;&gt;Markup Formatting Reference: Formatting Quick Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nshipster.com/swift-documentation/&#34;&gt;Swift Documentation - NSHipster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;counterarguments&#34;&gt;Counterarguments&lt;/h2&gt;
&lt;p&gt;Documentation is one of those things some developers get extremist about. One popular quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good code is its own best documentation. As you’re about to add a comment, ask yourself, “How can I improve the code so that this comment isn’t needed?” Improve the code and then document it to make it even clearer.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.azquotes.com/author/38834-Steve_McConnell&#34;&gt;Steve McConnell&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is nothing inherently wrong with this statement. I too avoid documenting very simple statements. The bigger problem is that the code we are writing today isn’t very good. It’s usually pretty lousy. It’s a version one for some half written client specification.&lt;/p&gt;
&lt;p&gt;If you aren’t finding possible improvements in the code you wrote last year you have a problem. The phase “good code” is very suspect.&lt;/p&gt;
&lt;p&gt;There are extremes with anything. Use your judgement. Most people don’t get yelled at for writing too much documentation though.&lt;/p&gt;
&lt;h2 id=&#34;how-to-get-started&#34;&gt;How to Get Started?&lt;/h2&gt;
&lt;p&gt;Document something, document anything.&lt;/p&gt;
&lt;p&gt;You need not take two weeks off to go back and document everything. Stick to documenting new types or types that are being refactored or take a shot at listing the most complex aspects of your current system and then work down the list.&lt;/p&gt;
&lt;p&gt;Give code documentation some time to become a habit. Documentation’s value usually doesn’t popup until a few months after writing it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Code Consistency with SwiftLint</title>
      <link>https://mikezornek.com/posts/2019/1/professional-ios-projects-code-consistency-with-swiftlint/</link>
      <pubDate>Thu, 24 Jan 2019 12:00:00 -0500</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2019/1/professional-ios-projects-code-consistency-with-swiftlint/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is part of a series, &lt;a href=&#34;https://mikezornek.com/professional-ios-projects/&#34;&gt;Professional iOS Projects&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;img src=&#34;book-cover.jpg&#34; style=&#34;float: right; width: 300px;&#34; alt=&#34;Book Cover: Writing Code No One Else Can Read&#34; data-action=&#34;zoom&#34;&gt;
&lt;p&gt;Have you ever opened a source file and knew instantly it was written by a specific member of the team because of all the curious syntax choices they made? Perhaps they are green and don’t know the community standards or perhaps they spend most of their days in another language which has its own preferred style. What do you do?&lt;/p&gt;
&lt;p&gt;Many programmers would agree at a certain level of maturity we look for code consistency in our own work and in our group projects. However manually enforcing a style guide is extremely tedious, error prone and can get personal real quick. The solution is to find tools that automate a community standard and let them enforce if not generate the code patterns for us.&lt;/p&gt;
&lt;p&gt;In this post we’ll introduce and demonstrate one such tool for Swift iOS developers called &lt;a href=&#34;https://github.com/realm/SwiftLint&#34;&gt;SwiftLint&lt;/a&gt;. Its a great first step into a world of consistent code and easy to get integrated into your Xcode project.&lt;/p&gt;
&lt;h2 id=&#34;what-is-swiftlint&#34;&gt;What is SwiftLint?&lt;/h2&gt;
&lt;p&gt;Wikipedia &lt;a href=&#34;https://en.wikipedia.org/wiki/Lint_(software)&#34;&gt;describes a linter&lt;/a&gt; as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lint, or a linter, is a tool that analyze source code to flag programming errors, bugs, stylistic errors, and suspicious constructs. The term originates from a Unix utility that examined C language source code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/realm/SwiftLint&#34;&gt;SwiftLint&lt;/a&gt; is a tool that can scan your Swift code files and generate a list of warnings and errors based on a community provided collection of rules. It has great Xcode integration and online documentation.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;There are a few different ways to install SwiftLint. I’ll review the &lt;a href=&#34;https://brew.sh/&#34;&gt;Homebrew&lt;/a&gt; method as it is the one I prefer. Assuming you have Homebrew already installed, run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install swiftlint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will install a command line tool called &lt;code&gt;swiftlint&lt;/code&gt; and while you can use it from the command line most will want to integrate it with their Xcode project. To do so, you’ll want to add a new Build Phase for your main app target, specifically a Run Script Phase at the end, and insert the following code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; which swiftlint &amp;gt;/dev/null; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  swiftlint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;
&lt;img src=&#34;xcode-build-phase.png&#34; alt=&#34;Xcode Build Phase Editor&#34; data-action=&#34;zoom&#34;&gt;
&lt;figcaption&gt;Xcode Build Phase Editor&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This script will look for the &lt;code&gt;swiftlint&lt;/code&gt; command line tool. If found, it will run it on your project&amp;rsquo;s source files. If not found, it will still allow the build to finish but will post a short message to the console.&lt;/p&gt;
&lt;h2 id=&#34;swiftlint-in-action&#34;&gt;SwiftLint In Action&lt;/h2&gt;
&lt;p&gt;With &lt;code&gt;swiftlint&lt;/code&gt; installed and your Xcode project setup, you now will experience new inline warnings and errors, helping to identify code that might lean away from community standards. Sometimes the warnings or errors will even offer automated fix options too.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;xcode-editor.png&#34; alt=&#34;Warnings and Errors in Xcode Editor&#34; data-action=&#34;zoom&#34;&gt;
&lt;figcaption&gt;Warnings and Errors in Xcode Editor&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;customizing-the-rules&#34;&gt;Customizing the Rules&lt;/h2&gt;
&lt;p&gt;Out of the box &lt;code&gt;swiftlint&lt;/code&gt; will enforce a small subset of the 166 (and growing) rule collection. You can however customize the rules you want to enforce on your project by adding a &lt;code&gt;.swiftlint.yml&lt;/code&gt; configuration file to the root of your project. Here you can explicitly opt in or disable rules. You can also configure file paths to exclude from rule matching (like &lt;code&gt;Pods&lt;/code&gt; or &lt;code&gt;Carthage&lt;/code&gt;). You can even configure some rules, defining the thresholds you want to be held accountable to (think file line size or method line size). More details on this configuration is in the &lt;a href=&#34;https://github.com/realm/SwiftLint/blob/master/README.md&#34;&gt;SwiftLint README&lt;/a&gt;. A &lt;a href=&#34;https://github.com/realm/SwiftLint/blob/master/Rules.md&#34;&gt;full list of Rules&lt;/a&gt; is also well documented.&lt;/p&gt;
&lt;p&gt;If you want to turn a rule off for individual occurrences, check out the inline &lt;code&gt;disable&lt;/code&gt; and &lt;code&gt;enable&lt;/code&gt; options:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// swiftlint:disable colon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; noWarning :String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// No warning about colons immediately after variable names!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// swiftlint:enable colon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; hasWarning :String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// Warning generated about colons immediately after variable names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Personally I recommend turning on all the rules to get started. If you have a previous code base this will probably result in hundreds of warnings and errors but you can easily filter these errors in Xcode to see them, one by one.&lt;/p&gt;
&lt;p&gt;When I first started using SwiftLint in a larger project, I did this rule by rule, either fixing the code issues and committing the changes or adding the rule to the disabled list. It took a few hours but was a great way to learn what people considered good standards.&lt;/p&gt;
&lt;h2 id=&#34;related-projects&#34;&gt;Related Projects&lt;/h2&gt;
&lt;p&gt;SwiftLint has been my personal go-to tool of choice but if you want to compare some related projects checkout:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sleekbyte/tailor&#34;&gt;GitHub - sleekbyte/tailor: Cross-platform static analyzer and linter for Swift.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nicklockwood/SwiftFormat&#34;&gt;GitHub - nicklockwood/SwiftFormat: A code library and command-line formatting tool for reformatting Swift code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Jintin/Swimat&#34;&gt;GitHub - Jintin/Swimat: An Xcode formatter plug-in to format your swift code.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/oclint/oclint&#34;&gt;GitHub - oclint/oclint: A static source code analysis tool to improve quality and reduce defects for C, C++ and Objective-C&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/realm/SwiftLint&#34;&gt;SwiftLint&lt;/a&gt; is a easy to install and configure tool that helps you add some code consistency to your Swift Xcode projects. It helps you avoid manual style checks during code reviews leaving more time to focus on actual code quality.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The README File</title>
      <link>https://mikezornek.com/posts/2019/1/professional-ios-projects-the-readme-file/</link>
      <pubDate>Tue, 08 Jan 2019 12:51:32 -0500</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2019/1/professional-ios-projects-the-readme-file/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is part of a series, &lt;a href=&#34;https://mikezornek.com/professional-ios-projects/&#34;&gt;Professional iOS Projects&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One of the most crucial documents in any project is its README file, a plain text file (sometimes formatted in &lt;a href=&#34;https://kirkstrobeck.github.io/whatismarkdown.com/&#34;&gt;Markdown&lt;/a&gt;) located in the root of the project directory, clearly named, usually in all caps, README.&lt;/p&gt;
&lt;p&gt;README is the initial point of contact for product owners, current and future developers and sometimes end users. Even if your project is a solo private endeavor taking the time to produce a good REAME file will answer many questions your future self will have.&lt;/p&gt;
&lt;h2 id=&#34;core-components&#34;&gt;Core Components&lt;/h2&gt;
&lt;h3 id=&#34;project-name-and-branding&#34;&gt;Project Name and Branding&lt;/h3&gt;
&lt;p&gt;Name, tagline, logo, and a short description help market and explain what this project is all about. If available, links to more detailed marketing sites is also helpful.&lt;/p&gt;
&lt;h3 id=&#34;project-status&#34;&gt;Project Status&lt;/h3&gt;
&lt;p&gt;Many project, particularly open source ones, like to promote their own status regarding test coverage, current versions, continuous integration, and more. Sometimes this comes in the form of small clickable badge images.&lt;/p&gt;
&lt;p&gt;Other helpful links for this section would be to a modern CHANGELOG file and Release Note document.&lt;/p&gt;
&lt;h3 id=&#34;feature-list&#34;&gt;Feature List&lt;/h3&gt;
&lt;p&gt;Included towards the top, the goal of this feature list section is to help people understand a project&amp;rsquo;s core competencies and if it is a good match for their needs. Don’t be afraid to embed high level architectural graphs, screenshots thumbnails or links to screencast demos. There is no reason a README should be text only.&lt;/p&gt;
&lt;h3 id=&#34;installation-and-getting-started&#34;&gt;Installation and Getting Started&lt;/h3&gt;
&lt;p&gt;Dedicated to the users, this section should help people understand what it takes to get to a working version of this software stood up. If prebuilt binaries are available, those should be the linked and recommended.&lt;/p&gt;
&lt;p&gt;If there are other setup needs those should be documented here as well. The basic goal is to help the user get to a Hello World demo of the core competency of the project. When it comes to more complex configuration settings, those should probably live in the main documentation, help system.&lt;/p&gt;
&lt;h3 id=&#34;development-and-contribution&#34;&gt;Development and Contribution&lt;/h3&gt;
&lt;p&gt;Dedicated to the current and future developers of the project, this section should help someone who wants to contribute or test a development version of the project how to get their environment prepped and how to build the code base.&lt;/p&gt;
&lt;p&gt;If there are processes for contributing bug reports, pull requests or documentation updates those should be documented here as well.&lt;/p&gt;
&lt;p&gt;If you have specific code style guidelines, those should also be linked to.&lt;/p&gt;
&lt;p&gt;Try not to make too many assumptions (we were all green devs at some point) and be as detailed as possible.&lt;/p&gt;
&lt;h3 id=&#34;deployment&#34;&gt;Deployment&lt;/h3&gt;
&lt;p&gt;Deployment can mean a lot of different things to different projects but it doesn’t hurt to have a short summary in the README with more details in a separate guide.&lt;/p&gt;
&lt;p&gt;If you have an active TestFlight beta page, link to it here.&lt;/p&gt;
&lt;h3 id=&#34;links&#34;&gt;Links&lt;/h3&gt;
&lt;p&gt;While many will encounter your README on places like GitHub, project repos can be moved around, archived, and so on. For that and general convenience, it’s a great idea to have a raw list of project links. From a project’s home page to it’s repository URL to other things like issue trackers, support forums and related blog posts.&lt;/p&gt;
&lt;p&gt;If you want to be really helpful link to your competition and other related projects too.&lt;/p&gt;
&lt;h2 id=&#34;licensing&#34;&gt;Licensing&lt;/h2&gt;
&lt;p&gt;To help make it clear what others can do with this project it’s important to pick and document your license. A LICENSE file is a great place for the full legal speak, but a one liner and link on the README can answer most people&amp;rsquo;s questions in a single glance.&lt;/p&gt;
&lt;p&gt;If you need help picking a license &lt;a href=&#34;https://choosealicense.com/&#34;&gt;help is available.&lt;/a&gt; Also keep in mind the license of any third-party code libraries you are using, be sure to reference those as well.&lt;/p&gt;
&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/awesome-labs/iOS-readme-template&#34;&gt;awesome-labs/iOS-readme-template&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;README.md template for your iOS open-source projects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;apple-radar-bug-report&#34;&gt;Apple Radar Bug Report&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;#47121832&lt;/code&gt; - Xcode Project Templates should come with a opinionated README template.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have a suggested edit or addition, &lt;a href=&#34;https://mikezornek.com/contact&#34;&gt;let me know&lt;/a&gt;. See you next time for &lt;a href=&#34;https://mikezornek.com/posts/2019/1/new-series-anatomy-of-a-modern-ios-project/&#34;&gt;Anatomy of a Modern iOS App&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New Series: Professional iOS Projects</title>
      <link>https://mikezornek.com/posts/2019/1/new-series-professional-ios-projects/</link>
      <pubDate>Tue, 08 Jan 2019 12:40:03 -0500</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2019/1/new-series-professional-ios-projects/</guid>
      <description>&lt;p&gt;One of the lessons learned from &lt;a href=&#34;https://pragprog.com/book/tpp/the-pragmatic-programmer&#34;&gt;The Pragmatic Programmer&lt;/a&gt; by Andrew Hunt and David Thomas is to &lt;strong&gt;learn a new language every year&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut. Additionally, learning many languages is far easier now, thanks to the wealth of freely available software on the Internet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the last few years I’ve really tried to take this to heart and have worked with and dabbled in lots of languages, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Objective-C&lt;/li&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Elm&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Elixir&lt;/li&gt;
&lt;li&gt;Swift&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;…and related frameworks/tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ember&lt;/li&gt;
&lt;li&gt;ReactJS&lt;/li&gt;
&lt;li&gt;Rails&lt;/li&gt;
&lt;li&gt;Phoenix&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that context, one of the biggest issues I have with iOS development is that &lt;strong&gt;our projects, as a community, lack professional consistency&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you open a project in any of the frameworks I mentioned above you’ll find very specific places for each piece of the codebase; you’ll find code generators that follow these patterns for new files and tests; you’ll find community accepting tooling standards for bringing it all together. This consistency takes a whole world of questions and decisions off the table making your development life so much easier.&lt;/p&gt;
&lt;p&gt;On iOS, every Xcode project is its own unique beast. There are some patterns we get from UIKit but it only gets us so far.&lt;/p&gt;
&lt;p&gt;I feel like Apple has dropped the ball. In my opinion, Xcode should have more opinionated and structured project templates to offer. It should have open integration to third-party project templates to easily allow the community to drive us forward. Following “good practices” like migrating code to frameworks, should be easier. Testing should be more streamlined. Failure to add inline documentation should cause warnings. I can go on and on, and I will.&lt;/p&gt;
&lt;p&gt;“Professional iOS Projects” is a new blog series where I want to explore what we can do to improve our iOS projects. Apple of course drives us with its closed-sourced, time limited Xcode release schedule, but there is plenty we can work on ourselves, from lint tools to documentation, testing, folder structure, system design and more. It’s a series that could go on forever. 😱&lt;/p&gt;
&lt;p&gt;The first post is ready. It’s all about &lt;a href=&#34;https://mikezornek.com/posts/2019/1/professional-ios-projects-the-readme-file/&#34;&gt;the README file&lt;/a&gt;. Please check it out and &lt;a href=&#34;https://mikezornek.com/contact&#34;&gt;let me know&lt;/a&gt; what you think. I also welcome topic ideas for future articles.&lt;/p&gt;
&lt;p&gt;Going to shoot for a weekly release schedule so grab that &lt;a href=&#34;https://mikezornek.com/index.xml&#34;&gt;RSS feed&lt;/a&gt; and join me.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I&#39;m Teaching a Half Day iOS Refactoring Workshop in July</title>
      <link>https://mikezornek.com/posts/2017/6/im-teaching-a-half-day-ios-refactoring-workshop-in-july/</link>
      <pubDate>Mon, 12 Jun 2017 15:38:30 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2017/6/im-teaching-a-half-day-ios-refactoring-workshop-in-july/</guid>
      <description>&lt;p&gt;When I re-entered the self-employed world last March and launched &lt;a href=&#34;http://zornlabs.com/&#34;&gt;Zorn Labs LLC&lt;/a&gt; one of my main goals was to find a way to continue my education work. The first output of this effort has been workshops, specifically one on Refactoring iOS.&lt;/p&gt;
&lt;p&gt;I’ve developed and taught the workshop for a local development studio &lt;a href=&#34;https://tonicdesign.com/&#34;&gt;Tonic Design&lt;/a&gt; and am now going to run it publicly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://zornlabs.ticketleap.com/ios-refactoring-workshop/details&#34;&gt;iOS Refactoring Workshop&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Throwing away bad code and writing something new from scratch is both risky and expensive. You need to avoid this temptation and instead learn to master small improvements over time.&lt;/p&gt;
&lt;p&gt;Refactoring is the art of improving code without changing user behavior. Adding dedicated refactoring time to your workflow and sprints can pay for itself many times over in both added source code flexibility and application stability.&lt;/p&gt;
&lt;p&gt;In this workshop we will review refactoring concepts from a high level and then explore example cases found in many iOS projects. As a group we’ll refactor and discuss the benefits of our changes. We’ll then work on our own (or in pairs) to execute what we’ve learned and then demonstrate the results for the class.&lt;/p&gt;
&lt;p&gt;This workshop is targeted at those iOS developers who are getting over the hump of learning iOS and now want to know how to write higher quality iOS code. This workshop is capped at 12 people to make sure there is plenty of time for questions and individual attention.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tickets for the half day workshop cost $189.00 even (we take care of all the ticketing fees). For more information on the agenda, see &lt;a href=&#34;https://zornlabs.ticketleap.com/ios-refactoring-workshop/details&#34;&gt;the event page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;TICKETS NO LONGER FOR SALE&lt;/p&gt;
&lt;p&gt;Local performances of this workshop (and others in development) are available for corporate purchase. &lt;a href=&#34;mailto:zorn@zornlabs.com&#34;&gt;Contact us&lt;/a&gt; for more information.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Regarding Knight Rider and Delegation</title>
      <link>https://mikezornek.com/posts/2016/8/regarding-knight-rider-and-delegation/</link>
      <pubDate>Tue, 02 Aug 2016 22:14:36 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2016/8/regarding-knight-rider-and-delegation/</guid>
      <description>&lt;p&gt;One of the saddest aspects of being a &lt;a href=&#34;https://www.bignerdranch.com/&#34;&gt;Big Nerd Ranch&lt;/a&gt; instructor in 2016 is that students these days do not appreciate the Michael Knight is to Delegation, as RoboCop is to Subclassing discussion of yesteryear.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&#34;http://amzn.to/2aOLIBx&#34;&gt;Cocoa Programming for OS X: The Big Nerd Ranch Guide&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Delegation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s start with a story: Once upon a time, there was a man with no name. Knight Industries decided that if this man were given guns and wheels and booster rockets, he would be the perfect crime-fighting tool. First they thought, “Let’s subclass him and override everything we need to add the guns and wheels and booster rockets.” The problem was that to subclass Michael Knight, they needed to wire his insides to the guns, wheels, and booster rockets – a time-consuming task requiring lots of specialized knowledge. So instead, Knight Industries created a helper object, the Knight Industries 2000, or “KITT,” a well-equipped car designed to assist Michael Knight in a variety of crime- fighting situations.&lt;/p&gt;
&lt;p&gt;While approaching the perimeter of an arms dealer’s compound, Michael Knight would say, “KITT, I need to get to the other side of that wall.” KITT would then blast a big hole in the wall with a small rocket. After destroying the wall, KITT would return control to Michael, who would charge through the rubble and capture the arms dealer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Note how creating a helper object is different from the RoboCop approach. RoboCop was a man subclassed and extended. The RoboCop project involved dozens of surgeons who extended the man into a fighting machine. This is the approach taken by many object-oriented frameworks.&lt;/p&gt;
&lt;p&gt;In the Cocoa framework, many objects are extended in the Knight Industries way – by supplying them with helper objects. In this section, you are going to provide the speech synthesizer with a type of helper object called a delegate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What do you think the new metaphor should be?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Quick Launching for Cocoa Unit Tests</title>
      <link>https://mikezornek.com/posts/2015/10/quick-launching-for-cocoa-unit-tests/</link>
      <pubDate>Wed, 14 Oct 2015 01:22:26 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2015/10/quick-launching-for-cocoa-unit-tests/</guid>
      <description>&lt;p&gt;I was doing some proofreading and research today regarding the latest testing features in Xcode 7. In the process I ended up rereading this article from &lt;a href=&#34;https://www.bignerdranch.com/blog/weve-got-you-covered/&#34;&gt;Mark Dalrymple on code coverage&lt;/a&gt;. It’s a great article but it also reminded me of a little tip I wanted to share on the blog.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    // bail out early if we&#39;re running as a test harness.
    if (NSClassFromString(@&amp;quot;XCTestCase&amp;quot;)) return YES;

    // otherwise load the main storyboard.
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@&amp;quot;MainStoryboard&amp;quot; bundle:nil];
    UIViewController *vc = [storyboard instantiateInitialViewController];
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not only can this type of check help speed up your unit test times by a little bit, but, it also makes sure you aren’t loading things like crash log capture tools, performance monitoring injections, or other things that might otherwise interfere with your unit test logic or code coverage numbers. Now if you are doing the new UI testing you’ll probably have to use some other kind of flag to define this path, but regardless the core idea is the same.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Code Patterns Talk, Video Now Available</title>
      <link>https://mikezornek.com/posts/2015/4/code-patterns-talk-video-now-available/</link>
      <pubDate>Thu, 23 Apr 2015 17:09:17 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2015/4/code-patterns-talk-video-now-available/</guid>
      <description>&lt;p&gt;We’ve been trying to a better job of capturing our main talks at &lt;a href=&#34;http://phillycocoa.org/&#34;&gt;Philly CocoaHeads&lt;/a&gt;. You can find and subscribe to our small but growing collection of videos on Vimeo: &lt;a href=&#34;https://vimeo.com/phillycocoa&#34;&gt;https://vimeo.com/phillycocoa&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I did a talk last month reviewing a some iOS code patterns. The runtime is about 27 minutes. &lt;a href=&#34;mailto:mike@mikezornek.com&#34;&gt;Feedback very welcome.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Update April 27, 2025: Video not available.&lt;/p&gt;
&lt;p&gt;Some Code Patterns, Mike Zornek from &lt;a href=&#34;https://vimeo.com/phillycocoa&#34;&gt;Philly CocoaHeads&lt;/a&gt; on &lt;a href=&#34;https://vimeo.com&#34;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This talk covers a handful of code patterns that were successful on my recent projects. Some of these patterns include Block Safety, &amp;ldquo;Tell, Don&amp;rsquo;t Ask&amp;rdquo;, Using DataSources for your network-based *Service objects.&lt;/p&gt;
&lt;p&gt;Apologies the audience participation isn&amp;rsquo;t well captured.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Think of the Smallest Possible Code Change, and Then Make It Smaller</title>
      <link>https://mikezornek.com/posts/2015/4/think-of-the-smallest-possible-code-change-and-then-make-it-smaller/</link>
      <pubDate>Thu, 16 Apr 2015 03:23:25 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2015/4/think-of-the-smallest-possible-code-change-and-then-make-it-smaller/</guid>
      <description>&lt;p&gt;I’m working on a client project right now. We do peer review of the code via pull requests. It works great, but the quality of the reviews you get are very dependent on the size of the pull request you make.&lt;/p&gt;
&lt;p&gt;Take for example, one of my recent pull requests, which had the following git characteristics:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1,780 additions
1,618 subtractions
24 files changed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not my largest pull request ever but still way larger than what I’d prefer. I got zero feedback. It was merged on first pass. Now take one I did the next day:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;80 additions
1 subtraction
7 files changed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We had 10 conversation posts on this pull request, discussing three distinct recommendations and/or questions. Questions on things I was already doing for a few pull requests already but I guess slipped by.&lt;/p&gt;
&lt;p&gt;I don’t blame the reviewer, I blame myself. It’s really hard to be detail focused when there is so much to review.&lt;/p&gt;
&lt;p&gt;So keep those pull requests small and focused. You’ll get better feedback and you’ll probably get integrated faster too!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>An “App Architecture” Kata</title>
      <link>https://mikezornek.com/posts/2014/11/an-app-architecture-kata/</link>
      <pubDate>Mon, 24 Nov 2014 02:00:29 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2014/11/an-app-architecture-kata/</guid>
      <description>&lt;p&gt;At the last &lt;a href=&#34;http://www.meetup.com/PhillyCocoaHeads/events/212626112/&#34;&gt;Side Project Saturday&lt;/a&gt; CocoaHeads event I ran a special little exercise. Here was how I described it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’d like to run a little event, (maybe after lunch?) for anyone who wants to participate. Should take like 45-60m.&lt;/p&gt;
&lt;p&gt;You will be presented with a mobile app idea. It’ll be fairly basic and we’ll list all of the behaviors we need and some we’d like in the future. You will then pair up with someone and pencil out how this could be architected. Each group will then present their app architecture and answer questions, accept feedback from the rest of the group.&lt;/p&gt;
&lt;p&gt;From Wikipedia: A code kata is an exercise in programming which helps a programmer hone their skills through practice and repetition. The term was probably first coined by Dave Thomas, co-author of the book The Pragmatic Programmer, in a bow to the Japanese concept of kata in the martial arts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;App architecture is one of those things I’m always trying to improve so I thought it would be cool to see how other people would solve similar problems.&lt;/p&gt;
&lt;p&gt;We had six people participate. We started with a brief explanation of the app we were going to sketch out an architecture for. Then, we broke up into pairs of two. After about 40 minutes we came back and showed the group what we came up with.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://mikezornek.com/media/images/kata-app-mockup.png&#34;&gt;&lt;img src=&#34;http://mikezornek.com/media/images/kata-app-mockup-thumb.png&#34; alt=&#34;Kata App Wireframe&#34; title=&#34;Kata App Wireframe&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The one group ended up documenting behaviors per screen. They did a great job of documenting the little things that developers might look over as assumed behavior (which add up fast). It was pointed out that it’s also a great idea to document the things you will not be doing since there tends to be lots of great ideas during brainstorms but when you are planning a sprint of a version target you need to be clear about what’s in and what’s out.&lt;/p&gt;
&lt;p&gt;The other two groups (including my own) were more visual, using tools like &lt;a href=&#34;https://www.omnigroup.com/omnigraffle&#34;&gt;OmniGraffle&lt;/a&gt; to draw representation of models, controllers and services. There was some common separation of responsibilities with slight differences: the one group making an “APIStore” that combined the state and networking and another (mine) that favored separate “Network” and “Session” managers.&lt;/p&gt;
&lt;p&gt;Some of the more high-end abstractions I introduced included a FormController that could take a Form model (that had say a collection of FormFields) which described the form at a model level and then through a FormController might be able to render the form on screen through a TableView for a generic representation or maybe through specific outlets to a custom layout. It could also handle things like input validation. True, this is overkill for our one simple login form but assuming this app might grow to contain edit person forms at some point it might not be too bad of an idea (and plus the whole purpose of this event is to discuss interesting ideas).&lt;/p&gt;
&lt;p&gt;I also took the time to introduce a pattern thats been out for a while but is a recent addition to my personal toolkit, that being ViewModel. You can read more about &lt;a href=&#34;http://www.objc.io/issue-13/mvvm.html&#34;&gt;MVVM on objc.io&lt;/a&gt;. In short it’s a great way to centralize the code you use to transform model objects for user interface purposes and keep that logic out of the model.&lt;/p&gt;
&lt;p&gt;In conclusion, everyone who participated seemed to enjoy the exercise and I would encourage you to replicate it amongst your own peers. It’s still up for debate if “Side Project Saturday” is the best venue for such things as many who come have their own stuff to work.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Philly Craftsmanship</title>
      <link>https://mikezornek.com/posts/2014/8/philly-craftsmanship/</link>
      <pubDate>Sun, 03 Aug 2014 00:52:02 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2014/8/philly-craftsmanship/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.meetup.com/Software-as-Craft-Philadelphia/&#34;&gt;Software as Craft Philadelphia&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A community of professionals dedicated to well-crafted software&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Was very happy to attend the inaugural meeting of this group last week. Was a great mix of discussion and hands-on coding/pairing. Thanks to &lt;a href=&#34;http://www.promptworks.com/&#34;&gt;Promptworks&lt;/a&gt; for hosting.&lt;/p&gt;
&lt;p&gt;During the discussions, the Software Craftsmanship North America conference (as well as its &lt;a href=&#34;http://manifesto.softwarecraftsmanship.org/&#34;&gt;manifesto&lt;/a&gt;) were mentioned. You can find a bunch of the conference videos on the &lt;a href=&#34;https://vimeo.com/eighthlight&#34;&gt;eighthlight vimeo channel&lt;/a&gt;. Seems like pretty interesting stuff.&lt;/p&gt;
&lt;p&gt;In related news (since I think all hosts were in attendance at said meeting), I want to give a plug to the podcast &lt;a href=&#34;http://turing.cool&#34;&gt;Turing-Incomplete podcast&lt;/a&gt;. Finally starting to catch up on this Philly showcase of talent and really enjoying the discussions. Keep up the good work!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Focused Testing in Xcode</title>
      <link>https://mikezornek.com/posts/2012/8/focused-testing-in-xcode/</link>
      <pubDate>Mon, 27 Aug 2012 03:10:55 +0000</pubDate>
      <author>mike@mikezornek.com (Mike Zornek)</author>
      <guid>https://mikezornek.com/posts/2012/8/focused-testing-in-xcode/</guid>
      <description>&lt;p&gt;I’ve set a very informal goal to produce content for this blog on a daily basis. We’re not there yet, but before the night is lost, here is a quick Xcode tip I fell into today.&lt;/p&gt;
&lt;p&gt;So I’m using &lt;a href=&#34;https://github.com/RestKit/RestKit&#34;&gt;RestKit&lt;/a&gt; in a client project. In this project we &lt;code&gt;POST&lt;/code&gt; and &lt;code&gt;PUT&lt;/code&gt; lots of records. RestKit does not currently have an option to, when serializing a record, include those record attributes which are &lt;code&gt;nil&lt;/code&gt; as &lt;code&gt;null&lt;/code&gt;s in the resulting &lt;code&gt;JSON&lt;/code&gt;. While there has been an ongoing &lt;a href=&#34;https://github.com/RestKit/RestKit/issues/669&#34;&gt;ticket&lt;/a&gt; for this feature, my own release date is approaching and so I dug in this weekend to see what I could do.&lt;/p&gt;
&lt;p&gt;As part of adding this code, I wanted to run and make additions to the RestKit test suite, but running the whole suite over and over as you are making very specific changes is a bit of a time waste. Here is my Xcode tip.&lt;/p&gt;
&lt;p&gt;When working in an Xcode project that has lots of tests, you can temporarily setup Xcode to only run the tests you are working on by editing the schema. In the schema editor, look for the test action and from there you can expand the test target.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://mikezornek.com/media/images/edit_xcode_schema_to_focus_your_testing.png&#34;&gt;&lt;img src=&#34;http://mikezornek.com/media/images/edit_xcode_schema_to_focus_your_testing.png&#34; alt=&#34;Edit Xcode Schema to Focus Your Testing&#34; title=&#34;Edit Xcode Schema to Focus Your Testing&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You’ll see checkboxes for each test file and they expand further for each test case. Check and uncheck to focus in on the tests you are working around. Hold down the Option key as you click on the checkboxes to turn them all on/off with a single click.&lt;/p&gt;
&lt;p&gt;This can seriously speed up your editing cycle. Just make sure to switch them all back on (or do this change on a schema that isn’t shared in the repo) and verify that the full test suite passes before you commit your changes.&lt;/p&gt;
&lt;p&gt;As for my feature, I think I have it working, but will let things settle down before I generate a nice pull request for the RestKit development branch.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>