Making Some Progress on My RSS Reader

I've started numerous RSS reader attempts over the years. I revisited my tradition of starting an RSS reader a few weeks ago, but this time I may have broken the cycle. It's possible that soon I'll want to use this day-to-day. To celebrate the occasion, I wanted to write down what's appealing to me about a project like this.

My goals with this project are: have a usable RSS reader; have a project that can act as a vehicle for experimentation; and continue writing and maintaining software that I use every day.

a usable RSS reader

This is the minimum functionality that counts as "usable" to me: I can subscribe to new RSS feeds, have them refresh automatically, see posts in chronological order, and click on a post's title to open the page in my browser. The overall flow is: the landing page is a list of feeds I've subscribed to and a two-part form to add a new feed. The first part is a single text input field that accepts a feed URL. The second part acts as a kind of validation step: it displays the details of the feed (or an error message) and has a "save feed" button. Feed items can be seen by clicking on the feed title.

I've decided to avoid features like showing the number of unread posts or grouping feeds into different folders or supporting podcasts. I imagine they'd be fun to handle later, but I don't think they're necessary right now and I'd like to use this reader for a bit so I have some "user feedback" for myself.

a brief overview of the pieces involved

I picked Tauri as the overall application framework because I wanted the application to be primarily local. I know there are ways to do this entirely within the browser, but Tauri seemed to mimic the kind of front-end/back-end web development structure that I'm already familiar with. I'm using an existing RSS parsing library to actually read RSS feeds and I'm using SQLite to store data. All HTTP requests and SQLite interactions happen within Rust, with Tauri providing the bridge between Rust and TypeScript. Within the Rust back-end, I'm using tokio-cron-scheduler to schedule refresh jobs for all my subscribed feeds. I developed a small headache trying to wrap my head around async closures, but otherwise it wasn't too bad to set up.

I'm using TypeScript and Lit for UI development. I was originally planning to do this without any kind of frontend framework, but when I went to reach for web components I decided to try Lit, since it uses web components under the hood while providing some modern nicities. One day I might replace it with vanilla web components, but Lit's been easy and enjoyable to work with. The hardest part so far has been figuring out the TypeScript config.

a vehicle for experimentation

Another motivation for this project is that I'd like to have some kind of non-trivial program that provides even a remote excuse to try out certain things. Some such things are local-first software, UI development, and Rust's type system.

I don't think this really counts as local-first software since there's so little that's actually saved to my device, but I think this provides an opportunity. I could try to save web pages locally to read later, or I could try syncing state across devices. One example I think about often was when I used Joplin for taking notes. I set up a Dropbox folder to sync data between desktop and mobile and pretty much never thought about it after that initial set up. I'd like to try something similar here, since Tauri apparently supports building mobile targets (I have no idea how big or small of a task that is, though).

I'd also like to develop my UI design and implementation skills. The majority of my frontend programming occurred during the days of Angular 1. I didn't know what Flexbox was; I was floating left and right. I currently fumble my way through any UI I need to create, and my minimalist web aesthetic is as much driven by a lack of skill as it is personal preference. Using Tauri allows me to think about design while figuring out what frontend development is like in 2024, not 2014.

Regarding Rust's type system, I'm trying to learn more about how Rust models low-level system abstractions through the type system. To me, this includes things like lifetimes and ownership. In general, my experience with Rust is that it doesn't try to hide complexity but rather that it aims to give programmers a realistic toolkit for managing it. This has never been clearer to me than in the async realm, where one must deal with what it means for data to be available across threads or how code should suspend execution to let some other code run. I still don't have a comfortable grasp of async Rust, but this project has given me an opportunity to jump in and try.

Aside from async Rust, I've also tried to take advantage of a type system that lets me be more specific about program state. A few months ago I came across this post on Rust types for database-related code and wanted to try it out. With these, I can specify something like "this RSS feed might not exist in the database yet", which is tremendously freeing. These types do feel a bit clunky from time to time, but I really like that the type system handles these guarantees for me.

As far as other tech goes, I also decided to use Codeberg instead of Gits Hub or Lab, but I haven't used it for anything other than git push so I can't say what it's really like. Seems fine so far.

writing and maintaining the software I use every day

Last year, I wrote a cli for Dropbox. At the time, I thought it would be another project that sat in a git repo and accumulated dust. Instead, I use it all the time! It feels freeing to use something I made, to feel like I've acutally made a tool instead of a toy. If I use this reader as much as I use that little command-line client, I'd consider this project a huge success.

Another benefit to writing and maintaining my own software is that I can go at my own pace. I can be as rigorous or relaxed as I'd like. I am the target audience for both the application and the codebase. for instance, if I don't think I need to see a specific error, I'll just catch it, do nothing, and move on with my life! At the same time, if I want to go wild and look into whether it's feasible to extend Litestream to write to Dropbox, who's gonna stop me?

And lastly, building these things on my own helps me build up my product management intuition, as I continue to think critically about the software I use and how I could improve it.


The code for this project can be found here: https://codeberg.org/rors/r2s2/