HyreCar, based in Los Angeles, matches people who are interested in driving for Uber, Lyft or other rideshare services with car owners who have extra vehicles giving them both the ability to earn additional income. By tapping into an emerging and fast-growing market, HyreCar has grown more than 400% since early 2017 and has connected almost 400,000 drivers to cars.
For HyreCar, their explosive growth was both a blessing and a curse. To keep up with their app’s high demand, HyreCar outsourced their development work to many different offshore teams. This led to an unstable software platform that was hard to improve and impossible for new developers to familiarize themselves with. The app had constant outages and disorganization that caused extremely slow development speed. Despite these technical issues, HyreCar grew and continued to invest in sales and operational infrastructure. In early 2017, HyreCar leadership became overwhelmed with the problems and technical debt caused by their technology stack. The company asked us to build a sustainable platform that could keep up with the high demands of their customers.
Hear us tell the story in our talk From Hell to GraphQL at GraphQL Day 2019 or continue reading below.
At the start of the project, we faced a monumental set of challenges. We found that HyreCar’s original technology and infrastructure had been created by over twenty different developers in multiple countries who had little to no communication. The stack was outdated, undocumented, and unscalable. To top it all off, HyreCar had an IPO fast approaching. We needed to migrate an entire user base from a stack with an unfinished frontend and unstable backend without losing data or causing major outages. This all needed to happen during a critical stretch in HyreCar’s journey without any internal developers that had prior knowledge about the codebase or business domain experience.
Here are a few metrics that outline HyreCar’s state when we started:
We kicked off the project by working with HyreCar to prioritize a lengthy feature list, identifying high-risk items, and test assumptions. As a user-centric design and development team, we honed in on gathering quantitative and qualitative feedback from HyreCar’s users. Equipped with this data, our team came to the conclusion that HyreCar needed a full rebuild of their infrastructure in order to handle their user requirements, scaling demands, administrative feature requests, and to establish a strong foundation for future in-house engineers.
Here is a high-level summary of our development roadmap:
In order to accomplish these requirements in such a short timeframe, our team focused on utilizing modern technologies that emphasize flexibility, speed, scalability, stability and lower costs for our clients.
The stack included:
React | Typescript | GraphQL | Prisma | Apollo | Algolia | Auth0 | Serverless | SegmentIO
Focusing first on user experience, our team rebuilt the front end of the app. This provided the most value to the users while equipping our team with important domain knowledge and a grasp on how the HyreCar business worked.
Through a series of weeklong design sprints, the business leads at HyreCar worked with our team of UI/UX, business analysts, and developers to create a prototype for a new app. The prototype was developed iteratively, based on feedback from users and HyreCar’s business experts, and addressed many of the customer concerns that were uncovered during the initial discovery phase. It prioritized simplicity and intuitive user experience. For example, renting a car on the site originally required 7 steps; with the new design, it only took 3.
With the new prototype in hand, we were equipped with a fresh understanding of the business requirements and a strategic plan for building the first version of the product web client. The next steps were to build a React web application that would power both the driver and car owner user experiences. As development proceeded, we quickly realized the limitations of the legacy REST API. The undocumented routes and complex data structures meant a creative and fresh user experience was unrealistic in the current state.
Once the React web client was successfully released, our team had a strong understanding of HyreCar’s business requirements, user tendencies, and critical business logic. With this knowledge, we were prepared to confidently and efficiently rebuild the backend of the HyreCar platform. Keeping in mind that HyreCar also had native mobile apps in their roadmap and that the new API needed to be flexible enough to handle various use cases we agreed that GraphQL would be the perfect choice for this scenario.
Our strategy was simple:
With the IPO three months away, we dedicated a week to discover whether our plan was feasible.
This part of the process was straightforward since we already had a strong understanding of HyreCar’s business. It was just a matter of following some best practices and consulting with James Baxley over at the Apollo team to come up with a suitable schema.
The first major hurdle we identified was implementing our schema and using it to “wrap” the existing REST endpoints. The problem was that the endpoints did not follow any convention, so retrieving specific pieces of data was nearly impossible and required fetching from data-heavy endpoints which caused performance to suffer. For example, if we wanted to retrieve certain pieces of information for a rental, the /rentals/:rentalid route did not give us everything we needed. Instead, we needed to fetch all of the rentals via the /rentals endpoint and find the specific rental we were looking for. We were aware of these problems and knew while building the web app that we would need to add some new routes to their legacy API.
At the time, HyreCar’s in-house engineers were recently hired and had very little knowledge of the codebase. As mentioned earlier, this codebase was touched by several engineers and the organizational structure was extremely poor. Making small changes to the codebase would have cascading effects and cause bugs in other areas of the application. On top of this, their server, which was on a single EC2 instance, would constantly crash leading to an uptime of 80%. It was clear that the existing API would not be able to handle the expected growth in users after the IPO.
A Look at the Database
Because we could not rely on the REST API code, we decided to write our own business logic and access the database directly from the GraphQL API. When we dove into the database schema, it was difficult to see how or why many of the tables and columns were used. The database had evolved with the business and the majority of what remained was no longer necessary. The MySql database also did not comply with best practices and would result in drastic slowdowns.
Reevaluating our Strategy
If we wanted to continue with our original strategy, it would have required at least six months to a year to deliver a stable GraphQL API to HyreCar. However, it was clear that the existing REST API and database would not be able to withstand a drastic increase in their user base after the IPO. By this point, there were two and a half months left until HyreCar’s IPO. Our only option was to rebuild the database and GraphQL server from scratch and migrate the data with minimal planned downtime.
This was our new strategy:
To address the issues of a bloated database, we broke apart the database into multiple service-based databases for users, cars, rentals, payments, etc. This isolated the data to a specific context of the business and gave us the freedom to use a suitable type of database per business function. Additionally, if one of the databases becomes too large or no longer necessary, it would not affect the rest of the system.
To bind all of these different databases together into one coherent API for frontend clients, we used GraphQL. GraphQL enabled us to iterate on our API without having to worry about breaking the functionality of existing apps that were using it.
Another big issue with Hyrecar’s REST API was that third-party integrations like analytics tracking, CRM, and notifications were collocated with their core business logic. This often led to the server crashing or core operations failing because one of the integrations broke. For the new build, we implemented an event-based system where functions would run independently in response to an event that gets triggered by the core API. For example, if a driver requests to book a car, the core API would trigger an event called “driver.requestedBooking” and a number of functions would subscribe to this event and send a notification to the requested car owner, update the CRM for the sales agents to follow up and so forth. Now, if one of those functions fails, the core transaction will still go through and the other functions will still work.
We were able to successfully deliver on our strategy within the three-month timeframe— just in time for HyreCar’s IPO.
Through our work with HyreCar, we created a product that delivered a seamless user experience and improved HyreCar’s ability to deliver new products faster. Perhaps most importantly, this product was built on a technical foundation that could scale with HyreCar’s continued growth. Since working with us, HyreCar has grown its development team to twenty members, and most importantly, customer complaints about critical business transactions have decreased dramatically. Additionally, the delivery of new features has become exciting, not nerve-wracking.
With our help as a technology partner, HyreCar has successfully IPO’d, continued to surpass critical growth milestones and can now feel proud of its technology stack and development process.
Here are a few metrics that outline HyreCar’s state today: