Writing

I write about grounded architecture and testing, practical AI-assisted engineering, and hands-on code and tooling.

I also post shorter, less formal TIL notes here.

I’m most active on Bluesky, and you can also find me on LinkedIn.

  • Experience Report: Building a time-tracking AI assistant

    This is a short experience report about using skills (with Codex and its models) to build a personal AI assistant that helps me maintain my time-tracking log. To set expectations: the assistant does not manage my calendar or tasks. It helps me keep a time-tracking log that lives …

  • AI’s Opportunity: Pacing Control Loops with Development

    What caught my attention in the book Vibe Coding by Gene Kim and Steve Yegge is the idea that, as LLMs and coding agents change how we build software, control loops—tests, reviews, and other signals that tell you whether a change behaves as expected—should be faster and more inte…

  • On Building Reliable Software with LLMs

    This post captures my current thinking on how LLMs are impacting software development, particularly around software quality and engineering discipline. My main observation: most of the best practices we've relied on for years are just as important—maybe even more so—in an LLM-ass…

  • The Unification of Commands and Skills in Claude Code

    For background, because you may be noticing them in some of the outputs and inputs to Claude Code, I want to combine two skills: text-grader: grade a text for correct UK English spelling and grammar til-rules-checker: check my 'Today I Learned' format rules for my Today I Lea…

  • Agent Chisels: My LLM Agent Skills and Workflows

    I have been meaning to share more about my LLM workflows and tooling for a while, partly to have a reference for conversations, but mostly to learn in public. Agent Chisels is where I will be sharing the custom artefacts (primarily skills, with commands and agents to follow) that…

  • My Best Technical Decision of 2025: Moving to Proton for Peace of Mind

    This year I bit the bullet and moved mail, calendar and drive from Google to Proton. Knowing that my family is not being profiled when, for example, I plan a doctor's appointment feels liberating. Sure, there were fun and useful technical improvements, like getting a podcast micr…

  • Implementing an Urgent Feature with Opencode, Claude, and Zed

    This is a short post to share a positive experience I had using an LLM agent to quickly add a feature to an existing personal CLI time-tracking application. Below, I describe how I added it using Zed, Opencode and Claude. To start, I wasn't even sure the feature I needed existed …

  • TIL rules to remember

    I have been writing "Today I Learned" posts (TILs) for a few weeks now and I started writing them as a complement to long form blogging. But I found myself spending 45-60 minutes, sometimes longer, per TIL instead of 15-25. This defeated the purpose of quickly recording and inter…

  • DORA Research: Evidence-Based and Scientifically Grounded Software Engineering

    Years ago, the book Accelerate changed my view on software development and delivery fundamentally. Of course, there are its findings (dare I say 'revolutionary'?) on which technical and organisational factors drive high performance software delivery. But that is not what I want t…

  • Grounded decision records from AI conversations

    If you've read some of my posts before or worked with me, you know I like using Architectural Decision Records (ADRs) for lots of reasons. To me the most important one is documenting the why of a decision. If you've worked with AI models before, you've probably asked them for opt…

  • Remove Claude Code branding from commit messages using output styles

    When Claude Code creates git commits for you, it automatically adds its own signature to every commit message, including a promotional link and co-author attribution. Personally I think this is pretty annoying but especially for professional work or team repositories you may pref…

  • How to Use Jujutsu (jj) with Claude Code

    I prefer Jujutsu (jj) over Git for version control, but getting Claude Code to work with jj proved tricky since Claude Code defaults to git. This post explains how to configure Claude Code to use jj instead of Git for version control operations and file change detection. I'll sho…

  • Examples of using Claude Code's output styles

    A very short post on Claude Code's new output styles feature which I have been experimenting with in the past days. Here are some actual examples of how you can leverage output styles to change 'hard-configured' Claude Code behaviour: Remove Claude Code branding from commit mes…

  • Output Styles in Claude Code

    Claude Code's output styles control how the AI responds to your requests. This summary covers the built-in styles and when to use each one. TLDR: Output styles = stored system prompts that change Claude's behaviour. Slash commands = stored user prompts for quick actions. Use th…

  • Grounding AI Instructions in Living Documentation

    Context engineering shows interesting potential to ground documentation to actual code, or as how I sometimes refer to it: reality. Linking AI instruction files (CLAUDE.md, .rules, .cursorrules, etc) to development documentation may turn static docs into living resources. Each co…

  • Using Code Coverage as a Check for Test Refactoring

    TLDR: Use code coverage reports to verify that test refactorings haven't accidentally changed what functionality you're testing. Same coverage percentage before and after refactoring gives confidence your tests still cover the same code paths. If we refactor code, tests should co…

  • Rust code coverage: use 'llvm-cov' over 'tarpaulin'

    A few days ago, I wrote about an issue I encountered where the code coverage for one of my projects failed on CI but worked fine locally. I also discussed a solution. It turns out there's an even better alternative: switch code coverage tools entirely and use llvm-cov instead of …

  • Test Naming Guidelines

    TLDR: Below are test naming guidelines that help me write consistent, clear test names. This is quick post with the Test Naming Guidelines I have been using to make my test names consistent across multiple projects. I use also these with LLMs when writing tests or refactoring mul…

  • Rust: When Cargo Code Coverage Works Locally But Fails in CI

    A short post to help if you run into the same issue. TLDR: If your code coverage reports show vastly different results between local development and CI, explicitly set --engine llvm in your cargo tarpaulin command. I recently ran into a frustration you may be familiar with: your …

  • Continuous Deployment for Personal CLI Tools

    Git pre-push hooks can automate local installation of your personal CLI tools, creating a development workflow where your working environment always has the latest version of your code. When developing CLI tools, for example for personal use, I often want to run the latest versio…

  • Ground Your ADRs with a Verification Section

    Making architectural decisions is one thing, but have you ever wondered how to make them more effective? Adding a Verification section to Architecture Decision Records (ADRs) can make the difference. This simple addition bridges the gap between theory and practice, making decisio…

  • Notes on Preparatory Refactoring

    Notes inspired by Emily Bache's short Youtube video Design Better Code with Preparatory Refactoring in TDD | Demo. A preparatory refactoring is a refactoring to make future changes to accommodate new requirements easy. By definition, current behavior should not be changed. Instea…

  • Less Mentioned Benefits of Architecture Decision Records

    Teams adopt Architecture Decision Records (ADRs) to document decisions, avoid revisiting settled matters, onboard newcomers, adapt to changing circumstances, and sharpen their thinking. However, there are several other valuable benefits that often go unnoticed. A clear decision p…

  • Notes on 🚀 TDD, Where Did It All Go Wrong

    My short notes on 🚀 TDD, Where Did It All Go Wrong. Still a lot of testing wisdom in this talk (re-watched 6 years after publication). Focus on behaviour Behaviour should be your primary focus when writing tests. The need for a new test should arise from new behaviour or requirem…

  • Notes on TDD & DDD From the Ground Up Live Coding

    Some short notes from Chris Simon's Talk TDD & DDD From the Ground Up Live Coding When choosing the right testing level, developers face an important trade-off. Higher-level tests provide better coverage for refactoring, but make it harder to pinpoint the exact location of fa…

  • How to extract all TODOs from code using Scala-CLI

    In recent years, Scala CLI has replaced sbt for my home and smaller work projects. Scala CLI lacks the extensive plugin ecosystem of sbt, so you need to write any additional functionalities yourself. Fortunately, writing simple scripts is a primary use case for Scala CLI, which w…

  • Slice Work into Smaller, Prioritised Deliverables instead of using Story Points

    Have you ever wondered if there are better ways to estimate work than using Story Points? Below is a potentially simpler, more effective method to prioritise and estimate your software development tasks that could save your team countless hours of debate and confusion. This mini-…

  • Boost Your Thinking and Writing with Mini-Essays

    To become a better writer consistently writing is essential. Mini-essays provide a practical approach. Mini-essays are short pieces of writing that focus on a single idea or topic. Key properties of Mini-Essays Length: Mini-essays are short, usually 100 to 300 words to avoid di…

  • DDD and FP can be friends

    DDD (Domain Driven Design) is not tied to a particular programming paradigm and strategic and tactical design choices apply to the architecture and code level. This article was triggered by a talk that does not align with my thinking and experience with DDD and FP over the past y…

  • FizzBuzz fun: Exploring Functional Programming Design Patterns : Monoids

    In this post, we will continue from where we left off in a previous article in this series, "FizzBuzz Fun in Scala: Combining Functions," and explore where further abstraction leads us in terms of functional programming design patterns. Our goal is to show that, despite their int…

  • Simplifying if-complexity in FizzBuzz

    In this series, I've mentioned that using an if-expression in the FizzBuzz problem can be more error-prone and complex compared to functional approaches. In this brief article, I'll demonstrate why that's the case. Let's start with a simple working implementation using ifs: // Co…

  • FizzBuzz fun in Scala: Combining functions

    Every implementation of FizzBuzz in this series, at its core, has relied on an infinitely counting lazy list. This modelling is logical, as the game can theoretically be played indefinitely. In this post, we will explore the possibility of defining a single function operating on …

  • Fizzbuzz fun in Scala: A straightforward implementation

    In previous articles of this series, I examined various implementations and meanwhile experimented with others at different levels of abstraction. However, before delving into those, I wanted to present what I believe to be the most straightforward approach, which allows for easy…

  • Software Architecture Note: On Negotiation and Limiting Accidental Complexity

    In this brief article, I will discuss two insights from the book Fundamentals of Software Architecture: An Engineering Approach by Mark Richards and Neal Ford: the importance of negotiation in an architect's job and an effective communication approach. I will then offer a way on …

  • FizzBuzz Functional Fun in Scala 3

    Nearly a decade ago, I wrote a post about implementing FizzBuzz in a more functional manner, which also happened to be the final entry on a blog I started that year. Now, I want to dedicate more time to writing, and rebooting my blog seems to be a good way to achieve this. What b…

  • FizzBuzz Functional Fun in Scala

    Updated with a more functional implementation of FizzBuzz November 2015 Updated with a link to an implementation using Monoids July 2016 FizzBuzz fun in Scala using Scala Streams. The straightforward implementation of FizzBuzz usually involves defining a list or array of fixed si…

  • Welcome!

    Years ago I had a blog and even one what was then called 'a homepage'. The past time I have mostly been sharing my thoughts and interests on Twitter but I have some ideas that would require more than 140 characters so I created this blog to crystallize them when ready.