James' Digital Gardenhttps://james-s-w-clark.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://james-s-w-clark.github.io/garden/rtx-asdf/Fri, 21 Jul 2023 00:00:00 +0000https://james-s-w-clark.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/james-s-w-clark/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/james-s-w-clark/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/james-s-w-clark/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>ChatOps - just say the wordseedinghttps://james-s-w-clark.github.io/garden/chatops/Thu, 18 May 2023 00:00:00 +0000https://james-s-w-clark.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://james-s-w-clark.github.io/garden/ways-of-working-checklist/Fri, 05 May 2023 00:00:00 +0000https://james-s-w-clark.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://james-s-w-clark.github.io/garden/rota-driven-development/Fri, 28 Apr 2023 00:00:00 +0000https://james-s-w-clark.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>Symlinks, syncs, and app configurationevergreenhttps://james-s-w-clark.github.io/garden/config-symlink-fast-setup/Wed, 18 Jan 2023 00:00:00 +0000https://james-s-w-clark.github.io/garden/config-symlink-fast-setup/<p>When setting up a new Windows device, there are some tools that can help you to install your apps quickly and easily from the command line (WinGet, chocolatey). Whilst these are great (and can actually install most of your apps), one thing they can’t do is transfer your configuration between devices.</p> <p>In this short blog, we’ll be using:</p> <ul> <li>A cloud sync of choice (Google Drive / OneDrive / DropBox etc.) <ul> <li>So I have my configuration files on any device</li> </ul> </li> <li>Symbolic links, in a tiny script file <ul> <li>So apps can easily access the backed-up configuration, and sync changes</li> </ul> </li> <li>An application we love, which uses simple configuration files</li> </ul> <hr> <p>For this worked example, we&rsquo;ll use Espanso, and a folder &ldquo;Junction&rdquo; symlink.</p> <p>The folder linking must be done before the source folder (Espanso&rsquo;s config) is created. Either do this before installing the app, or do some file/folder shuffling. It doesn&rsquo;t matter if the target exists or not.</p> <p>In your cloud-sync&rsquo;d folder (<code>%HomePath%\OneDrive\Apps\espanso</code>), create a file <code>symlink.bat</code> and add:</p> <pre tabindex="0"><code>mklink /J %APPDATA%\espanso %HomePath%\OneDrive\Apps\espanso </code></pre><p>In Windows, the <code>%APPDATA%</code> folder will look like this if the command succeed; note the little arrow on our symlinked folder:</p> <p><img src="symlink_folder_icon.png" alt="Untitled"></p> <p>In <code>......./OneDrive/apps/espanso/match/base.yml</code>, add this to the main <code>matches</code> body:</p> <pre tabindex="0"><code>- trigger: &#34;:synctest&#34; replace: &#34;your espanso config was sync&#39;d sucessfully!&#34; </code></pre><p>Install espanso with default settings</p> <p>Espanso startup logs show our symlink folder being loaded in. It does this anyway (nothing special is happening to the file loading&hellip; other than it actually loading from our cloud sync&rsquo;d folder!):</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-scala" data-lang="scala"><span style="display:flex;"><span><span style="color:#f92672">...</span> <span style="color:#111">reading</span> <span style="color:#111">configs</span> <span style="color:#111">from</span><span style="color:#00a8c8">:</span> <span style="color:#960050;background-color:#1e0010">&#34;</span><span style="color:#00a8c8">C:\\Users\\james\\AppData\\Roaming\\espanso</span><span style="color:#960050;background-color:#1e0010">&#34;</span> </span></span><span style="display:flex;"><span><span style="color:#00a8c8">...</span> <span style="color:#00a8c8">reading</span> <span style="color:#00a8c8">packages</span> <span style="color:#00a8c8">from:</span> <span style="color:#960050;background-color:#1e0010">&#34;</span><span style="color:#00a8c8">C:\\Users\\james\\AppData\\Roaming\\espanso\\match\\packages</span><span style="color:#960050;background-color:#1e0010">&#34;</span> </span></span></code></pre></div><p>So if we enter our special phrase, <code>:synctest</code>, we should see it expanded to:</p> <p><code>your espanso config was sync’d sucessfully!</code></p> <p>On another computer (or a fresh installation of Windows), all you have to do is double-click the .bat file. In just a few minutes, we&rsquo;ve made a system that will always take care of our favourite Espanso packages &amp; personalised keywords. Also note that any changes we make will be backed up to the cloud too!</p> <hr> <p>What we’ve done here can be applied to more applications which have simple configuration. The scripts to create junctions/symbolic links could be per-app, or you could put them all in one script (to be run before a big WinGet/Brew install).</p> <p>Here’s a few configurations ones I may set up this synchronisation for:</p> <ul> <li>Headphone EQ - Peace/EqualizerAPO - .txt files represent frequencies/decibels etc.</li> <li>GPU Overclock/Undervolt - MSI Afterburner - Custom curve is a bit tricky to make (I have to search for my notes on instructions every time I set up)</li> <li>Calibre, for digital book management</li> <li>&hellip; I can&rsquo;t think of more, but I&rsquo;m happy even with just Espanso having this :-)</li> </ul> <p>The same principles apply to Ubuntu and MacOS - but implementation of your symlink script files might look more like <a href="https://apple.stackexchange.com/a/115647">this StackExchange answer</a>.</p>