What I did this week #1a - Technical Summary
This is a more technical summary of the main things I covered this week. In addition to the below, I setup a Chrome Extension that automates some manual work (uses Claude to summarize on-page content) and a Streamlit project that helps evaluate RE investment deals, but I don't have time to write those up.
List Assist
1. Moved from on-device storage to Supabase
- Using the iPhone's local storage is great for testing and iterating quickly. It's probably also fine for applications that don't need auth or data persistence.
- Since my app will require both of those, I needed to move to the cloud. This would also allow me to more securely use API keys for the AI model without exposing them to the client/storing it within the app itself.
The Claude Sonnet 3.7 x Cursor Agent combo is a runaway mine train
- It's thrilling, but one wrong move can lead to a world of pain. The best way I can describe this combo is that the model is a SUPER eager employee. It will take your prompt, execute on it, then build on what it's executed. The sheer volume of code generated it hard to keep up with, but it does tend to work.
- Now that's great if you're starting a fresh project or working on something that doesn't require understanding the ins-and-outs, but for something already in flight it can lead to a lot of issues. The model doesn't know all history, rationale for decisions etc., and may not remember to read certain files so can easily miss important context. For me, this led to a bunch of additional complexity, some over-engineering, and unnecessary code.
- I let Cursor Agent guide me through implementing the Supabase config, connect the app to the database, and setup the data/image storage. It did this in a single session; impressively quick.
- However, I spent a couple days trying to get my head around the architecture that it had decided to implement. The setup was a little different than I was used to; it added multiple layers of abstraction by storing function imports in a dedicated api file and created a bunch of helper functions in separate utility files.
Prompting is everything, lesson learned (again)
- While 3.5 was less 'powerful', this actually led to some better outcomes, when using Cursor's Agent mode, at least. With less power, less initiative, the model leaned on the user more. This allowed you to more easily track and course correct.
- As these tools continue to become more powerful, I think we'll see more 'forced' stops and checks, in the interim at least (until we can fully trust the autotonomous system). With all that said, even with these issues the 3.7 x Cursor Agent combo is uber impressively powerful. Like with many things AI, this road also lead to needing better prompting; more specificity on how you want the model to behave will, I'm sure, lead to better outcomes.
2. Setup optimistic UI patterns & backend config
- Another big focus for this week, once the storage was migrated from Local to Supabase, was managing the change in UX to support cloud-based storage. When everything was stored locally, the app was zippy; there was very little load time between actions or screens because everything was already available on device.
- Moving to the cloud means I need to regularly transfer data between a server that's somewhere in the US and my phone, which is somewhere in the UK.
- A quick improvement to the UX was to add some state management with loading and progress indicators, like on app startup or processing data/results.
- Other changes required changing the architecture and order of operations. For example, I now only loading the minimum of what's needed the home page, instead of loading all user data immediately. In this vein, I want to add some progressive loading and pre-fetching of data that's likely to be accessed to make the experience even smoother. I've also implemented some local caching of items from the database using React Query. I'm actually surprised at how simple this library made this process.
- There's still a whole bunch to optimize for the processing, but the main building blocks are in place now.
Create a better UX by de-coupling backend operations from the UI
- The user doesn't need to know all the things that are happening in the backgound. Things should feel instant, always.
- The biggest sin is to make users 'wait' for things to process; the user should be able to continue their workflow while you handle the processing the background. The only time loading screens should be allowed is when the results of the load are needed in the immediate next step the user's about to take.
- This requires some more work, managing states/triggers/timing effectively, but it's needed to give users a buttery smooth experience.