Successfully Merged Polling Mixin PR
This week, I successfully merged another pull request into the develop branch, which focused on fixing and restructuring the polling mixin implementation across controller files. The restructuring process helped make the controllers more organized and consistent compared to before.
Working on Debounce LLM Buttons
For the rest of the week, I mainly focused on a new task:
Task: Debounce LLM Buttons
At the beginning, I drafted a mockup/prototype for how the feature should behave:
- Disable LLM buttons immediately after click to prevent repeated requests
- Re-enable buttons automatically after response is received
- On
429 quota exceedederror, disable the button temporarily based on Gemini retry duration - Add cooldown countdown indicator
- Apply changes only to
mark_page.dart(the page that uses LLM calls)
Initially, I implemented it using a scary red error message. However, after reviewing my implementation, Dr. Shawn advised me to improve the user experience because displaying error messages directly to judges could create panic or confusion.
Instead, he suggested:
- using a red icon indicator
- greying out the button
- adding a badge/countdown rather than displaying technical errors directly
After that, I changed the implementation to use:
- a red disabled icon
- a countdown badge during cooldown
- automatic re-enable once the cooldown finishes
This approach creates a much cleaner and friendlier UX for judges during the competition.
Biggest Lesson This Week — Clean Architecture Matters
Another important lesson this week came from handling the Gemini API error response.
At first, I tried processing the error by searching strings from the message text itself. However, Dr. Shawn explained that this approach is fragile because:
- human-readable messages can change anytime
- formatting may differ
- language may not always remain the same
Instead, I learned to process the structured JSON fields directly, such as:
codestatusretryDelay
This is much safer and more maintainable for production systems.
Dr. Shawn also explained the importance of separating responsibilities properly:
- Controller → handles business logic and Gemini API processing
- Widget/UI → only handles visual display and interactions
This means:
- the controller detects quota errors and extracts retry duration
- the widget only reacts to a custom state or exception and updates the UI
I realized that this architecture is important because if the AI provider changes in the future (for example from Gemini to Cloudflare), only the controller needs modification while the UI can remain unchanged.
What I Learned
Through this task, I learned:
- how debounce mechanisms prevent users from spamming API calls
- how to properly handle quota/rate limit errors
- the importance of separating business logic from UI
- why clean and maintainable architecture matters in real projects
- how structured API responses are more reliable than string processing
This week helped me understand software engineering concepts more deeply beyond just making the feature “work”.
Looking Ahead
For next week, my plans are:
- Fix the LLM button implementation according to Dr. Shawn’s feedback
- Start the next task:
Migrating QR Scanner from HS256 to ES256 JWT Verification - Perform testing using participant confirmation-slip QR codes during the upcoming event at Sunway University on 23rd & 24th May
Hoping to continue improving both my coding quality and development speed moving forward.
0 Comments