Simplify, simplify, simplify!
Henry David Thoreau
If there’s one thing I should know by now in my life, it’s that I am an over-thinker. You’d think someone who thinks so much would think about the fact that overthinking is not helping, but it turns out it doesn’t work that way. This plays out in programming projects sometimes by way of me overcomplicating or over engineering a solution that doesn’t need to be nearly so complex.
This week was a perfect reminder of this lesson: to always ask yourself, “Can this be simplified?”
In our app, Bridge, comments are stored in Firestore and displayed on the screen through a StreamBuilder. The StreamBuilder is a widget which builds itself based on the latest snapshot of interaction with a stream. And a stream is a source of asynchronous data events, such as a changing Firestore collection. This all works dandy and our list of comments update instantly when is adding or upvoted/downvoted. I ran into a problem however, when I needed a piece of a comment – a User’s attribute – to update instantly when it was edited on their Profile Screen. Because the stream was ‘listening’ to a Comments subcollection, and not the Users collection, it didn’t know or care when a User updated their attribute. In true overthinker fashion I latched on to this concept of streams and proceeded to spend an inordinate amount of time researching different Flutter package dependencies for merging and managing multiple streams. I tried a couple options, adding them to the pubspec.yaml, changing up all the existing mapping and work done on the original stream. I could never get it to work, and making one thing work seemed to break something else. Eventually I thought, hey, maybe I don’t need to mess with the streams at all, maybe I’m overthinking this.
As soon as I let my brain step back, get out of tunnel-vision, and re-assess, I realized there was no need to be constantly getting a snapshot of the Users collection, like the stream does. I could just make the widget that displays a single comment be stateful, and put a query getting the author of the comment’s attribute (if any) in a function called in initState(). At first I couldn’t quite figure out where I would call setState() to trigger the widget tree rebuild. Normally, there would be some sort of interaction, like a tap or swipe to trigger this event, but I just wanted a rebuild when the user navigated from the Profile Screen back to the previous. For some reason I thought this was something that was already happening implicitly through Navigator.push(), Navigator.pop(), etc., but it’s not. I still don’t completely understand how some of the inner processes work, but I decided to try calling setState() right after pushing the route to the Profile Screen. I figured when the Navigator popped back, it would immediately run into this setState(), which would make the comment widgets rebuild. And it worked! Like a charm. I don’t know if it’s the most conventional method for accomplishing my goal, but not only does it work, but it is far easier than merging streams.
Moral of the story: always try to simplify your approach. Ideally, before spending hours going on a deep dive into a complex, yet only potentially workable solution! Happy Coding!