I had to make significant changes while integrating the backend, specifically regarding how I generated IDs and returned objects to avoid duplication. I initially allowed users to provide their own IDs for ease of use, but I later realized this was a mistake. Even using UUIDs felt like the wrong approach for this specific project. I ultimately decided on a prefixed ID strategy (e.g., a1, a2 for authors; b1, b2 for books). I spent a lot of time going back and forth on this issue, which required major changes to my controllers.
I utilized server-side validation primarily but used client-side validation in conjunction with it, specifically to check if an author was a duplicate. If I had relied only on server-side validation, I would have compromised the user experience regarding duplicate management. The current approach allows me to enforce data integrity on the server while providing immediate feedback on the client.
State Management was a primary struggle. I was (and still am) often confused about whether to utilize useEffect multiple times or consolidate them into one, and which variables are best declared as state variables. However, I thoroughly enjoyed the component architecture—being able to create distinct components and easily reuse them made the development process feel modular and efficient.
I prefer React. Although I initially believed it was difficult, once I acclimated, it proved to be an easier way to achieve the same results compared to the manual DOM manipulation we did in CS375. The main trade-off is the need to carefully manage how many times the application re-renders, which is different from simply writing a function and executing it directly.
Using types and Zod was incredibly helpful for catching bugs and defining schemas. I didn't find the typing process too difficult; it was helpful in allowing me to clearly define what my objects and requests should look like. Having the skeleton code for widgetSchema also made this process significantly easier.
I used LLMs to write parts of the code, specifically for refactoring and debugging. I would often ask questions iteratively and follow the examples provided to correct my logic. They definitely made the process more fun. While I am not sure if they saved me time, they allowed me to pursue errors to their absolute depth, ensuring I understood the root cause.