James' Digital Gardenhttps://idiosapps.github.io/Recent content on James' Digital GardenHugo -- gohugo.ioen-gbJames Clark ©Fri, 21 Jul 2023 00:00:00 +0000RTX ON - it's execution timeevergreenhttps://idiosapps.github.io/garden/rtx-asdf/Fri, 21 Jul 2023 00:00:00 +0000https://idiosapps.github.io/garden/rtx-asdf/<p>I&rsquo;ve been using previously used <code>sdkman</code> for a few years to manage my JDK &amp; Scala installations. It supports a good amount of tooling, but it&rsquo;s very JVM focused. You may know <code>nvm</code> or <code>n</code> for managing and switching Node versions, or Volta/fnm for more general Javascript tooling management.</p> <p>Recently I&rsquo;ve been getting into Elixir &amp; Phoenix LiveView, and I came across a similar tool called <code>asdf</code>. Actually though, thanks to its &ldquo;plugins&rdquo; system and almost 700 plugins, you can install so many different tools. Sounds good to me - I have projects using Python, Elixir, Java/Scala, Node, Terraform, AWS CLI, etc.. With one application, I can have tooling defined locally (per-project) so it&rsquo;s all independent and easy to get the tooling right.</p> <p>This was working great for Elixir &amp; Erlang, but the ergonomics felt a little off. In order to list versions, you have to first download the plugin. And due to its &ldquo;shim&rdquo; mechanism, it adds about 100ms delay to each command that passes through the asdf executable (my ELI5 understanding).</p> <p>I then came across <a href="https://github.com/jdxcode/rtx">rtx</a>, a Rust tool inspired by <code>asdf</code> that takes a different approach. Here&rsquo;s some features I&rsquo;m really liking:</p> <ul> <li>Speed - <code>rtx</code> points to tooling versions via the PATH, and updates the PATH when necessary - this keeps interactions fast (it doesn&rsquo;t go through a &ldquo;shim&rdquo; unless it has to, unlike <code>asdf</code>) <ul> <li>Also, apparently <code>python</code> called via <code>rtx</code> is much more response than <code>python</code> with <code>pyenv</code></li> </ul> </li> <li>Installs - If you have a bunch of microservices on different Node/Java versions, <code>rtx</code> reloads the relevant version via the PATH when you switch project in your terminal. You don&rsquo;t need to run commands like <code>nvm use node 16</code> - it&rsquo;s automatic. Global installs are supported too.</li> <li>Plugins - <code>asdf</code>&rsquo;s amazing plugins are here still, but you don&rsquo;t have to explicltly install them first! <ul> <li><code>rtx</code> does have it&rsquo;s own plugins, but &lt;10 at the time of writing. Re-using asdf&rsquo;s plugins is smart</li> </ul> </li> <li>Documentation - the CLI &amp; interactions are friendly, and setup is (almost) frictionless</li> <li>Configuration - <code>.rtx.toml</code> and the CLI interactions with it are easy to use, and really powerful - see below!</li> </ul> <h1 id="show-me-the-config">Show me the config</h1> <p>For our documentation website, I suggested we move from install nvm/node/yarn/sbt to just this configuration file (.rtx.toml):</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#111">[</span><span style="color:#75af00">tools</span><span style="color:#111">]</span> </span></span><span style="display:flex;"><span><span style="color:#75af00">node</span> <span style="color:#111">=</span> <span style="color:#d88200">&#34;16&#34;</span> </span></span><span style="display:flex;"><span><span style="color:#75af00">yarn</span> <span style="color:#111">=</span> <span style="color:#d88200">&#34;1.22.19&#34;</span> </span></span><span style="display:flex;"><span><span style="color:#75af00">sbt</span> <span style="color:#111">=</span> <span style="color:#d88200">&#34;1.9.2&#34;</span> </span></span></code></pre></div><p>and this one-click script (in IntelliJ) to go from 0 to READY:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl https://rtx.pub/install.sh <span style="color:#111">|</span> sh <span style="color:#75715e"># install rtx </span> </span></span><span style="display:flex;"><span><span style="color:#111">echo</span> <span style="color:#d88200">&#39;eval &#34;$(~/bin/rtx activate zsh)&#34;&#39;</span> &gt;&gt; ~/.zshrc <span style="color:#75715e"># hook rtx into shell</span> </span></span><span style="display:flex;"><span>rtx install <span style="color:#75715e"># install tooling</span> </span></span><span style="display:flex;"><span>yarn <span style="color:#75715e"># install deps </span> </span></span><span style="display:flex;"><span>yarn run <span style="color:#75715e"># launch dev website</span> </span></span></code></pre></div><p>That&rsquo;s a nice developer experience. I&rsquo;m happy to know someone can clone a repo, click a button, grab a drink, and come back to a website!</p> <hr> <h1 id="ci---does-it-add-value-here">CI - does it add value here?</h1> <p>So, <code>rtx</code> is pretty cool for local development - but what about CI?</p> <p>For our main project, we use a JDK, Scala, and Mill. There&rsquo;s a few Actions for setup (setup-java, coursier-setup, mill-setup, etc.) - but they usually want a version typing out. This could lead to drift between development and CI, and introduce a bit of toil when somebody finally notices or remembers.</p> <p><a href="https://github.com/actions/setup-java">setup-java</a></p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">steps</span><span style="color:#111">:</span> </span></span><span style="display:flex;"><span>- <span style="color:#f92672">uses</span><span style="color:#111">:</span> <span style="color:#ae81ff">actions/checkout@v3</span> </span></span><span style="display:flex;"><span>- <span style="color:#f92672">uses</span><span style="color:#111">:</span> <span style="color:#ae81ff">actions/setup-java@v3</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span><span style="color:#111">:</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">distribution</span><span style="color:#111">:</span> <span style="color:#d88200">&#39;openjdk&#39;</span> <span style="color:#75715e"># See &#39;Supported distributions&#39; for available options</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">java-version</span><span style="color:#111">:</span> <span style="color:#d88200">&#39;17&#39;</span> </span></span></code></pre></div><p>But it&rsquo;d be nice if we could set up more, with less lines right? See <a href="https://github.com/coursier/setup-action">Coursier&rsquo;s setup-action</a>:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">steps</span><span style="color:#111">:</span> </span></span><span style="display:flex;"><span>- <span style="color:#f92672">uses</span><span style="color:#111">:</span> <span style="color:#ae81ff">actions/checkout@v3</span> </span></span><span style="display:flex;"><span>- <span style="color:#f92672">uses</span><span style="color:#111">:</span> <span style="color:#ae81ff">coursier/setup-action@v1</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span><span style="color:#111">:</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">jvm</span><span style="color:#111">:</span> <span style="color:#ae81ff">adopt:17</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">apps</span><span style="color:#111">:</span> <span style="color:#ae81ff">sbtn bloop ammonite</span> </span></span></code></pre></div><p>Ah, so it seems the versions can&rsquo;t be specified (other than for the jvm).</p> <p>With the <a href="https://github.com/marketplace/actions/rtx-action">rtx Action</a>, our <code>.rtx.toml</code> files can be used - which is accurate, and brief:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">steps</span><span style="color:#111">:</span> </span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span><span style="color:#111">:</span> <span style="color:#ae81ff">actions/checkout@v3</span> </span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span><span style="color:#111">:</span> <span style="color:#ae81ff">jdxcode/rtx-action@v1</span> </span></span></code></pre></div><p>I ran <a href="https://github.com/IdiosApps/havvk/blob/master/.github/workflows/rtx-action-check.yml">this</a> as a workflow dispatch. The first run took 3m36s (it takes a while locally to install Elixir &amp; Erlang too), but <a href="https://github.com/IdiosApps/havvk/actions/runs/5627022179/job/15248908167">the second run (started soon after) took only 20 seconds</a>! GitHub Actions seems to have nicely cached the worker for my <code>master</code> branch (270MB total). Apparently there&rsquo;s a <a href="https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows">10GB total limit</a> - though I can&rsquo;t see how long it lasts. That&rsquo;s cool though - our action <em>just works</em> in CI, is super clean, and in Public GitHub they help us keep things fast with zero-configuration caches!</p> <h1 id="-but-my-versions-for-different-tools-are-scattered-around-my-source">&hellip; but my versions for different tools are scattered around my source!</h1> <p>Let&rsquo;s say you use three tools, which are specified in different files:</p> <ul> <li>openjdk-17 - in a Dockerfile</li> <li>Scala 2.13.xy - in a Dependencies.sc file</li> <li>mill - in .mill-version</li> </ul> <p>Fortunately, <code>rtx</code> uses the <code>tera</code> templating engine so we can grab these dynamically. These commands are kinda grim (I couldn&rsquo;t use &quot; or &lsquo;; I found <code>cut</code> to be a good command, thanks ChatGPT), but are probably &ldquo;good enough&rdquo; to not need updating. The sources they read won&rsquo;t be changing spacing much:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#111">[</span><span style="color:#75af00">tools</span><span style="color:#111">]</span> </span></span><span style="display:flex;"><span><span style="color:#75af00">mill</span> <span style="color:#111">=</span> <span style="color:#111">{</span> <span style="color:#75af00">version</span> <span style="color:#111">=</span> <span style="color:#d88200">&#34;{{exec(command=&#39;echo $(cat .mill-version)&#39;)}}&#34;</span> <span style="color:#111">}</span> </span></span><span style="display:flex;"><span><span style="color:#75af00">java</span> <span style="color:#111">=</span> <span style="color:#111">{</span> <span style="color:#75af00">version</span> <span style="color:#111">=</span> <span style="color:#d88200">&#34;{{exec(command=&#39;grep -m 1 openjdk docker/Dockerfile | cut -c 12- | tr : -&#39;)}}&#34;</span> <span style="color:#111">}</span> </span></span><span style="display:flex;"><span><span style="color:#75af00">scala</span> <span style="color:#111">=</span> <span style="color:#111">{</span> <span style="color:#75af00">version</span> <span style="color:#111">=</span> <span style="color:#d88200">&#34;{{exec(command=&#39;grep -m 1 2.13 dependencies/Dependencies.sc | cut -c 33-39&#39;)}}&#34;</span> <span style="color:#111">}</span> </span></span></code></pre></div><p>The secret sauce here is:</p> <ul> <li><code>grep -m 1 &lt;phrase&gt;</code> returns the first line that matches</li> <li><code>cut 12-</code> gives from the 12th char onwards, <code>cut 33-39</code> does what you&rsquo;d think</li> </ul> <p>Yep, it does look dumb, but:</p> <ul> <li>For Java we just pin to a major version; if we stick to the same vendor, there&rsquo;ll be no issue</li> <li>For Mill, it&rsquo;s just a plain cat. Not too bad :)</li> <li>For Scala, until there&rsquo;s a migration to Scala 3 then we&rsquo;ll just see 2.13.11 -&gt; 2.13.xy</li> </ul> <h1 id="additions--alternatives">Additions &amp; Alternatives</h1> <ul> <li>For <code>asdf</code>, there is <a href="https://github.com/mhanberg/lazyasdf">lazyasdf</a> - it&rsquo;s a TUI for <code>asdf</code> (like how k9s is a TUI for k8s)</li> <li>An alternative to <code>asdf</code>/<code>rtx</code> is <a href="https://github.com/aquaproj/aqua">aqua</a>, written in Go. The local configuration (like .rtx.toml) is aqua.yaml, and it supports global installs too <ul> <li>The <a href="https://github.com/aquaproj/aqua-registry/tree/main/pkgs">Aqua registry</a> has gives 1200+ results - but I see nothing for Elixir, Java/JDK/JVM, and the only node result is &ldquo;kubectl-node-shell&rdquo;</li> <li>The fzf-esque interactive search for packages with <code>aqua g</code> is nice, even if I can&rsquo;t find what I want</li> </ul> </li> </ul> <h1 id="whats-bad-about-rtx-security">What&rsquo;s bad about rtx (security)?</h1> <p>There&rsquo;s a good <a href="https://github.com/jdxcode/rtx/blob/main/SECURITY.md">security write-up on the rtx repo</a>.</p> <p>As you can see, with Tera templating you can run some arbitrary commands (firstly in PRs/GitHub Actions, then locally if a change is merged). There is a command <a href="https://github.com/jdxcode/rtx#rtx-trust-options-config_file">rtx trust</a>, meaning &ldquo;rtx will parse the file with potentially dangerous features enabled&rdquo; - I guess that&rsquo;d be useful if you clone some OSS repo and don&rsquo;t want the tooling. There&rsquo;s also configuration via environment variables, e.g. <a href="https://github.com/jdxcode/rtx#rtx_trusted_config_paths">RTX_TRUSTED_CONFIG_PATHS</a> that may be useful.</p> <p>Even tools like <a href="https://github.com/IdiosApps/dependabot-gradlewrapper-test#what-are-some-problems-with-the-gradle-wrapper">gradlew have risks</a> though, and that&rsquo;s massively popular.</p> <p>To answer &ldquo;can/should I use rtx?&rdquo;, at this point you need to do your own homework ;)</p> <h1 id="conclusion">Conclusion</h1> <p>I encourage you to give <a href="https://github.com/jdxcode/rtx">rtx</a> a try. It&rsquo;ll be my tooling manager of choice for personal projects now, and I&rsquo;m encourgaging its use at work. So far I&rsquo;m using it in a backend JVM repo, a yarn/node documentation repo, and an Elixir/Erlang repo.</p>Career - Disney Streaming - What I Doneseedinghttps://idiosapps.github.io/garden/disney-what-i-done/Tue, 06 Jun 2023 00:00:00 +0000https://idiosapps.github.io/garden/disney-what-i-done/<p>Outside of usual sprint project work (Scala Functional Programming microservices), I enjoyed dabbling with different bits of tech and ideas (mostly tech/way of working related) in my time at Disney Streaming so far!</p> <h1 id="migrating-our-team-to-kubernetes">Migrating our team to Kubernetes</h1> <p>We were running our applications on a bespoke ECS-like platform - which worked fairly well, apart from deployments regularly failing due to nodes being too small to fit pods onto. It has health checks, self-healing properties, etc. like Kubernetes - but you can&rsquo;t easily <code>ssh</code> into pods even in non-prod environments easily. There&rsquo;s more reasons for the move, but basically there&rsquo;s a company-wide effort to move to EKS.</p> <p>I loved using Kubernetes (with k9s!) at Sainsbury&rsquo;s, so I volunteered to lead this migration project for our team. Here&rsquo;s some things I learned whilst leading this:</p> <ul> <li> <p>A shared knowledge base such as Google Docs works great. We captured key meeting notes, decisions, diagrams, etc. here.</p> <ul> <li>Anyone can get up to speed quickly</li> <li>Easy to ask questions, add comments</li> </ul> </li> <li> <p>Creating a &ldquo;team training Slack channel&rdquo; for a new tech domain works great</p> <ul> <li>As you work through the training, questions, problems, and solutions crystallise</li> <li>All information is contained neatly in the channel, not spread all over various places <ul> <li>It&rsquo;s easier to collate key points and give feedback to the course owners</li> </ul> </li> <li>You can expand the channel beyond just your team, sharing the benefits</li> </ul> </li> <li> <p>For real-time knowledge sharing, encourage various people to take tickets on the work. Pair with them for smooth KT</p> </li> <li> <p>In refinement, it can be great to call out a ticket as a pairing ticket - a &ldquo;🍐&rdquo; emoji in the title is a nice reminder that some felt they had something new to learn from it</p> </li> </ul> <p>I also wrote a popular internal blog post for our organisation about how to use <a href="https://k9scli.io/"><code>k9s</code></a>, with specific instructions for a frictionless walk-through.</p> <h1 id="ci-jenkins">CI (Jenkins)</h1> <ul> <li>Consider adding a &ldquo;notes&rdquo; text parameter to some builds. Even if you don&rsquo;t update the build description with this, it can be very useful to know why some builds were run (e.g. manual perf testing of a branch - what change, what is expected)</li> <li>For performance tests, put time-stamped links to observability platforms (DataDog, Grafana, etc.) in the output - it really helps the ergonomics of diagnosing any issues. Lower barrier to entry helps keep performance high!</li> <li>Be mindful of how many messages you&rsquo;re sending to Slack, and where. If there&rsquo;s just a little traffic, it can go to a visible team chat. If it&rsquo;s noisy, it&rsquo;ll probably go to a chat where people don&rsquo;t look as often!</li> <li>For parameters, be explicit - say <code>3600</code> for the <code>default</code> seconds run time, rather than <code>default</code> then loading in the number based on that string</li> </ul> <h1 id="ci-github-actions">CI (GitHub Actions)</h1> <p>Apart from linting, auto-fixing, formatting, etc. there are some really cool things you can do with GHA and GH</p> <ul> <li> <p>Have a fairly complex/tedious workflow for e.g. building docker images and performance testing them on a branch? Use ChatOps to listen to a command and let an Action do it for you</p> <ul> <li>It can reply with a comment, linking to the builds, perf tests, dashboards, etc.</li> <li>It can describe what process it is doing, for more explicit documentation</li> </ul> </li> <li> <p>Use Chinthakagodawita&rsquo;s <a href="https://github.com/chinthakagodawita/autoupdate">autoupdate</a> action to keep PR&rsquo;s up-to-date with the <code>main</code> branch</p> <ul> <li>If you have <code>auto merge</code> enabled, you can use the <code>PR_FILTER</code> of <code>auto_merge</code> <ul> <li>Done reviewing 5 PRs? Hit auto merge on them, and this will keep them merging until they&rsquo;re all done!</li> <li>Without this, you&rsquo;d have to wait and press &ldquo;merge from main&rdquo; four times. That could be like 10-30 minutes being distracted!</li> </ul> </li> </ul> </li> </ul> <p>Open source contributions:</p> <ul> <li>Coursier&rsquo;s <code>setup-action</code> is &ldquo;A GitHub Action to install Coursier and use it to install Java and Scala CLI tools.&rdquo;. It can set up various Java verisons and distributions. <ul> <li>We use Amazon Corretto at work, and AWS. I [added Corretto to the jvm-index repo](<a href="https://github.com/coursier/setup-action">https://github.com/coursier/setup-action</a> <a href="https://github.com/coursier/jvm-index/blob/master/src/Corretto.scala)">https://github.com/coursier/jvm-index/blob/master/src/Corretto.scala)</a>.</li> </ul> </li> </ul> <h1 id="docusaurus">Docusaurus</h1> <p>I was familiar with Hugo&rsquo;s Doks static site generator, and was happy to try a new SSG here: Docusaurus.</p> <p>We were on Docusaurus 1, and we had a lot of complexity with the sidebar, document ordering, couldn&rsquo;t use cool new plugins, etc. - so I was happy to simplify things and upgrade us to Docusuaurs 2. Here&rsquo;s a few tips:</p> <ul> <li>Set up <a href="https://github.com/marketplace/actions/deploy-pr-preview">PR preview</a>, so non-developers can see what their changes look like <ul> <li>You might need to &ldquo;recreate&rdquo; the Action from scratch to avoid nesting (it&rsquo;s a composite action) - see <a href="https://github.com/rossjrw/pr-preview-action/issues/33">this issue</a></li> </ul> </li> <li>Consider adding comments to your site, so people can reach out with the context directly above. <a href="https://utteranc.es/">utteranc.es</a> can help with this</li> <li>Add light/dark src/css/custom.css to match the rest of your project&rsquo;s branding</li> <li>For user-facing documentation, add a FAQ page. This could save a lot of time helping resolve confusion on your most common questions!</li> <li>When choosing document order, set weights like 0, 10, and 20. If you set 0, 1, and 2 then you can&rsquo;t insert a document between any of them without changing many files. With the former setup, you can set &ldquo;15&rdquo; to get between 10 and 20.</li> </ul> <h2 id="text-search-in-docusaurus">Text search in Docusaurus</h2> <p>I also added text search, to help our users navigate straight to what their looking for - without having to look through the structure of our sidebar. I did this as a spike for fun on a &ldquo;learning Friday&rdquo; - and when it was nearly ready, our users were excited for it - it was apparently quite a headache for them. Once I figured it out, it was really simple! I <a href="https://github.com/cmfcmf/docusaurus-search-local/commit/f169f9acc9fd44d7963f6e732466ba6cd38e6ce9">raised documentation</a> for this to make it easier for other people to get up to speed quickly with it too.</p> <p>package.json adds e.g.</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#d88200">&#34;dependencies&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#111">{</span> </span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;@cmfcmf/docusaurus-search-local&#34;</span><span style="color:#111">:</span> <span style="color:#d88200">&#34;^0.11.0&#34;</span><span style="color:#111">,</span> </span></span><span style="display:flex;"><span> <span style="color:#960050;background-color:#1e0010">...</span> </span></span><span style="display:flex;"><span><span style="color:#111">}</span> </span></span></code></pre></div><p>docusaurus.config.js adds e.g.</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75af00">plugins</span><span style="color:#f92672">:</span> <span style="color:#111">[</span><span style="color:#75af00">require</span><span style="color:#111">.</span><span style="color:#75af00">resolve</span><span style="color:#111">(</span><span style="color:#d88200">&#34;@cmfcmf/docusaurus-search-local&#34;</span><span style="color:#111">)],</span> </span></span></code></pre></div><p>To see it locally, do <code>yarn build</code> and <code>yarn serve</code>. These make a production-like version of your site. <code>yarn run dev</code> does not integrate most of the search plugins (the search index is built on build only)</p> <p>There&rsquo;s also <a href="https://github.com/easyops-cn/docusaurus-search-local">https://github.com/easyops-cn/docusaurus-search-local</a> if you need it to be local/static. Algolia is popular, but it needs a server. See more <a href="https://docusaurus.io/docs/search">in the Docusaurus docs</a></p> <h1 id="meetings">Meetings</h1> <ul> <li>Enable closed captions <ul> <li>Having the auto-generated subtitles should be accurate enough to help some of your team follow the conversation</li> <li>If the auto-generated subtitles are garbage, you probably need to spend some budget on upgrading microphones. If the computer can&rsquo;t understand you, maybe humans are having an issue too!</li> </ul> </li> </ul> <h1 id="calendar">Calendar</h1> <ul> <li>If a meeting is recorded, but a link to the recording in the invite. It gives a real home to the recording, rather than just a Slack message that gets lost. Helpful for people coming back from holiday/sickness - can flick through Calendar and get straight into the meetings they need to catch up on</li> </ul> <h1 id="build-caching">Build caching</h1> <p>Compiling your apps from scratch every time is a waste of time &amp; energy. Some build tools support delta/partial compilation - if only 1 file in 1000 changed, we can base our compile around that. GitHub Actions has a few options for caching dependencies, e.g. <a href="https://github.com/actions/cache">https://github.com/actions/cache</a> or <a href="https://github.com/coursier/cache-action">https://github.com/coursier/cache-action</a>. That <em>could</em> help a little. Some build tools have a remote cache - that&rsquo;s great for quicker builds on CI. But, if you don&rsquo;t have a remote cache - what can you do?</p> <p>Our team uses our own <code>mill</code> build tool container. It already ran some basic checks to check it&rsquo;d work with our project and could initialise some &ldquo;workers&rdquo; - but didn&rsquo;t do any caching. Here&rsquo;s what I did:</p> <ul> <li>Use a wrapper <code>millw</code>, a bit like <code>gradlew</code>. This would allow the container to build for any <code>.mill-version</code>, by downloading the necessary tooling <ul> <li>If we merge a build tool upgrade in our main repo, builds would still work without requiring a manual rebuild on the new version of this image. Not technically efficient due to the redownloads of the build tool, but ultimately removing some toil in making things a little smoother for humans.</li> <li>Compile, check formatting, fixing, etc. to generate these outputs in <code>out</code>, as well as downloading dependencies</li> <li>To prevent being over-written, run <code>mv /root/build/out /root/out-cache</code>. In Jenkins jobs for app builds, move this cache back (if the build is parameterised with using the cache). Dependencies cache doesn&rsquo;t need moving.</li> <li>The cache doesn&rsquo;t have to be used. It adds some size, but storage is cheap and saved time/energy is valuable. We use it for PR builds (not <code>main</code> - that&rsquo;s clean), and</li> </ul> </li> </ul> <p>The outcome of this is that, several minutes are shaved off each module (more or less, each microservice) build time. <em>Faster PR compilations means faster PR checks, which means delivering value faster and reducing our mean time to recovery.</em> It also means faster builds for ChatOps triggering branch builds + perf tests, giving fast feedback on performance critical code changes!</p> <figure><img src="build-cache.webp" alt="Can you guess which builds are using the cache?" width="100%"/><figcaption> <p>Can you guess which builds are using the cache?</p> </figcaption> </figure> <p>I was pleased with doing this, as using <code>deltas</code> like this has seemed awesome to me for a long time. I was amazed as a teenager when one Android custom ROM could deliver OTA updates 10x smaller than anyone else, by using deltas.</p> <h1 id="performance-tests">Performance tests</h1> <p>In your performance testing platform (we use Gatling), consider what types of test you want to have, and what should be compared:</p> <ul> <li>nightly, load (main) <ul> <li>I made them run for longer (why not? nobody is manually testing on the <code>perf</code> env at 3am)</li> <li>I made them run at peak RPS for 75% of the run time (configurable). Previously, only about 20% of the time was at peak RPS. Choose a traffic shape gives your services a proper workout!</li> </ul> </li> <li>soak (main) <ul> <li>Have seen dependencies clash and lead to slow memory leaks; soak tests protect us from this, run over the weekend</li> <li>I oversaw various performance test changes around this time after identifying improvements with the team in a post-mortem.</li> <li>Here, we basically decrease the load a little bit (75% of nightly) and run for much longer</li> </ul> </li> <li>load (branch) <ul> <li>results could be very far from average results on <code>main</code>, so have separate simulation to keep your &ldquo;usually good&rdquo; simulations clean</li> </ul> </li> </ul> <p>You can try different traffic shapes, e.g. a triangle wave over a day to simulate real traffic variety. How does your app perform as load varies?</p> <p>We previously sent the reports to Slack, with pass/fail and the targets. I added time-stamped hyperlinks to observability dashboards for ergonomics.</p> <h1 id="git-hooks">Git hooks</h1> <p>Git hooks are great - ensure your code is linted/compilable/tested before pushing. What&rsquo;s even cooler is combining them with interactive CLI tooling like <code>gum</code> - see my <a href="https://github.com/IdiosApps/gummy-hooks">&ldquo;gummy hooks&rdquo;</a> examples.</p> <ul> <li>Iterate quicker by using a bash script and just calling it - you don&rsquo;t actually have to do anything with Git to iterate on it.</li> </ul> <h1 id="scala-steward">Scala Steward</h1> <h2 id="not-receiving-updates">Not receiving updates</h2> <p>For Scala, a common tool for getting dependency upgrades (and new Scala versions!) is <a href="https://github.com/scala-steward-org/scala-steward">Scala Steward</a>. For about half a year, only a few of our dependencies were getting updates. You may remember when Log4j had multiple security vulnerabilities (and corresponding patches) within about one week, in December 2021. This one <em>was</em> patched automatically. A few other dependencies weren&rsquo;t being updated (note: I never saw security issues, or if we did we&rsquo;d patch manually).</p> <p>We were extracting a version and interpolating with it. The fix here was to declare each dependency and its version on its own line. It didn&rsquo;t really make PRs harder to review, and is even a bit clearer in a PR to show you what really changed.</p> <p>If you&rsquo;re not getting updates with Scala Steward, that might be something to look into!</p> <h2 id="not-receiving-updates-20-failed-to-decode-modules">Not receiving updates&hellip; 2.0: <code>Failed to decode Modules</code></h2> <p>If you have a big <code>Mill</code> Scala project (let&rsquo;s say, a monorepo - with about 10 modules) and fair number of dependencies - you might be seeing this problem.</p> <p>I ran a local clone of Steward with a teammate, adding some print-lines to diagnose the parser. We saw the input string for parsing was blank for our project. Looking at <code>MillAlg.scala</code>, we saw about <a href="https://github.com/scala-steward-org/scala-steward/pull/2717">5000 lines of the <em>end</em> of a JSON object</a>. The default buffer is 8192 bytes. Increasing the CLI argument <a href="https://github.com/scala-steward-org/scala-steward/pull/1829"><code>--max-buffer-size</code></a> to <code>32768</code> fixed the issue for us. The author also raised a <a href="https://github.com/scala-steward-org/scala-steward/pull/2940">PR</a> to give a more obvious error about this, instead of returning some partial JSON.</p> <h1 id="kinesis">Kinesis</h1> <p>With Kinesis, we were getting hundreds of thousands of errors per week -<code>[metrics_manager.cc:145] Metrics upload failed</code>- giving a very bad signal:noise ratio in our DataDog logs.</p> <p>We only use metrics at the &ldquo;stream&rdquo; level, rather than the &ldquo;shard&rdquo; level (a stream has many shards, and shards can sometimes report no data &amp; error).</p> <p>On a <code>KinesisProducerConfiguration</code>, do <code>.setMetricsGranularity(&quot;stream&quot;)</code>. The default level is &ldquo;shard&rdquo;.</p> <p>Also be mindful of costs. The Javadocs state that two shards with two streams each will produce <em>seven</em> CloudWatch metrics (4x shard, 2x stream, 1 global).</p> <p>AWS support was not so helpful with this error (<a href="https://github.com/awslabs/amazon-kinesis-producer/issues/188#issuecomment-557198786">essentially saying: &ldquo;it&rsquo;s a known issue, but please work around it by filtering out the logs&rdquo;</a>) - setting a more accurate configuration is better, and I <a href="https://github.com/awslabs/amazon-kinesis-producer/issues/188#issuecomment-1189202115">shared our recommendation on the issue</a>.</p> <h1 id="on-call">On-call</h1> <p>With good tests (unit, integration, end-to-end, performance, etc.), you won&rsquo;t get called out much and it might be worth the extra pay bump + other perks :)</p> <h1 id="gh-cli---downloading-files--using-in-github-actions"><code>gh</code> CLI - downloading files, &amp; using in GitHub Actions</h1> <p><code>curl $(gh api $URL_TO_FILE_ON_GITHUB) --jq .download_url) -o ./path/to/download.ext</code></p> <p>If you install the <code>gh</code> CLI on you GitHub Action runners too, it can be a nice way to interact with your GitHub (enterprise works too!). You just need to <a href="https://josh-ops.com/posts/gh-auth-login-in-actions/">set the enterprise token and GitHub Host as env variables</a>.</p>ChatOps - just say the wordseedinghttps://idiosapps.github.io/garden/chatops/Thu, 18 May 2023 00:00:00 +0000https://idiosapps.github.io/garden/chatops/<p>ChatOps: you say some trigger, and you get some response. The processing behind the scenes can be as complex or niche as you like.</p> <p>In this blog, we&rsquo;ll talk about three different ChatOps tools (Slack, GitHub Actions, Hubot) and how they can:</p> <ul> <li>Set up a basic reminder (Slack)</li> <li>Trigger image builds, performance tests, etc. on PRs (GitHub Actions)</li> <li>Send a list of open PRs, and their review counts, to Slack (Hubot)</li> </ul> <h1 id="slack">Slack</h1> <p>Slack has a few <a href="https://slack.com/intl/en-gb/help/articles/360057554553-Use-shortcuts-to-take-actions-in-Slack">baked in commands (&ldquo;Shortcuts&rdquo;)</a>. The most useful I&rsquo;ve seen is reminders - whether for yourself or for your team. Here&rsquo;s a few examples, with the format []<code>/remind [yourself or #channel] [what] [when].</code>](<a href="https://slack.com/intl/en-gb/help/articles/208423427-Set-a-reminder)">https://slack.com/intl/en-gb/help/articles/208423427-Set-a-reminder)</a>:</p> <ul> <li>/remind #my-team to join <a href="https://meet.google.com/?pli=1">Google Meet</a> on Wednesday at 4:30pm</li> <li>/remind me to file TPS reports in 20 minutes</li> <li>/remind me to have a great weekend every Friday at 5pm</li> </ul> <h1 id="github-actions">GitHub Actions</h1> <p>Note: If you have a project on Public GitHub, you can use their action &ldquo;runners&rdquo; for free. If you&rsquo;re in the GitHub Enterprise Suite, you&rsquo;ll need to deploy your own <a href="https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/using-self-hosted-runners-in-a-workflow#using-default-labels-to-route-jobs"><code>runs-on: [self-hosted]</code></a> &ldquo;runners&rdquo;. There are some projects that can help you kick-start self-hosting, such as <a href="https://github.com/philips-labs/terraform-aws-github-runner">the scalable spot instance setup &ldquo;terraform-aws-github-runner&rdquo;.</a></p> <p>perf tests awkward process, evolving over time as we change our Jenkins pipelines to multibranch etc.</p> <p>very valuable - perf test before merge</p> <p>low barrier to entry: chat ops. Ask a PR to be perf tested, and an hour later you have</p> <ol> <li>docker images build</li> <li>applications performance tested</li> </ol> <h1 id="hubot">Hubot</h1>Ways of Working 'checklist'seedinghttps://idiosapps.github.io/garden/ways-of-working-checklist/Fri, 05 May 2023 00:00:00 +0000https://idiosapps.github.io/garden/ways-of-working-checklist/<p>Every team will figure out their own unique ways of working through &ldquo;Forming, Storming, Norming and Performing&rdquo; - but here are some techniques that I&rsquo;ve seen provide lots of value - usually with little effort!</p> <p>✏ Why not take a note of each one you aren&rsquo;t using yet as you read?</p> <h1 id="github">GitHub</h1> <h2 id="pr-templates">PR Templates</h2> <p>Open source projects often have multiple PR templates, to help capture context on <a href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/about-issue-and-pull-request-templates#issue-templates">bug reports, feature requests, and security vulnerabilities.</a></p> <p>In your team&rsquo;s day-to-day repositories, it&rsquo;s likely you aren&rsquo;t using templates. Maybe they &ldquo;get in the way&rdquo; and &ldquo;just get deleted&rdquo;, but these two features might make it more interesting!</p> <h3 id="markdown-comments">Markdown comments</h3> <p>GitHub uses MarkDown (their own special flavour of MarkDown, really) - and it supports comments:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>&lt;!-- Please enter the ticket number below (GitHub will autolink to Jira), e.g. JIRA-1234 --&gt; </span></span><span style="display:flex;"><span>JIRA-420 </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>&lt;!-- </span></span><span style="display:flex;"><span>For this feature/fix, please link any tests from other repositories too: </span></span><span style="display:flex;"><span>- [ ] e2e: E2E-PR-1337 </span></span><span style="display:flex;"><span>- [ ] perf-tests: PERF-404 </span></span><span style="display:flex;"><span>--&gt; </span></span></code></pre></div><p>These comments are only visible when editing - you can&rsquo;t see them on the posted description. You can use comment to give friendly reminders on:</p> <ul> <li>Providing context</li> <li>Linking to the ticket (rather than paraphrasing all that context!)</li> <li>Ensuring tests (unit, integration, performance) are covered <ul> <li>You could give a commented-out checklist if you want</li> </ul> </li> </ul> <h3 id="autolinks">AutoLinks</h3> <p>In each GitHub repository, you can set up &ldquo;AutoLinks&rdquo;. They&rsquo;re basically an autogenerated, tidy hyperlink.</p> <p>The GitHub Docs give a good example - but I&rsquo;ll extract a snippet and save you getting distracted:</p> <ul> <li>Reference prefix: <code>JIRA-</code></li> <li>Target URL: <code>https://jira.example.com/issue?query=&lt;num&gt;</code></li> <li>Preview: <code>JIRA-123</code> is converted to <code>https://jira.example.com/issue?query=123</code></li> </ul> <p>Combined with templates, you can ensure that every PR has a short link to the relevant tickets. This is much better than just having the ticket number (and no link) in the title/description/branch/commits:</p> <ul> <li>It saves the PR author time in making these links</li> <li>It saves the reviewers time fishing around in Jira and getting distracted</li> <li>It ensures everyone has easily accessible context, so the PR description can focus on the actual changes</li> </ul> <p>Until I knew this I was using an Espanso text expansion macro <code>:JIRA</code> to do similar, but this setup gives your whole team an awesome shared capability</p> <h3 id="conventional-comments">Conventional comments</h3> <p>Stating the importance &amp; intent of your message up front can make communication clearer, and decisions faster.</p> <p>Read more in detail at <a href="https://conventionalcomments.org/">https://conventionalcomments.org/</a>, but basically comments on PRs can look more valuable like this:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>issue: this mock never gets called! </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>praise: this method is really easy to read, and handles the logic very well </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>nitpick: these two tests could be combined </span></span></code></pre></div><p>Compare the latter example to how it might be expressed without &ldquo;conventional comments&rdquo;:</p> <div class="highlight"><pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>These two tests could be combined, but it&#39;s not a blocker for this PR and I&#39;ll approve </span></span></code></pre></div><h3 id="conventional-commits">Conventional commits</h3> <p>Commits can look like:</p> <ul> <li><code>docs: add javadocs for user-facing swagger api</code></li> <li><code>bug: fix a flaky test</code></li> <li><code>chore: bump dependency version x-&gt;y</code></li> <li><code>feat: AI face detection when user blinks</code></li> </ul> <p>It could help you have a more atomic git history, which may make PRs easier to comb through. You can also use the prefixes to group changes, and make prettier changelogs.</p> <p>Read more: <a href="https://www.conventionalcommits.org/en/v1.0.0/">https://www.conventionalcommits.org/en/v1.0.0/</a></p> <h1 id="tickets--work-capture">Tickets / work capture</h1> <h2 id="make-templates">Make templates</h2> <ul> <li>Context, task, ACs, key contacts,</li> <li>User stories</li> </ul> <p>Templates are all about adding context in an organised way. Having this context gives your team more autonomy and interest in the problems, and can lead to better outcomes. Think &ldquo;Context over control&rdquo;</p> <h1 id="knowledge-management">Knowledge management</h1> <p>How are you recording your knowledge? Probably in a few places! It might look like this:</p> <ul> <li>Slack (short term - threads can be linked, good for captured asynchronous discussion)</li> <li>Google Docs (also great for captured async discussion, but leaning towards )</li> <li>Confluence (longer-term storage for internal decisions - awkward to collaborate on, not good for regular updates)</li> <li>Websites (static sites like Hugo&rsquo;s Doks &amp; Docusaurus can make information presentable, searchable, and written in simple markdown &amp; managed by e.g. Git)</li> <li>Some loose markdown files in various repos (maybe some readme.md)</li> </ul> <p>To get someone up to speed on your project, you&rsquo;d probably start with the higher-level, more organised/presentable formats. Hopefully there is a natural flow through the information, otherwise someone who knows the scenery may have to plan a route for you.</p> <p>But what if there were tools that combined the strengths of these platforms. Are there any services that are:</p> <ul> <li>simple: are written in simple markdown-like language</li> <li>collaborative: many users can write in real-time</li> <li>efficient: easy to convert discussions into clean documentation</li> <li>searchable: text search, or even graph search (how do ideas and documentation naturally relate?)</li> </ul> <h2 id="notion">Notion</h2> <p>I use Notion, which covers these points well. It&rsquo;s becoming more and more popular, and I&rsquo;ve seen a few companies using it. Despite appearing simple, there&rsquo;s plenty of power features under the hood:</p> <ul> <li>You can create tables of data - and create views over them, filter, sort, label and organise in helpful ways</li> <li>You can make timelines, calendars</li> <li>You can use it like a task management system (GTD, four quadrants - whatever you want)</li> <li>You can use it as a sprint/kanban board</li> </ul> <p>It&rsquo;s powerful - even for free users. For businesses, it&rsquo;s at least $15 per user, per month. That sounds like quite a lot, but <a href="https://www.atlassian.com/software/jira/pricing?&amp;aceid=&amp;adposition=&amp;adgroup=144583507597&amp;campaign=19306719987&amp;creative=642044705684&amp;device=c&amp;keyword=jira%20cost&amp;matchtype=e&amp;network=g&amp;placement=&amp;ds_kids=p74602839944&amp;ds_e=GOOGLE&amp;ds_eid=700000001558501&amp;ds_e1=GOOGLE&amp;gclid=Cj0KCQjwr82iBhCuARIsAO0EAZwOOUXmPpGJL3jh7S3mnHU5GnfebfyTdNgpRlczLTWDG9gWD0QTlGkaAs1cEALw_wcB&amp;gclsrc=aw.ds">it looks like Jira costs the same</a>.</p> <p>I&rsquo;ve never worked in a company using it as a central tool in all the ways above - so I can&rsquo;t actually vouch for it. Maybe it only works up to a certain scale of organisation - but maybe that could be your organisation.</p> <h2 id="obsidian">Obsidian</h2> <p>I didn&rsquo;t get far into Obsidian - the theory can get pretty deep, and there&rsquo;s many methodologies. You might have heard of:</p> <ul> <li>&ldquo;Second brain&rdquo;, and</li> <li>&ldquo;Zettelkasten&rdquo;</li> </ul> <p>The key concept is that ideas are related, and naturally link up (like in our brain). You can view them as a graph (looks like synapses in our brain), converge, and diverge thoughts whilst keeping them linked. There&rsquo;s also a cool plugin system. I had a play and set up cloud sync to GitHub and OneDrive. I&rsquo;ve already got years of notes in Notion, and didn&rsquo;t quite get sold on Obsidian.</p> <p>Arguably, the notes (and their relations!) might not be personal enough to be maximally useful for everyone. However, across a small team it could work really well. <a href="https://obsidian.md/pricing">$50 per user, per year - plus about $100 a year for sync.</a></p> <p>If you think you&rsquo;re having problems in some of those areas, maybe try a different knowledge management system. This is totally not an advert ;) I&rsquo;d just love to see first-hand how these tools could work for some teams instead of the usual Jira/Confluence fare! If you have some 💲 and some ⌛, your team could spike using these tools.</p> <h1 id="discussions">Discussions</h1> <table> <thead> <tr> <th>Problem</th> <th>Solution</th> </tr> </thead> <tbody> <tr> <td>Rabbit holes</td> <td>Be mindful of topics dominating meetings - consider a separate meeting/thread to go into specifics</td> </tr> <tr> <td>Circling</td> <td>Be mindful of discussions looping. Raise the concern, or capture notes everyone can see and help to align on a plan</td> </tr> <tr> <td>Uncaptured discussion</td> <td>Take notes and share them. Ask for corrections, as you may have misunderstood. Whether it&rsquo;s minutes for regular meetings, or details in ticket refinement - capturing 5 minutes of context now can save a few minutes in the future</td> </tr> <tr> <td>Discussion contains too many moving pieces</td> <td>Make a quick sketch, in TLDRAW or even Mermaid. Humans find it hard to remember 5-9 &ldquo;bits&rdquo; of info - compress ideas into a visual)</td> </tr> <tr> <td>Out of office/ill teammates missed important discussion meetings</td> <td>Record the meetings, and update the calendar invite with the recording link. Transcribe the audio, provide a searchable interface to save time</td> </tr> <tr> <td>Solutionising without being aligned</td> <td>Define the problem statement. &ldquo;What questions are we trying to answer?&rdquo;, &ldquo;What data lets us answer these questions?&rdquo;, &ldquo;How can we get that data?&rdquo;</td> </tr> </tbody> </table> <h1 id="collaborative-working">Collaborative working</h1> <h2 id="visible-welcoming-huddles">Visible, welcoming huddles</h2> <p>Is your team pairing and mobbing, but in private calls? It&rsquo;s not transparent or welcoming - so consider this:</p> <p>Take the number of devs you have, and divide by two. Make this many &ldquo;pairing&rdquo; Slack channels. It gives a space for everyone to pair, or form mobs. If someone needs help, it&rsquo;s easy to hop in and out without the complexity of setting up more calls.</p> <h2 id="remote-pairing">Remote pairing</h2> <table> <thead> <tr> <th>Tool</th> <th>Review</th> </tr> </thead> <tbody> <tr> <td>Zoom</td> <td>Solid screenshare quality, awkward drawing tools, and confusing controls. Preferred screen-sharing platform for now</td> </tr> <tr> <td>Slack</td> <td>Worst screenshare &amp; audio quality. Most convenient to drop in/out with pairing channels</td> </tr> <tr> <td>VS Code</td> <td>Shared editor &amp; terminal are good - but the file explorer seems too strict to let the guest explore the project and be productive</td> </tr> <tr> <td>Intellij</td> <td>Code With Me is decent now - my main issue is the Shared Terminal is completely broken for the host (a big problem if you run your tests there!)</td> </tr> <tr> <td><a href="https://tuple.app/">Tuple</a></td> <td>Great screenshare quality (configurable), good interactivity. Configuration maybe a bit too permissive, but necessary. Great features like &ldquo;pebble drop&rdquo; to show where you&rsquo;re looking</td> </tr> </tbody> </table> <h1 id="quality-checks">Quality checks</h1> <ul> <li>git hooks</li> <li>github actions has a broad marketplace</li> </ul>Rota Driven Development ⁉evergreenhttps://idiosapps.github.io/garden/rota-driven-development/Fri, 28 Apr 2023 00:00:00 +0000https://idiosapps.github.io/garden/rota-driven-development/<p>How can you take a bunch of T-shaped developers and upskill everyone to be a 🟩-shaped developer?</p> <p>You might know a few ways you can do this already:</p> <ul> <li>Knowledge sharing sessions</li> <li>Pairing/Mobbing</li> <li>Giving regular, honest feedback</li> </ul> <p>You might know why it could be a good idea:</p> <ul> <li>Employees want to be empowered</li> <li>Learning, teaching, and broadening horizons can be rewarding &amp; fun</li> <li>Reduced &ldquo;bus factor&rdquo;</li> </ul> <p>But what would something <em>really extreme</em> look like? Enter: &ldquo;Rota Driven Development&rdquo; <em>Note: You might even want to experiment with this setup if you already have pairing/mobbing as your main way of working. Otherwise, this might sound quite terrible! But let&rsquo;s see how it might be valuable. This post isn&rsquo;t about why pairing is good or bad - but what an extreme variant of it could look like</em></p> <h1 id="illustrative-example">Illustrative example</h1> <p>Let&rsquo;s say we have three developers:</p> <ul> <li>BackEnd expert (B), with a bit of Cyber (c) [Bc_]</li> <li>Cyber expert (C), no other experience [<em>C</em>]</li> <li>FrontEnd expert (F), with a bit of BackEnd (b) [b_F]</li> </ul> <p>When you pair these developers, they&rsquo;ll level up by working on tasks together:</p> <ul> <li> <p>[Bc_] + [b_F] -&gt; [Bcf] + [B_F] (let&rsquo;s say the BackEnd expert didn&rsquo;t share much on Cyber this time)</p> </li> <li> <p>[B_F] + [<em>C</em>] -&gt; [BcF] + [bCf] (they worked across all three topics)</p> </li> <li> <p>Already, the team is becoming much more well-rounded. Everyone has picked up at least the basics of every field.</p> </li> </ul> <p>Of course, it&rsquo;s an extreme example. More realistically, there could be many domains (framework, syntax, literally domain knowledge, etc.) within any of these three fields - so it can still make sense for e.g. BackEnd developers only.</p> <p>In a real team, there would probably be a few more people as well - so everyone can Always Be Transferring Knowledge</p> <h1 id="your-teams-skill-matrix">Your team&rsquo;s &ldquo;skill matrix&rdquo;</h1> <p>To find out what some quality pairings would be, you can make a shared table of people and how they feel their skills are out of 5. It should highlight gaps, and if you update it few weeks/months you use it to track progress.</p> <h1 id="planning-work-for-maximal-learning">Planning work for maximal learning</h1> <p>In &ldquo;second language acquisition&rdquo;, there is a theory called &ldquo;i+1&rdquo;: To have a smooth, low-stress learning environment, you feed someone content that is slightly more complex than their current level. In other words, don&rsquo;t throw people in at the deep end. If you can estimate the complexity (via story points or some other metric), you could combine that with the skill matrix to optimise growth in your employees&rsquo; skill set.</p> <h1 id="but-tickets-and-rotations-dont-line-up-nicely">But tickets and rotations don&rsquo;t line up nicely</h1> <p>There&rsquo;s a few approaches you could try:</p> <ul> <li>Set pairings for a whole sprint</li> <li>Set pairings for only the first ticket in a sprint, and then let people self-organise</li> </ul> <h1 id="how-can-my-team-see-if-this-works-for-us">How can my team see if this works for us?</h1> <ol> <li>Check if your team is even interested in such an idea</li> <li>Make the up-front investment (skills matrix), and continued effort investment (changes to planning/ticket preparation)</li> <li>Run a trial for a few weeks. Maybe run a retro on the rotation process, and iterate if you see value there. Scrap it and move on if not.</li> </ol> <h1 id="conclusion">Conclusion</h1> <p>For teams that have already bought into pairing and want to try a more focused approach to maximise their learning: &ldquo;Rota Driven Development&rdquo; could be an interesting experiment to try.</p>