Blog about software development

On this blog I write about programming, system administration, and other tech topics that I love. You can find more about me on GitHub and LinkedIn. — Maurits van der Schee

Jinja-like templating for HTML written in PHP

PHP has built-in templating, but mixing PHP and HTML gets messy quickly. Separate template engines like Twig or Smarty add dependencies and complexity. I wanted a small implementation with Jinja-like syntax that’s easy to understand and modify. So I wrote MintyPHP Template. It allows you to write things like: <h1>{{ title }}</h1> {% if user.is_admin %} <span class="badge">Admin</span> {% endif %} <ul> {% for item in items %} <li>{{ item.name }}</li> {% endfor %} </ul> All output is HTML-escaped by default. Variables use {{ }}, control structures use {% %}, and comments use {# #}. ...

January 4, 2026 · Maurits van der Schee

Translating gettext PO files with Google Translate

Managing translations for multilingual software can be tedious. You maintain a POT template with all your strings, and then need to keep multiple (gettext) PO files synchronized and translated. I wrote a small command-line tool in Go called “potranslate” to automate the translation part using Google Translate. Use it from the command line: # Scans for default.pot and PO files in ./locales potranslate --source-lang en ./locales Point it at a directory with POT and PO files, and it will: ...

December 31, 2025 · Maurits van der Schee

Context Engineering: Mastering AI Tools

There’s an old saying: “A craftsman is only as good as their mastery of their tools.” Carpenters master their saws and chisels, surgeons master their scalpels, and software engineers master their IDEs, languages, and frameworks. Today, AI coding assistants are our newest tools. The question is: do you know how to master them? The AI revolution has levels We’ve moved through distinct levels of AI assistance over the past few years. We started at level zero with no AI at all, then progressed to copy-pasting from ChatGPT. We got autocomplete, then inline editing. Now we have tools that can make project-wide changes and act as agents. The most advanced level is where AI helps with architectural thinking itself. ...

December 29, 2025 · Maurits van der Schee

Avoid BigQuery SQL injection in Go with saferbq

When building BigQuery applications using the Go SDK you may allow users to select tables or datasets dynamically. This means you need to include user-specified identifiers in your SQL queries. I was surprised that the BigQuery manual and code examples do not warn about SQL injection vulnerabilities when doing this. Even more surprising: BigQuery does not provide a built-in mechanism to safely handle user input in table or dataset names. The official SDK supports parameterized queries for data values using @ and ? syntax, but these cannot be used for identifiers that need backtick escaping. You may be tempted to use string concatenation, but that opens the door to SQL injection, and should be avoided. This post explains the problem and introduces saferbq, a Go package I wrote to help you write injection-free BigQuery SQL. ...

December 13, 2025 · Maurits van der Schee

Using the AnkerWork C310 webcam on Linux

I recently upgraded the webcam of my main Linux machine from an Ankerwork C200 (2k webcam) to an Ankerwork C310 (4k webcam). The C200 worked pretty well out of the box without having to update firmware or adjust settings in Windows or on MacOS. Unfortunately the C310 was showing a very overexposed picture that was only fixed by moving my face out of the center of the (captured) image. This led me to believe that some option of the Ankerwork C310 was turned on that should have been turned off. ...

December 7, 2025 · Maurits van der Schee

Evaluating PDF24 Toolbox with Simplewall

You can view a PDF in your browser, Firefox does this fast and accurately, no need for Adobe Reader. But even if you want to edit a PDF, you don’t need Adobe Acrobat. On Linux we can install PDF toolkit with a single “sudo apt install pdftk”. But even on Windows there are some good PDF tools available, like PDF24, which even costs nothing. With PDF24 you can do all of the following: ...

December 5, 2025 · Maurits van der Schee

USB-Soft-KVM: monitor switching with DDC/CI

USB-Soft-KVM is a lightweight Linux solution that turns a simple USB switch into a full-featured KVM solution. By combining an inexpensive USB switch with software-based monitor switching via DDC/CI, you get complete keyboard-video-mouse control on a budget. This software solution automatically switches your monitor’s input source using DDC/CI commands over the I2C bus whenever you toggle the USB switch by responding to USB device connection events. It’s perfect for users with a laptop and desktop sharing one monitor. ...

November 22, 2025 · Maurits van der Schee

Migrating the TQdev.com blog to Hugo

In 2016 I wrote “My name is Maurits van der Schee and I love thinking about software architecture and building high traffic web applications” in my first TQdev.com post when I migrated from WordPress to a self-written PHP blog platform. I wrote “I love the idea of gradually (while writing posts) making this blogging software feature complete”. It was an experiment that lasted for 9 years and most of the time everything was working great. I’ve spent a lot of time writing articles and almost no time improving the blogging software. Now, 9 years later, it was time for another migration. ...

November 20, 2025 · Maurits van der Schee

Creating 103mail.com - Update 3

I am still building a free email service that respects privacy and prevents profiling on 103mail.com. I started this effort in 2024 and have been building slowly since (because work and life happens). I have reached a new milestone and it is thanks to SDD (Spec Driven Development with SpecKit) and AI (VSCode + Copilot + Claude Sonnet 4.5) that I have made good progress lately. In this post I’ll explain to you a bit about my way of working and about the progress. ...

November 18, 2025 · Maurits van der Schee

Mocking static methods and built-in functions in PHP

Testing code that relies on static methods or built-in functions can be challenging in PHP. Traditionally, you’d have to refactor your code to inject dependencies or wrap functions in testable interfaces. To allow you to write clean, maintainable tests without invasive refactors, I created MintyPHP Mocking. It allows you to write things like: $mock = new StaticMethodMock(Adder::class, $this); $mock->expect('add', [1, 2], 3); $result = Adder::add(1, 2); $mock->assertExpectationsMet(); For mocking static methods, and: $mock = new BuiltInFunctionMock('App\Service', $this); $mock->expect('microtime', [true], 1763333612.602); $service = new Service(); $timestamp = $service->getCurrentTime(); $mock->assertExpectationsMet(); For mocking PHP’s built-in functions. ...

November 16, 2025 · Maurits van der Schee