Motivation
I moved up to SF in the summer of 2022. I didn’t bring up my car initially because the place we moved into didn’t have a dedicated garage. I was also hesitant about street parking, because around that time, SF was notorious for window smashes and car break-ins. I didn’t really know the neighborhood I was moving into, much less the fact that SF is very different neighborhood-to-neighborhood, so I decided to play it safe and leave my car at my parents’.
In July of 2024, my girlfriend moved up for a month for a medical rotation in Oakland. She had the option of paying out of pocket and living close to the hospital, or staying with me and bringing her car up. We both decided option #2 would be a bit more fun, so we drove her car up from the LA area to up here in SF.
Towards the end of the month, after a dinner, we parked near our home and didn’t really think much of it. The next day, she found a street cleaning ticket on her windshield, which she was pretty sad about. I had budgeted for 1-2 street cleaning tickets while she’d be here and told her it wasn’t a problem, it happens. I started to think more about why I had implicitly assumed that it was “just gonna happen,” and found myself a bit frustrated.
Other friends who had visited had gotten a couple of street cleaning tickets, my roommate had also racked up a couple during the years, too. It’s not fun for anyone involved — I don’t even think the meter maids that have to do a round a couple of minutes ahead of the street cleaners (which run at around 12-6 AM in my neighborhood) enjoy having to hop out of their 3-wheelers to issue citations.
I started to think about why exactly this happens. For the situation with me and my girlfriend, I simply was not familiar with the schedule in our area. Even though the signs are posted, the cleaning times are different, even on the 2 sides of a single street. I didn’t know much about what exact days and times street cleaning occurred on, and the one night I didn’t double check resulted in a ~90 dollar fine.
I started to look around to see what alternatives there were to look at the schedules near me and set up alerts. I found a couple, but for one reason or another I wasn’t happy with the options out there:
- Xtreet: Each click on a street line resulted in a cryptic modal pop-up, which didn’t result in a good user experience. Setting up an alert prompted me to log in or sign up, which I didn’t want to do for a site I wasn’t familiar with.
- Street Cleaning Parking App: Unfortunately this only exists for ios and not android. I’ve been an android user my entire life, and I needed to be able to access this info through my phone. Also, from the comments in the app store, it sounds like this follows a subscription-based model. I think this kind of an app should be free, more on this in a bit.
- Data SF’s Map of Street Sweeping Routes: This was the most promising. I was able to click on streets to view information, but as I used it more I realized there were 2 things missing:
- Streets would only show one of the sides’ information, not both.
- There was no way to set up notifications for reminders to move my car.
However, Data SF’s map made me realize that this data was all public. I had been doing some data engineering work at my current job and have always wanted to get a bit more familiar with the frontend side of things, so I decided to take a stab at it.
In terms of the design, I really liked this project: Name SF Streetsand wanted to use its design as inspiration for what I created.
The Requirements + Experiment
The high level requirements for usability, in my eyes, boiled down to the following:
- Streets should be clear to see and easily selectable
- Information about BOTH sides of the street should be available
- The focus of this would be to create an app that shows when the next cleaning would be, not to show the overall schedules
- Users should be able to set up some notification to move their car on time
And on the personal side, my main requirement was to make this free to use, and free to keep up. This is something I want to try to maintain in the projects I build (this blog is a good example: Setting up this blog). I think it’s really fun to find something to focus what you build around. For me, when I want to build things for personal use, that’s cost optimization.
I also wanted to make this a learning experience for myself. I decided on this:
- How well can AI build something like this?
- How well can I build something like this with the help of AI?
The first iteration of this app was almost exclusively built by Claude 3.5 Sonnet. I was prompting it with the format of the data, what I wanted to do, the steps I wanted to take, what the frontend should look like, etc. I put the code together and got this initial working version, which honestly I was really surprised by: Fully AI Generated Version.
At first glance, the AI version looked pretty good! However, it didn’t meet the full requirements and it had a couple of bugs:
- It wasn’t able to set up notifications
- Some streets had weird cleaning descriptions
- It was annoying to have to know the neighborhood name, clicking on the button, and then going back to the map
These were all a bit annoying, but the worst part of it was that I barely learned anything. I mean, I had expected I wasn’t going to really get anything out of it, but I realized that I actually didn’t know anything about what the code was doing. For the 4 hours I took to build this out, I was just copying and pasting code, and then telling Claude that something was wrong so it could find the error and fix it. That part sucked — I didn’t enjoy building something that had a usable end product, but not knowing anything about it.
So, the second part of this experiment was to build it out myself, with some support from AI. The data transformations were written mostly by me. I read through documentation, understood the data, and wrote the code how I understood it. Sometimes, when I ran into a bug that I wasn’t super familiar with and couldn’t find much info about, I caved and asked AI. At the end of the day, I understood what I was doing and felt myself actually using brainpower to understand and learn. Unfortunately, as I’m not a frontend developer, I relied heavily on AI to generate the frontend, but even then, I made sure to look over the code and understand what it was doing.
The result of the second part is the current site: sf-street-cleaning! I’m overall pretty happy with the end product and I see the ways in which this can grow. Even though the transformation code is absolutely not production-quality, it works well enough and resulted in a pretty usable end product. I’ll likely spend some time cleaning that up and optimizing it a bit more. I also learned how to work with geojson (which I think is a really cool file format), and a bit of JS (specifically working with maps, like leaflet and its python equivalent folium).
What do I gain from this?
I’m just happy to build and learn. It’s fun putting things like this together, and I recently had a thought about how to motivate myself to do more:
You spend the first 20 years of your life learning. Use that knowledge to do some good in the world. Help people, find ways to get involved, and make it a habit.
I want to make cool things, that people can actually use and enjoy. I think that’s staying true to being an engineer. While this may be a simple app, I see it as the first step to hopefully building a lot more. Thanks for checking it out, hopefully it’s useful to you, and feel free to reach out to me regarding what you’d like to see added!
The remainder of this will be a bit more technical:
Engineering / Usability Decisions
Surprisingly, I didn’t think a simple project would have so many different options and decisions to make. When I first started it, my thoughts were, “I’ll just take this data, transform it, load it into the map, and it should all work!” In actuality, there were some interesting thoughts I had, and I wanted to share a couple here:
How can I keep this free to use?
I have a backend engineering background, so the first iterations of this project was powered by a FastAPI backend. The backend served files for each neighborhood, so when users selected a neighborhood, the endpoint was hit and data was returned. I originally thought this would be the way to go because I wanted the requests to include the current timestamp. By doing so, I’d always be able to compute and show the next cleaning after the current time.
Unfortunately, the free tiers available on sites like Renderare not powerful enough to run the transformations I needed to (it’s probably doable, but Render has a timeout value that can be hit while your server is coming up). This is because I didn’t want to run the transformations on the fly, so I precomputed a bunch of data before the service came up and decided that I could just restart the service on a CRON schedule. However, since I couldn’t bring the server up in time, I had to shift focus.
I realized that, actually, I don’t need to use a backend for this. It’s just a static site. If I’m re-generating the data every day, I can leverage the fact that there’s at max 1 street cleaning per day. What this means is that I only need to maintain the NextStreetCleaningTime
and the NextNextStreetCleaningTime
. On the frontend, if the current time is after the NextStreetCleaningTime
, then display the NextNextStreetCleaningTime
.
This change enabled me to make use of github actions + runners instead. They have a bit more generous free tier, which is based on how many minutes of compute you use. Plus, the machines they use are a bit more powerful too. As of now, the data generation takes ~3 minutes at max, and github provides 2000 minutes free every month, so I should be in the clear.
How can notifications work for free?
This one was something I struggled with for a bit. I didn’t feel true motivation to work on this until I had figured it out.
My first thought was that for a notification service, I’d probably need to pay. Maybe there’s good free-tiers out there, but I didn’t want to risk a lot of usage resulting in an expensive bill. I knew that things like AWS Simple Notification Service existed, but I didn’t want to have to worry about all the infra/billing/etc. with setting up a cloud service account.
I started thinking about the notifications I usually get. Most are app notifications, but the main ones aside that are Gmail and Google Tasks Reminders. I started looking into how I could make use of the Google Suite of tools for a notification system.
Gmail has this concept of schedule-sending emails. I was hoping I could use something like that, but I needed to figure out how I could generate an email template. Turns out, Google allows users to create links that can open the “Compose” window: support thread. Unfortunately, there’s no way I could find to do that with schedule-sending emails.
I decided to look into other options, and the interesting one I stumbled on was Google Calendar, specifically this other post: support thread. I realized there are ways to create a calendar event from just a URL, and that’s what I’m currently doing!
This allows users to adjust the notification time to their liking, and it puts a block on their calendar for when the street cleaning actually happens, all while staying completely free.