<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" >
<channel>
<title>Word Aligned</title>
<link>https://wordaligned.org</link>
<description>tales from the code face</description>
<dc:creator>tag@wordaligned.org</dc:creator>
<language>en-gb</language>
<item>
<title>Priority queues in Python</title>
<description>&lt;p&gt;In the previous article I noted that Python&amp;#8217;s
&lt;a href=&quot;https://docs.python.org/3/library/heapq.html&quot;&gt;heapq&lt;/a&gt; module is the
only part of standard Python I could think of which deals with sorting,
but which doesn&amp;#8217;t give you full control over the sort order.&lt;/p&gt;
&lt;p&gt;That means you need to take care when using a heapq as a priority queue.&lt;/p&gt;
&lt;p&gt;For example, the &lt;a href=&quot;https://en.wikipedia.org/wiki/A*_search_algorithm&quot;&gt;A* search
algorithm&lt;/a&gt; is a
&lt;strong&gt;best first&lt;/strong&gt; path finder. It maintains a priority queue of possible
steps to take, ordered by an estimate of the total distance of the
path routed through these steps. At each stage it pops the next step
&amp;#8212; the one with the shortest estimated total distance &amp;#8212; from the queue,
then updates based on the new position.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;import heapq

def a_star(start, heuristic, moves):
    &quot;&quot;&quot;A* graph search

    - start: initial state
    - heuristic(s): estimates path length from state s to finish. 
                    heuristic(s) == 0 =&amp;gt; finished
    - moves(s): neighbours of s

    Returns the shortest path to the finish and its cost, on success.
    None otherwise.
    &quot;&quot;&quot;
    costs = {start: 0}
    prev = {start: None}
    frontier = [(heuristic(start), start)]
    heapq.heapify(frontier)

    def path(s):
        return [] if s is None else path(prev[s]) + [s]

    while frontier:
        priority, state = heapq.heappop(frontier)
        if heuristic(state) == 0:
            return costs[state], path(state)
        for n in moves(state):
            n_cost = costs[state] + 1
            if n not in costs or n_cost &amp;lt; costs[n]:
                costs[n] = n_cost
                heapq.heappush(frontier, (n_cost + heuristic(n), n))
                prev[n] = state

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The code above is a Python A* implementation. For simplicity, we&amp;#8217;ll
assume the cost of each step is 1. It&amp;#8217;s easy enough to adapt the function
if this isn&amp;#8217;t the case.&lt;/p&gt;
&lt;p&gt;The priority queue here is named &lt;code&gt;frontier&lt;/code&gt;, the collection of states
we need to explore. The sequence &lt;code&gt;heapify&lt;/code&gt;, &lt;code&gt;heappop&lt;/code&gt;, &lt;code&gt;heappush&lt;/code&gt;
maintains the priority ordering. (The call to &lt;code&gt;heapify&lt;/code&gt; isn&amp;#8217;t even
needed since a list with one element is already a heap.)  So, each
time we pop a state from the queue, we get the one with the lowest
estimated cost. Then, based on the moves we can make from this new
step, we update our internal records of costs and previous nodes.&lt;/p&gt;
&lt;p&gt;Note that the items on the queue are &lt;code&gt;(cost, state)&lt;/code&gt; pairs. The costs
will be numbers, typically positive integers &amp;#8212; the exact values depend
on the heuristic function.&lt;/p&gt;
&lt;p&gt;Exactly what gets used as &lt;code&gt;state&lt;/code&gt; is up to the caller
which supplies &lt;code&gt;start&lt;/code&gt;, the initial state, and &lt;code&gt;moves&lt;/code&gt;, which steps
from a state to its neighbours.&lt;/p&gt;
&lt;p&gt;However, if items on the queue are tied on &lt;code&gt;cost&lt;/code&gt;, the heapq may need to
compare &lt;code&gt;state&lt;/code&gt; values. If the states have no defined ordering
this results in a runtime error.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; class State: pass
... 
&amp;gt;&amp;gt;&amp;gt; x1, x2 = State(), State()
&amp;gt;&amp;gt;&amp;gt; (1, x1) &amp;lt; (2, x2)
True
&amp;gt;&amp;gt;&amp;gt; (1, x1) &amp;lt; (1, x2)
Traceback (most recent call last):
  File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;
TypeError: &#x27;&amp;lt;&#x27; not supported between instances of &#x27;State&#x27; and &#x27;State&#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We cannot supply a sort key to the &lt;code&gt;heapq&lt;/code&gt; functions. Does this mean
clients must ensure state objects &amp;#8212; whatever they actually are &amp;#8212; can be
compared? As the code stands, yes, but the &lt;a href=&quot;https://docs.python.org/3/library/heapq.html#priority-queue-implementation-notes&quot;&gt;module documentation&lt;/a&gt; has advice on handling this situatation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[&amp;#8230;] store entries as 3-element list including the priority, an
entry count, and the task. The entry count serves as a tie-breaker
so that two tasks with the same priority are returned in the order
they were added. And since no two entry counts are the same, the
tuple comparison will never attempt to directly compare two tasks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This strategy gives a more usable &lt;code&gt;a_star&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;import heapq
import itertools

def a_star(start, heuristic, moves):
    costs = {start: 0}
    prev = {start: None}
    seq = itertools.count().__next__
    frontier = [(heuristic(start), seq(), start)]

    def path(s):
        return [] if s is None else path(prev[s]) + [s]

    while frontier:
        _, _, state = heapq.heappop(frontier)
        if heuristic(state) == 0:
            return costs[state], path(state)
        for n in moves(state):
            n_cost = costs[state] + 1
            if n not in costs or n_cost &amp;lt; costs[n]:
                costs[n] = n_cost
                heapq.heappush(frontier, (n_cost + heuristic(n), seq(), n))
                prev[n] = state

&lt;/pre&gt;

&lt;/div&gt;</description>
<dc:date>2022-02-25</dc:date>
<guid>https://wordaligned.org/articles/priority-queues-in-python</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/priority-queues-in-python</link>
<category>Python</category>
</item>

<item>
<title>Binary search gets a sort key</title>
<description>&lt;p&gt;Suppose you have an list of distinct elements which has been sorted
and rotated. How would you look up an element within that list?&lt;/p&gt;
&lt;p&gt;For example, the list:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[7, 11, 13, 19, 2, 3, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is sorted (the first 7 primes, in order) and rotated (to put 7 first).&lt;/p&gt;
&lt;p&gt;With this list as input, then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;look up &lt;code&gt;13&lt;/code&gt; returns &lt;code&gt;2&lt;/code&gt; since &lt;code&gt;13&lt;/code&gt; is at index &lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;look up &lt;code&gt;2&lt;/code&gt; returns &lt;code&gt;4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;look up &lt;code&gt;4&lt;/code&gt; returns the sentinel value &lt;code&gt;-1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The obvious technique is to just search the list:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def lookup(values, v):
    try:
        return values.index(v)
    except IndexError:
        return -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a linear algorithm which processes the entire list. Is there a way
to take advantage of its sorted+rotated-ness?&lt;/p&gt;
&lt;p&gt;If the list &lt;strong&gt;was&lt;/strong&gt; sorted then we could apply a binary search for a
logarithmic lookup. And in fact, by applying a custom ordering, the
list &lt;strong&gt;is&lt;/strong&gt; sorted.&lt;/p&gt;
&lt;p&gt;How can we apply a custom ordering in Python?&lt;/p&gt;
&lt;p&gt;The way to do this has changed as Python has developed. The table below shows
the evolution of standard Python functions which sort and compare.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Functions&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;max, min, list.sort([cmp]), bisect.bisect&lt;/td&gt;
&lt;td&gt;Note that [cmp] slows the sorting process down considerably&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.3&lt;/td&gt;
&lt;td&gt;2003&lt;/td&gt;
&lt;td&gt;heapq&lt;/td&gt;
&lt;td&gt;Also known as the priority queue algorithm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td&gt;2004&lt;/td&gt;
&lt;td&gt;sorted(iterable[, cmp[, key[, reverse]]]), list.sort([cmp[, key[, reverse]]]), itertools.groupby(iterable[, key)&lt;/td&gt;
&lt;td&gt;In general, the key and reverse conversion processes are much faster than specifying an equivalent cmp function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td&gt;2004&lt;/td&gt;
&lt;td&gt;heapq.nlargest, heapq.nsmallest&lt;/td&gt;
&lt;td&gt;Heapq extended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;2006&lt;/td&gt;
&lt;td&gt;max([key]), min([key]), heapq.nlargest(&amp;#8230;[, key]), heapq.smallest(&amp;#8230;[, key])&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.6&lt;/td&gt;
&lt;td&gt;2008&lt;/td&gt;
&lt;td&gt;heapq.merge&lt;/td&gt;
&lt;td&gt;Heapq extended again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;2008&lt;/td&gt;
&lt;td&gt;sorted(iterable, key[, reverse]), list.sort(key[, reverse])&lt;/td&gt;
&lt;td&gt;No more &lt;code&gt;cmp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;heapq.merge(&amp;#8230;, key)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.10&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;bisect.bisect(&amp;#8230;, key) etc&lt;/td&gt;
&lt;td&gt;That leaves the low-level &lt;code&gt;heapq&lt;/code&gt; functions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The earliest versions of Python allowed you to sort lists, and
the sort was customised using a &lt;code&gt;cmp&lt;/code&gt; function &amp;#8212; though the documentation
warned there would be a performance penalty[*]. The builtin &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;
functions could not be cutomised, and nor could the comparison used in
the &lt;code&gt;bisect&lt;/code&gt; module &amp;#8212; which is Python&amp;#8217;s binary search implementation.&lt;/p&gt;
&lt;p&gt;At 2.3 the &lt;code&gt;heapq&lt;/code&gt; module appeared, but, like &lt;code&gt;bisect&lt;/code&gt;, there was no way
to customise the ordering of heap elements.&lt;/p&gt;
&lt;p&gt;2.4 introduced the &lt;code&gt;key&lt;/code&gt; argument to customise ordering,
noting this should be preferred to &lt;code&gt;cmp&lt;/code&gt;. Unlike &lt;code&gt;cmp&lt;/code&gt; which compares two
elements, &lt;code&gt;key&lt;/code&gt; takes a single element and returns a sort rank for that element.
The &lt;code&gt;key&lt;/code&gt; argument was added alongside &lt;code&gt;cmp&lt;/code&gt; in &lt;code&gt;list.sort&lt;/code&gt; and the new &lt;code&gt;sorted&lt;/code&gt;
builtin function; and &lt;code&gt;key&lt;/code&gt; was the only way to customise the grouping in
&lt;code&gt;itertools.groupby&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;2.5 added &lt;code&gt;key&lt;/code&gt; to &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;, and also to &lt;code&gt;heapq.nlargest&lt;/code&gt;, &lt;code&gt;heapq.nsmallest&lt;/code&gt;.
Although these &lt;code&gt;heapq&lt;/code&gt; functions now accept a &lt;code&gt;key&lt;/code&gt;, the lower level heap functions
to heapify, push, pop and replace do not.&lt;/p&gt;
&lt;p&gt;2.6 introduced &lt;code&gt;heapq.merge&lt;/code&gt;, a handy function to merge sorted inputs
using a heap, but with no option to specify a sort key.&lt;/p&gt;
&lt;p&gt;3.0 got rid of &lt;code&gt;cmp&lt;/code&gt;, making &lt;code&gt;key&lt;/code&gt; the only way to customise
sorting. To migrate from Python 2 to 3 any &lt;code&gt;cmp&lt;/code&gt; functions need
converting to &lt;code&gt;key&lt;/code&gt; functions. As with Python 2.5, at 3.0 you could
apply a key to &lt;code&gt;list.sort&lt;/code&gt;, &lt;code&gt;sorted&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;,
&lt;code&gt;itertools.groupby&lt;/code&gt;, &lt;code&gt;heapq.nlargest&lt;/code&gt;, &lt;code&gt;heapq.nsmallest&lt;/code&gt; &amp;#8212; but not to
&lt;code&gt;bisect&lt;/code&gt; or other &lt;code&gt;heapq&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;3.5 added &lt;code&gt;key&lt;/code&gt; to &lt;code&gt;heapq.merge&lt;/code&gt;, aligning it with &lt;code&gt;heapq.nlargest&lt;/code&gt;
and &lt;code&gt;heapq.nsmallest&lt;/code&gt;, though it remained impossible to use a sort key
with the lower level heap functions.&lt;/p&gt;
&lt;p&gt;The next change came in 3.10, when the &lt;code&gt;key&lt;/code&gt; parameter was
added to the &lt;code&gt;bisect&lt;/code&gt; module. As far as I can tell that means the only part of
standard Python which doesn&amp;#8217;t let you fully customise ordering is the &lt;code&gt;heapq&lt;/code&gt; module.&lt;/p&gt;
&lt;h2 id=&quot;bisect-with-a-search-key&quot;&gt;Bisect with a search key&lt;/h2&gt;
&lt;p&gt;So, to return to the original puzzle, consider our example
sorted+rotated list:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; values = [7, 11, 13, 19, 2, 3, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first four elements are greater than or equal to the first
element, 7. The last three elements are less than 7.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; [v &amp;lt; values[0] for v in values]
[False, False, False, False, True, True, True]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;False&lt;/code&gt; &amp;lt; &lt;code&gt;True&lt;/code&gt; the result of the list comprehension above is sorted.
Extending this idea, the following comprehension is also sorted.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; [(v &amp;lt; values[0], v) for v in values]
[(False, 7), (False, 11), (False, 13), (False, 19), (True, 2), (True, 3), (True, 5)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have a logarithmic lookup using binary search:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from bisect import bisect_left

def lookup(values, v):
    key = lambda x: (x &amp;lt; values[0], x)
    i = bisect_left(values, key(v), key=key)
    return i if (i &amp;lt; len(values) and values[i] == v) else -1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;dont-search-for-v-search-for-its-key&quot;&gt;Don&amp;#8217;t search for v, search for its key&lt;/h2&gt;
&lt;p&gt;I was surprised to realise the value &lt;code&gt;v&lt;/code&gt; being looked up has to have the &lt;code&gt;key&lt;/code&gt;
function applied &lt;strong&gt;before&lt;/strong&gt; calling &lt;code&gt;bisect_left&lt;/code&gt;. That is, to find where &lt;code&gt;v&lt;/code&gt;
should go in &lt;code&gt;values&lt;/code&gt; to maintain the sort order, we pass &lt;code&gt;key(v)&lt;/code&gt; to &lt;code&gt;bisect_left&lt;/code&gt;.
This doesn&amp;#8217;t match the interface to binary search in other languages. It also means
in our example we have to handle empty lists as a special case.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def lookup(values, v):
    if not values: return -1
    key = lambda x: (x &amp;lt; values[0], x)
    i = bisect_left(values, key(v), key=key)
    return i if (i &amp;lt; len(values) and values[i] == v) else -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[*] Before the introduction of the sort &lt;code&gt;key&lt;/code&gt;, the standard pattern was
&lt;a href=&quot;https://docs.python.org/3/howto/sorting.html#the-old-way-using-decorate-sort-undecorate&quot;&gt;decorate-sort-undecorate&lt;/a&gt;.&lt;/p&gt;</description>
<dc:date>2022-02-15</dc:date>
<guid>https://wordaligned.org/articles/binary-search-gets-a-sort-key</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/binary-search-gets-a-sort-key</link>
<category>Python</category>
<category>Puzzles</category>
</item>

<item>
<title>On Exactitude in Programming</title>
<description>&lt;p&gt;Recently I attended a demonstration of a product intended to help design software, right down to implementation details. It failed to convince me. It did, however, succeed in reminding me of this short work by Jorge Luis Borges:&lt;/p&gt;
&lt;blockquote&gt;&lt;h3&gt;On Exactitude in Science&lt;/h3&gt;
&lt;p&gt;Jorge Luis Borges, Collected Fictions, translated by Andrew Hurley.
&lt;p&gt;&amp;#8230;In that Empire, the Art of Cartography attained such Perfection that the map of a single Province occupied the entirety of a City, and the map of the Empire, the entirety of a Province. In time, those Unconscionable Maps no longer satisfied, and the Cartographers Guilds struck a Map of the Empire whose size was that of the Empire, and which coincided point for point with it. The following Generations, who were not so fond of the Study of Cartography as their Forebears had been, saw that that vast Map was Useless, and not without some Pitilessness was it, that they delivered it up to the Inclemencies of Sun and Winters. In the Deserts of the West, still today, there are Tattered Ruins of that Map, inhabited by Animals and Beggars; in all the Land there is no other Relic of the Disciplines of Geography.
&lt;p&gt;&amp;#8212;Suarez Miranda, Viajes devarones prudentes, Libro IV,Cap. XLV, Lerida, 1658
&lt;/blockquote&gt;

&lt;p&gt;and also of this tweet by &lt;a href=&quot;https://twitter.com/KevlinHenney&quot;&gt;@KevlinHenney&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;The act of describing a program in unambiguous detail and the act of programming are one and the same.&lt;/p&gt;&amp;mdash; Kevlin Henney (@KevlinHenney) &lt;a href=&quot;https://twitter.com/KevlinHenney/status/3361631527?ref_src=twsrc%5Etfw&quot;&gt;August 17, 2009&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;</description>
<dc:date>2021-01-05</dc:date>
<guid>https://wordaligned.org/articles/on-exactitude-in-programming</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/on-exactitude-in-programming</link>
<category>Design</category>
</item>

<item>
<title>Python maths updates</title>
<description>&lt;p&gt;A quick note on some useful updates made to standard Python maths support. &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.prod&quot;&gt;Math.prod&lt;/a&gt; does for &lt;code&gt;*&lt;/code&gt; what &lt;a href=&quot;https://docs.python.org/3/library/functions.html#sum&quot;&gt;sum&lt;/a&gt; does for &lt;code&gt;+&lt;/code&gt;. It was added at Python 3.8.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&amp;gt;&amp;gt;&amp;gt; math.prod([3, 4, 5])
60
&amp;gt;&amp;gt;&amp;gt; math.prod([])
1

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Added in 3.9, &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.lcm&quot;&gt;math.lcm&lt;/a&gt;, returns the least common multiple of its integer arguments. As with &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.prod&quot;&gt;math.prod&lt;/a&gt;, an empty list of arguments returns 1. Extended in 3.9, the related function &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.gcd&quot;&gt;math.gcd&lt;/a&gt; now accepts an arbitrary list of arguments.&lt;/p&gt;
&lt;p&gt;For Euclidean geometry, &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.hypot&quot;&gt;math.hypot&lt;/a&gt; now supports n-dimensional points, and &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.dist&quot;&gt;math.dist&lt;/a&gt; has been added, again working on any pair of n-dimensional points.&lt;/p&gt;
&lt;p&gt;These useful additions and extensions are all in the standard math module (along with several others not mentioned here). Previously you&amp;#8217;d have to roll your own or rely on e.g. &lt;a href=&quot;https://numpy.org/&quot;&gt;numpy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also wanted to mention a nice extension to the power function; in this case to the builtin &lt;a href=&quot;https://docs.python.org/3/library/functions.html#pow&quot;&gt;pow&lt;/a&gt; &amp;#8212; &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.pow&quot;&gt;math.pow&lt;/a&gt; remains as it was. Builtin &lt;a href=&quot;https://docs.python.org/3/library/functions.html#pow&quot;&gt;pow&lt;/a&gt; takes an optional third parameter &lt;code&gt;pow(base, exp[, mod])&lt;/code&gt;. If &lt;code&gt;mod&lt;/code&gt; is specified it must be a non-zero integer, and both &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;exp&lt;/code&gt; must also be integers. The significant but subtle change made at 3.8 is that &lt;code&gt;exp&lt;/code&gt; can now be a negative integer, enabling modular inverse calculations. &lt;/p&gt;
&lt;p&gt;Quoting the &lt;a href=&quot;https://docs.python.org/3/library/functions.html#pow&quot;&gt;documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&amp;#8230; If &lt;i&gt;mod&lt;/i&gt; is present and &lt;i&gt;exp&lt;/i&gt; is negative, &lt;i&gt;base&lt;/i&gt; must be relatively prime to &lt;i&gt;mod&lt;/i&gt;. In that case, &lt;i&gt;pow(inv_base, -exp, mod)&lt;/i&gt; is returned, where inv_base is an inverse to base modulo mod.&lt;/p&gt;&lt;p&gt;Here&amp;#8217;s an example of computing an inverse for 38 modulo 97:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&gt;&gt;&gt; pow(38, -1, mod=97)
23
&gt;&gt;&gt; 23 * 38 % 97 == 1
True
&lt;/pre&gt;&lt;/code&gt;&lt;/blockquote&gt;</description>
<dc:date>2021-01-03</dc:date>
<guid>https://wordaligned.org/articles/python-maths-updates</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/python-maths-updates</link>
<category>Python</category>
</item>

<item>
<title>Fearless Debugging</title>
<description>&lt;h2 id=&quot;jurassic-jigsaw&quot;&gt;Jurassic Jigsaw&lt;/h2&gt;
&lt;p&gt;My thanks to &lt;a href=&quot;http://was.tl&quot;&gt;Eric Wastl&lt;/a&gt; for another excellent &lt;a href=&quot;https://adventofcode.com/&quot;&gt;Advent of Code&lt;/a&gt;. I&amp;#8217;ve now &lt;a href=&quot;https://github.com/wordaligned/advent-of-code-2020&quot;&gt;worked through all 25 puzzles&lt;/a&gt;, some simple, some tough, some familiar, some new; all beautifully set and highly enjoyable.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/20&quot;&gt;Day 20, Jurrasic Jigsaw&lt;/a&gt;, took me longest by far to complete. The puzzle is easy to understand. You have to assemble jigsaw pieces into a seascape. For part one, you need to find the corner pieces. For part two, you must locate monsters in the seascape.&lt;/p&gt;
&lt;p&gt;Here, a jigsaw piece is a monochrome square, represented like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;..##.#..#.
##..#.....
#...##..#.
####.#...#
##.##.###.
##...#.###
.#.#.#..##
..#....#..
###...#.#.
..###..###
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is the sea monster:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   # 
#    ##    ##    ###
 #  #  #  #  #  #
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The twist was that the jigsaw pieces could be rotated and flipped over before matching them up. Once matched, the edges of the pieces were to be removed. Implementing the rotate, flip, match and remove code proved fiddly, and I was pleased to get this working and producing correct results for the supplied example.&lt;/p&gt;
&lt;p&gt;Unfortunately my code produced the wrong answer for part two, the bit where you have to locate sea monsters. So, I would need to debug.&lt;/p&gt;
&lt;h2 id=&quot;fear-of-debugging&quot;&gt;Fear of Debugging&lt;/h2&gt;
&lt;p&gt;Like it or not, debugging is a key part of software development.&lt;/p&gt;
&lt;p&gt;Generally, I do like it. There&amp;#8217;s satisfaction to be had in paring scope, retracing steps, then making the right fix, improving test coverage, and generally leaving the world a better place.&lt;/p&gt;
&lt;p&gt;What I don&amp;#8217;t like, though &amp;#8212; what scares me &amp;#8212; is the suspicion the bug lurks in the worst possible place. What if it&amp;#8217;s in a library we don&amp;#8217;t have the source for? Or if it&amp;#8217;s a timing issue caused by some erratic locking? Or if there&amp;#8217;s an issue with the compiler for the most obscure platform. Or, in this particular case, that the code to fiddle with jigsaw pieces has a bug &amp;#8212; a bug subtle enough to pass the examples but fail the real thing.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not unreasonable to fear the worst. At some point the issues mentioned above &lt;strong&gt;will&lt;/strong&gt; cause bugs, bugs which &lt;strong&gt;are&lt;/strong&gt; hard to fix. We need to be ready.&lt;/p&gt;
&lt;p&gt;Fear, though, is the wrong mindset. Debugging requires you to be calm, methodical and detached. Much as an artist draws what they see and not what they know, a programmer must observe and follow the evidence. A second pair of eyes is always useful; simply explaining the issue to a colleague gives you another perspective.&lt;/p&gt;
&lt;h2 id=&quot;here-be-monsters&quot;&gt;Here be Monsters&lt;/h2&gt;
&lt;p&gt;I was working on my own on the Advent of Code. I could have tried explaining to a &lt;a href=&quot;https://en.wikipedia.org/wiki/Rubber_duck_debugging&quot;&gt;rubber duck&lt;/a&gt;, but didn&amp;#8217;t. Instead I examined and traced my code. I checked and double-checked the flip, rotate, match and remove logic. I printed out intermediate state. I walked to the sea-front and back. I slept on it.&lt;/p&gt;
&lt;p&gt;Fearing the worst turned out to be the wrong strategy.&lt;/p&gt;
&lt;p&gt;What did work was reading the problem statement again, carefully. At last I saw it! Somehow, a rogue character had wormed its way into my inputs. The sea monster I had used looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   #
#    ##    ##    ###
 #  #  #  #  #  #
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;when it should have been:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  # 
#    ##    ##    ###
 #  #  #  #  #  #
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since both monsters appear the same number of times in the example seascape, my test case failed to catch the bug.&lt;/p&gt;
&lt;p&gt;So, with a single, simple, whitespace correction, my advent of code was complete. One of life&amp;#8217;s ironies is that when you lose something you find it in the last place you look. It&amp;#8217;s not always so with debugging: a bug can exist in many different places and sometimes the fix causes the codebase to unravel, requiring a chain of additional fixes, but, in this case, finding the bug fixed it.&lt;/p&gt;
&lt;p&gt;&lt;image src=&quot;https://wordaligned.org/images/seascape.png&quot; alt=&quot;Seascape with monsters&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A monster can exist in many different places, and in this case finding the monster fixed it&lt;/p&gt;</description>
<dc:date>2021-01-02</dc:date>
<guid>https://wordaligned.org/articles/fearless-debugging</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/fearless-debugging</link>
<category>Puzzles</category>
</item>

<item>
<title>Complex numbers for planar geometry</title>
<description>&lt;p&gt;Once again, I&amp;#8217;m enjoying solving &lt;a href=&quot;http://was.tl&quot;&gt;Eric Wastl&lt;/a&gt;&amp;#8217;s excellent &lt;a href=&quot;https://adventofcode.com&quot;&gt;Advent of Code&lt;/a&gt; puzzles.&lt;/p&gt;
&lt;p&gt;Today, &lt;a href=&quot;day12&quot;&gt;day 12&lt;/a&gt; involved a ship navigating in a 2D plane. The ship follows a series of instructions taking the form of actions and values such as &lt;code&gt;F10 N3 F7 R90 F11 ...&lt;/code&gt;, where, for the first part:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;actions N, S, E, W step by the value in the compass directions N, S, E, W&lt;/li&gt;
&lt;li&gt;actions L, R turn the ship left and right by the number of degrees specified by the value&lt;/li&gt;
&lt;li&gt;action F advances the ship in the direction it faces by the given value&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Perhaps the most obvious way to model this is by implementing a &lt;code&gt;Point&lt;/code&gt; class, with &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; values, and suitable methods to advance and rotate.&lt;/p&gt;
&lt;p&gt;Another way is to use complex numbers, which are natively supported by Python &amp;#8212; and many other languages. The complex plane &lt;em&gt;is&lt;/em&gt; a 2D plane. The point &lt;code&gt;(x, y)&lt;/code&gt; is represented by a single complex number &lt;code&gt;p = x + y * j&lt;/code&gt;. Stepping in any direction corresponds to addition, and rotation to multiplication.&lt;/p&gt;
&lt;p&gt;So, the instructions &lt;code&gt;N, S, E, W&lt;/code&gt; map to adding complex numbers &lt;code&gt;j, -j, 1, -1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Quarter turns left and right map to multiplication by &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;-j&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;def ship_position(instructions):
    &amp;#x27;&amp;#x27;&amp;#x27;Return the final position of the ship after following the instructions

    Instructions are a series of (action, value) pairs.
    &amp;#x27;&amp;#x27;&amp;#x27;
    ship, direction = 0, 1 # Start at the origin facing E
    step = {&amp;#x27;N&amp;#x27;:1j, &amp;#x27;W&amp;#x27;:-1, &amp;#x27;S&amp;#x27;:-1j, &amp;#x27;E&amp;#x27;: 1}
    turn = {&amp;#x27;R&amp;#x27;:-1j, &amp;#x27;L&amp;#x27;:1j}
    for action, value in instructions:
        if action in &amp;#x27;NSEW&amp;#x27;:
            ship += value * step[action]
        elif action in &amp;#x27;LR&amp;#x27;:
            assert value % 90 == 0 # check rectilinear motion
            direction *= turn[action] ** (value//90)
        else:
            assert action == &amp;#x27;F&amp;#x27;
            ship += value * direction
    return ship

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It&amp;#8217;s also possible to implement the conditionals above arithmetically. We can think of each instruction advancing the ship (possibly by zero) and turning it (possibly by zero degrees).&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;def ship_position(instructions):
    ship, direction = 0, 1
    step = {&amp;#x27;N&amp;#x27;:1j, &amp;#x27;W&amp;#x27;:-1, &amp;#x27;S&amp;#x27;:-1j, &amp;#x27;E&amp;#x27;: 1}
    turn = {&amp;#x27;R&amp;#x27;:-1j, &amp;#x27;L&amp;#x27;:1j}
    for action, value in instructions:
        ship += value * (step.get(action, 0) + (action==&amp;#x27;F&amp;#x27;) * direction)
        direction *= turn.get(action, 1) ** (value//90)
    return ship

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;More solutions &lt;a href=&quot;https://github.com/wordaligned/advent-of-code-2020&quot;&gt;here&lt;/a&gt;, and thanks again to Eric Wastl.&lt;/p&gt;</description>
<dc:date>2020-12-12</dc:date>
<guid>https://wordaligned.org/articles/complex-numbers-for-planar-geometry</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/complex-numbers-for-planar-geometry</link>
<category>Python</category>
<category>Puzzles</category>
</item>

<item>
<title>Cryptic Message</title>
<description>&lt;p&gt;Anyone able to help make sense of this bizarre tweet which appeared on my timeline?&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;The challenge is to decipher the message&lt;/p&gt;&amp;mdash; Thomas Guest (@thomasguest) &lt;a href=&quot;https://twitter.com/thomasguest/status/1137215876271415297?ref_src=twsrc%5Etfw&quot;&gt;June 8, 2019&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;Please answer using the same style so others can find their own solution. Bonus points for both quality and quantity.&lt;/p&gt;
&lt;div&gt;&lt;img src=&quot;https://wordaligned.org/images/laboratory.jpg&quot; alt=&quot;Laboratory&quot; title=&quot;Searching for clues&quot; /&gt;&lt;/div&gt;</description>
<dc:date>2019-06-08</dc:date>
<guid>https://wordaligned.org/articles/cryptic-message</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/cryptic-message</link>
<category>Puzzles</category>
</item>

<item>
<title>Dr G&#8217;s Award Winning Puzzles</title>
<description>&lt;p&gt;A colleague of mine shares my love of puzzles. Whilst I like solving them, he also likes to design and build them. What I hadn&amp;#8217;t realised is that there&amp;#8217;s a community of puzzlers out there, who hold conventions, share designs, and generally celebrate and advance the art of puzzling.&lt;/p&gt;
&lt;p&gt;Dr G &amp;#8212; my colleague &amp;#8212; is part of that community and also owns a 3D printer. He works from home but whenever he visits the office there&amp;#8217;ll be a freshly-printed puzzle for us to play with. I feel as excited as a young hobbit when Gandalf visits the Shire.&lt;/p&gt;
&lt;p&gt;The best puzzles have just a few simple pieces. You can see how the parts must finally align but the geometry conspires to confound. There &lt;em&gt;will&lt;/em&gt; be a sequence of twists and turns. There &lt;em&gt;must&lt;/em&gt; be.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/casino-unpacked.jpg&quot; alt=&quot;Casino&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Casino, designed by Dr Volker Latussek, is both mould breaking and an instant classic. You have to slot 6 identical casino chips into a cubic box. The lip which makes the opening to the box rectangular rather than square is the single asymmetry which makes this task almost impossible rather than utterly trivial.&lt;/p&gt;
&lt;p&gt;I fiddled with it, rolling the chips into position, sliding and shunting. After many minutes of manipulation I put it down, the chips loosely arranged in and on top of the box. After a lunch break I picked it up, and to my amazement the chips slid easily and directly into place.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/casino-solved.jpg&quot; alt=&quot;Casino&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/packtic-unpacked.jpg&quot; alt=&quot;PackTIC&quot;/&gt;&lt;/p&gt;
&lt;p&gt;PackTIC, designed by Andrew Crowell is a very different puzzle. The TIC stands for Turning Interlocking Cube. A bit like a 3D version of Tetris, you have to manipulate a 5 very different cubilinear pieces so they fuse into an irregular chassis. I took this one on the train with me. At the end of the journey I had figured out how the pieces would fit, but not how to assemble them. The following morning, as with the Casino puzzle, everything just clicked into place.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/packtic-solved.jpg&quot; alt=&quot;PackTIC&quot;/&gt;&lt;/p&gt;</description>
<dc:date>2019-04-09</dc:date>
<guid>https://wordaligned.org/articles/dr-gs-award-winning-puzzles</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/dr-gs-award-winning-puzzles</link>
<category>Self</category>
<category>Puzzles</category>
</item>

<item>
<title>Aligning the first line of a triple-quoted string in Python</title>
<description>&lt;p&gt;Python&amp;#8217;s triple-quoted strings are a convenient syntax for strings where the contents span multiple lines. Unescaped newlines are allowed in triple-quoted strings. So, rather than write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;song = (&quot;Happy birthday to you\n&quot;
        &quot;Happy birthday to you\n&quot;
        &quot;Happy birthday dear Gail\n&quot;
        &quot;Happy birthday to you\n&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you can write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;song = &quot;&quot;&quot;Happy birthday to you
Happy birthday to you
Happy birthday dear Gail
Happy birthday to you
&quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only downside here is that the first line doesn&amp;#8217;t align nicely with the lines which follow. The way around this is to embed a &lt;code&gt;\newline&lt;/code&gt; escape sequence, meaning both &lt;a href=&quot;https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals&quot; title=&quot;String and Bytes literals&quot;&gt;backslash and newline are ignored&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;song = &quot;&quot;&quot;\
Happy birthday to you
Happy birthday to you
Happy birthday dear Gail
Happy birthday to you
&quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;</description>
<dc:date>2019-02-17</dc:date>
<guid>https://wordaligned.org/articles/aligning-the-first-line-of-a-triplequoted-string-in-python</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/aligning-the-first-line-of-a-triplequoted-string-in-python</link>
<category>Python</category>
</item>

<item>
<title>Python Counters @PyDiff</title>
<description>&lt;p&gt;On Monday I gave a talk at &lt;a href=&quot;http://www.pydiff.wales/&quot;&gt;PyDiff&lt;/a&gt; on the subject of Python Counters. A Counter is a specialised &lt;code&gt;dict&lt;/code&gt; which has much in common with a &lt;code&gt;set&lt;/code&gt;. Of course all dicts are like sets, but with Counters the resemblance is even stronger. The &lt;a href=&quot;https://docs.python.org/3/library/collections.html#collections.Counter&quot;&gt;documentation&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Counter class is similar to bags or multisets in other languages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Alongside set operations of union, intersection and is-a-subset, Counter also supports addition and subtraction &amp;#8212; natural and unsurprising operations for a container whose job is to keep count of its elements. If you want to unite the contents of two Counters, it&amp;#8217;s probably &lt;code&gt;+&lt;/code&gt; you want rather than &lt;code&gt;|&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Counters came to mind as a lightning talk subject since I had a go at the &lt;a href=&quot;https://adventofcode.com/2018&quot; title=&quot;25 Christmas themed puzzles made available one-per-day as a countdown to Christmas&quot;&gt;Advent of Code&lt;/a&gt; last year and used no fewer than 12 Counters in my &lt;a href=&quot;https://github.com/wordaligned/advent-of-code-2018/blob/master/solutions.ipynb&quot;&gt;solutions&lt;/a&gt; to 25 puzzles &amp;#8212; and that total could well increase since I haven&amp;#8217;t finished yet.&lt;/p&gt;
&lt;p&gt;The talk itself is on &lt;a href=&quot;https://github.com/wordaligned/python-counters&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/wordaligned/python-counters&quot;&gt;&lt;img alt=&quot;Coins&quot; src=&quot;https://wordaligned.org/images/coins.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description>
<dc:date>2019-01-19</dc:date>
<guid>https://wordaligned.org/articles/python-counters-pydiff</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/python-counters-pydiff</link>
<category>Talks</category>
<category>Python</category>
</item>

<item>
<title>Metaphormers</title>
<description>&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-553-firework.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-23-fire.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-242-flash.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;A metaphor is a figure of speech where you describe something in terms of something else. For example, when Katy Perry sings &amp;#8220;Baby, you&amp;#8217;re a firework&amp;#8221; she doesn&amp;#8217;t mean you&amp;#8217;re an explosive for use on bonfire night &amp;#8212; she&amp;#8217;s saying you&amp;#8217;ve got a spark inside you, you should &amp;#8220;ignite the light&amp;#8221;, &amp;#8220;show &amp;#8216;em what you&amp;#8217;re worth&amp;#8221;, &amp;#8220;shoot across the sky&amp;#8221; and &amp;#8220;make &amp;#8216;em go, Oh, oh, oh!&amp;#8221;.&lt;/p&gt;
&lt;p&gt;You&amp;#8217;re spectacular &amp;#8212; a &lt;strong&gt;firework&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This post considers some metaphors for computer programming. I hope we can gain some insights into what we do by looking at it from a different angle. In other words: what are we like?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-236-pen.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-108-text-resize.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-111-align-left.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We &lt;strong&gt;write&lt;/strong&gt; software. That&amp;#8217;s not a metaphor though. It&amp;#8217;s &lt;strong&gt;literally&lt;/strong&gt; what we do. We write, edit, review and publish texts. In scrum teams we even work on &lt;strong&gt;stories&lt;/strong&gt;. It&amp;#8217;s not particularly helpful.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not unhelpful either, unlike the next couple of examples, for which I blame recruitment agents.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-592-person-running.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-18-music.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-49-star-empty.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;An advert for a programming &lt;strong&gt;ninja&lt;/strong&gt; isn&amp;#8217;t meant to attract a Japanese mercenary trained in espionage and assassination, must have 2 years PHP experience &amp;#8212; it&amp;#8217;s meant to make a dull job sound exciting. Similarly a &lt;strong&gt;rockstar&lt;/strong&gt; is unwelcome on most software teams. Creativity and even attitude may be useful. Not so the rampant ego and &lt;a href=&quot;http://www.thisisinsider.com/van-halen-brown-m-ms-contract-2016-9&quot;&gt;trantrums&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-313-rugby.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-330-soccer-ball.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-463-basketball.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;How about &lt;strong&gt;sports&lt;/strong&gt;? We&amp;#8217;re &lt;strong&gt;agile&lt;/strong&gt;. We work in &lt;strong&gt;teams&lt;/strong&gt; on &lt;strong&gt;sprints&lt;/strong&gt; scoring (story) &lt;strong&gt;points&lt;/strong&gt;. In our &lt;strong&gt;scrum&lt;/strong&gt; meetings we discuss &lt;strong&gt;tactics&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-273-cake.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-274-drink.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-276-fast-food.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-278-pizza.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-277-cutlery.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Is coding like &lt;strong&gt;cooking&lt;/strong&gt;? We assemble the right &lt;strong&gt;ingredients&lt;/strong&gt; and follow tried and trusted &lt;strong&gt;recipes&lt;/strong&gt;. Our products are &lt;strong&gt;consumed&lt;/strong&gt; and adjusted to &lt;strong&gt;taste&lt;/strong&gt; based on feedback.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-263-spade.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-311-flower.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-22-snowflake.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-232-sun.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-2-leaf.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-71-umbrella.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-361-bug.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Software grows organically. Tending to a codebase is a form of &lt;strong&gt;gardening&lt;/strong&gt; &amp;#8212; we nurture new features and allow them to &lt;strong&gt;blossom&lt;/strong&gt;, all the while &lt;strong&gt;pruning&lt;/strong&gt; dead code and trying to keep &lt;strong&gt;bugs&lt;/strong&gt; under control. Release cycles are seasonal. Success depends on both weather and climate.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-535-lab-alt.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-235-brush.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-599-scissors-alt.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;If Computer &lt;strong&gt;Science&lt;/strong&gt; is the discipline, &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Art_of_Computer_Programming&quot;&gt;The &lt;strong&gt;Art&lt;/strong&gt; of Computer Programming&lt;/a&gt;, supplies the detail, and the practice is often described as a &lt;strong&gt;Craft&lt;/strong&gt;. There&amp;#8217;s a progression, &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Pragmatic_Programmer&quot;&gt;from journeyman to master&lt;/a&gt;, during which we learn the &lt;strong&gt;tools&lt;/strong&gt; of our &lt;strong&gt;trade&lt;/strong&gt;. Although end users may never see the elegant code which underpins the interface they use, we take pride in our work and like to think they can sense our attention to detail.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-21-home.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-69-ruler.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-377-hand-saw.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-375-claw-hammer.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The most popular metaphor is &lt;a href=&quot;https://en.wikipedia.org/wiki/Code_Complete&quot;&gt;&lt;strong&gt;construction&lt;/strong&gt;&lt;/a&gt;. It&amp;#8217;s there in our job titles: &lt;strong&gt;Architect&lt;/strong&gt;, &lt;strong&gt;Project Manager&lt;/strong&gt;, &lt;strong&gt;Engineer&lt;/strong&gt;. We plan, assemble, build, test, deliver. Unfortunately this metaphor fails to recognise the supple, fluid nature of software &amp;#8212; its &lt;strong&gt;softness&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re building a house you start with foundations and then the walls go up, at which point it becomes impossible to change the foundations. If you&amp;#8217;re building software, you could start with the wiring and then put the roof on. There&amp;#8217;s nothing stopping you swapping the foundations at any point: running on another platform, or switching the memory manager, for example, is no more difficult than changing the user interface styling.&lt;/p&gt;
&lt;p&gt;Or consider a software service, supported by a collaboration of microservices which are continually developed, reconfigured, replaced. That&amp;#8217;s not construction. It&amp;#8217;s communication.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-371-globe-af.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-51-link.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-33-wifi-alt.png&quot; alt=&quot;icon&quot;/&gt;
&lt;img src=&quot;https://wordaligned.org/images/glyphicons/glyphicons-552-podcast.png&quot; alt=&quot;icon&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Communication is the metaphor I&amp;#8217;m going to champion. Code &lt;strong&gt;communicates&lt;/strong&gt;, via compiler or &lt;strong&gt;interpreter&lt;/strong&gt;, with the platform. It communicates with us via editor and browser. We use text, pictures, speech, gestures. We share rooms, screens, thoughts. We listen to our users. We engage with our community.&lt;/p&gt;
&lt;p&gt;At the start of this post I dismissed &amp;#8220;writing&amp;#8221; as too literal. Beyond the literal and beneath the words, it&amp;#8217;s evident we&amp;#8217;re in the &lt;strong&gt;language&lt;/strong&gt; business: not just programming languages, but also the dialect of our APIs and modules, the metaphors which describe and define our designs. Design patterns are simply shared metaphor &amp;#8212; factory, visitor, facade &amp;#8212; and a codebase communicates by shaping and extending its own local metaphors.&lt;/p&gt;
&lt;p&gt;Software is the development of metaphor. We are &lt;strong&gt;metaphormers&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;As Katy Perry would say: Oh, oh, oh!&lt;/p&gt;
&lt;p style=&quot;text-align:center&quot;&gt;&amp;sect;&lt;/p&gt;

&lt;p&gt;The icons used on this page were downloaded from &lt;a href=&quot;http://glyphicons.com&quot;&gt;http://glyphicons.com&lt;/a&gt; and are licensed under the &lt;a href=http://creativecommons.org/licenses/by/3.0/deed.en&gt;CC BY 3.0&lt;/a&gt; terms.&lt;/p&gt;</description>
<dc:date>2018-05-30</dc:date>
<guid>https://wordaligned.org/articles/metaphormers</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/metaphormers</link>
<category>Self</category>
<category>Talks</category>
</item>

<item>
<title>Creating a dict of lists in Python</title>
<description>&lt;p&gt;Suppose you have a list of objects which you want to convert into a dict mapping from some object key to the (sub-)list of objects with that key. To provide a simple example, let&amp;#8217;s start with a list of fruits.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;from collections import namedtuple

Fruit = namedtuple(&amp;#x27;Fruit&amp;#x27;, &amp;#x27;name colour&amp;#x27;)

def banana():     return Fruit(&amp;#x27;banana&amp;#x27;, &amp;#x27;yellow&amp;#x27;)
def grape():      return Fruit(&amp;#x27;grape&amp;#x27;, &amp;#x27;green&amp;#x27;)
def pear():       return Fruit(&amp;#x27;pear&amp;#x27;, &amp;#x27;green&amp;#x27;)
def strawberry(): return Fruit(&amp;#x27;strawberry&amp;#x27;, &amp;#x27;red&amp;#x27;)
def cherry():     return Fruit(&amp;#x27;cherry&amp;#x27;, &amp;#x27;red&amp;#x27;)

fruits = [
    banana(), pear(), cherry(), cherry(), pear(),
    grape(), banana(), grape(), cherry(), grape(),
    strawberry(), pear(), grape(), cherry()]

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We&amp;#8217;d like to arrange a fruitbowl &amp;#8212; a dict which groups fruits by colour. This can be done by creating an empty bowl, then iterating through the fruits placing each in the correct list.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;fruitbowl = {}

for fruit in fruits:
    fruitbowl.setdefault(fruit.colour, []).append(fruit)

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Dict.setdefault&lt;/code&gt; is a bit of an oddity in Python, both doing something and returning a value, but it&amp;#8217;s a convenient shorthand in this case. Despite this convenience it&amp;#8217;s more common to use a &lt;code&gt;defaultdict&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;from collections import defaultdict

fruitbowl = defaultdict(list)

for fruit in fruits:
    fruitbowl[fruit.colour].append(fruit)

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here&amp;#8217;s a function to display the fruitbowl.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;def print_bowl(bowl):
    print(&amp;#x27;\n&amp;#x27;.join(
        &amp;#x27;{}: {}&amp;#x27;.format(colour,
                        &amp;#x27;, &amp;#x27;.join(f.name for f in fruits))
        for colour, fruits in bowl.items()))

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If we call this function, we see the fruits have indeed been grouped by colour.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&amp;gt;&amp;gt;&amp;gt; print_bowl(fruitbowl)
yellow: banana, banana
green: pear, pear, grape, grape, grape, pear, grape
red: cherry, cherry, cherry, strawberry, cherry

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is all fine and idiomatic Python, but whenever I see an empty dict being created followed by a loop to populate it, I wonder if a comprehension could be used.&lt;/p&gt;
&lt;p&gt;Is there a way to declare and initialise the dict in a single expression? Here&amp;#8217;s the best I came up with.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;from operator import attrgetter
from itertools import groupby

colour = attrgetter(&amp;#x27;colour&amp;#x27;)

fruitbowl = {
    col: list(fts)
    for col, fts in groupby(sorted(fruits, key=colour), colour)}

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Is this better than the &lt;code&gt;defaultdict&lt;/code&gt; solution. Probably not, but it&amp;#8217;s a technique worth remembering. Maybe the &lt;code&gt;fruitbowl&lt;/code&gt; isn&amp;#8217;t needed, and we actually just need to iterate through the fruits grouped by colour. For example, which colour is most popular?&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&amp;gt;&amp;gt;&amp;gt; max(fruitbowl.items(), key=lambda kv: len(kv[1]))[0]
&amp;#x27;green&amp;#x27;

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Using &lt;code&gt;groupby&lt;/code&gt;, we don&amp;#8217;t need the bowl.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&amp;gt;&amp;gt;&amp;gt; def grouplen(k_gp):
...     return sum(1 for _ in k_gp[1])
&amp;gt;&amp;gt;&amp;gt; max(groupby(sorted(fruits, key=colour), colour), key=grouplen)[0]
&amp;gt;&amp;gt;&amp;gt; &amp;#x27;green&amp;#x27;

&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this case, we don&amp;#8217;t need &lt;code&gt;groupby&lt;/code&gt; either. &lt;a href=&quot;./timtowtdi-vs-tsboapooowtdi&quot;&gt;There is more than one way to do it&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;typocode&quot;&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&amp;gt;&amp;gt;&amp;gt; from collections import Counter
&amp;gt;&amp;gt;&amp;gt; Counter(map(colour, fruits)).most_common(1)
[(&amp;#x27;green&amp;#x27;, 7)]

&lt;/pre&gt;

&lt;/div&gt;</description>
<dc:date>2018-04-29</dc:date>
<guid>https://wordaligned.org/articles/dict-of-lists</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/dict-of-lists</link>
<category>Python</category>
<category>Streams</category>
</item>

<item>
<title>TIMTOWTDI vs TSBO-APOO-OWTDI</title>
<description>&lt;h2 id=&quot;timtowtdi&quot;&gt;TIMTOWTDI&lt;/h2&gt;
&lt;p&gt;TIMTOWTDI stands for &amp;#8220;There is more than one way to do it&amp;#8221;, an approach promoted by the Perl community.&lt;/p&gt;
&lt;p&gt;The mindset behind it gets explored in more detail by the language&amp;#8217;s creator, Larry Wall, in a talk given in 1999: &lt;a href=&quot;https://www.perl.com/pub/1999/03/pm.html/&quot;&gt;&amp;#8220;Perl, the first postmodern computer language&amp;#8221;&lt;/a&gt;. He attributes the slogan to his daughter, Heidi, who says it&amp;#8217;s a strategy which works well in her maths class; and &lt;strong&gt;she&lt;/strong&gt; associates it with another saying used at school: &amp;#8220;Tsall Good&amp;#8221;. This doesn&amp;#8217;t mean everything is good, or even everything has good bits. It means, overall, things are good. See the big picture.&lt;/p&gt;
&lt;p&gt;Perl epitomises this. It&amp;#8217;s eclectic and inclusive, supporting a variety of styles. One-liner? Fine! Like a shell script? Sure! Structured programming, object-oriented, functional? Why not! Tsall good.&lt;/p&gt;
&lt;p&gt;I like that.&lt;/p&gt;
&lt;p&gt;But do I feel that way about programming?&lt;/p&gt;
&lt;h2 id=&quot;tsbo-apoo-owtdi&quot;&gt;TSBO-APOO-OWTDI&lt;/h2&gt;
&lt;p&gt;A contrasting mantra appears in the &lt;a href=&quot;https://www.python.org/dev/peps/pep-0020/&quot;&gt;Zen of Python&lt;/a&gt;, a list of aphorisms which summarise the guiding principles behind Python&amp;#8217;s design. Item number 13 states &amp;#8220;There should be one &amp;#8212; and preferably only one &amp;#8212; obvious way to do it.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Perhaps realising this sounds overly prescriptive, this rule is tempered by item 14, &amp;#8220;Although that way may not be obvious at first unless you&amp;#8217;re Dutch.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Guido van Rossum, Python&amp;#8217;s BDFL &amp;#8212; Benevolent Dictator For Life &amp;#8212; would be the Dutch person who finds things obvious. That&amp;#8217;s right: &lt;strong&gt;Dictator&lt;/strong&gt;. Programmers don&amp;#8217;t like being told what to do any more than two year olds. How then has Python become so popular? &lt;/p&gt;
&lt;p&gt;Maybe emphasis falls on &lt;strong&gt;should&lt;/strong&gt;. There &lt;strong&gt;should&lt;/strong&gt; be only one obvious way to do it: it&amp;#8217;s just that &amp;#8212; Dutch or otherwise &amp;#8212; we haven&amp;#8217;t got there yet.&lt;/p&gt;
&lt;h2 id=&quot;timtop&quot;&gt;TIMTOP&lt;/h2&gt;
&lt;p&gt;For example, there is more than one Python. Obviously there&amp;#8217;s Python 2 and Python 3, but it&amp;#8217;s less obvious which to use. Don&amp;#8217;t forget &lt;a href=&quot;https://pypy.org/&quot;&gt;PyPy&lt;/a&gt;. Increasingly Python comes packaged with data processing and visualisation extensions, served up as a &lt;a href=&quot;http://jupyter.org/&quot;&gt;Jupyter&lt;/a&gt; notebook.&lt;/p&gt;
&lt;h2 id=&quot;timtopom&quot;&gt;TIMTOPOM&lt;/h2&gt;
&lt;p&gt;There is more than one program options module.&lt;/p&gt;
&lt;p&gt;When I started with Python there was &lt;a href=&quot;https://docs.python.org/3/library/getopt.html&quot;&gt;getopt&lt;/a&gt;, the one and only command line handler. Coming from a C/C++ background I was quite happy to use something resembling GNU&amp;#8217;s getopt. Then &lt;a href=&quot;https://docs.python.org/3/library/optparse.html&quot;&gt;optparse&lt;/a&gt; appeared. Now there&amp;#8217;s &lt;a href=&quot;https://docs.python.org/3/library/argparse.html&quot;&gt;argparse&lt;/a&gt;. All of these libraries are readily available. Which should I use? Not optparse, that&amp;#8217;s deprecated, unless I&amp;#8217;m already using it and it works, that is. Regarding the other contenders, the &lt;a href=&quot;https://docs.python.org/3/library/getopt.html&quot;&gt;documentation&lt;/a&gt; archly notes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Users who are unfamiliar with the C &lt;a href=&quot;http://man7.org/linux/man-pages/man3/getopt.3.html&quot;&gt;&lt;code&gt;getopt()&lt;/code&gt;&lt;/a&gt; function or who would like to write less code and get better help and error messages should consider using the &lt;a href=&quot;https://docs.python.org/3/library/argparse.html#module-argparse&quot;&gt;argparse module&lt;/a&gt; instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are other non-standard Python options for parsing a command line too: ones which &lt;a href=&quot;http://docopt.org/&quot;&gt;generate code from the usage&lt;/a&gt; notes, or by &lt;a href=&quot;https://github.com/google/python-fire&quot;&gt;inspecting the code you want to expose&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is more than one way to do it.&lt;/p&gt;
&lt;h2 id=&quot;timtoutf&quot;&gt;TIMTOUTF&lt;/h2&gt;
&lt;p&gt;There is more than one unit test framework. The obvious one, &lt;a href=&quot;https://docs.python.org/3/library/unittest.html&quot;&gt;unittest&lt;/a&gt;, like getopt, draws inspiration from elsewhere &amp;#8212; in this case Java&amp;#8217;s Junit. Unfortunately the port is too faithful, and you&amp;#8217;ll have to inherit from super classes etc to test something. I much prefer &lt;a href=&quot;https://docs.pytest.org&quot;&gt;PyTest&lt;/a&gt;, which flexes the language itself to deliver test assertions as &lt;code&gt;assert&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s also a &lt;a href=&quot;https://docs.python.org/3/library/doctest.html&quot;&gt;doctest&lt;/a&gt; module in the standard library which executes and checks code found in strings (hold that thought!), and there are many other non-standard testing frameworks.&lt;/p&gt;
&lt;p&gt;There is more than one way to do it.&lt;/p&gt;
&lt;h2 id=&quot;timtowofs&quot;&gt;TIMTOWOFS&lt;/h2&gt;
&lt;p&gt;There is more than one way of formatting strings.&lt;/p&gt;
&lt;p&gt;As we&amp;#8217;ve seen there&amp;#8217;s more than one Python, and libraries are always up for reinvention. This is arguably evolution rather than a multiplicity of options. That is, the most recent way to do it should be preferred.&lt;/p&gt;
&lt;p&gt;When it comes to string formatting, though, there has &lt;strong&gt;always&lt;/strong&gt; been more than one way to do it, and more ways are still being added.&lt;/p&gt;
&lt;p&gt;Do you use &lt;code&gt;&#x27;single&#x27;&lt;/code&gt; or &lt;code&gt;&quot;double&quot;&lt;/code&gt; quotes for a string? &lt;code&gt;&quot;&quot;&quot;Triple&quot;&quot;&quot;&lt;/code&gt; quotes. Raw strings? Raw with an &lt;code&gt;r&lt;/code&gt; or Raw with an &lt;code&gt;R&lt;/code&gt;? TIMTOWTDI.&lt;/p&gt;
&lt;p&gt;What if you want to embed the value of a variable in a string? Users familiar with C&amp;#8217;s &lt;code&gt;printf()&lt;/code&gt; function might prefer &lt;code&gt;%&lt;/code&gt; formatting. Fans of $shell $parameter $expansion can use &lt;a href=&quot;https://docs.python.org/3/library/string.html#template-strings&quot;&gt;template strings&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-3101/&quot;&gt;Advanced string formatting&lt;/a&gt; &amp;#8212; &lt;code&gt;str.format&lt;/code&gt; &amp;#8212; appeared in Python 3.0, backported to Python 2.6. No doubt it has advantages over &lt;code&gt;%&lt;/code&gt; formatting, but for me it&amp;#8217;s a little more obscure and a little less obvious. Python 3.6 introduces &lt;a href=&quot;https://www.python.org/dev/peps/pep-0498/&quot;&gt;f-strings&lt;/a&gt; which build on &lt;code&gt;str.format&lt;/code&gt; and knock down my reservations. The syntax allows you to evaluate expressions in strings: evidently Python is heading in Perl&amp;#8217;s direction.&lt;/p&gt;
&lt;h2 id=&quot;apsdotadiw&quot;&gt;APSDOTADIW&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s finish by returning to Perl, and to &lt;a href=&quot;https://www.perl.com/pub/1999/03/pm.html/&quot;&gt;Larry Wall&amp;#8217;s 1999 talk&lt;/a&gt;. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How many times have we heard the mantra that a program should do one thing and do it well?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perl is not that program. Perl wants to do everything well. It integrates features and makes no attempt to homogenise them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You&amp;#8217;ve all heard the saying: If all you have is a hammer, everything starts to look like a nail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perl is no hammer: it has memorably been described as a Swiss army chainsaw, but Larry Wall likens it to a more conventional tool.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If all you have is duct tape, everything starts to look like a duct. Right. When&amp;#8217;s the last time you used duct tape on a duct?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Python may aspire to offer a single obvious way to do something. It fails splendidly, being more duct tape than hammer.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I presented this blog post as a &lt;a href=&quot;https://www.meetup.com/PyDiff/events/249220768&quot;&gt;lightning talk at PyDiff&lt;/a&gt; a couple of days ago. The &lt;a href=&quot;https://wordaligned.org/docs/timtowtdi&quot;&gt;slides are here&lt;/a&gt;. The talk was recorded too: &lt;a href=&quot;https://cardiff.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=324c4015-51ed-4bd7-a1c7-a8c50089e746&quot;&gt;I appear about 24 minutes in&lt;/a&gt;.&lt;/p&gt;</description>
<dc:date>2018-04-19</dc:date>
<guid>https://wordaligned.org/articles/timtowtdi-vs-tsboapooowtdi</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/timtowtdi-vs-tsboapooowtdi</link>
<category>Python</category>
<category>Perl</category>
</item>

<item>
<title>DDD Wales, 2018</title>
<description>&lt;p&gt;The first ever &lt;a href=&quot;https://www.dddwales.com/&quot;&gt;DDD Wales&lt;/a&gt; was held yesterday at &lt;a href=&quot;https://swansea.techhub.com/&quot;&gt;TechHub Swansea&lt;/a&gt;. It was a free-to-attend one day event comprising 5 full one hour sessions split into 3 parallel tracks; that makes 15 sessions to choose from. Additionally, there were lightning talks in the lunch break.&lt;/p&gt;
&lt;div&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Wow what a day! Time for some rest! Thank you again to all our amazing sponsors, exhibitors, Speakers, attendees and venue. &lt;br&gt;&lt;br&gt;See you next year &lt;a href=&quot;https://twitter.com/hashtag/DDDWales?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#DDDWales&lt;/a&gt;&lt;/p&gt;&amp;mdash; DDD Wales (@dddcymru) &lt;a href=&quot;https://twitter.com/dddcymru/status/977684471750316032?ref_src=twsrc%5Etfw&quot;&gt;March 24, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;

&lt;p&gt;I enjoyed &lt;a href=&quot;https://twitter.com/kevinrjones&quot;&gt;Kevin Jones&lt;/a&gt;&amp;#8217; introduction to Kotlin, the more so since it was almost entirely coded live. Kevin ably demonstrated Kotlin to be &amp;#8220;Java without the ceremony&amp;#8221;. I could see connections with other modern compiled languages &amp;#8212; Swift for example &amp;#8212; languages which aren&amp;#8217;t feature-shy, but which aim for a light, clean syntax; languages which build on existing systems and libraries. It was interesting to see his use of the JetBrains IDE as a teaching aid, and indeed to pick up on audience thoughts on the use of IDEs to flesh out code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/ChrisCundill&quot;&gt;Chris Cundill&amp;#8217;s&lt;/a&gt; talk on &lt;a href=&quot;http://releaseflow.org/#about&quot;&gt;&amp;#8220;release flow&amp;#8221;&lt;/a&gt; was another highlight. You may not have heard of release flow but you&amp;#8217;ll know what it is: a tried and tested strategy for code branching. Chris used his talk to challenge and call out some more recent alternatives &amp;#8212; Gitflow being the prime target. The session got me thinking. One dimension Chris didn&amp;#8217;t cover was people: personalities, roles and permissions. Who can merge to which branch? Which developers work in private then push bulk updates? Git has won the version control system battle. The fight has moved into surrounding areas: branching, merging, reviewing, continuous integration, and the competition is bringing improvements in tooling and best practice.&lt;/p&gt;
&lt;p&gt;The final talk I attended was &lt;a href=&quot;https://twitter.com/davidcarboni&quot;&gt;David Carboni&amp;#8217;s&lt;/a&gt; session on creating a minimal Docker container to run a microservice written in &lt;a href=&quot;https://golang.org/&quot;&gt;Go&lt;/a&gt;. David started off by explaining why simplicity matters. I agree. I couldn&amp;#8217;t agree more. The rest of the session was, again, live coding, replaying a &lt;a href=&quot;https://github.com/davidcarboni/ddd&quot;&gt;demo&lt;/a&gt; which uses the techniques described in &lt;a href=&quot;https://blog.codeship.com/building-minimal-docker-containers-for-go-applications/&quot;&gt;a couple&lt;/a&gt; of &lt;a href=&quot;http://devcenter.wercker.com/docs/quickstarts/advanced/building-minimal-containers-with-go&quot;&gt;blog posts&lt;/a&gt; to whittle a Docker container down from a base size of ~700MB to a &lt;a href=&quot;https://docs.docker.com/develop/develop-images/baseimages/&quot;&gt;scratch&lt;/a&gt; size ~7MB.&lt;/p&gt;
&lt;p&gt;All in all, a great day. The split-level &lt;a href=&quot;https://swansea.techhub.com/&quot;&gt;venue&lt;/a&gt; suited the three track conference well. The speakers delivered terrific sessions which the audiences engaged with. I&amp;#8217;d like to thank the organisers, sponsors, speakers, and other attendees.&lt;/p&gt;</description>
<dc:date>2018-03-25</dc:date>
<guid>https://wordaligned.org/articles/ddd-wales-2018</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/ddd-wales-2018</link>
<category>Self</category>
<category>Swansea</category>
</item>

<item>
<title>Perec @IgniteSwansea #3</title>
<description>&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/docs/ignite/perec/me-at-ignite.jpg&quot; alt=&quot;Puzzle&quot;/&gt;&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;http://www.igniteswansea.co.uk/&quot;&gt;Ignite Swansea #3&lt;/a&gt; I spoke about Georges Perec&amp;#8217;s masterpiece, Life A User&amp;#8217;s Manual. &lt;/p&gt;
&lt;p&gt;Perec was &amp;#8212; and indeed still is &amp;#8212; a member of OuLiPo, a Parisian literary group interested in exploring the effects of applying mathematical patterns to text. His work seemed an appropriate subject for a presentation constrained to fit the ignite formula:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;20 slides &amp;times; 15 seconds = 5 minutes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;#8217;s material I&amp;#8217;ve spoken about &lt;a href=&quot;https://wordaligned.org/tags/perec&quot;&gt;before&lt;/a&gt; but &lt;a href=&quot;https://wordaligned.org/docs/ignite/perec/&quot;&gt;the slides are new&lt;/a&gt;. The talk was &lt;a href=&quot;https://youtu.be/-y7YOKIa6yQ&quot;&gt;recorded&lt;/a&gt;. I enjoyed attempting &lt;a href=&quot;https://en.wikipedia.org/wiki/Just_a_Minute&quot;&gt;just-a-minute&lt;/a&gt; &amp;times; 5, though on the night I could have sworn I was subject to a cruel powerpoint bug which sped up the playback.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/-y7YOKIa6yQ?rel=0&amp;amp;showinfo=0&quot; frameborder=&quot;0&quot; allow=&quot;autoplay; encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;OuLiPo fans might like to see if they can find the clinamen. The moustache is what happens in the fourth week of &lt;a href=&quot;https://uk.movember.com/&quot;&gt;Movember&lt;/a&gt;. My thanks to all &lt;a href=&quot;http://www.igniteswansea.co.uk/&quot;&gt;@IgniteSwansea&lt;/a&gt; and &lt;a href=&quot;https://www.cinemaco.co.uk/&quot;&gt;Cinema &amp;amp; Co&lt;/a&gt; for putting on such a great evening.&lt;/p&gt;</description>
<dc:date>2018-02-03</dc:date>
<guid>https://wordaligned.org/articles/perec-igniteswansea-3</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/perec-igniteswansea-3</link>
<category>Self</category>
<category>Perec</category>
<category>Talks</category>
<category>Oulipo</category>
</item>

<item>
<title>Bugwards Compatible</title>
<description>&lt;p&gt;&lt;a href=&quot;https://twitter.com/chrisoldwood&quot;&gt;Chris Oldwood&lt;/a&gt; recently tweeted about &amp;#8220;TFW you write some tests for a bit of legacy code before making a change and you unearth a bunch of bugs&amp;#8221;&lt;/p&gt;
&lt;div&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;TFW you write some tests for a bit of legacy code before making a change and you unearth a bunch of bugs.&lt;/p&gt;&amp;mdash; Chris Oldwood (@chrisoldwood) &lt;a href=&quot;https://twitter.com/chrisoldwood/status/959576034059448321?ref_src=twsrc%5Etfw&quot;&gt;February 2, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;

&lt;p&gt;He doesn&amp;#8217;t elaborate on what exactly &amp;#8220;that feeling&amp;#8221; is, but I&amp;#8217;ll bet it&amp;#8217;s not surprise. Writing tests for code almost invariably shakes something out &amp;#8212; perhaps some undocumented assumptions about the inputs; perhaps a failure to match the documented behaviour; perhaps an access violation which will crash the application.&lt;/p&gt;
&lt;p&gt;&amp;#8220;That feeling&amp;#8221; can include relief: the code is legacy code and evidently the bugs have gone unnoticed or at least unreported. Often, any such relief may be accompanied by a sense of wonder. The bugs may be so severe &amp;#8212; the code so broken &amp;#8212; that the maintainer questions how it &lt;strong&gt;ever&lt;/strong&gt; worked.&lt;/p&gt;
&lt;p&gt;&amp;#8220;That feeling&amp;#8221; may also be dismay, since the legacy code requires changing. If the existing behaviour is buggy but predictable it could well be that clients have adapted to this behaviour and wouldn&amp;#8217;t welcome a fix. In other words, the change will have to be both backwards and &lt;strong&gt;bugwards compatible&lt;/strong&gt;. Chris will have to tread carefully.&lt;/p&gt;
&lt;p&gt;Such delicate decisions are not limited to the code&amp;#8217;s runtime behaviour. It might seem that, once the code is under test, Chris can &lt;a href=&quot;http://wiki.c2.com/?RefactorMercilessly&quot;&gt;refactor mercilessly&lt;/a&gt; &amp;#8212; renaming variables, updating idioms, tidying layout. Again, tread carefully! Make sure the code &lt;strong&gt;is&lt;/strong&gt; under test. Be aware of the differences which reviewers must evaluate. Consider the wider context. Respect the original authors.&lt;/p&gt;</description>
<dc:date>2018-02-02</dc:date>
<guid>https://wordaligned.org/articles/bugwards-compatible</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/bugwards-compatible</link>
<category>Tests</category>
</item>

<item>
<title>Meetup? Turn Up!</title>
<description>&lt;p&gt;&lt;a href=&quot;https://www.meetup.com/Agile-Bath-Bristol/events/245853715/&quot;&gt;&lt;img alt=&quot;Sell out&quot; src=&quot;https://wordaligned.org/images/agile-bb-meetup.png&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Monday&amp;#8217;s &lt;a href=&quot;https://www.meetup.com/Agile-Bath-Bristol/events/245853715/&quot;&gt;Agile Bath &amp;amp; Bristol meetup&lt;/a&gt; was a sell out. All 50 available spaces were taken. I myself was lucky to get a place &amp;#8212; I was on the waiting list until a spot opened up at 3pm on the day. And I was the speaker!&lt;/p&gt;
&lt;p&gt;The reality turned out to be different: of the 50 who&amp;#8217;d claimed spaces, roughly one in four actually showed up.&lt;/p&gt;
&lt;p&gt;I know, it was &lt;a href=&quot;https://en.wikipedia.org/wiki/Blue_Monday_(date)&quot;&gt;Blue Monday&lt;/a&gt;. I know, there are bugs going round &amp;#8212; my daughter has been running a fever and didn&amp;#8217;t go in to college, and if I hadn&amp;#8217;t been presenting I myself would have cancelled to stay in with her. I know, your work day over-runs, you&amp;#8217;re hungry, something else comes up. I know, it&amp;#8217;s a free event, so it&amp;#8217;s not as though you&amp;#8217;ve &lt;em&gt;lost&lt;/em&gt; anything.&lt;/p&gt;
&lt;p&gt;Despite all these things a 25% turnout reflects badly on us all. It&amp;#8217;s unfair on the sponsors and organisers, especially when refreshments are offered. It&amp;#8217;s impolite to those who turn up at the advertised time, and must then sit waiting in case more people who&amp;#8217;ve said they&amp;#8217;re coming actually show up. It&amp;#8217;s tough on the speakers: planning a session for an audience of 50 is different to one you&amp;#8217;d plan for 12.&lt;/p&gt;
&lt;p&gt;I realise 25% is egregiously low, but &amp;#8212; in my experience &amp;#8212; 50% is far from unusual, and even considered acceptable. I think it&amp;#8217;s shabby. The one excuse noone has is forgetting the event is on &amp;#8212; Meetup etc. integrate with your calendar and issue repeated reminders to attend and requests to cancel if you cannot.&lt;/p&gt;
&lt;p&gt;So, my thanks to those who turned up and participated. I enjoyed it. Smaller numbers allowed for a more collaborative session. Ironically, topics discussed included punctuality, respect, commitment.&lt;/p&gt;
&lt;p&gt;Please, don&amp;#8217;t sign up to a meetup you don&amp;#8217;t plan to attend. If you decide to cancel, release your place so someone else can have it. Otherwise, arrive on time.&lt;/p&gt;</description>
<dc:date>2018-01-18</dc:date>
<guid>https://wordaligned.org/articles/meetup-turn-up</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/meetup-turn-up</link>
<category>Talks</category>
</item>

<item>
<title>Advent of Code 2017</title>
<description>&lt;p&gt;A big thanks to &lt;a href=&quot;http://was.tl&quot;&gt;Eric Wastl&lt;/a&gt; for another great &lt;a href=&quot;http://adventofcode.com/2017&quot;&gt;Advent of Code&lt;/a&gt;. Inspired by &lt;a href=&quot;https://github.com/norvig/pytudes/blob/master/ipynb/Advent%20of%20Code.ipynb&quot;&gt;Peter Norvig&lt;/a&gt;, I&amp;#8217;ve published &lt;a href=&quot;https://github.com/wordaligned/advent-of-code-2017/blob/master/advent-of-code-2017.ipynb&quot;&gt;my solutions&lt;/a&gt; as a Jupyter notebook.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/wordaligned/advent-of-code-2017/blob/master/advent-of-code-2017.ipynb&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/wordaligned/advent-of-code-2017/8e8344b4c5fc00827e42576059f36389dcfa453c/done.png&quot; alt=&quot;Done!&quot;/&gt;&lt;/a&gt;&lt;/p&gt;</description>
<dc:date>2018-01-12</dc:date>
<guid>https://wordaligned.org/articles/advent-of-code-2017</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/advent-of-code-2017</link>
<category>Puzzles</category>
<category>Python</category>
</item>

<item>
<title>Computer World</title>
<description>&lt;p&gt;&lt;a data-flickr-embed=&quot;true&quot;  href=&quot;https://www.flickr.com/photos/thomasguest/37406493811/in/dateposted-friend/&quot; title=&quot;The Hitchhiker&amp;#x27;s Guide to the Galaxy&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4371/37406493811_0d17fab6cf.jpg&quot; width=&quot;401&quot; height=&quot;500&quot; alt=&quot;The Hitchhiker&amp;#x27;s Guide to the Galaxy&quot;&gt;&lt;/a&gt;&lt;script async src=&quot;https://wordaligned.org//embedr.flickr.com/assets/client-code.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Douglas Adams&amp;#8217; &amp;#8220;Hitchhiker&amp;#8217;s Guide to the Galaxy&amp;#8221; tells the story of the two most powerful computers ever made. The first, Deep Thought, was designed to figure out the meaning of Life the Universe and Everything. After 7,500,000 years of processing it came up with the concise but unedifying Ultimate Answer of 42. It then undertook the task of designing its successor, a computer sophisticated enough to calculate the Ultimate Question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;&amp;#8230; A computer which can calculate the Question to the Ultimate Answer, a computer of such infinite and subtle complexity that organic life itself shall form part of its operational matrix &amp;#8230; Yes! I shall design this computer for you. And I shall name it also unto you. And it shall be called &amp;#8230; The Earth.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I first heard this it seemed ridiculous. Now, almost 40 years on, I&amp;#8217;ve realised it&amp;#8217;s true.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s no longer correct to think of computers as discrete units. Computers have the property that when you connect two of them you get another computer, and so on. The network &lt;strong&gt;is&lt;/strong&gt; the computer. The Apple in your hand, the Echo on your shelf, the chip in your &lt;a href=&quot;https://www.amazon.co.uk/Scepticism-Inc-Bo-Fowler/dp/009927468X&quot;&gt;shopping trolley&lt;/a&gt; &amp;#8212; all combine to form a global connected device. And as Adams predicted, we ourselves form part of the operating system, constantly feeding data back in.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wordaligned.org/images/planet-earth.jpg&quot; alt=&quot;Planet Earth&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Douglas Adams&amp;#8217; insight puts software development into perspective. True: we no longer print our product on silicon or ship it in boxes, and yes: we accept &lt;a href=&quot;http://wordaligned.org/articles/why-software-development-isnt-like-construction&quot;&gt;construction&lt;/a&gt; is not the right metaphor, but: nor is production. &lt;a href=&quot;http://swanseacon.co.uk/schedule/#session-27&quot;&gt;Professor Dave Snowden&lt;/a&gt; talks about entanglement &amp;#8212; think of a system growing like brambles in a thicket. He emphasises what&amp;#8217;s natural, evolutionary and human. Object oriented design lost out when it narrowed its focus. Remember, people are objects too. The world is our platform.&lt;/p&gt;</description>
<dc:date>2017-09-30</dc:date>
<guid>https://wordaligned.org/articles/computer-world</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/computer-world</link>
<category>Apple</category>
<category>Self</category>
<category>Design</category>
</item>

<item>
<title>SwanseaCon 2017</title>
<description>&lt;div&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Unit tests, lets get sceptical &lt;a href=&quot;https://twitter.com/thomasguest&quot;&gt;@thomasguest&lt;/a&gt; was a great end to the morning before lunch &lt;a href=&quot;https://t.co/EM4RPAs975&quot;&gt;pic.twitter.com/EM4RPAs975&lt;/a&gt;&lt;/p&gt;&amp;mdash; SwanseaCon (@SwanseaCon) &lt;a href=&quot;https://twitter.com/SwanseaCon/status/912361247760404480&quot;&gt;September 25, 2017&lt;/a&gt;&lt;/blockquote&gt;&lt;script async src=&quot;https://wordaligned.org//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;

&lt;p&gt;I&amp;#8217;m just back from a packed two days at &lt;a href=&quot;http://swanseacon.co.uk&quot;&gt;SwanseaCon&lt;/a&gt; and would like to thank the organisers, speakers and participants for making such a welcoming and diverse conference happen right where I live.&lt;/p&gt;
&lt;p&gt;For me, highlights included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Professor Dave Snowden&amp;#8217;s erudite and slide-free talk. It was a privilege to listen: although I may not quite have kept up, I will certainly follow up&lt;/li&gt;
&lt;li&gt;Irina Tsyganok&amp;#8217;s sensitive and inspirational presentation on pair-programming&lt;/li&gt;
&lt;li&gt;Lawrence Weetman&amp;#8217;s dishwashing demo &amp;#8212; with three on-stage helpers, no less&lt;/li&gt;
&lt;li&gt;Scott Fulton&amp;#8217;s honest report on some personal agile life lessons&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The venue wasn&amp;#8217;t too shabby either.&lt;/p&gt;
&lt;p&gt;&lt;a data-flickr-embed=&quot;true&quot;  href=&quot;https://www.flickr.com/photos/thomasguest/37286571132/in/photostream/&quot; title=&quot;The view from SwanseaCon&quot;&gt;&lt;img src=&quot;https://farm5.staticflickr.com/4462/37286571132_a5892fe22c_z.jpg&quot; width=&quot;640&quot; height=&quot;185&quot; alt=&quot;The view from SwanseaCon&quot;&gt;&lt;/a&gt;&lt;script async src=&quot;https://wordaligned.org//embedr.flickr.com/assets/client-code.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Having attended a fair few technical conferences, it felt refreshing and important to be part of something a little softer. Software development is about community, communication and culture, and SwanseaCon scored top marks on all three.&lt;/p&gt;
&lt;p&gt;So, again, thanks!&lt;/p&gt;</description>
<dc:date>2017-09-26</dc:date>
<guid>https://wordaligned.org/articles/swanseacon-2017</guid>
<author>tag@wordaligned.org (Thomas Guest)</author>
<link>https://wordaligned.org/articles/swanseacon-2017</link>
<category>Self</category>
<category>Talks</category>
<category>Swansea</category>
</item>

</channel>
</rss>
