<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tim talks tech]]></title><description><![CDATA[Tim talks tech]]></description><link>https://techblog.timhilton.xyz</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 14:58:51 GMT</lastBuildDate><atom:link href="https://techblog.timhilton.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Month in review: February 2026]]></title><description><![CDATA[Things that happened

I've installed https://github.com/johncmunson/claude-code-transcripts which is handy for copying formatted content from Claude Code into Obsidian. (I installed this rather than S]]></description><link>https://techblog.timhilton.xyz/feb-month-notes</link><guid isPermaLink="true">https://techblog.timhilton.xyz/feb-month-notes</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Tue, 03 Mar 2026 09:02:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/0a94d8c4-dfa7-4ad0-b8e8-0b0995600705.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Things that happened</h1>
<ul>
<li><p>I've installed <a href="https://github.com/johncmunson/claude-code-transcripts">https://github.com/johncmunson/claude-code-transcripts</a> which is handy for copying formatted content from Claude Code into Obsidian. (I installed this rather than Simon Willison's original version because I don't have python tooling installed.) I've used it a few times if I've wanted to copy something from the transcript and retain the formatting, and it's worked well so far.</p>
</li>
<li><p>The guy who has taken the lead on AI adoption at work was speaking to the whole company recently and I was really encouraged by some of what he was saying. It seems there is a bottom-up desire for transparency around when AI has been used, which I thought was a good sign of responsible usage. He was also quite positive about having varied adoption rates around the business, and happy for people to use AI as much or as little as they find helpful. I was glad of that attitude, as opposed to trying to push AI on people who don't find it useful. His emphasis was very much on making tools and training <em>available</em> to everyone, but leaving it up to individuals how helpful they find those tools while doing their work.</p>
</li>
</ul>
<h1>Things I learnt</h1>
<ul>
<li>I needed to update some data in a data model I wasn't familiar with. I used AI too much, and it took a long time to verify what AI produced. I ended up changing tack, and just using AI to find the relevant database tables. I then manually verified that no other tables were relevant by checking foreign keys, and manually worked out what the data change should be. It was definitely a case where using AI slowed things down.</li>
</ul>
<h1>Things I've been thinking about</h1>
<ul>
<li>With the coding agent space moving so quickly, there's always something new to try. It's impossible to keep on top of all the new developments. One impact of this is that the industry holds out the perpetual hope that salvation is just around the corner. Even if you hit frustrations actually using an agent for your work, a week later some new shiny <em>thing</em> will come out with the promise of making everything better. For example, I often vibe code <a href="https://www.timhilton.xyz/user-scripts">user scripts</a> (pieces of javascript which run in the browser when using a specified website, in order to customise its appearance or functionality). This is very hit–and–miss, presumably at least partly because the LLM agent has no way to verify whether the script is behaving as intended. Now there is a chrome extension for Claude which can be used by Claude Code to interact with the browser. This would probably make Claude better at this sort of work (although it also introduces security risks and I haven't yet read up on the mitigations which are in place, so I currently have no plans to install it). But it's another thing to install, another thing to try. It's <em>yet another</em> implicit message that the good stuff is just around the corner, and that even if you've found AI not to be useful you should try it again — and again, and again, and again, increasing your mental lock–in each time.</li>
</ul>
<h1>Things I've published</h1>
<ul>
<li><p><a href="https://techblog.timhilton.xyz/first-impressions-of-claude-code-after-using-github-copilot">First impressions of Claude Code after using GitHub Copilot</a></p>
</li>
<li><p><a href="https://techblog.timhilton.xyz/powershell-script-to-download-azure-devops-project-wiki">Powershell script to download Azure DevOps project wiki</a></p>
</li>
</ul>
<h1>Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Finding undeployed changes</p>
</li>
<li><p>TIL how PasswordHasher handles salt</p>
</li>
<li><p>Giving Claude Code readonly access to a database</p>
</li>
<li><p>TIL why dictionary lookups are O(1)</p>
</li>
<li><p>Claude Code forking and rewinding</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Powershell script to download Azure DevOps project wiki]]></title><description><![CDATA[Azure DevOps has two types of wikis:

Code wikis (Git-backed) - which you can clone

Project wikis (non-Git) - stored in Azure DevOps' internal storage


The Azure DevOps UI gives you the URL to clone]]></description><link>https://techblog.timhilton.xyz/powershell-script-to-download-azure-devops-project-wiki</link><guid isPermaLink="true">https://techblog.timhilton.xyz/powershell-script-to-download-azure-devops-project-wiki</guid><category><![CDATA[Powershell]]></category><category><![CDATA[azure-devops]]></category><category><![CDATA[wiki]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 27 Feb 2026 16:58:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/1b531860-35d9-45ca-b2e9-d626b2076b19.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Azure DevOps has two types of wikis:</p>
<ol>
<li><p><strong>Code wikis</strong> (Git-backed) - which you can clone</p>
</li>
<li><p><strong>Project wikis</strong> (non-Git) - stored in Azure DevOps' internal storage</p>
</li>
</ol>
<p>The Azure DevOps UI gives you the URL to clone a code wiki locally, but does not provide a way to download a project wiki. Using Claude, I vibe coded a powershell script to download a project wiki. I’ve tested it only once and although it worked for my wiki, I can’t guarantee it generalises well to all wikis.</p>
<p>It requires a PAT token. You can create these from <a href="https://dev.azure.com/%7BYour_Organization%7D">https://dev.azure.com/{Your_Organization}/_usersSettings/tokens</a>. The only permission necessary is <code>Wiki (Read)</code>. When adding a new PAT token, you'll need to click Show All Scopes then scroll to the bottom of the list to find it.</p>
<h1>The script</h1>
<p>For some reason, Hashnode (the platform which powers this blog) has messed up the formatting of this powershell script and tried to escape lots of characters. There shouldn't be any backslash characters (<code>\</code>) in the script, so if you remove all of them then it should work.</p>
<pre><code class="language-powershell">$org = "your-org"
$project = "your-project"
$wikiId = "your-wiki-id"
$pat = "your-personal-access-token"

Write-Host "Starting wiki backup..." -ForegroundColor Green

\(base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":\)pat"))
\(headers = @{Authorization = "Basic \)base64AuthInfo"}

# Get all pages
\(pagesUrl = "https://dev.azure.com/\)org/\(project/_apis/wiki/wikis/\)wikiId/pages?recursionLevel=full&amp;api-version=7.0"
Write-Host "Fetching pages from: $pagesUrl" -ForegroundColor Cyan

try {
    \(result = Invoke-RestMethod -Uri \)pagesUrl -Headers $headers
    Write-Host "Wiki structure retrieved" -ForegroundColor Green
} catch {
    Write-Host "Error fetching pages: $_" -ForegroundColor Red
    exit
}

# Function to recursively process pages
function Process-WikiPage {
    param($page)
    
    # Skip the root page (path = "/")
    if ($page.path -ne "/") {
        Write-Host "Downloading: \((\)page.path)" -ForegroundColor Yellow
        \(pageUrl = "https://dev.azure.com/\)org/\(project/_apis/wiki/wikis/\)wikiId/pages?path=\((\)page.path)&amp;includeContent=true&amp;api-version=7.0"
        
        try {
            \(content = Invoke-RestMethod -Uri \)pageUrl -Headers $headers
            
            # Save to file
            \(filePath = "wiki-backup\)($page.path).md"
            \(directory = Split-Path \)filePath -Parent
            if (\(directory -and !(Test-Path \)directory)) {
                New-Item -Path $directory -ItemType Directory -Force | Out-Null
            }
            \(content.content | Out-File -FilePath \)filePath -Encoding UTF8
            Write-Host "Saved: $filePath" -ForegroundColor Green
        } catch {
            Write-Host "Error downloading \((\)page.path): $_" -ForegroundColor Red
        }
    }
    
    # Process subpages recursively
    if (\(page.subPages -and \)page.subPages.Count -gt 0) {
        foreach (\(subPage in \)page.subPages) {
            Process-WikiPage -page $subPage
        }
    }
}

# Start processing from the root
Process-WikiPage -page $result

Write-Host "Backup complete!" -ForegroundColor Green
</code></pre>
]]></content:encoded></item><item><title><![CDATA[First impressions of Claude Code after using GitHub Copilot]]></title><description><![CDATA[Background
I’m a long-time user of GitHub Copilot as a professional programmer, as my employer gave me access when we first started trialling its use in our company. I’ve used it mainly through Rider, which is the IDE I generally prefer, although I h...]]></description><link>https://techblog.timhilton.xyz/first-impressions-of-claude-code-after-using-github-copilot</link><guid isPermaLink="true">https://techblog.timhilton.xyz/first-impressions-of-claude-code-after-using-github-copilot</guid><category><![CDATA[claude-code]]></category><category><![CDATA[claude.ai]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[copilot]]></category><category><![CDATA[agentic AI]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Tue, 03 Feb 2026 14:00:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769678312304/8a7fdf31-3386-4e9f-ae69-a1450397ebde.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-background">Background</h1>
<p>I’m a long-time user of GitHub Copilot as a professional programmer, as my employer gave me access when we first started trialling its use in our company. I’ve used it mainly through Rider, which is the IDE I generally prefer, although I have used Copilot in both Visual Studio and VS Code as well to a lesser extent.</p>
<p>A week or two ago I was given access to Claude Code as well, so I’ve been using it fairly heavily for some upgrades I’ve been working on. It’s not a piece of work I’ve chosen to be representative of my normal workflow, it’s just what I’ve happened to be working on, but it’s been interesting to compare and contrast Claude Code with GitHub Copilot.</p>
<p>Here are my initial thoughts (which are, of course, all subject to change over time).</p>
<h1 id="heading-planning">Planning</h1>
<p>The single feature which has most impressed me has been Claude Code’s plan mode. Plans are very thorough and clear, and the default behaviour is to clear context before implementing the plan, which makes sense to me. It’s nice to have written plans without the overhead of managing all the markdown files containing the plans, as Claude does it for you. They are just saved to disk, so you can find the plans and copy them elsewhere if you want to.</p>
<p>Claude does take a long time to write plans, so in that sense I suspect it's slower than Copilot. It results in high quality stuff though. This may also be down to a difference in which model is being used, I haven’t really paid attention to the models too much. I tend to default to Claude Sonnet 4.5 in Copilot to try and balance a powerful model with a low quota usage. Claude Code is using Opus 4.5 most of the time, so this difference may well be the model rather than the method of interacting with it. I suppose the more significant difference is how my model selection has been shaped by the defaults built into each product, and the way that usage quotas are determined. Even if this is an unfair comparison when looking narrowly at what each product <em>can</em> do with the same model, I think it’s a fair comparison of how I have <em>actually</em> used the two products while trying to get work done.</p>
<p>I love the commit messages which Claude Code writes. Again this may be because it defaults to using Opus rather than Sonnet, but they’re very clear and contain a lot of detail. I’ve already benefited from this, searching my commit history for 'Google' when a Google maps integration broke, and immediately finding the commit which broke it.</p>
<h1 id="heading-ui">UI</h1>
<p>The biggest surprised for me has been how much I enjoy the Claude Code UI. I <em>should</em> prefer Copilot. I like having everything in a single IDE and I generally prefer GUIs to CLIs, yet I still prefer Claude Code to Copilot. Admittedly Copilot doesn’t have the best support in Rider, Microsoft have clearly prioritised adding features to Copilot in VSCode rather than in their Rider plugin, but this has still been a surprise to me. Claude Code somehow seems well thought through in way that Copilot doesn’t. I would struggle to articulate the specific features which have given me this impression, but it’s a surprisingly strong impression. Copilot feels a bit clunky, whereas Claude Code feels enjoyable.</p>
<p>I think one advantage of Claude Code (and presumably the other agentic coding CLI tools) is that they are consistent regardless of what IDE a developer prefers, whereas Copilot is very different in VSCode / VS / Rider (and presumably also other IDEs), depending on where Microsoft are up to with implementing new features in the relevant plugin. I get the impression VSCode leads the pack in terms of getting new copilot features, then other IDEs may or may not get the same features later, whereas a CLI tool gives everyone access to new features at the same time.</p>
<p>When I want to copy the agent’s output and paste it elsewhere, I’ve found that it’s easier to copy from Claude Code than the Copilot plugin in Rider. It seems like very simple functionality, but the formatting always seems to get messed up when copying from Copilot in Rider (and I would like a button to copy a response with a single click, though I appreciate that in agent mode it would be a little ambiguous exactly which messages should be included).</p>
<p>Claude Code is good for working with long prompts. The Copilot UI in Rider struggles with this, and normal keyboard shortcuts for navigating around a long piece of text don’t always work as expected. Claude Code has the shortcut CTRL+G to open the prompt in a separate text editor without disrupting the workflow at all, giving you full access to whatever text editing tooling you’re used to while writing prompts. I have found this very helpful. The same shortcut works when reviewing a plan produced by Claude Code, so you don’t have to read it in the terminal window or manually copy the plan elsewhere.</p>
<p>I prefer Claude Code’s approach to approving file changes and command line tools. Claude Code has 3 modes — plan mode (in which no files can be edited), auto–edit mode (in which all project files can be edited), and default (in which the user is prompted to approve edits to files). There’s a keyboard shortcut to cycle through them, making it very easy to allow Claude to make extensive changes when you want it to. Copilot (in Rider) doesn’t seem to have the option to auto–approve file edits, and the nearest setting I could find is to auto–approve after a short delay. As far as I can tell, you have to open the settings window every time you want to turn this on or off, which introduces much more friction than Claude Code.</p>
<p>Similarly, Copilot (in Rider) manages tool approval via the settings window. To be honest I’m not super confident with how (or if) it works, I’ve set up various approvals but still get asked for approval for those tool calls. Claude Code makes it really easy to approve specific commands without breaking flow, as the approval is done inline with the rest of the conversation. By default this is saved to <code>.claude/settings.local.json</code> in the directory where you are running Claude, but it’s also possible to save these settings to the <code>.claude/settings.json</code> in your user directory if you want them to apply to all directories (e.g. if you’re happy for claude to run <code>git log</code> in one project, you’re probably happy for it to run <code>git log</code> in all projects).</p>
<p>Copilot wants you to approve changes to files, but it’s already made the changes so they may have been picked up by external tools. You might build on top of them but the codebase is in a weird limbo state until you accept/reject the changes. This is disruptive to the workflow, and can cause code to be reverted unexpectedly if the approval/rejection comes a while later. I think it also causes Copilot to get confused when running <code>git add</code> or <code>git commit</code> sometimes. I’ve used auto-approve mode for Claude Code when I’m ready for it to make changes, and this has been a much smoother workflow.</p>
<p>Copilot has a nasty habit of opening multiple terminals in Rider, especially if it’s not getting the results it expects from the commands its running. It seems to like opening a new terminal to ensure it has a clean slate, but it doesn’t tidy up after itself by closing them again. Claude Code, of course, already runs in a terminal, so when it executes commands it doesn’t need to open a terminal elsewhere, keeping everything clean. Ironically, one of the advantages of Claude Code is that, being a CLI tool, it’s easy to run multiple instances in different directories. I’ve found this helpful for asking questions of a codebase without opening it in an IDE, something which Copilot can’t do.</p>
<p>Possibly the only thing (so far) that I’ve found I prefer in the Copilot UI is the ability to add files to the prompt. I find the UI somehow more intuitive than using <code>@</code> in Claude Code.</p>
<h1 id="heading-frustrations">Frustrations</h1>
<p>As I suspect is common to pretty much all LLM tools, Claude Code is sometimes prone to going off on strange tangents and being useless. My impression is that it does this less than GitHub Copilot, but still more than I’d like. It can waste a lot of time ‘thinking’ before reaching a useless conclusion.</p>
<p>Also, when I use Claude Code via windows command prompt it keeps creating <code>nul</code> files. If that happens to you, there are instructions for deleting them at <a target="_blank" href="https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code">https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code</a>.</p>
<h1 id="heading-concerns">Concerns</h1>
<p>These are my main concerns about the impact of using Claude Code:</p>
<ol>
<li><p>Will I stop learning? This is a broader concern about the use of LLMs generally, but I think it’s even more pronounced for Claude Code. The workflow around planning then implementing is great, but it doesn’t have a space for learning. Of course, you can still use Claude Code in others ways for learning, but it’s not baked into that (otherwise very helpful) workflow. I found that Copilot, lacking an obvious workflow, is easier to ask questions while in the flow of making other changes, blending a mixture of learning and implementing at the same time.</p>
</li>
<li><p>Is it too fun? Will I waste time playing around rather than doing useful work? There’s no denying that Claude Code feels to me like magic in a way that GitHub Copilot doesn’t, and I have no idea why that is!</p>
</li>
<li><p>As with all LLM tools, I am wary of the danger that the tool will feel fast but actually take longer than doing the work myself.</p>
</li>
</ol>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I am aware that Claude Code isn’t the only CLI for agentic coding, but I’ve not played around with Gemini CLI / Copilot CLI / any others, so I don’t know how much my experiences are related to Claude Code itself, and how much they apply more generally to CLI agents.</p>
<p>I think the fact I’ve been working on upgrades recently has played in favour of Claude Code. AI tools are generally most impressive when working with a topic which is well documented online, but about which you don’t know too much. That gives much more room for them to impress you than a topic in which you are already well–versed. Some of the upgrades I’ve been doing have been in this territory, so I suspect my opinions may change as I use Claude Code for a more diverse set of tasks over time, some of which fall more within my technical comfort zone.</p>
<p>Having said that, so far it’s been a great tool that I’ve enjoyed using, and it has replaced GitHub Copilot as my go–to coding agent. I don’t know how my AI use will evolve, but I may use Claude Code for planning and implementing bigger changes, Claude web view or GitHub Copilot for more general research and learning, and Copilot for quick inline things in my IDE.</p>
<p>If you’ve used Claude Code, how do you experiences fit with what I’ve described above?</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: January 2026]]></title><description><![CDATA[Things that happened

From a technical point of view, the main thing that happened in January is that I got access to Claude Code and have been playing around with that. I hope to write up my thoughts soon.

Things I learnt

I’ve published a number o...]]></description><link>https://techblog.timhilton.xyz/month-in-review-january-2026</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-january-2026</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 02 Feb 2026 17:45:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/TGeFx4x4NHU/upload/d9d7c8626cd7ad854ab15892943de625.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li>From a technical point of view, the main thing that happened in January is that I got access to Claude Code and have been playing around with that. I hope to write up my thoughts soon.</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li>I’ve published a number of short Today I Learnt blog posts. I’ll link to them below so won’t repeat them here.</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://codemanship.wordpress.com/2025/12/30/the-ai-ready-software-developer-18-productivity-you-keep-using-that-word/">The AI-Ready Software Developer #18 – “Productivity”. You Keep Using That Word. – Codemanship's Blog</a></p>
<ul>
<li>This points out the misaligned incentives in the software industry, which I've noticed over the course of my career so far, and applies the insights to the impact of AI coding.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://codemanship.wordpress.com/2026/01/10/walking-skeletons-devops-drills/">Walking Skeletons, Delivery Pipelines &amp; DevOps Drills – Codemanship's Blog</a></p>
<ul>
<li>I love the idea of deliberately practicing starting new projects. I'm comfortable with the DevOps aspects of this but have long been aware I have never set up authentication from scratch on a greenfield project (though I have made substantial changes to existing authentication, like changing to a different authentication provider). I can imagine there could be a few things like that which I tend to take for granted, and might take a bit more effort than I'd expect if I were to create something substantial from scratch.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://ploum.net/2026-01-19-exam-with-chatbots.html">Giving University Exams in the Age of Chatbots</a></p>
<ul>
<li><p>This is a very interesting approach, allowing LLMs but giving clear rules about accountability.</p>
</li>
<li><p>Learning was, in this case, inversely correlated with LLM usage. This seems like bad news for me and my career (and other developers who have leaned into using LLM coding agents). I need to think more about this. What's the smart use of LLMs for me to ensure I still learn and stay sharp over the long term?</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-installing-a-net-sdk-can-break-net-maui-builds">TIL installing a .NET SDK can break .NET MAUI builds</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-rider-can-show-a-diff-of-a-directory-between-two-branches">TIL Rider can show a diff of a directory between two branches</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-the-format-for-pasting-environment-variables-into-a-rider-run-configuration">TIL the format for pasting environment variables into a Rider run configuration</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-c-property-overrides-are-separate-for-getters-and-setters">TIL C# property overrides are separate for getters and setters</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code">Deleting <code>nul</code> files created in error by Claude code</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/finding-a-bug-by-checking-git-history-one-commit-at-a-time">Finding a bug by checking git history one commit at a time</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-about-typescript-typing-as-const">TIL about typescript typing <code>as const</code></a></p>
</li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>First impressions of Claude Code after using GitHub Copilot</p>
</li>
<li><p>TIL why C# classes sometimes have multiple Dispose methods</p>
</li>
<li><p>TIL how to get a git diff between 2 branches within a folder</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL about typescript typing `as const`]]></title><description><![CDATA[I knew that typescript supports a type being a specific string, rather than the string type, so (for example) a function parameter can only receive the string “foo” and not a different string. Today I learnt that this can be done by using the as cons...]]></description><link>https://techblog.timhilton.xyz/til-about-typescript-typing-as-const</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-about-typescript-typing-as-const</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 28 Jan 2026 13:09:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/pXjpJhdOSdk/upload/33cfea943a3fe46eef6158d9da215dfb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I knew that typescript supports a type being a specific string, rather than the <code>string</code> type, so (for example) a function parameter can only receive the string “foo” and not a different string. Today I learnt that this can be done by using the <code>as const</code> syntax.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Foo {
  <span class="hljs-comment">// prop1 is typed as string</span>
  <span class="hljs-keyword">static</span> prop1 = <span class="hljs-string">'foo'</span>;

  <span class="hljs-comment">// prop2 is typed as 'foo'</span>
  <span class="hljs-keyword">static</span> prop2 = <span class="hljs-string">'foo'</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;

  <span class="hljs-keyword">static</span> func1 = <span class="hljs-function">(<span class="hljs-params">input: <span class="hljs-keyword">typeof</span> Foo.prop1</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Input was <span class="hljs-subst">${input}</span>`</span>);
  <span class="hljs-keyword">static</span> func2 = <span class="hljs-function">(<span class="hljs-params">input: <span class="hljs-keyword">typeof</span> Foo.prop2</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Input was <span class="hljs-subst">${input}</span>`</span>);
}

Foo.func1(<span class="hljs-string">'bob'</span>); <span class="hljs-comment">// works fine</span>
Foo.func2(<span class="hljs-string">'bob'</span>); <span class="hljs-comment">// Argument of type '"bob"' is not assignable to parameter of type '"foo"'.</span>
</code></pre>
<p>However, calling <code>typeof</code> will still return <code>'string'</code> rather than <code>'foo'</code>. That’s because using <code>as const</code> only affects how typescript checks types, not the javascript output which is produced from the typescript source code.</p>
]]></content:encoded></item><item><title><![CDATA[Finding a bug by checking git history one commit at a time]]></title><description><![CDATA[I’m far from a command line wizard, but am gradually picking up more tricks and tips as time goes by.
I recently found a styling bug I was confident I’d introduced in the previous few commits, but I wasn’t sure which one. In the past I’ve used git bi...]]></description><link>https://techblog.timhilton.xyz/finding-a-bug-by-checking-git-history-one-commit-at-a-time</link><guid isPermaLink="true">https://techblog.timhilton.xyz/finding-a-bug-by-checking-git-history-one-commit-at-a-time</guid><category><![CDATA[command line]]></category><category><![CDATA[Git]]></category><category><![CDATA[Bugs and Errors]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Tue, 27 Jan 2026 10:40:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/iLrMmnIL8x4/upload/b4c2524a6b482a8efad6508b2695e072.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’m far from a command line wizard, but am gradually picking up more tricks and tips as time goes by.</p>
<p>I recently found a styling bug I was confident I’d introduced in the previous few commits, but I wasn’t sure which one. In the past <a target="_blank" href="https://techblog.timhilton.xyz/how-to-find-buggy-code-using-git-bisect">I’ve used git bisect</a> but on this occasion I took a different approach. I knew I wouldn’t have to go back many commits, but I wasn’t sure how far back to go in order to be confident of finding working code (which is necessary for git bisect). I decided to go back through my git history one commit at a time and test each time. The bug was in a vue app and I wasn’t confident whether or not hot reloading would work given the nature of the changes, so I stopped the app each time and served it again.</p>
<p>The approach I took was to simply run the following command repeatedly, testing the app each time:</p>
<pre><code class="lang-bash">git checkout HEAD~1; npm run serve
</code></pre>
<p>This checks out the previous commit (which is what <code>HEAD~1</code> means) then runs the <code>serve</code> script from the project’s <code>package.json</code> file. While the bug was still present, I simply stopped the script and reran it which moved me back again to the previous commit.</p>
<p>I don’t often use the <code>HEAD~1</code> syntax in git but I’m becoming more familiar and confident with it, and finding more occasions where it’s useful to me. I’m also becoming gradually more confident combining commands using <code>;</code>, and this was a good example of a case when even a short time ago I wouldn’t have been able to do this so simply.</p>
]]></content:encoded></item><item><title><![CDATA[Deleting `nul` files created in error by Claude code]]></title><description><![CDATA[I’ve recently been given access to Claude Code at work, so I’ve been trying it out to see how I get on with it. I tend to run it from a Windows Command Prompt, and I’ve noticed that it keeps creating files named nul with 0KB size. Worse, when I try t...]]></description><link>https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code</link><guid isPermaLink="true">https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code</guid><category><![CDATA[claude-code]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Command prompt]]></category><category><![CDATA[command line]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Sat, 24 Jan 2026 15:25:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HjBcAVWlxnE/upload/51231dc434290cda481f3d5d7d35e64c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’ve recently been given access to Claude Code at work, so I’ve been trying it out to see how I get on with it. I tend to run it from a Windows Command Prompt, and I’ve noticed that it keeps creating files named <code>nul</code> with 0KB size. Worse, when I try to delete them I have to provide admin credentials, and even as an admin the file isn’t actually deleted and reappears after refreshing Windows Explorer.</p>
<p>Claude Code sometimes runs commands which contain something along the lines of <code>&gt; ./nul</code>, which I assume does something meaningful in Bash but not in Windows Command Prompt. Windows creates a file instead of whatever the intended behaviour is. Something about the filename <code>nul</code> means the normal Windows operations for deleting a file can’t be used. So how can I get rid of the file?</p>
<p>Happily, once I explained the problem to Claude, it gave me a Windows Command Prompt command to delete the file:</p>
<pre><code class="lang-bash">del <span class="hljs-string">"\\?\%CD%\nul"</span>
</code></pre>
<p>This command needs running in the same directory as the <code>nul</code> file.</p>
<p>Apparently, the <code>\\?\</code> prefix bypasses Windows' normal checks for reserved filenames, allowing you to directly access and delete the <code>nul</code> file. Admin permissions are not required. I’ve updated Claude’s instructions to try and avoid it creating more of these <code>nul</code> files in the future, but I suppose I’ll need to wait a while to see how that turns out!</p>
]]></content:encoded></item><item><title><![CDATA[TIL C# property overrides are separate for getters and setters]]></title><description><![CDATA[I recently hit an interesting gotcha with some code in a C# codebase i was working with. It baffled me because I didn’t understand how this could compile.
MyClass.Foo has a getter but no setter, yet an instantiated MyClass can have the Foo property s...]]></description><link>https://techblog.timhilton.xyz/til-c-property-overrides-are-separate-for-getters-and-setters</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-c-property-overrides-are-separate-for-getters-and-setters</guid><category><![CDATA[C#]]></category><category><![CDATA[override]]></category><category><![CDATA[getter and setter]]></category><category><![CDATA[TIL]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Sat, 24 Jan 2026 15:17:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_BBZMuDnOPQ/upload/c796fb3e51034c085134b5aed4df6a81.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently hit an interesting gotcha with some code in a C# codebase i was working with. It baffled me because I didn’t understand how this could compile.</p>
<p><code>MyClass.Foo</code> has a getter but no setter, yet an instantiated <code>MyClass</code> can have the <code>Foo</code> property set! How is that happening, and what does it do?</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span> : <span class="hljs-title">LibraryClass</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> OtherProperty { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">string</span> Foo =&gt; OtherProperty; <span class="hljs-comment">// getter-only, no way to set the value</span>
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DoThing</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> myClass = <span class="hljs-keyword">new</span> MyClass
        {
            <span class="hljs-comment">// How does this compile? There is no setter for Foo.</span>
            Foo = <span class="hljs-string">"I'm setting this property"</span>
        };
    }
}
</code></pre>
<p>It turns out that even though the <code>Foo</code> property only has a getter defined within <code>MyClass</code>, there’s a setter on the <code>Foo</code> property within <code>LibraryClass</code>, and this means it’s valid to write to the property within <code>MyService</code>.</p>
<p>The reason is that the <code>override</code> keyword is only overriding the getter, not the whole property. The setter therefore still exists in its original form, and can be used. What this does it write the set value to the backing field, but it’s not possible to get that value back out and do anything with it. It’s not useful, but it is valid and it does compile.</p>
]]></content:encoded></item><item><title><![CDATA[TIL the format for pasting environment variables into a Rider run configuration]]></title><description><![CDATA[Summary
I was editing a run configuration in Rider and needed to add several environment variables to it. There’s a button in the dialogue to paste them in, but no guidance regarding the format of the data, and no feedback if you paste the wrong form...]]></description><link>https://techblog.timhilton.xyz/til-the-format-for-pasting-environment-variables-into-a-rider-run-configuration</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-the-format-for-pasting-environment-variables-into-a-rider-run-configuration</guid><category><![CDATA[#rider]]></category><category><![CDATA[jetbrains rider]]></category><category><![CDATA[Environment variables]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 14 Jan 2026 14:20:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bw8iOoOzjc0/upload/92afa526c213118e3aebf4c34fd4e14a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-summary">Summary</h1>
<p>I was editing a run configuration in Rider and needed to add several environment variables to it. There’s a button in the dialogue to paste them in, but no guidance regarding the format of the data, and no feedback if you paste the wrong format.</p>
<h1 id="heading-what-is-a-run-configuration">What is a run configuration?</h1>
<p>Rider allows you to create run configurations, which can be selected from a dropdown and have Run/Debug/Stop buttons next to them. When you open a solution, Rider populates these with several defaults depending on the types of projects in your solution, but you can edit these and add more of your own. It’s this section of the UI:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768400152415/e0619f4e-f4f6-4ac0-a294-34e810c9a070.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-how-to-define-environment-variables">How to define environment variables</h1>
<p>In my case, the relevant project was an Azure function. Editing the run configuration for it, there is a field for Environment Variables. You can type directly into this textbox, but if you click the icon on the right then you can add them as Name/Value pairs, and there’s an icon for pasting the data in.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768400365468/3987f93f-b78a-4811-98aa-7754fbfee3f4.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-what-format-to-use">What format to use</h1>
<p>To paste environment variables into the run configuration, you need your variables in this format:</p>
<pre><code class="lang-plaintext">ThingEnabled=true;MySetting=foo;OtherSetting=bar
</code></pre>
<p><a target="_blank" href="https://www.jetbrains.com/help/rider/Run_Debug_Configuration.html#envvars-progargs">https://www.jetbrains.com/help/rider/Run_Debug_Configuration.html#envvars-progargs</a> does hint at this format. It says “In the Environment variables field, type the variable name and value: <code>&lt;name&gt;=&lt;value&gt;</code>. If you add several variables, they should be separated with semicolons.” but doesn’t mention pasting so it’s easy to miss. More significantly, there’s no guidance within the IDE so you have to go looking for the documentation to find out the format.</p>
]]></content:encoded></item><item><title><![CDATA[TIL Rider can show a diff of a directory between two branches]]></title><description><![CDATA[Today I learnt that you can right–click on any project or directory within the Solution panel, and under the Git menu there is the option to Compare with Branch or Tag (or a separate option to Compare with Revision). This allows you to easily find al...]]></description><link>https://techblog.timhilton.xyz/til-rider-can-show-a-diff-of-a-directory-between-two-branches</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-rider-can-show-a-diff-of-a-directory-between-two-branches</guid><category><![CDATA[jetbrains rider]]></category><category><![CDATA[#rider]]></category><category><![CDATA[Git]]></category><category><![CDATA[Diff]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 14 Jan 2026 11:30:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KFJSGahF6hg/upload/22e671c829f2416f0bb9c4848f2245e7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I learnt that you can right–click on any project or directory within the Solution panel, and under the Git menu there is the option to Compare with Branch or Tag (or a separate option to Compare with Revision). This allows you to easily find all changes between two branches within a specific folder.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768389953657/6e80cdd9-999a-491e-86cc-043e5743a038.png" alt class="image--center mx-auto" /></p>
<p>Clicking this opens a new panel containing the list of changed files, and clicking on the files shows the diffs in the same UI as other diffs within Rider.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768390067867/51d58c1a-5afd-4372-81cf-683dbab3bd98.png" alt class="image--center mx-auto" /></p>
<p>I always like to find new features and tools which I already have access to. This feature was useful for me today, and I daresay it will be useful again.</p>
<p>As an aside, this is the git command to get a diff of all changes within a specified directory on the current branch since it diverged from <code>develop</code>.</p>
<pre><code class="lang-bash">git diff develop...HEAD -- Path/To/Directory
</code></pre>
<p>If there’s a lot, you can append <code>| clip</code> to copy the output to your clipboard, or append <code>&gt; diff.txt</code> to put it in a new text file.</p>
]]></content:encoded></item><item><title><![CDATA[TIL installing a .NET SDK can break .NET MAUI builds]]></title><description><![CDATA[Introduction
I was flummoxed when working with a .NET MAUI app when I opened the application and it wouldn’t build. I had previously worked on it a month or so ago and had set everything up on my laptop so it would build, yet without any code changes...]]></description><link>https://techblog.timhilton.xyz/til-installing-a-net-sdk-can-break-net-maui-builds</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-installing-a-net-sdk-can-break-net-maui-builds</guid><category><![CDATA[#maui]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[claude.ai]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 12 Jan 2026 09:37:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/uh0u8OH4zuE/upload/47b6b8472267a2c77cc5e90044be5ff6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>I was flummoxed when working with a .NET MAUI app when I opened the application and it wouldn’t build. I had previously worked on it a month or so ago and had set everything up on my laptop so it would build, yet without any code changes there were suddenly 5 build errors.</p>
<p>After a lot of time wasted trying to fix the problem, I eventually realised the key piece of information I hadn’t considered — the previous day, I had installed the .NET 10 SDK on my laptop for the first time. This broke the build for my .NET MAUI app, and this blog post explains why that happened. At the end, I reflect on my use of AI in solving this problem, and how it both helped and hindered.</p>
<h1 id="heading-build-errors">Build errors</h1>
<p>I got 5 build errors, two of which were basically the same (<code>NETSDK1202</code> for two different workloads).</p>
<blockquote>
<pre><code class="lang-plaintext">9&gt;Microsoft.NET.EolTargetFrameworks.targets(38,5): Error NETSDK1202 : The workload 'net8.0-android' is out of support and will not receive security updates in the future. Please refer to https://aka.ms/maui-support-policy for more information about the support policy.
9&gt;ProjectName.App.csproj: Error NU1012 : Platform version is not present for one or more target frameworks, even though they have specified a platform: net8.0-android, net8.0-ios
9&gt;ProjectName.App.csproj: Error NU1015 : The following PackageReference item(s) do not have a version specified: Microsoft.Maui.Controls, Microsoft.Maui.Controls.Compatibility
9&gt;Microsoft.NET.EolTargetFrameworks.targets(38,5): Error NETSDK1202 : The workload 'net8.0-ios' is out of support and will not receive security updates in the future. Please refer to https://aka.ms/maui-support-policy for more information about the support policy.
9&gt;Microsoft.NET.TargetFrameworkInference.targets(252,5): Error NETSDK1135 : SupportedOSPlatformVersion 11.0 cannot be higher than TargetPlatformVersion 1.0.
</code></pre>
</blockquote>
<h1 id="heading-explanation">Explanation</h1>
<p>At the root of my solution was a <code>global.json</code> file which looked like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"sdk"</span>: {
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"8.0.0"</span>,
    <span class="hljs-attr">"rollForward"</span>: <span class="hljs-string">"latestMajor"</span>,
    <span class="hljs-attr">"allowPrerelease"</span>: <span class="hljs-literal">false</span>
  }
}
</code></pre>
<p>The application was using .NET MAUI 8, which is why <code>version</code> is set to 8.0.0. However, it uses <code>"rollForward": "latestMajor"</code>. This means it uses the latest .NET SDK which is installed. Installing the .NET 10 SDK effectively changed what version the application is using. Using the later version, the dotnet workloads which the MAUI project used weren’t compatible.</p>
<p>Running <code>dotnet workload restore</code> installed workloads which were compatible with .NET 10, but that broke things in the project because it’s not yet upgraded to .NET 10.</p>
<h1 id="heading-solution">Solution</h1>
<p>Once I understood this problem, the fix was a simple change to the json. I used <code>"rollForward": "latestFeature"</code> instead, which means it uses the latest version of v8, but doesn’t upgrade to later major versions. Once I’d cleaned the output directories, the build then ran as it had before I’d installed the .NET 10 SDK and passed.</p>
<h1 id="heading-lessons-about-using-ai">Lessons about using AI</h1>
<p>I used AI tools in trying to fix this problem, because to begin with I had no idea what was wrong. AI was both a help and a hindrance, but definitely more of a hindrance overall. Because I was out of my comfort zone, I was too slow to abandon the use of AI even though I could see it wasn’t making any progress.</p>
<p>I started by trying to get GitHub Copilot to fix the build errors. Unfortunately it dug itself into a hole making unsuitable changes, and couldn’t get out of it. It ran the build repeatedly, seemingly unable to believe the build was still broken, and determined to think that it could fix them by clearing package caches one more time. With hindsight, I wonder if GitHub Copilot, as a coding agent, has been biased toward action too much for this problem. It failed to do any diagnosis, and because I didn’t realise what had caused the problem I wasn’t able to provide that information.</p>
<p>I had much more success asking Claude (via the web chat interface) about the errors. It’s hard to say how much the difference was caused by using Claude rather than Copilot, as by this point I’d realised the possibility that the .NET SDK installation was the root cause, and this was critical information. Either way, it was able to explain the root cause and how to fix it, and was much more useful.</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: December 2025]]></title><description><![CDATA[Not much this month, as it's been a busy month outside of technical thinking.
Things that happened

I launched my website — https://www.timhilton.xyz/. It's vibe–coded slop, but it gives me a dumping ground for random bits and bobs. It's mostly techn...]]></description><link>https://techblog.timhilton.xyz/month-in-review-december-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-december-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 31 Dec 2025 21:38:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5AiWn2U10cw/upload/c68b162a6355d1d8205bb569411e9c81.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Not much this month, as it's been a busy month outside of technical thinking.</p>
<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li>I launched my website — <a target="_blank" href="https://www.timhilton.xyz/">https://www.timhilton.xyz/</a>. It's vibe–coded slop, but it gives me a dumping ground for random bits and bobs. It's mostly technical at the moment, though I may find time for putting other things on it in the future.</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://lyra.horse/blog/2024/05/stealing-your-telegram-account-in-10-seconds-flat/">Stealing your Telegram account in 10 seconds flat Ʊ lyra's epic blog</a></p>
<ul>
<li>It feels magical that there are no images on this blog post, even though there are (what appear to be) screenshots. Each one is actually handcrafted HTML &amp; CSS, which is mindblowing! As Teller (of Penn and Teller fame) said, “Sometimes magic is just someone spending more time on something than anyone else might reasonably expect.”</li>
</ul>
</li>
<li><p><a target="_blank" href="https://mikelovesrobots.substack.com/p/wheres-the-shovelware-why-ai-coding">Where's the Shovelware? Why AI Coding Claims Don't Add Up</a></p>
<ul>
<li>I thought this was a helpfully evidence–based analysis of LLM coding. It's inspired me to try and track a little more objectively what impact using an LLM has on my own productivity. I've often thought it's unclear if the overall impact is positive or negative for me, though there are definitely <em>some</em> tasks which are far faster with an LLM. I don't expect to completely abandon using LLMs, but it's possible I may use them for fewer tasks or only specific tasks.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://codemanship.wordpress.com/2025/11/25/the-future-of-software-development-is-software-developers/">The Future of Software Development is Software Developers – Codemanship's Blog</a></p>
<ul>
<li>I can't remember what struck me about this, but I'm sharing it anyway 😅</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li>Nothing this month.</li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Claude fixing an image</p>
<ul>
<li>This was an interesting case of Claude fixing a problem which I would have had no idea how to approach.</li>
</ul>
</li>
<li><p>Sharing github copilot prompts across multiple IDEs</p>
</li>
<li><p>What keyboard shortcuts I use as a professional programmer</p>
<ul>
<li>I'm hoping to publish this at some point, but have only just started analysing what shortcuts I use most.</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Month in review: November 2025]]></title><description><![CDATA[Things that happened

I was working on an intermittent bug, trying to find the precise conditions which cause it by reading through code. I make notes in Obsidian as I go. I think I need to get better at creating summaries and headlines which clearly...]]></description><link>https://techblog.timhilton.xyz/month-in-review-november-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-november-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 05 Dec 2025 19:00:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/E-EEQSjDdck/upload/cf3da8bba7904c10ad4243f0d504968b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li><p>I was working on an intermittent bug, trying to find the precise conditions which cause it by reading through code. I make notes in Obsidian as I go. I think I need to get better at creating summaries and headlines which clearly communicate things I'm learning from the code. At the moment I'm good at recording all the details, and I'm good at creating overall summaries, but I don't do anything to create summaries in the middle. For example, perhaps the high level summary is that a piece of code uses a particular setting, and the detailed version lists all the method calls which the execution path takes. I could do with summaries of those code paths, saying things like 'this code gets this setting from the database' without spelling out how that works.</p>
</li>
<li><p>I've removed a few apps from running on Windows startup, and have instead written a batch script to open them. I run that script manually from a desktop shortcut and it opens the apps much faster than the Windows startup routine did. It was previously slow enough that I would sometimes be waiting 5–10 minutes for apps to open. Now they open in seconds.</p>
</li>
<li><p>I've started trying to consolidate my Keyboard Shortcuts across the different apps I commonly use.</p>
</li>
<li><p>My company has started holding in-person engineering discussions, and this month is the first time I was able to go to one. It was a good discussion, though I'll wait to see some concrete changes come out of the discussion before giving it an unqualified thumbs–up.</p>
</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li><p>I was surprised how badly Claude did trying to summarise 2 documents for me in preparation for a meeting. The process of going through the documents and creating my own summary was invaluable in preparing for the meeting, but until I'd done that I didn't know what information I wanted in the summary. Claude wasn't able to work it out, and also added (incorrect) information which wasn't in the documents.</p>
</li>
<li><p>I've twice asked GitHub Copilot to find the exact bit of code which did something, using Claude Sonnet 4.5 both times. I've been very impressed by the output — it has provided a markdown document with a lot of useful detail and code snippets, even though I hadn't specified any of this. I've not yet verified the accuracy of these documents, although (as always) they look plausible.</p>
</li>
<li><p>My company has started using Dependency Track for keeping on top of the libraries we depend on. I think it's a great idea, and it's a while since it was first suggested, so it's nice seeing it come to fruition. I knew nothing about it beyond the basic concept, but I was asked to set it up for one of our projects, so I had the chance to learn more about how it works.</p>
</li>
<li><p>A colleague wrote a SQL script using <code>OPENJSON</code> which I wasn't familiar with. It was interesting to see how this could be used to convert some JSON data into a table.</p>
</li>
<li><p>Azure DevOps pipelines can run based on a definition hosted in GitHub.</p>
</li>
<li><p>EF Core includes <a target="_blank" href="https://learn.microsoft.com/en-us/ef/core/querying/related-data/eager#filtered-include">Filtered Includes</a>. This has been available functionality for a while, but I wasn't aware of it. I sounds like a very useful performance improvement, and is definitely something I want to be mindful of when writing EF queries.</p>
</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://lukeplant.me.uk/blog/posts/why-im-not-letting-the-juniors-use-genai-for-coding/">Why I’m not letting the juniors use GenAI for coding -</a> <a target="_blank" href="http://lukeplant.me.uk">lukeplant.me.uk</a></p>
</li>
<li><p><a target="_blank" href="https://diataxis.fr/">Diátaxis</a> — A systematic approach to technical documentation authoring.</p>
<ul>
<li><p>I like this concept and the categories it creates.</p>
</li>
<li><p>I'm not keen on the use of Action, Cognition, Acquisition and Application. I find those terms too cerebral to be intuitive without more context. I think I prefer the ideas of 'working' vs 'learning', and 'understanding' vs 'doing'.</p>
</li>
<li><p>I'll definitely want to give this more thought in my professional life.</p>
</li>
<li><p>See also: <a target="_blank" href="http://documentation-writer.prompt.md">documentation-writer.prompt.md</a> <a target="_blank" href="https://github.com/github/awesome-copilot/blob/main/prompts/documentation-writer.prompt.md">· github/awesome-copilot</a> (which is where I came across this framework).</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-other-people-said">Things other people said</h1>
<p><em>Quote of the month</em></p>
<p>"My basic rule of thumb for LLMs is that I use them only in contexts where:</p>
<ul>
<li><p>accuracy and reliability does not matter (some "creative writing" type use cases), or,</p>
</li>
<li><p>the nature of the task forces me to immediately verify the accuracy, and doing so is easy (such as some software development uses)."</p>
</li>
</ul>
<p><a target="_blank" href="https://lukeplant.me.uk/blog/posts/should-we-use-llms-for-christian-apologetics/">Should we use AI and LLMs for Christian Apologetics? -</a> <a target="_blank" href="http://lukeplant.me.uk">lukeplant.me.uk</a></p>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><a target="_blank" href="https://tjhilton.hashnode.dev/til-rider-can-show-sql-results-inline-within-query">TIL: Rider can show SQL Results inline within query</a></li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>How to manage email templates in Outlook</p>
</li>
<li><p>Asking GitHub copilot to explain code and comparing different models</p>
</li>
<li><p>Opening my startup applications faster on Windows 11</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL: Rider can show SQL Results inline within query]]></title><description><![CDATA[I use JetBrains Rider as my primary IDE, and I like to use it for as much of my development process as possible. I prefer to avoid jumping around between multiple different applications if I can, so when I want to run some SQL I typically use Rider r...]]></description><link>https://techblog.timhilton.xyz/til-rider-can-show-sql-results-inline-within-query</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-rider-can-show-sql-results-inline-within-query</guid><category><![CDATA[#rider]]></category><category><![CDATA[jetbrains rider]]></category><category><![CDATA[SQL]]></category><category><![CDATA[IDEs]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 14 Nov 2025 11:01:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763118456807/224ed301-9987-4358-95aa-8c575bd9de98.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I use JetBrains Rider as my primary IDE, and I like to use it for as much of my development process as possible. I prefer to avoid jumping around between multiple different applications if I can, so when I want to run some SQL I typically use Rider rather than opening SSMS or Azure Data Studio (or the VS Code plugin which is replacing it).</p>
<p>Today I learnt that Rider contains an option to display the results of a query inline within the SQL window. I don’t think this will be my default way of viewing SQL results, I think I’ll stick with a table of data at the bottom of the window, but I can definitely see this being useful for debugging long queries by checking the results at each step of a lengthy process. I always like to know what tools are available even if I don’t have imminent plans to use them, because it opens up more possibilities for the future.</p>
<p>Details of how to enable this (either per–file or for all queries) are in the <a target="_blank" href="https://www.jetbrains.com/help/rider/Viewing_Query_Results.html#in_editor_results">official documentation</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: October 2025]]></title><description><![CDATA[A brief review this month. It’s gone by in a whirl!
Things that happened

I've spent the last few months doing some technical upgrades for a client. I've come to the end of that work and started working in our support department.

Things I learnt

I ...]]></description><link>https://techblog.timhilton.xyz/month-in-review-october-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-october-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 03 Nov 2025 18:10:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/i1gmjozst4s/upload/fa8a258231e05ee94f71a20e129d39b1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A brief review this month. It’s gone by in a whirl!</p>
<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li>I've spent the last few months doing some technical upgrades for a client. I've come to the end of that work and started working in our support department.</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li>I read a lot about the <code>Domain</code> and <code>SameSite</code> properties on cookies, as part of planning some work to change what subdomain an application is hosted on. Cookies are used between multiple applications which are all currently on the same domain, so I was reading up on the details of how browsers treat these cookies to ensure we don't break anything. I think I came away with a good understanding in the end, but I regret that I used an LLM for some of the research as it ended up being quite misleading. Happily I checked what it told me with human-written sources and found its errors, but I probably ended up spending longer clarifying my understanding than I would have needed to if I'd skipped the LLM and just done my research manually in the first place.</li>
</ul>
<h1 id="heading-things-other-people-said">Things other people said</h1>
<p><em>Quote of the month</em></p>
<p>“It’s also become clear to me that LLMs actively reward existing top tier software engineering practices<br />…<br />If you’re going to really exploit the capabilities of these new tools, you need to be operating <em>at the top of your game</em>.”<br /><a target="_blank" href="https://simonwillison.net/2025/Oct/7/vibe-engineering/">Vibe engineering</a></p>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><a target="_blank" href="https://tjhilton.hashnode.dev/installing-a-crt-file-as-a-trusted-root-certificate-in-windows-11-while-kleopatra-is-installed">Installing a <code>.crt</code> file as a Trusted Root Certificate in Windows 11 while Kleopatra is installed</a></li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Code reviewing out loud</p>
</li>
<li><p>Claude style for writing code review comments</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Installing a `.crt` file as a Trusted Root Certificate in Windows 11 while Kleopatra is installed]]></title><description><![CDATA[I was recently setting up a project which requires the installation of a .crt file as a Trusted Root Certificate for the Current User. The standard way of doing this is to right-click the file and select “Install Certificate”. However, I have Kleopat...]]></description><link>https://techblog.timhilton.xyz/installing-a-crt-file-as-a-trusted-root-certificate-in-windows-11-while-kleopatra-is-installed</link><guid isPermaLink="true">https://techblog.timhilton.xyz/installing-a-crt-file-as-a-trusted-root-certificate-in-windows-11-while-kleopatra-is-installed</guid><category><![CDATA[kleopatra]]></category><category><![CDATA[Certificates]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 15 Oct 2025 17:18:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ZdqSuxl3Lak/upload/0cd85a992d7d29324805b4f0d21c0341.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was recently setting up a project which requires the installation of a <code>.crt</code> file as a Trusted Root Certificate for the Current User. The standard way of doing this is to right-click the file and select “Install Certificate”. However, I have Kleopatra installed, and this removes the “Install Certificate” option from the context menu.</p>
<p>The workaround I found was as follows:</p>
<ol>
<li><p>Search the start menu for “Manage User Certificates” and select the option with that name.</p>
</li>
<li><p>Expand the “Trusted Root Certification Authorities” folder.</p>
</li>
<li><p>Right-click “Certificates”, hover over “All Tasks” then click “Import”.</p>
</li>
</ol>
<p>This opens a wizard which I followed to install the <code>.crt</code> file.</p>
<p>According to Claude (so I have no idea if this is true or not 😅):</p>
<blockquote>
<p>Kleopatra associates <code>.crt</code> files with GnuPG operations, which removes the "Install Certificate" context menu option.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Month in review: August / September 2025]]></title><description><![CDATA[Things that happened

I installed Linux Mint on my personal laptop. I know nothing about Linux but it's an old Windows 10 laptop which isn't capable of running Windows 11, and Windows 10 support of coming to an end. The installation was more effort t...]]></description><link>https://techblog.timhilton.xyz/month-in-review-august-september-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-august-september-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 08 Oct 2025 08:23:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/usC4K8aX0uY/upload/0014d25257052989b61100e1846c806f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li><p>I installed Linux Mint on my personal laptop. I know nothing about Linux but it's an old Windows 10 laptop which isn't capable of running Windows 11, and Windows 10 support of coming to an end. The installation was more effort than I hoped and I had to troubleshoot quite a bit, but I got there without an unreasonable effort. Performance is much better so I'm sticking with it for now.</p>
</li>
<li><p>I've used GitHub issues and Jules to create and update some of my user scripts. Jules has high enough usage limits on its free tier then it's effectively free at the moment. If you give it access to a GitHub repository, you can tag an issue <code>jules</code> and it will try to fix the issue and create a PR. The quality isn't great but it's an asynchronous workflow that I can trigger from mobile just as easily as desktop, so it's handy for ideas I have on the go.</p>
<ul>
<li>I plan to publish my user scripts at some point, but they're not currently publicly accessible.</li>
</ul>
</li>
<li><p>I've improved how I use Obsidian for work notes.</p>
<ul>
<li><p>I'm getting better at using meaningful headings within my work item notes so the document outline becomes more helpful.</p>
</li>
<li><p>I'm trying to get in the habit of adding a timestamped progress summary to my work item notes whenever I stop work on one of them (e.g. at the end of the day, or when switching to a different task) in the hopes of making it easier to pick them back up.</p>
</li>
<li><p>I'm also going to try and add callouts at the top of work item notes with key details like how to run an app, repro steps for a bug, etc. when this sort of information is relevant.</p>
</li>
<li><p>I'm making heavy use of callouts. <a target="_blank" href="https://obsidian.md/plugins?id=callout-manager">Callout Manager</a> is a very handy extension for this. I've added several new callout types of my own. I'm also using the auto-collapse feature a lot for error messages so they're searchable but not in the way.</p>
</li>
<li><p>I'm also linking between my notes more, linking to specific headings, and modifying the display text for the links.</p>
</li>
</ul>
</li>
<li><p>It was interesting using Claude to try and debug an issue with Application Insights telemetry not being sent to Azure. Claude made loads of useless suggestions and kept repeating suggestions that I had already told it didn’t work. It also tried to gaslight me into believing that everything was already working. Having said that, it also gave me some code snippets for getting diagnostic logs which were helpful, and the eventual fix was suggested by Claude and not by the Microsoft help articles about diagnosing Application Insights problems. It didn’t feel atypical that Claude was a mixture of useless, frustrating, and useful.</p>
</li>
<li><p>Claude has also been helpful for investigating obscure issues. I've investigated hosting problems in a .NET app which had no server side code, but used a <code>web.config</code> file to configure serving an angular app. I've also asked highly-specific questions about nuances of .NET Framework and .NET Core for individual pieces of code. Discussions with Claude were more fruitful for these obscure issues than they often were for more conventional requests — perhaps because my own knowledge was more lacking so I found lower quality answers helpful in a way that I wouldn't have done for subject areas where I was more knowledgeable.</p>
</li>
<li><p>My company has started training all employees in how to make the most of LLMs. As you might expect, the tone was enthusiastic about their use, but I appreciated that the advice was quite pragmatic. It was also emphasised that we humans are the experts, not the LLM.</p>
<ul>
<li><p>Two pieces of advice that struck me as very sensible:</p>
<ul>
<li><p>Timebox your prompting, and be disciplined to give up trying to use AI if it's not giving you what you want. Don't waste lots of time playing around with your prompts only to end up doing the task without AI.</p>
</li>
<li><p>If the LLM can get you 80% of what you want, it's often not worth the effort of using the LLM for the remaining 20%. Just make the required changes yourself.</p>
</li>
</ul>
</li>
<li><p>I also appreciated the reminder to commit small and often, to limit the damage that an LLM will realistically do if it messes up the code.</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li><p>How did I not know about <code>git grep</code>? 🤯 I used it to search a very large git repository and it was super-fast.</p>
<ul>
<li><p>I imagine this is largely because it knows to ignore everything covered by the <code>.gitignore</code>, which is what I wanted. If I was using any other tool (e.g. command prompt <code>findstr</code>, or notepad++ directory search, or a powershell script) then a lot of time would have been wasted searching <code>node_modules</code> and other irrelevant folders.</p>
</li>
<li><p>I've already used this many times since finding out about it. It's been especially helpful because I'm working in a repository containing about a dozen solutions which share some common code, so finding code usages isn't always straightforward.</p>
</li>
<li><p>Because I typically run <code>git</code> commands from windows command prompt, I've sometimes forwarded the output to a file (using <code>git grep foo &gt; file.txt</code> to replace the file, or <code>git grep foo &gt;&gt; file.txt</code> to append to it) to keep a record of the results or perform further text manipulation on them.</p>
</li>
<li><p>The search term is treated as regex, but it's also possible to use <code>git grep -F "search term"</code> to search for an exact string without having to escape any regex special characters.</p>
</li>
<li><p>I also learnt about <code>git ls-files</code> which is the equivalent for searching files based on their names rather than their contents.</p>
<ul>
<li>e.g. <code>git ls-files "*package.json"</code> to find all <code>package.json</code> files across the whole repository.</li>
</ul>
</li>
</ul>
</li>
<li><p>I'm becoming more familiar and comfortable with KQL for querying app insights telemetry. I'm still far from an expert, but I can find what I'm looking for a lot quicker than I previously could.</p>
</li>
<li><p>I now know how to type an em-dash in windows (it's ALT + 0151) and android (when using gboard — you have to switch to the symbol keyboard then long press the hyphen). I've read one or two blog posts lamenting the decline of the em-dash now that it's become associated with AI-generated text, and I'd never known before what the purpose of the em-dash is. I've never been a great writer and I barely even edit what I write on my blog, but I've realised that the way I write I often need an em-dash. Not knowing how to type them, I've never used them before — until now!</p>
<ul>
<li><p>I think this was the blog post which first made me think about this: <a target="_blank" href="https://joeldueck.com/ai-is-right-about-em-dashes.html">AI is right about em-dashes • Joel Dueck</a></p>
</li>
<li><p>This is the article that most helped me understand the differing purposes of hyphens and dashes: <a target="_blank" href="https://practicaltypography.com/hyphens-and-dashes.html">Hyphens and dashes | Butterick’s Practical Typography</a></p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-been-thinking-about">Things I've been thinking about</h1>
<ul>
<li><p>My company recently did its annual employee survey and one of the questions asked what area of my role I find most challenging. As I reflected on this, I think it's probably working with a new technology that I'm not familiar with — especially one which has a substantial learning curve and which I need to get up to speed with quickly. I get intimidated by large complex pieces of technology, or black boxes which require learning a lot of concepts in order to understand what they do (authentication libraries are a prime example of this). It seems to me that the way to become less intimidated is probably to broaden my experience.</p>
<ul>
<li><p>I like the stability of a long-term project. I like getting to know the project well — which includes getting to know stakeholders, colleagues, the codebase and usually some project-specific processes. However, this does narrow the breadth of experience which I gain over time.</p>
</li>
<li><p>How much is this a problem? I'm not sure. It's not causing me any problems right now, but I hope to be in this industry for another few decades and I imagine that breadth of experience makes it easier to adapt to changes.</p>
</li>
<li><p>Would I mind working with the same technologies for the rest of my career? Honestly, I think it wouldn't be my preference, but I don't think I'd massively object to it <em>if</em> I knew that those technologies would carry me through to the end of my career. I don't feel any great need to be cutting edge, but I don't want to become obsolete.</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-im-grateful-for">Things I'm grateful for</h1>
<ul>
<li>As I was in July, I'm again grateful for the IT team at work. I raised a ticket that my laptop couldn't use the monitors on one of our hotdesks. It was investigated the next day and about a week later it had been replaced and the desk was useable again. I dread to think how long that would have taken in a large bureaucratic organisation.</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p>I've only recently come across the concept of interactive blog posts, and I've found them to be a really enjoyable way to learn a topic.</p>
<ul>
<li><p><a target="_blank" href="https://www.joshwcomeau.com/svg/friendly-introduction-to-svg/">A Friendly Introduction to SVG • Josh W. Comeau</a> inspired me to learn about SVGs even though I have no</p>
<ul>
<li><p><a target="_blank" href="https://svg-tutorial.com/">https://svg-tutorial.com/</a></p>
</li>
<li><p><a target="_blank" href="https://www.svgviewer.dev/">https://www.svgviewer.dev/</a></p>
</li>
</ul>
</li>
<li><p>The first one I came across was about using LLMs to process an email inbox and how that was a better use of AI than writing or summarising emails. I didn't make a note of the link though and can't find it now.</p>
</li>
<li><p><a target="_blank" href="https://samwho.dev/big-o/">https://samwho.dev/big-o/</a> is another example</p>
</li>
</ul>
</li>
<li><p><a target="_blank" href="https://colton.dev/blog/curing-your-ai-10x-engineer-imposter-syndrome/">No, AI is not Making Engineers 10x as Productive</a></p>
<blockquote>
<p>One thing I've noticed about all these characters in AI coding hype pieces is there is almost always a degree of separation from the writer to the actual productivity benefits. The poster is a founder, or a manager, or an investor, making grandiose claims about someone else's productivity. There's nothing wrong with secondary sources but if you can't find a primary source, you might start questioning the reliability of the information.</p>
<p>Presentations from actual engineers demonstrating how they achieve more productivity with AI are much more varied and much more muted in their praise. These demos show largely AI as the same technology you and I were familiar with before we got so anxious: a neat text generator that sometimes does magic but often requires you to take the wheel.</p>
</blockquote>
</li>
<li><p><a target="_blank" href="https://obsidian.rocks/obsidian-search-five-hidden-features/">Obsidian Search: Five Hidden Features - Obsidian Rocks</a></p>
<ul>
<li>I noticed the "Explain search terms" toggle in the obsidian search and wondered what it was for, as my searches didn't have anything worthy of explanation. This article was very helpful for understanding the built in functionality for searching within obsidian.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://dev.to/wojtekmaj/why-using-bun-in-production-maybe-isnt-the-best-idea-3deb?">Why using Bun in production (maybe) isn't the best idea - DEV Community</a></p>
<blockquote>
<p>Production depends on <strong>sustainability, predictability, and trust</strong>.</p>
</blockquote>
<ul>
<li>This is a great summary of my concerns about using LLMs too.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://hbr.org/2025/09/ai-generated-workslop-is-destroying-productivity">AI-Generated “Workslop” Is Destroying Productivity</a></p>
<blockquote>
<p>AI generated work content that masquerades as good work, but lacks the substance to meaningfully advance a given task.</p>
<p>The insidious effect of workslop is that it shifts the burden of the work downstream, requiring the receiver to interpret, correct, or redo the work. In other words, it transfers the effort from creator to receiver.</p>
<p>When coworkers receive workslop, they are often required to take on the burden of decoding the content, inferring missed or false context. A cascade of effortful and complex decision-making processes may follow, including rework and uncomfortable exchanges with colleagues.</p>
<p>Approximately half of the people we surveyed viewed colleagues who sent workslop as less creative, capable, and reliable than they did before receiving the output.</p>
</blockquote>
<ul>
<li>The point is that this is not merely doing bad work, but requiring <em>others</em> to fix the problems which it creates.</li>
</ul>
</li>
</ul>
<h1 id="heading-things-other-people-said">Things other people said</h1>
<p><em>Quote of the month</em></p>
<ul>
<li><p>"Keyframe animations are meant to be general and reusable. We can apply them to specific selectors with the animation property"<br />  <a target="_blank" href="https://www.joshwcomeau.com/animation/keyframe-animations/">An Interactive Guide to CSS Keyframe Animations with @keyframes • Josh W. Comeau</a></p>
<ul>
<li>I don't do a lot of front end work and I've always been confused about how to use keyframes and animations. Knowing that the keyframe is meant to be reusable and the animation property is meant to use it somewhere made it all click together much better for me.</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><a target="_blank" href="https://tjhilton.hashnode.dev/til-the-uk-has-20000-fake-phone-numbers">TIL: The UK has 20,000 fake phone numbers</a></li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Claude at work: what worked and what didn't</p>
</li>
<li><p>My experience of installing Linux mint</p>
</li>
<li><p>Diagnosing why Application Insights telemetry wasn't sent to Azure</p>
</li>
<li><p>No, AI is not like a junior developer</p>
</li>
<li><p>Authenticating Augment extension in VSCode web</p>
</li>
<li><p>Extracting simple HTML tools from Lovable</p>
</li>
<li><p>Overriding <code>Access-Control-Allow-Origin</code> headers in chrome</p>
</li>
<li><p>First impressions of using <a target="_blank" href="http://claude.ai">claude.ai</a> at work</p>
</li>
<li><p>Using collapsible callouts in Obsidian to prevent error messages disrupting flow</p>
</li>
<li><p>New Outlook quick steps and templates</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL: The UK has 20,000 fake phone numbers]]></title><description><![CDATA[When creating test data I always prefer to use known false data for anything related to communications. https://www.example.com and the .example TLD are maintained for fake websites and email addresses, but I only today looked up what the equivalent ...]]></description><link>https://techblog.timhilton.xyz/til-the-uk-has-20000-fake-phone-numbers</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-the-uk-has-20000-fake-phone-numbers</guid><category><![CDATA[Testing]]></category><category><![CDATA[Phone number]]></category><category><![CDATA[Test Data]]></category><category><![CDATA[fake data]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 03 Sep 2025 10:16:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/CNSH-JGEwtI/upload/3ab24349f132810bc065d4670189e9ab.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When creating test data I always prefer to use known false data for anything related to communications. <a target="_blank" href="https://www.example.com">https://www.example.com</a> and the <code>.example</code> TLD are maintained for fake websites and email addresses, but I only today looked up what the equivalent is for phone numbers.</p>
<p>I found that Ofcom (the UK’s communications regulator) maintains a list of 20,000 fake phone numbers which are intended for use in films, TV, etc. These seem like excellent candidates for creating fake phone numbers in software testing too!</p>
<p>There are 20 ranges of reserved phone numbers which won’t be assigned to anyone, and each range contains 1,000 numbers. The full details are at <a target="_blank" href="https://www.ofcom.org.uk/phones-and-broadband/phone-numbers/numbers-for-drama">https://www.ofcom.org.uk/phones-and-broadband/phone-numbers/numbers-for-drama</a>.</p>
<p>If you just want a single fake phone number, you can use these:</p>
<blockquote>
<p>Mobile: 07700 900000</p>
<p>UK-wide landline: 03069 990000</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Month in review: July 2025]]></title><description><![CDATA[Things that happened

I had my appraisal. It pushed me to think more seriously about how I can most effectively share evergreen knowledge with the wider company. Others have suggested this before but I've always resisted giving talks, etc. because of...]]></description><link>https://techblog.timhilton.xyz/month-in-review-july-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-july-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Thu, 31 Jul 2025 19:03:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/RanxGMHPsLI/upload/dbe9ce2e32cd49b2fe72287a2e364386.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li><p>I had my appraisal. It pushed me to think more seriously about how I can most effectively share evergreen knowledge with the wider company. Others have suggested this before but I've always resisted giving talks, etc. because of the time commitment (and the fact that talks at my company typically happen during our lunch breaks). I've started to give more serious thought to ways I could share knowledge and skills without it taking too much time away from development. I've also set this as a formal Objective within our HR system so I will be prompted on this again in the future.</p>
</li>
<li><p>I was going to bookmark <a target="_blank" href="https://bartwullems.blogspot.com/2020/08/azure-devops-github-emoji.html">this handy list of emojis supported by Azure DevOps</a>, right up until the moment I realised I'd already got it bookmarked 🤦</p>
<ul>
<li><a target="_blank" href="https://gist.github.com/tomaslucas/504b8a0909ddff21dab8a3b952522a58">Similar (or possibly identical) list</a> in a slightly different format.</li>
</ul>
</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li><p><a target="_blank" href="http://ASP.NET">ASP.NET</a> Data Protection</p>
<ul>
<li><p>I had never heard of this, but needed to use it and explain some technical choices to a client. I researched this from the Microsoft documentation and felt afterwards that I had a solid understanding of it. I'm certainly no expert, but I knew enough to be able to articulate the technical options we had, make a recommendation, and implement the final decision.</p>
</li>
<li><p>I also learnt a bit more about Key Vault permissions while working out what permissions I needed to ask our IT department for in order to test this work.</p>
</li>
</ul>
</li>
<li><p>fuslogvw.exe (Assembly Binding Log Viewer)</p>
<ul>
<li><p>This is a tool which I've never heard of, even though it comes built into Visual Studio. In the end, it wasn't useful for me so I never really dug into what it does and how it works. It was still interesting to find out about it and run it.</p>
</li>
<li><p>You can run it within Visual Studio by opening either <code>Developer PowerShell</code> or <code>Developer Command Prompt</code>, then running the command <code>fuslogvw</code>.</p>
</li>
<li><p>Official documentation: <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer">https://learn.microsoft.com/en-us/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer</a></p>
</li>
</ul>
</li>
<li><p>SQL Server indexes can include data from non-indexed columns.</p>
<ul>
<li><p>I learnt this from a recommendation within Azure. It provided the SQL for adding an index which it recommended.</p>
</li>
<li><p>I assume this means that if a query only needs those columns, the entire query can be resolved from the index without needing to actually read the database table. I haven't read up on this or experimented with it, so I may have misunderstood this.</p>
</li>
</ul>
</li>
<li><p>Git aliases can use the current date, by invoking a powershell script.</p>
<ul>
<li>I made use of this within one of the aliases for <a target="_blank" href="https://tjhilton.hashnode.dev/managing-local-changes-which-should-not-be-committed-using-only-git-stashes">Managing local changes which should not be committed using only git stashes</a>.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://tjhilton.hashnode.dev/til-pin-screen-using-sharex">I can pin part of my screen using ShareX</a>.</p>
</li>
</ul>
<h1 id="heading-things-ive-been-thinking-about">Things I've been thinking about</h1>
<ul>
<li><ul>
<li><p>My job title is currently Senior Software Engineer. My company is planning to split the Senior grade into two, but hasn't yet published the details of how the two new grades will be defined. I'm looking forward to finding out how the two new grades are defined, and which grade I will be given.</p>
<ul>
<li>My company is currently hosting workshops for people to see a draft of the relevant document and provide feedback. That gave me a good feel for where I instinctively place myself, but I am still keen to look through the published document in detail and give it some proper thought.</li>
</ul>
<ul>
<li><p>Best ways to use GitHub Copilot, and whether I should try other AI tools professionally.</p>
<ul>
<li><p>For a while my company has been paying for a Copilot license for me, and I could choose to give that up and get a licence for Claude or ChatGPT instead. They would only pay for one AI tool per person (which I think is completely reasonable) so I can't easily play around with different tools from day to day.</p>
</li>
<li><p>This policy has recently changed to give everyone a licence for Copilot and an extra AI licence if requested. I'm hoping this will help me explore other AI developer tools more.</p>
</li>
<li><p>I'm working in VS at the moment, and I suspect the Copilot tooling is far from the best available. For example, you can't drag and drop files from outside your codebase into the Copilot context. (VS Code and Rider both support this functionality.)</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-im-grateful-for">Things I'm grateful for</h1>
<ul>
<li><p>I received very speedy responses from my company's IT department when I needed them to make changes to Azure resources and update my permissions for various functionality. I really appreciate that they accept the priority we assign to our own requests, trusting us not to take the mickey.</p>
</li>
<li><p>I've had a number of opportunities recently to encourage colleagues with specific feedback, and I've also received some specific encouragements from colleagues.</p>
<ul>
<li>I have realised that the level of encouragement I get from a compliment is directly proportional to how specific it is.</li>
</ul>
</li>
<li><p>My company is also planning some AI training for all staff, broken down by role. Knowing the person who is heading up the training, I am expecting this to be genuinely helpful, but I assume this will be delivered after the summer holidays when staff have more availability.</p>
</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://pod.link/1718797329/episode/47c00dfd16c0fc53efe304cfbd42dceb">Simon Willison on the Generationship podcast</a>. I've not come across the podcast before, but Simon Willison keeps on top of the current state of LLMs and AI tools from a software development perspective so I like to hear his views from time to time to know what (in his opinion) is the current state of play. I took 4 things away from the podcast:</p>
<ul>
<li><p>It's important to teach &amp; model that we all make mistakes, and how to recover from them.</p>
</li>
<li><p>Senior developers ask stupid questions.</p>
<ul>
<li><p>Psychological safety - senior developers already have a reputation for competence, so asking a stupid question won't damage their reputation.</p>
</li>
<li><p>Learning - senior developers have become senior by learning, and they have learnt by asking questions. They may have become senior by becoming comfortable asking about things they don't understand.</p>
</li>
</ul>
</li>
<li><p>Publish your notes so that others can benefit from them.</p>
<ul>
<li><p>I imagine my notes could be a useful reference for others at times. People do occasionally ask me about work I did in the past, or if I've ever seen a particular error before, etc. I tend to search my notes, but perhaps there would be value to others being able to do that.</p>
</li>
<li><p>I'm not sure how this would work on a commercial project, as it may not be appropriate to share notes with people who are uninvolved with the project (even within a single company).</p>
</li>
</ul>
</li>
<li><p>Gen AI lowers the cost of generating little tools and side projects which might not otherwise have been worth it.</p>
</li>
</ul>
</li>
<li><p><a target="_blank" href="https://www.firstround.com/ai/shopify">From Memo to Movement: The non-obvious insights, tactics and workflows Shopify used to bring an ambitious memo to life</a></p>
<ul>
<li><p>Perhaps the best use for AI as a dev may not be writing production code but creating useful tools.</p>
</li>
<li><p>“Most people will tell you the ideal UX for both internal and user-facing products is for you to ask a question and receive the answer, not the messy details,” says Thawar. “But if your goal is to teach people how to master something, showing them those details is better.”</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-other-people-said">Things other people said</h1>
<p><em>Quote of the month</em></p>
<ul>
<li><p>"The client is not interested in <em>building</em> good software, they just want to <em>have</em> it. They have no interest in the process." (<em>A colleague</em>)</p>
<ul>
<li><p>This was said to me as a frustration on a particular project where this reality was causing problems, but I think it probably has a broad applicability to how software professionals liaise with clients.</p>
</li>
<li><p>I think this is a double-edged sword - it's positive to relate well to clients and understand their point of view, but can also be frustrating because they may not care about something we are passionate about.</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><p><a target="_blank" href="https://tjhilton.hashnode.dev/using-visual-studio-after-being-used-to-rider">Using Visual Studio after being used to Rider</a></p>
</li>
<li><p><a target="_blank" href="https://tjhilton.hashnode.dev/managing-local-changes-which-should-not-be-committed-using-only-git-stashes">Managing local changes which should not be committed using only git stashes</a></p>
</li>
<li><p><a target="_blank" href="https://tjhilton.hashnode.dev/til-pin-screen-using-sharex">TIL: Pin screen using ShareX</a></p>
</li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Further thoughts on Visual Studio vs Rider (following on from <a target="_blank" href="https://tjhilton.hashnode.dev/using-visual-studio-after-being-used-to-rider">Using Visual Studio after being used to Rider</a>).</p>
<ul>
<li>It's still not good news for Visual Studio.</li>
</ul>
</li>
<li><p>Instructions for using <code>fuslogvw</code>.</p>
<ul>
<li><p>It turned out that this tool doesn't do what I wanted, so I ended up without a concrete use case to blog about.</p>
</li>
<li><p>I also didn't publish a write-up of how I did end up trying to find all binding errors within an <a target="_blank" href="http://ASP.NET">ASP.NET</a> MVC app.</p>
</li>
</ul>
</li>
<li><p>Thoughts on <a target="_blank" href="https://pod.link/1718797329/episode/47c00dfd16c0fc53efe304cfbd42dceb">Simon Willison's appearance on the Generationship podcast</a>.</p>
<ul>
<li><p>Brief thoughts are included above within this blog post.</p>
</li>
<li><p>I wondered about writing something a bit more reflective to follow these ideas a bit more.</p>
</li>
</ul>
</li>
<li><p>How I use <a target="_blank" href="https://www.todoist.com">todoist</a> as a professional programmer</p>
<ul>
<li>I'll probably write this up one day but didn't get round to it this month.</li>
</ul>
</li>
<li><p>Writing a user script with AI and getting it (nearly) right first time</p>
<ul>
<li>I might wait until I find out how much effort it is to get the user script working fully before I blog about this.</li>
</ul>
</li>
<li><p>Why I'm keen to vibe code useful tools</p>
<ul>
<li>Includes some thoughts about the future of AI development tools. I hope to write this at some point.</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL: Pin screen using ShareX]]></title><description><![CDATA[What does ‘Pin screen’ mean?
The idea is that I can select a portion of the screen, then that image will stay in place as I work on other things. The image can also be easily dragged around, made partially transparent, or zoomed in/out.
Since stumbli...]]></description><link>https://techblog.timhilton.xyz/til-pin-screen-using-sharex</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-pin-screen-using-sharex</guid><category><![CDATA[sharex]]></category><category><![CDATA[workflow]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Screenshot]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 28 Jul 2025 10:11:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zqO87IQK6c0/upload/022420ce37ec20a5995fdfc1d1595884.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-does-pin-screen-mean">What does ‘Pin screen’ mean?</h1>
<p>The idea is that I can select a portion of the screen, then that image will stay in place as I work on other things. The image can also be easily dragged around, made partially transparent, or zoomed in/out.</p>
<p>Since stumbling across this functionality I’ve used it a few times to create a temporary on-screen reference for myself.</p>
<ul>
<li><p>A namespace from one code file stayed on my screen while I was navigating my codebase.</p>
</li>
<li><p>A list of package version numbers from some instructions I’d written myself in Obsidian stayed on my screen while I switched note within Obsidian to make notes about some problems I was encountering.</p>
</li>
<li><p>I wanted to compare two object instantiations within a long code file containing many similar object instantiations. I pinned one of them then scrolled down to the other.</p>
</li>
</ul>
<p>This is what the functionality looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753697372615/7e78e55e-7fca-4cea-845e-7ffc886deb40.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-how-to-use">How to use</h1>
<ol>
<li><p>Right click the ShareX icon in the windows taskbar.</p>
</li>
<li><p>Hover over Tools.</p>
</li>
<li><p>In the Tools sub-menu, click Pin to screen. This will open a dialog box with different options for what you pin to your screen.</p>
</li>
<li><p>I’ve been using ‘Pin to screen from screen’ which is admittedly a mouthful.</p>
</li>
<li><p>Select the area you want to keep on-screen. A coloured box will appear round it.</p>
</li>
<li><p>Drag the box elsewhere if you want to move it. Hover over the box with your cursor then scroll up/down with your mousewheel to zoom in/out. Hold down CTRL while scrolling to change the opacity.</p>
<ol>
<li>Hovering over the box also gives an icon for copying the image to your clipboard, and for opening other settings.</li>
</ol>
</li>
<li><p>Right click the box to dismiss the image. (It isn’t saved anywhere by default, though you could create a custom Workflow within ShareX if you want them to be routinely kept.)</p>
</li>
</ol>
<p>If you want to create a custom keyboard shortcut for this, you can do so from Hotkey Settings within the ShareX menu (opened by right-clicking the icon in the Windows taskbar).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753697091490/b6ad36b2-6ded-4ad9-939d-725bd677bbc1.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item></channel></rss>