I played with a lot of toys when I was younger. As time passed, I bought less toys…but I still feel like I’m playing with toys.
I suppose, instead of buying them, I build toys now.
Freshmen year of college, I met a lot of people. My Facebook friends list saw a growth spike, as did those of the people I met. For simplicity, let’s say I received W birthday wishes on my Facebook wall on my next birthday after college started.
Due to the demands of school and my own desires, I met less and less people and I met with less and less friends from that initial group. As a result, I received fractions of W birthday wishes on the following birthdays.
A thought I had when thinking about this observation:
“Suppose I was a person who unfortunately based my self-esteem on the number of people who post happy birthday messages on my Facebook every year. Additionally, suppose I am aware of the trend that meeting and interacting with less people results in less birthday posts. How would I go about maximizing the happy birthdays I received [within the domain of Facebook]?”
The thought began as a “What if…”, but the more I thought about it, the funnier of a hypothetical situation it sounded. My next shower was spent exploring how one could really go about this problem.
We have the relationship of “more interactions => more wishes”, so it makes sense to increase our interactions. One way to go about this is to simply wish others on their birthdays. Some people will wish you on your birthday because they want to genuinely wish you, others might wish you because they remember you wishing them on theirs and want to return the kindness.
Another idea is to physically meet and engage with more people than we do currently. However, this approach is constrained by our finite energy and time. We could very well host massive potlucks every month, rotating out the guests in a way that optimizes how many unique people attend and how repeatedly we interact with each person to improve our chances of receiving a birthday wish, but this introduces more logistical issues.
To keep our problem simple and focused for our own sake of simplicity and focus, let’s apply a constraint of minimizing our own interactions.
Now, the problem can be restated as,
“How do I maximize my birthday wishes with respect to the force of ‘I wish you-you might wish me too’ while minimizing my own efforts?”
The best idea that stuck was to automate the process of us posting happy birthday wishes to the walls of our Facebook friends.
Have we gone too far with using code to automate processes? I say yes, but I also take lengthy showers, so we must keep going.
A generic description of the solution: A tool that would check Facebook each day for that day’s birthdays and then post wishes on their walls without any input from me beyond construction of the tool. So…how do we do this?
My first idea was to create a Chrome extension that would run once every 24 hours. The idea was to make an HTTP request to Facebook, scrape the returned webpage data for the HTML that corresponds to the little birthday button on our home page, parse that data for the names of today’s birthdays and then programmatically post the wishes to their walls.
Sounds good, but this idea had a few issues:
• I need special permissions (CORS Headers) in the Chrome extension to access the site data of a website that isn’t currently open in my browser.
Solution? Either I set up my CORS, or I keep the Facebook website open permanently. I had final exams to study for, so I was looking for a quick solution — I couldn’t learn CORS at the time and keeping Facebook open permanently seemed like a very distractive decision to make.
• I needed my computer to be open and logged on to wifi once everyday in order for the extension to do its job. I don’t like the idea of having to open my computer everyday strictly for this purpose — it doesn’t really minimize my own efforts, as we are looking to do with this problem, because I could just open my computer and type the wish out myself daily.
Solution? Create an AWS Lambda function with the necessary code and attach a CRON job so that it runs every 24 hours, but this wasn’t going to happen because of the above issue. Setting up the tool on an automatic server that runs regardless of my actions is the ideal solution, but is just not possible at the moment. No matter!
Next idea: Instead of collecting the webpage data, why not just use Facebook’s provided APIs? If Facebook already has some getTodayBirthday function, let’s just implement that into our script!
There wasn’t any getTodayBirthday function, sadly.
For me to receive the birthdays of my friends, I would have needed to create an app hosted on Facebook and then have all my friends authorize the app to collect their birthdate data. I’m not interested in pinging all the people on my friends list to have them authorize my app — that itself is a significant amount of work, but this solution would definitely get the job done. If I was interested and patient enough to go through the whole list, the problem would be completely solved…until I added new friends on Facebook.
This app built on the API would require me to request all future Facebook friends to authorize the app. As the friend list grows, so does my total work expended. We want to minimize work, so let’s keep thinking.
The idea I brought to life: Build an app on my phone that stores names, phone numbers, and birthdates, checks daily for that day’s birthdays, then sends SMS messages to the recipients.
This method isn’t issue-free, either, but the problems presented with a mobile app solution weren’t greatly debilitating:
Yeah, I still have to manually enter contact info for all the people I desire to keep in my birthday list, but this can be remedied by me handing my phone to people when I meet them with the app open. Less composite work on my side in terms of updating the birthday list as well as with remembering birthdays [because the phone will for me].
In terms of phone usage, I do have my phone on everyday, so I don’t have to worry about missing days should this habit remain. Suppose I decide to turn off my phone or I travel to some part of the world and lose data for a few days — I could add a few more lines of code that queue the recipients to message if SMS fails and have the app run through the queue once I’m back online.
E Z P Z.
As I use an Android phone and was working in time constraints, I decided to build the app in Android (Java and XML). Should I build a small tool like this again in the future, I’ll explore other mobile frameworks (such as React Native) to build the tool in.
Sure, of course, it would be easiest to use what I am most familiar with even in the future, but it is important to explore different technologies and frameworks in order to see what capabilities are present elsewhere. Maybe it’s easier to build certain apps with another framework? Perhaps I will see that Android is really the best way to go about building Android apps even after compromising the cross-platform ease offered with React? The only way to answer these questions is with experience, and so the value in exploration can be seen.
As Android Studio had it, the way my XML looked in the preview was a bit misplaced on my actual device. Classic Android, thank you for the warm welcome back. I decided that the misaligned input fields gave the app a sense of personality and decided to move on [after having spent significant time playing with the layout and alignment].
There were a few benchmarks we needed to meet to ensure that this app could work sufficiently on Android:
• Can I send SMS programmatically through Android?
• How should I go about saving the user data? What if I need to modify existing data, such as changing a recipient’s phone number?
• The app needs to run periodically, how is this implemented?
It didn’t take long to learn that yes, SMS can be sent programmatically, as well as how. Awesome! Let’s keep going!
One way of saving data to disk with Android is to write to Shared Preferences. I tried to learn sharedPrefs a year and a half ago, but it looks like Android documentation has gotten a lot better / I’ve gotten better at reading documentation because I was able to do now (implement sharedPrefs properly) what I couldn’t learn to do then.
Shared preferences ended up being a small disaster. With sharedPrefs, I can save Strings or a List of Strings to disk — the individual Strings were modifiable and can be overwritten but the Lists supposedly were non-mutable.
Suppose I add a person to the app. I save them as something like KEY:VALUE as DATE:PhNumber+Name, so I know whose birthday it is.
Let’s say I add another person who has the same birthday as another person. I would read disk and realize that I already have a sharedPrefs data for this date, so I can grab that existing person, add her/him and this new person to a list, and overwrite that sharedPrefs data with this list.
Now! If I want to add yet another person, I couldn’t! Because my list was instantiated with two individuals, it shall remain that way, existing only for me to read from. What will I do when I want to add at least three people to the same birthday? And what if a friend changes a phone number, how should I update the phone number when I can’t change the list?
Suddenly, on the scene, enters a new character: File input-output.
Using file IO, I can forego sharedPrefs altogether and instead create a .txt file for each day of the year. In that txt file, I decided to keep a format of one person’s data per line in the format Name/PhNumber. Now, in the code, I just open the file corresponding to today’s date, and while reading it line-by-line, SMS each recipient. Should I need to modify existing data, I can just open the file in a text-editor on my phone, manually overwrite whatever I want, and save the file. Very easy and convenient, compared to me having to set up an additional interface and functionality for editing if I had decided to keep Shared Preferences.
Finally, all we have left is configuring the app to run periodically.
I added a service activity to the app so that it can run in the background once turned on, but Android seems to have updated the way services work since I last interacted with them because I found my app’s onDestroy() getting called over and over and over once I would close the app.
Maybe my service was configured incorrectly? Whatever the case, I use my phone for an alarm, so I know there is a way to run periodic operations with Android.
Further digging brought me to the AlarmManger class. I just schedule an intent to fire at an interval of M milliseconds and that’s the show! Or, it had looked like.
One sunset and sunrise at a university library later, I could not get the alarms to perform as desired. My app kept getting killed off upon me leaving the app to go to the home screen or closing the app in the background, contrary to what I read online and in documentation. My implementation was definitely wrong and I was horribly tired, so I headed home.
On the bright side, I finally saw the sun after a few days of poor sleep-study scheduling habits. I enjoyed whatever vitamin D I could scrape naturally after relying on milk for so long.
To accomplish the periodic operationality, Samsung has a neat little app called Routines.
Using Samsung Routines, I can configure all types of processes to execute on certain events, such as the opening of an app when the phone clock reads a specific time. A hacky and opportune solution, but a simple solution it is.
A solution to the problem of optimizing birthday wishes to effort expended.
Is it an app? It looks like one, it’s built like one, and a dissection of it shows that yes, HappyBirthday is an app.
HappyBirthday doesn’t feel like an app, though. It feels like a toy, like a LEGO that once built, sits there as you wonder what to do with it now.
I still learned (sharedPrefs, file IO, design choices, …) during the build process, but this app is an unlikely candidate for my resume. Which is fine.
I built HappyBirthday because I wanted to, and I enjoyed doing it. It was fun and I look forward to doing something similar again. I wouldn’t call this software development, or computer science, or even a solution, even though the original purpose was to solve a problem.
This is just fun. Another manifestation of me in the having fun process. Any other name doesn’t justify what HappyBirthday feels to me.
I think that of everything, this is the most important. That HappyBirthday was fun.