Hi, I’m Redowan

...and this is the graveyard for my musings on software.

Einstellung effect

In 9th grade, when I first learned about Lenz’s Law1 in Physics class, I was fascinated by its implications. It states: The direction of an induced current will always oppose the motion causing it. In simpler terms, imagine you have a hoop and a magnet. If you move the magnet close to the hoop, the hoop generates a magnetic field that pushes the magnet away. Conversely, if you pull the magnet away, the hoop creates a magnetic field that pulls it back....

February 24, 2024

Strategy pattern in Go

These days, I don’t build hierarchical types through inheritance even when writing languages that support it. Type composition has replaced almost all of my use cases where I would’ve reached for inheritance before. I’ve written1 about how to escape the template pattern2 hellscape and replace that with strategy pattern3 in Python before. While by default, Go saves you from shooting yourself in the foot by disallowing inheritance, it wasn’t obvious to me how I could apply the strategy pattern to make things more composable and testable....

February 17, 2024

Anemic stack traces in Go

While I like Go’s approach of treating errors as values as much as the next person, it inevitably leads to a situation where there isn’t a one-size-fits-all strategy for error handling like in Python or JavaScript. The usual way of dealing with errors entails returning error values from the bottom of the call chain and then handling them at the top. But it’s not universal since there are cases where you might want to handle errors as early as possible and fail catastrophically....

February 10, 2024

Retry function in Go

I used reach for reflection whenever I needed a Retry function in Go. It’s fun to write, but gets messy quite quickly. Here’s a rudimentary Retry function that does the following: It takes in another function that accepts arbitrary arguments. Then tries to execute the wrapped function. If the wrapped function returns an error after execution, Retry attempts to run the underlying function n times with some backoff. The following implementation leverages the reflect module to achieve the above goals....

February 4, 2024

Type assertion vs type switches in Go

Despite moonlighting as a gopher for a while, the syntax for type assertion and type switches still trips me up every time I need to go for one of them. So, to avoid digging through the docs or crafting stodgy LLM prompts multiple times, I decided to jot this down in a gobyexample1 style for the next run. Type assertion Type assertion in Go allows you to access an interface variable’s underlying concrete type....

January 31, 2024

Patching pydantic settings in pytest

I’ve been a happy user of pydantic1 settings to manage all my app configurations since the 1.0 era. When pydantic 2.0 was released, the settings portion became a separate package called pydantic_settings2. It does two things that I love: it automatically reads the environment variables from the .env file and allows you to declaratively convert the string values to their desired types like integers, booleans, etc. Plus, it lets you override the variables defined in ....

January 27, 2024

Omitting dev dependencies in Go binaries

As of now, unlike Python or NodeJS, Go doesn’t allow you to specify your development dependencies separately from those of the application. However, I like to specify the dev dependencies explicitly for better reproducibility. While working on a new CLI tool1 for checking dead URLs in markdown files, I came across this neat convention: you can specify dev dependencies in a tools.go file and then exclude them while building the binary using a build tag....

January 21, 2024

Eschewing black box API calls

I love dynamically typed languages as much as the next person. They let us make ergonomic API calls like this: import httpx # Sync call for simplicity r = httpx.get("https://dummyjson.com/products/1").json() print(r["id"], r["title"], r["description"]) or this: fetch("https://dummyjson.com/products/1") .then((res) => res.json()) .then((json) => console.log(json.id, json.type, json.description)); In both cases, running the snippets will return: 1 'iPhone 9' 'An apple mobile which is nothing like apple' Unless you’ve worked with a statically typed language that enforces more constraints, it’s hard to appreciate how incredibly convenient it is to be able to call and use an API endpoint without having to deal with types or knowing anything about its payload structure....

January 15, 2024

Annotating args and kwargs in Python

While I tend to avoid *args and **kwargs in my function signatures, it’s not always possible to do so without hurting API ergonomics. Especially when you need to write functions that call other helper functions with the same signature. Typing *args and **kwargs has always been a pain since you couldn’t annotate them precisely before. For example, if all the positional and keyword arguments of a function had the same type, you could do this:...

January 8, 2024

Rate limiting via Nginx

I needed to integrate rate limiting into a relatively small service that complements a monolith I was working on. My initial thought was to apply it at the application layer, as it seemed to be the simplest route. Plus, I didn’t want to muck around with load balancer configurations, and there’s no shortage of libraries that allow me to do this quickly in the app. However, this turned out to be a bad idea....

January 6, 2024

Statically enforcing frozen data classes in Python

You can use @dataclass(frozen=True) to make instances of a data class immutable during runtime. However, there’s a small caveat—instantiating a frozen data class is slightly slower than a non-frozen one. This is because, when you enable frozen=True, Python has to generate __setattr__ and __delattr__ methods during class definition time and invoke them for each instantiation. Below is a quick benchmark comparing the instantiation times of a mutable dataclass and a frozen one (in Python 3....

January 4, 2024

Planning palooza

When I started my career in a tightly-knit team of six engineers at a small e-commerce startup, I was struck by the remarkable efficiency of having a centralized hub for all the documents used for planning. We used a single Trello board with four columns—To-do, Doing, Q/A, Done—where the tickets were grouped by feature tags. We’d leverage a dummy ticket as an epic to sketch out the full plan for a feature and link related tickets to it....

January 1, 2024

Reminiscing CGI scripts

I’ve always had a thing for old-school web tech. By the time I joined the digital fray, CGI scripts were pretty much relics, but the term kept popping up in tech forums and discussions like ghosts from the past. So, I got curious, started reading about them, and wanted to see if I could reason about them from the first principles. Writing one from the ground up with nothing but Go’s standard library seemed like a good idea....

December 25, 2023

Debugging dockerized Python apps in VSCode

Despite using VSCode as my primary editor, I never really bothered to set up the native debugger to step through application code running inside Docker containers. Configuring the debugger to work with individual files, libraries, or natively running servers is trivial1. So, I use it in those cases and just resort back to my terminal for debugging containerized apps running locally. However, after seeing a colleague’s workflow in a pair-programming session, I wanted to configure the debugger to cover this scenario too....

December 22, 2023

Banish state-mutating methods from data classes

Data classes are containers for your data—not behavior. The delineation is right there in the name. Yet, I see state-mutating methods getting crammed into data classes and polluting their semantics all the time. While this text will primarily talk about data classes in Python, the message remains valid for any language that supports data classes and allows you to add state-mutating methods to them, e.g., Kotlin, Swift, etc. By state-mutating method, I mean methods that change attribute values during runtime....

December 16, 2023

Finding flow amid chaos

Despite being an IC for the bulk of my career, finding my groove amidst the daily torrent of meetings from the early hours has always felt like balancing on a seesaw during a never-ending earthquake. Now, pair that with the onslaught of Slack inquiries and the incessant chiming of email notifications, and you have a front-row ticket to the anxiety circus. There are days when carving out a single hour of focus time is a wild goose chase, pushing me to work after hours to get stuff done, followed by a guilt trip about screen-gazing my life away....

November 25, 2023

The diminishing half-life of knowledge

Ever been in a situation where you landed a software engineering job with a particular tech stack, mastered it, switched to another company with a different stack, nailed that too, and then found yourself in a third company that used the original stack? Now, you suddenly sense that your hard-earned acumen in that initial stack has not only atrophied over the years but also a portion, or all of it, has become irrelevant, making it a bit of a struggle to catch up with the latest changes....

November 12, 2023

Oh my poor business logic

Adopting existing tools that work, applying them to the business problems at hand, and quickly iterating in the business domain rather than endlessly swirling in the vortex of technobabble is woefully underrated. I’ve worked at two kinds of companies before: One that only cares about measurable business outcomes, accruing technical debt and blaming engineers when no one wants to work with their codebase, ultimately hurting the product. Another that has staff engineers spending all day on linter configurations and writing seldom-read RFCs while juniors want to ditch Celery for Kafka because the latter is hip....

November 5, 2023

Pesky little scripts

I like writing custom scripts to automate stuff or fix repetitive headaches. Most of them are shell scripts, and a few of them are written in Python. Over the years, I’ve accumulated quite a few of them. I use Git and GNU stow1 to manage them across different machines, and the workflow2 is quite effective. However, as the list of scripts grows larger, invoking them becomes a pain because the tab completion results get cluttered with other system commands....

October 29, 2023

Footnotes for the win

There are a few ways you can add URLs to your markdown documents: Inline links [inline link](https://example.com) This will render as inline link. Reference links [reference link] Define the link destination elsewhere in the document like this: [reference link]: https://example.com This will render the same way as before, reference link. Footnote style reference links footnote style reference link[^1] Define the link destination using a footnote reference: [^1]: https://example.com This will render a bit differently with a clickable number beside the origin text that refers to the backref at the bottom of the document....

October 7, 2023