<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Liam Asman&#39;s Blog</title>
    <link>https://liamasman.com/</link>
    <description>Recent content on Liam Asman&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-GB</language>
    <copyright>Copyright © 2025, Liam Asman.</copyright>
    <lastBuildDate>Sun, 23 Nov 2025 17:30:00 +0000</lastBuildDate>
    <atom:link href="https://liamasman.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Avoid booleans by default</title>
      <link>https://liamasman.com/blog/posts/2025/11/avoid-booleans-by-default/</link>
      <pubDate>Sun, 23 Nov 2025 17:30:00 +0000</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/11/avoid-booleans-by-default/</guid>
      <description>&lt;p&gt;Booleans make maintaining and changing code needlessly error-prone. Use enums instead.&lt;/p&gt;&#xA;&lt;h3 id=&#34;method-parameters&#34;&gt;Method parameters&lt;/h3&gt;&#xA;&lt;p&gt;What does the following function do?&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;updateState(state, true);&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;Specifically, what does &lt;code&gt;true&lt;/code&gt; mean? What would it mean to be false?&lt;/p&gt;&#xA;&lt;p&gt;Modern IDEs may give the parameter name as a hint, but it&amp;rsquo;s still cumbersome to read.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;updateState(state, silent: true)&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;A boolean in a method implies that changing the boolean changes the behaviour, so there is a high likelihood of that&#xA;method containing an if statement. So why not just make two separate methods and keep the methods shorter?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Booleans make maintaining and changing code needlessly error-prone. Use enums instead.</p>
<h3 id="method-parameters">Method parameters</h3>
<p>What does the following function do?</p>
<p><code>updateState(state, true);</code></p>
<p>Specifically, what does <code>true</code> mean? What would it mean to be false?</p>
<p>Modern IDEs may give the parameter name as a hint, but it&rsquo;s still cumbersome to read.</p>
<p><code>updateState(state, silent: true)</code></p>
<p>A boolean in a method implies that changing the boolean changes the behaviour, so there is a high likelihood of that
method containing an if statement. So why not just make two separate methods and keep the methods shorter?</p>





<pre tabindex="0"><code>updateStateSilently(State state);
updateStateWithNotification(State state);</code></pre><p>Here&rsquo;s another scenario:</p>





<pre tabindex="0"><code>void updateState(State state, bool silent, bool isAdmin);</code></pre><p>What happens when we want to make a change to the function signature, such as removing one of the booleans?
We need to be very careful that we refactor appropriately - deleting the wrong parameter could incorrectly invoke
admin privileges!</p>
<p>Again, ide tools may manage to handle this for you, but it&rsquo;s not fool proof. What if instead, we used an enum?</p>





<pre tabindex="0"><code>void updateState(State state, NotificationMode notificationmode, PrincipalStatus principalStatus);

...

void updateState(state, NotificationMode.SILENT, PrincipalStatus.USER);</code></pre><p>Now, if we incorrectly deleted the wrong parameter, we&rsquo;ll get a compilation error instead!</p>
<h3 id="state">State</h3>
<p>Sometimes, you might have a boolean field in an object.</p>
<p>Consider the following example of an Order in a financial exchange. Sometimes, a user may want to place an order onto the
order book, but want it to be cancelled if it would immediately match with an opposite order already on the book
(frequently used by market makers). We call this a *post only` order.</p>





<pre tabindex="0"><code>NewOrder{
  Symbol symbol,
  Price price,
  Quantity quantity,
  boolean postOnly
}</code></pre><p>As a developer, we&rsquo;ve been tasked with implementing a new behaviour: if a post-only order would match, then instead
of cancelling the order, we adjust the price of the order to be as close as possible to the original price without
it matching.</p>
<p>We could add a new boolean to the object, or an enum that expresses the behaviour of the post only order, but we&rsquo;d only
set it if the order was post only to begin with. This makes for some unsightly code, with behaviours that aren&rsquo;t entirely
predicatble to a developer reading the code for the first time.</p>
<p>Instead, we could change the postOnly field from a boolean to an enum, with three possible behaviours:</p>





<pre tabindex="0"><code>OnMatchBehaviour.EXECUTE
OnmatchBehaviour.CANCEL
OnmatchBehaviour.ADJUST</code></pre><p>But because we used a boolean to start with, we now have to change many places from <code>true</code> and <code>false</code>. We may also
be making a breaking change to our API. If we had used an enum in the first place, our change would have been much easier
to make.</p>
<p>I recommend using Enums as much as you can instead of booleans. The enum can have a <code>boolean isSomething()</code> method to be
used in an <code>if</code> statement. If you then need to add a third enum, removing the <code>isSomething()</code> method will then result
in a compilation failure, ensuring that you update the code in all the correct places.</p>
<p>Alternatively, you could use a <code>switch()</code> statement without a default case, so that a new Enum also results in a
compilation failure.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to stop Shokz headphones triggering standby mode in Linux</title>
      <link>https://liamasman.com/blog/posts/2025/11/how-to-stop-shokz-headphones-triggering-standby-mode-in-linux/</link>
      <pubDate>Tue, 18 Nov 2025 18:00:00 +0000</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/11/how-to-stop-shokz-headphones-triggering-standby-mode-in-linux/</guid>
      <description>&lt;p&gt;I was having a problem with my Shokz OpenComm2 headphones that when turning them on, Linux Mint would immediately prompt for shutdown/suspend.&lt;/p&gt;&#xA;&lt;p&gt;Here is how I fixed it. I am using Shokz OpenComm2 with the Loop 120 USB A adapter.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Get the Vendor ID and Product ID.&lt;/strong&gt;&lt;!-- raw HTML omitted --&gt;&#xA;With the device turned on, run &lt;code&gt;lsusb&lt;/code&gt;. Look for the following:&lt;!-- raw HTML omitted --&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Bus 003 Device 007: ID 3511:2ef2 Shokz Loop120 by Shokz&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Create a file at &lt;code&gt;/etc/udev/rules.d/10-shokz-fix.rules&lt;/code&gt;&lt;/strong&gt; with the following contents. You will need to use &lt;code&gt;sudo&lt;/code&gt; to create this file.&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Rule to prevent Shokz headphones from triggering standby/sleep&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SUBSYSTEM==&amp;#34;usb&amp;#34;, ATTRS{idVendor}==&amp;#34;3511&amp;#34;, ATTRS{idProduct}==&amp;#34;2ef2&amp;#34;, DRIVER==&amp;#34;usbhid&amp;#34;, ATTR{authorized}=&amp;#34;0&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;Replace the idVendor and idProduct with the corresponding values from &lt;code&gt;lsusb&lt;/code&gt; if necessary&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Reload the udev rules&lt;/strong&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo udevadm control --reload-rules&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Unplug and plug-in the adapter to reapply the rules to the active device.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I was having a problem with my Shokz OpenComm2 headphones that when turning them on, Linux Mint would immediately prompt for shutdown/suspend.</p>
<p>Here is how I fixed it. I am using Shokz OpenComm2 with the Loop 120 USB A adapter.</p>
<ul>
<li><strong>Get the Vendor ID and Product ID.</strong><!-- raw HTML omitted -->
With the device turned on, run <code>lsusb</code>. Look for the following:<!-- raw HTML omitted -->





<pre tabindex="0"><code>Bus 003 Device 007: ID 3511:2ef2 Shokz Loop120 by Shokz</code></pre></li>
<li><strong>Create a file at <code>/etc/udev/rules.d/10-shokz-fix.rules</code></strong> with the following contents. You will need to use <code>sudo</code> to create this file.





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span># Rule to prevent Shokz headphones from triggering standby/sleep
</span></span><span style="display:flex;"><span>SUBSYSTEM==&#34;usb&#34;, ATTRS{idVendor}==&#34;3511&#34;, ATTRS{idProduct}==&#34;2ef2&#34;, DRIVER==&#34;usbhid&#34;, ATTR{authorized}=&#34;0&#34;</span></span></code></pre></div>Replace the idVendor and idProduct with the corresponding values from <code>lsusb</code> if necessary</li>
<li><strong>Reload the udev rules</strong>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo udevadm control --reload-rules</span></span></code></pre></div></li>
</ul>
<p>Unplug and plug-in the adapter to reapply the rules to the active device.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Book Review: Start With Why - Simon Sinek</title>
      <link>https://liamasman.com/blog/posts/2025/06/book-review-start-with-why-simon-sinek/</link>
      <pubDate>Fri, 27 Jun 2025 05:00:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/06/book-review-start-with-why-simon-sinek/</guid>
      <description>&lt;p&gt;&lt;em&gt;Start With Why&lt;/em&gt; presents a compelling and practical framework that many professionals could benefit from implementing.&lt;/p&gt;&#xA;&lt;p&gt;Sinek&amp;rsquo;s core premise — that understanding your fundamental purpose drives better decision-making and long-term thinking&#xA;— is both convincing and actionable.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately, the book suffers from significant structural issues. The central concept, while valuable, could be effectively&#xA;communicated in a much shorter format. The text relies heavily on repetitive examples, with Apple&amp;rsquo;s story appearing so&#xA;frequently that it becomes distracting rather than illustrative.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><em>Start With Why</em> presents a compelling and practical framework that many professionals could benefit from implementing.</p>
<p>Sinek&rsquo;s core premise — that understanding your fundamental purpose drives better decision-making and long-term thinking
— is both convincing and actionable.</p>
<p>Unfortunately, the book suffers from significant structural issues. The central concept, while valuable, could be effectively
communicated in a much shorter format. The text relies heavily on repetitive examples, with Apple&rsquo;s story appearing so
frequently that it becomes distracting rather than illustrative.</p>
<p>While the underlying message has serious merit, the execution doesn&rsquo;t justify the investment required for the full 200+
page book.</p>
<p>For readers interested in Sinek&rsquo;s framework, his <a href="https://youtu.be/u4ZoJKF_VuA?si=k6hJCjy38mXbWvRP">original TED talk</a> delivers the same essential value in a more concise
format.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Getting to Senior Developer: Prioritisation</title>
      <link>https://liamasman.com/blog/posts/2025/06/getting-to-senior-developer-prioritisation/</link>
      <pubDate>Wed, 25 Jun 2025 05:00:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/06/getting-to-senior-developer-prioritisation/</guid>
      <description>&lt;p&gt;Being self-organised is a key attribute for becoming a senior software engineer. Part of self-organisation is the ability to prioritise tasks.&lt;/p&gt;&#xA;&lt;p&gt;Developers may get stuck pursuing minor software improvements over adding real value. This could be due to&#xA;inexperience in estimating effort versus value, and not realising when a task is taking longer than expected. Alternatively, the developer&#xA;could be choosing a low-value task that feels comfortable; achieving a solo contribution.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Being self-organised is a key attribute for becoming a senior software engineer. Part of self-organisation is the ability to prioritise tasks.</p>
<p>Developers may get stuck pursuing minor software improvements over adding real value. This could be due to
inexperience in estimating effort versus value, and not realising when a task is taking longer than expected. Alternatively, the developer
could be choosing a low-value task that feels comfortable; achieving a solo contribution.</p>
<p>When you have the freedom to choose what to work on, consider the priorities for the team and how you can best help. Remember:
today&rsquo;s priority may not be the same as yesterday&rsquo;s, so you may need to shelve what you are working on. This is okay: the work is not lost.</p>
<p>If you are not sure what the priorities are, ask! This will show initiative and higher-level thinking.</p>
<p>It&rsquo;s important to note that low <em>business</em> value does not mean low value: maintaining a healthy codebase is important. This is where the skill of
prioritisation comes in: technical debt reduction must be balanced alongside the goals of the business.</p>
<p>Think: What is the goal? How do I help us get there?</p>
]]></content:encoded>
    </item>
    <item>
      <title>Respect and Trust</title>
      <link>https://liamasman.com/blog/posts/2025/05/respect-and-trust/</link>
      <pubDate>Mon, 12 May 2025 00:00:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/05/respect-and-trust/</guid>
      <description>&lt;p&gt;In a world full of opinions, conflict, and ego - how often do we still lead with respect?&lt;/p&gt;&#xA;&lt;p&gt;Respect is a baseline acknowledgement of a person&amp;rsquo;s dignity, regardless of their views, status or usefulness to us. By&#xA;initiating with a baseline level of respect, we enable faster formation of relationships and smoother collaboration.&#xA;It&amp;rsquo;s something we should offer freely — not hold back as leverage — and be granted to every person we meet for the first&#xA;time. Nevertheless, while respect should be given, respect can also be lost.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In a world full of opinions, conflict, and ego - how often do we still lead with respect?</p>
<p>Respect is a baseline acknowledgement of a person&rsquo;s dignity, regardless of their views, status or usefulness to us. By
initiating with a baseline level of respect, we enable faster formation of relationships and smoother collaboration.
It&rsquo;s something we should offer freely — not hold back as leverage — and be granted to every person we meet for the first
time. Nevertheless, while respect should be given, respect can also be lost.</p>
<p>Trust, on the other hand, is a quantity that must be earned. Trust must be earned through consistency, honesty and
follow-through. If broken, trust will be far harder to rebuild than it was to construct in the first place.</p>
<p>In this post, I explore how trust and respect work together, why they matter, and how we can be intentional about
building both.</p>
<h2 id="what-is-trust">What is trust?</h2>
<p>In the security world, trust is something that can break your security model. For example, if we give a team member
full admin access to the database, we are trusting them to behave correctly, but there are ultimately no safeguards to
the integrity or privacy of the data.</p>
<p>We can generalise the idea. Trust is a calculated risk — we allow an entity the potential to cause harm while
believing that it won&rsquo;t. An entity could be anything: a person, some software, a rope. Harm does not need to be
intentional — we don&rsquo;t trust a toddler with a knife not because we think they might try to kill us, but because they
do not have the skills to handle the knife safely.</p>
<p>In a professional relationship, trust is placed in people when we believe they will act with integrity
and diligence. Risks associated with the installed trust are considered, with appropriate mitigation in place where
suitable, such that the benefit of placing trust in someone outweighs the risks associated with it. For example,
giving full administrator rights to a user is highly risky. Taking regular back-ups of the database and monitoring
data access mitigates the risk of accidental corruption or intentional espionage.</p>
<h2 id="earning-trust">Earning trust</h2>
<p>We do not blindly place trust in people. That would be reckless and dangerous. Now of course, if the risks are low we
may have a certain level of trust that we assume of people — trust in &ldquo;the goodness of humanity&rdquo;, if you will.
Nevertheless, those that we trust when the risks are greater have earned that trust.</p>
<p>Trust is accumulated over time through three main avenues: consistency, honesty, and reliability. Trust is also
somewhat transitive: if Alice has trust in Bob, and Bob has trust in Cathy, then Alice may also have some level of
trust in Cathy through the trust she has in Bob. Naturally, it won&rsquo;t be as strong, but it gives a head-start.</p>
<p>A significant part of being trustworthy can be boiled down to predictability; if someone can predict how you are going
to act, then they can trust in your behaviour. If your behaviour can&rsquo;t be predicted, then the other person can&rsquo;t trust
that you won&rsquo;t do them harm.</p>
<p>We can become predictable and build trust in three ways: consistency, honesty and reliability.</p>
<h3 id="consistency">Consistency</h3>
<p>When you are consistent in your actions you become predictable. When you have shown a stable behaviour in the past,
I can predict that your behaviour will be the same in the future. Be consistent in how you show up and interact with
people. Be consistent in your decision-making. Be consistent in your processes.</p>
<h3 id="honesty">Honesty</h3>
<p>Obviously, a liar can&rsquo;t be trusted. However, in this regard honesty goes further. I can add three more dimensions to
what it means to be honest: being open, admitting fault over pushing blame, and being self-reflective.</p>
<p>Being transparent and open means allowing people to understand our thought processes, and allowing them to challenge
us when we are wrong. When someone knows why you made a decision, even if they don&rsquo;t agree with it, they are more
likely to engage with us positively and accept the decision. Also, we should not hide when things are going wrong.
Informing others when things are going badly is better to be done early so that fixes require less effort by all
involved.</p>
<p>Admitting fault is a sign of maturity and leadership. A trustworthy person knows they are not the centre of the
universe, and are not infallible.</p>
<p>Being self-critical and reflective is a sign of growth. Learn to analyise and recognise how your actions affected
outcomes. You will be more trusted if you can show you are open to change.</p>
<h3 id="reliability">Reliability</h3>
<p>Our word is our most valuable asset. When we say we will do something, it is important that we follow through on our
promises. By having a track record of doing as we say, we can be trusted in the future.</p>
<p>Similarly, we should not gossip. It only signals that you are not a safe person to trust.</p>
<h2 id="breaking-and-building-trust">Breaking and building trust</h2>
<p>When we have built trust, we have demonstrated the qualities of ourselves that make us trustworthy — consistency,
honesty, and reliability.</p>
<p>When trust is broken, it means that we have shown that at least one of those qualities was not actually true of us. In
order to rebuild trust, we must show not only that we have the quality that was deficit, but that we have actually
learned from our experience, grown, and built that quality into who we are now.</p>
<p>This is why I believe it is far harder for someone to regain the trust of another, than to build that trust in the first
place.</p>
<p>For the person we have harmed, there is an emotional cost and a fear of being burned again that must be overcome.</p>
<p>This is why it is so important to stick to your word, even in small matters.</p>
<h2 id="respect-a-different-kind-of-currency">Respect: a different kind of currency</h2>
<p>We have discussed how trust is earned through demonstrating qualities of consistency, honesty, and reliability.
Respect, on the other hand, should be given to all by default as a sign of human dignity. You may build a deeper
respect for someone that you know well or who has achieved lots, but every new interaction should begin with a
baseline level of respect.</p>
<p>This starting level of respect should assume that the other person is competent and well-meaning, and has value to the
wider world. We should give them time to speak and be heard, and not interrupt or talk over them.</p>
<p>However, respect can be lost. No matter what, we should always treat people as we would like to be treated.
Nevertheless, if someone displays qualities or behaviours that fall short of the standards we assume all well-meaning
and competent people have, the respect we share towards them will similarly fall.</p>
<p>As someone loses our respect, we should not start treating them poorly, of course. Remember the golden rule: &ldquo;Treat
others as you yourself would like to be treated&rdquo;. However, it would be human to be more avoidant of that person,
and not put as much value in their opinions. Should a professional relationship suffer from falling respect, it is
important that it is addressed and managed correctly, with discussions with managers, and HR if appropriate.</p>
<p>Respect can be lost through arrogance, incompetence, or the general disregard for others&rsquo; boundaries, time, or values.
Respect can also be multi-dimensional - you could respect someone&rsquo;s work ethic, for example, while not respecting their
management style.</p>
<h2 id="interaction-of-trust-and-respect">Interaction of trust and respect</h2>
<p>Respect and trust will often move in tandem, but there is no obligation for them to do so.</p>
<p>You may respect someone&rsquo;s skills, but not trust their motives. You may trust someone emotionally, but not respect
their judgement.</p>
<p>That said, in high functioning teams and relationships, mutual trust and respect are present and reinforcing each other.</p>
<p>That is why it is so important to continuously work on the behaviours that strengthen both respect and trust, and make
them an integral part of who we are by building good habits.</p>
<h2 id="building-respect">Building respect</h2>
<p>While we should give respect to everybody, we can not control how they give respect to others. Some people may be
more open than others. In any case, we may just wish to have a stronger relationship and deepen the mutual respect.</p>
<p>Here are eight ways we can encourage another&rsquo;s respect of ourselves to grow:</p>
<ul>
<li><strong>Listen</strong>. Learn to actively listen, not just wait for a gap to say your thing. Especially when there is a
disagreement.</li>
<li><strong>Acknowledge time and effort</strong>. No matter the person&rsquo;s role, their contribution is meaningful.</li>
<li><strong>Treat everyone with the same level of courtesy</strong>, not just those &ldquo;above&rdquo; you.</li>
<li><strong>Don&rsquo;t interrupt or talk over others</strong> — it signals disrespect even if unintentional.</li>
<li><strong>Be open to feedback</strong> without defensiveness.</li>
<li><strong>Give credit publicly</strong>. Critique in private.</li>
<li><strong>Respect boundaries</strong> — personal, professional, and emotional.</li>
<li><strong>Demonstrate respect towards others</strong>, and respect towards you will follow.</li>
</ul>
<h2 id="final-thoughts">Final thoughts</h2>
<p><strong>Key takeaways:</strong></p>
<ul>
<li>Respect is a starting point; trust is an earned position</li>
<li>Trust is fragile - harder to regain than to build</li>
<li>Living with integrity protects both</li>
</ul>
<p><strong>To build trust:</strong></p>
<ul>
<li>Keep your word, even in the small things - people notice</li>
<li>Admit mistakes early. Honesty in failure builds more trust than hiding the truth</li>
<li>Be consistent - trust thrives on predictability over time</li>
<li>Follow through - If you say you&rsquo;ll do it, do it</li>
<li>Be transparent - especially when you can&rsquo;t deliver or something changes</li>
<li>Don&rsquo;t gossip or break confidences - it signals you&rsquo;re not a safe person to trust</li>
<li>Build trust by proxy - earn trust faster by being vouched for by someone already trusted</li>
</ul>
<p><strong>To build respect:</strong></p>
<ul>
<li>Actively listen</li>
<li>Acknowledge time and effort</li>
<li>Treat everyone with the same level of courtesy</li>
<li>Don&rsquo;t interrupt or talk over others</li>
<li>Be open to feedback</li>
<li>Give credit publicly</li>
<li>Respect boundaries</li>
<li>Respect others</li>
</ul>
<p>Trust and respect aren&rsquo;t just values to be talked about; they&rsquo;re behaviours we demonstrate. They&rsquo;re built (or broken)
in the everyday: in how we listen, how we follow through, and how we treat others when it&rsquo;s inconvenient. You don&rsquo;t
need a title to earn respect, and you don&rsquo;t need permission to start building trust.</p>
<p>How are you showing up to build trust and earn lasting respect?</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to type Em-Dashes in Linux Mint</title>
      <link>https://liamasman.com/blog/posts/2025/05/how-to-type-em-dashes-in-linux-mint/</link>
      <pubDate>Sat, 10 May 2025 17:00:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/05/how-to-type-em-dashes-in-linux-mint/</guid>
      <description>&lt;p&gt;The em-dash &amp;ldquo;—&amp;rdquo; is a trusty steed for writers, used structure to a sentence where a comma might not suffice.&lt;/p&gt;&#xA;&lt;p&gt;It has been said to be a sign of plagiarism using generative AI, because most computer keyboards do not have the&#xA;em-dash, and so most people wouldn&amp;rsquo;t type with them naturally. That said, if a text has been written using an editor&#xA;like Microsoft Word then the em-dash might have been autocorrected into place over a hyphen.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The em-dash &ldquo;—&rdquo; is a trusty steed for writers, used structure to a sentence where a comma might not suffice.</p>
<p>It has been said to be a sign of plagiarism using generative AI, because most computer keyboards do not have the
em-dash, and so most people wouldn&rsquo;t type with them naturally. That said, if a text has been written using an editor
like Microsoft Word then the em-dash might have been autocorrected into place over a hyphen.</p>
<p>Personally, I quite like the dash. While I was once oblivious to the difference between a hyphen &ldquo;-&rdquo; and an em-dash &ldquo;—&rdquo;,
the recent discussion around AI writing has made me realise that I should be using the em-dash (if we&rsquo;re approaching
syntax prescriptively). The hyphen is for compound words, like <em>em-dash</em>. The em-dash, on the other hand, is used to
separate clauses.</p>
<p>Here&rsquo;s how to type the em-dash (and other special characters) in Linux Mint — specifically version 22.1 Cinnamon —
which is the OS I am currently using.</p>
<h2 id="instructions">Instructions</h2>
<p><strong>1. Open:</strong>
<em>System Settings → Keyboard → Layouts → Options</em></p>
<p><strong>2. Expand:</strong>
<em>&ldquo;Position of Compose Key&rdquo;</em></p>
<p><strong>3. Select a compose key.</strong></p>
<p>I chose <em>&lsquo;Right Ctrl&rsquo;</em>.
Close the window when done.</p>
<p><strong>4. Type an em-dash:</strong></p>
<p>Press <code>&lt;compose key&gt; - - -</code></p>
<p>(That is, press the compose key, then press the hyphen key three times.)</p>
<p>You do not need to hold the compose key down while typing the hyphens.</p>
<p>To type an en-dash, use: <code>&lt;compose key&gt; - - .</code></p>
<h2 id="some-other-useful-compose-sequences">Some other useful compose sequences:</h2>
<p>The full list of compose sequences can be found at
<code>/usr/share/X11/locale/en_US.UTF-8/Compose</code></p>
<table>
  <thead>
      <tr>
          <th>Character</th>
          <th>Compose Sequence</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>—</td>
          <td><code>- - -</code></td>
      </tr>
      <tr>
          <td>–</td>
          <td><code>- - .</code></td>
      </tr>
      <tr>
          <td>Ä</td>
          <td><code>A &quot;</code></td>
      </tr>
      <tr>
          <td>ä</td>
          <td><code>a &quot;</code></td>
      </tr>
      <tr>
          <td>±</td>
          <td><code>+ -</code></td>
      </tr>
      <tr>
          <td>¢</td>
          <td><code>| c</code></td>
      </tr>
      <tr>
          <td>¥</td>
          <td><code>Y =</code></td>
      </tr>
      <tr>
          <td>€</td>
          <td><code>c =</code></td>
      </tr>
      <tr>
          <td>§</td>
          <td><code>s o</code></td>
      </tr>
      <tr>
          <td>©</td>
          <td><code>o c</code></td>
      </tr>
      <tr>
          <td>®</td>
          <td><code>o r</code></td>
      </tr>
      <tr>
          <td>™</td>
          <td><code>t m</code></td>
      </tr>
      <tr>
          <td>‹</td>
          <td><code>. &lt;</code></td>
      </tr>
      <tr>
          <td>›</td>
          <td><code>. &gt;</code></td>
      </tr>
      <tr>
          <td>«</td>
          <td><code>&lt; &lt;</code></td>
      </tr>
      <tr>
          <td>»</td>
          <td><code>&gt; &gt;</code></td>
      </tr>
      <tr>
          <td>°</td>
          <td><code>o o</code></td>
      </tr>
      <tr>
          <td>²</td>
          <td><code>^ 2</code></td>
      </tr>
      <tr>
          <td>³</td>
          <td><code>^ 3</code></td>
      </tr>
      <tr>
          <td>µ</td>
          <td><code>m u</code></td>
      </tr>
      <tr>
          <td>…</td>
          <td><code>. .</code></td>
      </tr>
      <tr>
          <td>₀</td>
          <td><code>_ 0</code></td>
      </tr>
      <tr>
          <td>₁</td>
          <td><code>_ 1</code></td>
      </tr>
      <tr>
          <td>‽</td>
          <td><code>? !</code></td>
      </tr>
      <tr>
          <td>†</td>
          <td><code>| -</code></td>
      </tr>
      <tr>
          <td>‡</td>
          <td><code>| =</code></td>
      </tr>
      <tr>
          <td>♥</td>
          <td><code>&lt; 3</code></td>
      </tr>
      <tr>
          <td>💩</td>
          <td><code>p o o</code></td>
      </tr>
      <tr>
          <td>ℕ</td>
          <td><code>N N</code></td>
      </tr>
      <tr>
          <td>ℚ</td>
          <td><code>Q Q</code></td>
      </tr>
      <tr>
          <td>ℝ</td>
          <td><code>R R</code></td>
      </tr>
      <tr>
          <td>ℤ</td>
          <td><code>Z Z</code></td>
      </tr>
      <tr>
          <td>←</td>
          <td><code>&lt; -</code></td>
      </tr>
      <tr>
          <td>↑</td>
          <td><code>| ^</code></td>
      </tr>
      <tr>
          <td>→</td>
          <td><code>- &gt;</code></td>
      </tr>
      <tr>
          <td>↓</td>
          <td><code>| v</code></td>
      </tr>
      <tr>
          <td>≤</td>
          <td><code>&lt; =</code></td>
      </tr>
      <tr>
          <td>≥</td>
          <td><code>&gt; =</code></td>
      </tr>
  </tbody>
</table>
]]></content:encoded>
    </item>
    <item>
      <title>Trunk-based development</title>
      <link>https://liamasman.com/blog/posts/2025/04/trunk-based-development/</link>
      <pubDate>Sat, 19 Apr 2025 16:30:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/04/trunk-based-development/</guid>
      <description>&lt;h2 id=&#34;what-is-trunk-based-development&#34;&gt;What is trunk-based development?&lt;/h2&gt;&#xA;&lt;p&gt;Trunk-based development is a collaborative development approach where all developers&#xA;commit directly to the main branch (often called &amp;ldquo;trunk&amp;rdquo;). Feature branches and&#xA;pull-requests should be avoided. Instead, teams rely on fast feedback loops,&#xA;high collaboration, and strong CI practices to maintain code quality and stability.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-is-trunk-based-development-better-than-branches&#34;&gt;Why is trunk-based development better than branches?&lt;/h2&gt;&#xA;&lt;p&gt;Feature branches are ineffective for several reasons:&lt;/p&gt;&#xA;&lt;h3 id=&#34;1-slow-feedback-loop&#34;&gt;1. Slow feedback loop&lt;/h3&gt;&#xA;&lt;p&gt;The pull request cycle requires waiting for a reviewer. After receiving feedback,&#xA;you make changes, then wait again. Repeat ad nauseum.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="what-is-trunk-based-development">What is trunk-based development?</h2>
<p>Trunk-based development is a collaborative development approach where all developers
commit directly to the main branch (often called &ldquo;trunk&rdquo;). Feature branches and
pull-requests should be avoided. Instead, teams rely on fast feedback loops,
high collaboration, and strong CI practices to maintain code quality and stability.</p>
<h2 id="why-is-trunk-based-development-better-than-branches">Why is trunk-based development better than branches?</h2>
<p>Feature branches are ineffective for several reasons:</p>
<h3 id="1-slow-feedback-loop">1. Slow feedback loop</h3>
<p>The pull request cycle requires waiting for a reviewer. After receiving feedback,
you make changes, then wait again. Repeat ad nauseum.</p>
<h3 id="2-merge-conflicts">2. Merge conflicts</h3>
<p>You wrote the code against a version of the main branch. It may have moved on
since then. You now have to spend time fixing merge-conflicts.</p>
<h3 id="3-quality">3. Quality</h3>
<p>Reviewers did not write the code. Reading and understanding code takes time,
especially for a pull request for a full feature - otherwise it gets skimmed and
rubber-stamped. Either quality suffers, or velocity does.</p>
<h2 id="how-do-we-keep-quality-high-without-pull-requests">How do we keep quality high without pull requests?</h2>
<h3 id="pair-programming">Pair programming</h3>
<p>Pair programming means continuous code review. No waiting. Code quality improves,
defects are caught early, and features are developed faster as pairs bounce ideas
between themselves, rather than waiting for responses to questions in a team channel.</p>
<p>Pair programming also results in better knowledge sharing and improved developer
satisfaction.</p>
<h3 id="test-driven-development-and-responsive-ci">Test driven development and responsive CI</h3>
<p>Commit early, commit often. Comprehensive test suites should be run for every commit.
The test suite should complete quickly - ideally within 10 minutes. If a commit
breaks the build, revert immediately. Don&rsquo;t wait for the next developer to notice.
Don&rsquo;t leave the broken commit while you fix the bug. Revert - push - fix - push.</p>
<p>Trunk should always be releasable.</p>
<h3 id="feature-toggles-and-incremental-commits">Feature toggles and incremental commits</h3>
<p>Big features often require a lot of work to get working; an acceptance test for
a feature may not pass until the end of development.
Instead of completing the entire feature before committing, disable
the test and commit in small, testable increments.</p>
<p>Use static feature flags to disable compilation or run-time behaviour that
shouldn&rsquo;t be visible to users yet. You can safely commit
code with a failing test, as long as it doesn&rsquo;t cause the tests for existing behaviour
to fail, and the failing test is disabled until the feature flag is enabled.</p>
<p>This lets us commit in small, frequent batches. Any merge conflicts will then hopefully be
minimal in scope and impact.</p>
<h2 id="other-benefits">Other benefits</h2>
<h3 id="ship-more-often">Ship more often</h3>
<p>The only code that matters is code that is in production.
The only code that is in production is code that is in the main branch.
Working on trunk means working on what matters.</p>
<p>By having trunk always in a releasable state, we can ship to production at any
time. This means we can ship as often as we&rsquo;d like.</p>
<h3 id="boosted-morale">Boosted morale</h3>
<p>Developers like to get things into production. Having code sit on a feature
branch for a long time damages morale. Big-bang releases are also anxiety inducing.
Both of these are avoided with trunk-based development and frequent releases.</p>
<h3 id="better-collaboration">Better collaboration</h3>
<p>Long-lived branches create knowledge silos; when a developer spends a long time
on a feature branch they become the de facto owner of that code. If they are
away for any reason, progress stalls.</p>
<p>This is avoided with pair-programming and frequent commits to the main branch
which form a log of work done and break the task up into smaller, more manageable
tasks.</p>
<h2 id="in-summary">In summary</h2>
<p>For faster delivery, better software quality, and happier teams:</p>
<ul>
<li>Pair program</li>
<li>Write tests first</li>
<li>Run fast CI</li>
<li>Commit small, commit often, commit to main</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Vibe Coding</title>
      <link>https://liamasman.com/blog/posts/2025/04/vibe-coding/</link>
      <pubDate>Thu, 17 Apr 2025 18:00:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/04/vibe-coding/</guid>
      <description>&lt;p&gt;&amp;ldquo;Vibe Coding&amp;rdquo; is a term used to describe the creation of software simply by&#xA;prompting an LLM, and accepting whatever it outputs.&lt;/p&gt;&#xA;&lt;p&gt;Although the term soon became the butt of some jokes, I believe there is a place&#xA;for &amp;lsquo;Vibe Coding&amp;rsquo; in serious software development.&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/vibe-coding/vibe-tweet_hu_b6a0507b350a280f.png&#34; alt=&#34;Post on X (formerly known as Twitter) by Andrej Karpathy (@karpathy). 11:17pm, 2 February 2025. There\&amp;#39;s a new kind of coding I call \&amp;#34;vibe coding\&amp;#34;, where you fully give in to the vibes, embrace exponentials, and forget that the code even exists. It\&amp;#39;s possible because the LLMs (e.g. Cursor Composer w Sonnet) are getting too good. Also I just talk to Composer with SuperWhisper so I barely even touch the keyboard. I ask for the dumbest things like \&amp;#34;decrease the padding on the sidebar by half\&amp;#34; because I\&amp;#39;m too lazy to find it. I \&amp;#34;Accept All\&amp;#34; always, I don\&amp;#39;t read the diffs anymore. When I get error messages I just copy paste them in with no comment, usually that fixes it. The code grows beyond my usual comprehension, I\&amp;#39;d have to really read through it for a while. Sometimes the LLMs can\&amp;#39;t fix a bug so I just work around it or ask for random changes until it goes away. It\&amp;#39;s not too bad for throwaway weekend projects, but still quite amusing. I\&amp;#39;m building a project or webapp, but it\&amp;#39;s not really coding - I just see stuff, say stuff, run stuff, and copy paste stuff, and it mostly works.&#34; class=&#34;post-img&#34; title=&#34;I&amp;#39;m not sure about the term, but Andrej has a point about it being &amp;#39;Not bad for throwaway weekend projects&amp;#39;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;Andrej Karpathy has been credited with coining the term &#34;Vibe Coding&#34;.&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>&ldquo;Vibe Coding&rdquo; is a term used to describe the creation of software simply by
prompting an LLM, and accepting whatever it outputs.</p>
<p>Although the term soon became the butt of some jokes, I believe there is a place
for &lsquo;Vibe Coding&rsquo; in serious software development.</p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/vibe-coding/vibe-tweet_hu_b6a0507b350a280f.png" alt="Post on X (formerly known as Twitter) by Andrej Karpathy (@karpathy). 11:17pm, 2 February 2025. There\&#39;s a new kind of coding I call \&#34;vibe coding\&#34;, where you fully give in to the vibes, embrace exponentials, and forget that the code even exists. It\&#39;s possible because the LLMs (e.g. Cursor Composer w Sonnet) are getting too good. Also I just talk to Composer with SuperWhisper so I barely even touch the keyboard. I ask for the dumbest things like \&#34;decrease the padding on the sidebar by half\&#34; because I\&#39;m too lazy to find it. I \&#34;Accept All\&#34; always, I don\&#39;t read the diffs anymore. When I get error messages I just copy paste them in with no comment, usually that fixes it. The code grows beyond my usual comprehension, I\&#39;d have to really read through it for a while. Sometimes the LLMs can\&#39;t fix a bug so I just work around it or ask for random changes until it goes away. It\&#39;s not too bad for throwaway weekend projects, but still quite amusing. I\&#39;m building a project or webapp, but it\&#39;s not really coding - I just see stuff, say stuff, run stuff, and copy paste stuff, and it mostly works." class="post-img" title="I&#39;m not sure about the term, but Andrej has a point about it being &#39;Not bad for throwaway weekend projects&#39;" loading="lazy">
    

<span class="img-caption">
    
Andrej Karpathy has been credited with coining the term "Vibe Coding".

</span></p>
<p>Let&rsquo;s be clear; this is not a replacement for software development. Unchecked,
untested code should not make its way to production. I do not believe AI will be
a replacement for programmers any time soon, and certainly not in its current
state.</p>
<p>What AI can do is improve a developer&rsquo;s productivity. If I do not know how to
build an iOS app, AI can get me started, or if I do not know a particular API, AI
can point me in the right direction. This is AI used as a learning aid. All the
AI&rsquo;s output should be read, understood. Anything that is confusing should be
clarified and verified. Production code should be tested, and the test cases
designed by a human.</p>
<p>If I need to write a suite of similar looking tests, AI can help me generate them.
This is AI used as a productivity tool to remove tedious, repetitive tasks. Again,
all the AI&rsquo;s output should be checked.</p>
<p>&lsquo;Vibe coding&rsquo;, at its extreme, involves blindly accepting whatever the LLM has
generated. We do not check the output, we do not understand it. We run the
program, and if it does something wrong, we tell the AI to fix it. Edge cases
are ignored, and the code is not backed by a comprehensive test suite.
This is code that is fragile. This is code that is unmaintainable.</p>
<p>This is code that is not fit for production.</p>
<p>But it is fit for a prototype. It is fit for a proof of concept. It is fit for a
hackathon.</p>
<p>To build good software fast, we need an engineering mindset. We need to test
early and often and get fast feedback. A common issue in commercial software
development is that the business doesn&rsquo;t know what it wants, or isn&rsquo;t aware of
all the issues or edge cases that need business consideration.</p>
<p>A prototype that can be built quickly with vibe coding can be shown to the
business team and used to gather feedback. It can be used to explore the
problem space. It can be used to explore the solution space. It can be used to
explore the user experience. It can be used to explore the technology stack.
It can be used to explore the business model.</p>
<p>Once you have your feedback, and you move to writing production quality software,
the vibe code may be referenced, but picked from with consideration. Standard
software engineering practices should be followed; pair-programming and test-driven-development
must not be forgotten about. Ensure those that see the prototype understand that
it is an early prototype for gathering feedback, and not production quality code -
we all know how sales people can take a prototype and run with it!</p>
<p>I expect that in the future AI will be a competent pair-programmer. I do not
think we are at that stage yet. To blindly trust AI code would be a mistake. But
we do not need to trust it for it to be useful.</p>
<p>So get vibing! Try it yourself, but remember to set boundaries. Start a dialogue
with your teams about how to use AI in your software development process.
Finally, share your experiences! The more we share our experiences of using AI,
the faster the engineering community can learn and adapt to this rapidly
evolving technology.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A trip to York</title>
      <link>https://liamasman.com/blog/posts/2025/04/a-trip-to-york/</link>
      <pubDate>Tue, 15 Apr 2025 21:19:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/04/a-trip-to-york/</guid>
      <description>&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_001_hu_9ae02ee001e6f6d5.jpg&#34; alt=&#34;A collection of coloured Ghosts in the Yorkshire Ghost Merchants shop&#34; class=&#34;gallery-img&#34; title=&#34;An audience with the Ghosts&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;An audience with the Ghosts in The Shambles&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_002_hu_bff929960e0b4694.jpg&#34; alt=&#34;A pair of Ghosts in a street beneath a banner from York Ghost Merchants&#34; class=&#34;gallery-img&#34; title=&#34;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;A pair of Ghosts&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_003_hu_83ec29b7fd759441.jpg&#34; alt=&#34;A roast dinner in a Yorkshire pudding&#34; class=&#34;gallery-img&#34; title=&#34;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;Roast dinner in a Yorkshire pudding&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_004_hu_9433d9fb5a4ec1c1.jpg&#34; alt=&#34;Ladybug&#34; class=&#34;gallery-img&#34; title=&#34;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;Ladybug&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_005_hu_f4ce2a0aaee30aa5.jpg&#34; alt=&#34;River Ouse&#34; class=&#34;gallery-img&#34; title=&#34;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;River Ouse&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_006_hu_313a6974bcee1c59.jpg&#34; alt=&#34;Man and two children on a horse-pulled rickshaw&#34; class=&#34;gallery-img&#34; title=&#34;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;    &#xA;    &#xA;    &#xA;    &#xA;        &#xA;        &lt;img src=&#34;https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_007_hu_72ef5e632396eea5.jpg&#34; alt=&#34;Man on a bench in a park sleeping&#34; class=&#34;gallery-img&#34; title=&#34;&#34; loading=&#34;lazy&#34;&gt;&#xA;    &#xA;&#xA;&lt;span class=&#34;img-caption&#34;&gt;&#xA;    &#xA;Nice place for a nap&#xA;&#xA;&lt;/span&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_001_hu_9ae02ee001e6f6d5.jpg" alt="A collection of coloured Ghosts in the Yorkshire Ghost Merchants shop" class="gallery-img" title="An audience with the Ghosts" loading="lazy">
    

<span class="img-caption">
    
An audience with the Ghosts in The Shambles

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_002_hu_bff929960e0b4694.jpg" alt="A pair of Ghosts in a street beneath a banner from York Ghost Merchants" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
A pair of Ghosts

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_003_hu_83ec29b7fd759441.jpg" alt="A roast dinner in a Yorkshire pudding" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
Roast dinner in a Yorkshire pudding

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_004_hu_9433d9fb5a4ec1c1.jpg" alt="Ladybug" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
Ladybug

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_005_hu_f4ce2a0aaee30aa5.jpg" alt="River Ouse" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
River Ouse

</span></p>



    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_006_hu_313a6974bcee1c59.jpg" alt="Man and two children on a horse-pulled rickshaw" class="gallery-img" title="" loading="lazy">
    

<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_007_hu_72ef5e632396eea5.jpg" alt="Man on a bench in a park sleeping" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
Nice place for a nap

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_008_hu_3c947bb0bb9edcbc.jpg" alt="A bouquet of flowers on a bench with a card. The card reads &#34;This is a birthday bouquet, for my dearest friend. Happy birthday to him! Maybe he won&#39;t ever cross paths with it. But maybe... he will?&#34;" class="gallery-img" title="&#34;This is a birthday bouquet, for my dearest friend. Happy birthday to him! Maybe he won&#39;t ever cross paths with it. But maybe... he will&#34;" loading="lazy">
    

<span class="img-caption">
    
I would love to know the story behind this card

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250411_York_009_hu_5b6f99af11c696ba.jpg" alt="A red hot air balloon high in the sky over York Minster" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
High in the sky

</span></p>



    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250412_York_010_hu_39b4ed813a806ca7.jpg" alt="A brick building at the end of an alley way with leafy plants on the facade. Three school children are walking up the alley." class="gallery-img" title="" loading="lazy">
    

<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250412_York_011_hu_ee5ed92efe1cf90.jpg" alt="A statue of a cat pokes its head out over the porch of The Three Tuns pub" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
York has a cat trail!

</span></p>
<p>


    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250412_York_012_hu_33a55c787d423a9b.jpg" alt="York Minster lit up at night" class="gallery-img" title="" loading="lazy">
    

<span class="img-caption">
    
York Minster

</span></p>



    
    
    
    
        
        <img src="https://liamasman.com/blog/posts/2025/04/a-trip-to-york/20250412_York_013_hu_8ecc2c774a182473.jpg" alt="Two people looking at the city map in front of York Minster" class="gallery-img" title="" loading="lazy">
    

]]></content:encoded>
    </item>
    <item>
      <title>Creating a simple blog with Hugo and Netlify</title>
      <link>https://liamasman.com/blog/posts/2025/04/creating-a-simple-blog-with-hugo-and-netlify/</link>
      <pubDate>Wed, 09 Apr 2025 21:20:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/04/creating-a-simple-blog-with-hugo-and-netlify/</guid>
      <description>&lt;p&gt;I wanted to create a blog that would allow me to share posts on various&#xA;topics and photography. Wordpress is a bit too heavy-weight for what I wanted,&#xA;and I wanted to keep costs way down, preferably free, excluding the domain name.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt; is a static site generator that is fast, and has&#xA;great support for image processing. Posts are written in&#xA;&lt;a href=&#34;https://www.markdownguide.org/&#34;&gt;Markdown&lt;/a&gt; as individual text files and&#xA;converted to HTML as a build step in a CI pipeline. Hugo also supports RSS,&#xA;a small nerdy feature that I wanted to have.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I wanted to create a blog that would allow me to share posts on various
topics and photography. Wordpress is a bit too heavy-weight for what I wanted,
and I wanted to keep costs way down, preferably free, excluding the domain name.</p>
<p><a href="https://gohugo.io/">Hugo</a> is a static site generator that is fast, and has
great support for image processing. Posts are written in
<a href="https://www.markdownguide.org/">Markdown</a> as individual text files and
converted to HTML as a build step in a CI pipeline. Hugo also supports RSS,
a small nerdy feature that I wanted to have.</p>
<p>While I don&rsquo;t mind paying for hosting, I wanted to keep costs down. I don&rsquo;t
expect a lot of traffic, so for now the free tier of
<a href="https://www.netlify.com/">Netlify</a> is perfectly capable of hosting the site.</p>
<p>Posts are committed to a GitHub repository, and Netlify will automatically
build the site and deploy it to the web.</p>
<p>The following are the steps I took to set up the blog, including custom HTML and
CSS. I use Cloudflare for DNS for my domain, so will also briefly cover the
DNS configuration to point the domain to Netlify.</p>
<h1 id="initial-set-up">Initial Set Up</h1>
<p><strong>1. Install Hugo</strong></p>
<p>While not strictly necessary, I recommend installing Hugo on your local machine
so you can preview your changes before pushing them to GitHub. It also makes
setting up the skeleton of the site easier.</p>
<p>You can find instructions for installing on your system at</p>
<p><a href="https://gohugo.io/installation/">https://gohugo.io/installation/</a></p>
<p><strong>2. Create a new site and git repository</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hugo new site my-blog
</span></span><span style="display:flex;"><span>cd my-blog
</span></span><span style="display:flex;"><span>git init</span></span></code></pre></div><p>Find <code>hugo.toml</code> in the root directory. There are some basic configuration
options that need filling in.</p>
<p><strong>3. Add a theme</strong></p>
<p>Find a theme you like. A list of themes can be found at
<a href="https://themes.gohugo.io/">https://themes.gohugo.io/</a>.</p>
<p>Add it to your website as a git submodule, and reference it in the hugo.toml
file.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git submodule add https://github.com/clente/hugo-bearcub themes/hugo-bearcub
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;theme = &#34;hugo-bearcub&#34;&#39;</span> &gt;&gt; hugo.toml</span></span></code></pre></div><p><strong>4. Run Locally</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hugo server -D</span></span></code></pre></div><p>This will start a local web server on port 1313. You can view the site at
http://localhost:1313. The -D flag means draft posts will be included in the
output.</p>
<p>Hugo will automatically re-build the site as you make changes.</p>
<p><strong>5. npm install hugo</strong></p>
<p>In order for Netlify to build the site, you need to install Hugo as a dependency
in package.json. We can use npm to do this for us.</p>





<pre tabindex="0"><code>npm install hugo-bin --save-dev</code></pre><p><strong>6. Create a GitHub repository and push to git</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git add .
</span></span><span style="display:flex;"><span>git remote add origin git@github.com:my-user/my-blog.git
</span></span><span style="display:flex;"><span>git remote set-url origin git@github.com:my-user/my-blog.git
</span></span><span style="display:flex;"><span>git push -u origin main</span></span></code></pre></div><p><strong>7. Create a Netlify account and set up the site</strong></p>
<p>Netlify is pretty straight-forward to use. Use &lsquo;Import and Existing Project&rsquo;,
choose GitHub, and select the GitHub repository you just created. You should be
able to leave most of the settings as they are, but just in case:</p>





<pre tabindex="0"><code>Branch to deploy: main
Base directory:
Build command: hugo
Publish directory: public
Function directory: netlify/functions</code></pre><p><strong>8. Set up a custom domain</strong></p>
<p>Netlify has instructions for setting up a custom domain to point to the website.
They refer to using a &lsquo;flattened CNAME&rsquo;. In cloudflare, this is a standard CNAME
record. Cloudlfare will automatically do the flattening for you.</p>
<p>Ensure you disable Cloudflare&rsquo;s proxy for the DNS record; Netlify has its own
CDN, we do not need to run Cloudflare&rsquo;s on top. It would only harm performance.</p>
<h2 id="customising-the-theme">Customising the theme</h2>
<p>I liked the look of the <a href="https://github.com/janraasch/hugo-bearblog">hugo-bearblog</a>
theme, however there were a few changes I wanted to make.</p>
<p>First, I wanted the home page to be a list of all my blog post titles. As my
site evolves and I add more content, I may want to change this, but for the
beginning I wanted the site to be extremely simple. Home page -&gt; Blog post.</p>
<p>This meant overriding <code>index.html</code>, and removing the navigation bar by
overriding <code>nav.html</code>.</p>
<p>Second, I wanted to modify the layout of the titles as they are listed. In
particular, I wanted to add the category of the blog post to the listing.</p>
<p>Finally, I wanted to add a favicon.</p>
<p>We can achieve this with the following files:</p>
<p><strong>layouts/index.html</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ define &#34;main&#34; }}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;home&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;posts&#34;</span>&gt;
</span></span><span style="display:flex;"><span>        &lt;<span style="color:#f92672">ul</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;blog-posts&#34;</span>&gt;
</span></span><span style="display:flex;"><span>            {{ range where .Site.RegularPages &#34;Section&#34; &#34;blog&#34; }}
</span></span><span style="display:flex;"><span>            &lt;<span style="color:#f92672">li</span>&gt;
</span></span><span style="display:flex;"><span>                &lt;<span style="color:#f92672">span</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;post-list-item-date&#34;</span>&gt;
</span></span><span style="display:flex;"><span>                    &lt;<span style="color:#f92672">time</span> <span style="color:#a6e22e">datetime</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{{ .Date.Format &#34;2006-01-02&#34; }}&#39;</span>&gt;
</span></span><span style="display:flex;"><span>                        {{ .Date.Format (default &#34;02 Jan, 2006&#34; .Site.Params.dateFormat) }}
</span></span><span style="display:flex;"><span>                    &lt;/<span style="color:#f92672">time</span>&gt;
</span></span><span style="display:flex;"><span>                &lt;/<span style="color:#f92672">span</span>&gt;
</span></span><span style="display:flex;"><span>                &lt;<span style="color:#f92672">span</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;post-list-item-title&#34;</span>&gt;
</span></span><span style="display:flex;"><span>                    &lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;{{ .Permalink }}&#34;</span>&gt;{{ .Title }}&lt;/<span style="color:#f92672">a</span>&gt;
</span></span><span style="display:flex;"><span>                &lt;/<span style="color:#f92672">span</span>&gt;
</span></span><span style="display:flex;"><span>                &lt;<span style="color:#f92672">span</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;post-list-item-category&#34;</span>&gt;
</span></span><span style="display:flex;"><span>                {{ .Params.category }}
</span></span><span style="display:flex;"><span>                &lt;/<span style="color:#f92672">span</span>&gt;
</span></span><span style="display:flex;"><span>            &lt;/<span style="color:#f92672">li</span>&gt;
</span></span><span style="display:flex;"><span>            {{ else }}
</span></span><span style="display:flex;"><span>            &lt;<span style="color:#f92672">p</span>&gt;No posts yet!&lt;/<span style="color:#f92672">p</span>&gt;
</span></span><span style="display:flex;"><span>            {{ end }}
</span></span><span style="display:flex;"><span>        &lt;/<span style="color:#f92672">ul</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>{{ end }}</span></span></code></pre></div><p><strong>layouts/partials/nav.html</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#75715e">&lt;!-- This file is intentionally left blank --&gt;</span></span></span></code></pre></div><p><strong>assets/css/style.css</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#f92672">ul</span>.<span style="color:#a6e22e">blog-posts</span> <span style="color:#f92672">li</span> .<span style="color:#a6e22e">post-list-item-category</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">flex-grow</span>: <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">ul</span>.<span style="color:#a6e22e">blog-posts</span> <span style="color:#f92672">li</span> .<span style="color:#a6e22e">post-list-item-title</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">flex-grow</span>: <span style="color:#ae81ff">4</span>;
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><p><strong>layouts/partials/custom_head.html</strong></p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $style := resources.Get &#34;css/style.css&#34; | minify | fingerprint }}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">link</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;stylesheet&#34;</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;{{ $style.RelPermalink }}&#34;</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">link</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;icon&#34;</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/favicon.ico&#34;</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;image/x-icon&#34;</span> /&gt;</span></span></code></pre></div><p>Place your favicon icon in <strong>static/favicon.ico</strong></p>
<p>Commit and push to GitHub. Netlify will automatically build the site and deploy
it.</p>
<p>Congratulations!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fluffy Pancakes Recipe</title>
      <link>https://liamasman.com/blog/posts/2025/04/fluffy-pancakes-recipe/</link>
      <pubDate>Tue, 08 Apr 2025 20:30:00 +0100</pubDate>
      <guid>https://liamasman.com/blog/posts/2025/04/fluffy-pancakes-recipe/</guid>
      <description>&lt;h1 id=&#34;ingredients&#34;&gt;Ingredients&lt;/h1&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;150g Self-raising Flour&lt;/li&gt;&#xA;&lt;li&gt;55g Caster Sugar&lt;/li&gt;&#xA;&lt;li&gt;Pinch of Bicarbonate of Soda&lt;/li&gt;&#xA;&lt;li&gt;1 Egg, Beaten&lt;/li&gt;&#xA;&lt;li&gt;175ml Milk&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;steps&#34;&gt;Steps&lt;/h1&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Mix dry ingredients in bowl.&lt;/li&gt;&#xA;&lt;li&gt;Stir in egg &amp;amp; enough milk until smooth (may not need all milk).&lt;/li&gt;&#xA;&lt;li&gt;Drop spoon of batter into heated pan on &lt;strong&gt;medium&lt;/strong&gt; heat. When bubbles appear, turn over. No need for additional butter in the pan.&lt;/li&gt;&#xA;&lt;li&gt;Keep warm while making remaining pancakes.&lt;/li&gt;&#xA;&lt;li&gt;Serve. Great with butter, bacon and maple syrup.&lt;/li&gt;&#xA;&lt;/ol&gt;</description>
      <content:encoded><![CDATA[<h1 id="ingredients">Ingredients</h1>
<ul>
<li>150g Self-raising Flour</li>
<li>55g Caster Sugar</li>
<li>Pinch of Bicarbonate of Soda</li>
<li>1 Egg, Beaten</li>
<li>175ml Milk</li>
</ul>
<h1 id="steps">Steps</h1>
<ol>
<li>Mix dry ingredients in bowl.</li>
<li>Stir in egg &amp; enough milk until smooth (may not need all milk).</li>
<li>Drop spoon of batter into heated pan on <strong>medium</strong> heat. When bubbles appear, turn over. No need for additional butter in the pan.</li>
<li>Keep warm while making remaining pancakes.</li>
<li>Serve. Great with butter, bacon and maple syrup.</li>
</ol>
]]></content:encoded>
    </item>
  </channel>
</rss>
