To Refactor or Not to Refactor…

That is the question. And the answer is yes. Do it.

As we’re nearing the end of the term, and our Capstone projects are coming into something close to their final forms, I’m putting my focus and attention on refactoring. While I came into our project with knowledge of Flutter and Dart, it certainly was not advanced, and was constrained to the specific techniques taught in the Mobile Development class here at OSU. The unique requirements of our project, using Firestore in a much greater capacity, and developing on a team have resulted in a great deal of new learning.

One side effect of learning something new is that it’s not usually perfect the first time. And by not usually I mean almost never. So the code I have needs work. It’s accomplishing what it’s supposed to, but in terms of being DRY, of functions being short and doing one thing, and encapsulating code to avoid unnecessary dependencies, there is work to do. Part of the learning curve has been understanding Firestore, and the best way to write queries, and read and write data. Part of the refactoring work to be done will be to make sure I’m doing these database queries and writes consistently and efficiently. Then, having made sure that component is done well, I will take a look at the structure of my dart files, try to keep my model classes purely dart, and put other functions and classes in the most appropriate places. 

Aside from Firestore interactions, I’m hoping to make sure performance is most efficient by extracting widgets to their own classes, so that the build methods do not become over-encumbered with functions needlessly being rebuilt. Lastly, making sure conventions, line length, and comments are consistent across our program will be a priority.

While there is plenty to be done, I do find myself happy with how far I’ve come since the early days of my time here in the Online CS program. The quality between now and my first forays into programming is dramatic, and I can differentiate between quality code and poorly written code. And when I need to refactor I recognize the process for what offers – simply another opportunity to learn and improve. 

Don’t overthink it.

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!