joshuacerdenia

NiceFeed: Updating all subscriptions at once (And, picking up Python)

Per my earlier post, I had a nice break last week from working on NiceFeed while my internet was unusable. However, the plan to stay away from my computer turned out to be a miserable failure, and I decided instead to learn Python. I used Python Projects for Beginners: A Ten-Week Bootcamp Approach to Python Programming by Connor Milliken except instead instead of 10 weeks, I gave myself one. Of course, the real test is what to do with it now—I’d been planning to learn Django and pick up some backend skills, but the chapter on introductory data analytics really got my wheels spinning… We’ll see.

Anyway. A NiceFeed user emailed me about possibly adding an option to update all subscriptions at once. Up to this point, the closest thing I had was a background worker (via WorkManager) that cycles through all existing subscriptions but only updates one subscription every 15 minutes. If it finds any new content, it posts a notification displaying the most recent entry found. Needless to say, if a user has many, many subscriptions, it would take a long time for a full cycle to complete.

We want the app to be able to update all subscriptions in one move. This means quickly looping through every one of them, each time requesting the subscription URL, identifying any new content, and saving it to the database. To do this, I created a new CoroutineWorker class that does the following:


private val repo = NiceFeedRepository.get()
private val feedParser = FeedParser(repo.networkMonitor)

override suspend fun doWork(): Result {
    val feedUrls = repo.getFeedUrlsSynchronously()
    if (feedUrls.isEmpty()) return Result.success()

    for (url in feedUrls) {
        val currentEntryIds: List<String> = repo.getEntryIdsByFeedSynchronously(url)
        val feedWithEntries: FeedWithEntries? = feedParser.getFeedSynchronously(url)

        feedWithEntries?.entries?.let { entries ->
            val newEntries = entries.filterNot { currentEntryIds.contains(it.url) }
            val entryIds = entries.map { it.url }
            val oldEntryIds = currentEntryIds.filterNot { entryIds.contains(it) }
            repo.handleBackgroundUpdate(url, newEntries, oldEntryIds)
        }
    }

    return Result.success()
}

From there, it’s simply a matter of feeding it to WorkManager, which I’ve set to run the worker once a day. I’ve also added the option (via Snackbar message) to run the worker whenever new subscriptions are imported by OPML, since OPML only imports minimal feed data, without any entries. Now we are that much closer to a standard feature of most respectable RSS readers. I find that I enjoy “background” code like this much more than designing and creating the user interface… Hence, I’m still undecided as to whether I should also add a button to allow the option of running the worker whenever the user wants, rather than just on schedule. Thoughts for another day.

FizzBuzz, part 2: A fancier way

Piggybacking off my earlier post, because I have an obsessive personality I couldn’t help thinking of fancier, if more convoluted, ways to write FizzBuzz. I didn’t like the fact that I had to write the modulo operation and “Fizz” and “Buzz” more than once each. I came up with many variations of the code below (once again, in Kotlin):

val map = mapOf(3 to "Fizz", 5 to "Buzz")

fun main() {
    for (i in 1..100) {
        val fb = StringBuilder()
        map.forEach { if (i % it.key == 0) fb.append(it.value) }
        println(if (fb.isEmpty()) i else fb)
    }
}

Here the code uses a map (a set of key-value pairs) to establish the required relationships: 3 to Fizz, and 5 to Buzz. The outer loop, counting 1 through 100, is the same as before. We initialize an empty StringBuilder, and then start a second, inner loop that goes through each of the two aforementioned key-value pairs in the map and checks it against the current number i. If the operation returns true (that is, i is a multiple of the key of the current pair in the map), the value of the pair is added to the StringBuilder. So, if the operation returns true for the first key-value pair, we get “Fizz.” If only the second, “Buzz.” If both times, we get “FizzBuzz.” And each of these words appear in the code only once. Finally, we check if the string is empty in the end, and if so we just print the current number.

I could just as easily have done string concatenation by first assigning an empty string to a mutable variable (var fb = ""), but for reasons I don’t yet entirely understand, StringBuilder performs better, especially when loops are involved. In a program this small though, nobody will notice… I think?

Another beauty of this approach is that if we wanted to, we can change the rules very easily. We can add a third key-value pair to the map, maybe 7 to “Fuzz,” or use a different map entirely without rewriting anything else. Okay, I’m done with FizzBuzz now, moving on.

NiceFeed: An update, and taking a break

Due to current widespread disruption of internet services in the Philippines, I am taking a short break from NiceFeed through the end of the month, and plan to use the time to… stop staring at my computer screen all the time. But I’ll try to address somewhat urgent issues should they arise. 

Just today, a user wrote me about a crash in Android 6.0. I found the cause to be a few image resources that were mistakenly not accessible to API level 23 and below. Sometimes you get caught up in getting things right in all the obvious places, while big mistakes happen where you didn’t expect. After much fighting against my internet connection, I managed to roll out a quick update. It should be out on Google Play in a few days.

Also, the app has just been added to the IzzyOnDroid repo for the benefit of users outside the “walled garden”—as it has been described—of the Play Store (thanks for picking it up, IzzyOnDroid!). I appreciate the handful of users who have been trying out my app and taking the time to let me know of any issues or suggestions.

FizzBuzz: An intermezzo

Scaring myself with the revelation that many would-be developers ostensibly cannot write FizzBuzz, I became anxious to know if I would pass the test. The task is to write a program in as few characters as possible that will print the numbers 1 to 100 each on a new line, except multiples of 3 become “Fizz,” multiples of 5 are “Buzz,” and multiples of both 3 and 5 are “FizzBuzz.” As it turns out, the solution is nice and short in Kotlin:

fun main() {
    for (i in 1..100) { 
        println(when {
            i % 3 == 0 && i % 5 == 0 -> "FizzBuzz"
            i % 3 == 0 -> "Fizz"
            i % 5 == 0 -> "Buzz"
            else -> i
        })
    }
}

The overall logic is simple enough, just a plain old loop through 1 to 100 and conditionals to determine what to print. But I had to think for a second to remember the modulus operator… Here it means that when i is divided by either 3 or 5 and the remainder is 0, then it is a multiple of 3 or 5. I wonder if there’s an even more concise way to do this.

The when conditional makes things neat, instead of nested if/else if statements. i % 3 == 0 && i % 5 == 0 needs to come first, or else the program will print “Fizz” as long as i is a multiple of 3, regardless of whether it is also a multiple of 5. And so on. Another thing is that if i weren’t pressed for characters, I would maybe write "$i" in that else branch instead of just i to be consistent with the preceding branches, which all result in strings. But this appears to be a non-issue.

In the beginning was the Hello World

I have a friend who is a foreign policy expert who started out his career in theater. He’s always saying, “Everything I know about foreign policy I learned in the theater.” Someday I want to be able to say everything I know about software development I learned from music. Even at this stage the intersections are pretty obvious: logic, creativity, architecture, scalability, the balancing act between making end users work as little as possible and implementing complex features (either because they are needed, or… just because you can), etc., etc.

I enjoy personal, stream-of-consciousness writing but I want to keep this blog strictly about my coding projects. So this is the only bit of a background I will give for now: I picked up Android development early this year (around the time coronavirus started becoming a thing) and was instantly hooked! My weapon of choice is Kotlin. I’m not quite new to programming in general; I’ve had many false starts since I was a wee lad and my education in music included a considerable technological component (such as CSound and especially the visual programming environment Max/MSP), though I quickly became bored because I found myself not that interested in the musical results. Instead I devoted myself to large orchestral pieces—where I learned everything I know about managing a complex, jumbled mess of a project from start to finish and shipping it (literally, shipping like 50 or so instrumental parts to an orchestra), hoping you didn’t make one mistake in one part that could derail the whole thing. Kind of like programming, except with software you’re allowed to constantly release updates.

Anyway. Last week I released my latest app NiceFeed for open testing on the Google Play Store. NiceFeed is an RSS feed aggregator and news reader. I know RSS is an old, “undead” technology and there are already many similar apps out there, but I haven’t been too interested in many of the similar top-downloaded ones on offer. This is not intended for power users, we already have Feedly, etc. for that, but for people like me who want something nice to look at and won’t make them work too hard. I’ve had a lot of fun, as well as many frustrations, working on this app over the summer months and learning as I go. If anybody at all comes across this blog, I would love it if you could give the app a try (Android only for now… sorry!) and let me know what you think, maybe even open up an issue on my GitHub

Future posts here will be about continued development of NiceFeed, trying to solve issues I come across, etc, as well as other Android projects as I start them. Everybody says to blog as you learn, so I’m taking the bait. In the future I may also write about some other languages and tech stacks I’m interested in. I have my eyes on Flutter, as well as Python and Django. I also dabble intermittently in Arduino. Until then… banzai!