Juha-Matti Santala
The home of a developer community specialist.
- Posts
- 621 from 23 Mar 2021 to 28 Oct 2026
- Posting
- weekly (122 in the last year)
- Kind
- personal blog
- Feed
- https://hamatti.org/feed/feed.xml
2026 106
- Sharing notes with Hermes and Agora
- Djangonaut Log 2: Leaving the atmosphere and first merged contributions
- Assumptions are sneaky
- Debugging a flaky test — how I methodologically tamed an annoying bug
- A new notebook day
- Djangonaut Log 1: Lift-off and first week in Djangonaut Space
- I really like how Ultrapool calculates your money rewards
- Double check your website’s alt texts with a bookmarklet
- PlateUp!
- Pokemon TCG League Cup 2026-10-10
- 3… 2… 1… becoming a Djangonaut
- How to use Spelltable
- Webcam gaming setup
- Two new tiny Home Assistant improvements I made recently
- Pokemon TCG League Challenge 2026-09-26
- Make your website printable - a short guide
- I’m not a big fan of movie theater experience
- Why do we take notes?
- Moomin and nfo files for Jellyfin
- People and Blogs interview
- Hobbit draft, 2026-09-06
- What’s in my Magic the Gathering Battle Box
- 31st is for recap
- A lot of what I’ve learned, I’ve learned from open web
- Z is for zip file mocking - Python A to Z
- A fun debugging story from this weekend
- Y is for YAGNI - Python A to Z
- X is for XML parsing - Python A to Z
- W is for walrus operator - Python A to Z
- V is for visible characters - Python A to Z
- U is for uv - Python A to Z
- Reply to Dale’s comment on my IndieWeb post
- There’s no membership card for IndieWeb
- T is for time-machine - Python A to Z
- Pokemon TCG Worlds 2006 retro tournament, August 22nd 2026
- S is for slicing - Python A to Z
- R is for REPL - Python A to Z
- Q is for Q - Python A to Z
- P is for Python Enhancement Proposal (PEP) - Python A to Z
- O is for ORM - Python A to Z
- N is for namedtuple - Python A to Z
- Saoirse Ronan Appreciation Week, round 2
- M is for meetups - Python A to Z
- L is for learning - Python A to Z
- K is for keyword arguments - Python A to Z
- J is for JSON validation - Python A to Z
- HTML Day and the value of practicing the fundamentals
- I is for immutable - Python A to Z
- H is for htmx - Python A to Z
- G is for get_or_create - Python A to Z
- F is for f-strings - Python A to Z
- My custom keyword reference guide for Magic the Gathering Battle Box
- E is for environment variables - Python A to Z
- D is for dictionaries - Python A to Z
- C is for command line interfaces - Python A to Z
- B is for batteries included - Python A to Z
- A is for assert - Python A to Z
- Python A to Z - Blaugust 2026 introduction
- In the era of AI slop, human curation is even more important
- Not seeking growth is a perfectly valid strategy
- Chats and forums
- On blogging, Blaugust and challenging yourself
- A lovely dialogue about taking notes from See How They Run
- My first Finncon — Turku, 2026
- Thoughts on making zines after 7 months
- Improve Finder’s QuickLook with plugins
- Junited 2026 was wonderful
- House rules are great
- Goo of consciousness
- If you don’t know what to do, pick up a chair
- Unexpected weekend with Pedro Pascal as a father figure
- Writing about it - approach to writer’s block
- Chris Ramsey, Taskmaster and No way!?
- Pokemon TCG PRC-GRI retro tournament, June 14th 2026
- Future Frontend 2026 Recap
- A sign of a good tool is that you don’t notice it - one year with wallabag
- Junited is a celebration of the blogosphere
- An entire wiki in a single file? A look at Feather Wiki
- IndieWeb Carnival May 2026: Roundup of love letters
- Saoirse Ronan Appreciation Week
- Happy 10th birthday TurkuSec!
- Tame your pesky little scripts
- 11 more days time to write a love letter - IndieWeb Carnival
- Even the dogs have started to notice
- A love letter to our library bus
- Practicing writing about games
- I tell about my blog to anyone willing to listen
- IndieWeb Carnival May 2026: Write a love letter
- I have been tempted by AYN Thor — but I have AYN Thor at home
- Thumbs up for a good adventure
- Small bit of functional graphic design I like
- Dungeons & Degenerate Gamblers is the Betamax of casino roguelikes
- I’m building a Python script to create form filling bookmarklets
- How much change is the right amount of change?
- New protocol proposal for indie web: human.json
- Markdown content split to sections in Eleventy and Nunjucks
- I completed Stardew Valley’s shipping collection — in reverse
- Au revoir, Eleventy
- Happy 10th birthday Stardew Valley
- Different notebook sizes for different ideas
- Them weird dreams
- IndieWeb Carnival hosting Q&A with Zachary Kai
- Taskmaster UK Series 7 is peak entertainment
- I made a board game zine
- Gaming for busy people
- I added BookLore to my homelab
2025 84
- Year in Review 2025
- We played a full Scarlet & Violet Progression Series
- Merry Christmas!
- I played some games this year
- Advent of Code 2025 retrospective
- I’m a tool builder at heart
- Where are we going, IndieWeb?
- About writing and audience
- I built a tiny RSS generator for my Advent of Code solutions
- One thing I’d like to change about Pokémon TCG
- Improve your programming skills with Advent of Code
- My Debugging Python talk from PyCon Finland published
- Eulogy to my old laptop
- I designed a 3D printed photo caddy insert for Tiny Epic Galaxies
- What’s the story my front page tells?
- My writing inspiration lives through cycles
- Progressive enhancement is a crucial design principle for smart devices
- Obsidian is as simple or complex as you make it
- PyCon Finland 2025 recap
- I teach, therefore I learn, PyCon CZ, 14th June 2019
- Networking and writing as a catalyst for relationships and opportunities
- Tabletop game shows
- File organisation in Eleventy: Filters
- My favourite bird Pokémon TCG card arts
- You can have your hobby
- Leveraging Eleventy’s custom data file format feature for simpler game scoring format
- Custom git ignores with a global gitignore file or git exclude
- I will be speaking at PyCon Finland in Jyväskylä 17.10.
- Blaugust 2025 retrospective: Surprising Rainbow Diamond Award
- Static sites enable a good time travel experience
- I keep geeking out about my print styles
- Build the forum you want to see in the web
- There’s something I’ve never told you…
- Shortcut to add link to today’s note in Obsidian
- I wonder if my blog has been mentioned in US courts
- #971226 is my colour in the web
- I have found the joy of clipboard managers
- I’m happy when people learn and are inspired
- Linking to books online
- If you had absolutely no worries about money, and no fear, what are ten things you would do this week?
- Handwriting is slow which gives me time to think
- Notes require regular gardening
- Board game nights are my favourite way to socialise and make new friends
- My wallet doesn’t run out of battery
- Questions and answers about blogging
- Is writing a hobby for me?
- Saturday Extra: Raindrops
- Network stress test for my smart home
- Blog comments, a must-have or fun extra?
- I really like Home Assistant’s triggers and actions model for its flexibility
- Newsletters I read
- wallabag, I choose you!
- Do not, I repeat, do not read the comments
- Dotfiles feel too intimate and personal to share
- Naming devices is fun
- Solutions and references
- Find new blogs to follow from this year’s Blaugust participants
- "You can't pause an online game" — how childhood gaming formed my work preferences
- Welcome to Blaugust 2025
- Better alternative to shell scripts with Python, uv and pytest
- IndieWeb principles and I
- Custom CLI tool to link Mastodon posts and blog posts
- Blaugust 2025 starts August 1st
- Random page feature for a static site with Eleventy
- A good luck charm
- Everyday Tabletop Gaming Carry (EDTGC)
- Sometimes it’s the small details that matter
- Guide VS Code to recognising PEP 723 dependencies
- The web is more than just information
- Starting my video projector with Python and Playwright
- A fish in a pond
- Better communication skills can lead to better career opportunities
- I like my green 3D printed webcam cover
- As a developer, my most important tools are a pen and a notebook
- Mozilla is shutting down Pocket, what next?
- When a community graduates
- Notifications about (almost) anything with ntfy.sh
- Providing next event as API with Eleventy’s Global Data Files and Netlify Functions
- Writing notes helps you remember — and forget
- Hard to spot auto-format error with Prettier, Netlify redirects and Mastodon webfinger
- Systems of the dead stagnate
- Improvised lightning talk extravaganza
- How I write and publish blog posts in April 2025
- Resisting the urge to rewrite the website
2024 1
2023 2
2021 1
Undated 427
- Life without advertisements is a great life
- Review: Last One Laughing UK
- Shared RSS subscriptions for a software team
- I want to like Trainers’ Pokemon but I can’t
- “Shrink designing” board games
- Track software versions for technical blog posts
- UX of home-cooked software
- view-source explorers welcome
- Redesign and rewrite of playtest printer
- List blog posts grouped by year with Eleventy
- Bedside notes
- Explaining it helps you learn it
- Leaves is a great two player game
- My mom believes there’s a silver lining
- How long does it take me to write a blog post?
- Look for deep discussions, not a mentorship
- Nonlinear writing
- Access the DOM inside an iframe with Javascript
- Be careful with introducing AI into your notes
- Introducing: From Juhis with Love
- Advent of Code 2024 retrospective
- The ability to code sometimes feels like magic to me
- Say hello to Garden of Learning
- Human curation over algorithmic recommendations
- Year in Review 2024
- Merry Christmas!
- Three Rules, a new podcast by Matt D’Avella
- Writing is my canary bird
- Increasing the surface area of luck
- Struggles with believing in myself
- Three is a pattern
- Advent of Code 2024: How to write notes as a developer
- I like the person I am when I travel
- Search your notes first
- End of year self-reflection with Year Compass
- Impact.
- How I teach Eleventy from scratch
- The Non-Prime Regex is in the cross-section of two of my interests
- Notion is adding an offline mode
- I built a custom RSS hydrator for better GitHub and Youtube feeds
- My on the go solution with iPad and Raspberry Pi
- How I take work notes as a developer
- Multilingualism in a global web
- 12th anniversary of hamatti.org
- Automate filling a form with a bookmarklet
- Auto Note Mover and templates make a nice duo in Obsidian
- Do one thing well and communicate with others
- What to do first with a legacy project?
- Blindspot is a great series that suffers from a pacing issue
- What’s up with blogging challenges?
- Blaugust 2024 retrospective
- Book recommendation: Fluent Python (2nd Edition)
- What’s coming to Python in 3.13 and 3.14
- Couple of great Python podcasts
- Quick prototyping with sqlite3
- Parse command line arguments with argparse
- Pretty print and validate JSON on command line with json.tool
- Test your codebase with unittest
- Branch out with pattern matching
- Serve local HTML and CSS files with http.server
- Bring your custom toolkit to REPL sessions
- Keep track of happenings with logging
- Memoize with functools.cache
- map and filter with list comprehensions
- Combine iterables with zip
- Random number chosen by fair dice roll
- Write more pythonic code with context managers
- Combinatoric iterators from itertools
- Rituals build community camaraderie
- A bunch of small game reviews: Shogun Showdown, Into the Breach and Fly Corp
- Data classes in Python with dataclasses
- Rotating turn order with deque
- Debug with pdb and breakpoint
- Document intended usage through tests with doctest
- Improved print readability with pprint
- help() me Obi-Wan Kenobi, you’re my only hope
- Count ‘em
- Improve your code with namedtuples
- Reading and writing CSV with Python
- Parsing nginx server logs with regular expressions
- Blaugust 2024: Batteries included
- I have a super power: suspension of disbelief
- My desk setup, 2024 edition
- Art forgery, LLMs and why it feels a bit off
- Notes are a tool for …
- Home-cooked, situated software
- Advocate for your colleagues
- Blaugust starts August 1st
- Future Frontend 2024 Recap
- Different ways I start writing new code
- I prefer discussion in open web
- First impressions on Seasons
- Scoping the /now
- A peek into my pocket notebook
- Why a personal site rather than social media presence?
- JSON Schema: require properties based on values of other properties
- Website self-sustenance checkup
- Short history of my blogging journey
- Tomorrow is Volunteer Responsibility Amnesty Day
- Multi-select, filterable command-line interface with inquirer
- Crafting tabletop games
- Webmention bookmarklet
- What does it feel like to read RSS feeds?
- Make ripples through time and space by writing
- IndieWeb Carnival May Round-up post: Creative Environments
- Third places and meetups
- A lot of advice is a product of survivorship bias
- Inflexible systems grind my gears
- Reminder: IndieWeb Carnival May is still running
- Recap of 11ty International Symposium on Making Web Sites Real Good
- Two small hockey web projects
- But someone already wrote about it
- The nook of creativity
- The importance of momentum in writing
- Indie Web Carnival May 2024: Creative environments
- The Future of Jamstack panel discussion
- Good enough as a power for good
- index.md is a valid Eleventy project
- Prepare, Perform, Ponder
- I can :has() cheeseburger
- Markdown - the trade-offs of simplicity
- Sharing podcast episodes is weird
- Documentation pages from dotfiles with config-renderer
- Full-text RSS feed is an offline-friendly act
- Chance of serendipity
- Traveling through time
- I had a chat about personal web at The Future of Jamstack
- I completed #100DaysToOffload
- Recent evolution of my note taking systems
- My most used bookmarklets
- On content creation and personal web
- Search directly on a website with Firefox bookmark keywords
- Thoughts on accessibility in personal web
- Chesterton’s Fence and tech documentation
- Display full URL after a link when a page is printed
- Search, Webmentions and microformats
- THE Eleventy Meetup Feb 20th
- Pull request is my proposal for changes
- Talk ideas for new and experienced speakers
- Thank you, Startuplifers
- We organized a Code in the Dark event
- Stickers tell stories
- Public notes
- Anonymous, asynchronous friendships
- Highlight Mastodon posts by hashtag with Stylus and :has
- I like to glue things together
- We have a great developer community scene in Turku
- Please, don’t force me to log in
- Python Bytes featured Syntax Error
- Community websites with Eleventy
- The Lazarus Project (review)
- A few core memories
- I wish Python had Integer.times
- Debugging Python
- Join us at Future Frontend 2024
- Write it anyway
- Workaround for Notion’s lack of heading levels
- Advent of Code 2023 retrospective
- Year in Review 2023
- Merry Christmas!
- Two months with Obsidian
- We’re building community for Python developers
- Advent of Code is just around the corner
- Three travel essentials
- People and Blogs newsletter
- What's in the name? The story behind my domain
- Done is the engine of more
- Use SQL to query your CSV files
- Learning Rust #10: Added new feature with a HashMap
- Showing most popular posts with Netlify Analytics
- Priority order when you start blogging
- Great details on conference badges
- I got to show you this
- Handling JSON on command line
- Document your secrets
- Traveling Europe on land: Turku to Prague
- How you can make conferences better
- Pull requests are great
- My iterative approach to software development
- Blaugust 2023: Lessons Learned
- Use pangrams to avoid mistakes in conference badge prints
- My First 100K
- Custom cookie consent for video embeds
- Compressing overlapping strings in Python
- Where do my links live?
- 6 months of recovery, how is life?
- Building Dark Mode for hamatti.org
- Let’s talk about Steam Deck
- Website rewrite and switching to Notion as CMS
- Stardew Valley Mods I use
- Youtubers I watch
- Bloggers I read: Saturday
- Bloggers I read: Friday
- Bloggers I read: Thursday
- Bloggers I read: Wednesday
- Bloggers I read: Tuesday
- Pokemon tools updated for Obisidian Flames
- Desert Island Discs
- Future Frontend 2023 Recap
- Projects I'm proud of: Teaching programming
- Projects I'm proud of: Potluck
- Projects I'm proud of: Newsletters
- Projects I'm proud of: Turku ❤️ Frontend
- Projects I'm proud of: Boost Turku & Startup Journey
- Tools don't matter - until they do
- What makes a blog post a blog post?
- Where to publish your blog?
- Build an idea bank and never run out of blog ideas
- A bunch more of small game reviews: Dredge, Dishonored, Farm Keeper
- Blaugust 2023, here we come
- Blog comments via Mastodon
- What tech docs can learn from video game tutorials?
- Hey dev student: you should study creative writing
- Give your commands consistent names
- Document outdated components
- How to network while being beneficial to oneself professionally?
- Writing documentation is a great tool to improve software quality
- I found new great games
- I got my hands on the finished product (Potluck)
- In a beautiful world, APIs would be open
- How to document a workaround?
- A look at my on-going projects
- How to sort a Pokemon deck list?
- Potluck #3: My workflow
- Organizing a mess with cherry-picking
- A quick life update
- A bunch of small game reviews: Village Rails, Skulls of Sedlec, Barotrauma
- I combat impostor syndrome with building in public
- Potluck #2: The Deck
- The imperfect mess of note taking
- In defense of Quote Toots
- Potluck #1: Research and Design
- Guide to landing your first dev job
- My Pokemon apps updated for Crown Zenith
- I'm leaving Mozilla
- Me and the elves - Advent of Code 2022 retrospective
- Introducing: Syntax Error
- Year in Review 2022
- Merry Christmas
- DevRelCon Prague 2022 Recap
- Mastodon redirect with your domain in Netlify
- Verifying identity online
- Python prep for Advent of Code 2022
- steamos-readonly
- New Firefox extension to help Pokemon TCG players
- My overengineered tooling for Pokemon TCG Card Viewer extension
- How to wait for user input from Firefox extension page before continuing
- I joined Mastodon
- Find assigned tasks from Google Drive
- Upcoming live stream: first look at Rocket Oct 22nd
- Ad-Filtering Dev Summit 2022 Recap
- React Finland 2022 Recap
- Set up a dashboard using Google Slides
- kittens-everywhere – how to build a browser extension
- Traveling in connected, digitalized world
- Why I do what I do?
- I built a Firefox extension for Pokemon TCG players
- The Firehose
- I wrote my first Dropzone 4 action
- Embracing failure
- Unit test your Python code in Jupyter Notebooks
- Appendix A to Developer's Guide to Communities
- Developer's Guide to Communities
- Javascript's console is so much more than just console.log
- A lighthouse
- Goodbye, Futurice
- print is your best debugging tool
- GLC Decklist Validator updated with Astral Radiance
- Summer reading for scifi fans
- Learning Rust #9: A talk about rustlings
- A good job interview sets both sides up for success
- A week in life of a developer advocate
- Shy introvert's (short) guide to speaking in conferences
- Documentation: man pages vs tldr
- My trip to Django Day Copenhagen 2022 and Stockholm
- Listen to everyone, listen to no one
- Last two years have been awful
- I'm speaking in Django Day Copenhagen 2022 in April
- Added custom highlight function for nhl-235
- Rant: Please stop ruining the search
- I started writing Weeklies
- My least favorite board game genre: co-op games
- 45 stars, Christmas was almost saved - Advent of Code retrospective
- Year in Review 2021
- Merry Christmas!
- Tips for Advent of Code
- Advent of Code 2021
- Customizing liiga.fi experience
- Minimal Travel Table Top Game Collection 3: Project 108
- Hello code, my old friend
- Reaction GIF board with Stream Deck
- The most social and loneliest job: being a solo developer advocate
- Tiny handy tools: Community Edition
- Tiny handy tools
- Over a year of weekly blogging
- Python 3.10 is out and I'm excited
- How would you compare two version numbers?
- Where do you see yourself in five years?
- Roll and Write board games are awesome
- React Finland 2021 Recap
- Learning Rust #8: What's next?
- Syntax highlight all the things
- Blogging is my new favourite refactoring tool
- Your blog should have an RSS feed
- Learning Rust #7: Learn from the community
- Blog post filter with Netlify Functions
- Javascript Basics: Scope
- codebase ep. 4: Web Components with Matias
- Learning Rust #6: Understanding ownership in Rust
- My travel setup for Nintendo Switch
- Why scheduling Slack messages and emails is so valuable for community builders
- My (career) story in tech and developer relations
- codebase ep. 3: PHP with Larry
- Learning Rust #5: Rustlings
- Does it make sense to finish what you started?
- Scheduling operations in Python
- codebase ep. 2: Clojure with Ykä
- Learning Rust #4: Parsing JSON with strong types
- Falling forward
- Documentation-driven command line tools in Python with docopt
- Introducing developer community show codebase
- Learning Rust #3: crates.io & publishing your package
- My pockets are full of games
- 5 minutes that changed my life
- How to parse command line arguments in Python
- I gamified my own blog
- Learning Rust #2: Option & Result
- Learning in public
- Pattern matching is coming to Python
- My home office setup
- Learning Rust: Pattern Matching
- Introducing: 235
- Project: card-print-css
- Thoughts on debugging
- You should start a blog today
- Year in Review 2020
- Merry Christmas my friends
- Advent of Code #3: Slowing down
- Advent of Code #2: Borrows, unwraps and lots of compiler errors
- Advent of Code #1: Getting Started
- Customize your Internet experience
- Added keyboard support to ON24 with bookmarklet
- Functions 101
- Validating dynamic data conditionally with Joi
- How to ask help for technical problems?
- It's time for a remote work retrospective
- Dev Diary #2: Working prototype
- The many designs of on-screen inputs
- Arts, crafts and software: enhancing Flamme Rouge
- Adding keyboard shortcuts to Viaplay
- Recreational Mathematics
- Hidden Identity in Table Top Games
- I built a digital version of Black Hole game
- Different approaches to learning programming
- How to scrape a website with Python & BeautifulSoup
- Minimal Travel Table Top Game Collection 2: Social Distancing Edition
- Tips for giving talks online
- Dev Diary #1: Pokemon TCG Cube Draft
- <code>blocks
- True, True, True == (True, True, True) in Python
- Morning Coffee Projects: Youtube extension
- 8 tech podcasts I listen
- Testing lifehack: testlab repositories
- Building a website with a static site generator, part 3: Domain, Analytics and Forms
- Building a website with a static site generator, part 2: Eleventy
- Building a website with a static site generator, part 1: Setup
- How my site is built with Eleventy + Ghost
- New Guide - Humane Guide to Debugging Web Apps
- Minimal Travel Table Top Game Collection
- Helsinki Dev Lunch
- Year in review 2019
- My journey in diversity and inclusion in tech
- Why I love using command line interface?
- I love writing scripts to solve small problems
- Simple backend system for frontend workshops in Javascript
- Make your function calls more readable
- How to enable SSL in Netlify with custom domain
- PHP needs its own ES6
- “Event is over and it was a failure. What happened?” — Pre-mortem can help you avoid pitfalls
- Event organizer - automate what you can, focus on people with all you’ve got
- Better bash history search with McFly
- Post a message from Slack to Twitter with Zapier
- Learning programming has never been more accessible in Helsinki
- Year in Review 2018
- Internet = People = ❤️
- Developers do design — but we’re not taught it
- City Bound Nomadic
- The Reset Button
- The Cost of a Purchase
- Space has a Tendency to Fill Itself
- My love-hate relationship with PHP Arrays
- Beginning of a Journey
- What living a minimalistic life has taught me
- Do you want to learn new stuff?
- Help your customers become better
- Food Connects People - How to Hack Your Community with Food
- Communities in Marketing
- How I convinced 15+ companies to contribute to OSS
- 5 Reasons to Contribute to Open Source
- How to build a kickass developer community
- Year in Review 2017
- 5 Reasons to Attend a Meetup
- Improve the world — help someone learn
- Intentional and multifunctional - How I got rid of most of my belongings
- Code in the Dark Turku
- If you are not doing code reviews, start now!
- Why do good communities thrive?
- Building mobile app prototypes with Keynote
- Build your community like a garden
- What Rails Girls taught me about non-organizations
- Building a developer community calls for strong support
- Year in Review 2016
- 8 hours later + Turku <3 Frontend Hackathon
- Why I love hackathons
- What's with all these sorts, PHP?
- Beauty of the Pipe
- Case study - DataMonkey as educational platform
- Adventures of a Junior Developer
- The Beautiful Game
- Becoming a better programming teacher
- Rails Girls San Francisco
- Command line magic with git and bash history
- Difficulties with teaching and learning programming
- Computer illiterate generations – what should we do?
- Rails Girls – building the future
- 69 Lines of SQL
- TDD Pair Programming at University