Your Website2023-02-27T00:00:00+00:00http://www.nichesoftware.co.nz/Bevan Arpsbevan@nichesoftware.co.nzhttp://www.nichesoftware.co.nz/2023/02/27/api-constructorsUsing Constructors2023-02-27T00:00:00+00:002023-02-27T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>The API we presented <a href="/2023/02/18/api-inconvenience.html">last time</a> had a problem - it required users to remember to call <code class="language-plaintext highlighter-rouge">Initialize()</code> before an instance could be used without problems occurring.</p>
<p>Sometimes this is called <code class="language-plaintext highlighter-rouge">temporal coupling</code>, because the ordering, or timing, of calls need to be just right.</p>
<p>In C#, our object may have a declaration like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ImportOperation</span>
<span class="p">{</span>
<span class="k">public</span> <span class="nf">ImportOperation</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// ... elided ...</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">ServiceClient</span> <span class="n">client</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// ... elided ...</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>and consumption like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">operation</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ImportOperation</span><span class="p">();</span>
<span class="n">operation</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
</code></pre></div></div>
<p>or in Go, the declaration:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">ImportOperation</span> <span class="k">struct</span> <span class="p">{</span>
<span class="c">// ... elided ...</span>
<span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">op</span> <span class="o">*</span><span class="n">ImportOperation</span><span class="p">)</span> <span class="n">Initialize</span><span class="p">(</span><span class="n">client</span> <span class="n">ServiceClient</span><span class="p">)</span> <span class="p">{</span>
<span class="c">// ... elided ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>and consumption:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">operation</span> <span class="n">ImportOperation</span>
<span class="n">operation</span><span class="o">.</span><span class="n">Initialize</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
</code></pre></div></div>
<p>The first, and perhaps most obvious, way to improve things would be to use a constructor, so that an uninitialized instance can’t be obtained in the first place.</p>
<p>In C#, you’d end up with this declaration:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ImportOperation</span>
<span class="p">{</span>
<span class="k">public</span> <span class="nf">ImportOperation</span><span class="p">(</span><span class="n">ServiceClient</span> <span class="n">client</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ... elided ...</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>and this consumption:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">operation</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ImportOperation</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
</code></pre></div></div>
<p>This isn’t a bad approach, but it doesn’t always work.</p>
<p>For one, C# does not have asynchronous constructors, making it impossible to roll <code class="language-plaintext highlighter-rouge">Initialize()</code> into the constructor if it needs <strong>await</strong> when invoked.</p>
<p>Also, Go doesn’t have constructors - and the idiomatic use of uninitialized structs (with useful <em>zero values</em>) would seem to pose a blocker too.</p>
<p>How else can we make the API one with a <em>pit of success</em> where users can’t get things wrong?</p>
http://www.nichesoftware.co.nz/2023/02/18/api-inconvenienceAn Inconvenient API2023-02-18T00:00:00+00:002023-02-18T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine that you’re working on an unreleased project, and you discover a need to extend one of your custom types. There’s some complex initialization required before methods will work properly.</p>
<p>You end up with client code that looks like this in C#:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">operation</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ImportOperation</span><span class="p">();</span>
<span class="n">operation</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
</code></pre></div></div>
<p>or like this in Go:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">operation</span> <span class="n">ImportOperation</span>
<span class="n">operation</span><span class="o">.</span><span class="n">Initialize</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
</code></pre></div></div>
<p>You realize that the API isn’t perfect, so you decide to document the requirement for <code class="language-plaintext highlighter-rouge">Initialize()</code> to be called, and move on.</p>
<p>That’s enough, right?</p>
<p>Well, no.</p>
<p>You’ve forgotten that while documentation is important as a reference, by and large people don’t read documentation unless something has gone wrong. This isn’t because they’re bad people; it’s because they’re focusing on the goal they want to achieve - and that goal probably doesn’t include putting on some soft jazz music and sitting down on a cold winters night with a cup of cocoa in front of a blazing fire to read 20k words of documentation.</p>
<p>How should we modify this API so that our users simply can’t get things wrong in the first place?</p>
<p>If we can find a way to do this, not only do we make things much simpler for anyone consuming our code, but we now have less documentation to write as well.</p>
http://www.nichesoftware.co.nz/2022/09/11/method-archetypesMethod Archetypes2022-09-11T00:00:00+00:002022-09-11T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>How do you decide what methods or functions to write as you’re coding? Here’s a technique that I learned about years ago that guides you towards software with great reusability and easier testability.</p>
<p>As far as practical, I try to write methods and functions that conform to one of three specific method archetypes: <em>Queries</em>, <em>Commands</em>, or <em>Orchestrations</em>.</p>
<p>Aside: I no longer remember where I learned this approach, and a protracted online search has uncovered no leads for me to followup. If you know who came up with this idea, please let me know so that I can give them credit.</p>
<h3 id="definitions">Definitions</h3>
<p>A <em>Query</em> returns information about current state.</p>
<p>Calling a query method makes no observable changes to the internal state of the system, and will return the same value if called multiple times in a row. If you’re calling multiple query methods on an instance, you’re free to reorder those calls without running any risk of changing the semantics of the code.</p>
<p>(The qualification above about <em>observable</em> state changes is important - sometimes a query method will update some internal state. Potential reasons for this include caching, logging, and tracing,.)</p>
<p><em>Commands</em> are about making changes to the state of the system. Typically will have no return value - or possibly only an <strong>error</strong>. Sometimes it’s useful to make these commands idempotent.</p>
<p>An <em>Orchestration</em> is a method that coordinates queries and commands with a specific goal. Often these are short and declarative, with complex logic encapsulated away in other methods.</p>
<h3 id="motivation">Motivation</h3>
<p>The separation between queries and commands makes things more explicit in consuming code - it’s obvious where state changes are being triggered. This helps the predictability of code, making it easier for consuming developers to make required changes without tripping over hidden dependencies or unanticipated changes.</p>
<p>I’ve also found that the separation tends to make testing easier - once an object has been set up, using the query methods to verify is in the desired state is safe.</p>
<h3 id="stacks">Stacks</h3>
<p>A good example of these archetypes in actions can be seen by considering the classic stack data structure.</p>
<p>A minimal definition of a stack consists of a data type with just two methods: <code class="language-plaintext highlighter-rouge">Push()</code> adds something onto the stack, and <code class="language-plaintext highlighter-rouge">Pop()</code> pulls it off again.</p>
<p>Conventionally, we tend to also include <code class="language-plaintext highlighter-rouge">Peek()</code> to read the top item without modifying the stack and <code class="language-plaintext highlighter-rouge">IsEmpty()</code> to check whether there’s anything on the stack in the first place.</p>
<p>This API may be very familiar, but when you look closely it becomes clear that it’s a little odd.</p>
<ul>
<li>We have two different ways to access the item at the top of the stack, both of which would return the same item.</li>
<li>If we’re writing a multi-threaded system, there’s an inherent race condition: If we check for <code class="language-plaintext highlighter-rouge">IsEmpty() == false</code>, our <code class="language-plaintext highlighter-rouge">Pop()</code> can still blow up if some else pops the item first.</li>
</ul>
<p>With method archetypes, we can do better.</p>
<p><code class="language-plaintext highlighter-rouge">Peek()</code> is a classic query - returns the top item off the stack without modifying the stack in any way.</p>
<p>If we’re willing to <strong>throw</strong> or <strong>panic</strong> when called on an empty stack, we can write the method signature very simply:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// C#</span>
<span class="k">public</span> <span class="n">T</span> <span class="nf">Peek</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Go</span>
<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="n">Stack</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">Peek</span><span class="p">()</span> <span class="n">T</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>
<p>(In both languages, I’m assuming a generic stack that contain any item of type <code class="language-plaintext highlighter-rouge">T</code>.)</p>
<p>Alternatively, we could return additional information to let our clients know if there was an item to retrieve:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// C#</span>
<span class="k">public</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="kt">bool</span><span class="p">)</span> <span class="nf">Peek</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Go</span>
<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="n">Stack</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">Peek</span><span class="p">()</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="kt">bool</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>
<p>Our original <code class="language-plaintext highlighter-rouge">Pop()</code> method is a problem, because it combines the functionality of our existing <code class="language-plaintext highlighter-rouge">Peek()</code> query along with an additional state change.</p>
<p>Let’s break out that state changes as a separeate command <code class="language-plaintext highlighter-rouge">Discard()</code>.</p>
<p>To blindly discard the top item, we’d declare as:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// C#</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Discard</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Go</span>
<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="n">Stack</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">Discard</span><span class="p">()</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>
<p>If we desire some idempotency (which can be useful in multi-threaded or multi-processing cases), we can pass the item we’re wanting to discard. We then need to know whether the item was successfully discarded or not:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// C#</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="nf">Discard</span><span class="p">(</span><span class="n">T</span> <span class="n">top</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Go</span>
<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="n">Stack</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">Discard</span><span class="p">(</span><span class="n">top</span> <span class="n">T</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>
<p>Our stack is now fully operational - but if we still want a <code class="language-plaintext highlighter-rouge">Pop()</code> method, we can write one as an orchestration between <code class="language-plaintext highlighter-rouge">Peek()</code> and <code class="language-plaintext highlighter-rouge">Discard()</code>:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// C#</span>
<span class="k">public</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="kt">bool</span><span class="p">)</span> <span class="nf">Pop</span><span class="p">(</span><span class="n">T</span> <span class="n">top</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">result</span><span class="p">,</span> <span class="n">ok</span> <span class="p">=</span> <span class="nf">Peek</span><span class="p">()</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ok</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">Discard</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">result</span><span class="p">,</span> <span class="n">ok</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Go</span>
<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="n">Stack</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="n">Pop</span><span class="p">(</span><span class="n">top</span> <span class="n">T</span><span class="p">)</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">result</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">Peek</span><span class="p">();</span> <span class="n">ok</span> <span class="p">{</span>
<span class="n">s</span><span class="o">.</span><span class="n">Discard</span><span class="p">()</span>
<span class="k">return</span> <span class="n">result</span><span class="p">,</span> <span class="n">ok</span>
<span class="p">}</span>
<span class="k">var</span> <span class="n">zero</span> <span class="n">T</span>
<span class="k">return</span> <span class="n">zero</span><span class="p">,</span> <span class="no">false</span>
<span class="p">}</span>
</code></pre></div></div>
<p>One of the emergent properties of our slightly revised stack definition is that it can be trivially made safe for threading use; we don’t have any temporal coupling between methods, allowing atomic operation to be added purely through internal locks.</p>
<h3 id="conclusion">Conclusion</h3>
<p>This is a very simple introduction to method archetypes, and one that doesn’t really do them justice. I’ve found them to be a useful technique - give it a go and let me know how you get on.</p>
http://www.nichesoftware.co.nz/2022/07/02/bash-puzzle-solvedA bash puzzle, solved2022-07-02T00:00:00+00:002022-07-02T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>When we finished last time, I’d just run a simple bash script with some surprising output.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./provision.sh
<span class="nt">--XISTS</span><span class="o">=</span><span class="nt">--false</span>
resource group exists
</code></pre></div></div>
<p>Seeing the <code class="language-plaintext highlighter-rouge">--</code> show up at the start of the line is odd - where do those characters come from? I expected to see <code class="language-plaintext highlighter-rouge">--</code> at the end of the line, not the start.</p>
<p>What’s happening?</p>
<p>The <code class="language-plaintext highlighter-rouge">--</code> showing up at the start of the line is actually written <em>last</em>, overwriting the initial <code class="language-plaintext highlighter-rouge">$E</code>.</p>
<p>It turns out that the <code class="language-plaintext highlighter-rouge">az</code> command is returning six characters, not five!</p>
<p>Instead of <code class="language-plaintext highlighter-rouge">false</code>, it is returning <code class="language-plaintext highlighter-rouge">false\r</code> - the expected string, with an extra trailing carriage return character.</p>
<p>But why?</p>
<p>Searching online, I found a clue that led me to the root cause of my pain.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>which az
/mnt/c/Program Files <span class="o">(</span>x86<span class="o">)</span>/Microsoft SDKs/Azure/CLI2/wbin/az
</code></pre></div></div>
<p>I was (quite accidentally!) running the Windows version of <strong>az</strong>, which naturally was writing CRLF (<code class="language-plaintext highlighter-rouge">\r\n</code>) at the end of each line of output, instead of the simple LF (<code class="language-plaintext highlighter-rouge">\n</code>) expected by Linux.</p>
<p>On the one hand, it’s kind of nice to have things so smoothly integrated that the Windows version of the Azure CLI works for most uses even from Linux.</p>
<p>On the other hand, I did spend a couple of hours doubting my ability to write a simple bash script because even the simple things didn’t appear to work.</p>
<p>On the gripping hand, installing the Linux version of the Azure CLI was as simple as <code class="language-plaintext highlighter-rouge">sudo apt install azure-cli</code>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>which az
/usr/bin/az
</code></pre></div></div>
<p>And now everything works.</p>
http://www.nichesoftware.co.nz/2022/06/25/bash-puzzleA bash puzzle2022-06-25T00:00:00+00:002022-06-25T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Here’s a bit of a puzzle - all of the clues in this post, and the answer will follow in the next one. It starts with trying to write a simple bash script to create an Azure Resource Group.</p>
<p>Working in my Ubuntu WSL2 environment, I wanted to write a bash shell script that created an Azure Resource Group if a group with that name doesn’t already exist.</p>
<p>The idiomatic way to test whether a resource group exists by using the <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli">Azure CLI tool</a>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>az group exists <span class="nt">--resource-group</span> demogroup
</code></pre></div></div>
<p>This command literally returns either <code class="language-plaintext highlighter-rouge">true</code> or <code class="language-plaintext highlighter-rouge">false</code>, and is designed for use in a conditional test like this one:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create resource group</span>
<span class="k">if</span> <span class="o">[</span> <span class="si">$(</span>az group exists <span class="nt">-n</span> demogroup<span class="si">)</span> <span class="o">==</span> <span class="nb">false</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span>az group create <span class="nt">-n</span> demogroup <span class="nt">--location</span> eastus
<span class="k">else
</span><span class="nb">echo</span> <span class="s2">"resource group exists"</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Unfortunately, when I ran this script fragment, I was dutifully informed the resource group existed:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./provision.sh
resource group exists
</code></pre></div></div>
<p>This in spite of the fact the resource group did not exist!</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>az group exists <span class="nt">-n</span> demogroup
<span class="nb">false</span>
</code></pre></div></div>
<p>I hope you can appreciate that this was quite confusing.</p>
<p>Skipping a whole bunch of failed attempts to solve the problem, I eventually modified the script to pull out the result of the <strong>az</strong> command and write it to the console before the test:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create resource group</span>
<span class="nv">EXISTS</span><span class="o">=(</span>az group exists <span class="nt">-n</span> demogroup<span class="o">)</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="se">\$</span><span class="s2">EXISTS=--</span><span class="nv">$EXISTS</span><span class="s2">--"</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$EXISTS</span> <span class="o">==</span> <span class="nb">false</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span>az group create <span class="nt">-n</span> demogroup <span class="nt">--location</span> eastus
<span class="k">else
</span><span class="nb">echo</span> <span class="s2">"resource group exists"</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Running this script, I got the following surprising output:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./provision.sh
<span class="nt">--XISTS</span><span class="o">=</span><span class="nt">--false</span>
resource group exists
</code></pre></div></div>
<p>This was the clue that I needed to solve the problem - can you solve it too?</p>
http://www.nichesoftware.co.nz/2022/06/11/improve-troubleshooting-aggregate-errorsImprove your troubleshooting by aggregating errors2022-06-11T00:00:00+00:002022-06-11T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In the early days of the web, circa 1995 or so, it was common for the forms on websites to return a single error on submission, identifying only the first field that needed attention. This resulted frequent failed submissions as users would only be able to fix one thing at a time. To say that this made for a laborious and frustrating process would be a massive understatement.</p>
<p>Some of those websites would even return the user to a blank webform, requiring everything to be re-entered from scratch!</p>
<p>Often, users would only persist with completion the form if they had no alternative – which must have resulted in costly abandoned sales for the ecommerce websites of the era.</p>
<p>User experiences became significantly better – and the volume of ecommerce sales increased dramatically – once forms started identifying all the outstanding issues on form submission, allowing users to fix them all in one pass.</p>
<p>We can apply the same lessons to our software by aggregating errors where appropriate and returning them in one go.
In the <a href="https://github.com/azure/azure-service-operator">Azure Service Operator</a> (ASO) code generator we applied this when processing multiple items in a loop.</p>
<p>While one failure in the loop was enough to cause the code generator to fail with a fatal error, we processed all the items in the loop, returning an aggregate of those errors at the end to allow all of the issues to be addressed at one time.</p>
<p>The required code is remarkably simple; we followed a standard pattern using the Kubernetes <code class="language-plaintext highlighter-rouge">errors</code> package, conventially imported as <a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/util/errors"><code class="language-plaintext highlighter-rouge">kerrors</code></a>:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">errs</span> <span class="p">[]</span><span class="kt">error</span>
<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">def</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">defs</span> <span class="p">{</span>
<span class="n">t</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="c">// elided</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="n">errs</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">errs</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
<span class="k">continue</span>
<span class="p">}</span>
<span class="c">// elided</span>
<span class="p">}</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">errs</span><span class="p">)</span> <span class="o">></span> <span class="m">0</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">kerrors</span><span class="o">.</span><span class="n">NewAggregate</span><span class="p">(</span><span class="n">errs</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>While the <code class="language-plaintext highlighter-rouge">NewAggregate()</code> factory has the useful bonus feature of returning a nil if the passed slice is empty (see the <a href="https://github.com/kubernetes/apimachinery/blob/v0.23.6/pkg/util/errors/errors.go#L46">implementation</a>), we usually made an explicit check to ensure we return an explicit nil instead of an invalid result.</p>
<p>By returning all the errors in one go, we enable our users to take remedial action so their next invocation of the generator will successfully execute that stage of processing and (hopefully!) generate the code required for their new custom resource definition.</p>
<p>Taking a few minutes to improve the developer experience (DX) of someone using your code is a worthwhile investment of your time - after all, you’re going to benefit as well.</p>
http://www.nichesoftware.co.nz/2022/05/28/improve-troubleshooting-wrap-errorsImprove your troubleshooting by wrapping errors2022-05-28T00:00:00+00:002022-05-28T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>When managing errors in your code, help out your future self (and anyone else who will be supporting your code in the future) by doing more than the simplest possible thing.</p>
<p>A common approach in Go code is to detect an error and simply pass it up the chain:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">err</span> <span class="o">:=</span> <span class="n">manager</span><span class="o">.</span><span class="n">Process</span><span class="p">()</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">err</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We relearned while working on <a href="https://github.com/Azure/azure-service-operator">Azure Service Operator</a> (ASO) that this approach has all the same flaws as naïve exception handling in C# – by the time details of the error appear in a log file (or are otherwise made available for consumption), it has no context and is difficult to troubleshoot.</p>
<p>In C#, the idiomatic way to manage this is to catch the original exception and wrap it in another for context:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span>
<span class="p">{</span>
<span class="n">manager</span><span class="p">.</span><span class="nf">Process</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span>
<span class="s">"Unable to process events"</span><span class="p">,</span>
<span class="n">ex</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In ASO we made it a standard to (almost) always wrap errors with additional context before passing them up the chain, using the package <code class="language-plaintext highlighter-rouge">github.com/pkg/errors</code>:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">err</span> <span class="o">:=</span> <span class="n">manager</span><span class="o">.</span><span class="n">Process</span><span class="p">()</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">errors</span><span class="o">.</span><span class="n">Wrapf</span><span class="p">(</span><span class="n">err</span><span class="p">,</span> <span class="s">"unable to process events"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A bonus feature of <code class="language-plaintext highlighter-rouge">errors.Wrapf()</code> is that it returns <strong>nil</strong> if the error passed in is already <strong>nil</strong>.</p>
<p>So instead of writing this at the end of a function:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">err</span> <span class="o">:=</span> <span class="c">// … elided …</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">errors</span><span class="o">.</span><span class="n">Wrapf</span><span class="p">(</span><span class="n">err</span><span class="p">,</span> <span class="s">"unable to process events"</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">nil</span>
</code></pre></div></div>
<p>You can just write:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">err</span> <span class="o">:=</span> <span class="c">// … elided …</span>
<span class="k">return</span> <span class="n">errors</span><span class="o">.</span><span class="n">Wrapf</span><span class="p">(</span><span class="n">err</span><span class="p">,</span> <span class="s">"unable to process events"</span><span class="p">)</span>
</code></pre></div></div>
<p>On first encounter, this violated the <em>principle of least surprise</em>, but in the Go ecosystem, this is idiomatic behaviour.</p>
<p>The only exceptions where we didn’t wrap errors was where we could easily verify that the error already contained all the context we’d need.</p>
<p>We found that this made our errors much longer - and much, much, more informative, making troubleshooting much easier.</p>
http://www.nichesoftware.co.nz/2022/05/14/keep-your-promisesKeep your promises2022-05-14T00:00:00+00:002022-05-14T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>One of the best ways to disappoint someone is to break a promise - and this applies both to the software we write and the applications we use as well.</p>
<p>When running tests, the Go compiler has a <code class="language-plaintext highlighter-rouge">-json</code> option allowing you to request output in JSON format. This is useful as it allows those test results to be easily processed by a separate application.</p>
<p>The implied promise is that using the <code class="language-plaintext highlighter-rouge">-json</code> option will give you output in JSON format. This is such an obvious thing that we do not really think about it. We assume that the flag does what it says it does.</p>
<p>Unfortunately, the Go compiler (at least as of version 1.18) breaks this promise - sometimes the output is not JSON at all.</p>
<p>Here’s an example we recently encountered with <a href="https://github.com/Azure/azure-service-operator">Azure Service Operator</a> (ASO).</p>
<p>First, here’s one of the log lines that adheres to JSON format; I’ve formatted it for readability, but in the original output it’s all on one line:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
"Time": "2022-05-14T09:15:45.8395504+12:00",
"Action": "output",
"Package": "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel",
"Output": "ok \tgithub.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel\t4.986s\tcoverage: 13.1% of statements in ./...\n"
}
</code></pre></div></div>
<p>Most of the lines have the same schema.</p>
<p>But some do not.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FAIL github.com/Azure/azure-service-operator/v2/tools/generator/internal/codegen/pipeline [build failed]
</code></pre></div></div>
<p>Pretty safe to say, that’s not JSON - and it broke the <a href="https://github.com/Azure/azure-service-operator/tree/main/v2/tools/mangle-test-json">program that a colleague wrote</a> to summarize our test results.</p>
<p>When you make a promise, your code should keep that promise. This applies whether we’re talking about a command-line option (as in this example), a REST API, or simply the design of your types and methods.</p>
http://www.nichesoftware.co.nz/2022/04/18/when-are-you-doneWhen are you done?2022-04-18T00:00:00+00:002022-04-18T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>How do you tell when you are finished working on a change you are making to the code on your current project?</p>
<p>Do you decide you are finished because you are bored and tired?</p>
<p>Or are you done because the work is tedious, and every change is time consuming to test?</p>
<p>Is it done because you are impatient to get on to the next task and you just can’t be bothered to invest more time in this one?</p>
<p>These are terrible reasons to declare that a change is done – and yet they are reasons that I have been given by many early career software developers while chatting at conferences and code camps.</p>
<p>I have been around in the industry long enough that I have had to pick up the pieces after code like this is shipped and it is never clean, or easy, or tidy, or welcome.</p>
<p>Some fictional examples, partially based on real world situations I have experienced, on stories I have been told, and with the details changed to protect the guilty.</p>
<p>Remember that Excel import process from a couple of years ago that was supposed to look for a tab named with the customer’s Id, but where you hard coded it to use the first tab instead and never went back to fix it? We have just discovered that our analytics for all twelve largest of our largest customers are all corrupt – and identical – because we have been importing the wrong information.</p>
<p>Remember that Github build workflow that runs for every PR to test whether our project works properly across multiple platforms? It has only ever been running the builds on Linux, so we have been releasing untested Macintosh and Windows builds. We now suspect this explains why over 40% of our paying users are on Linux – most of the people who tried out our product on other platforms had a lousy experience, and we’ve lost millions.</p>
<p>Or do you remember your square tiling algorithm where you assumed the GCD of screen width and height would result in at most a few dozen tiles? That did not work so well on low resolution laptops with 1366x768 screens and killed performance completely.</p>
<p>You are not done just because you are bored.</p>
<p>You are not done just because it is tedious.</p>
<p>You are not done just because it works for a few happy path cases.</p>
<p>You are done when the code is complete, and you have verified that it works. All of it.</p>
http://www.nichesoftware.co.nz/2021/11/28/github-password-authenticationFixing GitHub Authentication2021-11-28T00:00:00+00:002021-11-28T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Returning to a project that had lain fallow for several months, I found I was unable to push changes from my work in progress branch up to GitHub.</p>
<p>When I tried to push my branch, I got the following error:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">C:\GitHub\wordtutor\</span><span class="w">
</span><span class="p">[</span><span class="n">feature/update-packages-dotnet6</span><span class="w"> </span><span class="o">+</span><span class="nx">2</span><span class="w"> </span><span class="nx">~0</span><span class="w"> </span><span class="nt">-0</span><span class="w"> </span><span class="o">!</span><span class="p">]</span><span class="w">
</span><span class="mi">11</span><span class="p">:</span><span class="mi">36</span><span class="p">:</span><span class="mi">24</span><span class="w"> </span><span class="n">PS</span><span class="err">></span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="nt">--set-upstream</span><span class="w"> </span><span class="n">origin</span><span class="w"> </span><span class="n">feature/update-packages-dotnet6</span><span class="w">
</span><span class="nx">remote:</span><span class="w"> </span><span class="nx">Support</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">password</span><span class="w"> </span><span class="nx">authentication</span><span class="w"> </span><span class="nx">was</span><span class="w"> </span><span class="nx">removed</span><span class="w"> </span><span class="nx">on</span><span class="w"> </span><span class="nx">August</span><span class="w"> </span><span class="nx">13</span><span class="p">,</span><span class="w"> </span><span class="nx">2021.</span><span class="w"> </span><span class="nx">Please</span><span class="w"> </span><span class="nx">use</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">personal</span><span class="w"> </span><span class="nx">access</span><span class="w"> </span><span class="nx">token</span><span class="w"> </span><span class="nx">instead.</span><span class="w">
</span><span class="n">remote</span><span class="p">:</span><span class="w"> </span><span class="n">Please</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="n">//github.blog/2020-12-15-token-authentication-requirements-for-git-operations/</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">more</span><span class="w"> </span><span class="nx">information.</span><span class="w">
</span><span class="n">fatal</span><span class="p">:</span><span class="w"> </span><span class="n">Authentication</span><span class="w"> </span><span class="n">failed</span><span class="w"> </span><span class="n">for</span><span class="w"> </span><span class="s1">'https://github.com/theunrepentantgeek/wordtutor.git/'</span><span class="w">
</span></code></pre></div></div>
<p>After reading the <a href="https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/">linked page</a> I was somewhat confused as I already had the <a href="https://github.com/GitCredentialManager/git-credential-manager">Git Credential Manager</a> installed; manually setting up a personal access token (PAT) shouldn’t be necessary.</p>
<p>Instead of just failing authentication, I expected the Git Credential Manager to automatically reprompt for my credentials, including 2FA as required. This wasn’t happening.</p>
<p>Upgrading the Git Credential Manager to the latest version by updating <a href="https://gitforwindows.org/">Git For Windows</a> to the latest version didn’t make any difference.</p>
<p>After following a number of dead-end leads, I ended up looking at my global <code class="language-plaintext highlighter-rouge">.gitconfig</code> file, found in my home directory (in my case, <code class="language-plaintext highlighter-rouge">C:\users\Bevan</code>).</p>
<p>Under the <code class="language-plaintext highlighter-rouge">[credential]</code> section, there was a duplicate <code class="language-plaintext highlighter-rouge">helper</code> setting … with a blank value …</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[credential]
helper =
helper = C:/Program\\ Files/Git/mingw64/libexec/git-core/git-credential-manager-core.exe
</code></pre></div></div>
<p>That blank value looked dodgy … so after backing up my <code class="language-plaintext highlighter-rouge">.gitconfig</code> file, I removed the extra:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[credential]
helper =
helper = C:/Program\\ Files/Git/mingw64/libexec/git-core/git-credential-manager-core.exe
</code></pre></div></div>
<p>Then, I retried my push …</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">C:\GitHub\wordtutor\</span><span class="w">
</span><span class="p">[</span><span class="n">feature/update-packages-dotnet6</span><span class="w"> </span><span class="o">+</span><span class="nx">2</span><span class="w"> </span><span class="nx">~0</span><span class="w"> </span><span class="nt">-0</span><span class="w"> </span><span class="o">!</span><span class="p">]</span><span class="w">
</span><span class="mi">11</span><span class="p">:</span><span class="mi">36</span><span class="p">:</span><span class="mi">36</span><span class="w"> </span><span class="n">PS</span><span class="err">></span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="nt">--set-upstream</span><span class="w"> </span><span class="n">origin</span><span class="w"> </span><span class="n">feature/update-packages-dotnet6</span><span class="w">
</span><span class="nx">info:</span><span class="w"> </span><span class="nx">please</span><span class="w"> </span><span class="nx">complete</span><span class="w"> </span><span class="nx">authentication</span><span class="w"> </span><span class="nx">in</span><span class="w"> </span><span class="nx">your</span><span class="w"> </span><span class="nx">browser...</span><span class="w">
</span><span class="n">Everything</span><span class="w"> </span><span class="n">up</span><span class="nt">-to-date</span><span class="w">
</span><span class="n">Branch</span><span class="w"> </span><span class="s1">'feature/update-packages-dotnet6'</span><span class="w"> </span><span class="n">set</span><span class="w"> </span><span class="n">up</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">track</span><span class="w"> </span><span class="n">remote</span><span class="w"> </span><span class="n">branch</span><span class="w"> </span><span class="s1">'feature/update-packages-dotnet6'</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="s1">'origin'</span><span class="o">.</span><span class="w">
</span></code></pre></div></div>
<p>Success!</p>
<p>So if you are failing to authenticate automatically with GitHub (or any upstream repo host), you’re running on Windows, and the Git Credential Manager isn’t automatically prompting you for updated credentials, check your <code class="language-plaintext highlighter-rouge">.gitconfig</code> file.</p>
http://www.nichesoftware.co.nz/2021/07/31/sharpen-the-sawSharpen The Saw - August 20212021-07-31T00:00:00+00:002021-07-31T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: An obsession with primitive types can be a problem; Ways to refactor to introduce semantic types; WSL now supports GUI apps and it’s wonderful; Lessons from Japanese martial arts; How to prepare to break a habit; Spam blogs; Why your sleep excuses are wrong; Morning habits and happiness; and Phil Haack’s most excellent CodeMania 2012 keynote.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="design-smell-primitive-obsession">Design Smell: Primitive Obsession</h4>
<p>Consider the fundamental data types built into your language. Typically they are int, double, string, char, and bool, though the exact set depends on your language. Go includes complex, C# includes DateTime, C++ doesn’t include string, and so on.</p>
<p>Of course, they are extremely useful, but sometimes they’re the wrong solution, often because they admit too wide a range of values.</p>
<p>Over reliance on primitive data types is known as Primitive Obsession and it’s a subtle source of bugs. In this blog post, Mark Seemann gives some good definitions, as well as some useful links for further reading.</p>
<p>Read more: <a href="https://blog.ploeh.dk/2011/05/25/DesignSmellPrimitiveObsession/">https://blog.ploeh.dk/2011/05/25/DesignSmellPrimitiveObsession/</a></p>
<h4 id="code-smell--primitive-obsession-and-refactoring-recipes">Code Smell – Primitive Obsession and Refactoring Recipes</h4>
<p>Over on the <a href="https://blog.ndepend.com/">NDepend blog</a>, Patrick Smacchia makes the case that while primitive types are the real building blocks of your application, over reliance on them can lead to problems.</p>
<p>Within the .NET base class library, a file path is often represented as a string, with a large number of helper methods to work with the path. It turns out that a proper encapsulation (such as that made available via the <a href="https://github.com/psmacchia/NDepend.Path">NDepend.Path</a> NuGet package) is surprisingly complex.</p>
<p>My experience shows the introduction of a simple semantic type to replace use of a primitive type will almost invariably flush out some bugs in the application.</p>
<p>Read more: <a href="https://blog.ndepend.com/code-smell-primitive-obsession-and-refactoring-recipes/">https://blog.ndepend.com/code-smell-primitive-obsession-and-refactoring-recipes/</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="the-initial-preview-of-gui-app-support-is-now-available-for-the-windows-subsystem-for-linux">The Initial Preview of GUI app support is now available for the Windows Subsystem for Linux</h4>
<p>This is exciting - you can now run Linux that require a GUI within WSL2 without having to install a separate X-Server and fight with Windows firewall settings.</p>
<p>Aside: I’ve had an X-Server installed on my work machine for some months, but every time I want to use it, I have had to go back and fight with the Windows Firewall settings because the required exclusions keep getting reset. With this release of WSL2, I don’t have that problem any more, everything just works.</p>
<p>So far I’ve used both GoLand and GitKraken under WSLg and they’ve worked flawlessly.</p>
<p>The only difficulty is that it’s only currently available on the Windows Insider Dev ring, so you have to opt in to a certain amount of instability to get access.</p>
<p>Read more: <a href="https://devblogs.microsoft.com/commandline/the-initial-preview-of-gui-app-support-is-now-available-for-the-windows-subsystem-for-linux-2/">https://devblogs.microsoft.com/commandline/the-initial-preview-of-gui-app-support-is-now-available-for-the-windows-subsystem-for-linux-2/</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="shu-ha-ri">Shu-Ha-Ri</h4>
<p>From Japanese martial arts, Martin Fowler teaches us about the ideas of Shu-Ha-Ri - describing how a person passes through three stages of gaining knowledge. This is both a good way to assess your own progress towards mastery of a subject, but also a good way to think about how to pass on what you now to others.</p>
<p>Read more: <a href="https://martinfowler.com/bliki/ShuHaRi.html">https://martinfowler.com/bliki/ShuHaRi.html</a></p>
<h4 id="four-questions-to-ask-before-you-try-to-make-or-break-a-habit">Four Questions to Ask Before You Try to Make or Break a Habit</h4>
<p>Whether it’s New Year, your Birthday, Lent or some other date on the calendar that’s of significance to you, making resolutions as a way to improve your habits is common. Gretchen Rubin thinks the key to making resolutions that work is to understand what kind of person you are before you begin.</p>
<p>Read more: <a href="https://lifehacker.com/four-questions-to-ask-before-you-try-to-make-or-break-a-1785984612">https://lifehacker.com/four-questions-to-ask-before-you-try-to-make-or-break-a-1785984612</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="the-abercrombie-and-fitch-brown-pants-fiasco-splogs-and-you">The Abercrombie and Fitch Brown Pants Fiasco, “Splogs,” and you</h4>
<p>There are tools out there for creating spam blogs - or splogs. In this article from 2012, Scott Hanselman diggs into one such fake site and finds literally hundreds of clones, all leeching off the Abercrombie and Fitch branding.</p>
<p>Scott summarizes it well: “The internet is way, way, more screwed up than you ever thought.</p>
<p>The goal of the scammers is simple: to get your credit card details and steal from you (or, some variation of the above).</p>
<p>Staying safe on the web is even more of a challenge today than it was back in 2012.</p>
<p>Read more: <a href="https://www.hanselman.com/blog/technical-analysis-the-abercrombie-and-fitch-brown-pants-fiasco-splogs-and-you">https://www.hanselman.com/blog/technical-analysis-the-abercrombie-and-fitch-brown-pants-fiasco-splogs-and-you</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="3-excuses-you-make-for-not-getting-enough-sleep-and-why-theyre-all-wrong">3 Excuses You Make for Not Getting Enough Sleep (and Why They’re All Wrong)</h4>
<p>It’s difficult to over estimate the value of a good nights sleep. If you’re like most people, you don’t get enough sleep - and you can point to a dozen reasons why that happens. In this article, the author argues that they’re actually in control of their three most common reasons.</p>
<p>Read more: <a href="https://medium.com/thrive-global/3-excuses-you-make-for-not-getting-enough-sleep-5306931b7091">https://medium.com/thrive-global/3-excuses-you-make-for-not-getting-enough-sleep-5306931b7091</a></p>
<h4 id="5-things-you-should-do-first-thing-in-the-morning-to-be-happier-all-day">5 Things You Should Do First Thing In The Morning To Be Happier All Day</h4>
<p>How good is your mental health first thing in the morning? If you, like many people, would like a better start to your day, here are five suggestions:</p>
<ul>
<li>Pick a wellness habit, then link it to an a.m. ritual you already have.</li>
<li>Get your phone out of your room.</li>
<li>Talk to yourself…</li>
<li>… and somebody else.</li>
<li>Incorporate gratitude.</li>
</ul>
<p>Read more: <a href="https://www.huffpost.com/entry/morning-routine-happiness_l_6081c788e4b0e7cb020c99a4">https://www.huffpost.com/entry/morning-routine-happiness_l_6081c788e4b0e7cb020c99a4</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="codemania-love-to-code-keynote">CodeMania Love To Code Keynote</h4>
<p>Back in 2012 the keynote for the very first CodeMania conference was delivered by Phil Haack - and it’s purely wonderful.</p>
<p>Audience: Everyone
Duration: 27m</p>
<p>Read more: <a href="http://haacked.com/archive/2012/08/27/codemania-love-to-code-keynote.aspx">http://haacked.com/archive/2012/08/27/codemania-love-to-code-keynote.aspx</a></p>
<p>Watch now: <a href="https://www.youtube.com/watch?v=HYnEhDOKoxA">https://www.youtube.com/watch?v=HYnEhDOKoxA</a></p>
http://www.nichesoftware.co.nz/2021/07/24/gesticulation-driven-developmentGesticulation Driven Development (GDD)2021-07-24T00:00:00+00:002021-07-24T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: While tackling a subtle bug in a complex application, you make a simple change that you think will address the issue. But when you run the tests, a whole bunch of seemingly unrelated tests start to fail. You reverse the change, and they pass again, so it’s most certainly your change causing the problem.</p>
<p>You reapply your fix, run the tests, and a distinct set of unrelated tests start to fail! You stare at the screen in bewilderment. You’re quite literally at a loss for words, reduced to gesturing futilely at the screen because none of this makes any sense at all.</p>
<p>Gesticulation Driven Development is when you don’t quite believe what’s happening on screen in front of you. Muted by frustration, the only way left to express yourself is by waving your hands.</p>
<p>Many developers never experience GDD, preferring instead the vigorous application of Profanity Driven Development.</p>
<p>Sometimes, however, what happens on screen is just so profoundly weird that words fail us.</p>
<p>Effectively responding to a situation involving GDD involves cutting yourself some slack - the computer is only doing what it’s told to do, so there must be a reasonable explanation for the unutterably weird thing you’re observing. A good place to start is by checking your assumptions.</p>
http://www.nichesoftware.co.nz/2021/07/10/magpie-driven-developmentMagpie Driven Development (MDD)2021-07-10T00:00:00+00:002021-07-10T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: Your team has a big release date coming up next month. This is a big deal, as you’re releasing a bunch of new features just prior to the industry’s biggest trade show. This morning you found out to your surprise that one of your senior developers has just about finished developing a critical new web-service. Using Rust.</p>
<p>Literally every other component in your back-end systems has been written in C#, running on the .NET Stack. Much of the foundation work your team has done over the last six months has been to migrate.NET 5, with some components already successfully running on .NET 6 in your test environments. This migration has been driven both by a desire to reduce costs, by switching to Linux servers, and by a desire to position your team well for the future. In other words, you’ve doubled down on .NET as your technology stack.</p>
<p>Investigating, you find out that there’s no compelling business reason for the component to be written in Rust. Not much of a technical reason either. It’s just that the developer involved really wanted to learn the Rust language and related ecosystem of tooling, and they figured this work project was the best place to do that learning.</p>
<p>Magpie Driven Development is when you have developers who want to use something new for no better reason than it’s shiny and fun.</p>
<p>Examples include someone using an unexpected programming language to complete some feature work, as illustrated here; someone picking up a research paper from MIT and using the associated demonstration code as the basis for their design; or someone choosing to use a different library for a given task than the one the team has standardized on.</p>
<p>It’s key to recognize that MDD occurs when developers indulge purely because they want to try something new. There’s little or no benefit to the product group or the wider team, and the change is often shoehorned into place regardless of the appropriateness of the solution.</p>
<p>Often MDD happens covertly – and senior developers get away with this more often than juniors.</p>
<p>Background: The <a href="http://www.nzbirdsonline.org.nz/species/australian-magpie">Australian Magpie</a> is a highly intelligent bird species commonly found in both Australia and New Zealand. They’re known to be highly territorial: I have vivid memories of being attacked by the Magpies living on my grandparent’s farm. They seemed to like going for my knees. Magpies also collect shiny things for their nests.</p>
http://www.nichesoftware.co.nz/2021/07/03/sharpen-the-sawSharpen The Saw - July 20212021-07-03T00:00:00+00:002021-07-03T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: Building a better UI by decomposing CRUD screens; check your certificate expiries in your CI builds; Windows 11 is coming; Visual Studio 2020 is 64 bit; INVEST in your backlog; 7 virtues of software design; PHPs Git server was hacked; Malware targeting Windows containers; FreeBSD’s close call; Space X torment; and What’s new in C# 9.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="decomposing-crud-to-a-task-based-ui">Decomposing CRUD to a task-based UI</h4>
<p>Derek Comartin makes the case in this post that a simple CRUD screen is often the wrong solution for user interaction - and that such screens should be decomposed into independent task-specific screens oriented towards specific user goals. I think he’s right - and that such decomposition is applicable in other areas as well, such as the division of functionality into microservices.</p>
<p>Read more: <a href="https://codeopinion.com/decomposing-crud-to-a-task-based-ui/">https://codeopinion.com/decomposing-crud-to-a-task-based-ui/</a></p>
<h4 id="certificate-expiration-check">Certificate Expiration Check</h4>
<p>Here’s a very simple unit test you may want to include in your continuous integration test suite. It fails the build if you get within 30 days of certificate expiry without rolling them, giving you time to take care of the issue before things actually break.</p>
<p>Read more: <a href="https://github.com/ardalis/CertExpirationCheck">https://github.com/ardalis/CertExpirationCheck</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="announcing-the-first-insider-preview-for-windows-11">Announcing the first Insider Preview for Windows 11</h4>
<p>Perhaps the biggest software update news of the month, Microsoft has announced that all the rumours were true - Windows 11 is coming. Better yet, if you’re enrolled in the Windows Insider program (and you have the resilience for dealing with the frustrations of a pre-beta operating system), you can try it for yourself right now.</p>
<p>The story around hardware requirements is interesting - the announced requirements are for relatively new hardware, yet Microsoft is allowing it to be installed on quite old hardware for testing purposes. For example, I’m running it successfully on an original Surface Pro tablet, circa 2012, and it seems to work just fine. I wouldn’t be surprised to see the requirements adjusted before GA.</p>
<p>Don’t put this on your primary productivity device unless you’re willing to completely reformat the drive and start from scratch if something goes wrong. If you do put this on your primary machine, make sure your backups and replications are running properly so that anything (everything!) you value exists elsewhere too.</p>
<p>Read more: <a href="https://blogs.windows.com/windows-insider/2021/06/28/announcing-the-first-insider-preview-for-windows-11/">https://blogs.windows.com/windows-insider/2021/06/28/announcing-the-first-insider-preview-for-windows-11/</a></p>
<h4 id="visual-studio-2022">Visual Studio 2022</h4>
<p>The next version of Visual Studio is here - and it’s a 64-bit application. This is a change many years in the making, and it promises improved performance and increased reliability for this stalwart development tool. In my own testing, I’ve already found it to be faster, even on some moderately sized solutions just with a handful of projects.</p>
<p>VS2022 installs side by side with any existing installation, so you can audition it without affecting your day to day work. <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022/">Download it here</a></p>
<p>Announcement blog posts:</p>
<ul>
<li><a href="https://visualstudio.microsoft.com/vs/preview/vs2022/">https://visualstudio.microsoft.com/vs/preview/vs2022/</a></li>
<li><a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-1-now-available/">https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-1-now-available/</a></li>
</ul>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="invest">INVEST</h4>
<p>The INVEST mnemonic is one way to capture the characteristics of a useful entry on your product team’s backlog:</p>
<ul>
<li>Independent</li>
<li>Negotiable</li>
<li>Valuable</li>
<li>Estimable</li>
<li>Small</li>
<li>Testable</li>
</ul>
<p>If each feature request or improvement has these characteristics, your velocity as a team will be more predictable.</p>
<p>Read more: <a href="https://en.wikipedia.org/wiki/INVEST_(mnemonic)">https://en.wikipedia.org/wiki/INVEST_(mnemonic)</a></p>
<h4 id="the-7-virtues-of-good-software-design">The 7 Virtues of Good Software Design</h4>
<p>An interesting DZone article where Santiago Garcia suggests that good software has seven important characteristics:</p>
<ol>
<li>Effectiveness</li>
<li>Robustness/safety/reliability</li>
<li>Maintainability</li>
<li>Flexibility</li>
<li>Reusability/portability</li>
<li>Scalability</li>
<li>Efficiency</li>
</ol>
<p>Moreover, they provide a good argument for why these virtues should be considered in this particular order.</p>
<p>Read more: <a href="https://dzone.com/articles/the-seven-virtues-of-a-good-design">https://dzone.com/articles/the-seven-virtues-of-a-good-design</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="phps-git-server-hacked-to-add-backdoors-to-php-source-code">PHP’s Git server hacked to add backdoors to PHP source code</h4>
<p>The PHP project’s primary git server was hacked in an attempt to inject a Remote Code Execution (RCE) vulnerability. With around 80% of the internet running on PHP, successfully injecting an RCE into the platform would have been catastrophic.</p>
<p>Read more: <a href="https://www.bleepingcomputer.com/news/security/phps-git-server-hacked-to-add-backdoors-to-php-source-code/">https://www.bleepingcomputer.com/news/security/phps-git-server-hacked-to-add-backdoors-to-php-source-code/</a></p>
<h4 id="first-known-malware-surfaces-targeting-windows-containers">First Known Malware Surfaces Targeting Windows Containers</h4>
<p>Running a Kubernetes cluster doesn’t absolve you of worry about security concerns. Consider Siloscape, some malware discovered by researchers from Palo Alto Networks specifically designed to escape from a Windows-based container and infect the host Kubernetes node.</p>
<p>Read more: <a href="https://beta.darkreading.com/vulnerabilities-threats/first-known-malware-surfaces-targeting-windows-containers">https://beta.darkreading.com/vulnerabilities-threats/first-known-malware-surfaces-targeting-windows-containers</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="buffer-overruns-license-violations-and-bad-code-freebsd-13s-close-call">Buffer overruns, license violations, and bad code: FreeBSD 13’s close call</h4>
<p>This is a fascinating exploration of the FreeBSD process and how things went very wrong for a few contributors. Fortunately, the problems were caught well before they because of an issue for the wider ecosystem of folks dependent on FreeBSD for day to day work.</p>
<p>Read more: <a href="https://arstechnica.com/gadgets/2021/03/buffer-overruns-license-violations-and-bad-code-freebsd-13s-close-call/">https://arstechnica.com/gadgets/2021/03/buffer-overruns-license-violations-and-bad-code-freebsd-13s-close-call/</a></p>
<h4 id="the-2008-moment-when-triumph-turned-to-torment-for-spacex">The 2008 moment when triumph turned to torment for SpaceX</h4>
<p>An excerpt from the book LIFTOFF, this Ars Technica post paints a vivid picture of the early days of SpaceX, back in 2008</p>
<p>Read more: <a href="https://arstechnica.com/science/2021/03/after-two-failures-spacex-needed-a-win-in-2008-would-it-get-one/">https://arstechnica.com/science/2021/03/after-two-failures-spacex-needed-a-win-in-2008-would-it-get-one/</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="whats-new-in-c">What’s New in C#?</h4>
<p>This video from .NET Conf 2020, recorded in November 2020, has Mads Torgersen and Dustin Campbell, demonstrates many of the new features of C# 9. These two are tremendously smart and they’re fun to listen to as well.</p>
<p>Watch now: <a href="https://channel9.msdn.com/Events/dotnetConf/2020/Whats-New-in-C">https://channel9.msdn.com/Events/dotnetConf/2020/Whats-New-in-C</a></p>
http://www.nichesoftware.co.nz/2021/06/26/rockstar-driven-developmentRockstar Driven Development (RDD)2021-06-26T00:00:00+00:002021-06-26T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: You come into work on Tuesday morning after a four-day holiday weekend to find a cryptic email from one of your best developers describing some changes they just checked into your main branch. In the approximately 112 hours since you thought everyone went home on Thursday afternoon, they’ve been on a kind of technological bender, ripping out the workflow engine your team has painstakingly built and debugged over the last five years and replacing it with an open-source library that loads its configuration out of MongoDB.</p>
<p>The replacement is around 85% complete, with a bunch of necessary unhandled edge cases needing attention. While individual tests run correctly, you can’t run your entire integration test suite because there’s a cross dependency and they can’t run in parallel. There is some documentation, but it’s largely conceptual and leaves out significant details. Half your development team has work in flight that will need to be redone. Most of your customers deploy using Azure Storage and Azure SQL Server, and they’re not going to be happy with the new dependency on an unfamiliar database technology.</p>
<p>Worst of all, your developer isn’t answering their mobile phone and you suspect they’ve turned it off. Their email said they were going to sleep until the weekend, which is great for them but leaves you in a large hole.</p>
<p>Rockstar Driven Development is when you have a developer who does whatever-they-want, whenever-they-want, because they’re considered the golden child who can do no wrong, and because management effectively has no control over them.</p>
<p>A Rockstar developer tends to be particularly good at what they do – and has often delivered substantial value in the past because of their expertise across multiple problem domains. They’ve often built-up considerable trust because of their past efforts, with the result that they’re now largely left to their own recognizance when it comes to what they do.</p>
<p>They are almost always long timers in the team, people who have been around since the earliest days of the company. Sometimes they are founders. Invariably they have deep knowledge of the business, and they’ve contributed a heap of business value with their efforts in the past – but this has contributed to an aura that they can do no wrong.</p>
<p>And this is where it becomes dangerous, as the Rockstar can become disengaged from what the product team needs, focussing instead on what they think is cool, interesting, or desirable.</p>
http://www.nichesoftware.co.nz/2021/06/12/distraction-driven-developmentDistraction Driven Development (DDD)2021-06-12T00:00:00+00:002021-06-12T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: You’re working a critical new feature, one your team anticipates will not only be really popular with your existing users, but which will organically drive growth by attracting a large number of new users. While you’ve been working on this over the last couple of weeks, you’ve noticed a couple dozen minor issues that you fixed as you encountered them. Now your development work is complete, you’ve created a pull request to merge the completed feature into your main branch, ready for release – but almost all of the code changes relate to minor fixes, not the feature itself.</p>
<p>Worse, two of those minor fixes would cause data loss if they got into production, so now you need to carefully reverse those fixes without introducing additional problems.</p>
<p>Distraction Driven Development happens when you include in a lot of unrelated minor changes as you work on a feature, resulting in a branch (or pull request) that addresses many different goals.</p>
<p>Let me be truly clear: the problem here is <em>not</em> that you fixed the minor issues that you saw. You should absolutely fix these issues as you identify them. This kind of ongoing <strong>code gardening</strong> is an important way to maintain, and even improve, the quality of your code over time.</p>
<p>The problem comes when the fixes become comingled with feature work and each other, making it an all or nothing proposition when it comes to accepting or rejecting the change.</p>
<p>Instead, commit the fixes to separate branches and create multiple pull requests, each specific to changes that affect a single area of your product – a single layer, a single assembly, a single service. This is the single responsibility principle of object-oriented development as applied to change.</p>
<p>Splitting up the fixes also serves to share the load of reviewing. A single large pull request is exponentially more difficult to review than a set of much smaller pull requests, each with a separate intent and purpose. As a side effect, small pull requests are easier and quicker to understand, with reviewers more likely to spot subtle errors and mistakes.</p>
http://www.nichesoftware.co.nz/2021/06/05/sharpen-the-sawSharpen The Saw - June 20212021-06-05T00:00:00+00:002021-06-05T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: Avoiding shotgun surgery; why too many parameters is a bad thing; upgrading to .NET 5; Creating a DSL using a Source Generator; Common sense practices to avoid; Why people write bad code; Rethinking passwords; The curious case of the Great Suspender; The importance of checking in with people; and how reviewing a Strangers’ Code can make you smarter.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="shotgun-surgery-what-it-is-and-how-to-stop-it">Shotgun Surgery: What It Is and How to Stop It</h4>
<p>From the NDepend blog, Erik Dietrich talks about the design smell “shotgun surgery” and why it indicates your codebase may be in poor condition. As always, the first step in fixing a problem is to recognize that it exists.</p>
<p><a href="https://blog.ndepend.com/shotgun-surgery/">Read more</a></p>
<h4 id="avoid-too-many-parameters">Avoid Too Many Parameters</h4>
<p>During a code review, Oren Eini noticed something concerning about a couple of the changes. Even though they were just adding some simple parameters to existing methods, he foresaw the changes could lead to problems. Find out what he saw, and how he intends to fix the problem.</p>
<p><a href="https://ayende.com/blog/178721/pr-review-avoid-too-many-parameters">Read more</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="from-net-standard-to-net-5">From .NET Standard to .NET 5</h4>
<p>The new release of .NET brings changes to the way targeting works. Driven by the introduction of a single codebase across multiple platforms, netcoreapp and netstandard are gone. They are replaced by net for cross platform libraries and by a number of platform specific targets.</p>
<p>In this article from Code Magazine, Immo Landwerth (a program manager on the .NET team) goes into all the details you need to know.</p>
<p><a href="https://www.codemag.com/article/2010022">Read more</a></p>
<h4 id="using-c-source-generators-to-create-an-external-dsl">Using C# Source Generators to create an external DSL</h4>
<p>Source Generators are an extremely powerful way to extend the C# compiler. They allow you to generate additional C# code, at compile time, to suit any requirements you have. In this article from the <a href="https://devblogs.microsoft.com/dotnet/">.NET Blog</a>, Luca describes how to implement an external DSL that gets compiled into C# code automatically.</p>
<p><a href="https://devblogs.microsoft.com/dotnet/using-c-source-generators-to-create-an-external-dsl/">Read more</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="5-common-sense-practices-dev-teams-should-avoid">5 Common-Sense Practices Dev Teams Should AVOID</h4>
<p>In this provocative post from the Axosoft blog, Hamid Shoajaee argues that these five practices should be avoided, not embraced:</p>
<ul>
<li>Treat Team Members the Same</li>
<li>Follow Established Procedures or Processes</li>
<li>Create a Detailed Design Before Starting Development</li>
<li>Make it Difficult to Change Requirements Mid-way</li>
<li>Assign Tasks Based on Resource Availability</li>
</ul>
<p>To find out why Hamid thinks these practices can sometimes be a problem, read their original post.</p>
<p><a href="https://blog.axosoft.com/5-common-sense-practices-you-should-avoid/">Read more</a></p>
<h4 id="3-reasons-why-people-write-insanely-bad-code">3 Reasons Why People Write Insanely Bad Code</h4>
<p>Why is it that some people write bad code? Deepak Karanth has some ideas. In this Dzone article, he outlines three possibilities:</p>
<ul>
<li>The Obvious Reason (they’re bad programmers)</li>
<li>Low Expectations</li>
<li>Programming Books (poor examples)</li>
</ul>
<p><a href="https://dzone.com/articles/3-reasons-why-people-write-insanely-bad-code">Read more</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="the-tyranny-of-passwords--is-it-time-for-a-rethink">The tyranny of passwords – is it time for a rethink?</h4>
<p>It’s a bit of a puff piece, but this article from The Guardian does make some good points about the pitfalls of passwords. The advice to use a password manager is sound - I use LastPass, and I’ve heard 1Password recommended frequently. Also of interest is the fact, almost glossed over, that the flaw of biometrics is that they can’t be changed. Unlike a password, if your fingerprint is compromised, you can’t change it.</p>
<p><a href="https://www.theguardian.com/technology/2021/jan/31/the-tyranny-of-passwords-is-it-time-for-a-rethink">Read more</a></p>
<h4 id="google-disables-and-removes-the-great-suspender-extension-for-containing-malware">Google disables and removes The Great Suspender extension for containing malware</h4>
<p>The curious case of a popular open source Chrome plugin that was sold by the original developer to a new owner, who then decided to do something at least slightly dodgy.</p>
<p><a href="https://www.neowin.net/news/google-disables-and-removes-the-great-suspender-extension-for-containing-malware/">Read more</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="staying-connected">Staying Connected</h4>
<p>Movember Country Director for New Zealand, Robert Dunne, shared this post in April 2020 about the importance of connecting with those we care about. All these months further on, I think his message is still spot on. Robert shares the idea of calling on ALEC (Ask/Listen/Encourage/Check-In) when you connect with someone who might be doing it tough.</p>
<p><a href="https://nz.movember.com/story/view/id/12107/a-message-from-robert-dunne-movember-s-new-zealand-country-director">Read more</a></p>
<h4 id="how-reviewing-strangers-code-on-github-can-make-you-a-better-programmer">How Reviewing Strangers’ Code on GitHub Can Make You a Better Programmer</h4>
<p>Reading an unfamiliar codebase is a particular skill, one that can be worth investing in developing. Taking the time to do this will make you a better developer - in this article, Ryan Pinkham explores why.</p>
<p><a href="https://dzone.com/articles/how-reviewing-strangers-code-on-github-can-make-yo">Read more</a></p>
http://www.nichesoftware.co.nz/2021/05/29/promotion-driven-developmentPromotion Driven Development (PDD)2021-05-29T00:00:00+00:002021-05-29T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: You’re the manager of a development team and you normally give your developers a fair amount of autonomy. There’s a shared backlog of tasks and developers are free to select whatever they like. Your expectation is that they’ll work on a mix of bugs, features, and general product quality improvements – but you’ve noticed some of your mid-level developers are exclusively working on new features, and never on bug fixes or improving quality of existing features.</p>
<p>Quietly chatting it over with one of your most senior developers, the pair of you quickly realise they’re trying to maximize their visibility in the hope of making the threshold for promotion.</p>
<p>Promotion Driven Development is when a developer works on the things that will get them promoted, rather than on the things the product (or the product group) needs.</p>
<p>The most obvious example of this is when someone exclusively works on new product features. It can also show up as someone who always spends their time working directly with important customers already using the product instead of the wider market of potential customers.</p>
<p>The problem here is a mismatch between the needs of the product group and the way that promotions are managed.</p>
<p>If your senior executives need to sign off on promotions, developers will be incentivised to work on projects that have visibility at that level.</p>
<p>If promotion requires delivery of new customer facing features, don’t be surprised when other factors, such as product reliability, ease of testing, developer productivity, build performance and so on are ignored (or left to juniors who have no choice).</p>
<p>Turning the problem around can be an effective way to gauge what’s going on.</p>
<p>If one of your developers wanted to introduce a change that would reduce the number of code defects by 50%, would they be rewarded? What if they could improve the reliability of your integration tests by addressing the causes of flaky tests? Who gets rewarded – the developer who spearheaded a new feature, worked on it for six months and moved their attention somewhere else, or the developer who picked up that new feature and spent six months making it reliable, performant and super easy to use?</p>
http://www.nichesoftware.co.nz/2021/05/15/complaint-driven-developmentComplaint Driven Development (CDD)2021-05-15T00:00:00+00:002021-05-15T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: You are developing a new product feature, requested by one of your company’s most important customers. After nearly a fortnight of work, you’ve almost finished the work – a couple more days and it will be ready for release. This morning your manager asked you to temporarily drop that work so that you can urgently work on a different feature, for a different customer.</p>
<p>When you look at your git branch history, you see that this is the fifth time you’ve put work aside to complete later in the last six months. Worse, you’ve never returned to any of those feature branches – so the very urgent feature work you were doing 5 months ago has never been completed, let alone released. Maybe that feature wasn’t so important anyway, it was for a customer who isn’t a customer anymore.</p>
<p>Complaint Driven Development is when your product roadmap is controlled by “which customer is complaining the loudest” instead of by a specific plan for how you’re going to develop and improve the product.</p>
<p>Very Important Customers occupy a very particular place in the life of any product.</p>
<p>On the one hand, you absolutely need to land a few large customers to validate the product you’re developing, and to bring in enough income for the company (or the product group) to survive.</p>
<p>But on the other hand, the demands of these customers can sometimes be extreme. They know full well that their business is far more important to you than it is to them – and they’ll use that as a lever to get the things they need at your expense.</p>
<p>If the things they’re demanding fit in with your product roadmap, then all is well – if a bit more stressful than you’d like. But all too often, the demands will be for very particular features that won’t really be very much use for other customers, or even for changes that will negatively impact the product by making it confusing for other users.</p>
<p>Maybe you’re building an ecommerce website toolkit, aimed at allowing small businesses to move quickly and easily to selling their goods and services online – and your major customer is insisting on an SAP integration.</p>
<p>Or, maybe you’re building the next big turn-by-turn navigation mobile app, smart enough to recognize traffic congestion faster so that you can redirect your users to alternative routes before they become congested as well – and you’ve been approached by a major fast-food retailer who wants your app to route drivers past their restaurants and to suggest taking a break when traffic is delayed.</p>
<p>The balancing act is to work out what you’re willing to do to keep these major customers happy enough that they stay as paying customers, but without ceding too much control over your product roadmap.</p>
<p>If you do agree to build a feature for a specific customer, you need to ensure you deliver on the promise. Fail on that and the customer will be more unhappy (and more likely to leave) than if you said “No” up front.</p>
<p>Where possible, build generic features that enhance the product for all stakeholders, instead of something custom for one situation.</p>
<p>For example, …</p>
<p>Instead of an SAP integration, implement an industry standard interface that allows any of your customers to integrate your ecommerce product with their back-end system, regardless of the vendor. Bonus points if the interface you adopt has native SAP support.</p>
<p>Provide your users with multiple options for reroutes and places to take a break by building a way to integrate with multiple places of interests – not just fast-food restaurants, but local tourist destinations, places to park, and children’s playgrounds as well. Keep your users happy by using opt-in, increase your bottom line by allowing multiple advertisers to pay for listings, and built community engagement by bringing tourists into town instead of routing them around it.</p>
<p>I think you get the idea.</p>
<p>Your important customers will naturally request features that make their life easier, not yours. Find the balance point where you can keep them happy while still building features that improve your product and attract other customers as well.</p>
http://www.nichesoftware.co.nz/2021/05/01/profanity-driven-developmentProfanity Driven Development (PDD)2021-05-01T00:00:00+00:002021-05-01T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: You’ve just started working on a new team and you’ve your first task, a simple bug fix to address a problem recently experienced by multiple customers. After pulling the code down onto your development machine, you’ve opened it in for the first time and you can’t quite believe what you’re seeing on screen in front of you.</p>
<p>The code is bad. Everywhere you look, you see problems. Local variables with misleading names, functions that run to thousands of lines of code, business logic squirreled away in the data access layer, injection related security flaws, the list goes on and on.</p>
<p>Before you know it, you’ve deployed your weapons grade vocabulary and your onboarding buddy has started to wonder if you have an undisclosed mental health issue.</p>
<p>Profanity Driven Development occurs when there is a dramatic disconnect between the reality of code you’re reading and the expectations you brought to the table.</p>
<p>While it can be tempting to dismiss all who went before as incompetent jerks who should have their keyboard privileges revoked, perhaps it would be wise to take a step back and take a breath.</p>
<p>I’ve found that there’s an almost universally applicable answer for why dodgy code looks the way it does: History.</p>
<p>Perhaps a summer intern wrote this this code, and they finished up last week to start the second year of their Information Management undergraduate degree. An intern who didn’t have the experience to know any better, and who wrote the best code they could.</p>
<p>Perhaps this code was by the company founder written five years ago, and it’s worked well enough all that time that no one has needed to address any bugs. It might be that your eyes are the first ones to recognize that there are some issues to address.</p>
<p>Or perhaps the company desperately needed to release the first version of their product for the annual industry trade show last month, knowing that the fate of the entire company was at stake. The development team may knowingly cut some corners with the intention of circling back to tidy things up later, and maybe that’s why you’ve joined the team.</p>
<p>Before you start cursing those who went before, find out what they were doing and why they did things that way. You might find out some interesting context with which to re-evaluate your opinions. Or you might just find that knowing their names means you can be considerably more fluent and biting with your profanity.</p>
http://www.nichesoftware.co.nz/2021/04/17/hype-driven-developmentHype Driven Development (HDD)2021-04-17T00:00:00+00:002021-04-17T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Imagine this: You’re the manager of a successful development team and your CFO has just come back from a conference. She walks into your office, slams a magazine down in front of you on your desk, and announces that you’re reimplementing your entire product suite in Rust and Blockchain.</p>
<p>Your company specialises in developing custom e-commerce websites for small businesses using WordPress, a handful of commonly used plugins, spectacular graphics design, and some secret sauce your team has painstakingly built up over the last decade.</p>
<p>What just happened?</p>
<p>Hype Driven Development is when promotion of a technology (whether a news item, magazine article, or conference presentation) gives the impression that it’s the one true solution for a broad category of problems even though the reality is that it’s merely a satisfactory solution for a narrow set of issues.</p>
<p>Your chief finance officer isn’t trying to make your life more difficult. Far from it.</p>
<p>Think about the nature of executive level roles – the so called CxO suite of offices. All the routine decision making happens at lower levels of management. At the top level, the focus is on two different things: Setting overarching business strategy and solving the problems that have been delegated-up because they’re difficult.</p>
<p>So why would your CFO announce such a dramatic change in technological direction for your successful business?</p>
<p>I suspect the most likely reason is that she sincerely believes the change is one that will address a fundamental underlying problem the business is experiencing. It doesn’t matter that her deep expertise is in an unrelated field, somehow, she has become convinced that Rust and Blockchain (in our example) are solutions that you need to adopt. (Alternatively, she might be engaging in an epic troll because she knows you well and knows just how to push your buttons to get an entertaining reaction.)</p>
<p>There are a few ways you could avoid this problem.</p>
<p>One approach would be to prevent your CFO from ever going to another conference, cancel all their magazine subscriptions, as well as placing a strict content filter on their internet browser. This might not go down too well – especially since accountants (and others in the financial industry) have certification requirements for annual professional development that must be satisfied.</p>
<p>More usefully, you should invest in your relationship with your CFO (and others in the executive suite) so they not only have a suitable understanding of the difficulties your team are facing, but also a deep level of trust that you have those challenges well in hand. They need to believe that they can safely focus their problem solving attention elsewhere.</p>
http://www.nichesoftware.co.nz/2021/04/03/other-development-methodologiesThe Other Development Methodologies2021-04-03T00:00:00+00:002021-04-03T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>We’ve all heard of Test-Driven Development (aka TDD), and those of us who’ve been around the block a few times have no double heard of Behaviour Driven Development (BDD) and Domain Driven Development (DDD) as well. But have you heard of their dodgy cousins?</p>
<p>In this series I want to explore a handful of these lesser-known development methodologies, exploring both what they are, and what you might want (or need) to do to address them when they occur.</p>
<p>Aside: If you haven’t read it, Eric Evan’s book <a href="https://www.bookdepository.com/Domain-Driven-Design-Eric-Evans/9780321125217">Domain Driven Design</a> is essential reading for anyone developing software for complex business domains. While stemming from the precepts of object-oriented design, the ideas he discusses are relevant regardless of the architectural style you choose.</p>
http://www.nichesoftware.co.nz/2020/12/05/dont-be-that-personDon't be that person2020-12-05T00:00:00+00:002020-12-05T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Nearly 15 years ago, I found myself with a particular problem at work. I felt like I was not being very productive, so I started closely tracking where my time was going.</p>
<p>I used the <a href="https://davidseah.com/node/the-emergent-task-timer/">emergent task timer</a> from <a href="https://davidseah.com/">David Seah</a>’s <strong>Printable CEO</strong> collection as a way to keep track of what I was doing for each 15-minute interval of my day. I had some idea of what I might find, but tracking reality was the best way to find out what was going on.</p>
<h4 id="what-did-i-find">What did I find?</h4>
<p>I was spending most of my time in Outlook. Second place went to Word. This was considerably sub-optimal for a software developer who considered writing code (with Visual Studio) as the primary way to deliver business value. Not much wonder I felt both under-productive and over-stressed.</p>
<p>When I investigated where my time in Outlook was going, I discovered that I was spending the majority of the time in conversation via email, reading and replying to an endless tsunami of emails.</p>
<p>I had developed a habit, with all good intentions, of quickly responding to my immediate colleagues when they emailed me. I did this out of a sense of obligation because I didn’t want them to be blocked waiting for an answer from me. Most of the emails were short and easy to write, so I had not noticed how much time they were taking up.</p>
<p>Over several years, I had inadvertently trained my colleagues to expect quick answers to their emails no matter when they sent them. Whether it was first thing in the morning or last thing in the afternoon, they’d likely have a response to their question within minutes.</p>
<p>I’d made it easier for them to email me and ask a question than for them to find the answer themselves. This was true even when their inboxes contained the answer because I’d previously answered the exact same question. I was repeating myself quite a lot, answering the same queries over and over again.</p>
<p>In effect, I’d trained some of my colleagues to be lazy.</p>
<h4 id="an-illustration">An illustration</h4>
<p>There was an occasion when we had a production outage that required up a follow-up post mortem. I wrote it up as a comprehensive email that covered all of the issues, detailed a complete timeline, identified many of the causal factors, and listed several actions that we would take to make sure the problem never happened again.</p>
<p>This email triggered an ongoing conversation for the following couple of weeks. One of my colleagues wanted to know more and asked a series of detailed follow up questions to clarify their understanding.</p>
<p>I answered <em>every one</em> of those questions by copy and paste of the relevant fragment from my original email.</p>
<p>Should I have done that? Probably not. I ended up having a rather difficult conversation with my manager, who was somewhat sympathetic to my grievances but not very approving of my actions.</p>
<p>The underlying problem was not really with the way my lazy colleague skipped reading the original email and asked questions that had already been answered, it was this:</p>
<blockquote>
<p>I had trained my colleagues that it was faster, easier, and more accurate to ask me the same questions over and over again than to find the answer for themselves.</p>
</blockquote>
<h3 id="time-for-a-change">Time for a change</h3>
<p>It was time to change the status quo for the better.</p>
<p>I started reviewing my email three times a day. First thing in the morning I’d triage my emails and answer anything urgent that had come in overnight. After lunch, I’d clear my inbox completely (aiming for inbox-zero, but with a timebox to limit how long I spent on email), and finally a quick review of messages at the end of the day in case any needed a quick response before I left.</p>
<p>Most of the people on my team adjusted quickly to my new practice, but there were a few who took several months to adapt, finding it frustrating that they no longer got a quick response to random questions at any time of the day.</p>
<p>The real benefit from my perspective, however, was that I got to spend much more of my time delivering business value by writing code, instead of spending my time in brief conversations it via email.</p>
<p>Being deliberate and introspective on my email habits lead to some useful lessons.</p>
<h4 id="busy-people-dont-read-long-emails">Busy people don’t read long emails</h4>
<p>People who are extremely busy (and those who want to look as though they are busy) will seldom read more than the very first sentence or two of an email message. Sometimes they only read the subject line. It’s therefore vital to make sure both that your subject is accurate and that you get to the point very quickly in your message. I’ve found <a href="http://five.sentenc.es/">five.sentec.es</a> a useful website in this regard.</p>
<h4 id="email-is-a-really-bad-way-to-have-a-conversation">Email is a really bad way to have a conversation</h4>
<p>Conversations in email seldom get anything useful done. They are typically protracted and seldom come to any actual decision. Often, a response will address only one or two of the things that have come up so far, with other issues being dropped. It’s also common for email threads to go around in cycles, relitigating things already discussed. All this simply because <em>busy people don’t read long emails</em>.</p>
<h4 id="email-is-a-good-way-to-make-a-record-of-a-conversation">Email is a good way to make a record of a conversation</h4>
<p>It’s a far better idea to actually have a conversation, to actually talk to your colleagues. This might be in real life, or perhaps via a Teams (Skype? Zoom?) call. We’re well-adapted as a species for face to face communication. Afterwards, capture a summary of the discussion and share it with interested parties by email. Explicitly call out any decisions made and any actions required as follow up.</p>
<h4 id="subject-lines-are-important">Subject lines are important</h4>
<p>We all have a limited amount of attention - and with an email, you are asking the recipient to spend some of that attention on you. Making your subject line concise and engaging is a good way to gain that attention - and poor subject lines a good way to encourage them to skip to the next message. Which of these subject lines is more likely to grab your attention?</p>
<ul>
<li>RE: CCW2020</li>
<li>Would you sponsor Code Camp Wellington 2020 in October?</li>
</ul>
<h4 id="conclusions">Conclusions</h4>
<p>It’s easy to spend far too much of your time moving email messages around instead of creating business value. Being deliberate and introspective about your use of email can, for most people, free up significant time to work on other things. By doing this, I gained back control of my time and was able to deliver on my commitments.</p>
http://www.nichesoftware.co.nz/2020/07/04/excel-weapon-mass-destructionWeapons of mass (privacy) destruction2020-07-04T00:00:00+00:002020-07-04T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>It seems that the details of the eighteen people in New Zealand with positive COVID-19 tests have been disclosed, and officials are speculating that it may have been due to human error:</p>
<blockquote>
<p>“I have been advised by the Ministry of Health that at this stage it cannot be confirmed beyond doubt whether a deliberate leak was involved or if this was simply human error,” Chris Hipkins, who is also States Services Minister, said. (<a href="https://www.stuff.co.nz/national/health/122036788/state-services-commission-investigating-privacy-breach-of-quarantined-covid19-patients">Stuff.co.nz</a>)</p>
</blockquote>
<p>(For foreign readers, Chris Hipkins is our freshly minted Minister of Health; he’s the elected official in charge of the New Zealand Health system. I’m also aware that we’re in an enviable position here in New Zealand, with a total of just 18 active COVID-19 cases.)</p>
<p>This isn’t the first privacy breach, and it likely will not be the last.</p>
<p>What strikes me, however, is the constant in all of these discussions: The error is attributed to human error, and the solution is always for humans to improve.</p>
<p>But here’s the thing.</p>
<p><em><strong>Humans make mistakes.</strong></em></p>
<p>This is so universal that it’s practically part of the definition of what it means to be human.</p>
<p>Instead of blaming one specific person, let’s take a step back and look at the whole system.</p>
<p>After all, our solution to injury rates in car crashes isn’t just to tell drivers to be more careful (though we <em>do</em> do that). Cars have seat-belts, airbags, crumple zones, anti-lock braking, blind-spot and lane departure warnings. Recent models have autonomous emergency braking.</p>
<p>We don’t rely on drivers avoiding mistakes, we improve the system around them so that fewer mistakes are made, and those mistakes have reduced consequences.</p>
<p>Reading between the lines on this case, and on many similar ones that have featured in the media over the last several years, I’ve noticed a common theme:</p>
<p><em><strong>Sensitive information stored in a file.</strong></em></p>
<p>I think this is a critical error that’s being made over and over again, every day.</p>
<p>As soon as you put sensitive information into a file, you’re just one action, one mistake, one human error away from a breach. It doesn’t matter whether the file is a spreadsheet, a word processor document, a PDF file, or something else.</p>
<p>Here’s an illustration. Some years ago, I worked on a system that managed a whole lot of data, including some that was extremely commercially sensitive. One of the key features of the system was an export to Excel feature that allowed for some pretty advanced data analysis. I added a feature to tag those Excel files as sensitive if any of the information exported had restricted disclosure rules. One of my colleagues protested that this wasn’t needed because the analysts wouldn’t make that kind of mistake … I did it anyway, and then (some months later) I got to see the logs showing how many disclosures had been blocked. Turns out they did make that kind of mistake after all.</p>
<p>Here are some ideas on ways to do better …</p>
<p><strong>Provide an online way to view sensitive information</strong> instead of dumping it into a file in the first place, provide a way for the right people to see the information online. There are secure ways to do this that can often be set up in a day or less, depending on the nature of the information and your security needs. Not only does this ensure that legitimate users are seeing up to date information (the information in a file can go stale), it means that incompetent or malicious users have to work harder to breach your system.</p>
<p><strong>Flag files as sensitive</strong> if they contain sensitive information. If you have a document management system, it should tag appropriate documents as sensitive automatically. If you have a system that allows exporting of information to a file, it should tag that file if needed. For example, there’s a standard way (and simple) to do this for Excel documents.</p>
<p><strong>Never distribute sensitive information by email</strong>. Once you commit the information into a file and send it to someone else, the information is no longer under your control. If you send it to the wrong person, you have a breach. If you send it to the right person, but they make a mistake, you have a breach. If you send it to the right person, but someone else has access to their email, you have a breach.</p>
<p><strong>Block sensitive files from being emailed</strong> by configuring your organizations’ email gateway to block emails with sensitive files attached. This can be as simple as checking for document metadata, or as complicated as only allowing a file to be sent to someone if their email address is present in the file (this can help prevent files from being sent to the wrong person).</p>
<p>Above all, we all need to do better as an industry. We can’t blame people for making mistakes if the only way they can do their jobs is by taking risks. If we want to avoid breaches caused by the distribution of sensitive information in files, we need to give people a better way to do their jobs.</p>
http://www.nichesoftware.co.nz/2020/06/13/wordtutorCaching without Race Conditions2020-06-13T00:00:00+00:002020-06-13T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>It wasn’t very long after my prior <a href="/2020/05/09/wordtutor-improved-caching.html">update on caching</a> that a friend informed me that the code has a race condition. Yes, the same friend who persuaded me to update it last time. Worse, during a Skype call, we identified code that would outright fail for an independent reason.</p>
<p>Here’s the code, for your consideration. Do you see the problem? I didn’t see it until it was pointed out to me.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">lock</span> <span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_completedRenders</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">existingStream</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">existingStream</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">haveSource</span> <span class="p">=</span> <span class="n">_pendingRenders</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="n">tcsStream</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>What’s the goal of this critical section?</p>
<p>At one level, the goal is to ensure the dictionaries <code class="language-plaintext highlighter-rouge">_completedRenders</code> and <code class="language-plaintext highlighter-rouge">_pendingRenders</code> are not concurrently accessed; reading from a dictionary while it’s is being updated is a recipe for some very odd side effects.</p>
<p>However, if this were the only reason to protect the code, I would switch to using a concurrent dictionary, remove the locks completely from this method, and move on. There is another reason why this code needs a lock.</p>
<p>We expect one of three outcomes when the <code class="language-plaintext highlighter-rouge">RenderSpeechAsync()</code> method of our cache runs:</p>
<ul>
<li>The text has already been rendered into speech, so we can return it at once from our cache;</li>
<li>Rendering into speech has already started, so we await completion of that request; or</li>
<li>We need to render the text into speech.</li>
</ul>
<p>It might seem that our code correctly fulfils the above requirements. Indeed, when I reviewed the code prior to writing the prior post, I thought it did.</p>
<p>But think about why we introduced this cache in the first place:</p>
<blockquote>
<p>The purpose of the cache is to ensure that we only make a single request to render any given piece of text into speech.</p>
</blockquote>
<p>And here is the problem: Nothing in that critical section ensures that we will call to our wrapped speech renderer only once for each piece of text. Nothing in that critical section changes any state, so we can run through it many times, with each execution giving the same results.</p>
<p>To fix our race condition, we need to modify state <em>within</em> the lock so that only one of our callers will do the rendering. Our first caller should trigger a call to our wrapped speech renderer. Any later calls for the same text should wait on the first.</p>
<p>The fix is to add the required <code class="language-plaintext highlighter-rouge">TaskCompletionSource</code> into the cache <em>before</em> the first lock completes, as follows:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p"><</span><span class="kt">byte</span><span class="p">[</span><span class="k">]></span> <span class="nf">RenderSpeechAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// ... elided ...</span>
<span class="k">lock</span> <span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_completedRenders</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">existingStream</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">existingStream</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">sourceAlreadyExists</span> <span class="p">=</span> <span class="n">_pendingRenders</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="n">source</span><span class="p">!);</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">sourceAlreadyExists</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">source</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TaskCompletionSource</span><span class="p"><</span><span class="kt">byte</span><span class="p">[</span><span class="k">]></span><span class="p">();</span>
<span class="n">_pendingRenders</span><span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="p">=</span> <span class="n">source</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">sourceAlreadyExists</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">await</span> <span class="n">source</span><span class="p">!.</span><span class="n">Task</span><span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// ... elided ...</span>
<span class="p">}</span></code></pre></figure>
<p>There’s a design issue with <code class="language-plaintext highlighter-rouge">IRenderSpeechService</code> as well. Returning a <code class="language-plaintext highlighter-rouge">Stream</code> from the cache is a bad idea. Streams are <em>stateful</em> objects, with a current read position. If two parallel code paths try to read the same stream at the same time, things will go badly. Fixing this is much easier - we change to using <code class="language-plaintext highlighter-rouge">byte[]</code> for storage instead of <code class="language-plaintext highlighter-rouge">Stream</code>. Each caller can independently process this. We run a small risk by not copying the array before returning it – this allows consumers to mutate the array, but the cost of copying the data would be high.</p>
<p>What’s the lesson here?</p>
<p>If you have a critical section to ensure that something only happens once, you need to make sure that the required state change occurs within the section.</p>
<p>Sounds simple, doesn’t it. Yet it’s a lesson that I’ve just had to relearn.</p>
http://www.nichesoftware.co.nz/2020/06/06/sharpen-the-sawSharpen The Saw - June 20202020-06-06T00:00:00+00:002020-06-06T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: Reducing the scope of each pull request; rules for better powerpoint presentations; a welcome to C# 9.0; Chrome has a new feature to manage your tabs; we’re all bad programmers; five ideas for eliminating bad code; thunderbolt ports are insecure; an unattributable data breach; kudos for Ashley Bloomfield; and The Clean Code Talks.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="how-to-scope-down-prs">How to Scope Down PRs</h4>
<p>Ever discovered a bug while working on a feature and thrown the fix into the same PR? While that’s fine for one bug, it can become a problem when too many extras are thrown into the PR, making it unfocused and difficult to review. This post discusses the problem and offers some guidance on how to keep things small.</p>
<p><a href="https://www.netlify.com/blog/2020/03/31/how-to-scope-down-prs">Read now</a></p>
<h4 id="rules-to-better-powerpoint-presentations">Rules to better PowerPoint presentations</h4>
<p>Here’s an interesting set of guidance from Sydney based SSW on building better PowerPoint slide decks. As with many lists of this kind, there’s value in reviewing them to see what can be useful for your context and then ignoring the rest. I don’t agree with all of this guidance, particularly the suggestions around the use of a template - though if you’re speaking for your employer, this can be important.</p>
<p><a href="https://rules.ssw.com.au/rules-to-better-powerpoint-presentations">Read now</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="welcome-to-c-90">Welcome to C# 9.0</h4>
<p>The C# team is closing in on the final features for the next version of the C# language and Mads Torgersen recently blogged on all the goodies they’re wanting to bring us. It’s a great list:</p>
<ul>
<li>Init-only properties.</li>
<li>Records (incl With-expressions).</li>
<li>Top-level programs.</li>
<li>Enhanced pattern matching.</li>
<li>More Target-Typing.</li>
<li>Covariant returns.</li>
</ul>
<p>Target typing and covariant returns will be extraordinarily useful when needed, but I suspect that init-only properties and records will have the biggest impact.</p>
<p><a href="https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0">Read now</a></p>
<h3 id="tab-groups-is-chromes-best-new-feature-in-years">Tab-Groups is Chrome’s best new feature in years</h3>
<p>Have you ever felt that the Tabs bar at the top of your Chrome window is just a little out of control? It’s really easy to end up with so many open tabs that finding the page you want is nigh on impossible. So we open another new tab instead. Tab Groups provide some structure to your tabs, hopefully making them easier to manage.</p>
<p><a href="https://www.gizmodo.com.au/2020/04/tab-groups-is-chromes-best-new-feature-in-years-and-heres-how-to-use-it/">Read now</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="youre-a-bad-programmer-embrace-it">You’re a Bad Programmer. Embrace It.</h4>
<p>Jared Richardson thinks we’re all bad programmers. I think he’s right. We all make mistakes. What differs is what we do about those mistakes. His advice mirrors my own - part of the solution is in choosing good tooling.</p>
<p><a href="https://dzone.com/articles/youre-bad-programmer-embrace">Read now</a></p>
<h4 id="5-practices-to-eliminate-bad-code">5 Practices to Eliminate Bad Code</h4>
<p>We’ve all been there. We think the work is done, the feature is complete, and then we spot the problem. Or, worse, someone else identifies the problem. Here are five suggestions from industry leaders on how to do better:</p>
<ul>
<li>Automate everything.</li>
<li>Treat code like art.</li>
<li>Collaborate and learn.</li>
<li>Write for humans.</li>
<li>Use the right tools.</li>
</ul>
<p><a href="https://dzone.com/articles/5-practices-to-eliminate-bad-code">Read now</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="thunderbolt-flaws-expose-millions-of-pcs-to-hands-on-hacking">Thunderbolt flaws expose millions of PCs to hands-on hacking</h4>
<p>If you have a Thunderbolt port on your laptop - and many of us do - then it’s highly likely that your machine is vulnerable to this new exploit. Realistically, because the attack requires physical access to the machine, most of us will be safe. It does highlight, however, how there can still be flaws in systems that have already been thoroughly analysed and vetted.</p>
<p><a href="https://www.wired.com/story/thunderspy-thunderbolt-evil-maid-hacking">Read now</a></p>
<h4 id="the-unattributable-db8151dd-data-breach">The unattributable “db8151dd” data breach</h4>
<p>Troy Hunt blogs about a data breach he received back in February 2020. Initially, he was unable to identify which organization had been breached. After the post went live, the source was narrowed down.</p>
<p><a href="https://www.troyhunt.com/the-unattributable-db8151dd-data-breach/">Read now</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="the-extremely-competent-somewhat-boring-civil-servant-who-has-new-zealanders-hearts-a-flutter">The extremely competent, somewhat boring civil servant who has New Zealanders’ hearts a-flutter</h4>
<p>During New Zealand’s Alert Level 4 lock-down, there was one constant that came up while chatting with friends and colleagues who live outside of New Zealand: their appreciation of the extreme competence with which New Zealand handled their COVID-19 response. Central to that response, our Director-General of Health, Dr Ashley Bloomfield. He’s become a bit of a celebrity.</p>
<p><a href="https://slate.com/news-and-politics/2020/04/new-zealand-covid-19-coronavirus-ashley-bloomfield.html">Read now</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="the-clean-code-talks-unit-testing">The Clean Code Talks: Unit Testing</h4>
<p>This talk might be over a decade old - but it’s a discussion on writing untestable code that’s worth the watch. There’s good advice here.</p>
<p><strong>Audience</strong>: Developers<br />
<strong>Length</strong>: 32m</p>
<p><a href="https://youtu.be/wEhu57pih5w">Watch now</a></p>
http://www.nichesoftware.co.nz/2020/05/30/powershell-inboxAutomated Inbox Cleanup with PowerShell2020-05-30T00:00:00+00:002020-05-30T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>This week I discovered that my Inbox had ballooned to over 20k messages. It was in desperate need of a clean-up. Here is how I automated that clean-up, getting it down to just under 1500 messages.</p>
<p>How did this happen? I normally use the Windows 10 Mail app, configured to download just the most recent month of messages. This keeps the number of visible messages down, and I can always open the full version of Office Outlook if I need something more. I hadn’t needed to open Office Outlook in a very long time, and had lost sight of the size of my Inbox. When my usual Mail app started crashing within 30s of startup, I suspected the size of my Inbox was the cause (it wasn’t, but that’s a separate story).</p>
<p>I use a simple approach to archiving messages. At the top level I have an <code class="language-plaintext highlighter-rouge">Archive</code> folder. Within that is a folder for each year, say <code class="language-plaintext highlighter-rouge">2020</code>. Within those, there are folders for each month of the year, as <code class="language-plaintext highlighter-rouge">2020-01</code>, <code class="language-plaintext highlighter-rouge">2020-02</code>, and so on. I don’t use month names as I want the folders to be shown chronologically, and not every mail tool respects other ordering.</p>
<p>At first, I was manually selecting groups of messages and dragging them into the proper archive folders, but it soon became clear that this was tedious, error prone, and taking way too long. Worse, Outlook would become non-responsive for extended periods as it moved the messages, making it impossible to do anything else mail related.</p>
<p>Time to work out what I can automate through Outlook. It turned out to be surprisingly easy.</p>
<p>Here is the script I wrote, with commentary about what is going on, step by step. Note that I’ve wrapped some code for readability.</p>
<p>We begin by importing a library of generic helper methods. In this case, the only method we are using is <code class="language-plaintext highlighter-rouge">Write-ColorText()</code>, used to provide good logging so that we can easily see what happens.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="o">.</span><span class="w"> </span><span class="o">.</span><span class="n">/script-library.ps1</span></code></pre></figure>
<p>PowerShell can output Unicode characters to the console, but I needed to tickle the configuration just slightly before it worked. I also needed to save the file as UTF-8 with a BOM (byte-order-mark) at the start, else PowerShell would read the file as ASCII and will trip over any Unicode characters included.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="p">[</span><span class="n">console</span><span class="p">]::</span><span class="n">OutputEncoding</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Text.UTF8Encoding</span></code></pre></figure>
<p>We connect to the Outlook application using COM, showing a log line to the console after successfully connecting.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="nv">$outlook</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">new-object</span><span class="w"> </span><span class="nt">-com</span><span class="w"> </span><span class="nx">outlook.application</span><span class="p">;</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w"> </span><span class="nt">-Green</span><span class="w"> </span><span class="s2">"[✓] Connected to Outlook"</span></code></pre></figure>
<p>Once we have access to the application, we find the Inbox:</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="nv">$mailboxName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"<mailboxname>"</span><span class="w">
</span><span class="nv">$ns</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$outlook</span><span class="o">.</span><span class="nf">GetNameSpace</span><span class="p">(</span><span class="s2">"MAPI"</span><span class="p">);</span><span class="w">
</span><span class="nv">$mailbox</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$ns</span><span class="o">.</span><span class="nf">Folders</span><span class="o">.</span><span class="nf">Item</span><span class="p">(</span><span class="nv">$mailboxName</span><span class="p">)</span><span class="w">
</span><span class="nv">$inbox</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$mailbox</span><span class="o">.</span><span class="nf">Folders</span><span class="o">.</span><span class="nf">Item</span><span class="p">(</span><span class="s2">"Inbox"</span><span class="p">)</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w"> </span><span class="nt">-Green</span><span class="w"> </span><span class="s2">"[✓] Found Inbox"</span></code></pre></figure>
<p>And then we find the top-level archive folder.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="nv">$archiveFolder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$mailbox</span><span class="o">.</span><span class="nf">Folders</span><span class="o">.</span><span class="nf">Item</span><span class="p">(</span><span class="s2">"Archive"</span><span class="p">)</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w"> </span><span class="nt">-Green</span><span class="w"> </span><span class="s2">"[✓] Found Archive Folder"</span></code></pre></figure>
<p>We are going to iterate over all the messages in the Inbox, checking each message to see if it needs archiving. While Outlook does not strongly define the order of message iteration, I have found that Outlook commonly groups together messages received at the same time. So, as a small optimization, I’m keeping track of the current archive folders for the current year and month, to make it faster to move messages when needed.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="nv">$yearFolder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$null</span><span class="w">
</span><span class="nv">$monthFolder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$null</span><span class="w">
</span><span class="nv">$messages</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$inbox</span><span class="o">.</span><span class="nf">Items</span><span class="w">
</span><span class="nv">$messageCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$messages</span><span class="o">.</span><span class="nf">Count</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w"> </span><span class="nt">-Gray</span><span class="w"> </span><span class="s2">"[○] Scanning </span><span class="nv">$messageCount</span><span class="s2"> messages"</span></code></pre></figure>
<p>To avoid completely emptying my Inbox, I define a 90-day threshold. Only messages older than this will be archived by the script.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="nv">$threshold</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">get-date</span><span class="p">)</span><span class="o">.</span><span class="nf">AddDays</span><span class="p">(</span><span class="nt">-90</span><span class="p">)</span><span class="o">.</span><span class="nf">Date</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="s2">"[○] Moving messages received prior to "</span><span class="w">
</span><span class="nv">$threshold</span><span class="o">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s2">"D"</span><span class="p">)</span></code></pre></figure>
<p>Now we are ready to iterate over all the messages.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$m</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="nv">$messages</span><span class="p">)</span><span class="w"> </span><span class="p">{</span></code></pre></figure>
<p>For logging purposes, we extract the subject of each message, truncating it to a useful length.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$m</span><span class="o">.</span><span class="nf">Subject</span><span class="o">.</span><span class="nf">Length</span><span class="w"> </span><span class="o">-gt</span><span class="w"> </span><span class="mi">40</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$subject</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$m</span><span class="o">.</span><span class="nf">Subject</span><span class="o">.</span><span class="nf">Substring</span><span class="p">(</span><span class="nx">0</span><span class="p">,</span><span class="w"> </span><span class="nx">40</span><span class="p">)</span><span class="o">+</span><span class="s2">"..."</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$subject</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$m</span><span class="o">.</span><span class="nf">Subject</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>If the message is too new, we skip it and move to the next one. You may want to comment out the logging line if you find it too chatty.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="w"> </span><span class="nv">$date</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$m</span><span class="o">.</span><span class="nf">ReceivedTime</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$date</span><span class="w"> </span><span class="o">-ge</span><span class="w"> </span><span class="nv">$threshold</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w">
</span><span class="nt">-Gray</span><span class="w"> </span><span class="s2">"[•] Skipping "</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="nv">$subject</span><span class="w">
</span><span class="nt">-Gray</span><span class="w"> </span><span class="s2">" received "</span><span class="w"> </span><span class="nv">$date</span><span class="o">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s2">"s"</span><span class="p">)</span><span class="w">
</span><span class="kr">continue</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>We are going to archive this message, so we check whether the year and month folders we already have are the right ones to use. If we need different folders, update our references and log that we’ve done so. This allows us to read the log and see where the script moved each message.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="w"> </span><span class="nv">$year</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$date</span><span class="o">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s2">"yyyy"</span><span class="p">)</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$yearFolder</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="nv">$year</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$yearFolder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$archiveFolder</span><span class="o">.</span><span class="nf">Folders</span><span class="o">.</span><span class="nf">Item</span><span class="p">(</span><span class="nv">$year</span><span class="p">)</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w">
</span><span class="nt">-Gray</span><span class="w"> </span><span class="s2">"[•] Found Archive for "</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="nv">$year</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$month</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$date</span><span class="o">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s2">"yyyy-MM"</span><span class="p">)</span><span class="w">
</span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$monthFolder</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="nv">$month</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">$monthFolder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$yearFolder</span><span class="o">.</span><span class="nf">Folders</span><span class="o">.</span><span class="nf">Item</span><span class="p">(</span><span class="nv">$month</span><span class="p">)</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w">
</span><span class="nt">-Gray</span><span class="w"> </span><span class="s2">"[•] Found Archive for "</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="nv">$month</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>Finally, we do the actual move, with a log line that tells us what happened. If you’re trying this out for yourself, I’d suggest commenting out the actual move and changing the log to read “Would Move” while you check that the script is doing the right thing.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="w"> </span><span class="nv">$updated</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$m</span><span class="o">.</span><span class="nf">Move</span><span class="p">(</span><span class="nv">$monthFolder</span><span class="p">)</span><span class="w">
</span><span class="n">Write-ColorText</span><span class="w">
</span><span class="nt">-Green</span><span class="w"> </span><span class="s2">"[✓]"</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="s2">" Moved "</span><span class="w">
</span><span class="nt">-Green</span><span class="w"> </span><span class="nv">$subject</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="s2">" received "</span><span class="w">
</span><span class="nt">-Green</span><span class="w"> </span><span class="nv">$date</span><span class="o">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s2">"s"</span><span class="p">)</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="s2">" from "</span><span class="w">
</span><span class="nt">-Green</span><span class="w"> </span><span class="nv">$m</span><span class="o">.</span><span class="nf">SenderName</span><span class="w">
</span><span class="nt">-White</span><span class="w"> </span><span class="s2">" to "</span><span class="w">
</span><span class="nt">-Green</span><span class="w"> </span><span class="nv">$month</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>The ability to automate Office Outlook with PowerShell is quite something. With just a short piece of PowerShell, I was able to automate a tedious task in reusable fashion. Each month – or just whenever I remember – I can rerun the script and keep my Inbox tidy.</p>
<p>I even wrote a companion script, imaginatively called “clean-archive” that iterates through all the archive folders doing further cleaning: moving misfiled messages, deleted messages from mailing lists, and so on. You might want to do the same.</p>
http://www.nichesoftware.co.nz/2020/05/16/do-not-gloss-over-complexityDon't Gloss Over Complexity2020-05-16T00:00:00+00:002020-05-16T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>We have a poor habit in the tech industry of glossing over the complexity of things. Sometimes this is done deliberately, but very often it happens accidentally, as the result of skipping due consideration, or at a subconscious level.</p>
<p>I saw this play out on Twitter this week in a scenario that’s all too common. An early career developer, enthusiastic about what they know and eager to share that knowledge with others, denigrated as “not a real developer” by someone with greater experience.</p>
<p>This is a situation that’s played out time and again. It’s easy to find examples of these kinds of aggressions that, in accumulation, serve to push people out of the industry.</p>
<p>One of the many contributing factors that leads to these situations is the way that we all forget the inherent complexity of lessons we’ve already learned.</p>
<p>Do you know how to ride a bike? Do you remember how hard it was to learn to ride?</p>
<p>I have some vivid memories of learning to ride a bike as a child, including a slow wobbly ride down our garden path where I was terrified that I’d hit our (very solid) letterbox. Guess what I hit. Ouch.</p>
<p>That memory is over 40 years old, but it still stands out.</p>
<p>I have some much newer memories from when I taught my daughter to ride. It was something she intensely wanted to do, but it was hard work. We went to the local park twice a day for her to practice - and boy was she proud when she showed off her new skills to her Mum.</p>
<p>Learning to ride a bike is hard because it’s a complex dynamic process. You can’t just steer the bike, you have to pedal and balance at the same time, making adjustments many many times every second. If you fail at any one of those, you fall off.</p>
<p>And yet, how many of us think about all those adjustments when we ride?</p>
<p>This is what happens to complexity once we master a skill - it becomes an automatic subconsious act, allowing us to concentrate on the next goal.</p>
<p>We don’t think about riding a bike, we think about how to not be squished by traffic, how we’re going to navigate to the local shops, and about what we’re going to buy when we get there.</p>
<p>As developers, there are so many similar examples of complex topics that become simple once we’ve mastered them.</p>
<p>I remember coaching first year computer science students who had never touched a computer before, helping them to comprehend the extremely literal way that computers execute each instruction in order, one at a time. (This was at the start of the ’90s, pre-word-wide-web, when computer ownership wasn’t the ubiqutous thing that it is today.)</p>
<p>Sequential execution of instructions is such a fundamental concept that I rarely think about it, but it’s something that has to be learned by every aspiring developer.</p>
<p>Think about some of the other concepts that new developers need to grok: conditional branching; looping; functions; data types; file types.</p>
<p>Now think about some of the more complex concepts you’ve already mastered - or perhaps you’re already working on.</p>
<p>Recursion. Pointers. Manual memory management. Abstraction. Encapsulation. Inheritance. Composition. OOP. Generic Types. SOLID. DRY. Unit testing. Functional programming. Monads. Functors. And so on…</p>
<p>Here’s the crux of the issue.</p>
<p>We can easily assume that something easy to understand because we understand it, and that anyone who doesn’t understand it is just not as smart. This can happen because it is so extremely easy to under-appreciate the complexity of what we already know.</p>
<p>We who have already climbed a mountain of understanding should be gracous and encouraging towards those who are still early in their climb. Especially since we’ve got more climbing ahead of us.</p>
http://www.nichesoftware.co.nz/2020/05/09/wordtutor-improved-cachingImproved Caching2020-05-09T00:00:00+00:002020-05-09T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>After our recent introduction of caching, I had an interesting conversation with a friend about the way I’d written the code. He was persuasive that the approach I’d taken had some significant issues and that it was worth taking the time to address them.</p>
<p><strong>The AzureSpeechGenerator class is doing too much.</strong> In violation of the single responsibility principle, the class has multiple conflicting responsibilities. It interacts with Azure Cognitive Services, caches the results, and plays audio through the speaker.</p>
<p><strong>The caching approach is flawed.</strong> Only completed speech audio is cached. Multiple overlapping requests to play the same audio can result in multiple requests to ACS to generate the same speech audio. This is wasteful in both time and cost.</p>
<p><strong>The null return for failed speech generation is non-idiomatic.</strong> In normal .NET code, unusual failures are conventionally indicated by throwing an exception, not by returning an error code. We don’t expect the call to ACS to fail, so the use of <strong>null</strong> as a sentinel return value is more than a little dodgy. Worse, we’re discarding all the details of the actual error.</p>
<p>To address these issues, we’re going to restructure the speech service subsystem. Fortunately, we can do this without changing the existing <code class="language-plaintext highlighter-rouge">ISpeechService</code> interface, so the rest of the application will remain untouched.</p>
<h3 id="separation-of-concerns">Separation of Concerns</h3>
<p>Let’s separate out our concerns (or responsibilities) by introducing a new interface: <code class="language-plaintext highlighter-rouge">IRenderSpeechService</code>. This interface abstracts the ability to convert content into speech:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">interface</span> <span class="nc">IRenderSpeechService</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
<span class="n">Task</span><span class="p"><</span><span class="n">Stream</span><span class="p">></span> <span class="nf">RenderSpeechAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>With this interface, we can apply the decorator design pattern and encapsulate all of our required caching functionality in a dedicated type, <code class="language-plaintext highlighter-rouge">CachingRenderSpeechService</code>.</p>
<p>Our existing <code class="language-plaintext highlighter-rouge">AzureSpeechService</code> can be dramatically simplified, focusing entirely on interacting with Azure. The core method, <code class="language-plaintext highlighter-rouge">RenderSpeechAsync</code> simplifies down to this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p"><</span><span class="n">Stream</span><span class="p">></span> <span class="nf">RenderSpeechAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">audioStream</span> <span class="p">=</span> <span class="n">AudioOutputStream</span><span class="p">.</span><span class="nf">CreatePullStream</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">audioConfig</span> <span class="p">=</span> <span class="n">AudioConfig</span><span class="p">.</span><span class="nf">FromStreamOutput</span><span class="p">(</span><span class="n">audioStream</span><span class="p">);</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">_synthesizer</span>
<span class="p">=</span> <span class="k">new</span> <span class="nf">SpeechSynthesizer</span><span class="p">(</span><span class="n">_configuration</span><span class="p">,</span> <span class="n">audioConfig</span><span class="p">);</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_synthesizer</span><span class="p">.</span><span class="nf">SpeakTextAsync</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Reason</span> <span class="p">==</span> <span class="n">ResultReason</span><span class="p">.</span><span class="n">SynthesizingAudioCompleted</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">();</span>
<span class="n">stream</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">AudioData</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="n">AudioData</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
<span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">details</span> <span class="p">=</span> <span class="n">SpeechSynthesisCancellationDetails</span><span class="p">.</span><span class="nf">FromResult</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RenderSpeechException</span><span class="p">(</span><span class="n">details</span><span class="p">.</span><span class="n">ErrorDetails</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Note the new exception type <code class="language-plaintext highlighter-rouge">RenderSpeechException</code> that is thrown near the end if something goes wrong. In our simplified <code class="language-plaintext highlighter-rouge">SpeechServices</code> implementation, we catch that to log any errors:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">SayAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">_logger</span><span class="p">.</span><span class="nf">Action</span><span class="p">(</span><span class="s">$"Say </span><span class="p">{</span><span class="n">content</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">speech</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_renderSpeechService</span><span class="p">.</span><span class="nf">RenderSpeechAsync</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
<span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="n">_player</span><span class="p">.</span><span class="nf">Stop</span><span class="p">();</span>
<span class="n">speech</span><span class="p">.</span><span class="nf">Seek</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">SeekOrigin</span><span class="p">.</span><span class="n">Begin</span><span class="p">);</span>
<span class="n">_player</span><span class="p">.</span><span class="n">Stream</span> <span class="p">=</span> <span class="n">speech</span><span class="p">;</span>
<span class="n">_player</span><span class="p">.</span><span class="nf">Play</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">catch</span><span class="p">(</span><span class="n">RenderSpeechException</span> <span class="n">ex</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">Failure</span><span class="p">(</span><span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h3 id="caching-improvements">Caching improvements</h3>
<p>With a dedicated wrapper class that does just caching, we can focus on doing the job properly.</p>
<p>Our prior implementation only cached the completed results of rendering phrases into speech; we also need to cache in-flight rendering so that we don’t trip up over ourselves by doing the same work over and over. This means we need two different stores in our cache:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// Cache of completed speech rendering</span>
<span class="k">private</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="n">Stream</span><span class="p">></span> <span class="n">_completedRenders</span>
<span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="n">Stream</span><span class="p">>();</span>
<span class="c1">// Details of speech rendering that is still under way</span>
<span class="k">private</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="n">TaskCompletionSource</span><span class="p"><</span><span class="n">Stream</span><span class="p">>></span> <span class="n">_pendingRenders</span>
<span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="n">TaskCompletionSource</span><span class="p"><</span><span class="n">Stream</span><span class="p">>>();</span></code></pre></figure>
<p>In case you haven’t seen it before outstanding asynchronous work is handled in .NET by using a <code class="language-plaintext highlighter-rouge">TaskCompletionSource</code>. This class is awaitable, allowing asynchronous code to use the normal await keyword to obtain the result when it’s available.</p>
<p>With two distinct dictionaries in use, we need to use locks to ensure our consumers never see partial updates.</p>
<p>The core of the cache is in the <code class="language-plaintext highlighter-rouge">RenderSpeechAsync</code> method. Here’s how it works.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p"><</span><span class="n">Stream</span><span class="p">></span> <span class="nf">RenderSpeechAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">haveSource</span><span class="p">;</span>
<span class="n">TaskCompletionSource</span><span class="p"><</span><span class="n">Stream</span><span class="p">>?</span> <span class="n">tcsStream</span><span class="p">;</span>
<span class="k">lock</span><span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_completedRenders</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">existingStream</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">existingStream</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>If the required stream is already present in our cache of completed results, we can return it directly. If not, we look in our cache of pending results.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"> <span class="n">haveSource</span> <span class="p">=</span> <span class="n">_pendingRenders</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="n">tcsStream</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">haveSource</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">await</span> <span class="n">tcsStream</span><span class="p">!.</span><span class="n">Task</span><span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>If we found something in our cache of pending results, we await the provision of a result and then return it. Note that we can’t do the await within the lock - not only does the compiler stop us from doing that, but we also don’t want to keep the lock while we’re waiting.</p>
<p>Since we didn’t find a pending result, we will need to call our nested RenderSpeechService; to avoid others doing the same work over, we need to add this into our cache of pending results.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"> <span class="n">tcsStream</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TaskCompletionSource</span><span class="p"><</span><span class="n">Stream</span><span class="p">>();</span>
<span class="k">lock</span><span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_pendingRenders</span><span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="p">=</span> <span class="n">tcsStream</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>With our cache updated, we call into our nested speech renderer. Once we have a result, we update our TaskCompletionSource, releasing any tasks that were awaiting the result. We also update our caches and then return the result.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"> <span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_renderSpeechService</span><span class="p">.</span><span class="nf">RenderSpeechAsync</span><span class="p">(</span><span class="n">content</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="n">tcsStream</span><span class="p">.</span><span class="nf">SetResult</span><span class="p">(</span><span class="n">stream</span><span class="p">);</span>
<span class="k">lock</span><span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_completedRenders</span><span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="p">=</span> <span class="n">stream</span><span class="p">;</span>
<span class="n">_pendingRenders</span><span class="p">.</span><span class="nf">Remove</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<h3 id="conclusion">Conclusion</h3>
<p>Code reviews are always valuable - and, assuming you have the time to do so, fixing up code issues is worthwhile too.</p>
http://www.nichesoftware.co.nz/2020/05/05/sharpen-the-sawSharpen The Saw - May 20202020-05-05T00:00:00+00:002020-05-05T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: How to choose between a static factory method and a constructor; What not to do with async; Meeting with Skype for free; How to stop wasting your time; What you don’t know about names; New static analysis features in GCC prove their worth; Making your C# more functional; Coding bootcamps for veterans; and, How to crash an airplane.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="static-factory-methods-vs-constructors-in-c">Static Factory Methods vs Constructors In C#</h4>
<p>While it’s sometimes obvious, it’s not always clear when to use a public constructor or a static factory method for a new class. Gustav used to lean heavily on public constructors but now he takes a more nuanced position. He includes some widely applicable guidelines at the end that I think are very useful.</p>
<p><a href="https://www.gustavwengel.dk/csharp-static-factory-vs-constructor">Read more</a></p>
<h4 id="c-async-antipatterns">C# Async Antipatterns</h4>
<p>When C# introduced the <strong>await</strong> and <strong>async</strong> keywords, it was a revolutionary approach to writing asynchronous code. Unfortunately, they don’t completely absolve you of responsibility - you still need to pay attention to what you’re doing. Here’s a good discussion of some <em>antipatterns</em> - things you should not be doing in your async code.</p>
<p><a href="https://markheath.net/post/async-antipatterns">Read more</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="host-a-quick-meeting-with-skypes-meet-now-no-login-needed">Host A Quick Meeting With Skype’s ‘Meet Now’, No Login Needed</h4>
<p>Isn’t it interesting how quickly “Zooming” entered the vocabulary as a verb for making a video conference call? Given some of the well-publicised concerns with the security and privacy of Zoom, it’s useful to be aware of alternatives.</p>
<p>For example, you can have a quick meeting with Skype without needing to have an account - and their limit of 4 hours per video call is a lot more generous than 40 minutes. Even better, you don’t get completely cut off when your time expires, the call just drops to audio-only.</p>
<p><a href="https://www.lifehacker.com.au/2020/04/host-a-quick-meeting-with-skypes-meet-now-no-login-needed/">Read more</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="how-to-stop-wasting-your-life-watching-tv-and-do-something-worthwhile-with-your-downtime">How to stop wasting your life watching TV and do something worthwhile with your downtime</h4>
<p>This one seems especially relevant in the times of COVID-19 and social distancing. Here are five strategies for making the most of your time, so that you don’t get to the end of the week and wonder why the only thing you did was work.</p>
<p><a href="https://getpocket.com/explore/item/how-to-stop-wasting-your-life-watching-tv-and-do-something-worthwhile-with-your-downtime">Read more</a></p>
<h4 id="falsehoods-programmers-believe-about-names">Falsehoods Programmers Believe About Names</h4>
<p>When’s the last time you had to enter your name into a computer website? We do it all the time when we sign up for online shopping, or place an order for dinner. How did the website prompt you for your name? If it’s like most, it used the very western approach of prompting you for your first and last names. Don’t see the problem? Read this post. Names are hard - and most computer systems screw them up.</p>
<p><a href="https://shinesolutions.com/2018/01/08/falsehoods-programmers-believe-about-names-with-examples/">Read more</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="gcc-10-gets-security-bug-trap">GCC 10 gets security bug trap</h4>
<p>The latest version of GCC (the GNU Compiler Collection) includes a static analysis feature designed to detect the kinds of bugs that lead to security problems. Even before release, it’s started to prove it’s worth, revealing a recently-introduced security vulnerability in OpenSSL, the library used by much of the internet to secure network connections.</p>
<p><a href="https://www.theregister.co.uk/2020/04/23/gcc_openssl_vulnerability/">Read more</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="your-c-is-already-functional-but-only-if-you-let-it">Your C# is already functional, but only if you let it</h4>
<p>In this blog post, Igal Tabachnik shares a surprisingly concise and very readable implementation of Fizz-Buzz in C#, using some of the newest features of the language. A good illustration of the expressive power of the new features and how they can be used to good effect.</p>
<p><a href="https://hmemcpy.com/2020/03/your-csharp-is-already-functional/">Read more</a></p>
<h4 id="this-veteran-started-a-code-boot-camp-for-people-who-went-to-boot-camp">This veteran started a code boot camp for people who went to boot camp</h4>
<p>After their time in the military, many veterans find it difficult to transition to civilian roles even though they are smart, disciplined and know how to work in a team. Jerome Hardaway was one of those vets. He learnt to code and has started a nonprofit dedicated to giving other vets a hand up by teaching them to code too.</p>
<p><a href="https://stackoverflow.blog/2020/01/02/this-veteran-started-a-code-bootcamp-for-people-who-went-to-bootcamp/?cb=1">Read more</a></p>
<p>Podcast bonus: Scott Hanselman interviews Jerome Hardaway
<a href="https://www.hanselminutes.com/562/vets-who-code-with-jerome-hardaway">Listen now</a></p>
<p><strong>Length</strong>: 31 minutes<br />
<strong>Audience</strong>: Everyone</p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="how-to-crash-an-airplane">How to crash an airplane</h4>
<p>The July 1989 crash of United Flight 232 is undoubtedly a tragedy. But it’s also a story of clear thinking, sound judgement and quite a lot of luck. Nickolas Means tells the story in an engaging and interesting way, with lessons we all can take forward.</p>
<p><strong>Audience</strong>: Everyone<br />
<strong>Length</strong>: 43m</p>
<p><a href="https://www.youtube.com/watch?v=099cHWSbAL8">Watch now</a></p>
http://www.nichesoftware.co.nz/2020/04/25/wordtutor-cachingCaching Speech2020-04-25T00:00:00+00:002020-04-25T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>If you’ve been playing around with maintenance screen and the speech integration that we completed <a href="/2020/04/18/wordtutor-maintenance-speech.html">last week</a> you may have noticed that there can be a noticeable lag between the time you press a play button and when you hear the speech.</p>
<p>The lag is caused by the necessary round trip to Azure Cognitive Services (henceforth ACS) to do the conversion of text to speech. In my testing (using service located relatively close to me, in Australia), rendering could take as much as 3.7 seconds.</p>
<p>This isn’t fast enough for interactive use.</p>
<p>It’s worth pointing out that I’m not being critical of ACS here. On top of the actual time taken by ACS to create the speech fragment, we’re also dealing with the round trip time between my laptop and the service itself. Given that New Zealand internet use seems to set a new record every few days, due to everyone working and playing from home, the performance I’m seeing is pretty good.</p>
<p>The cliche in software development is that most every problem can be solved by introducing another layer of indirection, unless your problem is too many layers of indirection.</p>
<p>Let’s introduce some caching - not only will this give us faster access to any particular phrase the second time we need it, we’ll reduce our calls to ACS by not rendering the same phrase multiple times.</p>
<p>Our first step is to move the call to ACS into a private method that simply returns a stream of binary data containing the required speech:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p"><</span><span class="n">Stream</span><span class="p">></span> <span class="nf">RenderSpeech</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">stopwatch</span> <span class="p">=</span> <span class="n">Stopwatch</span><span class="p">.</span><span class="nf">StartNew</span><span class="p">();</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">audioStream</span> <span class="p">=</span> <span class="n">AudioOutputStream</span><span class="p">.</span><span class="nf">CreatePullStream</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">audioConfig</span> <span class="p">=</span> <span class="n">AudioConfig</span><span class="p">.</span><span class="nf">FromStreamOutput</span><span class="p">(</span><span class="n">audioStream</span><span class="p">);</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">_synthesizer</span> <span class="p">=</span>
<span class="k">new</span> <span class="nf">SpeechSynthesizer</span><span class="p">(</span><span class="n">_configuration</span><span class="p">,</span> <span class="n">audioConfig</span><span class="p">);</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_synthesizer</span><span class="p">.</span><span class="nf">SpeakTextAsync</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Reason</span> <span class="p">==</span> <span class="n">ResultReason</span><span class="p">.</span><span class="n">SynthesizingAudioCompleted</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">();</span>
<span class="n">stream</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">AudioData</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="n">AudioData</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
<span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">_logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"Failed to say '</span><span class="p">{</span><span class="n">content</span><span class="p">}</span><span class="s">'."</span><span class="p">);</span>
<span class="k">return</span> <span class="k">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">finally</span>
<span class="p">{</span>
<span class="n">_logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"Elapsed </span><span class="p">{</span><span class="n">stopwatch</span><span class="p">.</span><span class="n">Elapsed</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>This differs from the approach taken previously in a few significant ways.</p>
<p>We use a different AudioConfiguration to ensure we don’t use the speaker but instead return the audio data for later reuse. Oddly, we don’t need to actually use <code class="language-plaintext highlighter-rouge">audioStream</code> as the data we want is returned directly to us in <code class="language-plaintext highlighter-rouge">result</code>; we capture the audio data for the speech and write it into a memory stream for caching.</p>
<p>Around this new method, we add a simple asynchronous cache:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p"><</span><span class="n">Stream</span><span class="p">></span> <span class="nf">GetSpeechStream</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_cache</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">stream</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">stream</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">RenderSpeech</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">stream</span> <span class="k">is</span> <span class="n">Stream</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// Successfully rendered, so store the result</span>
<span class="c1">// (Don't want to cache failures)</span>
<span class="n">_cache</span><span class="p">[</span><span class="n">content</span><span class="p">]</span> <span class="p">=</span> <span class="n">stream</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="n">Stream</span><span class="p">></span> <span class="n">_cache</span>
<span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="n">Stream</span><span class="p">>();</span></code></pre></figure>
<p>This is pretty straightforward caching code - if we have it in the cache, we return it immediately. If not, we render the speech and add it to the cache if that was successful.</p>
<p>Now we can rewrite the core <code class="language-plaintext highlighter-rouge">SayAsync()</code> method to use the cache:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">SayAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">speech</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">GetSpeechStream</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>
<span class="n">_player</span><span class="p">.</span><span class="nf">Stop</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">speech</span> <span class="k">is</span> <span class="n">Stream</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">speech</span><span class="p">.</span><span class="nf">Seek</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">SeekOrigin</span><span class="p">.</span><span class="n">Begin</span><span class="p">);</span>
<span class="n">_player</span><span class="p">.</span><span class="n">Stream</span> <span class="p">=</span> <span class="n">speech</span><span class="p">;</span>
<span class="n">_player</span><span class="p">.</span><span class="nf">Play</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>To make this work, we needed to upgrade the project to use .NET Core 3.1, as it was only in that release that the <code class="language-plaintext highlighter-rouge">SoundPlayer</code> class was introduced, allowing us to play audio.</p>
http://www.nichesoftware.co.nz/2020/04/18/wordtutor-maintenance-speechMaintenance & Speech2020-04-18T00:00:00+00:002020-04-18T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>With our speech infrastructure in place, our next step is to hook it up with our existing maintenance screen. This will allow our users to test out pronunciation as they make changes.</p>
<p>We’ll add a play button next to each of the individual fields in our form:</p>
<p><img src="/images/2020-04-18-maintain-word.png" class="img-responsive" /></p>
<p>To make room for the buttons on the righthand side of the data entry fields, we add an additional column to our grid just to their right. We want everything to remain nicely centred, so we add another column to their left as well.</p>
<p><img src="/images/2020-04-18-grid.png" class="img-responsive" /></p>
<p>Both new columns must have the same width for our centering to be maintained, so we’ll employ a WPF technique called a <em>shared size scope</em>. We turn this on for the grid, and then use the same scope name for both columns:</p>
<figure class="highlight"><pre><code class="language-xaml" data-lang="xaml"><Grid.ColumnDefinitions>
<ColumnDefinition
Width="*"/>
<ColumnDefinition
Width="Auto"
SharedSizeGroup="Button"/>
<ColumnDefinition
Width="*"
MinWidth="240"
MaxWidth="480"/>
<ColumnDefinition
Width="Auto"
SharedSizeGroup="Button"/>
<ColumnDefinition
Width="*"/>
</Grid.ColumnDefinitions></code></pre></figure>
<p>The exact name of the <code class="language-plaintext highlighter-rouge">SharedSizeGroup</code> doesn’t matter, just that the two columns use the same one. When the Grid measures up components to work out the sizes of the columns, these two columns will be grouped together and be the same size.</p>
<p>Each of the buttons is configured by using a new command, <code class="language-plaintext highlighter-rouge">StartSpeaking</code>. New for these buttons is the use of <code class="language-plaintext highlighter-rouge">CommandParameter</code> to pick up information from the view-model to pass into the implementation.</p>
<figure class="highlight"><pre><code class="language-xaml" data-lang="xaml"><Button
Content="u"
Grid.Row="4"
Grid.Column="3"
FontFamily="Wingdings 3"
Command="desktop:VoiceCommands.StartSpeaking"
CommandParameter="{Binding Spelling}"
Padding="5 0"/></code></pre></figure>
<p>The implementation of these commands follows the pattern we <a href="/2019/09/21/wordtutor-wpf-commands.html">used earlier</a>.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">RoutedCommandSink</span><span class="p"><</span><span class="kt">string</span><span class="p">></span> <span class="n">SpeakCommand</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="c1">// From the constructor </span>
<span class="n">SpeakCommand</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RoutedCommandSink</span><span class="p"><</span><span class="kt">string</span><span class="p">>(</span>
<span class="n">VoiceCommands</span><span class="p">.</span><span class="n">StartSpeaking</span><span class="p">,</span> <span class="n">Speak</span><span class="p">,</span> <span class="n">CanSpeak</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="nf">CanSpeak</span><span class="p">(</span><span class="kt">string</span> <span class="n">text</span><span class="p">)</span>
<span class="p">=></span> <span class="p">!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">text</span><span class="p">);</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Speak</span><span class="p">(</span><span class="kt">string</span> <span class="n">text</span><span class="p">)</span>
<span class="p">=></span> <span class="n">_store</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="k">new</span> <span class="nf">SpeakMessage</span><span class="p">(</span><span class="n">text</span><span class="p">));</span></code></pre></figure>
<p>The public property <code class="language-plaintext highlighter-rouge">SpeakCommand</code> is initialized from our constructor to publish the command. Enabling/disabling the command is handled by <code class="language-plaintext highlighter-rouge">CanSpeak()</code> and the actual speech is triggered by <code class="language-plaintext highlighter-rouge">Speak()</code>.</p>
<p>Unlike our earlier examples, we have a command accepting a parameter, in this case, the text to read aloud. As you’ll appreciate, having a parameter makes the command reusable in different places.</p>
<p>Running the application, I found that the buttons weren’t always updated at the right time. Sometimes the buttons remained disabled even when there was text to say, other times the buttons were available even when there was nothing to say.</p>
<p>Investigating this, I relearnt a lesson about command binding in WPF - sometimes it’s necessary to gently nudge the framework into updating.</p>
<p>Fortunately, our modular architecture means that we only need to apply the fix in one place. In our <code class="language-plaintext highlighter-rouge">ViewFactory</code>, we hook into our <code class="language-plaintext highlighter-rouge">PropertyChanged</code>, using it to suggest to the WPF command manager that command bindings need to be refreshed.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">viewModel</span><span class="p">.</span><span class="n">PropertyChanged</span> <span class="p">+=</span>
<span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> <span class="p">=></span> <span class="n">CommandManager</span><span class="p">.</span><span class="nf">InvalidateRequerySuggested</span><span class="p">();</span></code></pre></figure>
<p>Unfortunately, this is a global trigger that will affect all commands across the entire application. It would be nice if there was a way to trigger these updates just for the correct view. However, as long as we ensure all our commands have a quick and trivial implementation for evaluating enable/disable, we won’t have a problem.</p>
<p>With these play buttons in place, we can try out the speech synthesis properly. This is a significant milestone - but we have a long way to go.</p>
http://www.nichesoftware.co.nz/2020/04/11/wordtutor-speech-middlewareSpeech Middleware2020-04-11T00:00:00+00:002020-04-11T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Now that we’ve <a href="/2020/03/28/wordtutor-redux-middleware-implementation.html">modified our Redux store to support middleware</a>, we have the foundation needed to integrate speech synthesis into the main flow of our application.</p>
<p>Leveraging the <a href="/2020/02/15/wordtutor-speech-api.html">ISpeechService</a> abstraction we previously defined, the implementation falls out relatively easily, though (as we’ll see) there are a few wrinkles that will need to be followed up.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="nf">SpeechMiddleware</span><span class="p">(</span>
<span class="n">ISpeechService</span> <span class="n">speechServices</span><span class="p">,</span>
<span class="n">IReduxStore</span><span class="p"><</span><span class="n">WordTutorApplication</span><span class="p">></span> <span class="n">reduxStore</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_speechServices</span> <span class="p">=</span> <span class="n">speechServices</span><span class="p">;</span>
<span class="n">_reduxStore</span> <span class="p">=</span> <span class="n">reduxStore</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>The constructor for <code class="language-plaintext highlighter-rouge">SpeechMiddleware</code> predictably accepts an <code class="language-plaintext highlighter-rouge">ISpeechService</code> middleware reference, but why does it also need a reference to our store? This is so that we can asynchronously dispatch a <code class="language-plaintext highlighter-rouge">SpeechFinishedMessage</code> when playback completes.</p>
<p>Our implementation of <code class="language-plaintext highlighter-rouge">Dispatch()</code> reacts to a <code class="language-plaintext highlighter-rouge">SpeakMessage</code>, passing all messages through to the next handler in the chain.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">Dispatch</span><span class="p">(</span>
<span class="n">IReduxMessage</span> <span class="n">message</span><span class="p">,</span>
<span class="n">IReduxDispatcher</span> <span class="n">next</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">next</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">next</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">message</span> <span class="k">is</span> <span class="n">SpeakMessage</span> <span class="n">speak</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">Speak</span><span class="p">(</span><span class="n">speak</span><span class="p">.</span><span class="n">TextToSay</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">next</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>This async void method fits the usual pattern for event dispatch, which makes sense given that we’re reacting to a message representing a particular application event.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">async</span> <span class="k">void</span> <span class="nf">Speak</span><span class="p">(</span><span class="kt">string</span> <span class="n">textToSay</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_reduxStore</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="k">new</span> <span class="nf">SpeechStartedMessage</span><span class="p">(</span><span class="n">textToSay</span><span class="p">));</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="k">await</span> <span class="n">_speechServices</span><span class="p">.</span><span class="nf">SayAsync</span><span class="p">(</span><span class="n">textToSay</span><span class="p">)</span>
<span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">finally</span>
<span class="p">{</span>
<span class="n">_reduxStore</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="k">new</span> <span class="nf">SpeechFinishedMessage</span><span class="p">(</span><span class="n">textToSay</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>If you run the code at this point, you’ll start getting exceptions fired within the <code class="language-plaintext highlighter-rouge">Dispatch()</code> method of the <code class="language-plaintext highlighter-rouge">ReduxStore</code>, triggered by this check:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">if</span> <span class="p">(</span><span class="n">_dispatching</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// TOCONSIDER: If this exception becomes a problem, </span>
<span class="c1">// introduce a queue to serialize message processing instead.</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span>
<span class="s">"Calling Dispatch() while processing Dispatch() is not permitted."</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>What’s happening is that our middleware is trying to dispatch a second message while we’re still processing the first. Since actual reentrancy of our Redux store would result in loss of updates, we need to add support to serialize the processing of these messages (that is, to process them sequentially).</p>
<p>To fix this, we add a queue to buffer messages as they are received, delaying dispatch until we finish processing the current message. The trickiest piece of the implementation is the locking required to ensure multithreaded operation.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">Dispatch</span><span class="p">(</span><span class="n">IReduxMessage</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">currentlyDispatching</span><span class="p">;</span>
<span class="k">lock</span> <span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_messagesToDispatch</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span><span class="n">message</span>
<span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">message</span><span class="p">)));</span>
<span class="n">currentlyDispatching</span> <span class="p">=</span> <span class="n">_dispatching</span><span class="p">;</span>
<span class="n">_dispatching</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>We queue the message requiring dispatch onto our internal queue. At this point, we have one of two cases.</p>
<p>If we’re already dispatching messages (<code class="language-plaintext highlighter-rouge">_dispatching</code> is true), then we don’t want to process this message ourselves. If it’s false, then we need to process the message we have, as long as any extra message it provokes.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"> <span class="k">if</span> <span class="p">(!</span><span class="n">currentlyDispatching</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">while</span> <span class="p">(</span><span class="n">_dispatching</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">IReduxMessage</span> <span class="n">messageToDispatch</span><span class="p">;</span>
<span class="k">lock</span> <span class="p">(</span><span class="n">_padlock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_dispatching</span> <span class="p">=</span> <span class="n">_messagesToDispatch</span><span class="p">.</span><span class="nf">TryDequeue</span><span class="p">(</span>
<span class="k">out</span> <span class="n">messageToDispatch</span><span class="p">!);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_dispatching</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">iterator</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ReduxMiddlewareIterator</span><span class="p">(</span>
<span class="n">_processingQueue</span><span class="p">.</span><span class="n">Value</span><span class="p">);</span>
<span class="n">iterator</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="n">messageToDispatch</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The key to multithreaded safety is based on every manipulation of the queue and change to <code class="language-plaintext highlighter-rouge">_dispatching</code> happening within the control of the same lock.</p>
<p>Now we can work on hooking up speech generation with our maintenance screen. As well as being useful, this will be an easy way to prove that it works properly. Given the length of this post, that’s something to address next time.</p>
http://www.nichesoftware.co.nz/2020/03/28/wordtutor-redux-middleware-implementationRedux Middleware Implementation2020-03-28T00:00:00+00:002020-03-28T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Based on the interfaces we <a href="/2020/03/14/wordtutor-redux-middleware.html">defined last time</a>, let’s integrate middleware functionality into our existing Redux store. This will lay the foundation we need for asynchronous speech generation.</p>
<p>There’s a whole heap of code changes in this implementation, so instead of a blow by blow description of every piece, I’ll give you an overview of the highlights by following the flow of data - as usual, all of the code is available in the linked <a href="https://github.com/theunrepentantgeek/wordtutor/pull/37">pull request</a>.</p>
<p>Middleware is added to the Redux store by calling the imaginatively named <code class="language-plaintext highlighter-rouge">AddMiddleware()</code> method, where it’s added to the internal list <code class="language-plaintext highlighter-rouge">_middleware</code>.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">AddMiddleware</span><span class="p">(</span><span class="n">IReduxMiddleware</span> <span class="n">middleware</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_middleware</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">middleware</span><span class="p">);</span>
<span class="n">_processingQueue</span><span class="p">.</span><span class="nf">Clear</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>
<p>We store middleware as a list to allow components to be easily added and removed as required (though, admittedly, we have yet to add <code class="language-plaintext highlighter-rouge">RemoveMiddleware()</code>).</p>
<p>For the purposes of iteration, we want to have them wrapped up in a queue. Instead of recreating the queue every time we have a message to dispatch, we wrap queue creation into a <code class="language-plaintext highlighter-rouge">Cached<T></code> - a helper class much like <code class="language-plaintext highlighter-rouge">Lazy<T></code> but for the fact that it can be cleared (reset) when needed.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">readonly</span> <span class="n">Cached</span><span class="p"><</span><span class="n">ImmutableQueue</span><span class="p"><</span><span class="n">IReduxMiddleware</span><span class="p">>></span> <span class="n">_processingQueue</span><span class="p">;</span></code></pre></figure>
<p>We use an immutable queue so that we can pass it around without worrying about side effects. For example, if one of our middleware components decides to spontaneously unsubscribe in the middle of processing, we don’t want that to cause a crash.</p>
<p>In the constructor for <code class="language-plaintext highlighter-rouge">ReduxStore</code>, we initialise <code class="language-plaintext highlighter-rouge">_processingQueue</code>. Our <code class="language-plaintext highlighter-rouge">Cached<T></code> requires a factory method to be passed:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">_processingQueue</span>
<span class="p">=</span> <span class="k">new</span> <span class="n">Cached</span><span class="p"><</span><span class="n">ImmutableQueue</span><span class="p"><</span><span class="n">IReduxMiddleware</span><span class="p">>>(</span>
<span class="n">CreateProcessingQueue</span><span class="p">);</span></code></pre></figure>
<p>Creating the processing queue is fairly straightforward, but contains a couple of surprises:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="n">ImmutableQueue</span><span class="p"><</span><span class="n">IReduxMiddleware</span><span class="p">></span> <span class="nf">CreateProcessingQueue</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">queue</span>
<span class="p">=</span> <span class="n">ImmutableQueue</span><span class="p"><</span><span class="n">IReduxMiddleware</span><span class="p">>.</span><span class="n">Empty</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_subscriptions</span><span class="p">.</span><span class="n">Count</span> <span class="p">></span> <span class="m">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">queue</span> <span class="p">=</span> <span class="n">queue</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span>
<span class="n">_subscriptions</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">queue</span> <span class="p">=</span> <span class="n">_middleware</span><span class="p">.</span><span class="nf">Aggregate</span><span class="p">(</span>
<span class="n">queue</span><span class="p">,</span> <span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span> <span class="p">=></span> <span class="n">q</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span><span class="n">m</span><span class="p">));</span>
<span class="n">queue</span> <span class="p">=</span> <span class="n">queue</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span><span class="n">_reducer</span><span class="p">);</span>
<span class="k">return</span> <span class="n">queue</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>The members <code class="language-plaintext highlighter-rouge">_subscriptions</code> and <code class="language-plaintext highlighter-rouge">_reducer</code> <em>are themselves middleware components</em>.</p>
<p>This is a good indication that introducing middleware as an extension point is the right way to go. Not only do we gain a way to extend our ReduxStore with new functionality, but we’re able to <em>convert existing functionality</em> into the new structure.</p>
<p>To see what’s been changed, check out the private classes <code class="language-plaintext highlighter-rouge">SubscriptionMiddleware</code> and <code class="language-plaintext highlighter-rouge">ReducingMiddleware</code>.</p>
<p>Iteration of the queue of middleware components is delegated to the class <code class="language-plaintext highlighter-rouge">ReduxMiddlewareIterator</code>.</p>
<p>The key method here is <code class="language-plaintext highlighter-rouge">Dispatch()</code>. It uses indirect recursion, calling in turn into each middleware component, passing itself as the next call in the chain. Each recursive call consumes one item from the queue of components, with the recursion unrolling once the queue is exhausted.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">Dispatch</span><span class="p">(</span><span class="n">IReduxMessage</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_middleware</span><span class="p">.</span><span class="n">IsEmpty</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">_middleware</span> <span class="p">=</span> <span class="n">_middleware</span><span class="p">.</span><span class="nf">Dequeue</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">stage</span><span class="p">);</span>
<span class="n">stage</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Following the usual test-driven approach, a full suite of unit tests can be found in <code class="language-plaintext highlighter-rouge">ReduxMiddlewareTests</code>. Leveraging the naming convention <em>unit_scenario_expectation</em>, we can summarize those tests as follows:</p>
<p>Without middleware:</p>
<ul>
<li>Dispatch of a single message
<ul>
<li>Gives expected state</li>
</ul>
</li>
</ul>
<p>With middleware:</p>
<ul>
<li>Dispatch of a single message
<ul>
<li>Gives expected state</li>
<li>Passes message to middleware</li>
</ul>
</li>
</ul>
<p>With middleware that blocks message processing:</p>
<ul>
<li>Dispatch of a single message
<ul>
<li>State is not updated</li>
</ul>
</li>
</ul>
<p>That’s our whirlwind tour complete; next time we can look to implement support for asynchronous speech generation.</p>
http://www.nichesoftware.co.nz/2020/03/21/liskov-substitution-principle-goes-both-waysThe Liskov substitution principle goes both ways2020-03-21T00:00:00+00:002020-03-21T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>The Liskov Substitution Principle (or LSP) is one of the big five SOLID principles and one that is often poorly understood. Yet, ignorance of the LSP can lead to subtle, expensive, and sometimes embarrassing bugs.</p>
<p>The LSP can be stated in many ways, from the original formulation (which has to be regarded by non-mathematicians as dense to the point of being cryptic):</p>
<blockquote>
<p>Let <em>phi(x)</em> be a property provable about objects <em>x</em> of type <em>T</em>. Then <em>phi(y)</em> should be true for objects <em>y</em> of type <em>S</em> where <em>S</em> is a subtype of <em>T</em>.</p>
</blockquote>
<p>To the oft-stated:</p>
<blockquote>
<p>If code uses a Base class, then the reference to the Base class can be replaced with a reference to a Derived class without affecting the functionality of the code.</p>
</blockquote>
<p>What is often missed, however, is that the type compatibility goes both ways - they are <em>promises made by types</em> as much as they are <em>promises required by methods</em>.</p>
<p>Consider this method declaration:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">SendMessages</span><span class="p">(</span><span class="n">IList</span><span class="p"><</span><span class="n">EmailAddress</span><span class="p">></span> <span class="n">addresses</span><span class="p">)</span></code></pre></figure>
<p>Under the LSP this method needs to be prepared to accept any implementation of <code class="language-plaintext highlighter-rouge">IList<EmailAddress></code> - it must not be written in a way that requires, say, <code class="language-plaintext highlighter-rouge">List<EmailAddress></code> to be passed every time.</p>
<p>The reverse is true as well. Consider this class declaration:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">ContactList</span> <span class="p">:</span> <span class="n">IList</span><span class="p"><</span><span class="n">EmailAddress</span><span class="p">></span></code></pre></figure>
<p>By declaring that the class <code class="language-plaintext highlighter-rouge">ContactList</code> implements <code class="language-plaintext highlighter-rouge">IList</code>, we are making a promise that <strong><em>all</em></strong> the semantics of the <code class="language-plaintext highlighter-rouge">IList</code> interface will be correctly met, not just the syntax (with the obvious note that only the syntax is enforced by the compiler).</p>
<p>What happens if we implement our own version of <code class="language-plaintext highlighter-rouge">IList</code> with subtly different semantics, say that our <code class="language-plaintext highlighter-rouge">Add()</code> preserves uniqueness, like so:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">Set</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">:</span> <span class="n">IList</span><span class="p"><</span><span class="n">T</span><span class="p">></span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Add</span><span class="p">(</span><span class="n">T</span> <span class="n">item</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(!</span><span class="nf">Contains</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">_items</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// elided</span>
<span class="p">}</span></code></pre></figure>
<p>This is dangerous exactly because it looks <em>superficially</em> acceptable - most methods that require an <code class="language-plaintext highlighter-rouge">IList<T></code> to be provided as an argument will work fine when given a <code class="language-plaintext highlighter-rouge">Set<T></code>, giving a false sense of safety.</p>
<p>But then you’ll inadvertently find the one method that relies on the ability to store the same instance in a list multiple times. If you’re lucky, you’ll end up with a subtle and hard to diagnose error. If you’re not, your system will quietly do quite the wrong thing - such as sending a payment with the wrong amount, or issuing a prescription with too few drugs.</p>
<p>Unfortunately, the CLR includes some well known examples of what not to do, such as the way <code class="language-plaintext highlighter-rouge">Array</code> implements <code class="language-plaintext highlighter-rouge">IList</code> but throws an exception if you call <code class="language-plaintext highlighter-rouge">Add()</code> or <code class="language-plaintext highlighter-rouge">Remove()</code>. It would have been far better had it simply implemented <code class="language-plaintext highlighter-rouge">IEnumerable</code> (and then <code class="language-plaintext highlighter-rouge">IEnumerable<T></code>), but that boat sailed years ago and we can’t fix the problem now without breaking too much working code.</p>
<p>A non-CLR example that I saw several years ago was a configuration file reader for <code class="language-plaintext highlighter-rouge">.INI</code> files that provide access to the keys and values in each section by implementing <code class="language-plaintext highlighter-rouge">IDictionary<string, IDictionary<string,string>></code>.
This went poorly because it had very tight restrictions on what was permitted for section, keys, and values, throwing unexpected exceptions when other values were provided.</p>
<p>The key takeaway here is that you should be conservative with the promises your classes make. If you indicate your class implements <code class="language-plaintext highlighter-rouge">IList<T></code>, then it needs to implement <strong><em>all</em></strong> of the interface, including the semantics that the compiler doesn’t check for you automatically.</p>
http://www.nichesoftware.co.nz/2020/03/14/wordtutor-redux-middlewareRedux Middleware2020-03-14T00:00:00+00:002020-03-14T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>At this point in the development of the WordTutor, we need to properly incorporate speech generation into the application. We could hack and glue it into place on top of the existing architecture, or we can integrate it into the existing structure in a clean way.</p>
<p>There are pros and cons either way - but my experience is that nasty code inevitably becomes a curse on future developers. Let’s do it the right way.</p>
<p>On other platforms, Redux typically handles asynchronous and long-running tasks through a middleware extension point. This approach has some nice characteristics worth noting.</p>
<p><strong>Consistency</strong> - other parts of the application interact with these tasks by sending messages, just as they do for other application events. This consistency makes it easier for other developers to read, comprehend and modify the application.</p>
<p><strong>Encapsulation</strong> - other parts of the application need not even be aware of the asynchronous nature of the action. A message is sent requesting an action, and the application state changes when the action is complete. Having those two events separated in time is transparent to the consumer.</p>
<p>To create this middleware extension point in our existing ReduxStore, we need to define a couple of interfaces. The first of these is <code class="language-plaintext highlighter-rouge">IReduxMiddleware</code> and defines a single method:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">interface</span> <span class="nc">IReduxMiddleware</span>
<span class="p">{</span>
<span class="k">void</span> <span class="nf">Dispatch</span><span class="p">(</span><span class="n">IReduxMessage</span> <span class="n">message</span><span class="p">,</span> <span class="n">IReduxDispatcher</span> <span class="n">next</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>The <code class="language-plaintext highlighter-rouge">Dispatch()</code> method allows the middleware to act upon the supplied message, and the <code class="language-plaintext highlighter-rouge">next</code> parameter gives implementers a great level of flexibility. The message might be passed through unchanged, or it might be suppressed completely. The message might be replaced with a new message, or it might be supplemented with additional methods that are dispatched earlier or later.</p>
<p>The <code class="language-plaintext highlighter-rouge">IReduxDispatcher</code> interface simply allows for the message to be passed on:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">interface</span> <span class="nc">IReduxDispatcher</span>
<span class="p">{</span>
<span class="k">void</span> <span class="nf">Dispatch</span><span class="p">(</span><span class="n">IReduxMessage</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>To allow registration of middleware, we add a registration method into <code class="language-plaintext highlighter-rouge">IReduxStore</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">void</span> <span class="nf">AddMiddleware</span><span class="p">(</span><span class="n">IReduxMiddleware</span> <span class="n">middleware</span><span class="p">);</span></code></pre></figure>
<p>An alternative to this design would be for the ReduxStore constructor to accept all the defined middleware from the dependency injection container. This would introduce some difficulties around the order of middleware execution. Either we’d need to give up control of this (posing a problem for logging and exception management) or we’d need to extend our interface with some kind of priority or weighting (which is pretty nasty). Using an explicit <code class="language-plaintext highlighter-rouge">Add()</code> method is cleaner.</p>
<p>Next time, we’ll implement the changes to <code class="language-plaintext highlighter-rouge">ReduxStore</code> allowing the middleware to be used.</p>
http://www.nichesoftware.co.nz/2020/03/07/sharpen-the-sawSharpen The Saw - March 20202020-03-07T00:00:00+00:002020-03-07T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: Why Code Katas are important and how do do them well; the new Microsoft Edge is available now and coming to a PC near you; Yori is CMD reimagined; improving email one message at a time; why some people are chronically tardy; Intel patches CSME only for researches to find it’s still broken; the consequences of undocumented features; improving your CLI Prompt; and a talk on Unit Testing.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="code-katas">Code Katas</h4>
<p>In order to get good at something, we need to practice - even (or, perhaps, especially) when it comes to writing good software. Unfortunately, simply writing code every day doesn’t always count - the pressures of deadlines and commitments get in the way. Software Katas are about taking specific time to practice writing code. In this post, Mark Clearwater writes about his experiences.</p>
<p>Read more: <a href="https://blog.csmac.nz/code-kata/">blog.csmac.nz</a></p>
<h4 id="on-doing-katas">On doing katas</h4>
<p>Code Katas are a proven way to improve your proficiency as a developer - whether with a language you know, or one you’re learning. Some find them unhelpful, however - and Mark Seemann has some ideas about why this happens. The essence of his argument is that Code Katas are about solving the same (well understood) problem in a variety of different ways, forcing you to consider alternative solution techniques.</p>
<p>Read more: <a href="https://blog.ploeh.dk/2020/01/13/on-doing-katas/">blog.ploeh.dk</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="the-new-microsoft-edge-now-available-for-download">The new Microsoft Edge now available for download</h4>
<p>In case you missed the January announcement, the new Edge browser (based on the same open-source Chromium rendering engine used by Google Chrome) is now generally available for use. For the impatient, it’s available by explicit download, but for everyone else, it will be progressively rolled out by Windows Update.</p>
<p>Announcement: <a href="https://www.microsoft.com/en-us/microsoft-365/blog/2020/01/15/the-new-microsoft-edge-now-available-for-download/">microsoft.com</a></p>
<p>Download page: <a href="https://www.microsoft.com/en-us/edge?form=MO12GE&OCID=MO12GE">microsoft.com</a></p>
<h4 id="yori---the-quiet-little-cmd-replacement-that-you-need-to-install-now">Yori - The quiet little CMD replacement that you need to install NOW</h4>
<p>It’s amazing the impact that little tools can have on your day to day productivity. Scott Hanselman recommends Yori for everyone who uses CMD on a day to day basis:</p>
<blockquote>
<p>Yori feels very comfortable because it’s literally “CMD reimagined.”</p>
</blockquote>
<p>Read more: <a href="https://www.hanselman.com/blog/YoriTheQuietLittleCMDReplacementThatYouNeedToInstallNOW.aspx">hanselman.com</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="life-would-be-better-if-we-added-this-line-to-every-email">Life Would Be Better If We Added This Line to Every Email</h4>
<p>Writing effective emails is a skill - one that many people ignore. I’m a fan of <a href="http://five.sentenc.es/">five.sentenc.es</a> but that only takes you so far. Leah Fessler has a simple suggestion for your email signature that might prove useful. Even if you don’t adopt that suggestion, here’s one idea from the article that you should absolutely do:</p>
<blockquote>
<p>… write in the subject line what it is that this is about</p>
</blockquote>
<p>Read more: <a href="https://getpocket.com/explore/item/life-would-be-better-if-we-added-this-line-to-every-email">getpocket.com</a></p>
<h4 id="beat-the-clock-the-surprising-psychology-behind-being-perpetually-late">Beat the Clock: The Surprising Psychology Behind Being Perpetually Late</h4>
<p>In a former role, I had a colleague who would consistently be 5-10 minutes late for every one-hour meeting. Raised to believe that you should treat people as you would like to be treated yourself, I always found this behaviour frustrating and borderline insulting.</p>
<p>There must be a million reasons why people run late over and over again.</p>
<p>Often, the culprits are well-meaning and the underlying causes hard to identify. But, sometimes, the explanation is straightforward: with my former colleague, it was a simple power play: if a meeting room full of professionals was waiting on her arrival, clearly she was the most important person in the room.</p>
<p>Read more: <a href="https://getpocket.com/explore/item/beat-the-clock-the-surprising-psychology-behind-being-perpetually-late">getpocket.com</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="intel-patches-high-severity-flaw-in-security-engine">Intel Patches High-Severity Flaw in Security Engine</h4>
<p>Intel can’t seem to catch a break, with an ongoing series of security issues being identified with their processors. It’s gotten so bad that a good friend of mine is only considering AMD for a new high-end rig he’s building. In mid-February Intel patched a high severity vulnerability in CSME (their Converged Security and Management Engine).</p>
<p>Read more: <a href="https://threatpost.com/intel-patches-high-severity-flaw-in-security-engine/152794/">threatpost.com</a></p>
<p>But it gets worse - just a few weeks later, an even worse CSME issue is disclosed, one that’s reportedly unpatchable and unfixable. One significant mitigating factor is that it requires physical access to the machine to exploit.</p>
<p>Read more: <a href="https://www.thurrott.com/hardware/231536/security-researchers-discover-new-unfixable-flaw-on-intel-cpus">thurrott.com</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="the-opposite-of-documentation-is-superstition">The Opposite of Documentation is Superstition</h4>
<p>If a product feature you develop is left undocumented, what happens to it? Either it goes unused, undiscovered and ignored; or people come across the feature accidentally. This isn’t a good situation. For you as a developer, the value you contributed to the product is dramatically depreciated due to underuse. For the end-user, the value of the product is significantly reduced because the feature is unpredictable and seems unreliable.</p>
<p>Read more: <a href="https://buttondown.email/hillelwayne/archive/the-opposite-of-documentation-is-superstition/">buttondown.email</a></p>
<h4 id="how-to-make-a-pretty-prompt-in-windows-terminal">How to make a pretty prompt in Windows Terminal</h4>
<p>You can pack a lot of information into your prompt, regardless of the CLI you choose. In this post from Scott Hanselman, he walks you through a simple process to invigorate your prompts by filling them with useful information.</p>
<p>Read more: <a href="https://www.hanselman.com/blog/HowToMakeAPrettyPromptInWindowsTerminalWithPowerlineNerdFontsCascadiaCodeWSLAndOhmyposh.aspx">hanselman.com</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="the-clean-code-talks-unit-testing">The Clean Code Talks: Unit Testing</h4>
<p>This talk might be over a decade old - but it’s a discussion on writing untestable code that’s worth the watch. There’s good advice here.</p>
<p><strong>Audience</strong>: Developers<br />
<strong>Length</strong>: 32m</p>
<p>Watch Now: <a href="https://www.youtube.com/watch?list=PLED6CA927B41FF5BD&v=wEhu57pih5w&feature=emb_title">youtube.com</a></p>
http://www.nichesoftware.co.nz/2020/02/29/performanceAlways review code you copy2020-02-29T00:00:00+00:002020-02-29T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Recently a friend of mine noticed some code in a book that was, shall we say, considerably sub-optimal. It’s worth looking at the code to see how both the performance and readability of the code can be easily improved.</p>
<p>Here’s the original code:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Benchmark</span><span class="p">]</span>
<span class="k">public</span> <span class="n">IDictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span><span class="kt">int</span><span class="p">></span> <span class="nf">Original</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">counter</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">>();</span>
<span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">word</span> <span class="k">in</span> <span class="n">WordListLoader</span><span class="p">.</span><span class="n">Words</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">counted</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">key</span> <span class="k">in</span> <span class="n">counter</span><span class="p">.</span><span class="n">Keys</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="p">==</span> <span class="n">word</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">counter</span><span class="p">[</span><span class="n">key</span><span class="p">]++;</span>
<span class="n">counted</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">counted</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">counter</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">word</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">counter</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p><em><strong>Aside</strong>, I’m not going to call out the author of this code by name, nor mention the actual book it came from. Doing so would be unfair, both because the author would have no way to respond, and because I haven’t read the book myself (which means there may be other factors at play that justify the authors choices). The point of this post is to see what we can learn.</em></p>
<p>What does this code do?</p>
<p>Given a sequence of words, the code counts how many times each word occurs.</p>
<p>For testing, I took a copy of <a href="https://www.goodreads.com/book/show/8908.World_War_Z">World War Z</a>, extracted the text, and ran it through using BenchMark.Net.</p>
<table class="table">
<tr>
<th>Method</th>
<th class="text-right">Mean</th>
<th class="text-right">Error</th>
<th class="text-right">StdDev</th>
</tr>
<tr>
<td>Original</td>
<td class="text-right">1,806.73 ms</td>
<td class="text-right">35.070 ms</td>
<td class="text-right">51.406 ms</td>
</tr>
</table>
<p>For what it’s worth, here are the 16 most common words in the book:</p>
<table class="table">
<tr>
<th>Word</th>
<th class="text-right">Count</th>
</tr>
<tr>
<td>the</td><td class="text-right">6758</td>
</tr>
<tr>
<td>to</td><td class="text-right">3292</td>
</tr>
<tr>
<td>i</td><td class="text-right">2588</td>
</tr>
<tr>
<td>of</td><td class="text-right">2548</td>
</tr>
<tr>
<td>a</td><td class="text-right">2540</td>
</tr>
<tr>
<td>and</td><td class="text-right">2475</td>
</tr>
<tr>
<td>was</td><td class="text-right">2131</td>
</tr>
<tr>
<td>that</td><td class="text-right">1727</td>
</tr>
<tr>
<td>it</td><td class="text-right">1576</td>
</tr>
<tr>
<td>in</td><td class="text-right">1408</td>
</tr>
<tr>
<td>we</td><td class="text-right">1196</td>
</tr>
<tr>
<td>they</td><td class="text-right">1005</td>
</tr>
<tr>
<td>you</td><td class="text-right">998</td>
</tr>
<tr>
<td>were</td><td class="text-right">959</td>
</tr>
<tr>
<td>had</td><td class="text-right">940</td>
</tr>
<tr>
<td>for</td><td class="text-right">904</td>
</tr>
</table>
<p>Taking 1,800 ms to do a word count of the entire novel might be fast enough for some purposes. But, I believe the original code is not very efficient - we can do better.</p>
<p>The inner loop through Keys is entirely unnecessary - the class <code class="language-plaintext highlighter-rouge">Dictionary<K,T></code> includes <code class="language-plaintext highlighter-rouge">ContainsKey()</code>, with an implementation that’s far more efficient than the simple linear search used above. (In fact, the entire implementation is substantially more sophisticated than a simple list of tuples.)</p>
<p>Using <code class="language-plaintext highlighter-rouge">ContainsKey()</code> we can rewrite the code to this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">IDictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">></span> <span class="nf">UsingContainsKey</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">counter</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">>();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">word</span> <span class="k">in</span> <span class="n">WordListLoader</span><span class="p">.</span><span class="n">Words</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">counter</span><span class="p">.</span><span class="nf">ContainsKey</span><span class="p">(</span><span class="n">word</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">counter</span><span class="p">[</span><span class="n">word</span><span class="p">]++;</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="n">counter</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">word</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">counter</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>Observe how much shorter this code is than the original.</p>
<p>Running the benchmark again, we can see that it’s tremendously faster:</p>
<table class="table">
<tr>
<th>Method</th>
<th class="text-right">Mean</th>
<th class="text-right">Error</th>
<th class="text-right">StdDev</th>
</tr>
<tr>
<td>Original</td>
<td class="text-right">1,806.73 ms</td>
<td class="text-right">35.070 ms</td>
<td class="text-right">51.406 ms</td>
</tr>
<tr>
<td>UsingContainsKey</td>
<td class="text-right">15.10 ms</td>
<td class="text-right">0.250 ms</td>
<td class="text-right">0.234 ms</td>
</tr>
</table>
<p>In fact, it’s very nearly <em>120 times faster</em>.</p>
<p>We can do better on the performance front, however, leveraging the way that <code class="language-plaintext highlighter-rouge">TryGetValue()</code> returns a default value if the key isn’t found. We can rewrite the code without any branching:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">IDictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">></span> <span class="nf">UsingTryGetValue</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">counter</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">>();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">word</span> <span class="k">in</span> <span class="n">WordListLoader</span><span class="p">.</span><span class="n">Words</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">counter</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">word</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">count</span><span class="p">);</span>
<span class="n">counter</span><span class="p">[</span><span class="n">word</span><span class="p">]</span> <span class="p">=</span> <span class="n">count</span> <span class="p">+</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">counter</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>This is marginally faster, at the cost of being <em>a bit clever</em>:</p>
<table class="table">
<tr>
<th>Method</th>
<th class="text-right">Mean</th>
<th class="text-right">Error</th>
<th class="text-right">StdDev</th>
</tr>
<tr>
<td>Original</td>
<td class="text-right">1,806.73 ms</td>
<td class="text-right">35.070 ms</td>
<td class="text-right">51.406 ms</td>
</tr>
<tr>
<td>UsingContainsKey</td>
<td class="text-right">15.10 ms</td>
<td class="text-right">0.250 ms</td>
<td class="text-right">0.234 ms</td>
</tr>
<tr>
<td>UsingTryGetValue</td>
<td class="text-right">13.01 ms</td>
<td class="text-right">0.257 ms</td>
<td class="text-right">0.286 ms</td>
</tr>
</table>
<p>When talking performance, however, it’s always important to know <em>How fast is good enough?</em> The time taken by a developer writing the code - and by their colleagues maintaining it - are also factors.</p>
<p>For example, we can rewrite this method using LINQ extension methods and make it far easier to understand & maintain:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">IDictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">></span> <span class="nf">UsingLinq</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">counter</span> <span class="p">=</span> <span class="n">WordListLoader</span><span class="p">.</span><span class="n">Words</span>
<span class="p">.</span><span class="nf">GroupBy</span><span class="p">(</span><span class="n">w</span> <span class="p">=></span> <span class="n">w</span><span class="p">)</span>
<span class="p">.</span><span class="nf">ToDictionary</span><span class="p">(</span><span class="n">g</span> <span class="p">=></span> <span class="n">g</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span> <span class="n">g</span> <span class="p">=></span> <span class="n">g</span><span class="p">.</span><span class="nf">Count</span><span class="p">());</span>
<span class="k">return</span> <span class="n">counter</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>This isn’t as fast as the methods we’ve seen, though it’s still 70 times faster than the original. Arguably it is easier to read; the trade-off may be appropriate if the performance is good enough.</p>
<table class="table">
<tr>
<th>Method</th>
<th class="text-right">Mean</th>
<th class="text-right">Error</th>
<th class="text-right">StdDev</th>
</tr>
<tr>
<td>Original</td>
<td class="text-right">1,806.73 ms</td>
<td class="text-right">35.070 ms</td>
<td class="text-right">51.406 ms</td>
</tr>
<tr>
<td>UsingContainsKey</td>
<td class="text-right">15.10 ms</td>
<td class="text-right">0.250 ms</td>
<td class="text-right">0.234 ms</td>
</tr>
<tr>
<td>UsingTryGetValue</td>
<td class="text-right">13.01 ms</td>
<td class="text-right">0.257 ms</td>
<td class="text-right">0.286 ms</td>
</tr>
<tr>
<td>UsingLINQ</td>
<td class="text-right">25.51 ms</td>
<td class="text-right">0.493 ms</td>
<td class="text-right">0.782 ms</td>
</tr>
</table>
<h3 id="conclusion">Conclusion</h3>
<p>What lessons can we learn from this?</p>
<p><strong>Always measure performance.</strong> I had a strong hunch that the code was inefficient due to the unnecessary inner loop, but it wasn’t until I had profiled both approaches that I knew exactly how much faster it could be.</p>
<p><strong>Leverage your class library.</strong> Doing things the hard way by writing more code might seem superficially easier at first, but it’s unlikely to pay off in the long run. It’s highly likely that your platform’s class library will have more efficient and more reliable solutions than what you might write yourself.</p>
<p><strong>Be wary of blindly copying code.</strong> When you copy code, whether it’s out of a book, from a blog like this one, or from <a href="https://stackoverflow.com/">StackOverflow</a> it’s vital to understand what the code is doing. Critical thinking is a vital part of every developers toolkit.</p>
<h3 id="addendum">Addendum</h3>
<p>A friend suggested also benchmarking <code class="language-plaintext highlighter-rouge">ConcurrentDictionary<T,K></code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">IDictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">></span> <span class="nf">UsingConcurrentDictionary</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">counter</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ConcurrentDictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">>();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">word</span> <span class="k">in</span> <span class="n">WordListLoader</span><span class="p">.</span><span class="n">Words</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">counter</span><span class="p">.</span><span class="nf">AddOrUpdate</span><span class="p">(</span><span class="n">word</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="p">=></span> <span class="n">v</span> <span class="p">+</span> <span class="m">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">counter</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>The lambda expression will be allocated once, so this is relatively lightweight on heap allocation. The performance is very nearly as good as a regular dictionary, showing the cost of non-contested locks is negligible.</p>
<table class="table">
<tr>
<th>Method</th>
<th class="text-right">Mean</th>
<th class="text-right">Error</th>
<th class="text-right">StdDev</th>
</tr>
<tr>
<td>Original</td>
<td class="text-right">1,806.73 ms</td>
<td class="text-right">35.070 ms</td>
<td class="text-right">51.406 ms</td>
</tr>
<tr>
<td>UsingContainsKey</td>
<td class="text-right">15.10 ms</td>
<td class="text-right">0.250 ms</td>
<td class="text-right">0.234 ms</td>
</tr>
<tr>
<td>UsingTryGetValue</td>
<td class="text-right">13.01 ms</td>
<td class="text-right">0.257 ms</td>
<td class="text-right">0.286 ms</td>
</tr>
<tr>
<td>UsingLINQ</td>
<td class="text-right">25.51 ms</td>
<td class="text-right">0.493 ms</td>
<td class="text-right">0.782 ms</td>
</tr>
<tr>
<td>UsingConcurrentDictionary</td>
<td class="text-right">21.18 ms</td>
<td class="text-right">0.386 ms</td>
<td class="text-right">0.361 ms</td>
</tr>
</table>
http://www.nichesoftware.co.nz/2020/02/15/wordtutor-speech-apiSpeech API2020-02-15T00:00:00+00:002020-02-15T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>For the WordTutor application to work, we need to be able to read words (and letters) out loud to our student. To power the speech synthesis, we’re going to integrate Azure Cognitive Services into the application.</p>
<h3 id="azure-speech-api">Azure Speech API</h3>
<p>Setting up access to the Speech API within Azure Cognitive Services is relatively straightforward. Rather than repeating the details here, I’ll just point you to <a href="https://docs.microsoft.com/azure/cognitive-services/speech-service/quickstarts/text-to-speech">the quickstart</a>. I’m using the free tier (“F0”), allowing for up to 5 hours of speech rendering per month.</p>
<p>When you’re finished creating your service, take note of the region you used (mine was <code class="language-plaintext highlighter-rouge">australiaeast</code>) and one of the API keys generated for you.</p>
<h3 id="secret-management">Secret Management</h3>
<p>We don’t want to embed any secrets directly in the application, nor commit them to our git repository.</p>
<p>Fortunately, we can easily move those secrets out of the application, using a couple of NuGet packages:</p>
<ul>
<li><a href="https://www.nuget.org/packages/Microsoft.Extensions.Configuration"><code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Configuration</code></a> provides basic infrastructure; and</li>
<li><a href="https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets"><code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Configuration.UserSecrets</code></a> allows us to keep our secrets outside the project directory during development.</li>
</ul>
<p>There are other packages available as well, allowing configuration to be stored in other places.</p>
<p>With those packages installed, we can use the <code class="language-plaintext highlighter-rouge">dotnet</code> command to store our secrets.</p>
<p>For the entry-point project of our application we need a one-time initialization:</p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">PS> dotnet user-secrets init
Set UserSecretsId to 'ab66dbe0-608d-4ac8-84a4-cb083baac56b'
for MSBuild project '...\WordTutor.Azure.csproj'.</code></pre></figure>
<p>If you’re doing this for yourself, don’t make the mistake I just showed above! Secrets configuration needs to be done for the <em>entry point</em> of the project, so I had to redo the above step for the <code class="language-plaintext highlighter-rouge">WordTutor.Desktop</code> project.</p>
<p>Once completed, you’ll find a <code class="language-plaintext highlighter-rouge"><UserSecretsId></code> element has been added to the <code class="language-plaintext highlighter-rouge">.csproj</code> file of your project, in the first <code class="language-plaintext highlighter-rouge"><PropertyGroup></code>:</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><PropertyGroup></span>
<span class="nt"><OutputType></span>WinExe<span class="nt"></OutputType></span>
<span class="nt"><TargetFramework></span>netcoreapp3.0<span class="nt"></TargetFramework></span>
...
<span class="nt"><UserSecretsId></span>ab66dbe0-608d-4ac8-84a4-cb083baac56b<span class="nt"></UserSecretsId></span>
<span class="nt"></PropertyGroup></span></code></pre></figure>
<p>To store our two secrets, we again use the <code class="language-plaintext highlighter-rouge">dotnet</code> command:</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="n">PS</span><span class="err">></span><span class="w"> </span><span class="nx">dotnet</span><span class="w"> </span><span class="nx">user-secrets</span><span class="w"> </span><span class="nx">set</span><span class="w"> </span><span class="s2">"WordTutor:SpeechApiKey"</span><span class="w"> </span><span class="s2">"yoursupersecretapikeygoeshere"</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">saved</span><span class="w"> </span><span class="nx">WordTutor:SpeechApiKey</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">yoursupersecretapikeygoeshere</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">secret</span><span class="w"> </span><span class="nx">store.</span><span class="w">
</span><span class="n">dotnet</span><span class="w"> </span><span class="nx">user-secrets</span><span class="w"> </span><span class="nx">set</span><span class="w"> </span><span class="s2">"WordTutor:SpeechApiRegion"</span><span class="w"> </span><span class="s2">"australiaeast"</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">saved</span><span class="w"> </span><span class="nx">WordTutor:SpeechApiRegion</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">australiaeast</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">secret</span><span class="w"> </span><span class="nx">store.</span></code></pre></figure>
<p>These secrets are stored in your user profile on this PC. Navigate to the folder <code class="language-plaintext highlighter-rouge">%USERPROFLE%\AppData\Roaming\Microsoft\UserSecrets</code> to find a folder with the name matching the <code class="language-plaintext highlighter-rouge"><UserSecretsId></code> from above; inside there is <code class="language-plaintext highlighter-rouge">usersecrets.json</code>, containing your secrets. It’s worth emphasizing that there’s no encryption here; the goal is to keep the secrets out of your git repo, not to hide them from you.</p>
<h3 id="speech-service">Speech service</h3>
<p>We need to declare a service interface for our application, representing the speech service in a technology-agnostic way:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">interface</span> <span class="nc">ISpeechService</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
<span class="n">Task</span> <span class="nf">SayAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Using this interface will allow us to wire up a fake service for testing purposes, allowing us to verify correct behaviour without actually calling into the Azure implementation and incurring costs.</p>
<p>Our primary implementation of <code class="language-plaintext highlighter-rouge">ISpeechService</code> will be <code class="language-plaintext highlighter-rouge">AzureSpeechService</code>. To keep our dependencies properly isolated, this lives in a new project <code class="language-plaintext highlighter-rouge">WordTutor.Azure</code>. Anything else Azure related we choose to add in the future will live here too.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">AzureSpeechService</span> <span class="p">:</span> <span class="n">ISpeechService</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IConfigurationRoot</span> <span class="n">_configurationRoot</span><span class="p">;</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ILogger</span> <span class="n">_logger</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">AzureSpeechService</span><span class="p">(</span>
<span class="n">IConfigurationRoot</span> <span class="n">configuration</span><span class="p">,</span>
<span class="n">ILogger</span> <span class="n">logger</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// elided</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">SayAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// elided</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The <code class="language-plaintext highlighter-rouge">IConfigurationRoot</code> parameter for the constructor is how we retrieve the user secrets we stashed away earlier. In full, the constructor looks like this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="nf">AzureSpeechService</span><span class="p">(</span><span class="n">IConfigurationRoot</span> <span class="n">configuration</span><span class="p">,</span> <span class="n">ILogger</span> <span class="n">logger</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_configurationRoot</span> <span class="p">=</span> <span class="n">configuration</span>
<span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">configuration</span><span class="p">));</span>
<span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span>
<span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">logger</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">apiKey</span> <span class="p">=</span> <span class="n">_configurationRoot</span><span class="p">[</span><span class="s">"WordTutor:SpeechApiKey"</span><span class="p">];</span>
<span class="kt">var</span> <span class="n">apiRegion</span> <span class="p">=</span> <span class="n">_configurationRoot</span><span class="p">[</span><span class="s">"WordTutor:SpeechApiRegion"</span><span class="p">];</span>
<span class="n">_logger</span><span class="p">.</span><span class="nf">Debug</span><span class="p">(</span><span class="s">$"ApiKey: </span><span class="p">{</span><span class="n">apiKey</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="n">_logger</span><span class="p">.</span><span class="nf">Debug</span><span class="p">(</span><span class="s">$"ApiRegion: </span><span class="p">{</span><span class="n">apiRegion</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="n">_configuration</span> <span class="p">=</span> <span class="n">SpeechConfig</span><span class="p">.</span><span class="nf">FromSubscription</span><span class="p">(</span><span class="n">apiKey</span><span class="p">,</span> <span class="n">apiRegion</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h3 id="simpleinjector">SimpleInjector</h3>
<p>To make our <code class="language-plaintext highlighter-rouge">ISpeechService</code> available for consumption, we need to register it with our dependency injection container.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// Register Services</span>
<span class="n">container</span><span class="p">.</span><span class="n">RegisterSingleton</span><span class="p"><</span><span class="n">ISpeechService</span><span class="p">,</span> <span class="n">AzureSpeechService</span><span class="p">>();</span></code></pre></figure>
<p>We also need a singleton registration for <code class="language-plaintext highlighter-rouge">IConfigurationRoot</code>. To build this we need to first build it:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// Register Configuration</span>
<span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ConfigurationBuilder</span><span class="p">();</span>
<span class="n">builder</span><span class="p">.</span><span class="n">AddUserSecrets</span><span class="p"><</span><span class="n">Program</span><span class="p">>();</span>
<span class="n">container</span><span class="p">.</span><span class="n">RegisterInstance</span><span class="p"><</span><span class="n">IConfigurationRoot</span><span class="p">>(</span><span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">());</span></code></pre></figure>
<p>The generic parameter <code class="language-plaintext highlighter-rouge">Program</code> provided to the <code class="language-plaintext highlighter-rouge">AddUserSecrets()</code> call is used to identify the entry-point assembly. The <code class="language-plaintext highlighter-rouge"><UserSecretsId></code> element from the <code class="language-plaintext highlighter-rouge">csproj</code> file turns into an assembly level attribute, allowing the running application to find the secrets it needs.</p>
<h3 id="consumption">Consumption</h3>
<p>Finally, for demo purposes, we can inject <code class="language-plaintext highlighter-rouge">ISpeechService</code> into our main window, hook it up to a button and make everything work.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="nf">WordTutorWindow</span><span class="p">(</span>
<span class="n">ViewModelToViewValueConverter</span> <span class="n">converter</span><span class="p">,</span>
<span class="n">ISpeechService</span> <span class="n">speechService</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Resources</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"ViewModelToViewValueConverter"</span><span class="p">,</span> <span class="n">converter</span><span class="p">);</span>
<span class="nf">InitializeComponent</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">speechService</span> <span class="p">=</span> <span class="n">speechService</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Button_Click</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">RoutedEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">speechService</span><span class="p">.</span><span class="nf">SayAsync</span><span class="p">(</span><span class="s">"Hello World."</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Having (literally!) achieved <em>“Hello World”</em>, we need to make a number of improvements. Most notably, we currently have a non-trivial lag before speech begins - plus we’re re-rendering the same text as audio every time we want to speak. Some caching - and some pre-caching - seems to be in order.</p>
http://www.nichesoftware.co.nz/2020/02/08/dtoDumb Transfer Objects2020-02-08T00:00:00+00:002020-02-08T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>An anti-pattern variant of <em>Data Transfer Objects</em> (DTOs) where the objects are forcefully deprived of all possible functionality, even for matters that are directly relevant such as construction, serialization, and (first stage) validation.</p>
<p>Some believe that data transfer objects must only contain data and that there must be no behaviour declared on the type at all. Their understanding of the conceptual model is that DTOs are entirely and only about the data they contain.</p>
<p>In my experience, the purpose of a data transfer object is to encapsulate part of the external boundary of a system, taking explicit control of the way information (data) is transferred across that boundary.</p>
<p>For a data transfer object to fully meet this requirement, it has to also contain behaviour.</p>
<p>We can explore what this means from multiple perspectives.</p>
<h3 id="outbound-data">Outbound Data</h3>
<p>For outbound information, a DTO presents a well-designed structure to the outside world, one that intentionally shapes the information being made available. Ideally, this structure should be invariant over time, even as the system providing the data evolves and adapts.</p>
<p>I’ve found it useful for a DTO to have a formal constructor that initializes all mandatory properties, thus ensuring that the system never generates a DTO with key information missing. Such a constructor will often accept data in native formats, providing translation into serializable forms.</p>
<h3 id="inbound-data">Inbound Data</h3>
<p>For inbound data, a DTO needs to accept whatever is sent by clients - which makes it the first point of contact for untrustworthy data. The first responsibility here is for early detection of errors (missing or over-length properties, invalid formats, out of range values etc), while the second is for transformation (conversion of strings into timestamps, etc).</p>
<p>Adding straightforward validation code to a DTO provides an easy way to prevent invalid and/or malicious information from getting past the outer layers of our application.</p>
<p>For example, if you have a <code class="language-plaintext highlighter-rouge">FullName</code> field you can check that it contains only printable characters, isn’t too long, and so on. The goal here is to reject the obviously malicious.</p>
<p>There’s a trap here - we need to avoid making things too restrictive. Single character names are common in some places, and 100 characters aren’t enough for some real people. (See <a href="https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/">Falsehoods Programmers Believe About Names</a> for some good advice.)</p>
<p>A good rule of thumb is to include only validation on the DTO that can be done in isolation, without reference to outside sources. For example, you can check the format of an ISO 4217 currency code by rejecting any value longer than three characters, as well as any value not made up of letters. You shouldn’t worry about whether a well-formed code is known to your system - leave that to your business domain layer.</p>
<h3 id="type-conversion">Type Conversion</h3>
<p>We often require a DTO to transform the presentation of information from the forms used internally into forms suitable for publication. For example, converting a .NET <code class="language-plaintext highlighter-rouge">DateTimeOffset</code> structure into an ISO8601 format string, or an internal enumeration into a string.</p>
<p>This becomes particularly powerful when we start using semantic types in our application domain. We can expose a simple string representing a part number to the outside world, and convert that into a <code class="language-plaintext highlighter-rouge">PartNumber</code> instance for internal use.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Constraining your system to only use <em>dumb transfer objects</em> just makes your application more complicated - you still need all of the same behaviours, but now you need to find them new places to live. Put the behaviour where it belongs - on your <em>data transfer objects</em>, right on the external boundary of your application.</p>
http://www.nichesoftware.co.nz/2020/02/01/sharpen-the-saw Sharpen The Saw - February 20202020-02-01T00:00:00+00:002020-02-01T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: how to write better git commit messages; a cool debugger trick for Visual Studio; a new approach for producer/consumer programming in .NET Core 3.0; how to focus in on a part of a data structure; an alternative to a regular to-do list; how to apologize; protecting users against poor password choices; the NSA does the right thing; the day when someone discovered they had too many interfaces; a Java programmer discovers GoLang; and a Ted Talk on why privacy matters.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="a-note-about-git-commit-messages">A note about git commit messages</h4>
<p>Writing a good git commit message can be a challenge. I’ve sure we’ve all seen codebases littered with commit messages like “Addressing PR feedback”, “Fixing off-by-one bug”, “Second attempt at fixing off-by-one-bug” and “It should work this time”. Here’s some valuable guidance on writing commit messages that are actually useful to any future developers looking back.</p>
<p><a href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">Read More</a></p>
<h4 id="debugger-trick-when-working-with-utc-datetimes">Debugger Trick when Working with UTC DateTimes</h4>
<p>That moment when you learn you can use the <code class="language-plaintext highlighter-rouge">[DebuggerDisplay]</code> attribute in more places than you thought.
Chris Missal blogs about using it to clarify date display when debugging - but it has much wider applicability.</p>
<p><a href="https://lostechies.com/chrismissal/2012/06/12/debugger-trick-when-working-with-utc-datetimes/">Read More</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="an-introduction-to-systemthreadingchannels">An introduction to System.Threading.Channels</h4>
<p>For the cases when you need a producer/consumer model in your application, the new <code class="language-plaintext highlighter-rouge">System.Threading.Channels</code> library might be just what you need. I know that I’ve encountered many situations where this library would have been extremely useful - and as soon as some of those projects are converted to .NET Core 3.0, I suspect I’ll be ripping out my bespoke solutions in favour of this library.</p>
<p><a href="https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/">Read More</a></p>
<h4 id="lenscs">Lens.cs</h4>
<p>In functional programming, a <strong>Lens</strong> is something you can pass around that allows other code to focus tightly in on a specific part of a larger object, allowing the value to be easily read or modified, even if the larger object is immutable. This sample code From GitHub shows one way they can be implemented in C#. I haven’t quite got my head around how they work just yet, but it’s an interesting idea to play around with.</p>
<p><a href="https://gist.github.com/tonymorris/3262058">Read More</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="the-to-do-list-method-for-people-with-crazy-lives-and-short-attention-spans">The to-do list method for people with crazy lives and short attention spans</h4>
<p>I’ve become one of those insufferable people who live and die by their to-do list; most everything I need to do goes into the list(*). I, therefore, found this short blog post from Lila MacLellan to be somewhat challenging, as they make the assertion that standard to-do lists incentivize the wrong behaviour. My takeaway is that the purpose of the list is to ensure I don’t forget things - but it’s a poor tool for selecting what I work on next.</p>
<p>(*) In my defence, I do try to avoid evangelising it with other people - the key is to find an approach that works for you. My brain leaks like a rusty colander, so I find some form of external backup is necessary.</p>
<p><a href="https://getpocket.com/explore/item/the-to-do-list-method-for-people-with-crazy-lives-and-short-attention-spans">Read Me</a></p>
<h4 id="how-to-apologize-so-people-forgive-you">How to apologize so people forgive you</h4>
<p>It can be difficult to admit when you’ve made a mistake. In fact, some people find it so hard that they never admit their mistakes, not even to themselves. In this LifeHacker post, Aimée Lutkin suggests a useful technique for apologizing in a way that allows everyone to move on.</p>
<p><a href="https://www.lifehacker.com.au/2018/09/how-to-apologize-so-people-forgive-you/">Read More</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="pwned-passwords-in-practice-real-world-examples-of-blocking-the-worst-passwords">Pwned passwords in practice: Real-world examples of blocking the worst passwords</h4>
<p>One of the services that Troy Hunt makes available as a part of Have I Been Pwned is an API giving a safe way to check whether a given password has been included in any of the breaches listed on the side. In this post, Troy highlights several ways that his service has been integrated by other providers, protecting their users.</p>
<p><a href="https://www.troyhunt.com/pwned-passwords-in-practice-real-world-examples-of-blocking-the-worst-passwords/">Read More</a></p>
<h4 id="nsa-found-a-dangerous-microsoft-software-flaw-and-alerted-the-firm--rather-than-weaponizing-it">NSA found a dangerous Microsoft software flaw and alerted the firm — rather than weaponizing it</h4>
<p>The American NSA has a history of researching and discovering software flaws, hoarding them for later use. In a possibly surprising move (depending on who you talk to), they didn’t choose to keep this one secret, but instead formally notified Microsoft, enabling the flaw to be patched.</p>
<p>PSA: Make sure you have the latest Windows patches installed; if you don’t have the ones from January 2020, you’re vulnerable.</p>
<p><a href="https://www.washingtonpost.com/national-security/nsa-found-a-dangerous-microsoft-software-flaw-and-alerted-the-firm--rather-than-weaponize-it/2020/01/14/f024c926-3679-11ea-bb7b-265f4554af6d_story.html">Read More</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="65535-interfaces-ought-to-be-enough-for-anybody">65535 interfaces ought to be enough for anybody</h4>
<p>An interesting story digging into the implementation details of various .NET runtimes and how a limitation in one of them gave someone quite a headache. It all started when Audrey Akinshin came into work to find that her unit tests were failing even though none of that code had been recently modified.</p>
<p><a href="https://aakinshin.net/posts/mono-and-65535interfaces/">Read More</a></p>
<h4 id="comparing-golang-with-java">Comparing Golang with Java</h4>
<p>As some of my colleagues have adopted the Go language, I’ve been picking up details by a kind of osmosis as they comment on what they are doing. This probably means that I have a somewhat distorted view of things since they tend to comment on the extremes - the awesome features, and the quirks that they consider completely insane. This article by Peter Verhas gives some of his first impressions, based on his background with Java.</p>
<p><a href="https://javax0.wordpress.com/2016/04/27/comparing-golang-with-java/">Read More</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="glenn-greenwald-why-privacy-matters">Glenn Greenwald: Why privacy matters</h4>
<p>In this thought-provoking talk, Glenn Grenwald talks about the importance of privacy, how people dramatically change their behaviour when they think they’re being observed, and why people who assert that “only bad people have something to hide” are invariably unwilling to give up their own privacy.</p>
<p><strong>Audience</strong>: Everyone<br />
<strong>Length</strong>: 21m</p>
<p><a href="https://www.youtube.com/watch?v=pcSlowAhvUk">Watch Now</a></p>
http://www.nichesoftware.co.nz/2020/01/25/wordtutor-logging-implementationLogging Implementation2020-01-25T00:00:00+00:002020-01-25T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>To implement the <a href="/2019/12/28/logging-interfaces.html">logging interfaces</a> described earlier, there are some issues we need to consider. There are two different usage patterns we need to support, plus we need to support concurrent use, and avoid code duplication.</p>
<h3 id="usage-scenarios">Usage Scenarios</h3>
<p>The first scenario is when a method controls the context of its logging; the logger reference it needs is immediate to hand and easily used. Different parts of the application will pass around the logger as required.</p>
<p>The second, and more complex, is when a helper method wants to ensure that its logging is properly included in the active scope. We need to have some way for the current logging context to be found when required. Preferably, this would be a technique that doesn’t require adding a logger to every method signature.</p>
<p>For each of these scenarios, we will create a different logging class - a <code class="language-plaintext highlighter-rouge">ScopedLogger</code> for the case where we are keeping explicit references to our current logging context, and a <code class="language-plaintext highlighter-rouge">DelegatingLogger</code> for the case where we need to coordinate with a context created elsewhere. They will share the common base class <code class="language-plaintext highlighter-rouge">LoggerBase</code> to avoid code duplication.</p>
<h3 id="asynchronous-support">Asynchronous support</h3>
<p>To cleanly associate a distinct logger with each asynchronous task, we want something akin to the <code class="language-plaintext highlighter-rouge">[ThreadLocal]</code> attribute; fortunately, we don’t need to look far to find the <code class="language-plaintext highlighter-rouge">AsyncLocal<T></code> class. We use this to declare a static property to give us access to the logger wherever needed:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">LoggerBase</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">AsyncLocal</span><span class="p"><</span><span class="n">ScopedLogger</span><span class="p">?></span> <span class="n">_currentLogger</span>
<span class="p">=</span> <span class="k">new</span> <span class="n">AsyncLocal</span><span class="p"><</span><span class="n">ScopedLogger</span><span class="p">?>();</span>
<span class="k">protected</span> <span class="k">static</span> <span class="n">ScopedLogger</span><span class="p">?</span> <span class="n">CurrentLogger</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">=></span> <span class="n">_currentLogger</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span>
<span class="k">set</span> <span class="p">=></span> <span class="n">_currentLogger</span><span class="p">.</span><span class="n">Value</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>With this in place, we can introduce methods to actually write the message out:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">LoggerBase</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="k">abstract</span> <span class="k">void</span> <span class="nf">WriteLogMessage</span><span class="p">(</span>
<span class="n">LogKind</span> <span class="n">logKind</span><span class="p">,</span>
<span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="k">protected</span> <span class="k">void</span> <span class="nf">WriteLogMessage</span><span class="p">(</span>
<span class="n">ScopedLogger</span><span class="p">?</span> <span class="n">currentAction</span><span class="p">,</span>
<span class="n">LogKind</span> <span class="n">logKind</span><span class="p">,</span>
<span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">level</span> <span class="p">=</span> <span class="n">currentAction</span><span class="p">?.</span><span class="n">Level</span> <span class="p">??</span> <span class="m">0</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">now</span> <span class="p">=</span> <span class="n">DateTimeOffset</span><span class="p">.</span><span class="n">Now</span><span class="p">;</span>
<span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"</span><span class="p">{</span><span class="n">now</span><span class="p">:</span><span class="n">u</span><span class="p">}</span><span class="s"> </span><span class="p">{</span><span class="nf">Indent</span><span class="p">(</span><span class="n">level</span><span class="p">)}{</span><span class="n">_prefixes</span><span class="p">[</span><span class="n">logKind</span><span class="p">]}</span><span class="s"> </span><span class="p">{</span><span class="n">message</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>For <code class="language-plaintext highlighter-rouge">DelegatingLogger</code>, we implement the abstract <code class="language-plaintext highlighter-rouge">WriteLogMessge</code> using <code class="language-plaintext highlighter-rouge">CurrentLogger</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">DelegatingLogger</span> <span class="p">:</span> <span class="n">LoggerBase</span><span class="p">,</span> <span class="n">ILogger</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">WriteLogMessage</span><span class="p">(</span>
<span class="n">LogKind</span> <span class="n">logKind</span><span class="p">,</span> <span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">=></span> <span class="nf">WriteLogMessage</span><span class="p">(</span><span class="n">CurrentLogger</span><span class="p">,</span> <span class="n">logKind</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Conversely, for <code class="language-plaintext highlighter-rouge">ScopedLogger</code>, we already know the necessary context and we can pass it directly:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">ScopedLogger</span><span class="p">:</span> <span class="n">LoggerBase</span><span class="p">,</span> <span class="n">IScopedLogger</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">WriteLogMessage</span><span class="p">(</span>
<span class="n">LogKind</span> <span class="n">logKind</span><span class="p">,</span>
<span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_disposed</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ObjectDisposedException</span><span class="p">(</span>
<span class="s">"Scoped loggers may not be used after disposal."</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">base</span><span class="p">.</span><span class="nf">WriteLogMessage</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">logKind</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>I’ve thrown in a little sanity check to ensure we’re not continuing to use a scoped logger after the scope has been completed.</p>
<h3 id="avoiding-code-duplication">Avoiding code duplication</h3>
<p>We introduced the base class <code class="language-plaintext highlighter-rouge">LoggerBase</code> that provides functionality common to both logging situations. As a part of that class, let us declare an enumeration that captures the different kinds of logging messages we want to emit:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">protected</span> <span class="k">enum</span> <span class="n">LogKind</span>
<span class="p">{</span>
<span class="n">None</span><span class="p">,</span>
<span class="n">Debug</span><span class="p">,</span>
<span class="n">Info</span><span class="p">,</span>
<span class="n">OpenAction</span><span class="p">,</span>
<span class="n">CloseAction</span><span class="p">,</span>
<span class="n">Success</span><span class="p">,</span>
<span class="n">Failure</span>
<span class="p">}</span></code></pre></figure>
<p>We can then implement most of our desired logging methods as simple helpers that all delegate to <code class="language-plaintext highlighter-rouge">WriteLogMessage()</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">Success</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">=></span> <span class="nf">WriteLogMessage</span><span class="p">(</span><span class="n">LogKind</span><span class="p">.</span><span class="n">Success</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Failure</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">=></span> <span class="nf">WriteLogMessage</span><span class="p">(</span><span class="n">LogKind</span><span class="p">.</span><span class="n">Failure</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Info</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">=></span> <span class="nf">WriteLogMessage</span><span class="p">(</span><span class="n">LogKind</span><span class="p">.</span><span class="n">Info</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Debug</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">=></span> <span class="nf">WriteLogMessage</span><span class="p">(</span><span class="n">LogKind</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span></code></pre></figure>
<p>The remaining log method is <code class="language-plaintext highlighter-rouge">Action</code>, which returns a scoped logger after updating <code class="language-plaintext highlighter-rouge">CurrentLogger</code> to match.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">IScopedLogger</span> <span class="nf">Action</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">WriteLogMessage</span><span class="p">(</span><span class="n">LogKind</span><span class="p">.</span><span class="n">OpenAction</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="n">CurrentLogger</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ScopedLogger</span><span class="p">(</span><span class="n">CurrentLogger</span><span class="p">);</span>
<span class="k">return</span> <span class="n">CurrentLogger</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>For each kind of log message, we define a dictionary of prefixes to use so that they’re easily distinguishable in the output:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">readonly</span> <span class="n">Dictionary</span><span class="p"><</span><span class="n">LogKind</span><span class="p">,</span> <span class="kt">string</span><span class="p">></span> <span class="n">_prefixes</span>
<span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p"><</span><span class="n">LogKind</span><span class="p">,</span> <span class="kt">string</span><span class="p">></span>
<span class="p">{</span>
<span class="p">{</span> <span class="n">LogKind</span><span class="p">.</span><span class="n">Debug</span><span class="p">,</span> <span class="s">" · "</span> <span class="p">},</span>
<span class="p">{</span> <span class="n">LogKind</span><span class="p">.</span><span class="n">Info</span><span class="p">,</span> <span class="s">"[•]"</span> <span class="p">},</span>
<span class="p">{</span> <span class="n">LogKind</span><span class="p">.</span><span class="n">OpenAction</span><span class="p">,</span> <span class="s">"[>]"</span> <span class="p">},</span>
<span class="p">{</span> <span class="n">LogKind</span><span class="p">.</span><span class="n">CloseAction</span><span class="p">,</span> <span class="s">"[<]"</span> <span class="p">},</span>
<span class="p">{</span> <span class="n">LogKind</span><span class="p">.</span><span class="n">Success</span><span class="p">,</span> <span class="s">"[✔]"</span> <span class="p">},</span>
<span class="p">{</span> <span class="n">LogKind</span><span class="p">.</span><span class="n">Failure</span><span class="p">,</span> <span class="s">"[✘]"</span> <span class="p">}</span>
<span class="p">};</span></code></pre></figure>
<p>It’s very common for text-based loggers to use somewhat cryptic abbreviations for the different log levels. Here we could have instead used <code class="language-plaintext highlighter-rouge">DBG</code>, <code class="language-plaintext highlighter-rouge">INF</code>, <code class="language-plaintext highlighter-rouge">STA</code>, <code class="language-plaintext highlighter-rouge">FIN</code>, <code class="language-plaintext highlighter-rouge">SUC</code> and <code class="language-plaintext highlighter-rouge">ERR</code> - but I wanted something with a little more visual appeal, so I’ve used some Unicode characters instead.</p>
<h3 id="conclusion">Conclusion</h3>
<p>With this text-based logger in place, we can review the use of the application using the Output window of Visual Studio. Later on, we might want to replace this with something built into the application to allow troubleshooting without Visual Studio.</p>
http://www.nichesoftware.co.nz/2020/01/18/impossible-numbersImpossible Numbers2020-01-18T00:00:00+00:002020-01-18T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>There’s a very clever piece of design advice that I was taught at university that seems to be less well known than I expected.</p>
<p>A computer science lecturer of mine once said:</p>
<blockquote>
<p>There are ony three possible numbers in computer science. Zero, One, and Infinity.</p>
</blockquote>
<p>Unfortunately, I can’t remember which of my lecturers it was. If you were in any of my classes - and you recognize the quote, please let me know!</p>
<p>At first glance this advice seems a bit odd. Surely there are cases where other numbers are useful.</p>
<p>Over the course of my career, I’ve run into significant difficulties every time I’ve thought a different number was appropriate.</p>
<p>Here’s an example.</p>
<p><em>How do you capture the opening hours of a business for each day?</em></p>
<p>Imagine you are building an application for a small takeway burger bar called The Burger Box. Betty, the owner, tells you that she is open seven days a week, opening at 11am each day for the lunch crowd. Closing time varies each day, with Friday and Sunday extending into the wee small hours of the following morning.</p>
<p>One, very straightforward, approach is to capture the opening & closing hours for each day of the week. Exactly seven pairs, seeming to capture the requirements well - and the number of days in the week isn’t going to change any time soon.</p>
<p>But problems soon emerge.</p>
<p>How do you capture days where the business is required to close for the day?</p>
<p>In New Zealand, most businesses are required to be <a href="https://www.employment.govt.nz/leave-and-holidays/public-holidays/restricted-shop-trading-days/">closed on certain official holidays</a> such as Christmas Day, Good Friday, and Easter Sunday.</p>
<p>Or what do you do when the hours of opening are different - as they are on <a href="https://en.wikipedia.org/wiki/Anzac_Day">Anzac Day</a>, where businesses have to be close for the morning but are permitted to reopen at 1pm.</p>
<p>Both of these require support for defining opening hours that aren’t based on the day of the week.</p>
<p>Or, what do you do when you want to change the hours of opening - say if Betty decides to open at 4pm on Monday through Thursday because the lunchtime business has declined.</p>
<p>This requires support for changing the hours of opening for a specific day of the week, effective from a particular date.</p>
<p>It’s clear that seven is an impossible number here. Hard coding support for seven different opening hours just doesn’t work: it fails as soon as it encounters the real world.</p>
<p>For this situation, the only real number has to be infinity. You need to support an open ended list of opening hour rules.</p>
http://www.nichesoftware.co.nz/2020/01/11/wordtutor-logging-demoLogging Demonstrated2020-01-11T00:00:00+00:002020-01-11T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>After <a href="/2019/12/28/logging-interfaces.html">earlier defining our logging interface</a>, some readers posed a few questions about how it would work from a consumers perspective. So before we look at implementation details, let’s look at how we’ll instrument our code and what the output might look like.</p>
<h3 id="viewmodels">ViewModels</h3>
<p>Each View Model represents a different user activity, so we’ll give each one a different context.</p>
<p>In <code class="language-plaintext highlighter-rouge">VocabularyBrowserViewModel</code>, the changes are simple.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">readonly</span> <span class="n">IActionLogger</span> <span class="n">_logger</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">VocabularyBrowserViewModel</span><span class="p">(</span>
<span class="n">IReduxStore</span><span class="p"><</span><span class="n">WordTutorApplication</span><span class="p">></span> <span class="n">store</span><span class="p">,</span>
<span class="n">ILogger</span> <span class="n">logger</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">logger</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">logger</span><span class="p">));</span>
<span class="p">}</span>
<span class="n">_store</span> <span class="p">=</span> <span class="n">store</span>
<span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">store</span><span class="p">));</span>
<span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span><span class="p">.</span><span class="nf">Action</span><span class="p">(</span><span class="s">"Browse Vocabulary List"</span><span class="p">);</span>
<span class="c1">// ...</span></code></pre></figure>
<p>Aside: You can see both styles of parameter validation here. Sandwiching the <code class="language-plaintext highlighter-rouge">?? throw</code> style into the use of <code class="language-plaintext highlighter-rouge">logger</code> feels too cramped and is significantly harder to read, so I used the older <code class="language-plaintext highlighter-rouge">if ... throw</code> style.</p>
<p>In <code class="language-plaintext highlighter-rouge">RefreshFromScreen()</code>, when we find our screen has been closed, we need to dispose of the logger to close off the current nested context.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">void</span> <span class="nf">RefreshFromScreen</span><span class="p">(</span>
<span class="n">VocabularyBrowserScreen</span><span class="p">?</span> <span class="n">screen</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">screen</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_screenSubscription</span><span class="p">.</span><span class="nf">Dispose</span><span class="p">();</span>
<span class="n">_vocabularySubscription</span><span class="p">.</span><span class="nf">Dispose</span><span class="p">();</span>
<span class="n">_logger</span><span class="p">.</span><span class="nf">Dispose</span><span class="p">();</span> <span class="c1">// Log disposal added</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">Selection</span> <span class="p">=</span> <span class="n">screen</span><span class="p">.</span><span class="n">Selection</span><span class="p">;</span>
<span class="n">Modified</span> <span class="p">=</span> <span class="n">screen</span><span class="p">.</span><span class="n">Modified</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>However, in <code class="language-plaintext highlighter-rouge">ModifyVocabularyWordViewModel</code> it’s more complicated because we’re reusing the viewmodel for <em>two different activities</em>: both <em>adding</em> and <em>modifying</em> words.</p>
<p>To ensure that our logging is clear, we need to correctly describe our log action. We do this in our constructor by checking which mode we’re using before creating the logger:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="nf">ModifyVocabularyWordViewModel</span><span class="p">(</span>
<span class="n">IReduxStore</span><span class="p"><</span><span class="n">WordTutorApplication</span><span class="p">></span> <span class="n">store</span><span class="p">,</span>
<span class="n">ILogger</span> <span class="n">logger</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">logger</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">logger</span><span class="p">));</span>
<span class="p">}</span>
<span class="n">_store</span> <span class="p">=</span> <span class="n">store</span> <span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">store</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">screen</span> <span class="p">=</span> <span class="n">_store</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="n">CurrentScreen</span>
<span class="k">as</span> <span class="n">ModifyVocabularyWordScreen</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">areAdding</span> <span class="p">=</span> <span class="n">screen</span><span class="p">?.</span><span class="n">ExistingWord</span> <span class="k">is</span> <span class="k">null</span><span class="p">;</span>
<span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span><span class="p">.</span><span class="nf">Action</span><span class="p">(</span>
<span class="n">areAdding</span>
<span class="p">?</span> <span class="s">"Create Vocabulary Word"</span>
<span class="p">:</span> <span class="s">"Modify Vocabulary Word"</span><span class="p">);</span>
<span class="c1">// ...</span></code></pre></figure>
<h3 id="messages">Messages</h3>
<p>At the core of our application, our Redux store is going to be constantly processing messages that change the application state. Capturing these messages in the log should give us a good insight into how the application is operating.</p>
<p>Let’s create a new reducer, one explicitly for logging. At present, it just logs messages on the way through without modifying state - but in the future, we will use it for other processing when we make the log part of our application state.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">LoggingReducer</span>
<span class="p">:</span> <span class="n">IReduxReducer</span><span class="p"><</span><span class="n">WordTutorApplication</span><span class="p">></span>
<span class="p">{</span>
<span class="c1">// Reference to our logger</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ILogger</span> <span class="n">_logger</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">LoggingReducer</span><span class="p">(</span><span class="n">ILogger</span> <span class="n">logger</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">WordTutorApplication</span> <span class="nf">Reduce</span><span class="p">(</span>
<span class="n">IReduxMessage</span> <span class="n">message</span><span class="p">,</span>
<span class="n">WordTutorApplication</span> <span class="n">currentState</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"Message: </span><span class="p">{</span><span class="n">message</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="n">currentState</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h3 id="output">Output</h3>
<p>As a part of our internal plumbing (to be discussed in a later post), we wire things up so that messages logged through the global logger are correctly associated with the current execution context, resulting in a hierarchical log.</p>
<p>For demonstration purposes, we’re sending the output to Visual Studio’s output pane by using <code class="language-plaintext highlighter-rouge">Debug.WriteLine()</code>.</p>
<p>Once we’ve stripped out all the other messages that show up, we end up with output like this:</p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">01:51:35Z [>] Browse Vocabulary List
01:51:42Z [•] Message: Select 'beta'.
01:51:44Z [•] Message: Open screen to create new word.
01:51:44Z [<] Elapsed 00:00:09.3816114.
01:51:44Z [>] Create Vocabulary Word
01:51:48Z [•] Message: Modify Spelling to 'one'.
01:51:49Z [•] Message: Modify Pronunciation to 'won'.
01:51:53Z [•] Message: Modify Phrase to 'We won the game.'.
01:51:54Z [•] Message: Save new word 'one'.
01:51:54Z [<] Elapsed 00:00:10.0477900.
01:51:54Z [>] Browse Vocabulary List
01:51:56Z [•] Message: Select 'one'.
01:51:57Z [•] Message: Open screen to modify 'one'.
01:51:57Z [<] Elapsed 00:00:02.8714110.
01:51:57Z [>] Modify Vocabulary Word
01:52:00Z [•] Message: Modify Spelling to 'won'.
01:52:02Z [•] Message: Save changes to 'one'.
01:52:02Z [<] Elapsed 00:00:04.6584351.</code></pre></figure>
<p>The indentation clearly shows which messages are related to which activity. We additionally get visibility into the way the application swaps out a new viewmodel for each screen as we navigate around.</p>
<p>As we add additional activities into our application, the diagnostic value of the log will grow, but where it will become most useful is when we start running asynchronous workloads: instead of having all those log messages interleaved, making it hard to decipher what’s going on, we’ll have them showing in separate streams of activity.</p>
http://www.nichesoftware.co.nz/2020/01/04/sharpen-the-sawSharpen The Saw - January 20202020-01-04T00:00:00+00:002020-01-04T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: The story of the Visual Studio Code team turning on strict null checking; Eric Lippert talks about why <strong>null</strong> is not <strong>false</strong>; Analyzers for Fluent Assertion users; the PowerToys for Windows are back; Make sure you have five reasons to do anything; Remember IDEAL CHALK when writing code; how to choose a good password generator; retailers need to take responsibility for data breaches; more on programming fonts; fixing your inconsistent sleep schedule; and unit testing at Google.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="strict-null-checking-visual-studio-code">Strict null checking Visual Studio Code</h4>
<p>The Visual Studio Code team just finished a major change - enabling strict null checking across their codebase. They didn’t do this to fix bugs they knew about - but to address a specific category of recurring bugs that kept causing problems in their codebase.</p>
<blockquote>
<p>… understanding bugs not as isolated events but as symptoms of larger hazards in our source code.</p>
</blockquote>
<p>Their story has lessons that we all can learn and apply to our own projects.</p>
<p><a href="https://code.visualstudio.com/blogs/2019/05/23/strict-null">Read More</a></p>
<h4 id="null-is-not-false">Null is not false</h4>
<p>A trio of interesting posts from the famed Eric Lippert, talking about how C# handles null values, why a nullable bool is not false, and more. One of his key observations is that a value of null means “I don’t know”, and this drives the semantics of everything else, including why 100 + null == null, not 100.</p>
<p><a href="https://blogs.msdn.microsoft.com/ericlippert/2012/03/26/null-is-not-false/">Read part 1</a>;
<a href="https://blogs.msdn.microsoft.com/ericlippert/2012/04/12/null-is-not-false-part-two/">Read part 2</a>;
<a href="https://blogs.msdn.microsoft.com/ericlippert/2012/04/19/null-is-not-false-part-three/">Read part 3</a>.</p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="fluentassertions-analyzers">FluentAssertions analyzers</h4>
<p>If you’re working with FluentAssertions, here’s an analysis package that you might find useful - it provides best practice guidance right there in Visual Studio. This is a good example of a growing (and very useful) trend, where popular NuGet packages provide automated guidance packages.</p>
<p><a href="https://github.com/fluentassertions/fluentassertions.analyzers">Read More</a></p>
<h4 id="microsoft-reboots-the-powertoys-for-windows-10">Microsoft reboots the PowerToys for Windows 10</h4>
<p>Back in the days of Windows XP, the Power Toys was a great set of semi-official extensions for Microsoft Windows. Recently, Microsoft announced that the project is being rebooted, with a whole new set of tools … and they’re all going to be open source, hosted on GitHub.</p>
<p><a href="https://www.thurrott.com/windows/windows-10/206327/microsoft-reboots-the-powertoys-for-windows-10">Read More</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="five-reasons-for-doing-anything">Five reasons for doing anything</h4>
<p>Choosing how to prioritize your time can be challenging. Which of the forty-seven things that I’ve got on my list for <em>today</em> deserves my time? In this blog post, Tom Lorusso shares their technique for decision making.</p>
<p><a href="https://medium.com/microsoft-design/five-reasons-for-doing-anything-71f048cb835f">Read More</a></p>
<h4 id="two-words-to-code-by-ideal-chalk">Two words to code by… IDEAL CHALK</h4>
<p>Greg highlights a CodeProject post taking the ideas of SOLID to the next level by suggesting a new acronym. SOLID CHALK is guidance for your next software development project. I can’t decide whether this is a useful original idea or just a piece of fluff - but I suspect it has just enough value to be worth sharing.</p>
<p><a href="https://www.codeproject.com/Articles/337454/IDEAL-CHALK-mnemonic-acronym-and-mnemonic-images-f">Read More</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="use-a-good-password-generator">Use a good password generator</h4>
<p>From the department of “more detail than I ever thought I wanted to know”, Aaron Toponce has done an impressive audit of various online password generators. Even though I don’t agree with all of his scoring methodology, this is a good reminder that security is hard.</p>
<p><a href="https://pthree.org/2018/04/19/use-a-good-password-generator/">Read More</a></p>
<h4 id="lets-stop-giving-retailers-a-free-pass-on-data-breaches">Let’s stop giving retailers a free pass on data breaches</h4>
<p>It seems that retailers are currently getting away with lax security and negligent practices because they don’t seem to be adversely affected when they are breached - unlike the people whose details are revealed. We should collectively be changing our online habits to punish online retailers who screw up - especially those who don’t improve, and those who try to cover up the problem.</p>
<p><a href="https://www.itprotoday.com/endpoint-protection/lets-stop-giving-retailers-free-pass-data-breaches">Read More</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="top-10-programming-fonts">Top 10 programming fonts</h4>
<p>I’m a bit of a heretic who programs with proportional fonts. Why? I find them easier to read and the code ends up narrower overall, allowing me to easily work two files side by side - often a class on the left and its unit tests on the right.</p>
<p>For the majority of you who use a monospaced font, here’s a treat - Dan Benjamin wrote a review of some dedicated programming fonts that you might want to consider using. FWIW, I use Deja Vu Sans in my console windows, but we’ve already established that I’m odd. Make your own choices.</p>
<p><a href="http://hivelogic.com/articles/top-10-programming-fonts/">Read more</a></p>
<p>Don’t miss his update on the font Anonymous Pro:</p>
<p><a href="http://hivelogic.com/articles/anonymous-pro-programming-monospace-font/">Read more</a></p>
<h4 id="why-you-should-fix-your-inconsistent-sleep-schedule">Why you should fix your inconsistent sleep schedule</h4>
<p>The value of a good nights sleep can’t be overstated. The more we learn about the role of sleep, the more we learn that it is a vital part of staying healthy in both body and mind.</p>
<p><a href="https://getpocket.com/explore/item/why-you-should-fix-your-inconsistent-sleep-schedule">Read More</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="the-clean-code-talks-unit-testing">The clean code talks: unit testing</h4>
<p>This talk might be over a decade old - but it’s a discussion on writing untestable code that’s worth the watch. There’s good advice here.</p>
<p><strong>Audience</strong>: Developers<br />
<strong>Length</strong>: 32m</p>
<p><a href="https://www.youtube.com/watch?list=PLED6CA927B41FF5BD&v=wEhu57pih5w&feature=emb_title">Watch Now</a></p>
http://www.nichesoftware.co.nz/2019/12/28/logging-interfacesLogging2019-12-28T00:00:00+00:002019-12-28T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>As we progress building the WordTutor application, some of the functionality will be a great deal more complex - and that requires a better way to see what’s happening inside the application than we’ve had to date. It’s time to implement some logging.</p>
<p>We could, of course, use an existing logging library - but where’s the fun in that!</p>
<p>More seriously, the best logging library I ever used was one I used around twenty years ago while developing desktop applications in Delphi. This library had some innovative features, including the ability to automatically upload the logs to a central server if the application had previously crashed.</p>
<p>Perhaps the most useful feature of that library - and the one that I’d like to bring forward for use in the WordTutor, was support for hierarchical logging.</p>
<p>A problem I consistently see in application log files is that individual log messages lack context, making the messages less useful.</p>
<p>For example, what if you saw these log file messages:</p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">21:07:23.012 INFO Configuration file 'foo.config' loaded from the application folder
21:07:23.014 ERROR Configuration file 'foo.config' could not be loaded from user folder</code></pre></figure>
<p>Does the error message indicate the application has failed? Or is this a normal condition that happens when an optional configuration file isn’t being used?</p>
<p>By providing additional context as a part of our logging framework, we can make it clear. To illustrate, what if our logging looked like this:</p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">21:07:23.011 ACTION Loading application configuration files
21:07:23.012 INFO Configuration file 'foo.config' loaded from the application folder
21:07:23.014 ERROR Configuration file 'foo.config' could not be loaded from user folder
21:07:23.015 SUCCESS Loaded one configuration file</code></pre></figure>
<p>Now it’s clear that the ERROR is normal, and that we don’t need to pay it particular attention.</p>
<p>To achieve this, let’s create a very simple base ILogger interface:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">interface</span> <span class="nc">ILogger</span>
<span class="p">{</span>
<span class="n">IActionLogger</span> <span class="nf">Action</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="k">void</span> <span class="nf">Info</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="k">void</span> <span class="nf">Debug</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>We’re supporting just three levels of information. The Info and Debug levels are likely obvious at first inspection - but why does <code class="language-plaintext highlighter-rouge">Action</code> have a return value?</p>
<p>The IActionLogger interface allows logging to be made in a nested context, tracking the events that happen during that action.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">interface</span> <span class="nc">IActionLogger</span> <span class="p">:</span> <span class="n">ILogger</span><span class="p">,</span> <span class="n">IDisposable</span>
<span class="p">{</span>
<span class="k">void</span> <span class="nf">Success</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="k">void</span> <span class="nf">Failure</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>In addition to all the normal logging messages, we can also indicate whether the action was successful, or not.</p>
<p>What do you think of this approach? I’d be interested in your feedback.</p>
http://www.nichesoftware.co.nz/2019/12/21/empathy-future-developersEmpathy for future developers2019-12-21T00:00:00+00:002019-12-21T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Chatting with some fellow developers over the Christmas period, the subject of the so-called “soft skills” came up and one of them made a very interesting observation - that those skills lead to better code as well as better collaboration.</p>
<p><em>Side note</em>: I’ve come to hate the term “soft skills” because it somehow implies that those skills are easier to learn than the so-called “hard skills”. It’s my experience - both personally and observationally - that these skills are far harder to learn and execute well than the comparatively simple task of writing working code. This is not to say that writing code is actually easy - just that working with people is far harder (and, in some cases, far more rewarding) than working with code.</p>
<p>Empathy is the ability to understand someone else’s perspective on things - to picture yourself in their shoes and understand (at least partially) what it is like for them.</p>
<p>Understanding empathy within a team is relatively straightforward, but what about having empathy over time?</p>
<p>Production code has a temporal aspect that is sometimes ignored. For every piece of production code, there will be, sooner or later, some other developer who needs to read and understand it. Perhaps they’ll be fixing a bug or adding a feature. Or, maybe they need to understand what it does to copy the functionality elsewhere.</p>
<p>Empathy for that future developer - who might just be a future version of yourself - can be challenging because it’s a one-way street. This is very unlike the normal inter-personal situation where there is a feedback loop to drive self-correction.</p>
<p>So, what does this kind of empathy look like? Here are a few ideas.</p>
<p>Code needs to be <strong><em>readable</em></strong>. Write the code so that it’s easy to read, not easy to write. Make it as easy as possible for someone unfamiliar with the code to read through and understand what it does and what it works. Add comments to explain things that can’t be inferred from the code.</p>
<p>Code needs to be <strong><em>trustworthy</em></strong>. Names of types should reflect the semantics of the type. Names of methods should reflect what the method achieves. Names of fields and local variables should reflect what’s referenced. Names that are misleading or ambiguous should be avoided.</p>
<p>Code needs to have <strong><em>automated tests</em></strong>. Provide a safety net for that future developer so they can start to make changes confident that any unintended consequences of their changes will be picked up by the test suite. Make sure your tests are well structured and that test failures are easy to diagnose and fix. Run the tests as a part of your CI builds, and block any PR with failing tests.</p>
<p>Of course, this list is far from complete.</p>
<p>What would you add? How will you show empathy for the future developers charged with working on the code you’re writing today?</p>
http://www.nichesoftware.co.nz/2019/12/14/wither-convention-testingWither convention testing2019-12-14T00:00:00+00:002019-12-14T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>Following on from <a href="/2019/11/30/wordtutor-convention-testing.html">our previous post on convention testing</a> we can extend the conventions by considering the standards we want to follow when we write methods on our immutable types.</p>
<p>One of the conventions we’ve been following is the use of methods that create a near clone of the current object, but with a specific change present. We’ve been giving these methods names that start with <code class="language-plaintext highlighter-rouge">With</code> - in the functional programming world they’re commonly known as withers.</p>
<p>For our first test, let’s check that the return type of each wither is the same as the declaring type. Enforcing this ensures that we can chain withers together without losing type information as we go.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">FindWithersOfImmutableTypes</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">WithersShouldReturnTheirDeclaringType</span><span class="p">(</span>
<span class="n">MethodInfo</span> <span class="n">wither</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">wither</span><span class="p">.</span><span class="n">ReturnType</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span>
<span class="n">wither</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">,</span>
<span class="s">$"wither </span><span class="p">{</span><span class="n">wither</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> of type </span><span class="p">{</span><span class="n">wither</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> "</span>
<span class="p">+</span> <span class="s">$"should return </span><span class="p">{</span><span class="n">wither</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>We just check that the return type of the method is the same as the declaring type. The <em>because</em> string provides additional information that gets included if the test fails. The goal is to make it as obvious as possible what went wrong so that the fix can be completed as quickly as possible.</p>
<p>To find all the withers that need testing, we iterate over all known immutable types looking for methods with names that start with <code class="language-plaintext highlighter-rouge">With</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p"><</span><span class="kt">object</span><span class="p">[</span><span class="k">]></span> <span class="nf">FindWithersOfImmutableTypes</span><span class="p">()</span>
<span class="p">=></span> <span class="k">from</span> <span class="n">t</span> <span class="k">in</span> <span class="nf">GetImmutableTypes</span><span class="p">()</span>
<span class="k">from</span> <span class="n">m</span> <span class="k">in</span> <span class="n">t</span><span class="p">.</span><span class="nf">GetMethods</span><span class="p">()</span>
<span class="k">where</span> <span class="n">m</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">StartsWith</span><span class="p">(</span><span class="s">"With"</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">)</span>
<span class="k">select</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="n">m</span> <span class="p">};</span></code></pre></figure>
<p>Good news - all our existing withers satisfy the test.</p>
<p>Now we want to check the parameters we pass to the withers - the parameter names should match the names of the properties that are going to be modified. Using this convention makes the withers more predictable when we’re using them - the parameter names shown in IntelliSense will accurately reflect the changes being made.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">FindWithersOfImmutableTypes</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">WitherParametersShouldIdentifyProperties</span><span class="p">(</span>
<span class="n">MethodInfo</span> <span class="n">wither</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">properties</span> <span class="p">=</span> <span class="p">(</span>
<span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">wither</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="nf">GetProperties</span><span class="p">()</span>
<span class="k">select</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span>
<span class="p">).</span><span class="nf">ToHashSet</span><span class="p">(</span><span class="n">StringComparer</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">);</span>
<span class="n">wither</span><span class="p">.</span><span class="nf">GetParameters</span><span class="p">().</span><span class="nf">Should</span><span class="p">().</span><span class="nf">OnlyContain</span><span class="p">(</span>
<span class="n">p</span> <span class="p">=></span> <span class="n">properties</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">),</span>
<span class="s">$"parameters should be one of </span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">", "</span><span class="p">,</span> <span class="n">properties</span><span class="p">)}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>We start by finding all the properties of the declaring type and creating a set of all the names of the public properties. Each of the parameters is then checked to see if the parameter name is present - using a case insensitive check. Again we include a <em>because</em> string to describe what’s expected.</p>
<p>This time around, we have a couple of test failures, both on the class <code class="language-plaintext highlighter-rouge">VocabularyBrowserScreen</code>:</p>
<p>Firstly, the method <code class="language-plaintext highlighter-rouge">WithSelection()</code> fails because the parameter <code class="language-plaintext highlighter-rouge">word</code> needs to be renamed to <code class="language-plaintext highlighter-rouge">selection</code>.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">VocabularyBrowserScreen</span> <span class="nf">WithSelection</span><span class="p">(</span>
<span class="n">VocabularyWord</span> <span class="n">word</span><span class="p">)</span></code></pre></figure>
<p>Secondly, the method <code class="language-plaintext highlighter-rouge">WithNoSelection()</code> fails because it’s not a wither - it doesn’t have any parameters at all.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">VocabularyBrowserScreen</span> <span class="nf">WithNoSelection</span><span class="p">()</span></code></pre></figure>
<p>To fix this second test failure, let’s rename the method to <code class="language-plaintext highlighter-rouge">ClearSelection()</code> so that it’s not picked up by these tests.</p>
<p>But, we should have some tests for it, surely? Let’s create tests for <em>clearers</em>, with slightly different conventions:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">FindClearersOfImmutableTypes</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ClearersShouldReturnTheirDeclaringType</span><span class="p">(</span><span class="n">MethodInfo</span> <span class="n">clearer</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">clearer</span><span class="p">.</span><span class="n">ReturnType</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span>
<span class="n">clearer</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">,</span>
<span class="s">$"clearer </span><span class="p">{</span><span class="n">clearer</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> of type </span><span class="p">{</span><span class="n">clearer</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> "</span>
<span class="p">+</span> <span class="s">$"should return </span><span class="p">{</span><span class="n">clearer</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p"><</span><span class="kt">object</span><span class="p">[</span><span class="k">]></span> <span class="nf">FindClearersOfImmutableTypes</span><span class="p">()</span>
<span class="p">=></span> <span class="k">from</span> <span class="n">t</span> <span class="k">in</span> <span class="nf">GetImmutableTypes</span><span class="p">()</span>
<span class="k">from</span> <span class="n">m</span> <span class="k">in</span> <span class="n">t</span><span class="p">.</span><span class="nf">GetMethods</span><span class="p">()</span>
<span class="k">where</span> <span class="n">m</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">StartsWith</span><span class="p">(</span><span class="s">"Clear"</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">)</span>
<span class="k">select</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="n">m</span> <span class="p">};</span></code></pre></figure>
<p>Our first test is essentially identical to the same test for our withers - it might be worth merging the two later on.</p>
<p>Next, we want to check that the name of the clearer identifies the property we’re going to clear.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">FindClearersOfImmutableTypes</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ClearersShouldHaveNamesIdentifyingTheClearedProperty</span><span class="p">(</span>
<span class="n">MethodInfo</span> <span class="n">clearer</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">propertyName</span> <span class="p">=</span> <span class="n">clearer</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">Substring</span><span class="p">(</span><span class="s">"Clear"</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
<span class="n">clearer</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="nf">GetProperties</span><span class="p">()</span>
<span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Contain</span><span class="p">(</span>
<span class="n">p</span> <span class="p">=></span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span>
<span class="n">propertyName</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">),</span>
<span class="s">$"no property </span><span class="p">{</span><span class="n">propertyName</span><span class="p">}</span><span class="s"> was found on "</span>
<span class="p">+</span> <span class="s">$"</span><span class="p">{</span><span class="n">clearer</span><span class="p">.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>These additional conventions will help us construct any new immutable types correctly as we move forward.</p>
<p>What conventions do you have in your projects? How many of those conventions are currently managed by hand? Do you think any of them could be cross-checked by some smart unit tests?</p>
http://www.nichesoftware.co.nz/2019/12/07/sharpen-the-sawSharpen The Saw - December 20192019-12-07T00:00:00+00:002019-12-07T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>In today’s post: Why the repository pattern needs to be abandoned; a tool for troubleshooting assembly load issues; giving effective instructions; making your email hacker-proof; the tiny details are important; and, the computers of the Voyager space program.</p>
<p>Sharpen the Saw used to be an email newsletter of information I published for the professional development of software developers. Now it’s a series of blog posts. While targeted primarily at developers working with the Microsoft technology stack, content covers a wider range of topics.</p>
<h3 id="technique">Technique</h3>
<p><em>Always a way to improve the code you write every day.</em></p>
<h4 id="ditch-the-repository-pattern-already">Ditch the repository pattern already</h4>
<p>Once a key staple of application design, back in the era of client-server desktop software, the Repository Pattern has well and truly fallen out of favour. In this LosTechies post, Derek Greer goes through some of the reasons he has stopped using the pattern. He doesn’t call it an anti-pattern - but he comes close.</p>
<p><a href="https://lostechies.com/derekgreer/2018/02/20/ditch-the-repository-pattern-already/">Read More</a></p>
<h3 id="software--updates">Software & Updates</h3>
<p><em>A new or upgraded tool can be a beautiful thing.</em></p>
<h4 id="fusion">Fusion++</h4>
<p>Following on from my earlier post on troubleshooting assembly loading issues, <a href="https://github.com/awaescher">Andreas Wascher</a> reached out to let me know that he’s created a replacement viewer called Fusion++. Worth checking out.</p>
<p><a href="https://github.com/awaescher/Fusion">Read More</a></p>
<h3 id="being-professional">Being Professional</h3>
<p><em>A great developer does more than just write great code.</em></p>
<h4 id="10-tips-for-giving-effective-instructions">10 tips for giving effective instructions</h4>
<p>This one is quick and useful - for we all have times when we need to instruct others on how to get things done.</p>
<p><a href="https://www.ismckenzie.com/10-tips-for-giving-effective-instructions/">Read More</a></p>
<h3 id="security">Security</h3>
<p><em>Staying safe online and writing secure systems are both harder than we think.</em></p>
<h4 id="make-your-email-hacker-proof">Make your email hacker proof</h4>
<p>Stack Overflow founder Jeff Atwood makes a very good point that your email is the skeleton key to your online identity; if someone gets control of that, they can readily escalate to control of many other accounts just because they control the means of password reset/change. If you haven’t done so already, take the time to turn on two-factor authentication. Do it now.</p>
<p><a href="https://blog.codinghorror.com/make-your-email-hacker-proof/">Read More</a></p>
<h3 id="wildcard">Wildcard</h3>
<p><em>Sometimes the answer is random.</em></p>
<h4 id="this-is-all-your-app-is-a-collection-of-tiny-details">This is all your app is: a collection of tiny details</h4>
<p><a href="https://blog.codinghorror.com/">Jeff Atwood</a>’s blog post starts as a comparative review of his cat feeders, detailing many of the minor improvements made over five years of product development. He makes a more important point near the end of the post, however - these little details <em>are</em> your application, and they matter a whole lot.</p>
<p>I’m sure you’ve encountered, as I have, products that are built to satisfy some vital checklist of features - but which are, on a day to day basis, incredibly difficult to work with. Rough edges, incomplete features, buggy behaviour, and a general feel of being painful to use.</p>
<p><a href="https://blog.codinghorror.com/this-is-all-your-app-is-a-collection-of-tiny-details/">Read more</a></p>
<h3 id="video">Video</h3>
<p><em>Take some time to feed your mind.</em></p>
<h4 id="uptime-15364-days---the-computers-of-voyager">Uptime 15,364 days - the computers of voyager</h4>
<p>Launched well over 40 years ago in 1977, the Voyager probes are still working, with their faint telemetry signals still being received by a team at NASA. In this talk from Strangeloop 2019, Aaron Cummings talks about the genesis of the Voyager project and goes into a little detail about their onboard systems.</p>
<p><strong>Length</strong>: 49 minutes<br />
<strong>Audience</strong>: Everyone</p>
<p><a href="https://www.youtube.com/watch?v=H62hZJVqs2o">Watch now</a></p>
http://www.nichesoftware.co.nz/2019/11/30/wordtutor-convention-testingConvention testing for immutable types2019-11-30T00:00:00+00:002019-11-30T00:00:00+00:00Bevan Arpshttp://www.nichesoftware.co.nz/<p>The Redux architecture we’re using for our application state relies on all our state objects being properly immutable. So far, we’ve relied on nothing more than self-discipline to ensure no mistakes are made. By adding some convention testing to our project, we can enlist some help in avoiding common errors.</p>
<p>As a beginning, let’s declare a simple attribute that we can use to mark each immutable class. We’ll use this attribute to identify the classes that should be immutable and therefore subject to our rules.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">AttributeUsage</span><span class="p">(</span><span class="n">AttributeTargets</span><span class="p">.</span><span class="n">Class</span><span class="p">,</span> <span class="n">AllowMultiple</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ImmutableAttribute</span> <span class="p">:</span> <span class="n">Attribute</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>In addition to the immutable types we declare ourselves, we can use existing types from the .NET library itself. To make it easy to test whether a type is immutable, let’s define an extension method on <code class="language-plaintext highlighter-rouge">Type</code> that wraps our desired logic.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">bool</span> <span class="nf">IsImmutableType</span><span class="p">(</span><span class="k">this</span> <span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">GetCustomAttribute</span><span class="p"><</span><span class="n">ImmutableAttribute</span><span class="p">>()</span> <span class="k">is</span> <span class="kt">object</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_systemImmutableTypes</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">type</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">IsGenericType</span> <span class="p">&&</span> <span class="p">!</span><span class="n">type</span><span class="p">.</span><span class="n">IsGenericTypeDefinition</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">definition</span> <span class="p">=</span> <span class="n">type</span><span class="p">.</span><span class="nf">GetGenericTypeDefinition</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">parameters</span> <span class="p">=</span> <span class="n">type</span><span class="p">.</span><span class="nf">GetGenericArguments</span><span class="p">();</span>
<span class="k">return</span> <span class="n">definition</span><span class="p">.</span><span class="nf">IsImmutableType</span><span class="p">()</span>
<span class="p">&&</span> <span class="n">parameters</span><span class="p">.</span><span class="nf">All</span><span class="p">(</span><span class="n">t</span> <span class="p">=></span> <span class="n">t</span><span class="p">.</span><span class="nf">IsImmutableType</span><span class="p">());</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>The logic is relatively simple. If we’ve tagged the type with our new attribute, if it’s a system supplied immutable type, or if it’s a generic type made up of immutable types, then it’s immutable.</p>
<p>Using <strong>is object</strong> is a tidy way of checking the value isn’t <strong>null</strong>; I’ve seen this approach emerging in some C# 8.0 code - time will tell whether it becomes a common idiom. I found it odd to read at first, but it’s grown on me.</p>
<p>Not shown, the set <code class="language-plaintext highlighter-rouge">_systemImmutableTypes</code> contains standard .NET types we’ve selected as immutable. Currently those types are <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">string</code>, <code class="language-plaintext highlighter-rouge">bool</code>, and <code class="language-plaintext highlighter-rouge">IImmutableSet<></code>.</p>
<p>We can now define our first test - that all of the properties on an immutable type should themselves be immutable.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">PropertiesOfImmutableTypesToTest</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">PropertiesOfImmutableTypesShouldHaveImmutableTypes</span><span class="p">(</span>
<span class="n">PropertyInfo</span> <span class="n">property</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">property</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">.</span><span class="nf">IsImmutableType</span><span class="p">()</span>
<span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">BeTrue</span><span class="p">(</span>
<span class="s">$"property </span><span class="p">{</span><span class="n">property</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> should be "</span>
<span class="p">+</span> <span class="s">"declared as an immutable type"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>For each property passed into the test, we check that the type of the property is immutable. If not, we fail the test.</p>
<p>Where do those property values come from?</p>
<p>The <code class="language-plaintext highlighter-rouge">[MemberData]</code> attribute identifies which member, in our case a method, will be used to supply the data.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p"><</span><span class="kt">object</span><span class="p">[</span><span class="k">]></span> <span class="nf">PropertiesOfImmutableTypesToTest</span><span class="p">()</span>
<span class="p">=></span> <span class="k">from</span> <span class="n">t</span> <span class="k">in</span> <span class="nf">FindDeclaredImmutableTypes</span><span class="p">()</span>
<span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">t</span><span class="p">.</span><span class="nf">GetProperties</span><span class="p">()</span>
<span class="k">select</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="n">p</span> <span class="p">};</span>
<span class="k">private</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p"><</span><span class="n">Type</span><span class="p">></span> <span class="nf">FindDeclaredImmutableTypes</span><span class="p">()</span>
<span class="p">=></span> <span class="k">from</span> <span class="n">t</span> <span class="k">in</span> <span class="k">typeof</span><span class="p">(</span><span class="n">WordTutorApplication</span><span class="p">).</span><span class="n">Assembly</span><span class="p">.</span><span class="nf">GetTypes</span><span class="p">()</span>
<span class="k">where</span> <span class="n">t</span><span class="p">.</span><span class="nf">IsImmutableType</span><span class="p">()</span>
<span class="k">select</span> <span class="n">t</span><span class="p">;</span></code></pre></figure>
<p>Starting with [Immutable] on our <code class="language-plaintext highlighter-rouge">WordTutorApplication</code> class, we quickly need to add it to <code class="language-plaintext highlighter-rouge">VocabularySet</code>, <code class="language-plaintext highlighter-rouge">VocabularyWord</code> and <code class="language-plaintext highlighter-rouge">Screen</code> for this test to pass.</p>
<p>Our next test checks that all these properties are read-only. We don’t want our immutable types to have any writable properties, after all.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">PropertiesOfImmutableTypesToTest</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">PropertiesOfImmutableTypesMustNotBeWritable</span><span class="p">(</span>
<span class="n">PropertyInfo</span> <span class="n">property</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">property</span><span class="p">.</span><span class="n">CanWrite</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">BeFalse</span><span class="p">(</span>
<span class="s">$"property </span><span class="p">{</span><span class="n">property</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> of immutable type "</span>
<span class="p">+</span> <span class="s">"{property.DeclaringType!.Name} should not be writable"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Fortunately, all of our existing classes satisfy this test.</p>
<p>Our next test is to ensure that any subclass of an immutable type is itself marked as immutable.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">TestCasesAreSubclassesOfImmutableTypes</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">SubTypesOfImmutableTypesMustBeImmutable</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">type</span><span class="p">.</span><span class="nf">IsImmutableType</span><span class="p">().</span><span class="nf">Should</span><span class="p">().</span><span class="nf">BeTrue</span><span class="p">(</span>
<span class="s">$"Type </span><span class="p">{</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> should be marked [Immutable] because it "</span>
<span class="p">+</span> <span class="s">"descends from immutable type {type.BaseType.Name}."</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Again we’re using a <code class="language-plaintext highlighter-rouge">[MemberData]</code> attribute to specify where our test data comes from. Finding the subclasses is fairly straightforward:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p"><</span><span class="kt">object</span><span class="p">[</span><span class="k">]></span> <span class="nf">TestCasesAreSubclassesOfImmutableTypes</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">immutableTypes</span> <span class="p">=</span> <span class="nf">FindDeclaredImmutableTypes</span><span class="p">().</span><span class="nf">ToHashSet</span><span class="p">();</span>
<span class="k">return</span> <span class="k">from</span> <span class="n">t</span> <span class="k">in</span> <span class="k">typeof</span><span class="p">(</span><span class="n">WordTutorApplication</span><span class="p">).</span><span class="n">Assembly</span><span class="p">.</span><span class="nf">GetTypes</span><span class="p">()</span>
<span class="k">where</span> <span class="n">t</span><span class="p">.</span><span class="n">BaseType</span> <span class="k">is</span> <span class="n">Type</span>
<span class="p">&&</span> <span class="n">immutableTypes</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">BaseType</span><span class="p">)</span>
<span class="k">select</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="n">t</span> <span class="p">};</span>
<span class="p">}</span></code></pre></figure>
<p>Lastly, we want all our immutable types to be explicitly abstract or sealed:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Theory</span><span class="p">]</span>
<span class="p">[</span><span class="nf">MemberData</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">TestCasesAreImmutableTypes</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ImmutableTypesShouldBeSealedOrAbstract</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">type</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Match</span><span class="p">(</span><span class="n">t</span> <span class="p">=></span> <span class="n">t</span><span class="p">.</span><span class="n">IsAbstract</span> <span class="p">||</span> <span class="n">t</span><span class="p">.</span><span class="n">IsSealed</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p"><</span><span class="kt">object</span><span class="p">[</span><span class="k">]></span> <span class="nf">TestCasesAreImmutableTypes</span><span class="p">()</span>
<span class="p">=></span> <span class="k">from</span> <span class="n">t</span> <span class="k">in</span> <span class="nf">FindDeclaredImmutableTypes</span><span class="p">()</span>
<span class="k">select</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="n">t</span> <span class="p">};</span></code></pre></figure>
<p>What have we achieved here?</p>
<p>We have a set of simple conventions that we want all our immutable types to adhere to. Instead of stating these in a checklist or some other kind of documentation, we’ve embedded the rules into our test suite making their enforcement an active part of our development process.</p>