Lessons from Building EmojiBar 🎉
This Monday, I shipped my side project — a Chrome Extension that implements a Slack-like emoji picker for Facebook Messenger (check it out here 👍).

Seeing it finished and on the Chrome web store it has extremely rewarding, especially taking into account all the roadblocks I encountered along the way due to my mistakes, inexperience, and lack of knowledge.
This article is an attempt to do some self-reflection on the difficulties and challenges I bumped into, and the valuable lessons I should learn and keep in mind from them.
#1 Do the hard thing first
I started off this project not knowing a lot of things — how Chrome extensions work or how to programmatically manipulate text in a HTML element on the DOM, for instance. Turning to Trello, I tried to break down the end goal — the product — into a concrete set of doable steps, ranked them in terms of ‘risk’, and then worked the ‘riskiest’ tasks first. To me, the ‘riskiest’ tasks were a) seemed really hard to implement, b) important to the product being able to exist at all.
I tried this approach because of a problem I ran into during a previous side project. It involved an OCR (optical character recognition) component, but I put it off after making a small prototype and didn’t fully implement it before moving to other components, thinking I could come back to it. Later on I realized the OCR component, which required precise handwriting recognition, was too difficult for me to work on at the time — existing APIs weren’t accurate enough, and my CS background in computer vision wasn’t strong enough. I had basically wasted a lot of time working on other parts of the project, when I should have validated the viability of the entire project.
This time around, I identified the two components of my emoji picker I was most unsure of how to do — reliably attaching my emoji picker to the right DOM node on messenger.com & facebook.com/messages, and performing emoji insertion (if a user types ‘:grin:’, the emoji picker would remove ‘:grin:’ on the text box, and insert ‘😁’). It turned out my intuition was right that those two tasks took the longest amount of time for me, mostly because I was least familiar in these areas.
To reliably attach my emoji picker, I had to Google around for a good solution before settling on using arrive, a small NPM package for watching the creation/removal of DOM elements. To perform emoji insertion, I had to first lean a lot about the Selection and execCommand browser APIs (shout out to Mozilla Developer Network for having amazing documentation).
Once I had these two pieces done, I also felt a lot more confident I could ship my project, particularly because I was much more comfortable with the remaining tasks. For example, I was confident I could build the emoji picker React component itself because I’d been working with React a lot in the past few months.
Basically, doing the hardest thing let me minimize risk and be more effective.
#2 Find the simplest solution
I’ve been reading Edmond Lau’s great blog/book The Effective Engineer and one of the lessons he talks about is ‘finding the simplest solution’. It’s been cool for me to read his writing and then see opportunities as I was working on the project to implement this lesson.
Lau talks about how the no. of users-to-no. of engineer ratio at Instagram at the time they were acquired was insanely high, and how they managed to support so many users with so few engineers by consciously building a culture where simple solutions were preferred to avoid future complexity down the line. Luckily, the story stuck as I was figuring out how to do emoji insertion. Since I wasn’t very familiar with the execCommand browser API, my initial solution was an unbelievably ugly and janky solution that involved hidden buttons, jQuery and multiple setTimeout calls. I knew it wasn’t an ideal solution, but I was feeling really frustrated and just wanted to move on to other parts of the project. However, I think the Instagram story made me keep thinking of how I could better implement emoji insertion in the background of my thoughts for the next week.
Embarrassingly (but fortunately), I later realized I could replace ~50 lines of ugly code with one clean, easy-to-understand line to implement emoji insertion.
document.execCommand(‘insertText’, emojiToInsert);
Another story Lau talks about is how Etsy spent months implementing infinite scroll on their search results page, only to find after doing a lot of work it didn’t really increase sales. This story came in handy when I was trying to decide whether to build a feature. When the user brings up the emoji picker by typing a colon, I initially wanted to show the user’s most frequently used emojis. I thought this was cool because a) most people only use the same 10–15 emojis, b) remembering emoji codes can get tedious (e.g the code for ‘😁’ is ‘grin’). I knew, however, that implementing the feature would require to figure out how to store data for each individual etc. I ended up deciding I would instead just show the most popular emojis people use on Facebook on aggregate, as a rough approximation of my initial feature idea that was easier to implement. I realized it would be better to ship quickly and get people’s thoughts since there would be no point building out the feature if people hated/found no use for the Chrome extension itself. (Lau categorizes this story under ‘validate hypotheses’, but I think it’s still related to the core idea of ‘finding the simplest solution’)
#3 Read code before you write code
Prior to this side project, I hadn’t really spent a lot of time reading other people’s code. I read a lot of tech articles from Techcrunch to Dan Abramov’s Medium articles, but it didn’t occur to me reading Github repos could be super productive.
In hindsight, me not realizing this was tied to a mindset that came from majoring in CS at school. For obvious (and correct) reasons, you can’t look for solutions online, or your friend’s code when working on problem sets. Another part of it was a mild dose of insecurity — “this popular Github repo has >100 stars, so it’s code must be 10x better and complicated than mine that I probably won’t be able to understand it”.
I realized that I was completely wrong.
Not only did I realize that a lot of popular open source projects have well written, easy to follow code (makes sense in retrospect — clear code makes it easy for the community to contribute commits), I also realized reading code is great because you’re learning how other, smarter, more experienced developers approached a task you now need to do. Instead of wasting time reinventing the wheel or going down dead ends, I got to soak in knowledge efficiently, learnt best practices, and ended up understanding concepts I didn’t even know I didn’t know (I’m looking at you, promises).
In particular, jhen0409’s react-chrome-extension-boilerplate repo showed me how to use React for a Chrome extension, uzairfarooq’s arrive repo gave me a better understanding of the MutationObserver API, and buunguyen’s octotree repo showed me to inject a content script into the DOM the right way.
Hopefully, I’ll keep in mind the lessons I’ve learnt making the emoji picker and be a more effective engineer going forward. Sometimes the journey is as important as the destination.
