---
layout: post
title: "Zap-It ⚡: Product mindset in action"
excerpt: >
  Leverage a "product mindset" to pick side projects, minimizing output and
  maximing impact. Here we build a minimal URL-to-RSS web-app and its iOS
  client.
categories: [articles]
related:
  - _micros/pocket.md
---

### The product mindset

If you are like me, you'll feel a constant _tension_ between all those new cool
side-projects ideas you have and the other things competing for your
time/attention (work™, for instance).

I find it pretty useful to filter things off through a _product mindset_ to
decide what to do next. This blog post tells how I leverage such mindset.
Typically, things (aka "product discovery") go through a feedback loop:

1. Identify one or more opportunities (find users' pain).
1. Prototype a minimal solution and test it.
1. Gather feedbacks and iterate.

In most cases, side projects ideas will sparkle from _my own pain_. _I_ will be
the early adopter, but also the builder. "Business"-like pressure comes from the
limited time I have to work on side things. This means I need to minimize how
much I invest (_output_, time, lines of code, architectural stack), while
maximizing _impact_. Doing just bare minimum to solve the perceived pain.

### The opportunity: Quickly save things for later

I love reading blog posts and web articles, and I love doing it through RSS
feeds.

Sometimes, I'll find a promising (but _long_) read on the web. I'd like to
_store_ it somewhere so that I can read it later. And I'd like to do it
_quickly_, from my phone. There are a lot of archival/bookmarking tools out
there that do that.

For instance, I have self-hosted [Wallabag](https://www.wallabag.it/en) for a
while. I could use the iOS Wallabag app to add new entries for later and then
consume them through Wallabag's RSS feed. So far, so good. The problem was that
performance was _abysmal_. I experienced _tail latencies_ of 60 seconds or more
when adding new items. Worse, the UI of its iOS mobile app would be _blocked_
for that long, waiting for server-side confirmation.

### A minimal solution: URLs to RSS entries

The bad I/O of the machine hosting Wallabag was most likely what caused my
troubles with it. As Wallabag receives a new item, it fetches its content,
process it, and make it available for reading. All this happens on a foreground
process that, on the hardware where I was running it, was really _slow_!

Thinking more about this, I realized I didn't really need to do things
_synchronously_. In fact, most times I'll save something and read it only after
a _lot_ of time has passed. In addition, [Miniflux](https://miniflux.app) -- the
feed reader I use -- provides [support to "Fetch original
content](https://miniflux.app/features.html#content-manipulation)" through
background workers.

So, a minimal but good solution that works for me only needs to:

- Map URLs to RSS feed entries.
- Provide an iOS client.
- Be _quick_!

Miniflux will take care of the rest by consuming the feed entries, fetching
them, and making them available to [clients](https://reederapp.com).

### Zap-It ⚡

Here comes [Zap-It ⚡](https://github.com/aldur/zap-it): I saw the opportunity
to build something _very small_ that does one thing only, but does it well.

Zap-It reads web entries (a `link` and a `title`) from a REST API, stores
them in a `sqlite` database, and serves through an RSS feed. That's all! Even on
a potato-powered machine, it runs fast enough.

This philosophy makes it minimal and doesn't reinvent the wheel. For instance,
Zap-It doesn't implement access control, but delegates it to existing and
battle-tested solutions (the [GitHub README](https://github.com/aldur/zap-it)
provides a few examples).

Full disclosure -- I confess that I also _wanted_ to build this to:

- Experiment with Rust (obligatory 🦀)
- Start learning [Nix](https://nixos.org) (what all cool kids use these days)

### E2E delivery: iOS shortcuts

You might be thinking:

> OK, that's definitely minimal. But what about the iOS client?

Here comes [Apple
Shortcuts](https://support.apple.com/en-gb/guide/shortcuts/welcome/ios) -- poor
men's iOS client.

In short, shortcuts let users build small programs through a no-code UI. They
provide different integrations, they accessible from the iOS share sheet, and
can take what's currently on-screen as an input.

All this makes shortcuts _perfect_ to build small, context-aware, clients
interacting with light APIs. The UX is also pretty good too -- sometimes better
than native apps.

It's easier to show than tell:

{:.text-align-center}
![Using an iOS shortcut to save one of the articles of this blog.](../images/zap-it.gif){:.centered}
_The pleasure of seeing it run, and run fast!_

You can find the resulting shortcut
[here](https://www.icloud.com/shortcuts/83d641e49edc41858210d87f4eca6c33).

### Wrapping things up (and looking back)

Building Zap-It took time, of course. It would have been faster for me to code
it in Python instead of Rust/Nix. But there's pleasure in learning new things
too and not everything must be optimized.

Looking back, I should have spent a little more time at the design board.
For instance, the first iteration didn't require a `title`, but would render
entries through their raw URL in the feed reader -- not nice.

Thinking about outcome instead: so far, Zap-It serves me well. I use it multiple
times per day. It's fast, and its UX doesn't get in the way. The iOS shortcut
works well and it's reliable.

More importantly, it is a _finished_ side project. It is minimal but has all I
need. While building it, I had such a goal in mind. Focus on the end-to-end
flow, don't get bogged down in technical rabbit holes, think about impact.

I think that went pretty well!
