By Jonathan Levi
As one of Uber’s summer 2018 interns, I could not have been more excited to work on the technologies used by my friends and family on the Uber platform every day. Working on a computer science degree, I applied for a summer internship at Uber as a means of getting real, hands-on experience.
Pursuing an internship at Uber particularly interested me because, like working on my high school teacher’s music app, I knew I would get a chance to tackle complex technical challenges with lasting impact in the real world. Instead of making music software, however, I would be working on the Uber Eats Restaurant Management engineering team, a natural fit for my passion for using code to solve physical problems, in this case, food deliveries.
In this spirit, the focus of my internship involved building a solution to enable the seamless update of restaurant menus on the Uber Eats app for our Uber Eats Operations team, employees stationed in cities around the world who manage relationships with eaters, delivery-partners, and restaurant-partners. Creating this feature would free Operations team members from having to manually update restaurant menus on our platform, thereby saving them time and resources that could be better used serving our customers.
The feature design process
With my project objective in mind, my mentor, Uber software engineer Kabir Mahal, and I drafted the initial design. We planned to build a service using dependencies to store a scheduled menu change, schedule the change, and perform the menu update, publishing it live on the platform at its scheduled time.
The plan called for Menu Scheduler, our new service, to take an uploaded spreadsheet with menu data, store it, and use an internal cron service to update the restaurant’s menu at a set time. The UI would be an internal tool used by Operations to change information at a restaurant partner’s request. At first glance, this proposal looked solid, and I felt confident the engineering reviewers would give me the green light to move ahead and start building.
Little did I know how much the scope of my project would change within just a few days. As we gathered feedback on the architecture, we received comments noting that there were plans for scheduling all types of actions within Uber Eats, not only the upsert menu functionality. Unlike my experience building a music app in high school, designing a single feature for a global, ever-evolving product with millions of users requires extensive collaboration, research, and, of course, iteration.
The app design process showed me Uber’s culture of sharing technical projects throughout its engineering organization, a practice to ensure that engineers are building unique tools and improving efficiency. This culture of collaboration gave me insight into a few simultaneous efforts that could make our work more reusable and faster to build. For instance, another group on the Uber Eats engineering team was already working on updating our menu format through a new menu transformer tool and building a new self-service tool to help restaurant-partners edit information related to their business on Uber’s platform.
These revelations concerning the larger engineering initiatives around Uber Eats made me realize the many engineers involved in improving the service, and prompted me to rethink the entire design of my project.
Take two: the redesign
Our redesign moved the scheduling logic into bulk actions, an existing service used for changing store hours and value-added tax (VAT) rates at a city level, among other information. Having a dependency on that service enabled us to stop worrying about storage, as the action would also persist the menu data. When we announced our updated design, the Operations team replied enthusiastically with a list of other feature requests based on a scheduling component. The scope of my project progressed from serving a specific use case to including generic features with even greater impact for our customers.
By the second round of iterations, Menu Scheduler had become a lightweight service connecting many parts of Uber Eats: the UI, Menu Transformer, and bulk actions.
Although the planning process took longer than initially expected, the redesign led to more cross-team collaboration and learning. As it turned out, we were planning enough changes to put out two RFCs instead of one, a move that clarified our goals while separating the generic scheduling and its first use case, scheduling menus, into two documents. The redesign also established clear boundaries on how to split up the upcoming work between teams.
Coding in Go
Menu Scheduler touches many different services and involved extensive front-end and back-end work. When development began, my first task was to build capability into the scheduler to schedule menu updates via the bulk actions service. To accomplish this, however, I would need to write in Go, the programming language Uber Eats is written in, which I hadn’t previously learned. Fortunately, I found out that many of my new colleagues did not have prior experience using Go before joining Uber, making me feel more comfortable with learning it on the job. I always enjoying learning new programming languages, but in this case, it wasn’t just about building mock apps and playing around with them; I had a product to ship!
Before my internship at Uber, I had primarily worked in Python, so I enjoyed the increase in development speed that Go, a strongly typed language, provided. Learning Go at Uber let me focus on writing strong code instead of figuring out the basics of building a web app. During this process, I wrote software that fulfilled the project’s technical requirements while at the same time benefitted from an incredible learning experience. Whenever I had the time, I delved into some of the libraries used at Uber to get an understanding of Go’s fundamentals. Although I had never written a line of Go code before coming to Uber, I picked it up quickly and was able to land code in a matter of days with the help of my team.
Besides learning a new language, my entire internship project consisted of working within existing codebases. I was surprised by how much project owners cared both about the quality and growth of the craft—they ensured high quality code standards while letting me experiment with different approaches. While well-written code was important for my initial efforts in high school, coding well within a large organization also required easy-to-understand documentation and code reviews. At Uber, I could fail quickly, learn from my mistakes, and correct myself in a matter of hours thanks to our efficient code review process.
Demo Day, a company-wide event where we presented our projects for the entire engineering organization, was an exciting day for all of us interns. We finally got to show everyone in the office what we had been working on. It was rewarding to see our projects completed, and it encouraged me to reflect on my internship experience as a whole. I had not expected to get this level of autonomy and support to drive and oversee completion of such an interesting and important project at a large company.
My summer at Uber gave me an incredible opportunity to grow as both an engineer and a team player. I learned that software engineering is about much more than writing good software: engineers need to be mindful of the work around what they might consider their core work of writing code, such as code reviews, documentation, and efficient communication.
Here are some additional lessons I learned from my internship:
Do not underestimate the value of a strong support network: My team, as well as other Uber engineers I worked with, were very supportive, and I felt like I could ask them anything. This support pushed me to help out with other engineers’ work whenever I had the chance. I increased my productivity by putting up smaller diffs and communicating clearly about my objectives, issues, and failures. I improved my writing skills and ability to meet deadlines through the RFC process. In my experience, school work focuses less on these types of real-world considerations, but this internship gave me the opportunity to develop them during an entire summer.
There is nothing quite like developing at scale: The scale at which Uber Eats operates was what attracted me to this role in the first place. In school or at small companies, scale is often not a deciding factor in how you approach system design. At Uber, I learned the importance of measuring everything you do. When you write code that has many dependencies and needs to scale along with a growing business, it is critical to keep an eye on whether your code is working as intended.
Collaboration is key: Working on this project served as a great example of how collaboration and communication is critical to shipping features quickly, a skill Uber’s engineers are well-acquainted with given the speed and scale of the business. Perhaps what surprised and delighted me most was the culture of openness and willingness at Uber, a culture that enabled me to go beyond what I thought could be built over the course of a single summer.
Interested in pursuing an internship at Uber? Applications for the 2019 term are closed, but please check our web site next summer for new opportunities.
Subscribe to our newsletter to keep up with the latest innovations from Uber Engineering.
Header Image Attribution: Cubs at Play by Lip Kee, licensed under the Creative Commons Attribution-Share Alike 2.0 Generic license.