<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Juha-Matti Santala - Community Builder. Dreamer. Adventurer.</title>
  <subtitle></subtitle>
  <link href="" rel="self" />
  <link href="https://hamatti.org" />
  <updated>2026-08-14T00:00:00Z</updated>
  <id></id>
  <author>
    <name>Juha-Matti Santala</name>
    <email>juhis@hamatti.org</email>
  </author> 
  
  <entry>
    <title>M is for meetups - Python A to Z</title>
    <link href="https://hamatti.org/posts/m-is-for-meetups-python-a-to-z/" />
    <updated>2026-08-14T00:00:00Z</updated>
    <id>https://hamatti.org/posts/m-is-for-meetups-python-a-to-z/</id>
    <content type="html">
      
&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  You walk into a room that’s buzzing of nervous energy. Some people are
  chatting with each other, others are sitting alone in the corner looking at
  their phone or grabbing a drink or slice of pizza from the kitchen. After a
  moment, the MC welcomes everyone in and a speaker after another take the stage
  to talk about something they know.
&lt;/p&gt;

&lt;p&gt;
  You have likely been to a &lt;i class=&quot;notion-text-italic&quot;&gt;meetup.&lt;/i&gt; I love
  meetups. I’ve been participating in them for 13 years and have been running my
  own for over 10 years. A lot of my best friendships have started from those
  communities.
&lt;/p&gt;

&lt;p&gt;
  I have written about meetups and conferences from various perspectives in the
  past so consider this post as a
  &lt;i class=&quot;notion-text-italic&quot;&gt;literature review&lt;/i&gt; of sorts.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;&lt;a href=&quot;https://hamatti.org/posts/developers-guide-to-communities/&quot; class=&quot;notion-text-href&quot;&gt;Developer&#39;s Guide to Communities&lt;/a&gt;&lt;/b&gt;&lt;b class=&quot;notion-text-bold&quot;&gt; &lt;/b&gt;is a good starting point. It’s my magnum
  opus on why and how to join meetup communities as a software developer. It
  covers everything from why you as a developer should join as a participant or
  even start sharing as a speaker all the way to what meetups are and how they
  function.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;&lt;a href=&quot;https://archipylago.dev/blog/its-my-first-time-at-meetup/&quot; class=&quot;notion-text-href&quot;&gt;It&#39;s my first time at a meetup - how does it work?&lt;/a&gt;&lt;/b&gt;&lt;b class=&quot;notion-text-bold&quot;&gt; &lt;/b&gt;is a post I wrote for our local Python
  meetup group to give first-timers a feel for what they were joining if they
  decided to sign up for one of our events.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;&lt;a href=&quot;https://hamatti.org/1924c7c90c2d4823b004b29287d3f51f&quot; class=&quot;notion-text-href&quot;&gt;Shy introvert&#39;s (short) guide to speaking in conferences&lt;/a&gt;&lt;/b&gt;&lt;b class=&quot;notion-text-bold&quot;&gt; &lt;/b&gt;is for those who want to take the next step
  and start sharing their knowledge but are bit unsure. As I was traveling to
  Copenhagen to speak in
  &lt;a href=&quot;https://hamatti.org/posts/my-trip-to-django-day-copenhagen-2022-and-stockholm/&quot; class=&quot;notion-text-href&quot;&gt;Django Day 2022 conference&lt;/a&gt;, I wrote down all my best tips and tricks of how I — an introvert — navigate
  social conferences and get the best out of them.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;In &lt;/b&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;&lt;a href=&quot;https://marijkeluttekes.dev/blog/articles/2024/02/08/you-can-be-a-beginner-and-also-a-speaker-blogger-or-participant/&quot; class=&quot;notion-text-href&quot;&gt;You can be a beginner and also a speaker, blogger, or participant&lt;/a&gt;&lt;/b&gt;
  Marijke Luttekes writes encouraging words to everyone who considers them self
  too inexperienced to share: “Have you recently heard yourself or someone else
  say that you cannot share knowledge because you are a beginner or junior
  developer? I hope to convince you otherwise.”
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;&lt;a href=&quot;https://hamatti.org/posts/chance-of-serendipity/&quot; class=&quot;notion-text-href&quot;&gt;Chance of serendipity&lt;/a&gt;&lt;/b&gt;&lt;b class=&quot;notion-text-bold&quot;&gt; &lt;/b&gt;is my argument for giving events like
  meetups and conferences a chance. You never know what’s going to happen: who
  you’ll meet, what will inspire you — even to the extent of having
  life-changing experiences.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;




    </content>
  </entry>
   
  
  <entry>
    <title>L is for learning - Python A to Z</title>
    <link href="https://hamatti.org/posts/l-is-for-learning-python-a-to-z/" />
    <updated>2026-08-13T00:00:00Z</updated>
    <id>https://hamatti.org/posts/l-is-for-learning-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  A life of a software developer — no matter if you’re doing it professionally
  or as a hobby — is a life of continuous learning. The technologies evolve,
  problem solving skills are never complete and thanks to very generous sharing
  from the community, there’s always new things to learn.
&lt;/p&gt;

&lt;p&gt;
  For today’s entry to Python A-Z, I’ll share different resources that I’ve
  found good for learning more about Python.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Books&lt;/h2&gt;

&lt;p&gt;
  Luciano Ramalho’s Fluent Python is still my number one recommendation. I wrote
  a
  &lt;a href=&quot;https://hamatti.org/posts/book-recommendation-fluent-python/&quot; class=&quot;notion-text-href&quot;&gt;recommendation for it two years ago&lt;/a&gt;
  so I won’t repeat too much here. It’s a really good book for anyone who knows
  Python and wants to deepen their knowledge and get a better grasp of writing
  Python code that takes the best advantage of all of the language’s structures.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://automatetheboringstuff.com/&quot; class=&quot;notion-text-href&quot;&gt;Automate the boring stuff with Python&lt;/a&gt;
  by Al Sweigart is a good primer for Python (and available as free online
  book). It has a very positive, supportive and encouraging tone which is really
  nice because especially in the beginning, learning programming can be quite a
  challenging — but rewarding — endeavour.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://www.manning.com/books/python-workout&quot; class=&quot;notion-text-href&quot;&gt;Python Workout by Reuven M. Lerner&lt;/a&gt;
  is a good option if you have some experience writing Python under your belt
  but you want more exercise. It has 50 exercises to practice the basic
  fundamentals of Python. Each exercise is explained and teaches you different
  concepts in Python.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://www.manning.com/books/classic-computer-science-problems-in-python&quot; class=&quot;notion-text-href&quot;&gt;David Kopec’s Classic Computer Science Problems in Python&lt;/a&gt;
  is aimed for intermediate or advanced level developers and rather than
  teaching the basics, it focuses on interesting classic computer science
  problems (as one might guess from the name…) and how to solve those with
  Python. Each chapter focuses on a sub category of problems and at the end of
  the chapter ties it all together with how these skills are useful in
  real-world applications.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Podcasts&lt;/h2&gt;

&lt;p&gt;
  There are many interesting Python podcasts and for this, I also refer to my
  previous post in our Python meetup’s blog:
  &lt;a href=&quot;https://archipylago.dev/blog/start-your-year-with-a-new-podcast/&quot; class=&quot;notion-text-href&quot;&gt;Start your year with a new podcast&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  Whether you want to learn about the nitty gritty details of building Python
  itself or want to hear stories of the people in the Python community, there’s
  something in the Python podcast world for everyone.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Blogs (and other forms of web writing)
&lt;/h2&gt;

&lt;p&gt;
  Here are some of the blogs and people who do Python stuff from my RSS reader.
  I initially started writing about everyone and their blog (because
  &lt;a href=&quot;https://hamatti.org/posts/human-curation-over-algorithmic-recommendations/&quot; class=&quot;notion-text-href&quot;&gt;info dumps are not a great reader experience&lt;/a&gt;) but there are so many great people on this list that it got overwhelming.
&lt;/p&gt;

&lt;p&gt;
  Going through the list, I’m so happy that I’ve gotten to know many people on
  this list in-person as well and compiling the list brought back a lot of great
  memories.
&lt;/p&gt;
&lt;ul class=&quot;notion-bulleted_list&quot;&gt;
  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://adamj.eu/&quot; class=&quot;notion-text-href&quot;&gt;Adam Johnson&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.andreagrandi.it/&quot; class=&quot;notion-text-href&quot;&gt;Andrea Grandi&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://programmingmylife.com/&quot; class=&quot;notion-text-href&quot;&gt;Andrew Mshar&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://blog.pecar.me/&quot; class=&quot;notion-text-href&quot;&gt;Anže Pečar&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://noumenal.es/&quot; class=&quot;notion-text-href&quot;&gt;Carlton Gibson&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://cheuk.dev/&quot; class=&quot;notion-text-href&quot;&gt;Cheuk Ting Ho&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://coredispatch.xyz/&quot; class=&quot;notion-text-href&quot;&gt;Core Dispatch&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://daniel.feldroy.com/&quot; class=&quot;notion-text-href&quot;&gt;Daniel Roy Greenfeld&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://dawnwages.info/bajoran-engineer/&quot; class=&quot;notion-text-href&quot;&gt;Dawn Wages&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://dennyperez.dev/&quot; class=&quot;notion-text-href&quot;&gt;Denny Perez&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://georgiker.com/&quot; class=&quot;notion-text-href&quot;&gt;Georgi Ker&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://blog.ovalerio.net/&quot; class=&quot;notion-text-href&quot;&gt;Gonçalo Valério&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hugovk.dev/&quot; class=&quot;notion-text-href&quot;&gt;Hugo van Kemenade&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.b-list.org/&quot; class=&quot;notion-text-href&quot;&gt;James Bennett&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://jefftriplett.com/&quot; class=&quot;notion-text-href&quot;&gt;Jeff Triplett&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://johnnymetz.com/&quot; class=&quot;notion-text-href&quot;&gt;Johnny Metz&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://lukeplant.me.uk/&quot; class=&quot;notion-text-href&quot;&gt;Luke Plant&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://mariatta.ca/&quot; class=&quot;notion-text-href&quot;&gt;Mariatta&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://marijkeluttekes.dev/&quot; class=&quot;notion-text-href&quot;&gt;Marijke Luttekes&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://pythonbynight.com/&quot; class=&quot;notion-text-href&quot;&gt;Mario Munoz&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://martinheinz.dev/&quot; class=&quot;notion-text-href&quot;&gt;Martin Heinz&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://406.ch/&quot; class=&quot;notion-text-href&quot;&gt;Matthias Kestenholz&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://maurits.vanrees.org/&quot; class=&quot;notion-text-href&quot;&gt;Maurits van Rees&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://miabajic.dev/&quot; class=&quot;notion-text-href&quot;&gt;Mia Bajić&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.mostlypython.com/&quot; class=&quot;notion-text-href&quot;&gt;Mostly Python&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://kuttler.eu/&quot; class=&quot;notion-text-href&quot;&gt;Nicolas Kuttler&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://nkantar.com/&quot; class=&quot;notion-text-href&quot;&gt;Nik Kantar&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://pamelafox.org/&quot; class=&quot;notion-text-href&quot;&gt;Pamela Fox&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.paulox.net/&quot; class=&quot;notion-text-href&quot;&gt;Paolo Melchiorre&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.peterbe.com/&quot; class=&quot;notion-text-href&quot;&gt;Peter Bengtsson&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://savannah.dev/&quot; class=&quot;notion-text-href&quot;&gt;Savannah Ostrowski&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://sethmlarson.dev/&quot; class=&quot;notion-text-href&quot;&gt;Seth Larson&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.sheenaoc.com/&quot; class=&quot;notion-text-href&quot;&gt;Sheena O&#39;Connell&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://simonwillison.net/tags/python/&quot; class=&quot;notion-text-href&quot;&gt;Simon Willison&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://stfn.pl/&quot; class=&quot;notion-text-href&quot;&gt;Stefan Machura&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://b0uh.github.io/&quot; class=&quot;notion-text-href&quot;&gt;Thomas Loiret&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://timonweb.com/&quot; class=&quot;notion-text-href&quot;&gt;Tim Kamanin&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.screamingatmyscreen.com/&quot; class=&quot;notion-text-href&quot;&gt;Timo Zimmermann&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://www.pythonmorsels.com/&quot; class=&quot;notion-text-href&quot;&gt;Trey Hunner&lt;/a&gt;
    who also shares great
    &lt;a href=&quot;https://mastodon.social/@treyhunner&quot; class=&quot;notion-text-href&quot;&gt;daily tips in Mastodon&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  There’s also probably many that I have missed. My categorisation efforts in my
  RSS reader are not at the level I wish they were so there are probably many
  more that I read but couldn’t find or remember right now.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>K is for keyword arguments - Python A to Z</title>
    <link href="https://hamatti.org/posts/k-is-for-keyword-arguments-python-a-to-z/" />
    <updated>2026-08-12T00:00:00Z</updated>
    <id>https://hamatti.org/posts/k-is-for-keyword-arguments-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  In
  &lt;a href=&quot;https://www.youtube.com/watch?v=OSGv2VnC0go&quot; class=&quot;notion-text-href&quot;&gt;PyCon US 2013, Raymond Hettinger talked about writing beautiful, idiomatic
    Python&lt;/a&gt;. It’s a great talk but for this post, I’ll focus on what he talks about
  around 30 minute mark.
&lt;/p&gt;

&lt;p&gt;
  He shares an example (which dates the talk and example nicely; those were the
  times)
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;twitter_search(&#39;@obama&#39;, False, 20, True)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  We spend way more time reading code than we do writing it. While modern code
  editors and IDEs give you a lot of help (as you can see in the following
  screenshot from VS Code), it’s still an extra step.
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/k-is-for-keyword-arguments/1.png.webp&quot; alt=&quot;Screenshot from VS Code, showing a function call to twitter_search with an overlay documentation for parameter names, types and descriptions. &quot; /&gt;
&lt;p&gt;
  Keyword arguments are a great, small step to improving the readability of your
  code. Compare the two:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;twitter_search(&#39;@obama&#39;, False, 20, True)
# and 
twitter_search(&#39;@obama&#39;, retweets=False, numtweets=20, popularity=True)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  The second one is immediately more readable and the better names for your
  keywords you write, the better its readability becomes.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>J is for JSON validation - Python A to Z</title>
    <link href="https://hamatti.org/posts/j-is-for-json-validation-python-a-to-z/" />
    <updated>2026-08-11T00:00:00Z</updated>
    <id>https://hamatti.org/posts/j-is-for-json-validation-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  When you need to load external data into your software, you want to make sure
  it behaves properly, ie. it’s in correct form. One tool to validate input data
  is
  &lt;a href=&quot;https://pydantic.dev/docs/validation/latest/get-started/&quot; class=&quot;notion-text-href&quot;&gt;Pydantic&lt;/a&gt;. This is a quick tutorial to show how it works.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Installing Pydantic&lt;/h2&gt;

&lt;p&gt;Set up your environment and install with&lt;/p&gt;

&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;pip install pydantic&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Alternatively, you can run these with
  &lt;a href=&quot;https://docs.astral.sh/uv/&quot; class=&quot;notion-text-href&quot;&gt;uv&lt;/a&gt;:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;uv run --with pydantic code.py&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Simplified Pokédex data&lt;/h2&gt;

&lt;p&gt;
  For this demo, I’m using a simplified data set adapted from
  &lt;a href=&quot;https://github.com/Purukitto/pokemon-data.json&quot; class=&quot;notion-text-href&quot;&gt;Purukitto’s Pokemon.json&lt;/a&gt;. I’ve saved this to a file
  &lt;code class=&quot;notion-text-code&quot;&gt;pokedex.json&lt;/code&gt;.
&lt;/p&gt;

&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;[
  {
    &quot;id&quot;: 1,
    &quot;name&quot;: &quot;Bulbasaur&quot;,
    &quot;type&quot;: [&quot;Grass&quot;, &quot;Poison&quot;],
    &quot;stats&quot;: {
      &quot;HP&quot;: 45,
      &quot;Attack&quot;: 49,
      &quot;Defense&quot;: 49,
      &quot;Sp. Attack&quot;: 65,
      &quot;Sp. Defense&quot;: 65,
      &quot;Speed&quot;: 45
    },
    &quot;height&quot;: &quot;0.7 m&quot;,
    &quot;weight&quot;: &quot;6.9 kg&quot;
  },
  {
    &quot;id&quot;: 2,
    &quot;name&quot;: &quot;Ivysaur&quot;,
    &quot;type&quot;: [&quot;Grass&quot;, &quot;Poison&quot;],
    &quot;stats&quot;: {
      &quot;HP&quot;: 60,
      &quot;Attack&quot;: 62,
      &quot;Defense&quot;: 63,
      &quot;Sp. Attack&quot;: 80,
      &quot;Sp. Defense&quot;: 80,
      &quot;Speed&quot;: 60
    },
    &quot;height&quot;: &quot;1 m&quot;,
    &quot;weight&quot;: &quot;13 kg&quot;
  }
]&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Building a schema&lt;/h2&gt;
&lt;h3&gt;Step 1: Basic types&lt;/h3&gt;
&lt;p&gt;
  Let’s start with a first step. We’ll define a class that inherits from
  Pydantic’s &lt;code class=&quot;notion-text-code&quot;&gt;BaseModel&lt;/code&gt;. These classes will
  be the way we define the schema and what powers Pydantic’s validation engines.
&lt;/p&gt;

&lt;p&gt;For the first step, we’ll use basic definitions.&lt;/p&gt;

&lt;p&gt;
  A Pokémon has a couple of fields: an id, a name, a list of types, a dictionary
  of stats, height and weight. A Pokedex is a list of Pokémon.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;I will be using this as a base for all future snippets in this post but
    will only share what’s changed later on. You can find &lt;a href=&quot;https://gist.github.com/Hamatti/863a59df2e6122d823a8d99b39c9e9bf&quot;&gt;full code examples in GitHub&lt;/a&gt;.&lt;/b&gt;
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;import json

from pydantic import BaseModel
from typing import List, TypeAlias


class Pokemon(BaseModel):
    &quot;&quot;&quot;An entry in Pokedex&quot;&quot;&quot;

    id: int
    name: str
    type: List[str]
    stats: dict
    height: str
    weight: str


Pokedex: TypeAlias = List[Pokemon]


def read_pokedex(filename: str) -&amp;#62; Pokedex:
    pokedex = []
    with open(filename, &quot;r&quot;) as dex:
        data = json.load(dex)
        for entry in data:
            pokedex.append(Pokemon(**entry))
    return pokedex


if __name__ == &quot;__main__&quot;:
    pokedex = read_pokedex(&quot;pokedex.json&quot;)
    print(pokedex)&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Step 2: More refined types&lt;/h3&gt;
&lt;p&gt;
  Python itself offers enough for the basic types (like
  &lt;code class=&quot;notion-text-code&quot;&gt;int&lt;/code&gt;,
  &lt;code class=&quot;notion-text-code&quot;&gt;str&lt;/code&gt; ,
  &lt;code class=&quot;notion-text-code&quot;&gt;List&lt;/code&gt; and
  &lt;code class=&quot;notion-text-code&quot;&gt;dict&lt;/code&gt; in the example above) but Pydantic
  offers a lot more if we want to be more specific.
&lt;/p&gt;

&lt;p&gt;
  For example, our &lt;code class=&quot;notion-text-code&quot;&gt;id&lt;/code&gt; field is always a
  positive integer. We can use
  &lt;code class=&quot;notion-text-code&quot;&gt;PositiveInt&lt;/code&gt; from Pydantic to add an
  extra layer of validation.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from pydantic import BaseModel, PositiveInt

class Pokemon(BaseModel):
    &quot;&quot;&quot;An entry in Pokedex&quot;&quot;&quot;

    id: PositiveInt
    name: str
    type: List[str]
    stats: dict
    height: str
    weight: str&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Everything else stays the same but we import
  &lt;code class=&quot;notion-text-code&quot;&gt;PositiveInt&lt;/code&gt; and change
  &lt;code class=&quot;notion-text-code&quot;&gt;id&lt;/code&gt; to it.
&lt;/p&gt;

&lt;p&gt;
  Now, lets we add a third element to our JSON to see how this works. Here, I’ve
  introduced a mistake in data: &lt;code class=&quot;notion-text-code&quot;&gt;id&lt;/code&gt; is now
  -3 instead of 3.
&lt;/p&gt;

&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &quot;id&quot;: -3,
    &quot;name&quot;: &quot;Venusaur&quot;,
    &quot;type&quot;: [&quot;Grass&quot;, &quot;Poison&quot;],
    &quot;stats&quot;: {
      &quot;HP&quot;: 80,
      &quot;Attack&quot;: 82,
      &quot;Defense&quot;: 83,
      &quot;Sp. Attack&quot;: 100,
      &quot;Sp. Defense&quot;: 100,
      &quot;Speed&quot;: 80
    },
    &quot;height&quot;: &quot;2 m&quot;,
    &quot;weight&quot;: &quot;100 kg&quot;
  }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  If we run our code from step 1, all runs smoothly. If we run the code from
  step 2, we get a validation error:
&lt;/p&gt;

&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;pydantic_core._pydantic_core.ValidationError: 1 validation error for Pokemon
id
  Input should be greater than 0 [type=greater_than, input_value=-3, input_type=int]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;Remember to switch -3 to 3 before continuing.&lt;/b&gt;
&lt;/p&gt;
&lt;h3&gt;Step 3: Renaming fields&lt;/h3&gt;
&lt;p&gt;Our stats field looks like this:&lt;/p&gt;

&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;    &quot;stats&quot;: {
      &quot;HP&quot;: 80,
      &quot;Attack&quot;: 82,
      &quot;Defense&quot;: 83,
      &quot;Sp. Attack&quot;: 100,
      &quot;Sp. Defense&quot;: 100,
      &quot;Speed&quot;: 80
    }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  We can use Pydantic’s alias feature to rename them to a more pythonic versions
  and add an extra layer of validation.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from pydantic import BaseModel, PositiveInt, Field
from typing import List, TypeAlias


class Stats(BaseModel):
    hp: PositiveInt = Field(alias=&quot;HP&quot;)
    attack: PositiveInt = Field(alias=&quot;Attack&quot;)
    sp_attack: PositiveInt = Field(alias=&quot;Sp. Attack&quot;)
    sp_defense: PositiveInt = Field(alias=&quot;Sp. Defense&quot;)
    speed: PositiveInt = Field(alias=&quot;Speed&quot;)


class Pokemon(BaseModel):
    &quot;&quot;&quot;An entry in Pokedex&quot;&quot;&quot;

    id: PositiveInt
    name: str
    type: List[str]
    stats: Stats
    height: str
    weight: str&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Here, we add an import for &lt;code class=&quot;notion-text-code&quot;&gt;Field&lt;/code&gt; and
  create a new validation model &lt;code class=&quot;notion-text-code&quot;&gt;Stats&lt;/code&gt;. For
  each field, we define the key in JSON as
  &lt;code class=&quot;notion-text-code&quot;&gt;alias=&lt;/code&gt; argument and use the new Stats
  model in our Pokemon definition.
&lt;/p&gt;

&lt;p&gt;
  We now have added validation for all the stats and they are in a form that’s
  easier to use within Python code.
&lt;/p&gt;
&lt;h3&gt;Step 4: Parse data into usable format&lt;/h3&gt;
&lt;p&gt;Our height and weight data is in a string format:&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;    &quot;height&quot;: &quot;2 m&quot;,
    &quot;weight&quot;: &quot;100 kg&quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  It would be easier to use them if they were stored numerically. Good news! We
  can run code before or after validation to modify the values.
&lt;/p&gt;

&lt;p&gt;Let’s start by writing functions to turn these data points into numbers:&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;def parse_height(height: str) -&amp;#62; float:
    height = height.removesuffix(&quot; m&quot;)
    return float(height)


def parse_weight(weight: str) -&amp;#62; float:
    weight = weight.removesuffix(&quot; kg&quot;)
    return float(weight)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  We remove the unit suffixes and convert the rest to a
  &lt;code class=&quot;notion-text-code&quot;&gt;float&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;To run this, we need a few extra bits.&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from pydantic import BaseModel, BeforeValidator, Field, PositiveFloat, PositiveInt
from typing import Annotated, List, TypeAlias

class Pokemon(BaseModel):
    &quot;&quot;&quot;An entry in Pokedex&quot;&quot;&quot;

    id: PositiveInt
    name: str
    type: List[str]
    stats: Stats
    height: Annotated[PositiveFloat, BeforeValidator(parse_height)]
    weight: Annotated[PositiveFloat, BeforeValidator(parse_weight)]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  We import three new things:
  &lt;code class=&quot;notion-text-code&quot;&gt;pydantic.BeforeValidator&lt;/code&gt; ,
  &lt;code class=&quot;notion-text-code&quot;&gt;pydantic.PositiveFloat&lt;/code&gt; and
  &lt;code class=&quot;notion-text-code&quot;&gt;typing.Annotated&lt;/code&gt;. (If we want to run
  code after value is validated, we could use
  &lt;code class=&quot;notion-text-code&quot;&gt;pydantic.AfterValidator&lt;/code&gt;).
&lt;/p&gt;

&lt;p&gt;
  We then define height and weight as annotated floats and want to run their
  corresponding functions.
&lt;/p&gt;

&lt;p&gt;
  Now we can validate that the result of our parsing is a positive float for
  both of them and our code has access to properly typed values.
&lt;/p&gt;

&lt;p&gt;
  If our data used mixed units, this would also help us normalise the data.
  Here, all heights are in meters and weights are in kilograms so we didn’t have
  to do any conversions.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;‘Tis but a scratch!&lt;/b&gt;
&lt;/h2&gt;

&lt;p&gt;
  I’ve given you a glimpse into Pydantic’s validation tools and how to get
  started but there’s so much more you can do. They have
  &lt;a href=&quot;https://pydantic.dev/docs/validation/latest/get-started/&quot; class=&quot;notion-text-href&quot;&gt;pretty good documentation&lt;/a&gt;
  that will help you define and refine your validators even further.
&lt;/p&gt;

&lt;p&gt;
  Writing validators is not only good for catching up rogue, misformed data but
  it forces you to be explicit about understanding your data before you venture
  into building your program’s business logic.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>I is for immutable - Python A to Z</title>
    <link href="https://hamatti.org/posts/i-is-for-immutable-python-a-to-z/" />
    <updated>2026-08-10T00:00:00Z</updated>
    <id>https://hamatti.org/posts/i-is-for-immutable-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  When we start learning programming, one of the first things we’re taught is a
  concept of &lt;b class=&quot;notion-text-bold&quot;&gt;variable&lt;/b&gt;. Variables are very handy:
  they store some data in memory, have a name you can use to refer to them later
  in the code and they can change.
&lt;/p&gt;

&lt;p&gt;
  That’s what &lt;i class=&quot;notion-text-italic&quot;&gt;variable&lt;/i&gt; means.
  &lt;a href=&quot;https://www.merriam-webster.com/dictionary/variable&quot; class=&quot;notion-text-href&quot;&gt;Merriam-Webster defines the word as&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  able or apt to vary : subject to variation or changes
&lt;/blockquote&gt;

&lt;p&gt;A classic example is a counter that goes up.&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;counter = 0
print(counter) # 0
counter = counter + 1
print(counter) # 1
counter = counter + 1
print(counter) # 2
counter = counter + 1
print(counter) # 3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Most of the early days, months or years of learning programming is about
  understanding this idea and a few related bits like different types (numbers,
  strings, lists, dictionaries, booleans etc), conditionals and loops. After you
  learn those, the rest of your career is just banging your head to the wall
  when the simple constructs you wrote don’t work (or
  &lt;a href=&quot;https://hamatti.org/posts/debugging-python/&quot; class=&quot;notion-text-href&quot;&gt;you can talk to a duck and save a headache&lt;/a&gt;).
&lt;/p&gt;

&lt;p&gt;
  You build your internal schema of how to program based on the idea of a
  variable.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Functional programming&lt;/h2&gt;

&lt;p&gt;
  Then at some point — maybe at an advanced class at the university, at a meetup
  or in the always peaceful and polite discussion forums on the web — you’re
  introduced to the idea of immutability (&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://www.merriam-webster.com/dictionary/immutable&quot; class=&quot;notion-text-href&quot;&gt;not capable of or susceptible to change&lt;/a&gt;&lt;/i&gt;).
&lt;/p&gt;

&lt;p&gt;
  Someone comes hype the idea of
  &lt;a href=&quot;https://en.wikipedia.org/wiki/Functional_programming&quot; class=&quot;notion-text-href&quot;&gt;functional programming&lt;/a&gt;
  that you’ve never heard of. They start talking about how changing variable
  state is so error-prone and
  &lt;a href=&quot;https://en.wikipedia.org/wiki/Pure_function&quot; class=&quot;notion-text-href&quot;&gt;pure functions&lt;/a&gt;
  is where the game should be played at.
&lt;/p&gt;

&lt;p&gt;
  A pure function is a function that given an input, always returns the same
  output. There are no &lt;i class=&quot;notion-text-italic&quot;&gt;side effects&lt;/i&gt;. It only
  relies on the inputs provided (and doesn’t read anything from disk, other
  parts of memory, make any web calls and so on) and is deterministic in
  crafting its output.
&lt;/p&gt;

&lt;p&gt;
  Pure functions are way easier to test, have less unexpected issues and can
  make your code easier to reason with. The hardcore functional programming
  people don’t even store values in temporary variables. They call functions,
  pass the results to other functions and beauty emerges and birds sing.
&lt;/p&gt;

&lt;p&gt;
  But if your entire schema of how programming works was laid on the foundations
  of variables, it can be quite a head scratcher to start adopting. I was on my
  third year at the university studying computer science when I took a
  functional programming course and oh boy it was a doozy.
&lt;/p&gt;

&lt;p&gt;
  I don’t know if that course was a blessing or a curse. There were maybe easier
  ways to get into understanding immutability and pure functions in programming
  but on the other hand, diving directly to the deep end and learning to swim
  might have been a good form of shock therapy.
&lt;/p&gt;

&lt;p&gt;
  I’m not a purist but I do prefer as much functional style as possible — mostly
  to help make code easier to test and thus reducing the stress of growing
  complexity.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Tuples are great, m’kay&lt;/h2&gt;

&lt;p&gt;
  Some data structures are immutable: once you make it, you gotta stick with it.
&lt;/p&gt;

&lt;p&gt;
  In Python, we have
  &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#tuple&quot; class=&quot;notion-text-href&quot;&gt;tuples&lt;/a&gt;
  (and their more eloquent heir
  &lt;a href=&quot;https://hamatti.org/posts/improve-your-code-with-namedtuples/&quot; class=&quot;notion-text-href&quot;&gt;namedtuples&lt;/a&gt;). You cannot change the contents of a tuple, no matter how hard you try.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;date = (2026, 8, 10) # parentheses are optional but preferable

# Access them by index
print(date[0]) # 2026

# Can&#39;t change though
date[0] = 2025 
# TypeError: &#39;tuple&#39; object does not support item assignment&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I really like tuples. Especially namedtuples.&lt;/p&gt;

&lt;p&gt;
  They also make me appreciate Python’s beautiful design. All you really need is
  a comma in between two expressions and you’ve got yourself an immutable tuple.
&lt;/p&gt;

&lt;p&gt;If you want to return multiple values from a function, it’s tuple time!&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from typing import Tuple

def squares_and_cubes(number: int) -&amp;#62; Tuple[int, ...]:
  return number, number**2, number**3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Back in the day, I started with PHP and a bit later with Java at high school.
  When I moved into Python and learned about how easy it is to return multiple
  values through a tuple without having to explicitly craft a tuple, I started
  appreciating the language even more.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>HTML Day and the value of practicing the fundamentals</title>
    <link href="https://hamatti.org/posts/html-day-and-the-value-of-practicing-the-fundamentals/" />
    <updated>2026-08-10T00:00:00Z</updated>
    <id>https://hamatti.org/posts/html-day-and-the-value-of-practicing-the-fundamentals/</id>
    <content type="html">
      &lt;p&gt;
  On August 8th, we celebrated this year’s
  &lt;a href=&quot;https://2026.html.energy/&quot; class=&quot;notion-text-href&quot;&gt;HTML Day&lt;/a&gt;.
  &lt;i class=&quot;notion-text-italic&quot;&gt;(Or more accurately, many people around the world did. I tried to put
    together &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://turkufrontend.fi/html-day-2026/&quot; class=&quot;notion-text-href&quot;&gt;an event for our local community&lt;/a&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    but failed to garner enough interest from speakers and partners and had to
    cancel. My failure left a disappointing taste to my mouth and I failed to
    celebrate the event on my own.)&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  Tom wrote a post
  &lt;a href=&quot;https://endgameviable.com/post/2026/08/old-dog-not-understanding-html-day/&quot; class=&quot;notion-text-href&quot;&gt;Old Dog Not Understanding HTML Day&lt;/a&gt;
  where he expressed how he doesn’t get the appeal of HTML Day and writing HTML
  by hand.
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
&lt;p&gt;
  As a professional software engineer and sometimes web developer, you’d think
  I’d be excited about something like HTML Day. But the fact is that I hate
  hand-writing HTML. I avoid it as much as possible.&lt;/p&gt;
  &lt;p&gt;Sorry.&lt;/p&gt;
  &lt;p&gt;Once again I’m in the uncomfortable position of looking at a fun thing people are having fun with and reacting with, “Huh? I don’t get it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  To a certain extent, I agree with him: I dread the idea of writing a full
  website without any HTML generating tooling — outside an event like this. I
  love my
  &lt;a href=&quot;https://docs.emmet.io/&quot; class=&quot;notion-text-href&quot;&gt;Emmet snippets&lt;/a&gt;
  and &lt;a href=&quot;https://jamstack.org/&quot;&gt;static site generators&lt;/a&gt; so I can define the basic structures and let the
  machine go brrrrr and build the rest.
&lt;/p&gt;

&lt;p&gt;
  I especially agree with Tom’s later remark about using Markdown when writing
  instead of mixing creative writing and HTML implementation:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  I find it vastly easier and more intuitive to creatively write in Markdown
  than in HTML, when it comes to simple formatting like italics and bold and
  headings and such.
&lt;/blockquote&gt;

&lt;p&gt;
  The bits that I do write, I want to write myself by hand because it gives me
  greater control to make sure the output is as good, semantic HTML as possible.
&lt;/p&gt;

&lt;h2&gt;Practicing the fundamentals&lt;/h2&gt;
&lt;p&gt;
  First, let’s talk about HTML Day (and by extension, Advent of Code he also
  mentioned).
&lt;/p&gt;

&lt;p&gt;
  I think there’s tremendous value in gathering together as a community of
  practice to learn more about a topic, sharing good ideas and practicing your
  craft.
&lt;/p&gt;

&lt;p&gt;
  Even if we strip out the community benefits and even if you’d mostly generate
  your HTML by some sort of a tool on your day-to-day basis, I think it’s really
  good to regularly get back to the basics and practice them. If you’re not a
  developer who does web frontend, it’s not as important but for anyone who
  does.
&lt;/p&gt;

&lt;p&gt;
  HTML changes over time and it’s good to check what’s up with the standards,
  new options and best practices. When I started getting into frontend stuff
  back in my teens, we used iframes and tables to create layouts — now we have
  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox&quot; class=&quot;notion-text-href&quot;&gt;flexbox&lt;/a&gt;
  and
  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout&quot; class=&quot;notion-text-href&quot;&gt;CSS grid&lt;/a&gt;
  as an example. Smaller things happen all the time as well and taking a moment
  every now and then to check where you are is good.
&lt;/p&gt;

&lt;p&gt;
  Second, even if you generate your code, you need to know and have a feel for
  the fundamentals so you can judge if the code that was generated is any good.
&lt;/p&gt;

&lt;p&gt;Tom writes:&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  There’s that pesky elephant in the room in 2026 again. AI. It’s hard to escape
  the universal answer to most development questions: I can just get AI to write
  or check whatever HTML I need so I don’t have to get distracted by troublesome
  details while I stay focused on the big picture. Laziness, hurray!
&lt;/blockquote&gt;

&lt;p&gt;
  The more you use AI to generate your code — in any language — the more you
  should focus on making sure your fundamentals of the language are good so you
  can assess the code it gives you.
&lt;/p&gt;

&lt;p&gt;
  Our industry is famously quite bad at writing good HTML. Especially with the
  popularity of React, there are a lot of frontend developers who don’t know the
  fundamentals and through that lack of knowledge, end up writing inaccessible
  solutions or having to reinvent the wheel while they could rely on built-in
  tools in HTML and browsers to make websites and web apps accessible.
&lt;/p&gt;

&lt;p&gt;
  I don’t want to write all the HTML in my projects by hand every time. However,
  I do find a lot of value in regularly doing so to keep up with new
  advancements in the language as well as honing my fundamental skills.
&lt;/p&gt;

&lt;p&gt;
  I also love this quote from
  &lt;a href=&quot;https://frontendmasters.com/courses/complete-intro-containers-v2/&quot; class=&quot;notion-text-href&quot;&gt;Brian Holt&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
&lt;p&gt;
  When I don’t know how my tools work, I tend to resent them because they add
  complexity to my life.&lt;/p&gt;&lt;p&gt; When I understand what they are doing for me and what I
  no longer have to do because the tool is doing it for me, I tend to really
  like my tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Sometimes doing things the hard way makes me appreciate the tooling I have so
  I don’t have to do it every time.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>H is for htmx - Python A to Z</title>
    <link href="https://hamatti.org/posts/h-is-for-htmx-python-a-to-z/" />
    <updated>2026-08-09T00:00:00Z</updated>
    <id>https://hamatti.org/posts/h-is-for-htmx-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  For the past couple of years, all my new Django projects have been built with
  &lt;a href=&quot;https://htmx.org/&quot; class=&quot;notion-text-href&quot;&gt;htmx&lt;/a&gt; and I’ve worked
  on couple of other, non-Django projects that uses it as well. It’s a blast!
&lt;/p&gt;

&lt;p&gt;
  It took me a while to get used to but especially
  &lt;a href=&quot;https://www.youtube.com/watch?v=10G874qqtrc&quot; class=&quot;notion-text-href&quot;&gt;this demo by Michael Kennedy at PyBay 2021&lt;/a&gt;
  convinced me of its utility and looking back now, I love how simple it makes
  building most interactive websites and web apps.
&lt;/p&gt;

&lt;p&gt;
  htmx is a small (16k) Javascript library that makes it possible to build
  modern UIs by transferring HTML over the wire instead of JSON. Combined with
  Django’s templating system, it makes build smooth, fluid frontends with
  server-side rendering.
&lt;/p&gt;

&lt;p&gt;
  Here’s an example from my Pokémon TCG inventory application. I have a
  component for showing a card and a (-) [count] (+) style UI for it.
&lt;/p&gt;

&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;#60;button
	name=&quot;decrease-qty&quot;
	id=&quot;{{card.id}}-{{variant.variant|slugify}}&quot;
	data-foil=&quot;{{variant.variant}}&quot;
	hx-put=&quot;/collection/decrease/{{variant.id}}/&quot;
	hx-target=&quot;input#{{card.id}}-{{variant.variant|slugify}}&quot;
	hx-swap=&quot;outerHTML&quot;
&amp;#62;
-
&amp;#60;/button&amp;#62;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Here’s a button that decreases the amount in my database. It uses three htmx
  attributes: &lt;code class=&quot;notion-text-code&quot;&gt;hx-put&lt;/code&gt;,
  &lt;code class=&quot;notion-text-code&quot;&gt;hx-target&lt;/code&gt; and
  &lt;code class=&quot;notion-text-code&quot;&gt;hx-swap&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
  &lt;code class=&quot;notion-text-code&quot;&gt;hx-put&lt;/code&gt; tells the code to send a PUT
  request to the provided endpoint when this button is clicked.
&lt;/p&gt;

&lt;p&gt;
  &lt;code class=&quot;notion-text-code&quot;&gt;hx-target&lt;/code&gt; tells which element the
  returned HTML in the response should go into.
&lt;/p&gt;

&lt;p&gt;
  &lt;code class=&quot;notion-text-code&quot;&gt;hx-swap&lt;/code&gt; tells how to change it: in this
  case, replace the entire HTML element of the target.
&lt;/p&gt;

&lt;p&gt;
  I click the button in the UI, a PUT is sent to the server that updates the
  count in the database and sends back HTML that in this case is an
  &lt;code class=&quot;notion-text-code&quot;&gt;input&lt;/code&gt; with the value of the new
  count (and some extra htmx controls so I can change the value directly in the
  input as well).
&lt;/p&gt;

&lt;hr class=&quot;notion-divider&quot; /&gt;


&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  HTMX 4.0, the first JavaScript library to release exclusively on the Game
  Boy® platform!
&lt;/blockquote&gt;
&lt;p&gt;
  There’s also
  &lt;a href=&quot;https://swag.htmx.org/en-eur/products/htmx-4-the-game&quot; class=&quot;notion-text-href&quot;&gt;a Game Boy game by htmx&lt;/a&gt;
  and
  &lt;a href=&quot;https://sethmlarson.dev/htmx-4-the-game&quot; class=&quot;notion-text-href&quot;&gt;Seth Larson made a video and wrote a blog post about it&lt;/a&gt;.
&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>G is for get_or_create - Python A to Z</title>
    <link href="https://hamatti.org/posts/g-is-for-get-or-create-python-a-to-z/" />
    <updated>2026-08-08T00:00:00Z</updated>
    <id>https://hamatti.org/posts/g-is-for-get-or-create-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  Let’s take our first journey into the wonders of
  &lt;a href=&quot;https://www.djangoproject.com/&quot; class=&quot;notion-text-href&quot;&gt;Django&lt;/a&gt;,
  my favourite web backend. One of the reasons I love it is its ORM which we’ll
  talk a bit more when we reach the midway of the month and letter O.
&lt;/p&gt;

&lt;p&gt;
  Today, I want to show my appreciation for one of the methods in QuerySet:
  &lt;a href=&quot;https://docs.djangoproject.com/en/6.1/ref/models/querysets/#django.db.models.query.QuerySet.get_or_create&quot; class=&quot;notion-text-href&quot;&gt;get_or_create&lt;/a&gt;
  which allows you to create new items in the database but if one already
  exists, it returns it instead.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from .models import Bread, BreadType

# (here, Bread.bread_type is a ForeignKey to BreadType)

breads_input = [{ &#39;id&#39;: 1, &#39;breadType&#39;: &#39;bun&#39; } , ... ]

for bread_data in breads:
	bread_type, type_created = BreadType.objects.get_or_create(type=bread_data[&#39;breadType&#39;])
	bread, bread_created = Bread.objects.get_or_create(id=bread_data[&#39;id&#39;], bread_type=bread_type)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Here we process through some list of dictionaries (imagine it’s read from a
  JSON file or queried from a REST API). First, we try to create a new BreadType
  but if one already exists, we return a reference to it rather than creating a
  new one every time. Then we create a bread, using the previous reference. If
  we’d already have that specific bread inputted (maybe we ran the command
  twice), we want to get the existing one rather than creating new ones every
  time.
&lt;/p&gt;

&lt;p&gt;
  I especially love using it in my data entry scripts / custom Django commands.
  Many of my applications operate on a model where I periodically input new data
  through these commands: for example in Pokémon TCG app, when a new set is
  released.
&lt;/p&gt;

&lt;p&gt;
  Pokémon TCG is a great example. Right now, when my script reads in data for
  new cards, there are 13 such relationships between my Card model and other
  models. The codebase looks so much neater and easier to follow thanks to
  &lt;code class=&quot;notion-text-code&quot;&gt;get_or_create.&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit later on Aug 8th&lt;/strong&gt;: I rewrote the entire post to better explain what &lt;code&gt;get_or_create&lt;/code&gt; does.&lt;/p&gt;
    </content>
  </entry>
   
   
  
  <entry>
    <title>My custom keyword reference guide for Magic the Gathering Battle Box</title>
    <link href="https://hamatti.org/posts/my-custom-keyword-reference-guide-for-magic-the-gathering-battle-box/" />
    <updated>2026-08-07T00:00:00Z</updated>
    <id>https://hamatti.org/posts/my-custom-keyword-reference-guide-for-magic-the-gathering-battle-box/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;I’ll start by playing a &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://scryfall.com/card/blb/279/forest&quot; class=&quot;notion-text-href&quot;&gt;Forest&lt;/a&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;.&lt;/i&gt;
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-custom-keyword-reference-guide-for-magic-the-gathering-battle-box/1.png.webp&quot; alt=&quot;A full art Bloomburrow Magic the Gathering card Forest played on a playmat&quot; /&gt;
&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://youtu.be/OwUDLv52nrc?t=145&quot; class=&quot;notion-text-href&quot;&gt;Sure, it resolves.&lt;/a&gt;&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;I’ll tap the Forest to generate green mana and use it to cast &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Battle Box keyword reference guide&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;.&lt;/i&gt;
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-custom-keyword-reference-guide-for-magic-the-gathering-battle-box/2.png.webp&quot; alt=&quot;The Forest is tapped sideways and a booklet titled Battle Box keyword reference guide is played above it on the playmat.&quot; /&gt;
&lt;p&gt;
  I love
  &lt;a href=&quot;https://notes.hamatti.org/gaming/board-games/magic-the-gathering/mtg-battle-box&quot; class=&quot;notion-text-href&quot;&gt;Magic the Gathering Battle Box&lt;/a&gt;. It’s a great casual pick-and-play format where I can bring it with me to a
  lunch or an afterwork, shuffle the deck and start playing.
&lt;/p&gt;

&lt;p&gt;
  No need for everyone to bring their own deck, no long-winded drafting
  (although drafting cubes is hella fun) and deck construction. No mana drought
  or mana flood but a perfect curve.
&lt;/p&gt;

&lt;p&gt;
  A single, shared deck full of creatures and other spells that mostly focuses
  on combat and combat tricks. Each player has 10 lands (1 of each basic and 5
  dual-lands) they can play from Command Zone (I’m considering calling it
  Landfill for the memes).
&lt;/p&gt;

&lt;p&gt;There’s just one catch.&lt;/p&gt;

&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://notes.hamatti.org/gaming/board-games/magic-the-gathering/reading-the-card-explains-the-card&quot; class=&quot;notion-text-href&quot;&gt;“Reading the card explains the card”&lt;/a&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt; &lt;/i&gt;doesn’t always work. With casual players
  and a bunch of unexplained keywords (like Menace, Madness, Shadow, Surveil),
  it can be bit of a burden to figure out what the cards do.
&lt;/p&gt;

&lt;p&gt;
  That’s why I compiled my own Battle Box keyword reference guide (see the thing
  I did in my intro where I used a &lt;i class=&quot;notion-text-italic&quot;&gt;Forest&lt;/i&gt; to
  cast a &lt;i class=&quot;notion-text-italic&quot;&gt;booklet&lt;/i&gt;. smart, huh?): it lists all
  41 keywords that are present in my deck in alphabetical order and explains how
  they work. And the back cover has a quick guide for what “instant speed” and
  “sorcery speed” mean and when you can activate abilities and mana abilities.
&lt;/p&gt;

&lt;p&gt;
  Now, instead of players having to expose what they have in hand and ask me or
  awkwardly search the wiki on their phone, they can pick up the guide and
  check.
&lt;/p&gt;

&lt;p&gt;It was such a fun project and it looks gorgeous.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>F is for f-strings - Python A to Z</title>
    <link href="https://hamatti.org/posts/f-is-for-f-strings-python-a-to-z/" />
    <updated>2026-08-07T00:00:00Z</updated>
    <id>https://hamatti.org/posts/f-is-for-f-strings-python-a-to-z/</id>
    <content type="html">
      
&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  Programming languages have many ways to combine literal strings and variables.
  For a decade now, we in Python land have been able to enjoy the beauty and
  elegance of
  &lt;a href=&quot;https://docs.python.org/3/reference/lexical_analysis.html#f-strings&quot; class=&quot;notion-text-href&quot;&gt;f-strings&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;f-string is a string that is prefixed with the letter f:&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;string_type = &#39;f-string&#39;
print(f&#39;This is a {string_type}&#39;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  When you craft an f-string, you can evaluate Python code inside it by placing
  it inside curly braces `{ … }`.
&lt;/p&gt;

&lt;p&gt;
  In addition to simply putting in a variable, there are a bunch of format
  specifications that allow further modification of the output.
  &lt;a href=&quot;https://fstring.help/cheat/&quot; class=&quot;notion-text-href&quot;&gt;fstring.help&lt;/a&gt;
  has a really handy reference sheet for these but here are some that I use
  regularly.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Padding numbers&lt;/h2&gt;

&lt;p&gt;
  File browsers usually default to sorting alphabetically so if you have files
  &lt;code class=&quot;notion-text-code&quot;&gt;1.json&lt;/code&gt;,
  &lt;code class=&quot;notion-text-code&quot;&gt;2.json&lt;/code&gt; and
  &lt;code class=&quot;notion-text-code&quot;&gt;10.json&lt;/code&gt;, the 10 will sort before the 2.
  So to keep things neat and tidy, I often left-pad with zeroes to force proper
  sorting:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;for filename in range(1, 20):
  print(f&#39;{filename:02d}&#39;)
  
# Prints 01, 02, 03, ... 20&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Here &lt;code class=&quot;notion-text-code&quot;&gt;0&lt;/code&gt; is the value we use to fill and
  &lt;code class=&quot;notion-text-code&quot;&gt;2&lt;/code&gt; is the width to how many characters we
  want to pad up to.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Aligning text&lt;/h2&gt;

&lt;p&gt;
  When I build command line tools, I want a well-defined output structure and
  aligning items left or right with a given width is helpful.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;name, goals = &#39;Juhis&#39;, 20
print(f&#39;{name:&amp;#60;10}{goals:&amp;#62;5}&#39;)
# &#39;Juhis        20&#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;code class=&quot;notion-text-code&quot;&gt;&lt;&lt;/code&gt; is for left-align,
  &lt;code class=&quot;notion-text-code&quot;&gt;&gt;&lt;/code&gt; is for right-align,
  &lt;code class=&quot;notion-text-code&quot;&gt;^&lt;/code&gt; would be for center and the number is
  the width. In this example, it guarantees that the name field is at least 10
  characters and goals field is 5.
&lt;/p&gt;

&lt;p&gt;
  You can combine this with the previous example if you want to fill the empty
  space with something else, like underscore:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;item, value = &#39;Cucumber&#39;, 14
print(f&#39;{item:_&amp;#60;10}{value:_&amp;#62;5}&#39;)
# Cucumber_____14&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Debugging&lt;/h2&gt;

&lt;p&gt;
  For debugging, I use two formats. (Btw, if you wanna get better at debugging,
  check out
  &lt;a href=&quot;https://hamatti.org/posts/debugging-python/&quot; class=&quot;notion-text-href&quot;&gt;Debugging Python&lt;/a&gt;
  and if you’re curious about why printing is a good debug tool, read
  &lt;a href=&quot;https://hamatti.org/posts/print-is-your-best-debugging-tool/&quot; class=&quot;notion-text-href&quot;&gt;print is your best debugging tool&lt;/a&gt;.)
&lt;/p&gt;

&lt;p&gt;
  The first one uses &lt;code class=&quot;notion-text-code&quot;&gt;=&lt;/code&gt; sign to print out
  the name of the variable and its value separated with an equal sign. It’s a
  short hand for &lt;code class=&quot;notion-text-code&quot;&gt;f&#39;value={value}&#39;&lt;/code&gt; .
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;unknown = 400
print(f&#39;{unknown=}, {unknown = }&#39;) # Whitespace is preserved
# unknown=400, unknown = 400&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  The second one uses &lt;code class=&quot;notion-text-code&quot;&gt;!r&lt;/code&gt; to print out
  object’s &lt;code class=&quot;notion-text-code&quot;&gt;__repr__&lt;/code&gt; value.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;class Card:
	def __init__(self, name, number):
	  self.name = name
	  self.number = number
	  
	def __repr__(self):
	  return f&#39;Card(&quot;{self.name}&quot;, {self.number})&#39;

card = Card(&#39;Pikachu&#39;, 25)
print(f&#39;{card!r}&#39;)
# Card(&quot;Pikachu&quot;, 25)&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Percentages&lt;/h2&gt;

&lt;p&gt;
  The last one is actually something I didn’t know about before I started
  writing this but can be handy. You can convert floats to percentages with
  &lt;code class=&quot;notion-text-code&quot;&gt;:.0%&lt;/code&gt;:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;percent = 0.3738
print(f&#39;{percent:.0%}&#39;)
# 37%

print(f&#39;{percent:.2%}&#39;)
# 37.38%&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’s pretty handy!&lt;/p&gt;


    </content>
  </entry>
   
  
  <entry>
    <title>E is for environment variables - Python A to Z</title>
    <link href="https://hamatti.org/posts/e-is-for-environment-variables-python-a-to-z/" />
    <updated>2026-08-06T00:00:00Z</updated>
    <id>https://hamatti.org/posts/e-is-for-environment-variables-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  The code that a program runs is provided by the developer of the program. The
  inputs and interactions are initiated by the user of the program. The
  environment variables are data provided by the system that runs it. They are
  used to abstract configuration to the system level so that the same code can
  be ran in different environments and act differently (for example, development
  vs production environments).
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Accessing environment variables
&lt;/h2&gt;

&lt;p&gt;
  In Python, you can access environment variables through
  &lt;a href=&quot;https://docs.python.org/3/library/os.html#os.environ&quot; class=&quot;notion-text-href&quot;&gt;os.environ dictionary&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  If you run the following in a REPL, you’ll see all the environment variables
  Python has access to.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&amp;#62;&amp;#62;&amp;#62; for variable, value in os.environ.items():
...     print(f&#39;{variable}: {value}&#39;)
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  The &lt;code class=&quot;notion-text-code&quot;&gt;os.environ&lt;/code&gt; is created at the time
  Python started and won’t update to reflect changes in environment variables
  that happen while the program is running. You can use
  &lt;a href=&quot;https://docs.python.org/3/library/os.html#os.reload_environ&quot; class=&quot;notion-text-href&quot;&gt;os.reload_environ&lt;/a&gt;
  to update the values.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Automatically read variables from .env
&lt;/h2&gt;

&lt;p&gt;
  It’s common to store project-specific configuration values in a
  &lt;code class=&quot;notion-text-code&quot;&gt;.env&lt;/code&gt; file instead of managing the
  operating system level variables and having to remember to do that on every
  machine when they change.
&lt;/p&gt;

&lt;p&gt;
  To automatically read the values from
  &lt;code class=&quot;notion-text-code&quot;&gt;.env&lt;/code&gt;, you can use
  &lt;a href=&quot;https://pypi.org/project/python-dotenv/&quot; class=&quot;notion-text-href&quot;&gt;python-dotenv&lt;/a&gt;.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# Example from dotenv documentation
# https://pypi.org/project/python-dotenv/

from dotenv import load_dotenv

load_dotenv()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Environment variables are often used to store secrets and accidentally leaking
  such secrets can be catastrophic. There’s a command line tool
  &lt;a href=&quot;https://dotenvx.com/docs/secrets-in-python&quot; class=&quot;notion-text-href&quot;&gt;dotenvx&lt;/a&gt;
  that enables you to encrypt your secrets and then inject them to Python
  programs at runtime.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>D is for dictionaries - Python A to Z</title>
    <link href="https://hamatti.org/posts/d-is-for-dictionaries-python-a-to-z/" />
    <updated>2026-08-05T00:00:00Z</updated>
    <id>https://hamatti.org/posts/d-is-for-dictionaries-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#dict&quot; class=&quot;notion-text-href&quot;&gt;Dictionary&lt;/a&gt;
  is a data structure in Python that in other contexts and languages is called
  &lt;a href=&quot;https://en.wikipedia.org/wiki/Associative_array&quot; class=&quot;notion-text-href&quot;&gt;an associative array&lt;/a&gt;, akey-value store or a map. It’s a handy and efficient data structure for
  when you need to store and retrieve a value based on a key.
&lt;/p&gt;

&lt;p&gt;This is a 101 level introduction to dictionaries.&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Dictionary&lt;/h2&gt;
&lt;h3&gt;Creating a dictionary&lt;/h3&gt;
&lt;p&gt;The basic form of dictionary can be created in couple of ways:&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# dict constructor with keyword arguments
scores = dict(Charlie=10, Patty=25, Snoopy=30)

# dict constructor with tuples
scores = dict((&#39;Charlie&#39;, 10), (&#39;Patty&#39;, 25), (&#39;Snoopy&#39;, 30))

# key: value pairs
scores = { &#39;Charlie&#39;: 10, &#39;Patty&#39;: 25, &#39;Snoopy&#39;: 30 }

# dict comprehension
data = [(&#39;Charlie&#39;, 10), (&#39;Patty&#39;, 25), (&#39;Snoopy&#39;, 30)]
scores = { key: value for key, value in data }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  In each of these cases, the names are &lt;b class=&quot;notion-text-bold&quot;&gt;keys&lt;/b&gt; and
  numbers are &lt;b class=&quot;notion-text-bold&quot;&gt;values.&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
  There’s one big restriction to the keys of dictionaries: they need to be
  &lt;a href=&quot;https://docs.python.org/3/glossary.html#term-hashable&quot; class=&quot;notion-text-href&quot;&gt;hashable&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  An object is hashable if it has a hash value which never changes during its
  lifetime (it needs a &lt;code class=&quot;notion-text-code&quot;&gt;__hash__()&lt;/code&gt; method),
  and can be compared to other objects (it needs an
  &lt;code class=&quot;notion-text-code&quot;&gt;__eq__()&lt;/code&gt; method). Hashable objects which
  compare equal must have the same hash value.
&lt;/blockquote&gt;

&lt;p&gt;
  So you can’t use a &lt;code class=&quot;notion-text-code&quot;&gt;list&lt;/code&gt; as a key for
  example because it’s a mutable one.
&lt;/p&gt;
&lt;h3&gt;Accessing values&lt;/h3&gt;
&lt;p&gt;
  Regardless of what was used to create it, we can access the values in a couple
  of ways:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;scores = { &#39;Charlie&#39;: 10, &#39;Patty&#39;: 25, &#39;Snoopy&#39;: 30 }

# With brackets
scores[&#39;Charlie&#39;] # == 10

# With .get()
scores.get(&#39;Charlie&#39;) # == 10&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  The difference between these two is what happens when a key does not exist.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;scores[&#39;Linus&#39;]  # raises KeyError: &#39;Linus&#39;
scores.get(&#39;Linus&#39;)  # is None

# We can give .get() a default value
scores.get(&#39;Linus&#39;, 0)  # == 0&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Changing values&lt;/h3&gt;
&lt;p&gt;
  Dictionaries are &lt;i class=&quot;notion-text-italic&quot;&gt;mutable&lt;/i&gt; data structures
  which means you can change their data.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# Set new value
scores[&#39;Charlie&#39;] = 15

# Modify a value
scores[&#39;Charlie&#39;] += 5

# Delete a key
del scores[&#39;Charlie&#39;]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Since there is a direct “one key to one value” relationship, dictionaries are
  very handy in collecting data for or counting values belonging to this key.
&lt;/p&gt;

&lt;p&gt;
  Let’s say we have a dataset where each time someone scores a point, their name
  is listed. We then want to count how may points each has:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;marks = [
  &#39;Charlie&#39;, &#39;Charlie&#39;, &#39;Patty&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;, &#39;Charlie&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;
]

scores = {} # Creating an empty dict
for person in marks: # Go through every mark
  if person not in scores: # If it&#39;s not in the dict yet,
    scores[person] = 0 # create an entry with starting value 0
  
  scores[person] += 1 # Add 1 point to this person
  
print(scores)
# {&#39;Charlie&#39;: 3, &#39;Patty&#39;: 1, &#39;Snoopy&#39;: 4}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  We’ll look a bit later how we can improve this with some of the special
  dictionaries but this basic structure of turning data into a dictionary is a
  fundamental basic to learn in Python.
&lt;/p&gt;

&lt;p&gt;
  While the key needs to be hashable, the values can be anything. So instead of
  just increasing a number from zero upwards, we could store data as a list or
  another dictionary or whatever.
&lt;/p&gt;
&lt;h3&gt;Looping over&lt;/h3&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# By default, loops over keys in for-in
for person in scores:
  print(person, scores[person])
  
# Loop over values
for score in scores.values():
  print(score)
  
# Loop over both
for person, score in scores.items():
  print(person, score)&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Sorting a dictionary&lt;/h3&gt;
&lt;p&gt;
  On a concept level, basic mapping does not have an order. In Python,
  dictionaries maintain the order the keys are inserted in and there are ways to
  force an order (like
  &lt;a href=&quot;https://docs.python.org/3/library/collections.html#collections.OrderedDict&quot; class=&quot;notion-text-href&quot;&gt;OrderedDict&lt;/a&gt;) but it’s a good baseline to base your knowledge of dictionaries on.
&lt;/p&gt;

&lt;p&gt;
  However, when looping over a dictionary, you often want the data to be in some
  sort of order. In the earlier example when we counted marks to a dictionary,
  we might want to print it in an order of most points to least.
&lt;/p&gt;

&lt;p&gt;
  For this, we can use
  &lt;a href=&quot;https://docs.python.org/3/library/functions.html#sorted&quot; class=&quot;notion-text-href&quot;&gt;sorted&lt;/a&gt;
  function:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# Let&#39;s recreate our dictionary
scores = {&#39;Charlie&#39;: 3, &#39;Patty&#39;: 1, &#39;Snoopy&#39;: 4}

for person in sorted(scores, key=scores.get, reverse=True):
  print(f&#39;{person}: {scores[person]}&#39;)
  
# Snoopy: 4
# Charlie: 3
# Patty: 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  The first argument to &lt;code class=&quot;notion-text-code&quot;&gt;sorted&lt;/code&gt; is in this
  case our dictionary. The second key,
  &lt;code class=&quot;notion-text-code&quot;&gt;key=&lt;/code&gt; is a single argument function that
  defines what is used for sorting (in this case,
  &lt;code class=&quot;notion-text-code&quot;&gt;scores.get&lt;/code&gt; tells the function we want
  the values corresponding to the keys) and
  &lt;code class=&quot;notion-text-code&quot;&gt;reverse=&lt;/code&gt; can be used to reverse the
  order from ascending to descending.
&lt;/p&gt;

&lt;p&gt;
  It’s important to note that nothing internally in the dictionary changes when
  using &lt;code class=&quot;notion-text-code&quot;&gt;sorted&lt;/code&gt;. It returns a new list with
  the keys sorted based on the sorting criteria.
&lt;/p&gt;
&lt;h3&gt;You’ll do just fine with dictionary for a long time&lt;/h3&gt;
&lt;p&gt;
  Next, I’ll introduce some specialised dictionaries that are included in the
  standard library because developers have found these cases very useful. If
  you’re a new developer, I do recommend focusing on using and understanding the
  basic dictionary.
&lt;/p&gt;

&lt;p&gt;
  There’s nothing in the following dictionaries that you can’t do in the basic
  one.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://frontendmasters.com/courses/complete-intro-containers-v2/&quot; class=&quot;notion-text-href&quot;&gt;Brian Holt once said this in one of his containers course&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &lt;p&gt;When I don’t know how my tools work, I tend to resent them because they add
  complexity to my life. &lt;/p&gt;&lt;p&gt; When I understand what they are doing for me
  and what I no longer have to do because the tool is doing it for me, I tend to
  really like my tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Jumping into the more advanced use cases before understanding the basics
  really well can be detrimental. Finish this blog post to see what’s out there
  but don’t be afraid to manually write the code they would let you skip over
  and over again so that you’ll gain a deeper understanding.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;defaultdict&lt;/h2&gt;

&lt;p&gt;
  In the earlier example of creating and populating a dictionary, we had to
  check if a key existed before we could interact with it:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;marks = [
  &#39;Charlie&#39;, &#39;Charlie&#39;, &#39;Patty&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;, &#39;Charlie&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;
]

scores = {} # Creating an empty dict
for person in marks: # Go through every mark
  if person not in scores: # If it&#39;s not in the dict yet,
    scores[person] = 0 # create an entry with starting value 0
  
  scores[person] += 1 # Add 1 point to this person
  
print(scores)
# {&#39;Charlie&#39;: 3, &#39;Patty&#39;: 1, &#39;Snoopy&#39;: 4}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  There’s a way to shortcut this by using a
  &lt;a href=&quot;https://docs.python.org/3/library/collections.html#collections.defaultdict&quot; class=&quot;notion-text-href&quot;&gt;defaultdict&lt;/a&gt;:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from collections import defaultdict

marks = [
  &#39;Charlie&#39;, &#39;Charlie&#39;, &#39;Patty&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;, &#39;Charlie&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;
]

# Create a new dictionary with
# default value of 0 for each key
scores = defaultdict(int) 

for person in marks:
  scores[person] += 1
  
print(scores)
# defaultdict(&amp;#60;class &#39;int&#39;&amp;#62;, {&#39;Charlie&#39;: 3, &#39;Patty&#39;: 1, &#39;Snoopy&#39;: 4})&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Passing &lt;code class=&quot;notion-text-code&quot;&gt;int&lt;/code&gt; to
  &lt;code class=&quot;notion-text-code&quot;&gt;defaultdict&lt;/code&gt; tells the dictionary to
  start from a default value of 0. You could also pass
  &lt;code class=&quot;notion-text-code&quot;&gt;list&lt;/code&gt; and the default would be an empty
  list. As you can see comparing the two examples above, the code becomes way
  easier to read and comprehend.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Counter&lt;/h2&gt;

&lt;p&gt;
  Our example of counting things is such a common operation that there’s a
  special
  &lt;a href=&quot;https://docs.python.org/3/library/collections.html#collections.Counter&quot; class=&quot;notion-text-href&quot;&gt;Counter&lt;/a&gt;
  dictionary for it.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;from collections import Counter

marks = [
  &#39;Charlie&#39;, &#39;Charlie&#39;, &#39;Patty&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;, &#39;Charlie&#39;, 
  &#39;Snoopy&#39;, &#39;Snoopy&#39;
]

scores = Counter(marks)

print(scores)
# Counter({&#39;Snoopy&#39;: 4, &#39;Charlie&#39;: 3, &#39;Patty&#39;: 1})&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Not only does &lt;code class=&quot;notion-text-code&quot;&gt;Counter&lt;/code&gt; help us in
  creation of it but it has a couple of really handy methods.
&lt;/p&gt;

&lt;p&gt;
  I have
  &lt;a href=&quot;https://hamatti.org/posts/count-em/&quot; class=&quot;notion-text-href&quot;&gt;written about Counter before&lt;/a&gt;
  and rather than repeating myself here, I recommend reading through that post.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>C is for command line interfaces - Python A to Z</title>
    <link href="https://hamatti.org/posts/c-is-for-command-line-interfaces-python-a-to-z/" />
    <updated>2026-08-04T00:00:00Z</updated>
    <id>https://hamatti.org/posts/c-is-for-command-line-interfaces-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  Python is a great language for writing scripts that are executed from the
  command line. I’m
  &lt;a href=&quot;https://hamatti.org/posts/why-i-love-command-line/&quot; class=&quot;notion-text-href&quot;&gt;a big fan of command line interfaces&lt;/a&gt;
  and love building them for all sorts of needs both personally and when I’m
  part of a team.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Command Line Interface Guidelines
&lt;/h2&gt;

&lt;p&gt;
  An integral part of command line software is dealing with arguments and
  options. In this post, I’ll focus on the technical part within the Python code
  but I highly recommend reading
  &lt;a href=&quot;https://clig.dev/&quot; class=&quot;notion-text-href&quot;&gt;Command Line Interface Guidelines&lt;/a&gt;. It’s an open source guide to “help you write better command-line programs,
  taking traditional UNIX principles and updating them for the modern day”. I
  keep it at hand and always refer to it when I’m designing my interfaces.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Simple arguments through &lt;code class=&quot;notion-text-code&quot;&gt;sys.argv&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;
  For the simplest use cases, accessing the list of arguments through
  &lt;a href=&quot;https://docs.python.org/3/library/sys.html#sys.argv&quot; class=&quot;notion-text-href&quot;&gt;sys.argv&lt;/a&gt;
  is the best option. I usually use it at the beginning while I’m still forming
  the ideas of what the tool will look like or when the script only requires one
  or two positional arguments.
&lt;/p&gt;

&lt;p&gt;Let’s say we run a script with the following:&lt;/p&gt;

&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;python script.py 2 file.txt&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  To access those arguments, we write
  &lt;code class=&quot;notion-text-code&quot;&gt;&lt;a href=&quot;http://script.py/&quot; class=&quot;notion-text-href&quot;&gt;script.py&lt;/a&gt;&lt;/code&gt;
  to be:
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;import sys

script_name = sys.argv[0]  # script.py
copies = sys.argv[1]  # 2
filename = sys.argv[2]  # file.py&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  You can’t trust the user to always provide the right amount of arguments
  though so it’s a good idea to add some checks and instruct the user how to use
  it properly.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;import sys

if __name__ == &quot;__main__&quot;:
    arguments = sys.argv
    if len(arguments) &amp;#60; 3:
        print(&quot;&quot;&quot;Two arguments required for the amount of copies and the filename.
    
Usage; script.py &amp;#60;amount of copies&amp;#62; &amp;#60;filename&amp;#62;&quot;&quot;&quot;)
        sys.exit(1)

    copies = arguments[1]
    filename = arguments[2]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  This provides a top level check AND documentation at the same time and is a
  great habit to get into.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Documentation-first approach with docopt
&lt;/h2&gt;

&lt;p&gt;
  Speaking of documentation,
  &lt;a href=&quot;http://docopt.org/&quot; class=&quot;notion-text-href&quot;&gt;docopt&lt;/a&gt; and its
  maintained Python implementation
  &lt;a href=&quot;https://github.com/jazzband/docopt-ng&quot; class=&quot;notion-text-href&quot;&gt;docopt-ng&lt;/a&gt;
  provide a documentation-driven way for declaring the command line interface.
&lt;/p&gt;

&lt;p&gt;
  Defining the interface first leads to better user experience. In my
  experience, starting with implementation details often leads to either
  suboptimal interfaces or spaghetti code to try to mend an implementation to
  interface later. If you start by thinking how the user should interact with
  the application, then the rest follows to fill the gaps in an elegant way.
&lt;/p&gt;

&lt;p&gt;
  Using docopt, you write the usage pattern in your docstring and let the tool
  figure out what arguments and options it needs to derive from it (example from
  docs):
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&quot;&quot;&quot;Naval Fate.

Usage:
  naval_fate.py ship new &amp;#60;name&amp;#62;...
  naval_fate.py ship &amp;#60;name&amp;#62; move &amp;#60;x&amp;#62; &amp;#60;y&amp;#62; [--speed=&amp;#60;kn&amp;#62;]
  naval_fate.py ship shoot &amp;#60;x&amp;#62; &amp;#60;y&amp;#62;
  naval_fate.py mine (set|remove) &amp;#60;x&amp;#62; &amp;#60;y&amp;#62; [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=&amp;#60;kn&amp;#62;  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

&quot;&quot;&quot;
from docopt import docopt


if __name__ == &#39;__main__&#39;:
    arguments = docopt(__doc__, version=&#39;Naval Fate 2.0&#39;)
    print(arguments)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;a href=&quot;https://hamatti.org/posts/documentation-driven-command-line-tools-in-python-with-docopt/&quot; class=&quot;notion-text-href&quot;&gt;I have written about docopt&lt;/a&gt;
  a few years ago and that post still holds water so I recommend you go read
  that for more information.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Click&lt;/h2&gt;

&lt;p&gt;
  The library I use most often these days — because it works so nicely with
  custom Django commands with
  &lt;a href=&quot;https://github.com/django-commons/django-click&quot; class=&quot;notion-text-href&quot;&gt;django-click&lt;/a&gt;
  — is
  &lt;a href=&quot;https://click.palletsprojects.com/en/stable/&quot; class=&quot;notion-text-href&quot;&gt;click&lt;/a&gt;. Click uses Python decorators to define commands, subcommands, arguments and
  options.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# Example from click documentation
# https://click.palletsprojects.com/en/stable/

import click

@click.command()
@click.option(&#39;--count&#39;, default=1, help=&#39;Number of greetings.&#39;)
@click.option(&#39;--name&#39;, prompt=&#39;Your name&#39;,
              help=&#39;The person to greet.&#39;)
def hello(count, name):
    &quot;&quot;&quot;Simple program that greets NAME for a total of COUNT times.&quot;&quot;&quot;
    for x in range(count):
        click.echo(f&quot;Hello {name}!&quot;)

if __name__ == &#39;__main__&#39;:
    hello()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  You can add
  &lt;a href=&quot;https://click.palletsprojects.com/en/stable/advanced/#callbacks-for-validation&quot; class=&quot;notion-text-href&quot;&gt;extra validation through callbacks&lt;/a&gt;
  directly at this level which makes the actual code of your application a bit
  cleaner when the validation and first level input processing is done before
  the arguments and options ever reach your application logic.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;# Example from click documentation
# https://click.palletsprojects.com/en/stable/advanced/#callbacks-for-validation

def validate_rolls(ctx, param, value):
    if isinstance(value, tuple):
        return value

    try:
        rolls, _, dice = value.partition(&quot;d&quot;)
        return int(dice), int(rolls)
    except ValueError:
        raise click.BadParameter(&quot;format must be &#39;NdM&#39;&quot;)

@click.command()
@click.option(
    &quot;--rolls&quot;, type=click.UNPROCESSED, callback=validate_rolls,
    default=&quot;1d6&quot;, prompt=True,
)
def roll(rolls):
    sides, times = rolls
    click.echo(f&quot;Rolling a {sides}-sided dice {times} time(s)&quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  With django-click, you can use the same interface to define an interface for
  your custom commands.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;import djclick as click

@click.command()
@click.option(&quot;--file&quot;, help=&quot;Load set from a local JSON file&quot;)
def command(file):
	...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>B is for batteries included - Python A to Z</title>
    <link href="https://hamatti.org/posts/b-is-for-batteries-included-python-a-to-z/" />
    <updated>2026-08-03T00:00:00Z</updated>
    <id>https://hamatti.org/posts/b-is-for-batteries-included-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  Python is often described as having
  &lt;b class=&quot;notion-text-bold&quot;&gt;batteries included&lt;/b&gt;
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  The Python source distribution has long maintained the philosophy of
  “batteries included” – having a rich and versatile standard library which is
  immediately available, without making the user download separate packages.
  This gives the Python language a head start in many projects. - from
  &lt;a href=&quot;https://peps.python.org/pep-0206/&quot; class=&quot;notion-text-href&quot;&gt;withdrawn PEP 206&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  I love Python’s batteries included philosophy and its standard library so much
  that I dedicated an entire
  &lt;a href=&quot;https://hamatti.org/blog/batteries-included/&quot; class=&quot;notion-text-href&quot;&gt;Blaugust in 2024&lt;/a&gt;
  writing about it:
&lt;/p&gt;
&lt;ul class=&quot;notion-bulleted_list&quot;&gt;
  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/parsing-nginx-server-logs-with-regular-expressions/&quot; class=&quot;notion-text-href&quot;&gt;Parsing nginx server logs with regular expressions&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/reading-and-writing-csv-with-python/&quot; class=&quot;notion-text-href&quot;&gt;Reading and writing CSV with Python&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/improve-your-code-with-namedtuples/&quot; class=&quot;notion-text-href&quot;&gt;Improve your code with namedtuples&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/count-em/&quot; class=&quot;notion-text-href&quot;&gt;Count ‘em&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/help-me-obi-wan-kenobi-youre-my-only-hope/&quot; class=&quot;notion-text-href&quot;&gt;help() me Obi-Wan Kenobi, you’re my only hope&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/improved-print-readability-with-pprint/&quot; class=&quot;notion-text-href&quot;&gt;Improved print readability with pprint&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/document-intended-usage-through-tests-with-doctest/&quot; class=&quot;notion-text-href&quot;&gt;Document intended usage through tests with doctest&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/debug-with-pdb-and-breakpoint/&quot; class=&quot;notion-text-href&quot;&gt;Debug with pdb and breakpoint&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/rotating-turn-order-with-deque/&quot; class=&quot;notion-text-href&quot;&gt;Rotating turn order with deque&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/data-classes-in-python-with-dataclasses/&quot; class=&quot;notion-text-href&quot;&gt;Data classes in Python with dataclasses&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/combinatoric-iterators-from-itertools/&quot; class=&quot;notion-text-href&quot;&gt;Combinatoric iterators from itertools&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/write-more-pythonic-code-with-context-managers/&quot; class=&quot;notion-text-href&quot;&gt;Write more pythonic code with context managers&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/random-number-chosen-by-fair-dice-roll/&quot; class=&quot;notion-text-href&quot;&gt;Random number chosen by fair dice roll&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/combine-iterables-with-zip/&quot; class=&quot;notion-text-href&quot;&gt;Combine iterables with zip&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/map-and-filter-with-list-comprehensions/&quot; class=&quot;notion-text-href&quot;&gt;map and filter with list comprehensions&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/memoize-with-functools-cache/&quot; class=&quot;notion-text-href&quot;&gt;Memoize with functools.cache&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/keep-track-of-happenings-with-logging/&quot; class=&quot;notion-text-href&quot;&gt;Keep track of happenings with logging&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/bring-your-custom-toolkit-to-repl-sessions/&quot; class=&quot;notion-text-href&quot;&gt;Bring your custom toolkit to REPL sessions&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/serve-local-html-and-css-files-with-http-server/&quot; class=&quot;notion-text-href&quot;&gt;Serve local HTML and CSS files with http.server&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/branch-out-with-pattern-matching/&quot; class=&quot;notion-text-href&quot;&gt;Branch out with pattern matching&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/test-your-codebase-with-unittest/&quot; class=&quot;notion-text-href&quot;&gt;Test your codebase with unittest&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/pretty-print-and-validate-json-on-command-line-with-json-tool/&quot; class=&quot;notion-text-href&quot;&gt;Pretty print and validate JSON on command line with json.tool&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/parse-command-line-arguments-with-argparse/&quot; class=&quot;notion-text-href&quot;&gt;Parse command line arguments with argparse&lt;/a&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;a href=&quot;https://hamatti.org/posts/quick-prototyping-with-sqlite3/&quot; class=&quot;notion-text-href&quot;&gt;Quick prototyping with sqlite3&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  At
  &lt;a href=&quot;https://hamatti.org/posts/pycon-finland-2025-recap/&quot; class=&quot;notion-text-href&quot;&gt;PyCon Finland 2025&lt;/a&gt;, we got this cool LEGO Python logo that had batteries included:
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/b-is-for-batteries-included-python-a-to-z/1.png.webp&quot; alt=&quot;A LEGO Python logo with two pieces removed to the side, exposing two 1-by-1 circle pieces with battery stickers inside the logo. &quot; /&gt;
&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>A is for assert - Python A to Z</title>
    <link href="https://hamatti.org/posts/a-is-for-assert-python-a-to-z/" />
    <updated>2026-08-02T00:00:00Z</updated>
    <id>https://hamatti.org/posts/a-is-for-assert-python-a-to-z/</id>
    <content type="html">
      &lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  The
  &lt;a href=&quot;https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement&quot; class=&quot;notion-text-href&quot;&gt;assert statement&lt;/a&gt;
  is a built-in Python statement that gives developers a nice short hand for
  raising an &lt;code class=&quot;notion-text-code&quot;&gt;AssertionError&lt;/code&gt; based on a
  condition.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;assert expression, &quot;message&quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An assert statement is syntactic shorthand for&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;if __debug__:
  if not expression: raise AssertionError(&quot;message&quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To see how it works in practice, let’s jump into a REPL session:&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&amp;#62;&amp;#62;&amp;#62; age = 21
&amp;#62;&amp;#62;&amp;#62; assert age &amp;#62; 18, f&quot;Needs to be over 18 years old, {age=}&quot;
&amp;#62;&amp;#62;&amp;#62; age = 16
&amp;#62;&amp;#62;&amp;#62; assert age &amp;#62; 18, f&quot;Needs to be over 18 years old, {age=}&quot;
Traceback (most recent call last):
  File &quot;&amp;#60;python-input-5&amp;#62;&quot;, line 1, in &amp;#60;module&amp;#62;
    assert age &amp;#62; 18, f&quot;Needs to be over 18 years old, {age=}&quot;
           ^^^^^^^^
AssertionError: Needs to be over 18 years old, age=16&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  When the expression is truthy, nothing happens. When it’s falsy however,
  Python will raise an &lt;code class=&quot;notion-text-code&quot;&gt;AssertionError&lt;/code&gt; and
  if a message was provided, it will be printed after the error in the
  traceback.
&lt;/p&gt;

&lt;p&gt;
  Writing good assertion messages will make your life easier in the future. When
  you write your code, you have a good idea of what the assertion tests but as
  time goes on, the memories will fade and if you run into a random
  AssertionError in your script (see use case 1 below), it may require a lot of
  mental work to get back on track.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Use case 1: failsafe for scripting
&lt;/h2&gt;

&lt;p&gt;
  It’s handy for debugging but also as a sort of failsafe for scripts that you
  run manually.
&lt;/p&gt;

&lt;p&gt;
  When I write
  &lt;a href=&quot;https://hamatti.org/posts/tame-your-pesky-little-scripts/&quot; class=&quot;notion-text-href&quot;&gt;shell script style scripts with Python&lt;/a&gt;, I don’t always need to write the most robust code but a quick “make sure
  this is so” check that stops the execution is enough. In a use case like that,
  adding asserts is a quick way to make sure unexpected issues in data don’t
  make their way to wreck havoc later in the script.
&lt;/p&gt;

&lt;p&gt;
  When the script is run manually, it’s perfectly fine for it to crash to an
  unhandled exception. That’s not usually the case if you’re running it
  automatically (for example in CI or as a cronjob) so in those cases you want
  to make sure your script can either recover or properly logs its errors.
&lt;/p&gt;

&lt;p&gt;Let’s look at a simplified example:&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;#!/usr/bin/env -S uv run --quiet --script
import sys

path = sys.argv[1]
assert &#39;..&#39; not in path, f&quot;Can&#39;t go up in directory hierarchy, {path=}&quot;

# Run the script&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;(the shebang of the previous script makes it handy to write &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://notes.hamatti.org/technology/single-file-executable-python-scripts-with-uv&quot; class=&quot;notion-text-href&quot;&gt;single-file executable Python scripts&lt;/a&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt; using uv)&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
  Here, we have a script that accepts a file path as a command line argument and
  does something with it. I wanted to make sure it doesn’t accidentally escape
  to do things in folders above where it’s ran. This could happen accidentally
  for example if it’s being run by another script that could have inserted an
  &lt;code class=&quot;notion-text-code&quot;&gt;..&lt;/code&gt; into its list of filenames.
&lt;/p&gt;

&lt;p&gt;
  It’s not a perfect, robust error boundary as there could be files with double
  periods but it’s good enough for my script’s use case. The provided message
  lets me know if it skipped something because of double period.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;NOTE: &lt;/b&gt;It’s important to note that assertions
  will be disabled if the code is run with optimisations enabled (either by
  running the script with &lt;code class=&quot;notion-text-code&quot;&gt;python -O&lt;/code&gt; or
  &lt;code class=&quot;notion-text-code&quot;&gt;python -OO&lt;/code&gt; or having the environment
  variable
  &lt;code class=&quot;notion-text-code&quot;&gt;&lt;a href=&quot;https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE&quot; class=&quot;notion-text-href&quot;&gt;PYTHONOPTIMIZE&lt;/a&gt;&lt;/code&gt;
  set to a non-zero value). This means you cannot and should not rely on
  &lt;code class=&quot;notion-text-code&quot;&gt;assert&lt;/code&gt;s for data validation generally.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Use case 2: pytest&lt;/h2&gt;

&lt;p&gt;
  Popular testing library
  &lt;a href=&quot;https://docs.pytest.org/en/stable/&quot; class=&quot;notion-text-href&quot;&gt;pytest&lt;/a&gt;
  uses asserts for test cases.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;def test_empty_list_sums_to_zero():
  assert sum([]) == 0&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  I find it much more elegant and readable than the custom assertion libraries
  like unittest’s &lt;code class=&quot;notion-text-code&quot;&gt;self.assertEqual&lt;/code&gt;. It
  also allows writing tests without having to import anything in the test suite.
&lt;/p&gt;

&lt;p&gt;
  When you run this through &lt;code class=&quot;notion-text-code&quot;&gt;pytest&lt;/code&gt;, it
  will check whether &lt;code class=&quot;notion-text-code&quot;&gt;sum([])&lt;/code&gt; returns
  &lt;code class=&quot;notion-text-code&quot;&gt;0&lt;/code&gt; or not and either passes or fails the
  test.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>Python A to Z - Blaugust 2026 introduction</title>
    <link href="https://hamatti.org/posts/python-a-to-z-blaugust-2026-introduction/" />
    <updated>2026-08-01T00:00:00Z</updated>
    <id>https://hamatti.org/posts/python-a-to-z-blaugust-2026-introduction/</id>
    <content type="html">
      
&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Python A-Z&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is a blog series about Python. Each day, I share insights, ideas and
    examples for different parts of Python development that match with the
    letter of the day. &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;b class=&quot;notion-text-bold&quot;&gt;Blaugust&lt;/b&gt;&lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;
    is an annual blogging festival in August where the goal is to write a blog
    post every day of the month.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;Hello internet friend, and happy August!&lt;/p&gt;

&lt;p&gt;
  It’s the first of August around here and that means it’s time to kick off
  another Blaugust blogging festival that runs from August 1st to August 31st in
  various participating blogs across time and space of the blogosphere.
&lt;/p&gt;

&lt;p&gt;
  It’s customary to introduce yourself at the beginning so today’s post will be
  about who I am and what my plans for this year’s Blaugust are. If you’re new
  to my blog, welcome! I write weekly (and sometimes more) blog posts about
  technology, software development, community, tabletop and video games,
  writing, my life and everything else that comes to mind.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;It’s me!&lt;/h2&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;I’m Juhis, a community builder, writer, dreamer, adventurer and Pokémon
    enthusiast.&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
  I built my first blog back around 2002 and over the decades,
  &lt;a href=&quot;https://hamatti.org/posts/short-history-of-my-blogging-journey/&quot; class=&quot;notion-text-href&quot;&gt;many blogs of mine have come and gone&lt;/a&gt;. This blog that you’re reading right now, I started in 2018 and have been
  blogging regularly ever since. In addition to my blog, I publish my notes in
  &lt;a href=&quot;https://notes.hamatti.org/&quot; class=&quot;notion-text-href&quot;&gt;Garden of Learning&lt;/a&gt;
  and write a board game zine
  &lt;a href=&quot;https://zine.hamatti.org/&quot; class=&quot;notion-text-href&quot;&gt;Roll the Zine&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  As a writer, I like to dance with words and punctuation (and dance to the
  music as a human being as well but that’s a story for another day). You’ll
  find plenty of side notes in parentheses and liberal use of
  &lt;a href=&quot;https://em-dash-appreciation.org/&quot; class=&quot;notion-text-href&quot;&gt;em dashes&lt;/a&gt;. The finished blog posts you’ll read in this blog have often
  &lt;a href=&quot;https://hamatti.org/posts/how-long-does-it-take-me-to-write-a-blog-post/&quot; class=&quot;notion-text-href&quot;&gt;taken many turns and spent their time in the merry go round in my mind&lt;/a&gt;
  before they reach the public internet.
&lt;/p&gt;

&lt;p&gt;
  When it comes to technical blog posts, I’m like those cooking recipe writers
  who tell stories instead of purely info dumping the recipe on the page. This
  is a &lt;b class=&quot;notion-text-bold&quot;&gt;blog &lt;/b&gt;after all, not a tech text book.
&lt;/p&gt;

&lt;p&gt;
  I love learning new things and sharing them with others. I believe there’s
  room for sharing of experiences from all levels of experience and I encourage
  other people to start blogs to share what they have learn and know.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;What’s Blaugust?&lt;/h2&gt;

&lt;p&gt;Blaugust is a blogging festival and a community of bloggers.&lt;/p&gt;

&lt;p&gt;
  I quote Krikket from
  &lt;a href=&quot;https://nerdgirlthoughts.game.blog/2026/07/15/blaugust-2026-is-coming/&quot; class=&quot;notion-text-href&quot;&gt;the announcement post&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  For anyone arriving here for the very first time Blaugust is a month-long
  event that takes place each August which focuses on blogging primarily and has
  started to include other forms of serialized content over the last several
  years. The goal is to stoke the fires of creativity and allow bloggers and
  other content creators to mingle in a shared community while pushing each
  other to post more regularly. Above all the goal of Blaugust has always been
  to prove to folks that they can in fact sit down every day and create
  something fresh and then share it with the world. Posting regularly builds a
  community and in this era of AI-slop content, our voices are needed even more
  than we ever have been at any point in the past. Our hope is to create a
  nurturing environment where Veteran bloggers can help those just getting
  started and the cross-pollination of ideas can create something truly
  spectacular. Your blog gives you a permanent foothold on the Internet that you
  own and have complete control of, and that is a really good feeling in the
  midst of shifting trends.
&lt;/blockquote&gt;

&lt;p&gt;
  One of the goals — that I aim for — is to publish 31 posts in 31 days. The
  real goal however is to write and publish.
  &lt;b class=&quot;notion-text-bold&quot;&gt;Any number of posts is a win. &lt;/b&gt;In the Discord
  and other blogs, you’ll often hear “The only way to lose is by not
  participating” repeated.
&lt;/p&gt;

&lt;p&gt;
  For me, 31 posts is an intriguing challenge. Outside Blaugust, I’ve found a
  pretty nice rhythm of publishing one or two posts per week so personally, the
  challenge of daily blogging for a short amount of time is about wanting to see
  if I can sit down, come up with ideas and write even more.
&lt;/p&gt;

&lt;p&gt;
  If you want to join Blaugust, we have
  &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLScouIfF_RGkOPhWbyDjAhGTnxJ0smWfhZEiZRiAeLnvzPuO9g/viewform&quot; class=&quot;notion-text-href&quot;&gt;a sign up form&lt;/a&gt;
  and
  &lt;a href=&quot;https://discord.gg/EVvMnEGvgV&quot; class=&quot;notion-text-href&quot;&gt;a Discord server&lt;/a&gt;. I highly recommend joining if you have a blog and if you don’t have one,
  this is a great way to kickstart one.
&lt;/p&gt;

&lt;p&gt;
  I wrote earlier this summer about
  &lt;a href=&quot;https://hamatti.org/posts/on-blogging-blaugust-and-challenging-yourself/&quot; class=&quot;notion-text-href&quot;&gt;why I blog and why I participate in challenges like Blaugust&lt;/a&gt;.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Python A to Z&lt;/h2&gt;

&lt;p&gt;
  In
  &lt;a href=&quot;https://hamatti.org/blog/blaugust-2024/&quot; class=&quot;notion-text-href&quot;&gt;Blaugust 2024, I wrote about Python’s standard library&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  There’s so much more to Python though so this year I’m approaching it from a
  different angle and pick one topic for each letter in the English alphabet to
  write about. Some of them will include code examples, often in a recipe style
  of “how to do X with Python” while others will be about topics that don’t
  include code.
&lt;/p&gt;

&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&amp;#62;&amp;#62;&amp;#62; from string import ascii_lowercase
&amp;#62;&amp;#62;&amp;#62; print(f&#39;There are {len(ascii_lowercase)} letters in A to Z&#39;)
&quot;There are 26 letters in A to Z&quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  With 26 letters and 31 days, this creates a perfect structure for Blaugust. It
  leaves me 5 days for other things like this introduction post on the first and
  a wrap up post on the 31st as well as this month’s IndieWeb Carnival entry
  (&lt;a href=&quot;https://thoughts.uncountable.uk/august-2026-indieweb-carnival-purpose/&quot;&gt;Chris is hosting it on the theme of purpose&lt;/a&gt;) and a few days for other
  interesting topics that arise in August.
&lt;/p&gt;

&lt;p&gt;
  I have made some preparations and have topic level ideas for most letters but
  some are still undecided either because there are too many interesting options
  or because there are very few (unsurprisingly X, Y and Z are tough…).
&lt;/p&gt;

&lt;p&gt;
  Welcome along the journey for the next 31 days to learn new things about
  Python and celebrate the festival of blogging.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
   
  
  <entry>
    <title>In the era of AI slop, human curation is even more important</title>
    <link href="https://hamatti.org/posts/in-the-era-of-ai-slop-human-curation-is-even-more-important/" />
    <updated>2026-07-29T00:00:00Z</updated>
    <id>https://hamatti.org/posts/in-the-era-of-ai-slop-human-curation-is-even-more-important/</id>
    <content type="html">
      &lt;p&gt;
  I started last year by writing about
  &lt;a href=&quot;https://hamatti.org/posts/human-curation-over-algorithmic-recommendations/&quot; class=&quot;notion-text-href&quot;&gt;my growing desire for human curation&lt;/a&gt;. In that post, I mainly focused on contrasting human curation with
  recommendation algorithms that had overtaken many aspects of the web: from
  media platforms like Youtube, Spotify and Netflix to social media like
  Facebook, X and Instagram.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_Internet_theory&quot; class=&quot;notion-text-href&quot;&gt;The dead internet theory&lt;/a&gt;
  refers to the idea that the most of the user generated content in the web
  comes from bot activity and automated content rather than humans. It’s based
  on the idea that because these platforms operate so heavily on algorithms that
  can be gamed rather than human interest, it’s beneficial to many parties to
  fill the web with their generated content.
&lt;/p&gt;

&lt;p&gt;
  This benefit could come in form of direct financial benefit (like generating
  low/no effort Youtube videos and gaining money from ad revenue) or through
  other means like spreading political misinformation or riling up hate.
&lt;/p&gt;

&lt;p&gt;
  In 2026, it’s easier than ever to generate content with large language models
  (LLMs). Almost all of it is just empty fluff and the massive amount of it,
  combined with these recommendation algorithms choosing what you see, is what’s
  leading to it being harder and harder to find good stuff.
&lt;/p&gt;

&lt;p&gt;
  In the earlier post, I mainly focused on the value of human curation even when
  algorithms push content written by humans that’s easy to digest and sparks the
  maximum amount of emotions — usually negative ones since those are the ones
  more like to engage us in the way platforms want.
&lt;/p&gt;

&lt;p&gt;
  Quoting myself from the
  &lt;a href=&quot;https://hamatti.org/posts/human-curation-over-algorithmic-recommendations/&quot; class=&quot;notion-text-href&quot;&gt;earlier blog post&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  These algorithms exist to maximise engagement in the platform. And nothing
  engages more than controversial, surface-level and rage fuelling content.
  People who support the ideas activate because the thoughts resonate with them
  and are simple enough to boost and distribute. Those who disagree with the
  ideas fight back, replying, arguing and trying to tell their side of the
  story. The more people talk about it, the more it brings people to the
  discussion and to the platform.
&lt;/blockquote&gt;

&lt;p&gt;
  Now, more than ever, we need human curation to find
  &lt;b class=&quot;notion-text-bold&quot;&gt;anything meaningful.&lt;/b&gt; The problem with LLM
  generated slop is that it requires close to no effort to fill every avenue
  with it. If you push millions of pieces of content to Youtube, music
  platforms, app stores and social media every day, it just drowns everything
  under it due to the sheer volume.
&lt;/p&gt;

&lt;p&gt;
  I watch more Youtube than I should but I’m at the point where every day I
  question why I still open the app when so much of what Youtube’s algorithms
  push to my face is super low quality AI slop. You don’t know it’s that until
  you’ve opened the video, watched it for a bit and then realise there’s no
  cohesion or its full of mistakes.
&lt;/p&gt;

&lt;p&gt;
  I’m drawn more and more towards people I trust and gravitating towards their
  recommendations and shared experiences. I really enjoy when someone shares a
  movie or book review in their blog, explaining why they enjoyed (or didn’t
  enjoy) it. Or learning about new software or services based on their actual
  experiences, not LLM generated slop reviews.
&lt;/p&gt;

&lt;p&gt;Earlier I wrote&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  Curation is much more than just long lists of links. The scifi book list from
  earlier is more of a backlog for myself than curation for others because
  there&#39;s not enough context or personal recommendation involved for it to be
  very useful to others.
&lt;/blockquote&gt;

&lt;p&gt;
  It takes time and effort to share those but I think it’s crucial to
  participate in that. More now than maybe ever.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>Not seeking growth is a perfectly valid strategy</title>
    <link href="https://hamatti.org/posts/not-seeking-growth-is-a-perfectly-valid-strategy/" />
    <updated>2026-07-27T00:00:00Z</updated>
    <id>https://hamatti.org/posts/not-seeking-growth-is-a-perfectly-valid-strategy/</id>
    <content type="html">
      &lt;p&gt;
  The other day, I ran into a Mastodon discussion about open source software and
  how blaming your userbase isn&#39;t a great strategy for growth.
&lt;/p&gt;

&lt;p&gt;
  Scott Jenson
  &lt;a href=&quot;https://social.coop/@scottjenson/116913589001924603&quot; class=&quot;notion-text-href&quot;&gt;made a comment&lt;/a&gt;
  (emphasis mine):
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  I like this post from Ian Coldwater. Slagging off users isn&#39;t a growth
  strategy.
  &lt;b class=&quot;notion-text-bold&quot;&gt;Now, you may not want growth, perfectly fine, but this is specifically
    calling out apps that want mainstream consumers&lt;/b&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  and what sparked me to write this blog post was
  &lt;a href=&quot;https://infosec.exchange/@prism/116913598626009805&quot; class=&quot;notion-text-href&quot;&gt;this comment by Drew Mochak&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &quot;I don&#39;t want growth&quot; is such a wacky, fediverse-only take
&lt;/blockquote&gt;

&lt;p&gt;
  I&#39;m not sure I agree with the &quot;fediverse-only&quot; jab but given that it would be
  true, that would make me much happier about being part of Fediverse because
  not wanting growth is a perfectly valid strategy and I want to tell you why.
&lt;/p&gt;

&lt;p&gt;
  In another reply down the thread
  &lt;a href=&quot;https://infosec.exchange/@prism/116913804848004977&quot; class=&quot;notion-text-href&quot;&gt;he said this&lt;/a&gt;
  (emphasis mine):
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;I find it really strange to pre-suppose that a thing will only appeal to a
    certain group and to not see this as a failure mode.&lt;/b&gt;
  The truth is no one knows how people will react to anything put out into the
  world. &quot;you&#39;re the wrong audience for my tool&quot; just feels like elitism dressed
  up as incompetence, frankly. If someone wants to act like a hermet, that&#39;s
  their right, but I also won&#39;t take their opinions very seriously.
&lt;/blockquote&gt;

&lt;p&gt;
  Focusing on your target userbase is a complete opposite of a &quot;failure mode&quot;.
  It&#39;s what more projects should aim for. It&#39;s perfectly valid — and beneficial
  to both your project and the users you are targeting — to say &quot;hey, I&#39;m
  building this with this particular audience in mind and I won&#39;t be expanding
  it to meet your needs&quot;.
&lt;/p&gt;

&lt;p&gt;
  I&#39;m not opposed to seeking growth (although I am vehemently opposed to the
  capitalistic desire for always growing growth or growth at any expense).
  Seeing the world through the lenses of only growth being a good target is
  depressingly capitalist.
&lt;/p&gt;

&lt;p&gt;
  Since the original post he replied to was about open source projects, I&#39;m
  looking at this both from a personal/hobby project&#39;s and a commercial
  project&#39;s perspective.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://hamatti.org/posts/home-cooked-situated-software/&quot; class=&quot;notion-text-href&quot;&gt;Home-cooked, situational software&lt;/a&gt;
  is a great example of a category of software that thrives without growth. In
  that blog post, I quote Clay Shirky:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  The biggest difference this creates relative to classic web applications is
  that it becomes easy to build applications to be used by dozens of users, an
  absurd target population in current design practice. Making form-fit software
  for a small group of users has typically been the province of banks and
  research labs -- because of the costs involved, Web School applications have
  concentrated on getting large-scale audiences. And by privileging the value
  that comes with scale, Web School applications put other kinds of value,
  particularly social value, out of reach. - Clay Shirky /
  &lt;a href=&quot;https://gwern.net/doc/technology/2004-03-30-shirky-situatedsoftware.html&quot; class=&quot;notion-text-href&quot;&gt;https://gwern.net/doc/technology/2004-03-30-shirky-situatedsoftware.html&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  I have built so many projects where the user count is single digits. Often
  just me, sometimes me and a small community that benefits from it. I don&#39;t
  desire any more users because more users means more maintenance, more bug
  reports, more expectations and more responsibilities.
&lt;/p&gt;

&lt;p&gt;
  In a case of open source or hobby project, that usually doesn&#39;t translate to
  money and definitely not in any scale that would make it possible to spend
  less time at work to have more time for the hobby project.
&lt;/p&gt;

&lt;p&gt;
  In terms of commercial software, there are many use cases where building a
  service or a software that serves a small team of say 10 people is the best
  approach. Trying to morph it into something that can be opened to larger
  audiences usually just adds more overhead than it brings benefits.
&lt;/p&gt;

&lt;p&gt;
  If we focus on Drew&#39;s second comment about &quot;pre-supposing appeal to a certain
  group&quot;, I hear an argument about focus. Sure, if someone from outside the
  original target group finds your software, uses it and doesn&#39;t complain, you
  don&#39;t have to chase them away. But sometimes it is a good choice if you worry
  that growth will distract your focus or spread your workload too much.
&lt;/p&gt;

&lt;p&gt;
  Looking at so many software project these days, there seems to be a massive
  problem with loss of focus. At the massive scale — like Google or Meta —, it
  can probably work but for any smaller scale business definitely needs to focus
  on serving the niche audience they are building for instead of aiming to
  please everyone.
&lt;/p&gt;

&lt;p&gt;
  Too much growth, especially too early can become a death trap for new
  businesses. Every time you chase someone new, you&#39;re spending less time
  learning from your current customers and serving their needs
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>Chats and forums</title>
    <link href="https://hamatti.org/posts/chats-and-forums/" />
    <updated>2026-07-23T00:00:00Z</updated>
    <id>https://hamatti.org/posts/chats-and-forums/</id>
    <content type="html">
      
&lt;p&gt;
  This summer, I was invited to join a new community for people who write and
  was very happy to join. I was part of the “original group” if that makes sense
  in a steadily growing community. The group started as Signal group and for a
  while, it was lovely to be part of it.
&lt;/p&gt;

&lt;p&gt;
  Then we grew to around 40 people. All lovely people whose writing I had been
  following for years and who I loved chatting with. I was busy with other stuff
  for a few days and when I returned to Signal, I saw almost 200 unread messages
  spanning half a dozen interesting discussions.
&lt;/p&gt;

&lt;p&gt;
  That’s when it hit me. Not the amount of unread messages but the ephemerality
  of the discussion. Over the past few years, I have intentionally changed my
  habits. I have left (or significantly decreased usage of) social media
  platforms like X, Instagram and LinkedIn because I got annoyed at the
  algorithms pushing content and everything being “send and forget” type stuff.
&lt;/p&gt;

&lt;p&gt;
  I have instead focused more on reading and writing blogs, participating in
  forums and doing my social media in Mastodon. Like a frog in a slowly boiling
  pot, I hadn’t noticed the effect of the change until the Signal thing hit me.
&lt;/p&gt;

&lt;p&gt;
  In
  &lt;a href=&quot;https://hamatti.org/posts/build-the-forum-you-want-to-see-in-the-web/&quot; class=&quot;notion-text-href&quot;&gt;Build the forum you want to see in the web&lt;/a&gt;, I wrote about how instead of complaining, we should make these things
  happen and I haven’t been at my best in following my own advice, I’ll admit
  that.
&lt;/p&gt;

&lt;p&gt;
  There are a couple of specific things I think a forum can do way better than a
  single-threaded chat like Signal group and I wanted to explore and expand on
  those ideas more in this blog post.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Multiple different simultaneous discussions
&lt;/h2&gt;

&lt;p&gt;
  The first is that in a single-thread chat, it’s difficult to keep up with
  multiple discussions because every message is in the same feed. If two people
  were discussing thing A and then two different people start to discuss about
  B, it becomes difficult to see which messages are about which topic.
&lt;/p&gt;

&lt;p&gt;
  It sometimes makes me not reply to something that already passed because I
  feel now rude interrupting the on-going discussion.
&lt;/p&gt;

&lt;p&gt;
  Administrative discussions also happen in the same feed but they are often
  more time pressing and in a way more important for people to notice and
  discuss and take action on which can halt all the other discussion because you
  don’t want to push the current important, feed dominating messages out of
  view.
&lt;/p&gt;

&lt;p&gt;
  In our community, we have already started some longer term projects but in a
  single-thread discussion that requires so much more effort from people to
  drive them because every time there’s some new progress or desire to get
  people to participate, you need to rehash everything that has been decided,
  discussed or done in the past if you want everyone to have a good picture of
  the situation.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Discussions fade way too quickly
&lt;/h2&gt;

&lt;p&gt;
  The biggest thing I think we lose in a fast paced chat discussion is how short
  a lifespan of a topic or discussion becomes. Unless the topic is super hot in
  the group and maintains active discussion for a day, it is lost in the history
  within hours.
&lt;/p&gt;

&lt;p&gt;
  When I returned to my group with almost 200 unread messages, a good amount of
  discussions had started and then faded into the void. Sure, I could scroll
  back, find a message, reply to it and try to restart the discussion that
  happened while I was gone but it would be difficult for everyone to follow
  because the context and previous discussion is somewhere in the past, spread
  out and interwoven with all the other discussions.
&lt;/p&gt;

&lt;p&gt;
  What we lose is the build up on ideas. Imagine instead of a discussion on an
  interesting topic lasting for a couple of hours and containing everyone’s
  first thought, it would grow up over the years.
&lt;/p&gt;

&lt;p&gt;
  If the previous ideas are all in one place, easy to read at one’s own leisure
  and mulled over, there’s a larger likelihood that those ideas will bounce on
  each other and grow together into something more profound.
&lt;/p&gt;

&lt;p&gt;
  When someone then replies to a forum thread, even if it’s months old, other
  people can immediately catch up with all the previous discussion. I like that
  idea.
&lt;/p&gt;

&lt;p&gt;
  As I’ve been working more and more on my own notes, I’ve discovered a lot of
  new joy in the ability to think slowly, return to ideas and accumulate
  knowledge over longer periods of time rather than starting over from the
  scratch every time. That’s how I see forums compared to chats.
&lt;/p&gt;

&lt;p&gt;
  One reason why this matters so much is that short lifespan of a discussion
  means that to participate in it, I need to dish out my first thoughts on it.
  Most of the time, when someone brings up a topic, that&#39;s when a thought
  process starts in my head. Often the first good ideas form after I&#39;ve slept on
  it. The best ideas might start to form after a couple of days of letting it
  marinate in my subconciousness and through the early discussions.
&lt;/p&gt;
&lt;p&gt;
  If the entire discussion fades out within hours, we never get to those deeper,
  more formed thoughts. Over time, every discussion becames a collection of the
  most surface level ideas before we move to the next one.
&lt;/p&gt;
&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  New people joining old discussions
&lt;/h2&gt;

&lt;p&gt;
  To build on the previous idea, this becomes even bigger deal when new people
  join the community. Whether they can see the old chat history or not, it’s
  unlikely that people would scan through thousands of messages in unorganised
  never-ending feed to find and participate in discussions.
&lt;/p&gt;

&lt;p&gt;
  With a forum style platform, they could immediately skim through the threads
  by their titles and see which topics they have something to contribute on
  right away and have the rest in their mind to help new ideas form and knowing
  there’s a place for them in the platform.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  More time, more thought, more meaningful discussion
&lt;/h2&gt;

&lt;p&gt;
  I wish I had discovered these thoughts way earlier in life but I guess better
  late than never. I am glad that I have finally found ways that help me think
  more deeply and process thoughts and new knowledge better by giving it more
  time, more thought and participating in more discussions that are not just
  passing small talk that’s forgotten the moment silence takes its space in
  between thoughts.
&lt;/p&gt;

&lt;p&gt;
  I have now done it a lot on my own: through reading, working on my notes and
  writing. Going forward, I want to take even more action to foster that in the
  communities I’m part of.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>On blogging, Blaugust and challenging yourself</title>
    <link href="https://hamatti.org/posts/on-blogging-blaugust-and-challenging-yourself/" />
    <updated>2026-07-22T00:00:00Z</updated>
    <id>https://hamatti.org/posts/on-blogging-blaugust-and-challenging-yourself/</id>
    <content type="html">
      &lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;on blogging&lt;/h2&gt;

&lt;p&gt;
  Why do we blog? There are a ton of reasons and everyone who blogs have their
  own motivations and reasons. You could ask every blogger you follow and
  probably get as many answers as you ask people.
&lt;/p&gt;

&lt;p&gt;
  I write this blog because I have ideas rummaging in my head and I need to
  write them down to process them. Like
  &lt;a href=&quot;https://iamfran.com/notes/writing-is-thinking/&quot; class=&quot;notion-text-href&quot;&gt;Fran eloquently puts it&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  Putting your words on paper, even if digitally, forces you to deal with the
  core of the topic at hand.
&lt;/blockquote&gt;

&lt;p&gt;
  Writing ideas down in tangible form helps you discover gaps and structure
  those ideas in a way that helps me think them further and to have discussions
  about them with other people.
&lt;/p&gt;

&lt;p&gt;
  None of that requires me to &lt;b class=&quot;notion-text-bold&quot;&gt;publish&lt;/b&gt; those
  writings though, so it only covers half of the picture. My motivation for
  publishing is that if I already worked through my ideas and wrote them down in
  a (hopefully coherent) form, why not publish. I enjoy sharing my ideas so they
  can be read, challenged and discussed by other people. That’s who I learn
  more.
&lt;/p&gt;

&lt;p&gt;
  Sometimes I write and share to spread joy. Just this Monday, I wrote about
  &lt;a href=&quot;https://hamatti.org/posts/a-lovely-dialogue-about-taking-notes-from-see-how-they-run/&quot; class=&quot;notion-text-href&quot;&gt;a scene from a movie that I enjoyed&lt;/a&gt;. Maybe someone else will enjoy that, watch the movie and find joy in it.
  Yay.
&lt;/p&gt;

&lt;p&gt;
  A lot of my technical blogging has to do with documenting what I’ve tried and
  learned. I write them down to my notes so I can discover them later when I
  inevitably run into the same or similar issue again. I share them because I’ve
  gotten a lot of help and ideas from other blogs in the internet and want to
  contribute to that pool of resources.
&lt;/p&gt;

&lt;p&gt;
  At times of my career, I’ve also written about a lot of technical stuff to
  build a body of work to increase my chances of finding interesting work.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;on Blaugust&lt;/h2&gt;

&lt;p&gt;
  Every August — for over a decade already —, a group of bloggers gather
  together in the blogosphere to celebrate blogging, to learn from each other,
  to encourage each other and to challenge themselves. That community and the
  month-long festival of blogging is called
  &lt;a href=&quot;https://notes.hamatti.org/writing/events/blaugust&quot; class=&quot;notion-text-href&quot;&gt;Blaugust&lt;/a&gt;
  and I’ve been participating since 2023.
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  For anyone arriving here for the very first time Blaugust is a month-long
  event that takes place each August which focuses on blogging primarily and has
  started to include other forms of serialized content over the last several
  years. The goal is to stoke the fires of creativity and allow bloggers and
  other content creators to mingle in a shared community while pushing each
  other to post more regularly. Above all the goal of Blaugust has always been
  to prove to folks that they can in fact sit down every day and create
  something fresh and then share it with the world. /
  &lt;i class=&quot;notion-text-italic&quot;&gt;Belghast, &lt;/i&gt;&lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://aggronaut.com/2024/07/12/blaugust-2024-is-coming/&quot; class=&quot;notion-text-href&quot;&gt;https://aggronaut.com/2024/07/12/blaugust-2024-is-coming/&lt;/a&gt;&lt;/i&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Last year, over 150 people participated in the challenge. (And some people say
  blogging is dead.)
&lt;/p&gt;

&lt;p&gt;
  One of the original goals of Blaugust was to publish 31 blog posts in 31 days
  of August. Over the years, different alternative goals have been added to make
  it more serving for all sorts of bloggers. 31 in 31 is kinda hardcore but the
  positive effects appear on much lower amount of posts as well and the main
  goal is to encourage people to write.
&lt;/p&gt;

&lt;p&gt;If you want to be one of those people this year,&lt;/p&gt;
&lt;ul class=&quot;notion-bulleted_list&quot;&gt;
  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    Check out the
    &lt;a href=&quot;https://nerdgirlthoughts.game.blog/2026/07/15/blaugust-2026-is-coming/&quot; class=&quot;notion-text-href&quot;&gt;info post&lt;/a&gt;
    by Nerd Girl Krikket
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;b class=&quot;notion-text-bold&quot;&gt;&lt;a href=&quot;https://forms.gle/SfUWUMpFQxBFbF9N9&quot; class=&quot;notion-text-href&quot;&gt;sign up&lt;/a&gt;&lt;/b&gt;
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    optionally join our lovely
    &lt;a href=&quot;https://discord.gg/EVvMnEGvgV&quot; class=&quot;notion-text-href&quot;&gt;Discord community&lt;/a&gt;
    where you can share your ideas, your posts, ask for help or inspiration and
    get mental support for writing.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The other challenges or goals are&lt;/p&gt;
&lt;ul class=&quot;notion-bulleted_list&quot;&gt;
  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;b class=&quot;notion-text-bold&quot;&gt;Newbie Blogger Award&lt;/b&gt; – You did it! You
    joined Blaugust for the very first time and we are extremely happy to
    welcome you into this raucous community. As a result, we are going to
    recognize your efforts just for signing up.
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;b class=&quot;notion-text-bold&quot;&gt;Bronze Award &lt;/b&gt;– You made at least 5 posts
    during the month of August 2026.
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;b class=&quot;notion-text-bold&quot;&gt;Silver Award&lt;/b&gt; – You made at least 15 posts
    during the month of August 2026.
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;b class=&quot;notion-text-bold&quot;&gt;Gold Award&lt;/b&gt; – You made at least 25 posts
    during the month of August 2026.
  &lt;/li&gt;

  &lt;li class=&quot;notion-bulleted_list_item notion-color-default&quot;&gt;
    &lt;b class=&quot;notion-text-bold&quot;&gt;Rainbow Diamond Award&lt;/b&gt; – You beat the
    original challenge and posted 31 times or more during the month of August
    2026.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;on challenging yourself&lt;/h2&gt;

&lt;p&gt;
  Let’s be clear: you don’t need to participate in any kind of online writing
  challenge or event to enjoy blogging or to write daily/weekly/monthly or to
  write thoughtful replies to other people’s posts.
&lt;/p&gt;

&lt;p&gt;
  I find these events wonderful for the community that gathers around them. I’ve
  met so many wonderful people from around the world through things like
  Blaugust,
  &lt;a href=&quot;https://notes.hamatti.org/writing/events/indieweb-carnival&quot; class=&quot;notion-text-href&quot;&gt;IndieWeb Carnival&lt;/a&gt;,
  &lt;a href=&quot;https://notes.hamatti.org/writing/events/junited&quot; class=&quot;notion-text-href&quot;&gt;Junited&lt;/a&gt;
  or
  &lt;a href=&quot;https://notes.hamatti.org/writing/events/nanowrimo&quot; class=&quot;notion-text-href&quot;&gt;NaNoWriMo&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  The social accountability in these events helps me a lot. Publishing daily on
  the blog is tough. I’m proud I’ve managed to succeed in that already three
  Blaugusts in the running, I can’t imagine right now doing that for a longer
  period than one month a year. (Well, kinda twice because I do
  &lt;a href=&quot;https://notes.hamatti.org/technology/advent-of-code/2025/advent-of-code-2025-landing-page&quot; class=&quot;notion-text-href&quot;&gt;Advent of Code in December&lt;/a&gt;)
&lt;/p&gt;

&lt;p&gt;
  There are no real stakes: if I don’t manage to get my 31 posts done, nothing
  happens. I’m not beholden to any contract or even a promise to finish and
  succeed in my goal. Even then, making that commitment to join and aim for a
  goal gives me a lot of will power to achieve it. I find that kind of
  stubbornness one of my biggest strengths in getting stuff done in general.
&lt;/p&gt;

&lt;p&gt;
  Here’s my hot take on all of these, based on discussions I often have with
  people when I share the month’s Carnival theme or Blaugust or something else:
  &lt;b class=&quot;notion-text-bold&quot;&gt;you don’t have to follow any rules&lt;/b&gt;. Of course,
  that might mean that you’re not eligible to be part of the challenge or the
  event but none of these events are the point in themselves.
  &lt;b class=&quot;notion-text-bold&quot;&gt;Writing is&lt;/b&gt;.
&lt;/p&gt;

&lt;p&gt;
  If an event like this gives you ideas and encouragement to write more, go
  ahead. We are all publishing in our own blogs and we are the ultimate arbiters
  of what goes into our blogs. Don’t let the “can I do X?” questions in your
  head limit you from exploring ideas and topics in your blog just because they
  might not exactly match the rules of someone else’s challenge.
&lt;/p&gt;

&lt;p&gt;
  For example, with IndieWeb Carnival, I always use the theme selected by the
  host and their introduction to it as a starting point but I give myself pretty
  much unlimited creative freedom on how much I follow it. If at the time of
  publishing that blog post, I feel I can justify its participation in that
  theme, I send it to the host. Sometimes I feel I’ve travelled too far from the
  original path for it to make sense but the Carnival has done its positive
  thing already. I then leave it up to the host to decide if they consider it an
  acceptable entry.
&lt;/p&gt;

&lt;p&gt;
  Whether you have a blog already or not, I recommend joining Blaugust this
  year. In the community, we often repeat the mantra of “the only way to lose is
  not to participate”. Every post you make is a win, even if you only publish
  one in August.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>A lovely dialogue about taking notes from See How They Run</title>
    <link href="https://hamatti.org/posts/a-lovely-dialogue-about-taking-notes-from-see-how-they-run/" />
    <updated>2026-07-20T00:00:00Z</updated>
    <id>https://hamatti.org/posts/a-lovely-dialogue-about-taking-notes-from-see-how-they-run/</id>
    <content type="html">
      &lt;p&gt;
  This past weekend, I watched Saoirse Ronan’s (sure, there were some other
  actors too)
  &lt;a href=&quot;https://www.imdb.com/title/tt13640696/&quot; class=&quot;notion-text-href&quot;&gt;See How They Run&lt;/a&gt;
  and there was one scene that specifically made me giggle a bit as a notes
  geek.
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/a-lovely-dialogue-about-taking-notes-from-see-how-they-run/1.png.webp&quot; alt=&quot;A man and a woman are sitting in a car, filmed from the front. The woman is writing notes into a red notebook and the man sitting next to her is looking at the notebook. &quot; /&gt;
&lt;p&gt;
  In the scene, Inspector Stoppard (on left, played by Sam Rockwell) and
  Constable Stalker (played by Saoirse Ronan) are sitting in a car and Stalker,
  a young constable is making notes.
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &lt;strong&gt;Stoppard:&lt;/strong&gt; Tell me, do you write everything down in that little notebook?&lt;br /&gt;
&lt;strong&gt;Stalker:&lt;/strong&gt; Only if it&#39;s important, sir.&lt;br /&gt;
&lt;strong&gt;Stoppard:&lt;/strong&gt; How do you know if it&#39;s important?&lt;br /&gt;
&lt;strong&gt;Stalker:&lt;/strong&gt; Oh well - - . I just sort of put everything in as we go and then down the line when we know what&#39;s important, we know it&#39;s already in the notebook.&lt;br /&gt;
&lt;strong&gt;Stoppard:&lt;/strong&gt; So you do write everything down?&lt;br /&gt;
&lt;strong&gt;Stalker:&lt;/strong&gt; Yes, everything.&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  I loved this scene so much. It talked to the notes geek inside me so much. I
  often keep thinking about my note-taking practices and how I decide what to
  note down and how.
&lt;/p&gt;

&lt;p&gt;
  The movie is a fun whodunnit murder mystery with great cast. I highly
  recommend checking it out.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>My first Finncon — Turku, 2026</title>
    <link href="https://hamatti.org/posts/my-first-finncon-turku-2026/" />
    <updated>2026-07-15T00:00:00Z</updated>
    <id>https://hamatti.org/posts/my-first-finncon-turku-2026/</id>
    <content type="html">
      
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/1.png.webp&quot; alt=&quot;Finncon 2026. Turku Åbo 10.—12.7.2026 &quot; /&gt;
&lt;p&gt;
  Last weekend I attended my first
  &lt;a href=&quot;https://2026.finncon.org/&quot; class=&quot;notion-text-href&quot;&gt;Finncon&lt;/a&gt;. I
  haven’t been part of the fancon scene but I’ve been hanging around people who
  have enough to know that con reports are an important part of the culture.
&lt;/p&gt;

&lt;p&gt;
  I have only read one though:
  &lt;a href=&quot;https://masto.ai/@tero&quot; class=&quot;notion-text-href&quot;&gt;Tero’s&lt;/a&gt; report
  from 2005 Swecon in Göteborg that he re-published in his Egopuu zine’s
  Jyväskylä 2024 edition. It’s an event I’ve heard so many stories from even
  with my limited exposure to this world.
&lt;/p&gt;

&lt;p&gt;
  Anyway, here’s my story of my first con: Finncon 2026 in my hometown of Turku.
&lt;/p&gt;

&lt;hr class=&quot;notion-divider&quot; /&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;How did I get here?&lt;/h2&gt;

&lt;p&gt;
  We need to back up a couple of months. It’s May 7th. The day before was my
  last day at my then job which had unfortunately turned into quite a miserable
  experience that was weighing on my mental wellbeing. On this day however, all
  that misery was distant history: I was teeming with an abundance of energy and
  wanted to put it to a good use.
&lt;/p&gt;

&lt;p&gt;
  I had invited aforementioned Tero for an afterwork to catch up with my news
  and because I knew that having a chat with him over drinks always leads to
  something new happening. He’s great at sneakily planting seeds of ideas into
  my head. He’s been part of this scene for longer than I’ve been alive.
&lt;/p&gt;

&lt;p&gt;
  He was the one who initially encouraged me to start writing a zine and we had
  discussed zines over time many times. In January, trying desperately to find
  something to do that would bring joy to my life, I had
  &lt;a href=&quot;https://hamatti.org/posts/thoughts-on-making-zines-after-7-months/&quot; class=&quot;notion-text-href&quot;&gt;started working on my first zine&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;We talk about zines and Tero asks:&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  What if we’d go to Finncon to have a discussion about zines?
&lt;/blockquote&gt;

&lt;p&gt;Like a good lawyer, he knows to ask questions he knows the answer to.&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;Absolutely, &lt;/b&gt;I’m in.
&lt;/blockquote&gt;

&lt;p&gt;
  I’m always up to discussing my hobbies and passions whenever an opportunity
  arrives so it was an easy yes.
&lt;/p&gt;

&lt;p&gt;
  Tero got
  &lt;a href=&quot;https://bsky.app/profile/jukkahoo.bsky.social&quot; class=&quot;notion-text-href&quot;&gt;Jukka&lt;/a&gt;, another veteran who has been making zines way before I was born involved
  and we started scheming. Finally,
  &lt;a href=&quot;http://ontto-panula.com/&quot; class=&quot;notion-text-href&quot;&gt;H-P&lt;/a&gt; joined us
  and we had a four person panel discussion booked for Sunday morning of my
  first Finncon experience.
&lt;/p&gt;

&lt;p&gt;
  While I haven’t found my way into the fancon scene before, I am a life-long
  scifi nerd who also had a particular fantasy era in my childhood and teenage
  years. Doctor Who, Hitchhiker’s Guide to the Galaxy, Star (Wars|Trek|Gate),
  Babylon 5, Farscape and countless other scifi movies, series and books have
  been part of my life for as long as I remember.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Finncon 2026 in Turku, Finland
&lt;/h2&gt;

&lt;p&gt;
  For my first experience, Finncon unfortunately was cut a bit short as it
  happened to land on a weekend with a family celebration I wouldn’t miss on
  Saturday.
&lt;/p&gt;
&lt;h3&gt;Friday, July 10th&lt;/h3&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/2.png.webp&quot; alt=&quot;A street end leading to a set of stairs at a university campus. It’s a sunny summer day and a couple of people are climbing the stairs. &quot; /&gt;
&lt;p&gt;
  The weekend started with an old nemesis of mine:
  &lt;b class=&quot;notion-text-bold&quot;&gt;the Stairs of Knowledge&lt;/b&gt; (&lt;i class=&quot;notion-text-italic&quot;&gt;Tiedon portaat&lt;/i&gt;) that lead to the university campus. I used to study in this university
  between 2010 and 2013-ish and have taught a few lectures here as well so I’m
  intimately familiar with the dread of climbing these stairs.
&lt;/p&gt;

&lt;p&gt;
  They are especially nasty on a rainy, cold November morning when heading to an
  8 o’clock morning math lecture after a student party the previous night. They
  weren’t exactly forgiving on a summer afternoon in heat either, especially
  given that my physical form has — let’s say — specialised in other things than
  climbing stairs.
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/3.png.webp&quot; alt=&quot;Finncon 2026 badge for Juha-Matti Santala &quot; /&gt;
&lt;p&gt;
  While I’ve been to dozens of tech conferences around the world, I didn’t quite
  know what to expect from Finncon. I arrived at the main building to pick up my
  speaker badge and I was surprised by the amount of booths with artists selling
  their crafts.
&lt;/p&gt;

&lt;p&gt;
  Later, I made my way to the other building and there were floor after floor,
  corridor after corridor of these booths. Stickers, pins, paintings, books,
  jewelry, and so much more. We’ll talk about these in more in a bit.
&lt;/p&gt;

&lt;p&gt;The Friday afternoon program was short but excellent.&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/4.png.webp&quot; alt=&quot;A panel discussion with three people in a university lecture hall &quot; /&gt;
&lt;p&gt;
  The first session I joined was
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/kirjoittajan-oppaat-scifiin-ja-fantasiaan/&quot; class=&quot;notion-text-href&quot;&gt;Kirjoittajan oppaat scifiin ja fantasiaan (Writer’s guides to scifi and
      fantasy)&lt;/a&gt;&lt;/i&gt;
  with Saara Henriksson, Anne Leinonen and Jani Saxell. I’m an aspiring writer
  of scifi in that I think about one day wanting to write some stories but I
  haven’t actually written fiction since high school when I took part in
  NaNoWriMo.
&lt;/p&gt;

&lt;p&gt;
  I enjoyed the panel discussion (a side note: coming from a tech conference
  world where 95% of the talks are individual presentations and very rarely
  panels, it was interesting to see how Finncon was mainly panel discussions)
  and picked up a few good new ideas.
&lt;/p&gt;

&lt;p&gt;
  Saara showed a couple of interesting books that circulated around in the
  audience. I made notes of them and later turned the initial notes into a
  &lt;a href=&quot;https://notes.hamatti.org/writing/writing-guides&quot; class=&quot;notion-text-href&quot;&gt;published note combined with the other writing guides I have either read or
    heard about&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  The second thing on Friday I listened to was a panel discussion
  &lt;a href=&quot;https://2026.finncon.org/timetable/event/on-writing/&quot; class=&quot;notion-text-href&quot;&gt;On writing&lt;/a&gt;
  with the guests of honour
  &lt;a href=&quot;https://adriantchaikovsky.com/&quot; class=&quot;notion-text-href&quot;&gt;Adrian Tchaikovsky&lt;/a&gt;
  and
  &lt;a href=&quot;https://reettavuokkosyrjanen.com/&quot; class=&quot;notion-text-href&quot;&gt;Reetta Vuokko-Syrjänen&lt;/a&gt;
  with
  &lt;a href=&quot;https://www.cheryl-morgan.com/&quot; class=&quot;notion-text-href&quot;&gt;Cheryl Morgan&lt;/a&gt;
  (who was already a familiar name to me from the only con report I had ever
  read).
&lt;/p&gt;

&lt;p&gt;
  While I admit I haven’t (yet) read any of the works of either one, it was
  fascinating to hear about their processes of writing and especially how
  Adrian’s strong world building process aids him in writing books so fast.
&lt;/p&gt;

&lt;p&gt;
  Another interesting discussion was about how they both have written about the
  connection of mind and body in their stories but from very different
  perspectives.
&lt;/p&gt;

&lt;p&gt;
  During their discussion about which age groups they are writing for, I loved
  how Adrian mentioned
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  My audience is “people who read my books”
&lt;/blockquote&gt;

&lt;p&gt;
  It resonates a lot with my approach to this blog. Instead of doing some sort
  of market and SEO trend analysis on what people want to read, writing what I
  have to say and the readership forming from people who want to read that is
  liberating.
&lt;/p&gt;

&lt;p&gt;His audience is of course quite a bit larger than mine.&lt;/p&gt;
&lt;h3&gt;An interlude on writing and publishing a zine&lt;/h3&gt;
&lt;p&gt;
  Already in early May when we discussed the upcoming zine panel, I had decided
  to make a Finncon special edition of my
  &lt;a href=&quot;https://zine.hamatti.org/&quot; class=&quot;notion-text-href&quot;&gt;Roll the Zine&lt;/a&gt;
  zine for the event and focus on scifi games to be thematically appropriate.
&lt;/p&gt;

&lt;p&gt;
  I made plans, I chose games, I wrote a bit but I hit a really hard brick wall.
  It was a combination of a debilitating stress over the well-versed fandom who
  visits Finncons and the dread of a deadline for a hobby I chose to be an exact
  opposite of that.
&lt;/p&gt;

&lt;p&gt;
  Between the talks and an evening party on Friday, I went to have dinner,
  determined to finish writing the zine before the library would close. I wrote
  the last couple of pages, made the layout consistent, ran my scripts and
  behold: I had a finished digital version of
  &lt;a href=&quot;https://zine.hamatti.org/issues/5/&quot; class=&quot;notion-text-href&quot;&gt;Roll the Zine #5 - Finncon Special&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  I rushed into the library and made a run of 5 printed issues and
  &lt;a href=&quot;https://mastodontti.fi/@hamatti/116896451303521976&quot; class=&quot;notion-text-href&quot;&gt;tooted&lt;/a&gt;
  (translated from Finnish):
&lt;/p&gt;
&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/5.png.webp&quot; alt=&quot;Five copies of the same zine fanned out on a table. The zine is Roll the Zine&#39;s July 2026 issue, a Finncon special: To boldly play where no one has played before. &quot; /&gt;
  &lt;p&gt;My credibility to speak about zines in the zine panel discussion is restored.
  Roll the Zine’s Finncon special is fresh out of library’s printers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  I was so happy to get it out. The bit about “credibility” was written in jest
  but it was truly important for me to have this zine come out at during the
  event and especially before the panel discussion.
&lt;/p&gt;

&lt;p&gt;
  I ended up saving one copy for myself, gave one to an interested audience
  member, one to the board game table at the con and snuck the others to the
  magazine shelf at the local pub.
  &lt;a href=&quot;https://zine.hamatti.org/issues/5/&quot; class=&quot;notion-text-href&quot;&gt;Digital copies are available&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;Back to Friday evening’s scheduled programming&lt;/h3&gt;
&lt;p&gt;
  I’ve heard so many stories of how fancon people are great at partying. On
  Friday evening, I joined a book publishing party at a local pub. As a first
  time visitor, an introvert and someone who didn’t know a lot of people at the
  event, I felt quite socially shy (throughout the entire event actually) so I
  listened to book intros, bought a copy of
  &lt;a href=&quot;https://notes.hamatti.org/sources/books/matkaopas-mahdolliseen&quot; class=&quot;notion-text-href&quot;&gt;Matkaopas mahdolliseen&lt;/a&gt;
  writing guide and drank a few drinks.
&lt;/p&gt;

&lt;p&gt;
  I did end up having a couple of discussions with the few friends I did know
  there but I ended up going home earlier than I had planned.
&lt;/p&gt;
&lt;h3&gt;Saturday, 11th of July&lt;/h3&gt;
&lt;p&gt;
  As I mentioned earlier, my Saturday was mostly spent on family celebration so
  I missed the main program.
&lt;/p&gt;

&lt;p&gt;
  I joined the Saturday evening party for a while, had a couple of good
  discussions but felt even more socially shy and being a smart boy, went to bed
  early to maximise the odds of waking up early enough to not miss the Sunday
  morning panel.
&lt;/p&gt;
&lt;h3&gt;Sunday, 12th of July&lt;/h3&gt;
&lt;h4&gt;11.00 Mustetta ja niittejä zine discussion&lt;/h4&gt;
&lt;p&gt;
  Our panel discussion
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/mustetta-ja-niitteja/&quot; class=&quot;notion-text-href&quot;&gt;Mustetta ja niittejä&lt;/a&gt;&lt;/i&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/mustetta-ja-niitteja/&quot; class=&quot;notion-text-href&quot;&gt;
    (Ink and staples)&lt;/a&gt;
  was the opening act of Sunday. We had a nice small audience and spent 45
  minutes talking about the history of zines, how each of us got involved in the
  hobby, why we do it and we shared recommendations for where to find zines.
&lt;/p&gt;

&lt;p&gt;
  I wrote about
  &lt;a href=&quot;https://hamatti.org/posts/thoughts-on-making-zines-after-7-months/&quot; class=&quot;notion-text-href&quot;&gt;the panel and related ideas on Monday’s blog post&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  It was a lot of fun and it was great to be part of the program in a fancon
  with such a long history and wonderful community. Big thanks to my fellow
  panelists and the participating audience.
&lt;/p&gt;
&lt;h4&gt;Other Sunday stuff&lt;/h4&gt;
&lt;p&gt;
  A couple of other great discussions I participated were a discussion about the
  beginnings of fandom and another about the sea.
&lt;/p&gt;

&lt;p&gt;
  In
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/suomi-fandomin-alkuja/&quot; class=&quot;notion-text-href&quot;&gt;Suomi-fandomin alkuja&lt;/a&gt;&lt;/i&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/suomi-fandomin-alkuja/&quot; class=&quot;notion-text-href&quot;&gt;
    (Beginnings of Finnish fandom)&lt;/a&gt;, a group of old school fandom people talked about the history, sharing
  stories and learnings from over 40 years of Finnish fandom. It was so cool to
  see so many people who had been active in the fandom from 1970s being present
  in the audience and participating in the discussion.
&lt;/p&gt;

&lt;p&gt;
  As a community builder myself, this discussion gave me so much to think about:
  how to build long-lasting communities, how to bring people together and give
  them opportunities to participate through contributing and how to document the
  early days before it’s too late so later generations of the community get to
  enjoy those stories as well.
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/6.png.webp&quot; alt=&quot;A panel discussion of four people in a university hall. &quot; /&gt;
&lt;p&gt;
  In
  &lt;i class=&quot;notion-text-italic&quot;&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/meri-on-maan-avaruutta/&quot; class=&quot;notion-text-href&quot;&gt;Meri on Maan avaruutta&lt;/a&gt;&lt;/i&gt;&lt;a href=&quot;https://2026.finncon.org/timetable/event/meri-on-maan-avaruutta/&quot; class=&quot;notion-text-href&quot;&gt;
    (Sea is the space of Earth)&lt;/a&gt;, I listened to a nice discussion of how authors have explored different seas
  and oceans in their stories, drawing parallels between sea and space: the
  massive, never-ending uknown with its own life-forms and dangers.
&lt;/p&gt;

&lt;p&gt;I spent most of the other part of the day roaming around in the venue.&lt;/p&gt;
&lt;h3&gt;For a free event, it was surprisingly expensive&lt;/h3&gt;
&lt;p&gt;
  Finncon is a free event to participate. It’s organised by volunteers and I
  love the event and community for it.
&lt;/p&gt;

&lt;p&gt;
  What I and my wallet weren’t prepared for was how much temptation there was
  for a geek like me.
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/7.png.webp&quot; alt=&quot;A book called Matkaopas mahdolliseen with a colourful collage of scifi themed illustrations and a magazine Tähtivaeltaja with Obi-Wan Kenobi from Phantom Menace on the cover. &quot; /&gt;
&lt;p&gt;
  I picked up a copy of Matkaopas mahdolliseen from the book publishing party to
  learn from and a random copy of
  &lt;a href=&quot;https://tahtivaeltajablogi.com/&quot; class=&quot;notion-text-href&quot;&gt;Tähtivaeltaja&lt;/a&gt;
  from 1999 for zine inspiration.
&lt;/p&gt;

&lt;p&gt;
  I’m a couple of essays into the book and it’s been wonderful. So many thought
  provoking ideas and insights and it’s a gorgeous book too. The magazine is
  such a fun time capsule into the summer just before the theater releases of
  Star Wars Ep 1: Phantom Menace and Matrix. That was quite a summer for scifi
  movies.
&lt;/p&gt;

&lt;p&gt;
  Looking back, knowing how big of an impact both these movies have had on the
  genre and how much they are still discussed 27 years later, it’s fun to see
  what the discussion was at the time. Reading through commentary and reviews, I
  feel the expectations were way lower than what it ended up becoming.
&lt;/p&gt;

&lt;p&gt;I also got some stickers.&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/8.png.webp&quot; alt=&quot;A sticker of Pikachu holding a trans flag and a scarred/stitched end of tail with a heart shape. &quot; /&gt;
&lt;p&gt;
  This chonky trans Pikachu was the first thing that caught my attention and I
  bought a couple of copies of it to give out to friends too.
&lt;/p&gt;

&lt;p&gt;On Sunday, I bought these:&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/my-first-finncon-turku-2026/9.png.webp&quot; alt=&quot;Three stickers: a happy fox with text In my defense, I used to be so much worse; a distressed rabbit with text I say no worries but deep down I’m very worried; and the same rabbit from previous but this time sleeping under a blanket with text I did my best. It’s time for a nap. &quot; /&gt;
&lt;p&gt;as they were too spot on and cute to skip.&lt;/p&gt;

&lt;p&gt;
  I also picked up random collection of
  &lt;i class=&quot;notion-text-italic&quot;&gt;other stuff&lt;/i&gt;, mainly for inspiration.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Finncon was a lot of fun&lt;/h2&gt;

&lt;p&gt;
  I had such a wonderful weekend. Even with missing the Saturday program and
  feeling quite shy to talk to people, it was definitely a good weekend. Big
  thanks to all Finncon organisers, volunteers, presenters, panelists, artist
  and participants for making it such.
&lt;/p&gt;

&lt;p&gt;
  Who knows, maybe next year I’ll return one year more experienced and and with
  a few new friends from this year.
&lt;/p&gt;


    </content>
  </entry>
   
  
  <entry>
    <title>Thoughts on making zines after 7 months</title>
    <link href="https://hamatti.org/posts/thoughts-on-making-zines-after-7-months/" />
    <updated>2026-07-13T00:00:00Z</updated>
    <id>https://hamatti.org/posts/thoughts-on-making-zines-after-7-months/</id>
    <content type="html">
      
&lt;p&gt;
  Last weekend, I took part in a panel discussion about making zines with
  &lt;a href=&quot;https://masto.ai/@tero&quot; class=&quot;notion-text-href&quot;&gt;Tero&lt;/a&gt;,
  &lt;a href=&quot;http://ontto-panula.com/&quot; class=&quot;notion-text-href&quot;&gt;H-P&lt;/a&gt; and
  &lt;a href=&quot;https://bsky.app/profile/jukkahoo.bsky.social&quot; class=&quot;notion-text-href&quot;&gt;Jukka&lt;/a&gt;
  at this year’s
  &lt;a href=&quot;https://hamatti.org/38d0733fbc61802085b0cdfa77d3b56e&quot; class=&quot;notion-text-href&quot;&gt;Finncon&lt;/a&gt;. We had a wonderful 45 minute discussion: many good things were said but a
  lot remained unsaid due to limited time so I wanted to share my thoughts on
  zines, especially from the perspective of a new zine maker.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;What’s a zine?&lt;/h2&gt;

&lt;p&gt;
  When I tell people I make zines, the first question always is: what’s a zine?
  Zines, short for &lt;i class=&quot;notion-text-italic&quot;&gt;fanzine&lt;/i&gt; and parallel to
  &lt;i class=&quot;notion-text-italic&quot;&gt;magazine&lt;/i&gt; are a grassroots media format that
  started in the early 1900s from American political activism and spread
  especially in the science fiction fandom from 1930s onwards and later found
  popularity also in punk scene.
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  American zines trace their origins to the amateur press movement of the early
  20th century, when amateur printers purchased their own presses in order to
  produce small works concerning a specific topic or interest. Components of the
  amateur press movement can be seen in an often overlooked precursor to zines,
  the “little magazines” of the Harlem Renaissance. While not unique to the
  Harlem Renaissance, during the 1920s, individuals or small groups of Black
  artists and writers used the little magazine (a short, small distribution
  magazine) to undermine the established literary system. These self-published
  works, often local in scope, featured lesser-known voices of the Renaissance
  along with those of greater prominence. -
  &lt;a href=&quot;https://guides.lib.virginia.edu/zine/history&quot; class=&quot;notion-text-href&quot;&gt;Zine History &amp; Culture&lt;/a&gt;, University of Virginia’s Library
&lt;/blockquote&gt;

&lt;p&gt;
  Zines are prominent in counter culture as they enable people who don’t have
  access to spread their ideas via publishers or traditional media. In the age
  of the Internet, that dynamic has changed a lot and
  &lt;a href=&quot;https://indieweb.org/&quot; class=&quot;notion-text-href&quot;&gt;indie web&lt;/a&gt;
  movement shares a lot of similar ideas with zine culture.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;My zine inspiration&lt;/h2&gt;

&lt;p&gt;
  I’ve been following a few zines and zine creators for a few years.
  &lt;a href=&quot;https://jvns.ca/&quot; class=&quot;notion-text-href&quot;&gt;Julia Evans&lt;/a&gt;’
  &lt;a href=&quot;https://wizardzines.com/&quot; class=&quot;notion-text-href&quot;&gt;Wizard Zines&lt;/a&gt;
  are fantastic programming zines that have been a huge inspiration for me to
  start making my own.
  &lt;a href=&quot;https://www.youtube.com/@JPCoovert&quot; class=&quot;notion-text-href&quot;&gt;JP Coovert’s&lt;/a&gt;
  tabletop roleplaying zines and his enthusiasm to share and encourage everyone
  to make their own zines has been another big source of early inspiration.
&lt;/p&gt;

&lt;p&gt;
  In Youtube and Instagram, there’s a ton of visually stunning zines being
  shared by incredible illustrators. That’s been a double-sided sword for me.
  For a long time, they’ve been a bit of a barrier for me: I’m not an
  illustrator and in the beginning, I felt that I should also be able to make
  those beautifully illustrated zines to make it worth the while.
&lt;/p&gt;

&lt;p&gt;
  That couldn’t be further from the truth though. If you’re in the same boat I
  was in, this is me telling you:
  &lt;b class=&quot;notion-text-bold&quot;&gt;make a zine.&lt;/b&gt; Stop worrying about how it looks
  and just go and make one. And read a ton of other zines to see that there’s so
  much variety out there (see recommendations at the end).
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  My first zine: Roll the Zine
&lt;/h2&gt;

&lt;p&gt;
  Somewhere around the Yule holidays (likely after a few drinks with
  aforementioned Tero), I decided to start practicing. My “ultimate goal” was to
  make those software development zines but I wanted something less stressful
  with less expectations to start with.
&lt;/p&gt;

&lt;p&gt;
  I had recently started writing about games with more focus to figure out how
  to write interesting pieces about them (for example
  &lt;a href=&quot;https://notes.hamatti.org/gaming/video-games/helmet-gaming-challenge-2026&quot; class=&quot;notion-text-href&quot;&gt;this year for Helmet gaming challenge&lt;/a&gt;) and I love board games so picking up board and card games as my zine theme
  emerged from there.
&lt;/p&gt;

&lt;p&gt;
  When I was working on
  &lt;a href=&quot;https://zine.hamatti.org/issues/1/&quot; class=&quot;notion-text-href&quot;&gt;the first issue&lt;/a&gt;, I was looking at one of my board game projects dubbed Roll the Rest (a
  variant of sorts of
  &lt;a href=&quot;https://boardgamegeek.com/boardgame/341416/high-score&quot; class=&quot;notion-text-href&quot;&gt;Reiner Knizia’s High Score&lt;/a&gt;) that I had a printed
  &lt;a href=&quot;https://notes.hamatti.org/gaming/board-games/card-games-in-c-cassette-cases&quot; class=&quot;notion-text-href&quot;&gt;a C cassette cover&lt;/a&gt;
  for.
&lt;/p&gt;

&lt;p&gt;
  Hence,
  &lt;a href=&quot;https://zine.hamatti.org/&quot; class=&quot;notion-text-href&quot;&gt;Roll the Zine&lt;/a&gt;. On its website, I currently describe it as follows
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  Roll the Zine is a board and card game focused zine and a love letter to
  creativity, gaming and DIY culture. It&#39;s an exploration of media, imperfection
  and putting something out there.
&lt;/blockquote&gt;

&lt;p&gt;
  I’ve now published 5 issues and they are all quite different from each other
  as my skills and my idea about zines have evolved. I want to keep
  experimenting with the content, layout and presentation. I’m very
  systems-oriented guy so establishing a format and repeatable system is natural
  and highly desirable to me and with the zines, I want to fight that.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Human curation and recommendation algorithms of the web
&lt;/h2&gt;

&lt;p&gt;
  I advocate for
  &lt;a href=&quot;https://hamatti.org/posts/human-curation-over-algorithmic-recommendations/&quot; class=&quot;notion-text-href&quot;&gt;human curation&lt;/a&gt;. It’s always been valuable but it has become extremely important in the era
  of social media platforms and search engines that decide what you see through
  recommendation algorithms that emphasise controversy, rage bait and hate.
&lt;/p&gt;

&lt;p&gt;Roll the Zine is a zine that lives and breathes that idea.&lt;/p&gt;

&lt;p&gt;
  I write about board and card games I enjoy to share them with other people. My
  experiences, my thoughts, my preferences. The goal is to share those so others
  could discover them and add new games to their enjoyed collection.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Community&lt;/h2&gt;

&lt;p&gt;
  Zines are historically very communal. Some of them are collections of articles
  and art by people who read them. Others include commentary and letters from
  readers to writers.
&lt;/p&gt;

&lt;p&gt;
  I really want to get there with my zines in the future. So far, it’s just me
  putting ideas together, turning it into a pdf and printing them out. I’m
  participating into the community with my zine and writing though:
  &lt;a href=&quot;https://tekeli.li/of-dice-and-meeples/&quot; class=&quot;notion-text-href&quot;&gt;Of Dice and Meeples&lt;/a&gt;
  is a monthly Amateur Press Association (APA) to which people who write about
  board games submit their zines and articles.
&lt;/p&gt;

&lt;p&gt;
  If you are interested in board games and want to write something for Roll the
  Zine, get in touch! Email address is in the info box after this blog post.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  Connection through the century
&lt;/h2&gt;

&lt;p&gt;
  &lt;a href=&quot;https://fanac.org/fanzines/&quot; class=&quot;notion-text-href&quot;&gt;Fanac’s archive&lt;/a&gt;
  has a ton of scifi zines from 1930s onwards. I have never felt any kind of
  connection or similarity with people who lived a hundred years before me but
  reading through these zines I felt such thing.
&lt;/p&gt;

&lt;p&gt;
  As I was reading through the early issues of Comet or The Planet, it felt like
  I was reading stuff written by people like me who share similar interests of
  science fiction and are contributing to the fandom.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Recommendations&lt;/h2&gt;

&lt;p&gt;
  If you’re into board games, check out my
  &lt;a href=&quot;https://zine.hamatti.org/&quot; class=&quot;notion-text-href&quot;&gt;Roll the Zine&lt;/a&gt;
  as well as
  &lt;a href=&quot;https://tekeli.li/of-dice-and-meeples/&quot; class=&quot;notion-text-href&quot;&gt;Of Dice and Meeples APA&lt;/a&gt;
  (and the people who submit to it).
&lt;/p&gt;

&lt;p&gt;
  For science fiction,
  &lt;a href=&quot;https://fanac.org/fanzines/&quot; class=&quot;notion-text-href&quot;&gt;Fanac archive&lt;/a&gt;
  is a wonderful collection.
&lt;/p&gt;

&lt;p&gt;
  For software developers,
  &lt;a href=&quot;https://wizardzines.com/&quot; class=&quot;notion-text-href&quot;&gt;Wizard Zines&lt;/a&gt;
  is a fantastic one.
&lt;/p&gt;

&lt;p&gt;
  To find zines of various topics,
  &lt;a href=&quot;https://www.sherwoodforestzinelibrary.org/&quot; class=&quot;notion-text-href&quot;&gt;Sherwood Forest Zine Library&lt;/a&gt;
  is a great place.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;Half a year retrospective&lt;/h2&gt;

&lt;p&gt;
  I’m so glad I started finally making these zines. It has given me a new
  creative outlet, led me to a bunch of great discussions with people who enjoy
  either zines, board games or both.
&lt;/p&gt;

&lt;p&gt;
  I have learned so much about the tooling: for brainstorming, for crafting the
  pages, for turning a pdf into both digitally readable and printable versions,
  for printing and much much more.
&lt;/p&gt;

&lt;p&gt;
  I keep
  &lt;a href=&quot;https://notes.hamatti.org/maker-culture-and-diy/zine-folding-pattern&quot; class=&quot;notion-text-href&quot;&gt;A4-folded-to-8-pages blank zines &lt;/a&gt;on my desk and in my backpack at all times so I can experiment and draft
  whenever an idea for a potential zine pops into my head.
&lt;/p&gt;

&lt;p&gt;
  In addition to the 5 published issues of Roll the Zine, I’ve been
  experimenting with other zine ideas. I have half-finished Saoirse Ronan
  Appreciation Zine and Florence Pugh Appreciation Zine in my virtual desk
  drawer. I’ve been drafting a couple of technical zines.
&lt;/p&gt;


    </content>
  </entry>
   
  
  <entry>
    <title>Improve Finder’s QuickLook with plugins</title>
    <link href="https://hamatti.org/posts/improve-finders-quicklook-with-plugins/" />
    <updated>2026-07-11T00:00:00Z</updated>
    <id>https://hamatti.org/posts/improve-finders-quicklook-with-plugins/</id>
    <content type="html">
      &lt;p&gt;
  This blog post is a sort of Public Service Announcement for all the MacOS
  users who don’t know about QuickLook plugins.
&lt;/p&gt;

&lt;p&gt;
  MacOS’s file explorer Finder has a handy feature
  &lt;a href=&quot;https://support.apple.com/guide/mac-help/preview-a-file-mh14119/26/mac/26&quot; class=&quot;notion-text-href&quot;&gt;Quick Look&lt;/a&gt;
  that allows you to quickly preview a file without opening it. However, on
  default it supports a rather limited amount of popular file formats.
&lt;/p&gt;

&lt;p&gt;
  For example, trying to QuickLook an
  &lt;code class=&quot;notion-text-code&quot;&gt;.afdesign&lt;/code&gt; file gives the default
  “preview not available” info box:
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/improve-finders-quicklook-with-plugins/1.png.webp&quot; alt=&quot;MacOS preview info box for file demo.afdesign that’s 12.1MB and last modified July 2nd, 2026. &quot; /&gt;
&lt;p&gt;
  For text files, the default is to show plain text preview regardless of the
  underlying format like with Markdown:
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/improve-finders-quicklook-with-plugins/2.png.webp&quot; alt=&quot;MacOS preview for a readme.md file, showing the text as black plain text on white background. &quot; /&gt;
&lt;p&gt;Luckily, it’s extendable by plugins.&lt;/p&gt;

&lt;p&gt;
  I use
  &lt;a href=&quot;https://github.com/sbarex/QLMarkdown&quot; class=&quot;notion-text-href&quot;&gt;sbarex’s QLMarkdown&lt;/a&gt;
  for rendering Markdown files. It has a lot of configurable options and themes
  if you need something specific but has sensible defaults for quickly checking
  out your Markdown files.
&lt;/p&gt;

&lt;p&gt;
  Here’s an example QuickLook of README.md for
  &lt;a href=&quot;https://hamatti.github.io/nhl-235/&quot; class=&quot;notion-text-href&quot;&gt;nhl-235&lt;/a&gt;:
&lt;/p&gt;
&lt;img src=&quot;https://hamatti.org/assets/img/posts/improve-finders-quicklook-with-plugins/3.png.webp&quot; alt=&quot;MacOS preview for readme.md file with Markdown rendered, rendering an image, headings and clickable links. &quot; /&gt;
&lt;p&gt;
  Another example is video files. &lt;code class=&quot;notion-text-code&quot;&gt;.mp4&lt;/code&gt; and
  &lt;code class=&quot;notion-text-code&quot;&gt;.mov&lt;/code&gt; files preview nicely by default but
  &lt;code class=&quot;notion-text-code&quot;&gt;.mkv&lt;/code&gt; and
  &lt;code class=&quot;notion-text-code&quot;&gt;.webm&lt;/code&gt; videos don’t.
&lt;/p&gt;

&lt;p&gt;
  I use
  &lt;a href=&quot;https://github.com/Oil3/QLCodec&quot; class=&quot;notion-text-href&quot;&gt;Oil3’s QLCodec&lt;/a&gt;
  for mkv files and their
  &lt;a href=&quot;https://github.com/Oil3/Webm-QuickLook-Plug-In&quot; class=&quot;notion-text-href&quot;&gt;Webm-QuickLook-Plug-In&lt;/a&gt;
  for webm. Apparently the QLCodec should also work for webm but I had installed
  the latter earlier before I discovered my need for mkv previews so I have both
  for now.
&lt;/p&gt;

&lt;p&gt;
  sindresorhus has
  &lt;a href=&quot;https://github.com/sindresorhus/quick-look-plugins&quot; class=&quot;notion-text-href&quot;&gt;a nice list of plugins&lt;/a&gt;
  so if you’re looking for something specific that you need to preview
  regularly, check it out.
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>Junited 2026 was wonderful</title>
    <link href="https://hamatti.org/posts/junited-2026-was-wonderful/" />
    <updated>2026-07-08T00:00:00Z</updated>
    <id>https://hamatti.org/posts/junited-2026-was-wonderful/</id>
    <content type="html">
      
&lt;p&gt;
  &lt;a href=&quot;https://notes.hamatti.org/writing/events/junited&quot; class=&quot;notion-text-href&quot;&gt;Junited&lt;/a&gt;
  is a blogging festival created by
  &lt;a href=&quot;https://robertbirming.com/junited/&quot; class=&quot;notion-text-href&quot;&gt;Robert Birming&lt;/a&gt;
  a couple of years back
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &lt;p&gt;
    So here’s my suggestion for June: let’s show a little extra appreciation for
    this lovely digital space of ours. Junited is a love letter, from one
    blogger to another, and another, and another…
  &lt;/p&gt;
  &lt;p&gt;
    It’s simple: just share links to blog posts or blogs you think deserve more
    love. A new post, an old favorite, or just a blog you enjoy.
  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  We have a wonderful community of bloggers who participate and this was
  &lt;a href=&quot;https://notes.hamatti.org/writing/events/junited-2026&quot; class=&quot;notion-text-href&quot;&gt;the first year I took part&lt;/a&gt;, sharing 30 posts from across the Internet. All together,
  &lt;a href=&quot;https://robertbirming.com/junited/&quot; class=&quot;notion-text-href&quot;&gt;59 people were listed to participate this year&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  Robert crunched the numbers in
  &lt;a href=&quot;https://robertbirming.com/junited-2026-numbers/&quot; class=&quot;notion-text-href&quot;&gt;his recap post&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  &lt;p&gt;
    In total, there were &lt;strong&gt;59 bloggers&lt;/strong&gt; taking part this year.
  &lt;/p&gt;
  &lt;p&gt;
    About &lt;strong&gt;1,000 links&lt;/strong&gt; were shared. That&#39;s around
    &lt;strong&gt;17 links per blogger&lt;/strong&gt;.
  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  I hear a lot of talk in my social circles both online and offline about how
  sad it is that “blogging is dead”. Junited is a great example of how it’s far
  from dead and it’s actually thriving. If you want to start reading more blogs,
  this is your opportunity to find a ton of great blogs to add to your RSS
  reader and start reading.
&lt;/p&gt;

&lt;p&gt;
  I’m a big advocate of
  &lt;a href=&quot;https://hamatti.org/posts/human-curation-over-algorithmic-recommendations/&quot; class=&quot;notion-text-href&quot;&gt;human curation over algorithmic recommendations&lt;/a&gt;
  and that’s why I personally like participating in this. That’s also why I
  wanted to write a short bit about each link: what it’s about, what are my
  thoughts on it and if I’ve written about it too. I find that pure link lists
  with no context or explanation can be overwhelming to go through. Same as blog
  rolls or feed dumps that occasionally go around.
&lt;/p&gt;

&lt;p&gt;
  And while June is over, we don’t have to stop sharing! If you want structure
  for it, Robert’s
  &lt;a href=&quot;https://robertbirming.com/julyreply-2026-blog-connecting/&quot; class=&quot;notion-text-href&quot;&gt;JulyReply&lt;/a&gt;
  is one opportunity to it:
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  The idea is straightforward and something many bloggers already do. Replying
  to others&#39; blog posts in a &quot;Re:&quot; format.
&lt;/blockquote&gt;

&lt;p&gt;
  You can do this whenever though! If you read interesting bits and you want to
  share it with a little to say: maybe make a Junited-esque link post and share
  a bunch. If you have more to say, write a blog post, link to the original,
  grab some quotes and participate in the discussion!
&lt;/p&gt;

&lt;p&gt;That’s the beauty of blogging.&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>House rules are great</title>
    <link href="https://hamatti.org/posts/house-rules-are-great/" />
    <updated>2026-07-04T00:00:00Z</updated>
    <id>https://hamatti.org/posts/house-rules-are-great/</id>
    <content type="html">
      &lt;p&gt;
  PleasantKenobi published a clickbaity video titled
  &lt;a href=&quot;https://www.youtube.com/watch?v=101kYfxCFLU&quot; class=&quot;notion-text-href&quot;&gt;“House Rules Don’t Work For Magic”&lt;/a&gt;
  in which he argues that people should not do house rules. It’s clickbaity
  because in the video he lists some house rules that he actually likes. More
  about that later.
&lt;/p&gt;

&lt;p&gt;
  I commented on the video with
  &lt;b class=&quot;notion-text-bold&quot;&gt;“My hot take on house rules: if you don&#39;t like them, don&#39;t use them.” &lt;/b&gt;I wanted to expand on my thoughts and comment on a bunch of points he made in
  his video.
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  House rules in tabletop gaming
&lt;/h2&gt;

&lt;p&gt;
  Let’s start by talking about house rules in tabletop games in general and then
  touch on the topic of Magic.
&lt;/p&gt;

&lt;p&gt;
  &lt;b class=&quot;notion-text-bold&quot;&gt;House rule &lt;/b&gt;is a rule that’s not part of the
  official rules of a game but that a group playing a game has agreed to
  introduce — usually to increase their enjoyment of the game.
&lt;/p&gt;

&lt;p&gt;
  Some games, like
  &lt;a href=&quot;https://boardgamegeek.com/boardgame/2223/uno&quot; class=&quot;notion-text-href&quot;&gt;UNO&lt;/a&gt;, are taught through tradition and are so riddled with house rules that you
  usually need to have a discussion every time before you start playing to make
  sure everyone’s on the same page with how the game works this time. UNO even
  encourages house rules by often introducing a few options in the rule book.
&lt;/p&gt;

&lt;p&gt;
  House rules can be problematic if players are not careful. If you don’t know
  that some rule is a house rule and learn it thinking it’s the actual rules, it
  can be difficult to play with other groups.
&lt;/p&gt;

&lt;p&gt;
  I think house rules are essentially a wonderful tool: if you like playing a
  game but there are some bits that make the game way less enjoyable to you and
  your friends, don’t waste your limited time worrying about it and come up with
  rules that make it better for you.
&lt;/p&gt;

&lt;p&gt;
  There are two crucially important parts to house rules: clarity and consent.
  Everyone in the group should understand the house rules and they should agree
  to them before hand. Nobody else’s opinion matters but those who are playing
  at that game with those rules.
&lt;/p&gt;

&lt;p&gt;
  Different people enjoy different things and if you own a game that with small
  changes can become even better for you and your group, please do so!
&lt;/p&gt;

&lt;h2 class=&quot;notion-heading_2 notion-color-default&quot;&gt;
  House rules in Magic the Gathering
&lt;/h2&gt;

&lt;p&gt;
  PleasantKenobi is very clear in his video that not only does he not like house
  rules but he thinks nobody should play with them. His main argument is that
  Magic the Gathering is designed by good game designers and players making
  changes to the rules and balances of the game are worse. I don’t disagree on
  that.
&lt;/p&gt;

&lt;p&gt;He says&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  The other problem I have with house rules is that a lot of them are fucking
  shit and they kind of fuck the game up.
&lt;/blockquote&gt;

&lt;p&gt;
  I do disagree on that though: even if a house rule would “objectively” (in
  quotes because I’m not sure if it’s possible to measure) worse or less
  balanced but it creates a better gaming experience for people at the kitchen
  table, it does make it better.
&lt;/p&gt;

&lt;p&gt;
  Of course bad house rules are bad, I don’t think anyone argues against that.
  The point of house rules is that they are for the group that is playing with
  them and if they work for them, then they are good.
&lt;/p&gt;

&lt;p&gt;
  He also argues that problem with house rules in Magic the Gathering is that
  you might play with players outside of your house rule group in local game
  stores or tournaments. I’d argue it’s not a problem as long as you don’t try
  to enforce your own rules to others.
&lt;/p&gt;

&lt;p&gt;
  One house rule he mentions that our Commander play group occasionally follows
  is a “draw 10, put 3 back” rule. A casual
  &lt;a href=&quot;https://mtg.wiki/page/Commander_Brackets&quot; class=&quot;notion-text-href&quot;&gt;bracket 3&lt;/a&gt;
  game of Commander usually takes around 60-90 minutes in our group. We play to
  have a good time and I think it’s great if everyone gets an opportunity to
  participate in a game that long.
&lt;/p&gt;

&lt;p&gt;
  Having house rules on
  &lt;a href=&quot;https://mtg.wiki/page/Mulligan&quot; class=&quot;notion-text-href&quot;&gt;mulligans&lt;/a&gt;
  is not good for competitive gaming for sure but for a casual, “let’s hang out
  with friends and play a game or two”, I don’t think it’s worthy of one player
  missing out a full game because they bricked early on.
&lt;/p&gt;

&lt;p&gt;
  Another argument of his is that you just need to “get good”. He makes a good
  point — which I agree on — that some things you might want to house rule
  become less of an issue once you become better at the game: building decks,
  understanding complex interactions, making better decisions. However, that’s
  not a good reason to tell other people, who might just play in their casual
  kitchen table environment and never plan to play competitively, that changes
  they make that make the game
  &lt;b class=&quot;notion-text-bold&quot;&gt;more enjoyable to them&lt;/b&gt; is wrong or bad.
&lt;/p&gt;
&lt;h3&gt;A big part of Magic the Gathering is house rules&lt;/h3&gt;
&lt;p&gt;
  One house rule that PleasantKenobi agrees on is playing custom formats but I
  think he makes the general mistake of “what I like is good and doesn’t count”.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://notes.hamatti.org/gaming/board-games/magic-the-gathering/magic-the-gathering---commander&quot; class=&quot;notion-text-href&quot;&gt;Commander&lt;/a&gt;
  is one of the most popular Magic the Gathering formats and even though it has
  rules of its own, it’s a massive house rule to the original official
  sanctioned rules of the game. It turns two player 60 card duels into 4 player
  multiplayer singleton 100 card battles.
&lt;/p&gt;

&lt;p&gt;
  So are the other community made formats. Cubes,
  &lt;a href=&quot;https://notes.hamatti.org/gaming/board-games/magic-the-gathering/forgetful-fish&quot; class=&quot;notion-text-href&quot;&gt;Dandân&lt;/a&gt;,
  &lt;a href=&quot;https://notes.hamatti.org/gaming/board-games/magic-the-gathering/mtg-battle-box&quot; class=&quot;notion-text-href&quot;&gt;Battle box&lt;/a&gt;
  and
  &lt;a href=&quot;https://www.youtube.com/watch?v=S1TzcivSUZE&quot; class=&quot;notion-text-href&quot;&gt;Party box&lt;/a&gt;
  are all &lt;b class=&quot;notion-text-bold&quot;&gt;house rules&lt;/b&gt;. They prove that house
  rules indeed do work in Magic the Gathering and often create the most
  enjoyable experiences to many players.
&lt;/p&gt;

&lt;p&gt;
  At the end — after 15 minutes of bashing people for making house rules — he
  says
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  And I&#39;m not saying you can&#39;t change the rules of magic to create a new thing
  that you and your play group really enjoy.
&lt;/blockquote&gt;

&lt;p&gt;
  Once again, he actually argues that “house rules I enjoy are good but ones
  that others enjoy are not if I don’t like them”. Maybe it’s because Youtube
  rewards clickbait and ragebait content over good discussion but I’m holding
  people accountable for participating in that and make my comments based on
  what I see and hear.
&lt;/p&gt;

&lt;p&gt;
  I’ll finish off by saying that PleasantKenobi’s videos are great and if you’re
  into Magic, I recommend checking
  &lt;a href=&quot;https://www.youtube.com/@PleasantKenobi&quot; class=&quot;notion-text-href&quot;&gt;his channel&lt;/a&gt;
  out.
&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>Goo of consciousness</title>
    <link href="https://hamatti.org/posts/goo-of-consciousness/" />
    <updated>2026-07-01T00:00:00Z</updated>
    <id>https://hamatti.org/posts/goo-of-consciousness/</id>
    <content type="html">
      &lt;p&gt;It’s so fucking hot.&lt;/p&gt;

&lt;p&gt;
  As I’m writing this, I have a couple of deadlines for writing projects that
  are approaching at the speed of panic. My plan was to come to town today, grab
  lunch and sit down and write.
&lt;/p&gt;

&lt;p&gt;
  But it’s so hot my thoughts melt before they have time to properly form,
  interact and merge to create new ones.
&lt;/p&gt;

&lt;p&gt;It&#39;s all just goo of consciousness today.&lt;/p&gt;

    </content>
  </entry>
   
  
  <entry>
    <title>If you don’t know what to do, pick up a chair</title>
    <link href="https://hamatti.org/posts/if-you-dont-know-what-to-do-pick-up-a-chair/" />
    <updated>2026-06-24T00:00:00Z</updated>
    <id>https://hamatti.org/posts/if-you-dont-know-what-to-do-pick-up-a-chair/</id>
    <content type="html">
      &lt;p&gt;
  Jon Banafato shared his older blog post
  &lt;a href=&quot;https://www.jonafato.com/2024/12/20/stacking-chairs&quot; class=&quot;notion-text-href&quot;&gt;Stacking Chairs &lt;/a&gt;in Mastodon the other day.
&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  “Stacking chairs”, taken literally, is what it sounds like. You know those
  stackable plastic and metal chairs that they have in your local library’s
  community room or similar space? Grab one, add it to the top of the stack.
&lt;/blockquote&gt;

&lt;p&gt;
  It’s a great concept. Throughout my community career, I’ve used it a lot. I’ve
  told people that my superpower is carrying chairs. One of the alumni groups
  for a community I used to hang out in is called Tuolinkantajat (lit. chair
  carriers) for this same reason.
&lt;/p&gt;

&lt;p&gt;
  Jon does an excellent job of saying everything I wanted to say on the topic so
  I’ll mostly refer you to his post.
&lt;/p&gt;

&lt;p&gt;I want to highlight another piece from that post:&lt;/p&gt;

&lt;blockquote class=&quot;notion-quote notion-color-default&quot;&gt;
  It’s not particularly glamorous. There are plenty of exciting community
  volunteer roles that carry prestige with them, but this isn’t something that
  would end up on someone’s résumé.
&lt;/blockquote&gt;

&lt;p&gt;
  In many communities, there are positions that can be glamorous for personal
  glory. They can often attract people who care not for the community but for
  using the community as a lever to gain personal advantage.
&lt;/p&gt;

&lt;p&gt;
  Carrying or stacking chairs is the opposite of that. It’s the type of
  contribution that is serving the community first and foremost.
&lt;/p&gt;

&lt;p&gt;
  I used to work as a community manager for a local entrepreneurship community.
  We had this co-working space from which were moving to a new place. I
  scheduled a Community Day for people involved in the community to come
  together to carry stuff.
&lt;/p&gt;

&lt;p&gt;
  I get there in the morning a bit before the scheduled starting time. All of
  the tables and chairs had been carried next to the doors, ready to be hauled
  into a van for moving. They carried the chairs both literally and
  metaphorically for the community. That was a big moment I knew I was involved
  with the right people.
&lt;/p&gt;

&lt;p&gt;
  In
  &lt;a href=&quot;https://cz.pycon.org/2023/&quot; class=&quot;notion-text-href&quot;&gt;PyCon CZ 2023&lt;/a&gt;
  in Prague, after the talks were over, we had a board game night. As soon as
  the last lightning talk finished, people started stacking the chairs away from
  the main area to make space for tables for gaming. It was an amazing community
  experience to witness.
&lt;/p&gt;

&lt;p&gt;
  &lt;i class=&quot;notion-text-italic&quot;&gt;The title is paraphrasing Ben Grimm from MCU’s Fantastic Four where he says
    “My father used to say: if you don’t know what to do, pick a shovel.” Chairs
    are our shovels.&lt;/i&gt;
&lt;/p&gt;

    </content>
  </entry>
  
</feed>
