Being a developer, I often run into issues that I know could be solved by software applications. For instance, at Luno, we have a masseuse who comes in four days a week. But, as you can imagine, this has been a logistical nightmare, because who wouldn’t want a free massage? I have quickly learnt that it’s more valuable to be a problem-solver than a pioneer that adds no value. So, here’s how I developed a simple piece of software that prevents my work family from committing a felony over a massage.
A few months ago, our engineering director jokingly told a co-worker and me that we should think about a software solution to help out our masseuse. For context, the current booking system was a Google Sheet where we filled our names into corresponding massage slots.
The main problems with this quick and simple solution were that there was no way to:
- Prevent someone from writing over someone else’s name at the last minute.
- Monitor whether a small group of people were dominating the room (yes, Mafia style) by having massages daily or even weekly. Since, we are fast-growing, with an average of 20-25 people joining per month, this could become a big issue very quickly.
- Add cool features like the ones you can add to your own software, like Google Calendar reminders, Slack notifications, Slackbot integrations and even more features that have yet to be thought of.
So, as you can imagine, it was chaos. But, since one of our company’s core values is to ‘Move fast and take action’, I decided to make sure that this massage ordeal wouldn’t be the collapse of humanity and ethics as we know it. Here’s how I did it!
The plan of action
To solve these issues, I decided that I had to use some sort of custom software. But I had to decide how it would it look, what it would do, and how I could build it in such a way that another developer could easily take over and make it better.
The solution, which I believed would address most of these issues, would at the very least have to contain these primary characteristics or properties:
- A currency: Much like a stable coin in crypto, 1 Luno coin would equal 1 massage, or any other cool benefits that could be available in the future.
- A balance or account: Considering that there will be a form of currency at play, regardless of whether it’s real, we needed to be able to manage people’s balance or account. This was useful for creating realistic expectations around how often someone can actually get a massage, since there was now a ‘cost’ to getting one.
- Statistics: The key to scalability is collecting data and dissecting it to understand how your tech or product is being used, because this can direct your choices going forward. I always prefer facts to fiction because it allows you to act on the things that will actually make an impact, rather than what you would prefer to work on.
- Massage schedule configuration options: We had to allow a person in our People’s Team to create the new weekly schedule. We also needed a way that this could be done quickly and easily handed over.
- Maintainable code base: This code base had to have a coding pattern for the separation of concerns, otherwise it would be overly complicated to maintain and add new features.
- Booking slot swap option: We needed to have the functionality to allow the user to swap their slot for a more convenient time, instead of them having to cancel the slot altogether. For example, this would be useful if an important meeting came up.
Once I had looked at the problems and the solutions that I wanted to provide, all I wanted to do was start coding straight away. But, I needed to do one more thing before I could start coding which, trust me, is harder than it sounds! What was that thing? You’ve probably guessed it… choosing the tech stack!
Step 1: Tech stacking for scale
Okay, you may think that this is a bit much for something that's going to be an internal product, since it doesn't need to serve +3 million customers. But the habits that I enforce, and the way I think when approaching problems, will influence the way I approach and think about tech stacks when it comes to my normal sprint work. So, while a side project is an opportunity to build useful tools, I also want to benefit from this project by learning from the mistakes I make along the way.
So what tech stack did I choose? Well I decided on:
- Firebase’s Firestore for the database.
- Firebase Cloud functions to run background functions that audit the books.
- Angular, not js, and no - Angular is not the wrong spelling of ‘React’.
- Material Theming because, let’s get real, it makes everyone’s life easier.
The database: Firebase’s Firestore
I decided to go with Google’s Firebase Firestore as the database that I would integrate with. This was largely because:
- It is easy to start a new project.
- It offers free hosting and cloud functions.
These helped me a lot since it meant that I didn’t need to set up an entire back-end or database for a quick, fun project.
If you want to know more about Firebase go check them out here.
The front-end: Angular
I know, in this day and age, it feels like the entire community is just talking about React, but this article isn't about that discussion. But why Angular? Because once you’re proficient in a JS framework, why not use it? Just because it’s not the trending thing doesn't mean you shouldn’t use the framework that you know best.
I prefered to solve this specific problem using whatever tools I had at my disposal, because there wasn’t a significant performance difference between Angular and React. So, the quickest way to achieve my goal was to use the tools I had been using in my day-to-day, which is Angular v6.
Database architecture
Once I had decided on which tech stack to use, I started thinking about how I could store schedules, users, coins, bookings, and trades in a way that is scalable and easy to work with. Thinking through and planning the foundational architecture would make my life easier down the road, especially if I want to do more complicated features. Since, Firebase’s Firestore is a document-oriented database, I decided to break it up into the following collections:
- Schedules: The blueprints or schema that are available for each day of massages. They will contain the slots that are available for people to book.
- Bookings: These are references to the schedule slots. They will be used to represent that a specific user owns a slot.
- Users: A list of users, as well as corresponding entrant information, such as:
- When that user last signed on,
- When they last received a balance top-up,
- Their current balance, and
- Profile pictures.
Step 2: Creating the interface
Designing an interface is not really something I do a lot as a developer, but I do care about how the app I’m building will look at the end of the day. So then, how did I tackle this?
Massage slots
So, what’s the best way to show 30 ~ 50 individually bookable slots, all on one screen, without adding scrolling? Tables!
I know, I'm such an innovator… but really! It’s something that most people are familiar with, it’s not over the top, it's simple, dense, and adds a nice structure to the page. The main reasons that I went with tables are:
- Screen real estate: Tables are useful here because they force you to provide a simple layout, and they typically don't take up too much space. Rows can easily expand when needed and only the most important information remains in the view.
- Scalability: Tables are useful here because I can represent a whole week, add features to the day, or even specific time slots with great ease.
- Good and easy UX: Tables are useful here because you can use the user’s previous experiences and knowledge to help them understand which slots are available, which ones are taken, and by whom. It also provides this simple pattern that a user can become very familiar with quickly.
When thinking about the massage slot interface, my biggest motivating factor was that I wanted it to be simple. The simpler the better, because I don’t want people to be slacking/contacting me daily on how to do something. I would like for the experience to feel natural. I want complexity disguised as simplicity; the user must be able to interact with a highly-intelligent, yet simple piece of software that does exactly as the user expects it to.
The end result was this:
Profile page
When it came to creating profile pages, I honestly had no clue where to start, so I actually Googled a few designs but nothing looked right. All the designs were super fancy but focused on personal information and not information that the user would need to know about their account on the app. So, I hacked away until I was happy with this page. Once again, I kept it very simple and made sure that the following things were the essence of the page:
- Log in and log out ability
- Ability to easily see how many Luno coins the user has
- View of any offers that the user receives to swap their bookings
The big idea here was that everything involving the user in the app will be reflected here, whether it is preferences, bookings, or offers.
The end result was this:
Admin dashboard
In the day and age that we live in, a Single Page Application is not complete without a console to manage the system. I felt that this app wouldn’t be complete without a dashboard where someone can easily create schedules, manage the app, and gain sight of how many people we have on it, as well as each users’ massage history (in case of abuse).
To do this, we needed to have an admin dashboard that managed:
- The user list: Provides visibility and context to the People’s Team. They are set as admin, who can view the number of massages that a person has sent and received, how many Luno coins they have, when they last logged in, and when they last received an automatic top-up.
- Schedules: Gives our People’s Team the ability to easily create a new schedule – and edit that schedule whenever they need to – without having to code or access Firebase directly.
The end result was this:
Once this interface was clean, neat, and easy to use I was happy with it, so I went ahead and began creating the logic for the app.
Step 3: Connecting the interface to Firebase’s Firestore
Below is a diagram that visually represents how the app works from a logical perspective.
This diagram shows the direct relationship of every aspect of the product, from the client all the way to the database.
First, we have a relationship with the user and the app. They will interact with the app using their browser, and those interactions will provide events to the real-time ecosystem. Those events in the ecosystem will translate to a saved state in the database. For example, John makes a booking (event) which gets stored in the real-time database (Firestore) and all the other users in the ecosystem (people that are logged in) will see the change as soon as the user clicks the button.
The app speaks directly to Firebase’s (Google) Cloud Functions for when any new entry needs to be made into the database/ecosystem. The app also speaks directly to Firebase’s Firestore to read all entries and changes in the database in real time.
In the background, Firebase’s (Google) Cloud Functions are also secretly running in the background, responding to specific events that take place to ensure that no one has found a way to hack or abuse the system. These cloud functions act as the app’s auditor and makes sure that there is no suspicious behaviour which could, if compromised, make me look like a rookie (just kidding… okay not really) and ruin the experience for everyone. It would become the problem instead of being the solution.
The big day
The day we released the “hydra app” was a good day! It has helped ease a lot of unnecessary stress on the People’s Team, as well as prevent many complaints and issues from arising. I was shocked to see over 120 of my colleagues login for the first time within the first 5 minutes of launching the web app. At the time, we only had that amount of people in our Cape Town office. So, as you can imagine, I experienced a great feeling of satisfaction from having contributed something worthwhile. Since then, there have been plenty of feature requests.
Before this experience, I believed that complicated systems, that people left alone, were usually the ones that made a lasting impact. But, creating this app has helped me realise that sometimes you can do something small and still make a big impact. In this case, a massage app that makes the office a bit more sane and a bit less likely to become a murder scene.
Andrew graduated from the University of Cape Town and soon after realised his passion for solving complex problems with efficient and simple solutions. He became focused on learning and improving his skillset as a software engineer. Andrew loves code challenges and learning better ways to get the desired outcome. He started out as an iOS Swift engineer and then delved into the world of progressive web applications, specialising in Angular. Andrew enjoys Go, Swift, and of course Typescript.
Check out more from him on his Github account.