<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://agiletechnicalexcellence.com/atom.xml" rel="self" type="application/atom+xml" /><link href="https://agiletechnicalexcellence.com/" rel="alternate" type="text/html" /><updated>2026-02-12T12:00:07-08:00</updated><id>https://agiletechnicalexcellence.com/atom.xml</id><title type="html">Agile Technical Excellence</title><subtitle>&quot;Continuous attention to technical excellence and good design enhances agility.&quot; &amp;mdash; &lt;a href=&quot;https://agilemanifesto.org&quot;&gt;Agile Manifesto&lt;/a&gt;</subtitle><author><name>{&quot;name&quot; =&gt; nil, &quot;picture&quot; =&gt; nil, &quot;email&quot; =&gt; nil, &quot;twitter&quot; =&gt; nil, &quot;links&quot; =&gt; [{&quot;title&quot; =&gt; nil, &quot;url&quot; =&gt; nil, &quot;icon&quot; =&gt; nil}]}</name></author><entry><title type="html">Close those bugs</title><link href="https://agiletechnicalexcellence.com/2026/02/12/close-the-bugs.html" rel="alternate" type="text/html" title="Close those bugs" /><published>2026-02-12T00:00:00-08:00</published><updated>2026-02-12T00:00:00-08:00</updated><id>https://agiletechnicalexcellence.com/2026/02/12/close-the-bugs</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2026/02/12/close-the-bugs.html"><![CDATA[<p>Do you have bugs that have been open for a long time and that are low priority? Cancel them.</p>

<p>Make the hard decision. Either we’re going to fix it and we do it now, or we aren’t and we cancel it.</p>

<p>Letting that bug sit in a backlog somewhere in the hopes that someday we’ll have the time and interest to fix it is just delusional. We’ll never have time for low priority distractions, and keeping things around “just in case” is exactly that.</p>

<p>Most companies have hundreds, and I’ve seen systems with thousands, of bugs just like this. They’re noise that distracts us. We need more focus and clarity, not more distractions.</p>

<p>Fix the bugs, or accept that we won’t, and close them.</p>

<p>Indecision is waste.</p>]]></content><author><name>Mike Bowler</name></author><category term="waste," /><category term="bugs" /><summary type="html"><![CDATA[Do you have bugs that have been open for a long time and that are low priority? Cancel them.]]></summary></entry><entry><title type="html">Code coverage revisited</title><link href="https://agiletechnicalexcellence.com/2026/02/04/code-coverage.html" rel="alternate" type="text/html" title="Code coverage revisited" /><published>2026-02-04T00:00:00-08:00</published><updated>2026-02-04T00:00:00-08:00</updated><id>https://agiletechnicalexcellence.com/2026/02/04/code-coverage</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2026/02/04/code-coverage.html"><![CDATA[<p>I’ve had several conversations recently with people arguing that mandated code coverage numbers are a positive thing. For example <em>“all code must have 90% code coverage”</em>.</p>

<p>My argument is that code coverage is a great negative metric, in that at low values, it tells you useful things and at high values it tells you nothing. So mandating high numbers is not giving us the benefit we think it is, and in fact is often causing people to game the numbers.</p>

<p>Fresh off that, I just made a change to one of my own source files that had 100% code coverage, and no tests broke.</p>

<p>No, this was not an attempt to prove anything. I was fully expecting one or more tests to break when I did this.</p>

<p>The fact that nothing broke is quite honestly shocking as I thought this code was quite well covered. It does prove my point though.</p>

<p>Code coverage is great feedback to developers; it’s an indicator of where they should put their attention. It should never be a target.</p>

<p>Update: And to the surprise of nobody who believes in good tests, as I add more tests around this particular code to cover the edge cases that were missing, I’ve just found a bug.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[I’ve had several conversations recently with people arguing that mandated code coverage numbers are a positive thing. For example “all code must have 90% code coverage”.]]></summary></entry><entry><title type="html">Jira API: Sprints</title><link href="https://agiletechnicalexcellence.com/2026/01/29/jira-api-sprints.html" rel="alternate" type="text/html" title="Jira API: Sprints" /><published>2026-01-29T00:00:00-08:00</published><updated>2026-01-29T00:00:00-08:00</updated><id>https://agiletechnicalexcellence.com/2026/01/29/jira-api-sprints</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2026/01/29/jira-api-sprints.html"><![CDATA[<p>If you’re extracting data from a scrum board then at some point, you’ll need to extract sprint data, which is stored in two different places, inconsistently.</p>

<p>Your first contact with details on sprints is likely to be in the <a href="/2024/04/09/jira-issue-history.html">issue history</a>. In here, there is information about what sprints this issue is in.</p>

<p>What’s that you say? <em>“How is it possible for an issue to be in multiple sprints?”</em> If it doesn’t finish in one sprint and that sprint ends, its still considered in that one forever. Then you can add it to another sprint and now it’s in two. Repeat as often as you like for a never-ending set of sprints for a single issue.</p>

<p>I’ve seen issues that have been in over a dozen sprints because they never get finished and just keep carrying over from one sprint to the next. Yes, that’s completely dysfunctional and should never happen. Yet, it happens all the time.</p>

<p>The entry in the history might look like this.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sprint"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"fieldtype"</span><span class="p">:</span><span class="w"> </span><span class="s2">"custom"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"fieldId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"customfield_10020"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="s2">"76, 79"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"fromString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sprint 12, Sprint 13"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"to"</span><span class="p">:</span><span class="w"> </span><span class="s2">"76, 80"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"toString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sprint 12, Sprint 14"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="field-id">Field ID</h3>

<p>The first thing you might notice is that there is a <code class="language-plaintext highlighter-rouge">fieldId</code>, which most history items don’t have. This is a reference to the custom field (in the same document) that contains more information about the sprints that are referenced. That custom field may or may not exist. If it does exist, it will list information about one or more sprints and the sprint that you care about may or not be in that list.</p>

<p>Got it so far?</p>

<p>If it does all exist, it will look something like this, and you’ll see that it contains some useful information about the sprint such as start date, end date (which isn’t what you think it is), and completed date.</p>

<p>You might think that <code class="language-plaintext highlighter-rouge">endDate</code> is when the sprint actually completed but no, that’s <code class="language-plaintext highlighter-rouge">completedDate</code>. <code class="language-plaintext highlighter-rouge">endDate</code> is the date that you anticipated closing the sprint at the time you started it. Why are there two? I assume it made sense at one point.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"customfield_10020"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w">
    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Scrum Sprint 10"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"closed"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"boardId"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
    </span><span class="nl">"goal"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
    </span><span class="nl">"startDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-03-12T01:36:46.600Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"endDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-03-23T17:32:42.000Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"completeDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-07-13T16:58:25.335Z"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">43</span><span class="p">,</span><span class="w">
    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Scrum Sprint 11"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"closed"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"boardId"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
    </span><span class="nl">"goal"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
    </span><span class="nl">"startDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-07-13T17:37:23.922Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"endDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-07-25T09:33:21.000Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"completeDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-01-22T16:02:01.486Z"</span><span class="w">
  </span><span class="p">},</span><span class="w">
</span></code></pre></div></div>

<h3 id="multiple-sprints-at-once">Multiple sprints at once</h3>

<p>The next thing you might notice is that unlike every other history type, the from and to values allow for multiple values.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sprint"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"fieldtype"</span><span class="p">:</span><span class="w"> </span><span class="s2">"custom"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"fieldId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"customfield_10020"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="s2">"76, 79"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"fromString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sprint 12, Sprint 13"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"to"</span><span class="p">:</span><span class="w"> </span><span class="s2">"76, 80"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"toString"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sprint 12, Sprint 14"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>You might think that this history entry is telling you which sprints this item has been added to or removed from and in a roundabout way, it does.</p>

<p>You can see in this sample that this issue was in sprints 76 and 77 and is now in sprints 76 and 80. It’s always talking about the current state so we can infer from this that…</p>

<ul>
  <li>It used to be in <code class="language-plaintext highlighter-rouge">76</code> and still is, so nothing changed</li>
  <li>It used to be in <code class="language-plaintext highlighter-rouge">79</code> and now it isn’t, so it’s been removed.</li>
  <li>It used to not be in <code class="language-plaintext highlighter-rouge">80</code> and now it is, so it’s been added.</li>
</ul>

<p>When you’re parsing those, it’s pretty easy to parse the <code class="language-plaintext highlighter-rouge">from</code> and <code class="language-plaintext highlighter-rouge">to</code> fields because they’re just numbers separated by commas.</p>

<p>The <code class="language-plaintext highlighter-rouge">fromString</code> and <code class="language-plaintext highlighter-rouge">toString</code> fields are harder though because it’s all concatenated text, and since commas are allowed in sprint names, you can end up with commas in the middle of a name.</p>

<p><em>“Surely they would escape the commas in the text so it can be easily parsed”</em>, you say! They do not.</p>

<p>If you want unambiguous names, you need to parse the id and use that to index into the data in the custom field above. Of course, we’ve already learned that the sprint you want may or may not be there.</p>

<p>If it isn’t there then we have a separate API to get sprints, which is great. Except that it may not be there either. We’ll get there in a moment.</p>

<h3 id="remove-before-add">Remove before add</h3>

<p>There’s a lovely gotcha where an issue can be removed from a sprint before it was ever added. This happens when the issue gets created within the sprint. Jira considers it to be in that sprint but there is no record of it being added in the history. Then if it’s removed from that sprint, you’ll see the removal all by itself.</p>

<h3 id="the-sprint-api">The sprint API</h3>

<p>This API will return all (mostly) of the sprints for the current board.
<code class="language-plaintext highlighter-rouge">/rest/agile/1.0/board/{boardId}/sprint</code></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"maxResults"</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span><span class="w">
  </span><span class="nl">"startAt"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
  </span><span class="nl">"total"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
  </span><span class="nl">"isLast"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"values"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
      </span><span class="nl">"self"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://improvingflow.atlassian.net/rest/agile/1.0/sprint/1"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"closed"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Scrum Sprint 1"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"startDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2022-03-26T16:04:09.679Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"endDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2022-04-09T16:04:00.000Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"completeDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2022-04-10T22:17:29.972Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"createdDate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2022-03-26T16:03:49.814Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"originBoardId"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
      </span><span class="nl">"goal"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>I’m sure you’ve picked up by now that even this API doesn’t return all the sprints, although it often returns more here than we have in the custom field.</p>

<p>In my testing so far, it seems that it does return any sprint that actually has an issue in it. Any sprint that’s empty will not be returned, which is annoying.</p>

<h3 id="conclusion">Conclusion</h3>

<p>So in conclusion, like all the other Jira API’s, there is useful data in here but its inconsistent, incomplete, and poorly thought out.</p>

<hr />

<p>Other articles about the Jira API:</p>
<ul>

  
    <li><a href="/2024/04/07/jira-api-intro-authentication.html">Intro and authentication</a></li>
  

  
    <li><a href="/2024/04/09/jira-issue-history.html">Issue history</a></li>
  

  
    <li><a href="/2024/04/12/jira-api-statuses.html">Statuses</a></li>
  

  
    <li><a href="/2024/04/17/jira-api-board-details.html">Board details</a></li>
  

  

</ul>

<p>See also the <a href="https://jirametrics.org">JiraMetrics</a> tool, which is the reason I’ve had to learn the idiosyncrasies of the Jira API. If you just want access to the data then let JiraMetrics do it for you.</p>]]></content><author><name>Mike Bowler</name></author><category term="jira_api" /><summary type="html"><![CDATA[If you’re extracting data from a scrum board then at some point, you’ll need to extract sprint data, which is stored in two different places, inconsistently.]]></summary></entry><entry><title type="html">Bad documentation</title><link href="https://agiletechnicalexcellence.com/2025/10/25/bad-documentation.html" rel="alternate" type="text/html" title="Bad documentation" /><published>2025-10-25T00:00:00-07:00</published><updated>2025-10-25T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/10/25/bad-documentation</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/10/25/bad-documentation.html"><![CDATA[<p>I grew up in a large city, and when I first moved out to a small town, one of the first differences I noticed was how everyone gives directions based on how things used to be.</p>

<p><em>“You’ll turn left just past Flieler’s”</em>, where for the last twenty years it’s been called Sunoco, or <em>“turn just past where the Johnson’s used to live”</em>.</p>

<p>If you live in the community, it still works because everyone knows how it used to be. The problem is when you’re new to the community or if you’re just passing through. Then these descriptions are just meaningless or worse time-wasting.</p>

<p>I’ve been reminded of this over the last few weeks as I attempt to learn Google Ads and all the documentation is very precise in telling me where menu options used to be, and how things used to work, and is absolutely useless at telling me what I need to do today.</p>

<p>It’s all too easy when writing documentation to treat it as <em>one and done</em> work. I wrote it and won’t have to change it. Yet, incorrect documentation is much worse than no documentation. If I’m driving down the street looking for a sign that says <em>Flieler</em>, I’m going to drive right past the <em>Sunoco</em> sign and not even know it.</p>

<p>So when we write documentation for our products, we have to also consider the cost of maintaining that documentation. It will get out of date and if we don’t keep it in sync, we are wasting our clients time and money.</p>

<p>I did finally figure out how to get my ads campaign running, just as I finally did figure out how to get around that small town. It just took far longer than it should have.</p>

<p>If we’re going to call ourselves customer focused, we need to consider how much of our customers time we’re wasting.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[I grew up in a large city, and when I first moved out to a small town, one of the first differences I noticed was how everyone gives directions based on how things used to be.]]></summary></entry><entry><title type="html">Why don’t we collaborate more?</title><link href="https://agiletechnicalexcellence.com/2025/10/17/why-dont-we-collaborate-more.html" rel="alternate" type="text/html" title="Why don’t we collaborate more?" /><published>2025-10-17T00:00:00-07:00</published><updated>2025-10-17T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/10/17/why-dont-we-collaborate-more</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/10/17/why-dont-we-collaborate-more.html"><![CDATA[<p>In an office environment, it’s always been obvious when there’s a major production problem. You’ll see everyone standing around a single desk; everyone working together on the same problem at the same time. If there’s a blocker to what they’re doing, one or more people in the group will immediately do something to remove that obstacle, to ensure that the main work continues uninterrupted.</p>

<p>Everyone is hyper-focused on completing the single task in front of them and all distractions are ignored or removed.</p>

<p>Then when the emergency is over, we all drift away, back to our regular desks to work in isolation again. Typically scattering our focus across many different things, and now significantly less effective than we had been. The pressure is off so we revert to our familiar routine.</p>

<p>The above tells us that we all know how to work in a highly collaborative environment. We do know how to work together and we do it instinctively when the stakes are high, and it’s really important to get the work done quickly and correctly.</p>

<p class="key_point">We already know how to work in a really effective way, even though we rarely do.</p>

<p>So why don’t we work that way all the time?</p>

<p>First, I would be remiss if I didn’t acknowledge that some teams do work this way every day, and they get amazing results. They’re just not the majority. See teams that do <a href="/2023/04/22/ensemble-programming.html">ensemble work</a> or <a href="/2021/06/19/pair-programming.html">pairing</a>.</p>

<p>So why don’t we?</p>

<p><strong>It’s not rewarded:</strong> We’re not rewarded for focusing on a single thing until it’s finished. We’re rewarded instead for starting things. We’re rewarded for juggling many things at the same time. We’re <a href="https://improvingflow.com/2023/05/20/busyness.html">rewarded for being busy</a>, rather than effective. Worse, we’re often rewarded for putting out fires but not for preventing them.</p>

<p><strong>It’s comfortable:</strong> Working by ourselves has no social pressure. We’re not concerned about others judging how we work or what we do. As long as we look busy, we’re left alone. It’s a simple routine and routines make us feel calmer and safer.</p>

<p><strong>It’s the standard:</strong> Nobody will ask us to justify why we choose to work by ourselves; that’s the default. They might ask us to justify why we would work any other way, even when the default approach is less effective.</p>

<p>We already know how to work better. Perhaps it’s time to start doing that.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[In an office environment, it’s always been obvious when there’s a major production problem. You’ll see everyone standing around a single desk; everyone working together on the same problem at the same time. If there’s a blocker to what they’re doing, one or more people in the group will immediately do something to remove that obstacle, to ensure that the main work continues uninterrupted.]]></summary></entry><entry><title type="html">The extreme in eXtreme Programming (XP)</title><link href="https://agiletechnicalexcellence.com/2025/08/31/the-extreme-in-xp.html" rel="alternate" type="text/html" title="The extreme in eXtreme Programming (XP)" /><published>2025-08-31T00:00:00-07:00</published><updated>2025-08-31T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/08/31/the-extreme-in-xp</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/08/31/the-extreme-in-xp.html"><![CDATA[<p>My first exposure to anything Agile was with eXtreme Programming (XP) back in 1999. While it had many process steps similar to what Scrum and Kanban offer today, the thing that really differentiated XP was it’s focus on technical practices. It’s those technical practices that we are usually referring to when we talk about XP today.</p>

<p>Yet, the practices themselves weren’t intended to be end-states. They were merely the best practices that we knew about at the time, and today we know about a number that are even better. Continuous delivery and <a href="/2023/04/22/ensemble-programming.html">ensemble/mob programming</a> weren’t even a thing at that time and yet they’re both completely in line with what XP advocates.</p>

<p>The really important thing about XP is really in understanding where the <em>“extreme”</em> in the name comes from. The basic idea is that if we believe that a practice or approach is good then instead of doing it a little bit, let’s turn it up to extreme levels and do it all the time.</p>

<ul>
  <li>If we think that testing is a good thing then let’s do it all the time, by writing the tests first. (<a href="/2024/01/11/tdd-as-design.html">TDD</a>, BDD)</li>
  <li>If we think that talking to the customer is a good thing then let’s get them on the team so we can talk to them all the time. (Onsite customer)</li>
  <li>If we think that keeping the code integrated is a good thing then let’s do it constantly. (<a href="/2024/06/20/ci-is-not-a-server.html">continuous integration</a>)</li>
</ul>

<p>When we introduce some of these practices today, we often get push-back on the specific practices, while missing the intention behind it. If you don’t like the specific practice that we’re doing, then find a different way to turn the good up to extreme levels.</p>

<p>XP is <em>“extreme”</em> because it doesn’t settle for <em>“good enough”</em>. That seems like a positive to me.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[My first exposure to anything Agile was with eXtreme Programming (XP) back in 1999. While it had many process steps similar to what Scrum and Kanban offer today, the thing that really differentiated XP was it’s focus on technical practices. It’s those technical practices that we are usually referring to when we talk about XP today.]]></summary></entry><entry><title type="html">What work to select for an ensemble</title><link href="https://agiletechnicalexcellence.com/2025/08/25/work-for-an-ensemble.html" rel="alternate" type="text/html" title="What work to select for an ensemble" /><published>2025-08-25T00:00:00-07:00</published><updated>2025-08-25T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/08/25/work-for-an-ensemble</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/08/25/work-for-an-ensemble.html"><![CDATA[<p>When I facilitate an <a href="/2023/04/22/ensemble-programming.html">ensemble session</a> (also called Mob Programming) with a team, I’m often asked what work we should pick to work on. The answer is really whatever we would have done this week anyway.</p>

<p>Too many teams try to pick the “perfect” piece of work for the ensemble, and when they do, they inevitably pick something that nobody really cares about.</p>

<p>We’re not doing katas or fake examples. We’re not picking up that item that you’ve wanted to do for the last year but never got around to.</p>

<p>We’re picking something important enough that we would have done it this week anyway.</p>

<p>That could be implementing a new feature request, or fixing a bug, or performance tuning. The actual type of work doesn’t matter. What does matter is that it’s something that we care about finishing.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[When I facilitate an ensemble session (also called Mob Programming) with a team, I’m often asked what work we should pick to work on. The answer is really whatever we would have done this week anyway.]]></summary></entry><entry><title type="html">The big rewrite</title><link href="https://agiletechnicalexcellence.com/2025/06/25/the-big-rewrite.html" rel="alternate" type="text/html" title="The big rewrite" /><published>2025-06-25T00:00:00-07:00</published><updated>2025-06-25T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/06/25/the-big-rewrite</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/06/25/the-big-rewrite.html"><![CDATA[<p>I remember once having two back-to-back clients who had just rewritten significant systems in their environment. I asked why they’d chosen to rewrite the system from scratch rather than just fixing them as they were.</p>

<p>At the first, they said <em>“The old system was written in Java and Java is unusable so we rewrote it in C# and now it’s great.”</em></p>

<p>At the second, they said <em>“The old system was written in C# and C# is unusable so we rewrote it in Java and now it’s great.”</em></p>

<p>These statements can’t both be true at the same time. In fact, both Java and C# are reasonable languages and either one would have done the job. It wasn’t the language/platform that was at fault, no matter how much these companies told themselves that.</p>

<p>Does this mean that the platform is never the problem? No, there are legitimate cases, usually when we’ve built on top of proprietary vendor systems, when ongoing licensing and/or support costs from that vendor make it untenable to continue funding that code base. These cases are exceptionally rare however - I’ve seen two in my entire career.</p>

<p>What’s significantly more common is that we ignored quality in the product for so long that eventually we gave up and decided to rewrite it from scratch. We often call this <em>technical bankruptcy</em> - that point where it’s so painful to work with the existing system that we give up.</p>

<p>You might be thinking that we would never consciously choose to ignore quality and usually we don’t. It’s all those unconscious points where we prioritize something else over quality, that gets us in trouble.</p>

<ul>
  <li>Any time we defer fixing bugs in favour of shipping new features, we’re ignoring quality</li>
  <li>Any time we defer fixing technical debt, we’re ignoring quality</li>
  <li>Any time we ignore feedback from customers about usability issues, we’ve ignored quality</li>
  <li>Any time we have many items in progress (WIP) rather than staying focused on a few, we’re ignoring quality</li>
  <li>Any time we have people going off and working by themselves, rather than actively collaborating, we’re ignoring quality</li>
</ul>

<p>I’ve written about quality before, and today I want to stay more focused on the notion of a big rewrite.</p>

<p>I’ve seen cases where people are starting to talk about rewriting a system before the first system is even in production. They’ve made such a mess of the first product that they realize already that it’s not usable over the long haul and needs to be replaced.</p>

<p>Then what happens is that we rewrite the product on a new platform, and at the beginning, the new code is really easy to work with and easy to extend. However, by the time this new system is ready for production, it’s often in just as bad shape as the first system.</p>

<p>How could this possibly be? How could the new system be as bad as the one we’re replacing?</p>

<p>The simple answer is because all we changed was the code itself. We didn’t change our practices around quality. We didn’t change the way we write code. We didn’t do anything different on this second attempt than we had done on the first attempt. We might have a different design approach and a different language but all the things that led to poor quality code are still in place.</p>

<p>Since we never tried to improve the original code in place, we never developed the practices that lead to high quality code. We just did the same thing all over again, and got the same result.</p>

<p>Like the quote that is often attributed to Einstein: <em>“The definition of insanity is doing the same thing over and over again and expecting different results”</em></p>

<p>If we want better results, we need to build the skills that will lead to those better results. Throwing away a large code base and replacing it, does not teach the skills for building high quality code.</p>

<p>To develop those skills that will lead to better quality, we need to actively improve the code we have. The next time someone proposes throwing some code away and rewriting it, we need to say no. Improve it gradually instead.</p>

<p>We also need to be constantly practicing the skills of improving code. We should be refactoring constantly to improve that code, not just touching it when there is a new feature to add.</p>

<p>The <a href="/2025/06/22/scouting-rule.html">Scouting Rule</a> says that we should always leave the campsite cleaner than when we arrived. Applied to software, that means always leaving the code a little bit better. Did you see some duplication? Remove it. Did you see poor variable naming? Fix it.</p>

<p>If we do this regularly then we’ll never get to the point of a rewrite. I’ve seen ten year old code bases that were a pleasure to work with, and six month old code bases that were a disaster. Consider which one you want.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[I remember once having two back-to-back clients who had just rewritten significant systems in their environment. I asked why they’d chosen to rewrite the system from scratch rather than just fixing them as they were.]]></summary></entry><entry><title type="html">Scouting rule</title><link href="https://agiletechnicalexcellence.com/2025/06/22/scouting-rule.html" rel="alternate" type="text/html" title="Scouting rule" /><published>2025-06-22T00:00:00-07:00</published><updated>2025-06-22T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/06/22/scouting-rule</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/06/22/scouting-rule.html"><![CDATA[<p>We often talk about the scouting rule of <em>“always leave the campsite cleaner than you found it”</em>, or in a software context <em>“always leave the code a little bit better than you found it”</em>.</p>

<p>If you see duplication in the code, then remove that before you leave the method. If you see poor variable names then fix those before you leave.</p>

<p>What we don’t talk about as much is how a culture of branching and Pull Requests (PR’s) actively discourages making small changes for that purpose. If I want to rename a method to make it clearer and know that making that little change is going to require real effort to go through a review process and manual merges, then I’m more likely to decide to just live with the original name, even if it is is poor.</p>

<p>Whereas if I can make that little refactoring and directly check it into mainline then it’s a very low effort change that contributes to the quality of the product. It’s become easy to do the right thing.</p>

<p>How many things do we have like this, that actively discourage us from doing the right thing?</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[We often talk about the scouting rule of “always leave the campsite cleaner than you found it”, or in a software context “always leave the code a little bit better than you found it”.]]></summary></entry><entry><title type="html">Quality</title><link href="https://agiletechnicalexcellence.com/2025/06/17/quality.html" rel="alternate" type="text/html" title="Quality" /><published>2025-06-17T00:00:00-07:00</published><updated>2025-06-17T00:00:00-07:00</updated><id>https://agiletechnicalexcellence.com/2025/06/17/quality</id><content type="html" xml:base="https://agiletechnicalexcellence.com/2025/06/17/quality.html"><![CDATA[<p>The theme for this week seems to be quality so let’s look at some different aspects of that.</p>

<h1 id="setting-the-goal">Setting the goal</h1>

<p>First of all, let’s consider what is really the goal. We often find ourselves talking about <strong>testing</strong> rather than <strong>quality</strong> and that leads us down the wrong path. Testing is not the goal and never should be.</p>

<p>Why would we focus on the wrong thing? It has to do with a psychological phenomenon called <em>attribute substitution</em>, where in an attempt to reduce the mental effort required, we replace a complex decision with a simpler decision and aren’t even aware that we’ve done so.</p>

<p>Quality is a difficult thing to get our heads around so we simplify the problem to <em>testing</em> and focus on that. Yet, most of what we call testing happens too late in the process to actually improve the quality. See this article on <a href="https://improvingflow.com/2024/01/09/quality-vs-testing.html">quality vs testing</a> for more.</p>

<p>The best we can hope for with typical testing is that we’ll identify when we need to go back and rework the product. If we want the testing to actually improve the quality then it needs to happen during creation of the product, not after the fact. This is the essence of techniques like <a href="/2024/01/11/tdd-as-design.html">test driven development</a> where the <em>testing</em> happens before the code is even written.</p>

<p>What we normally call <em>testing</em> is an inspection step, not a quality one, and as Deming says: <em>“Inspection does not improve the quality, nor guarantee quality. Inspection is too late. The quality, good or bad, is already in the product.”</em></p>

<p>If we want to improve quality then we need to focus on quality. The moment we start talking about testing, we’ve taken our eyes off the ball.</p>

<h1 id="bugs">Bugs</h1>

<p>If you ask the typical team what a bug is, you won’t be able to get a clear answer. We talk about bugs all the time and yet we all seem to have different ideas of what they are.</p>

<p>I have a clear <a href="/2023/04/21/bugs.html">three point definition for a bug</a>. I don’t insist that anyone uses my definition, but I find that many teams do, because they don’t have their own.</p>

<p>It’s a defect if:</p>
<ol>
  <li>The team knew what it was supposed to do</li>
  <li>And it doesn’t do that thing</li>
  <li>And the team said they were done</li>
</ol>

<p>All three are important. If someone insists that it’s broken because it doesn’t do something that we never talked about, it’s not a bug. If we didn’t understand what it was supposed to do, then it’s not a bug when it doesn’t do that thing.</p>

<p>Why it’s important to have a clear definition of that bug, is that every bug is a place where we said we’d finished the work and we didn’t.</p>

<p>Having it so clearly defined will change the whole conversation around prioritizing the fixing of bugs. A bug is something that we’d already prioritized, and already decided to work on but stopped before we were finished. If we’d finished it, there would be no bug.</p>

<p>So now if someone asks if we want to talk about prioritize bugs, it’s really a matter of <em>“do we want to finish this thing that we’d already decided was important enough to have started first, or do we want to do this new feature that was clearly less important because we’re only looking at it now?”</em></p>

<p>Yes, I realize that priorities change and the newer thing might really be more important, but most of the time that isn’t true.</p>

<p>When you realize that those bugs really are more important than new features, you’ve just taken the first step towards a <a href="/2024/08/15/zero-bugs.html">zero defect policy</a></p>

<p>You may now be thinking <em>“What if we don’t want to fix it?”</em> Then close the bug. Why are you leaving it in the ticketing system if it isn’t important enough to finish? Yes, it really is that simple.</p>

<p>Have you ever sat in a bug prioritization meeting? You’ll never get that time back and that meeting was 100% waste. Either fix the bugs or decide that you won’t, and cancel them. Trying to prioritize one against the others is a waste of everyone’s time.</p>

<p>That last point in the bug definition of <em>“the team said they were done”</em> has one more interesting implication. We don’t ever open a bug if the story is still showing as open, which means that we can never have two tickets open for the same thing at the same time.</p>

<h1 id="pull-requests">Pull requests</h1>

<p>At many companies, Pull Requests (PR’s) are treated as if they were a quality step, and yet in the most common cases, they aren’t. PR’s are an inspection step that happens after some portion of the code is finished.</p>

<p>Can a PR be used to get feedback in the moment, to help with quality as the code is being built? Absolutely yes. Unfortunately, they’re almost never used in that way — instead they’re used for inspection and gate-keeping.</p>

<p>The common case for PR’s is that we create one and send off an asynchronous request for feedback. Then we move on to some other work because we know it will be at least hours, if not days, before we get any feedback. If we were actually using the PR for the purposes of improving quality, we’d want immediate synchronous feedback.</p>

<p>There are certainly people who use PR’s this way. Where they create the PR as a way to see all the changes in one place and then immediately review them with someone else so that they can get feedback that will then inform quality.</p>

<p>The asynchronous model, on the other hand, is a handoff. We’ve said that we’re finished and want someone else to approve it. This is now an inspection step.</p>]]></content><author><name>Mike Bowler</name></author><summary type="html"><![CDATA[The theme for this week seems to be quality so let’s look at some different aspects of that.]]></summary></entry></feed>