The Robobunker project was coming along extremely well, and every day we felt closer to releasing a product to the public. The only issue was that between every hardware iteration or malfunctioning we had long downtimes because most of our components are custom made by specialist robotics manufacturers, which often take several weeks to complete orders. At first, I was making the best of this non-coding period for business development, but one all our financials, strategy and business plan were in order I decided to apply the front-end skills I learned building the YellowLabel app to the golf course market.
The product I was going to build was designed to tailor every software need of a golf course under one umbrella since at the time courses needed to have a variety of software suites including a property management system, tee time booking (internal and online), and golf cart and pace of play monitoring. After my incredible experience using the React stack at YellowLabel, I was convinced that all of a course’s needs could be combined into one node.js backend that exposed data with GraphQL APIs to mobile and web front-ends. I had read a lot about the reusability of code when building a mobile and web product with React and React Native, and I was curious to explore the technology’s potential in saving developers time when building for different platforms and devices. More specifically, I was adamant to build a custom backend that could serve both a mobile and web client with the exact same code. The final product ended up being three separate front-end projects (two mobile apps and one website) with a common Node.js backend exposing GraphQL APIs.
The project involved two separate frontends, one client-facing and one staff-facing. The client interacted with the app through a tablet mounted on all the course’s golf carts which had the following functionality: on one page it visualizes the current position of the cart on the course and shows distances to the pin, green, and hazards and on a second page allows ordering of food and beverage to be delivered to their exact location. The staff version was designed to have both a tablet and a desktop website interface to allow employees to access the following functionalities both on the move and in the clubhouse: overview of cart positions throughout the day, monitor pace of play, unilaterally communicate with guests, process food and beverage orders, and schedule teetimes. Both the tablet apps were built using React Native with Expo, whilst the website was built using React. Given my previous experience with the YellowLabel app, it was actually pretty straight forward to build out these frontends since I used dummy data to simulate the backend APIs and Material-UI to help me design and style the frontend components. The only slight code complication arose from my decision to not use Redux for app-level state management, but it only required a one level prop-drill (outlined in a previous blog post to fix. The rest of the data management is handled by the backend, as it needed to be in real-time amongst the three frontends anyways.
Frontend Code Reusability
My main intellectual curiosity in this project was to see how much code I could reuse between the React website and the React Native staff app. My first step in testing this was to build a dummy-data JSON file that would be shared by both frontends to emulate what one single backend for them would look and feel like. This part turned out to be relatively simple as both the versions have the exact same functionalities, so read and write the exact same data from the database. On the other hand, the frontend components for the two platforms shared very little of the same code as the React components themselves were different in style, layout, and sometimes specific functionality. The pieces of code I was able to share the most between the platforms was the OnClick() functions in buttons that made the query or mutation through GraphQL to the backend. The conclusion of this is that when building truly cross-platform (iOS, android, web) products, you can share the vast majority of your ‘business logic’ (reading and mutating data) within each component, but you can share almost nothing of the pure UI code. It is a little disappointing that all the UI code must be rewritten for each platform as its by far the most time-consuming task when done at production-level detail, but the incredible ability to share backends is what keeps me so excited about this technology. I am confident that the code reusability over the years is just going to grow as the React community has been going far beyond any expectations in improving the framework and addressing developer concerns since its conception.
I built the frontend with identical dummy data for the staff tablet and web versions in order to test the hypothesis of building a single set of exposed GraphQL APIs in my Node.js backend. Since I was able to build the frontend UI with the same data structure across the web and mobile versions, I was confident about the single backend if I could expose data in real-time to all frontends. I was not 100% sure which type of database to use, but I decided to stick with MongoDB’s unstructured database as it proved itself to be fast and flexible in my previous projects. I was a little worried about exposing all the data in real-time, but with the help of a library called Nest.js, I was able to seamlessly give concurrent read and write access across all frontends. This all seemed to work perfectly when I was testing the different frontends inside my office, but obviously this was too good to be true…. Once I brought the tablets to the course, I quickly found out that the data had a significant lag time to show up on the screen. Unfortunately, this was not something I could fix by moving some of the ‘business logic’ and data storage to React/React Native (to maybe include Redux), as the data had to be shared in real-time across two completely different frontends.
Even though on the client facing app, the worst-case scenario meant waiting a few extra seconds for the food and beverage menu items and images to show up, these occasional lag times were bothering me beyond belief. I promised myself I would achieve real-time without touching a line of code in the frontend. The solution was to also host the backend on a small internal server which would be accessible in LAN by all the devices running the application since they all connect to a shared wifi network. One catch, I had to modify all the frontend GraphQL queries to contain an if-else statement to determine whether to make the call on a LAN IP address url or a regular web url. Although I broke my own promise, I’m still proud I did not have to modify any of the frontend code I wrote with the dummy-data!
The app is has been fully deployed at my partner golf course, San Domenico Golf with very good results so I decided on a simple strategy to sell to other courses around Italy and Europe. First thing was to generalize the backend to be able to take in only a few pieces of data and optional images to be used on a new golf course. The second was to hire a commission-based sales rep to sell this product all over Europe without any further intervention on my part since the installation process now required no programming knowledge. All a new golf course needs to run our software is tablets (iOS or Android) to mount on each cart for the guests, and tablets and desktop computers for the staff. The only catch is that the regular package being sold is the slightly laggy backend version hosted on AWS, whilst the internal server solution is a premium option that requires on-field installation. If there is significant interest for this product across Italy and Europe, I will build out the following new features: teetime scheduling and booking system, custom food and beverage outlet management, member and guest relationship management, proshop POS, analytics dashboard.