<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Euan Reid</title>
    <subtitle>The personal website of Euan Reid - technical leader, software engineer, and co-founder.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://www.euanreid.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://www.euanreid.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-26T00:00:00+00:00</updated>
    <id>https://www.euanreid.com/atom.xml</id>
    <entry xml:lang="en">
        <title>Delegation Means Letting Go</title>
        <published>2026-09-26T00:00:00+00:00</published>
        <updated>2026-09-26T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/work/leadership/delegation-means-letting-go/"/>
        <id>https://www.euanreid.com/work/leadership/delegation-means-letting-go/</id>
        
        <content type="html" xml:base="https://www.euanreid.com/work/leadership/delegation-means-letting-go/">&lt;p&gt;When I delegate a decision, I’ve made it someone else’s call. Within the scope
I’ve given them, they get to choose. That includes choosing things I wouldn’t.&lt;/p&gt;
&lt;p&gt;That can be hard when I know the technology well. I can probably spot a cheaper
approach or a problem they haven’t considered – and I’m accountable for the
result. But being accountable for a project doesn’t mean owning every decision.
When I delegate, I’m saying “you own this piece, and are accountable to me for
it”.&lt;/p&gt;
&lt;p&gt;As a director, I need to make the whole team more effective. That means taking
a broader view than I get from working through each engineering problem in
detail. If I keep making the decisions I’ve supposedly delegated, I’m
undermining the people I’ve delegated to – both by not empowering them to
decide and by making myself a bottleneck. I’ve also left myself with less time
to do my actual job.&lt;/p&gt;
&lt;h2 id=&quot;another-thing-to-maintain&quot;&gt;Another Thing to Maintain&lt;/h2&gt;
&lt;p&gt;Suppose a manual reporting process needs replaced and we have a deadline of
around six weeks. I delegate this to a senior engineer. We already have a
reporting service, so I’d prefer to extend it. They decide to implement a
small, separate tool instead – the existing service belongs to another team,
the changes we would need aren’t on that team’s schedule, and the engineer
thinks waiting for the other team would miss our deadline.&lt;/p&gt;
&lt;p&gt;I see their rationale, but I don’t particularly want another service to
maintain. Somebody will have to deal with its upgrades and failures long after
this deadline has passed. I think the other team can deliver for us in time.&lt;/p&gt;
&lt;p&gt;But I didn’t make using the shared service a requirement, because it wasn’t.
The decision they’ve made was within the scope I delegated. So it’s their call.&lt;/p&gt;
&lt;h2 id=&quot;what-i-need-my-time-for&quot;&gt;What I Need My Time For&lt;/h2&gt;
&lt;p&gt;A senior engineer is the right person to work through the reporting design in
detail. As a director, I need to consider why this report takes priority over
the other things we’ve been asked to deliver.&lt;/p&gt;
&lt;p&gt;Time and money are not unlimited. Suppose we have more work to do than we have
time and budget for. I need to be spending my time with my fellow leaders
deciding what things we actually do. I can fill my week with useful technical
conversations while those problems sit unresolved, but that just eats up the
time we’re already short of.&lt;/p&gt;
&lt;h2 id=&quot;once-work-has-started&quot;&gt;Once Work Has Started&lt;/h2&gt;
&lt;p&gt;Once the engineer chooses the separate tool, I need to support them in
delivering it. If another team questions the choice, I should make clear that
it was theirs to make. Referring every challenge back to me for a fresh
decision would undo the authority I gave them. Using “it was their decision” to
disclaim responsibility for the result would be cowardly. I chose who to give
the work to and how much room they had to do it.&lt;/p&gt;
&lt;p&gt;We should agree early on how much involvement I will have. Someone doing this
kind of work for the first time may want to work through estimates together; an
experienced engineer might only need to flag a change to the delivery date.&lt;/p&gt;
&lt;p&gt;Suppose the connection to the source data takes longer than expected. We need
to look at the remaining work and see whether the deadline is still realistic.
Reopening the topic of using the shared service won’t get the connection
finished.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;would&lt;/em&gt; intervene if the deadline was at risk or we discovered the design
couldn’t meet an unknown requirement. Usually I’d ask the engineer to work out
what to change, but some problems might require my involvement to resolve. I
should be able to explain which ones and why.&lt;/p&gt;
&lt;p&gt;I have work to deliver too. In this example, the teams need an answer about
their competing commitments. If they’re still waiting when the reporting tool
ships, I’ve not done my job.&lt;/p&gt;
&lt;h2 id=&quot;after-we-ship&quot;&gt;After We Ship&lt;/h2&gt;
&lt;p&gt;Suppose the separate tool works, but takes more maintenance than we’d prefer,
and we later learn that the shared service could definitely have delivered in
time. That doesn’t mean the call was wrong. They made the best call they could
based on the information available to them at the time.&lt;/p&gt;
&lt;p&gt;I have to be comfortable with good work going out that I would have done
differently. I can offer advice and intervene when something moves outwith the
scope we agreed, but within it the decision belongs to the person I gave it
to. My disagreement doesn’t entitle me to take it back.&lt;/p&gt;
&lt;p&gt;That is part of accepting a director’s job. There is more work than I can do
myself, and some of it needs the authority and perspective of my role. I need
other people to make the engineering decisions so I can get on with that work.
I can’t take on the wider responsibility and keep their decisions too.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Tomato and Boursin Tart</title>
        <published>2026-09-22T00:00:00+00:00</published>
        <updated>2026-09-22T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/life/cooking/tomato-boursin-tart/"/>
        <id>https://www.euanreid.com/life/cooking/tomato-boursin-tart/</id>
        
        <content type="html" xml:base="https://www.euanreid.com/life/cooking/tomato-boursin-tart/">&lt;p&gt;I first made some version of this when I was a teenager. It came from one of
the many cookbooks around the house, but I’ve long forgotten which.&lt;/p&gt;
&lt;p&gt;The original was very simple: pre-made puff pastry, Boursin, thick slices of
tomato, olive oil, and dried herbs. I’ve changed bits of it over the years, but
not much.&lt;/p&gt;
&lt;p&gt;The biggest change is that I make the pastry now as well, specifically
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://profoodhomemade.com/flaky-pastry-sausage-rolls/&quot;&gt;John Kirkwood’s flaky pastry&lt;/a&gt;.
Flaky pastry works particularly well here: crisp, buttery, and sturdy enough to
sit under the cheese and tomatoes. If I don’t want to make it, reverting to
puff pastry is the obvious move. Blocks and ready-rolled sheets work equally
well; the sheet only saves the rolling.&lt;/p&gt;
&lt;p&gt;Serves 4-6 as a light meal, 8 as a starter, or more if you cut it into canapés.&lt;/p&gt;
&lt;h2 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h2&gt;
&lt;h3 id=&quot;for-the-pastry&quot;&gt;For the Pastry&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;255 g plain flour&lt;/li&gt;
&lt;li&gt;185 g unsalted butter&lt;/li&gt;
&lt;li&gt;4 g fine salt&lt;/li&gt;
&lt;li&gt;90 ml ice-cold water&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;for-the-tart&quot;&gt;For the Tart&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;150 g Boursin Garlic &amp;amp; Fine Herbs&lt;/li&gt;
&lt;li&gt;3 large ripe tomatoes&lt;/li&gt;
&lt;li&gt;Extra-virgin olive oil&lt;/li&gt;
&lt;li&gt;Dried thyme, mixed herbs, or herbes de Provence&lt;/li&gt;
&lt;li&gt;Sea salt&lt;/li&gt;
&lt;li&gt;Freshly ground black pepper&lt;/li&gt;
&lt;li&gt;1 egg, beaten&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;make-the-pastry&quot;&gt;Make the Pastry&lt;/h2&gt;
&lt;p&gt;Put the butter in the freezer for about 15 minutes. It wants to be very cold, but still soft enough to grate.&lt;/p&gt;
&lt;p&gt;Mix the flour and salt in a large bowl. Put a box grater in the bowl and grate the butter straight into the flour, dipping the butter in the flour occasionally to stop it sticking. Toss the grated butter through the flour with your fingers, without rubbing it in.&lt;/p&gt;
&lt;p&gt;Put the bowl in the fridge or freezer for 10 minutes.&lt;/p&gt;
&lt;p&gt;Add the ice-cold water and bring the dough together quickly. Don’t knead it any more than needed to form a rough dough. Wrap it and put it back in the fridge for at least 15 minutes.&lt;/p&gt;
&lt;h2 id=&quot;make-the-tart&quot;&gt;Make the Tart&lt;/h2&gt;
&lt;p&gt;Heat the oven to 220°C, or 200°C fan, with a heavy baking tray inside.&lt;/p&gt;
&lt;p&gt;Roll the pastry on a lightly floured surface into a rectangle roughly 30 × 40 cm. Put it on baking parchment.&lt;/p&gt;
&lt;p&gt;Score a border about 2 cm from the edge, without cutting all the way through. Prick the pastry inside the border a few times with a fork. Put it in the fridge while you prepare the tomatoes.&lt;/p&gt;
&lt;p&gt;Cut the tomatoes into fairly thick slices, around 6-8 mm. If they are particularly wet, give the cut surfaces a quick blot with kitchen paper. They should still be juicy.&lt;/p&gt;
&lt;p&gt;Take the pastry from the fridge and spread the Boursin over the middle, stopping at the scored border.&lt;/p&gt;
&lt;p&gt;Lay the tomato slices over the cheese. A little overlap is fine. Season well with the herbs, salt, and pepper before drizzling olive oil generously over everything inside the border.&lt;/p&gt;
&lt;p&gt;Brush the exposed pastry border with beaten egg.&lt;/p&gt;
&lt;p&gt;Slide the tart, still on its parchment, onto the hot baking tray. Bake for about 25 minutes, or until the pastry is well risen and properly golden. Give it another few minutes if the base still looks pale.&lt;/p&gt;
&lt;p&gt;Leave it alone to cool for five minutes before cutting it. This is best served warm, not piping hot.&lt;/p&gt;
&lt;h2 id=&quot;a-few-notes&quot;&gt;A Few Notes&lt;/h2&gt;
&lt;p&gt;The olive oil goes on before baking. As well as tasting nice, it helps stop the
exposed tomato from drying too much in the oven.&lt;/p&gt;
&lt;p&gt;I prefer large slices of tomato here rather than small tomatoes or a finely
arranged layer. The tomato should still feel like tomato when you eat it.&lt;/p&gt;
&lt;p&gt;Part of what I love about this tart is that it allows its main ingredients –
the butter in the pastry, the Boursin, and the tomatoes – to show off. You
could add balsamic vinegar, caramelised onions, or another cheese, but I don’t
think those extras actually improve it. Like with steak, good ingredients don’t
need or want anything else.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Civilised Futurism</title>
        <published>2026-09-19T00:00:00+00:00</published>
        <updated>2026-09-19T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/culture/philosophy/civilised-futurism/"/>
        <id>https://www.euanreid.com/culture/philosophy/civilised-futurism/</id>
        
        <content type="html" xml:base="https://www.euanreid.com/culture/philosophy/civilised-futurism/">&lt;p&gt;I like the future.&lt;/p&gt;
&lt;p&gt;I like better technology, better medicine, better infrastructure, greater
freedom, easier access to knowledge, and the steady removal of needless
inconvenience. Modern life blesses us with extraordinary things previous
generations couldn’t even begin to imagine. I have no desire to recreate the
past nor patience for hardship preserved just because of tradition.&lt;/p&gt;
&lt;p&gt;But I also dislike the assumption that progress requires us to discard
everything that came before it.&lt;/p&gt;
&lt;p&gt;Modernisation is too often treated as a process of subtraction. Formality
becomes stuffiness. Ceremony becomes inefficiency. Craftsmanship becomes
unnecessary expense. Manners become affectation. Old institutions are presumed
obsolete because they are old; new things are presumed superior because they
are new.&lt;/p&gt;
&lt;p&gt;I think there is a better way to approach the future: keep what remains useful,
beautiful, or humane; discard what no longer deserves to survive; and build new
things with enough care and character that they might themselves be worth
preserving.&lt;/p&gt;
&lt;p&gt;I call that &lt;strong&gt;Civilised Futurism&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;progress-without-amnesia&quot;&gt;Progress Without Amnesia&lt;/h2&gt;
&lt;p&gt;Traditions are not valuable merely because they are old. Some encode
assumptions we are better without. Some solve problems that no longer exist.
Some survive through inertia alone.&lt;/p&gt;
&lt;p&gt;But traditions are also accumulated solutions.&lt;/p&gt;
&lt;p&gt;Manners make interaction easier. Ceremony marks occasions as significant.
Dress communicates context. Institutions carry knowledge and expectations
across generations. Craftsmanship gives ordinary things permanence and
pleasure.&lt;/p&gt;
&lt;p&gt;The useful question is not whether something is old or new. It is whether it
still serves a worthwhile purpose. Where it does, deliberately preserve it.
Where the purpose remains but the form has become outdated, thoughtfully adapt
it. Where neither remains useful, let it go.&lt;/p&gt;
&lt;h2 id=&quot;modern-systems-human-experience&quot;&gt;Modern Systems, Human Experience&lt;/h2&gt;
&lt;p&gt;Technology should improve life without having to dominate it.&lt;/p&gt;
&lt;p&gt;A genuinely advanced house need not look like a computer. A good restaurant
should not feel like a logistics platform. A useful institution does not need
to advertise every system keeping it running. The machinery can become more
sophisticated while the experience becomes calmer, simpler, and more human.&lt;/p&gt;
&lt;p&gt;That principle applies well beyond technology. Efficiency is valuable, but not
every part of life exists to be optimised. The point of sharing dinner is to
enjoy time with others – it shouldn’t be fast. Ceremonies, be they formal
occasions like weddings and funerals or informal ones like birthdays, contain
deliberate rituals because significance is not measured in throughput.&lt;/p&gt;
&lt;p&gt;Progress should create more room for civilisation, not less.&lt;/p&gt;
&lt;h2 id=&quot;modernity-with-manners&quot;&gt;Modernity with Manners&lt;/h2&gt;
&lt;p&gt;Manners are sometimes appropriated to enforce hierarchy or arbitrary rules, but
that’s not their purpose. Their purpose is to make consideration habitual – a
set of conventions for making life easier for other people. The particular
conventions can and should change. The underlying principle should not.&lt;/p&gt;
&lt;p&gt;The same is true of many things we inherit. We can keep the useful principle
without preserving every historical expression of it.&lt;/p&gt;
&lt;p&gt;Civilised Futurism is neither nostalgia nor techno-utopianism. It’s a mindset
that rejects both “we’ve always done it this way” as justification and “this is
old” as criticism. It’s the belief that we can enthusiastically build a more
advanced future without accepting that advancement requires us to become less
civilised. Keep the manners, ceremony, craftsmanship, institutional memory, and
sense of continuity that still enrich human life. Discard the injustices,
inefficiencies, and empty conventions that do not. Build new things with enough
care and character that they too may someday become traditions. Insist that
progress can and must retain beauty, warmth, responsibility, and character.&lt;/p&gt;
&lt;p&gt;Civilised Futurism is the belief that a better future shouldn’t just work
better, it should be worth living in.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Tooling Matters</title>
        <published>2026-09-15T00:00:00+00:00</published>
        <updated>2026-09-15T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/work/tooling/"/>
        <id>https://www.euanreid.com/work/tooling/</id>
        
        <content type="html" xml:base="https://www.euanreid.com/work/tooling/">&lt;p&gt;Engineering teams spend too much time maintaining things that aren’t
functionality. Linters, formatters, package-manager glue, hooks, CI wrappers,
editor setup, and version management – all of it needs attention, and the
interactions between them need more. Some of that work is necessary, but most
of it isn’t.&lt;/p&gt;
&lt;p&gt;A package script wraps a shell script because “consistency”. CI and editor
plugins acquire their own copies of a tool. Someone fixes an editor warning by
adding a duplicate configuration file. Eventually, a change passes locally and
fails in CI, and an engineer spends the afternoon working out which version of
which command actually decides whether the code is acceptable.&lt;/p&gt;
&lt;p&gt;I treat tooling as a systems problem. A repository’s tools have components,
boundaries, responsibilities, interfaces, failure modes, and an operational
cost. We tend to choose them individually then leave their interactions to
whoever next gets stuck. I’d rather design that system up front and ensure
I can explain it.&lt;/p&gt;
&lt;h2 id=&quot;who-decides&quot;&gt;Who Decides?&lt;/h2&gt;
&lt;p&gt;For starters, I take a leaf from RACI’s book: a tool is Responsible for
enforcing a standard; the engineer is Accountable for the code they commit. If
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.astral.sh/ruff/&quot;&gt;Ruff&lt;/a&gt; owns Python formatting, it decides what
correctly formatted Python looks like in that repository. Another formatter
doesn’t also get a vote. I’m still accountable for what I deliver, including
changes a tool makes on my behalf. Passing a check doesn’t transfer that
judgement to the executable.&lt;/p&gt;
&lt;p&gt;That gives me one canonical owner per concern. Two formatters rewriting the
same files are an obvious problem. Two linters enforcing the same rule, two
task runners defining the same workflow, or an editor silently overriding the
repository’s configuration are versions of the same mistake. I regard that
overlap as a design smell. Every exception adds something the next engineer
has to understand before they can trust the result.&lt;/p&gt;
&lt;p&gt;Ownership also needs a scope. A tool may support ten languages while owning
only one job in my repository. I can use Oxfmt for CSS formatting and Biome for
CSS linting without enabling Biome’s formatter. A wrapper can call the owner;
it shouldn’t carry an independent copy of the owner’s rules.&lt;/p&gt;
&lt;p&gt;I’m certain I’ll replace several of these tools over time. Most of them
replaced others, after all. When I do, I want the replacement to take over a
defined responsibility without making everyone learn a new way to work in the
repository. Put simply: which job does it do, and why should it do it?&lt;/p&gt;
&lt;h2 id=&quot;the-repository-has-an-interface&quot;&gt;The Repository Has an Interface&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://mise.jdx.dev/&quot;&gt;mise&lt;/a&gt; is my default approach for acquiring and
versioning tools, setting up environments, and orchestrating tasks in a
repository. Where practical, I start with
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://mise.jdx.dev/cli/use.html&quot;&gt;&lt;code&gt;mise use X&lt;/code&gt;&lt;/a&gt; which installs the tool and
records the version requirement in the repository. I want setup to be something
easy to do on a fresh checkout, with the same flow available to a developer and
to CI.&lt;/p&gt;
&lt;p&gt;I give Git hooks to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://prek.j178.dev/configuration/&quot;&gt;prek&lt;/a&gt;, configured
through &lt;code&gt;prek.toml&lt;/code&gt;. Hooks invoke the appropriate checks using the repository’s
chosen tools and configuration. Those checks must also work when run directly;
committing shouldn’t be the only way to find out whether a change is ready.&lt;/p&gt;
&lt;p&gt;In every repository, I want a small common set of commands:&lt;/p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;mise run fmt
mise run fix
mise run check
mise run test
mise run build
mise run validate
mise run ci
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fmt&lt;/code&gt; applies formatting and &lt;code&gt;fix&lt;/code&gt; applies configured automated repairs.
&lt;code&gt;check&lt;/code&gt; reports static problems without changing files. &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; do
what their names suggest, &lt;code&gt;validate&lt;/code&gt; composes the local readiness checks, and
&lt;code&gt;ci&lt;/code&gt; is the entrypoint for an automated pipeline. Each repository should
document what those last two involve. A desktop app and a website don’t use
identical pipelines, or even need all seven commands.&lt;/p&gt;
&lt;p&gt;The value is being able to move between repositories without relearning how to
work. A Python task can call uv; a Rust task can call Cargo. If a web workspace
already has a task graph, mise can delegate to it. Recreating that graph in
mise would give me two places to maintain the same dependencies. Consistency
matters most when moving across projects. The internals can vary more.&lt;/p&gt;
&lt;p&gt;Humans, editors, CI, and coding agents all benefit from that interface. An agent
should be able to discover how to validate a change without reconstructing the
workflow from package scripts and pipeline YAML. The engineer reviewing its
work should be able to run the same command.&lt;/p&gt;
&lt;p&gt;I also commit explicit editor settings and useful extension recommendations.
The selected formatter and its configuration should agree with the command
line. A contributor’s personal editor setup shouldn’t be a hidden prerequisite
for producing an acceptable commit.&lt;/p&gt;
&lt;h2 id=&quot;go-tall-not-wide&quot;&gt;Go Tall, Not Wide&lt;/h2&gt;
&lt;p&gt;Research by Ruder, Rutter, and others finds prose is most readable at 50-75
characters. Code isn’t prose, but the physical constraints of eyeballs scanning
text don’t disappear. Many developers argue for 100 or 120 characters rather
than the classic 80 of punch cards and terminals, saying wide monitors obviate
that limit, but I’m a firm believer in the value of that brevity – closer to
that optimal range, and far better for split editors and side-by-side diffs.&lt;/p&gt;
&lt;p&gt;Putting separate arguments or entries on separate lines also gives a small
change a small diff. That’s useful when reviewing an engineer’s work or an
agent’s patch: I want to see what changed without scanning a rewritten line
for the one altered value. Eighty columns is a target, and I leave the exact
layout to the formatter. Manual line-wrapping disputes waste time.&lt;/p&gt;
&lt;h2 id=&quot;fast-enough-to-matter&quot;&gt;Fast Enough to Matter&lt;/h2&gt;
&lt;p&gt;I prefer fast, portable tools. Portable because developers should be able to
collaborate regardless of their OS. Fast because it changes how people work.&lt;/p&gt;
&lt;p&gt;If a check finishes in a fraction of a second, all the context is still in my
mind and I can keep working. If it takes a few minutes, I’m probably refilling
my water or checking Slack, and some of that context is lost. If it takes
longer, I’ll batch up changes, go do something else, find out about errors
later, and have to reload all the working context to my brain.&lt;/p&gt;
&lt;p&gt;Speed isn’t the &lt;strong&gt;most&lt;/strong&gt; important thing, though. Correctness is. A faster
linter that doesn’t handle newer syntax in a language or a test runner that
doesn’t handle mocking correctly leaves work for someone else to do. When an
ecosystem has authoritative tooling, that’s generally the safest bet.&lt;/p&gt;
&lt;h2 id=&quot;the-tools-i-use&quot;&gt;The Tools I Use&lt;/h2&gt;
&lt;p&gt;For Python, I’m a firm believer in the Astral stack.
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.astral.sh/uv/&quot;&gt;uv&lt;/a&gt; handles packages and environments, Ruff
handles formatting and linting, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.astral.sh/ty/&quot;&gt;ty&lt;/a&gt; handles
type checking. I use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://docs.pytest.org/en/stable/&quot;&gt;pytest&lt;/a&gt; for tests.&lt;/p&gt;
&lt;p&gt;For JavaScript and TypeScript, I favour &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://viteplus.dev/guide/&quot;&gt;Vite+&lt;/a&gt;
and its &lt;code&gt;vp&lt;/code&gt; interface. It brings together tools including
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://oxc.rs/docs/guide/usage/formatter.html&quot;&gt;Oxfmt&lt;/a&gt; and
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://oxc.rs/docs/guide/usage/linter.html&quot;&gt;Oxlint&lt;/a&gt;; its
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://viteplus.dev/guide/check&quot;&gt;&lt;code&gt;vp check&lt;/code&gt;&lt;/a&gt; combines formatting and linting
with type checking when enabled. Integration is useful when it removes
configuration and version coordination I’d otherwise have to maintain myself.&lt;/p&gt;
&lt;p&gt;An integrated tool still needs boundaries. Vite+ can manage runtimes and hooks
too. In my setup, prek keeps the hooks. For a runtime, I choose either mise or
the ecosystem manager as the authority and have the other use that decision.
Installing both and letting them independently select versions would defeat
the point. The same applies to uv’s ability to manage Python versions.&lt;/p&gt;
&lt;p&gt;Rust already has &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://doc.rust-lang.org/cargo/&quot;&gt;Cargo&lt;/a&gt; for builds and
dependencies, with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/rust-lang/rustfmt&quot;&gt;rustfmt&lt;/a&gt; for formatting
and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://doc.rust-lang.org/clippy/&quot;&gt;Clippy&lt;/a&gt; for linting. I use
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://nexte.st/&quot;&gt;nextest&lt;/a&gt; for test execution and
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://embarkstudios.github.io/cargo-deny/&quot;&gt;cargo-deny&lt;/a&gt; for dependency policy
checks. The repository tasks can expose these tools without trying to hide
Cargo’s model from the engineers using it.&lt;/p&gt;
&lt;p&gt;The supporting files deserve owners too. My current choices are
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://rumdl.dev/&quot;&gt;rumdl&lt;/a&gt; for Markdown formatting and linting,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://lychee.cli.rs/&quot;&gt;lychee&lt;/a&gt; for links,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://tombi-toml.github.io/tombi/&quot;&gt;Tombi&lt;/a&gt; for TOML, and
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/quarylabs/sqruff&quot;&gt;sqruff&lt;/a&gt; for SQL formatting and linting.
For CSS, Oxfmt formats and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://biomejs.dev/linter/&quot;&gt;Biome&lt;/a&gt; lints. These
assignments also mean excluding those files from overlapping tools, even when
a newly installed tool offers to check everything by default.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://buf.build/docs/cli/&quot;&gt;Buf&lt;/a&gt; is my choice for Protobuf. Like Vite+, it
pulls together formatting and linting in a single tool, but it also handles
some Protobuf-specific concerns: breaking-change detection and code generation.&lt;/p&gt;
&lt;h2 id=&quot;who-cares&quot;&gt;Who Cares?&lt;/h2&gt;
&lt;p&gt;The point of good tooling is to let you not care. I don’t agree with every
decision rustfmt makes about Rust or Oxfmt makes about TypeScript, but I don’t
need to. Unless the choice they make is actively causing a problem, arguing
with a formatter is a bad use of time. The responsibility is delegated to them
the same way I delegate responsibility to engineers on my team – genuinely,
not provisionally. Delegation only works if you actually let go.&lt;/p&gt;
&lt;p&gt;By choosing good tools – fast, correct tools – and giving them clear
responsibilities, we free up our time to focus on things that really matter.
Engineering time is expensive – spend it wisely.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Watch Bells</title>
        <published>2019-11-11T00:00:00+00:00</published>
        <updated>2019-11-11T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/life/projects/watch-bells/"/>
        <id>https://www.euanreid.com/life/projects/watch-bells/</id>
        
        <content type="html" xml:base="https://www.euanreid.com/life/projects/watch-bells/">&lt;p&gt;Short version: rings ship’s bells on your computer according to the traditional
watch system. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://www.watchbells.com/&quot;&gt;Download it from WatchBells.com&lt;/a&gt; or
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/euan-reid/watch-bells&quot;&gt;browse the source code&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Timekeeping is a finicky business. Or it was. The rise of the internet and
network connected clocks with it – be they smartphone or desktop – rendered
keeping a watch accurate a thing of the past. Watches themselves made
reasonably accurate time portable. But watch has more than one meaning.&lt;/p&gt;
&lt;p&gt;A ship at sea is continually operating. Emergencies, by their nature, can arise
at any time, and a ship whose crew are not ready to deal with situations at a
moment’s notice is likely soon a ship in distress. On ships large enough and
voyages long enough to warrant it, the crew responsible for the essential
functions of operation are split into two groups – the Port and Starboard
divisions – and alternate those duties, one division resting while the other
“keeps watch”.&lt;/p&gt;
&lt;p&gt;The length and timing of watches vary, particularly on smaller boats, but there
are a few common patterns, the most well known and assumed-default of which
being the one formed by the British Navy in the Age of Sail. This pattern breaks
the day into 5 four-hour segments and 2 two-hour segments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First Watch (8pm-midnight)&lt;/li&gt;
&lt;li&gt;Middle Watch (midnight-4am)&lt;/li&gt;
&lt;li&gt;Morning Watch (4am-8am)&lt;/li&gt;
&lt;li&gt;Forenoon Watch (8am-midday)&lt;/li&gt;
&lt;li&gt;Afternoon Watch (midday-4pm)&lt;/li&gt;
&lt;li&gt;First Dog Watch (4pm-6pm)&lt;/li&gt;
&lt;li&gt;Last Dog Watch (6pm-8pm)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By creating an odd number of watches, the dog watches result in each division’s
watch hours changing from day to day. They also, by being shorter and arranged
around dinner time, make it easier to feed the entire crew a main meal with the
least amount of effort.&lt;/p&gt;
&lt;p&gt;But back to timekeeping. For much of said Age of Sail there was no portable way
to keep time (the marine chronometer being invented in 1761, and the Age of Sail
commonly held to be 1571-1862), and ships – useful ships, anyway – tend to
move around. However, solar noon can be readily observed and confirmed with a
sextant, giving a reference point. Portable hourglasses, unlike chronometers,
have been available since ancient times. By combining the two, ships were able
to keep track of time accurately enough for day-to-day practical purposes –
and to convey this to the crew, the ship’s bell would be rung every half hour.&lt;/p&gt;
&lt;p&gt;Of course, a single toll every half hour is only so useful when people might be
asleep for some number of them. Instead of ringing one for every half hour since
last noon (which would get cumbersome very quickly), bells instead count
through the half hours of a watch. Eight bells (or four, for the first dog
watch) signals the end of a watch, and for the next to take their posts.&lt;/p&gt;
&lt;p&gt;There’s one last thing to know, however, about the number of bells rung. The
last dog watch rings one through three bells again, rather than five through
seven. This is not, as might be assumed, because the watch is split and the
latter half is counting from their start. Instead, it is due to the Nore mutiny
of 1797 – five bells of the dog watch was the mutineers signal to commence so
it was decided to never again ring it, leading to the
one-two-three-four-one-two-three-eight pattern.&lt;/p&gt;
&lt;p&gt;History lesson complete, the project itself – ship’s bells for the desktop.
Using the computer clock, this program strikes bells in accordance with the
traditional watch system. It can be muted, unmuted, or closed by right clicking
on the tray icon. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/euan-reid/watch-bells&quot;&gt;The source code is available on
GitHub&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Blackberry-Sloe Sour</title>
        <published>2018-11-26T00:00:00+00:00</published>
        <updated>2018-11-26T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/life/cocktails/blackberry-sloe-sour/"/>
        <id>https://www.euanreid.com/life/cocktails/blackberry-sloe-sour/</id>
        
        <summary type="html">&lt;p&gt;A twist on a classic, this berry-forward drink has a pleasantly sticky
sweetness but remains surprisingly refreshing.&amp;hellip;
&lt;/p&gt;
</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Typhoon</title>
        <published>2018-11-25T00:00:00+00:00</published>
        <updated>2018-11-25T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/life/cocktails/typhoon/"/>
        <id>https://www.euanreid.com/life/cocktails/typhoon/</id>
        
        <summary type="html">&lt;p&gt;Illegal to serve in many bars around the globe due to its formidable alcohol
content, the Typhoon is “like a Dark and Stormy but far more dangerous” – and
one of the most delicious things I’ve ever drunk.&amp;hellip;
&lt;/p&gt;
</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Challenge Rating</title>
        <published>2018-11-17T00:00:00+00:00</published>
        <updated>2018-11-17T00:00:00+00:00</updated>
        
        <author>
          <name>Euan Reid</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.euanreid.com/life/roleplaying/homebrew/challenge-rating/"/>
        <id>https://www.euanreid.com/life/roleplaying/homebrew/challenge-rating/</id>
        
        <summary type="html">&lt;p&gt;Originally devised for Dungeons &amp;amp; Dragons 5e, this is a quick way to tune an
NPC to the party facing it. It sets armour class, hit points, attack bonus, and
damage without relying on the game’s built-in Challenge Rating. It transfers
readily to other d20 games, and often to other systems.&amp;hellip;
&lt;/p&gt;
</summary>
        
    </entry>
</feed>
