Ir al contenido

Blog


Parte 1: Proyectos de prácticas de verano de DoorDash 2024

3 de octubre de 2024

|
Rohan Garg

Rohan Garg

Thao Nguyen

Thao Nguyen

Anastasiya Masalava

Anastasiya Masalava

Yufan "Joy" Xiao

Yufan "Joy" Xiao

Shanting Hou

Shanting Hou

DoorDash ofrece un atractivo programa de prácticas en el que los becarios de ingeniería de software se integran profundamente en nuestros equipos de ingeniería, lo que les permite adquirir experiencia práctica en el mundo real que complementa su aprendizaje académico. Este es uno de los dos artículos que muestran los interesantes proyectos que han desarrollado nuestros becarios del verano de 2024. Su trabajo no sólo refleja sus habilidades técnicas y de resolución de problemas, sino que también desempeña un papel significativo en el impulso de la innovación en DoorDash.


Prevención del gasto excesivo en publicidad: Mejora de los algoritmos de planificación presupuestaria

Por: Rohan Garg

DoorDash's advertising platform, which aims to show the right user the right ad at the right time, lets advertisers consistently connect with consumers. Restaurants, for example, can specify an advertising budget for their campaigns and our platform can dynamically determine how that budget should be best spent throughout the day. Without pacing a campaign's ad spend in this way, it is possible to deplete the entire budget early in the day. Restaurants then would get fewer orders during the dinner rush, hampering their ability to compete on the platform. This problem is known as budget pacing; in this post, we discuss how we improved our budget pacing system through mitigating severe over-delivery.

El reto

When a consumer clicks on an advertisement, we charge that advertiser an ad fee. This fee is taken from the advertiser's daily budget - their monthly budget is split evenly across all days. Because of daily fluctuations in user traffic, however, we also set our own spend goals that can vary from day to day. Once the spend goal is hit, we stop serving ads for that advertiser. We can still bill advertisers up to double their daily budget because of an agreement made between DoorDash and advertisers. This gap allows for some overspending, up to the billing cap, after the pacing goal has been achieved. Overspend occurs when a consumer clicks on an ad before the daily spend goal has been reached, but then fails to place an order until after that goal is reached. This is called delayed attribution. If too many orders contribute to this delayed attribution, we spend past our daily goal, resulting in ad overspend.

En consecuencia, aunque una campaña ya no se sirva en las subastas, puede seguir cobrándose por una impresión de anuncio anterior. Esto es especialmente grave en el caso de las campañas para empresas (a veces más del 20%), ya que atraen a un gran número de consumidores y suelen tener altos índices de conversión.

Although we aim to minimize ad overspending, we must be careful not to throttle spending so much that we cause underspending. Our current method to prevent this is to switch from an algorithm that carefully paces spending for most of the day to one that deliberately spends the remaining amount up to the daily goal as efficiently as possible for the last few hours of the day. This mechanism is called fast finish, or FF. Technically, if a campaign has not reached the daily spend goal at certain hours, we immediately stop any pacing or throttling. This causes a sharp rise in ad spend, as shown in Figure 1. As a result, high-quality campaigns show a big spike in spending right after the FF period - a negative experience for our advertisers. Our goal in this project was to iterate on our intraday pacing system and the fast finish lever so that we can minimize overspending while avoiding underspending.

Figura 1: Curva de gasto diario de una campaña de ejemplo. La línea azul muestra el gasto antes de alcanzar el objetivo diario, mientras que la línea roja muestra la atribución retardada, o exceso de entrega.

Mejorar los algoritmos de planificación de presupuestos es un reto clave para DoorDash y su sector en general. Si no calculamos bien los presupuestos, podemos encontrarnos con recuentos de impresiones inestables, ingresos reducidos para DoorDash y días de bloqueo en los que una campaña publicitaria no recibe impresiones publicitarias durante muchos días a final de mes.

Dimensionar el problema 

To understand the business opportunity as well as the severity of advertiser overspend, we spent a week doing a deep dive into the ads platform data. For the last week of May 2024, enterprise ad campaigns experienced about 11.5% overspending beyond goals for the week. Because budgets can be depleted earlier in the month, we studied spending data for the first week of June 2024 as well. The data showed that in the first week of June, enterprise campaigns saw nearly 25% ad overspend. The data was clear - many advertisers were struggling with severe ad overspending. 

Desarrollar un nuevo enfoque

Nuestra solución consistió en utilizar parámetros específicos de la campaña para modificar varias propiedades de la lógica de finalización rápida. A partir de los datos de gasto excesivo de la campaña, variamos la hora a la que se iniciaba el final rápido y la velocidad a la que se limitaban los anuncios. 

Nuestro primer enfoque ajustaba dinámicamente la hora de finalización rápida para cualquier campaña en la que hubiera un elevado exceso de gasto. La idea era dar más tiempo a nuestro algoritmo de ritmo intradiario para servir a la campaña. Al conceder más tiempo para el gasto diario, probablemente alcanzaríamos el objetivo antes de tener que activar el final rápido, lo que provocaría menos atribuciones retrasadas. En las simulaciones, vimos que este enfoque aumentaba las horas de servicio diarias de la campaña hasta en un 6%.

Nuestro segundo enfoque cambió el nivel de urgencia para pasar del ritmo intradiario al de finalización rápida. En lugar de reducir inmediatamente a cero la probabilidad de aceleración de un anuncio, la redujimos lentamente a cero durante un periodo de tiempo determinado, por ejemplo, una hora. Al ralentizar la caída de la tasa de aceleración, nos planteamos la hipótesis de que podríamos suavizar el número de pedidos a medida que nos acercábamos al objetivo de gasto diario. Creíamos que esto también podría dar lugar a menos atribuciones retrasadas. En las simulaciones, vimos que este enfoque aumentaba las horas diarias de campaña hasta en un 3%.

Nuestro tercer enfoque simplemente combinaba los dos primeros. Idealmente, retrasar la hora de inicio de la finalización rápida aumentaría las horas gastables de la campaña; la ventana de transición suavizaría la curva de gasto, lo que daría lugar a menos pedidos con una alta atribución retrasada. En las simulaciones, vimos que este enfoque aumentaba las horas vivas diarias de la campaña hasta en un 8,2%.

Afrontar los retos técnicos

Durante este proyecto se plantearon tres retos técnicos principales. 

El primero consistía en diseñar el algoritmo para retrasar la hora de inicio del final rápido. Necesitábamos que este algoritmo fuera lo suficientemente robusto como para adaptarse a nuestros cambiantes parámetros de entrada, incluida la última hora de inicio de finalización rápida deseada. También necesitábamos que el algoritmo tuviera un comportamiento suave, por ejemplo, que no se produjeran grandes saltos en la hora de inicio del cierre rápido si una campaña empezaba a experimentar un mayor exceso de gasto. Pudimos resolver este problema seleccionando cuidadosamente una función no lineal suave que asignaba los valores de los datos históricos a los valores de la hora de inicio del cierre rápido.

Our second challenge stemmed from concern that our initial ideas were subject to a positive feedback loop that could cause unstable behavior. Essentially, we were using historical data to influence our algorithm, but over time the algorithm would influence the data, creating a feedback loop. We solved this problem by adding extra guardrails around our algorithm's output.

La tercera cuestión tenía que ver con los numerosos matices de la ingeniería del algoritmo y su integración con nuestro servicio de intercambio de anuncios. Por ahora, nuestra lógica de ritmo está integrada en el servicio principal y el presupuesto de latencia es limitado. En consecuencia, nos esforzamos por optimizar cuidadosamente la implementación mediante la paralelización y el almacenamiento en caché; por ejemplo, algunas entradas del algoritmo no cambian a lo largo del día, por lo que se almacenan en caché localmente para reducir la latencia.

Finalizar una solución

Tras realizar simulaciones y experimentos en línea, finalmente seleccionamos el tercer enfoque combinado, que incluye:

  • Introducir una ventana de transición entre el final intradiario y el final rápido, estrangulando probabilísticamente un X% de las solicitudes cuando el gasto es más rápido de lo esperado antes de reducir al 0% la estrangulación.
  • Incorporación de una hora de inicio de FF dinámica basada en el historial de gastos de campaña

Como resultado, nuestro nuevo sistema intradía se compone de tres etapas a lo largo de cada día: intradía, transición y final rápido.

Realizamos un experimento A/B en línea de una semana de duración que demostró la potencia de nuestro nuevo algoritmo, como se muestra en las figuras 2, 3 y 4, entre otras:

Figura 2: Histograma del aumento del promedio de horas vivas de la campaña. De media, observamos un aumento de 45 min al día.
Figura 3: Histograma de los experimentos de campaña que muestra la tasa media de sobreentrega. El grupo de tratamiento (barras naranjas) tiende a situarse a la izquierda, cerca de 0, lo que indica un menor exceso de entrega.
Figura 4: Ejemplo de curva de gasto diario de campaña. El grupo de tratamiento mostró un claro aumento de las horas de campaña en directo (los puntos azules terminaron a las 22:30, es decir, +1,1 horas más tarde que la línea recta azul) y también tuvo un menor exceso de entrega, pasando del 10% al 3%. 

Conclusión

In conclusion, we took a deep dive into over-delivery, brainstormed various solutions, and conducted simulations on our top three ideas. Based on our simulated results, we implemented our solution in production and measured its ability to mitigate over-delivery. The end result improves our ability to pace advertising budgets and improves the advertiser experience on the platform. Improving budget pacing moves DoorDash's advertising platform closer to its ultimate goal: Delivering the right ad to the right user at the right time. 


Identificación del dispositivo activo principal para los dashers que utilizan varios dispositivos

Por: Thao Nguyen

Durante mis prácticas de verano, trabajé para mejorar la forma en que el dominio de logística de DoorDash realiza el seguimiento de las ubicaciones de Dasher. Alrededor del 10% de los Dasher utilizan más de un dispositivo durante un turno, lo que puede dar lugar a problemas si las ubicaciones de los diferentes dispositivos reportan información contradictoria, como ubicaciones que varían entre dispositivos. 

It is crucial to know which of a Dasher's various devices are authenticated and should be used in location tracking. This is important because some devices might be unintentionally activated, such as when a family member accidentally opens the DoorDash app from a different location and leaves it running. In a more troubling scenario, a malicious former Dasher,  banned because of poor performance,  might attempt to exploit this system vulnerability to earn money illegally ‚Äî a situation that DoorDash, our customers, and our merchants would all want to avoid.

Mi proyecto pretendía identificar el dispositivo principal para saber dónde está cada Dasher, qué está haciendo y si se está produciendo alguna actividad sospechosa. Determinar el dispositivo primario también garantiza que los servicios posteriores solo utilicen datos de localización fiables, reduciendo así el consumo de datos ruidosos procedentes de múltiples dispositivos.

Aplicación

Este proyecto utilizó Apache Flink, un potente marco de procesamiento de flujos, para mejorar la precisión del seguimiento de ubicaciones de Dasher.

The new service I developed processes raw location data streams from an existing Kafka topic that is continuously updated with Dasher collected from the Dasher mobile application . My project added a key feature: An `isFromMainDevice` field that indicates whether a particular location report originates from the Dasher's primary device. After a series of logic checks on the location data, this field is set to true or false. Such checks include, among others, filtering out accidentally activated devices, applying production configurations, and identifying duplicate records. To accurately identify the main device during this process, I collaborated with another internal service that specializes in account compliance and fraud detection. By leveraging this service's dedicated databases, sophisticated logic, and thorough testing, I was able to ensure that the system correctly identified the primary device, thus enhancing the overall reliability and efficiency of the location-tracking process.

Una vez procesados, los registros de datos de localización mejorados se envían a un nuevo tema de Kafka, donde están listos para ser utilizados por servicios posteriores como la asignación, el seguimiento de pedidos y el cálculo geográfico.

Impacto

This project significantly improved the accuracy of Dasher location tracking by identifying and prioritizing data from each Dasher's primary device. More reliable location reports contribute to reducing system abuse issues and enhance the overall efficiency of downstream services. The refined data now helps DoorDash make better assignment decisions and improves the accuracy of geo-calculations, ultimately contributing to a more reliable and secure platform for Dashers, merchants, and consumers alike.


Aplicación de transformadores de visión para detectar y prevenir el fraude en el reciclado de fotografías

por Anastasiya Masalava

Como muchas empresas de cara al cliente, DoorDash establece una serie de algoritmos para detectar y prevenir el fraude de los consumidores. Durante mis prácticas de verano, trabajé en el desarrollo de una solución para reducir el fraude de reciclaje de fotos, un esquema en el que un consumidor envía imágenes duplicadas o ligeramente modificadas (escaladas o rotadas) para solicitar múltiples reembolsos de diferentes entregas. Veamos las dos siguientes imágenes de solicitud de reembolso:

Estas imágenes fueron presentadas por el mismo cliente como prueba para dos solicitudes de devolución relacionadas con dos entregas diferentes. Estas solicitudes deberían marcarse como reutilización de imágenes para evitar devoluciones. Sin embargo, es difícil para los agentes humanos detectar estas imágenes duplicadas mediante búsquedas manuales en la base de datos. Este tipo de situación requiere un sistema automatizado de detección de imágenes duplicadas.

Selección de un algoritmo robusto

La primera solución básica para la detección de imágenes duplicadas sería un algoritmo hash SHA-256, que puede comparar las huellas dactilares de dos archivos de imagen para detectar duplicados exactos. Pero esta solución no puede detectar ninguna transformación de la imagen, como rotación o escalado; cualquier imagen ligeramente modificada no se identificará como duplicada.

Para subsanar estas limitaciones, implementé un algoritmo de hash perceptivo, el P-hash, diseñado para soportar pequeñas modificaciones de la imagen, como la compresión, la corrección del color y el brillo. Para detectar la similitud entre dos imágenes utilicé la distancia Hamming, que mide el número mínimo de sustituciones necesarias para cambiar una cadena hash por otra. Aunque P-hash ofrece una buena forma de detectar imágenes ligeramente duplicadas, tiene una limitación: Tiende a fallar cuando las alteraciones de la imagen afectan significativamente a los patrones de píxeles, por ejemplo en presencia de rotación o escalado.  

Para hacer la solución más robusta, desplegué un transformador de visión, o ViT, modelo de aprendizaje profundo, que aplica la arquitectura de transformadores a tareas de visión por ordenador. Las imágenes duplicadas se pueden encontrar en tres pasos, como se muestra en la figura 1.

Figura 1: Similitud coseno-par entre las imágenes incrustadas generadas por el codificador Vision Transformer

First up, the ViT's encoder computes dense representations — embeddings — of images to compress high-dimensional pixel images into vectors, preserving information about the image. These embeddings are then used to compute pairwise cosine similarities between images; potential duplicate image pairs can be retrieved if their cosine similarity is greater than the threshold.

The biggest advantage of this algorithm is ViT's ability to understand the general context of images, improving its performance in identifying similarities. 

Evaluar el rendimiento

Para discernir la solución óptima, creé un conjunto de datos de prueba de pares de imágenes y realicé tres experimentos. El algoritmo transformador de visión supera a SHA-256 en un 52% y a P-Hash en un 1,3%, según la puntuación F1, una medida equilibrada que refleja tanto los falsos positivos como los falsos negativos.

Impacto

Experiment readout indicates that the Dup Photo detection can bring upwards of $0.6M annual savings. With the expansion of more use cases, the impact can be further increased. Over the course of my internship, I implemented an automation node to flag new refund requests if any duplicate image pairs have been detected in a consumer's previous requests. This solution can significantly reduce time spent on reviews and can minimize losses from photo recycling fraud. 


Por qué DoorDash necesita una interfaz de usuario basada en servidor con mosaico 

Por: Yufan (Joy) Xiao

Traditionally, a mobile app's user interface, or UI, is defined within the app itself on systems such as iOS or Android. This way, the app receives data from the backend to update text values and other content in its UI components. However, this approach creates two challenges to updating the UI:

  1. Delayed release cycles: Updating the app's UI requires releasing a new version of the app. This process can take several weeks to get approval from app stores, increasing the time to release.
  2. Retraso en la adopción por parte de los usuarios: Incluso después de publicar una nueva versión, es posible que los usuarios no actualicen inmediatamente su aplicación, lo que limita el alcance de las nuevas funciones y mejoras de la interfaz de usuario.

Mosaic, DoorDash's standard server-driven UI, or SDUI, framework offers an effective solution to these challenges by moving the UI definition to the backend, making the mobile app responsible only for rendering the UI components. Using Mosaic, we can change the UI simply by updating the backend response. These changes take effect as soon as the mobile app receives the updated response, significantly reducing the need for app version updates. Figure 1 below demonstrates a key difference between what's being transferred between frontend and backend.

Figura 1: Transferencia de datos de la interfaz de usuario tradicional a la interfaz de usuario basada en servidor

Por qué necesitamos la paginación

Algunos servicios necesitan devolver grandes cantidades de información en respuesta a las peticiones de los usuarios. Por ejemplo, cuando un consumidor visita la página de inicio de DoorDash o busca tiendas, el servicio puede encontrar más de 1.000 tiendas. Si se cargaran todas a la vez, se produciría una latencia significativa que afectaría negativamente a la experiencia del usuario. 

Pagination allows us to break down large data sets into smaller chunks that are returned on demand. It's crucial to integrate pagination functionality into Mosaic to handle large data sets efficiently without compromising performance.

Resumen de la aplicación

Flujo de datos (ejemplo de página de inicio)

A continuación se describe una serie de pasos sobre cómo un cliente envía una petición al backend y obtiene una respuesta paginada a través de Mosaic. La figura 2 muestra su diagrama de secuencia.

  • Cliente: Envía una solicitud de transferencia de estado representacional, o REST, a la pasarela unificada, incluyendo los parámetros necesarios para procesar la página de inicio y un token de página para la paginación.
  • Unified gateway: This is DoorDash's internal tool that converts REST requests into Google remote procedure call, or gRPC, requests. Responses are then transformed   back into REST responses.
  • Servicio gRPC: Procesa la solicitud y genera un contrato Mosaic, que se incluye en la respuesta gRPC.
  • Fuente de datos: Aquí es donde el servicio gRPC recupera los datos que requieren paginación. Las fuentes de datos pueden ser una base de datos, servicios posteriores o THIRD OPTION, entre otros.
Figura 2: Flujo de datos de Frontend a Backend y a Frontend 

Conversión de datos paginados de backend en contratos Mosaic

En el servicio backend, definimos una función lambda que convierte cada elemento de datos en un grupo de componentes de interfaz de usuario. Estos componentes de IU, como texto, imágenes, botones o información sobre herramientas, ya están definidos en Mosaic.

La respuesta del backend incluye grupos de componentes de interfaz de usuario junto con un token de página para indicar el punto de inicio de la siguiente página. El cliente utiliza este token de página para las siguientes solicitudes, como se ve en la Figura 3.

Figura 3: Respuesta del backend con los componentes de la interfaz de usuario y el token de página siguiente

Renderización de la interfaz de usuario en la aplicación móvil Android 

Como se ve en la Figura 4, después de que la aplicación móvil recibe la respuesta REST en formato JSON, la biblioteca Mosaic la convierte en un modelo de dominio. A continuación, Android ViewModel gestiona el token de página desde el modelo de dominio y mantiene las páginas existentes. El ViewModel se vincula con una actividad o fragmento de Android, que renderiza la interfaz de usuario con Mosaic.

Figura 4: Conversión de la respuesta de modelo de red a modelo de dominio y, finalmente, renderización

Impacto

Este proyecto acelera significativamente la adopción del marco Mosaic en DoorDash, especialmente permitiendo que el servicio de alimentación migre al nuevo marco SDUI.

Gracias a la función de paginación, Mosaic no sólo es compatible con un entorno de desarrollo sólido y flexible, sino que también ofrece una estrategia SDUI más escalable, lo que mejora el rendimiento general de la aplicación y la experiencia del usuario.


Mejora de la transparencia y la eficiencia con la herramienta de depuración de personalización de DoorDash

Por: Shanting Hou

During my internship at DoorDash, I worked with the New Verticals, or NV team to develop a personalization debug tool to enhance operator transparency and significantly reduce debug time for engineers. Our solution contributed to the overall efficiency and reliability of DoorDash's retail and category pages.

Mejorar la comprensión de las herramientas y la eficacia de la depuración 

The NV team, particularly members focused on customer experience and product personalization, were grappling with inefficiencies in their outdated web debugger tool. The tool was not equipped to handle the growing complexity of retrieving essential information such as machine learning, or ML, prediction scores and personalized insights, which are crucial for testing ML features and responding to cross-functional team inquiries. Team members frequently had to rely on engineering support to diagnose and resolve issues, including limited item visibility, discrepancies in personalized content, mismatches between displayed deals and user preferences, and understanding the algorithm's ranking logic. This dependency on engineers not only slowed operational processes but also hindered team autonomy and led to inefficient debugging procedures. 

Crear una solución global 

To address these challenges, I was tasked with revamping the debugging tool. First, I dived deeply into the tool's current use cases, discussing issues with ML and back-end engineers responsible for the ranking algorithm. I sought to identify the most critical features that needed to be logged to streamline the debugging process as well as to visualize the ranking logic more effectively. Primary challenges involved deciphering the ranking logic's intricate flow and the logging information design. Both required navigating complex system logic and comprehending ongoing experiment values to pinpoint the ranking algorithm's core stages. With the guidance of engineers Yucong Ji and Anthony Zhou, I was able to overcome these challenges and develop a clear understanding of the algorithm.

El siguiente paso consistió en traducir esta lógica técnica a términos fácilmente comprensibles tanto para ingenieros como para operadores, lo que implicó clasificar los distintos pasos de clasificación en sus posibles resultados. Descubrí, por ejemplo, que los ajustes de anclaje de los carruseles podían dejarlos en uno de estos tres estados: desanclados, anclados a un rango determinado de la página o fijos en una posición específica. Para garantizar la claridad, documenté la lógica de los campos de registro en un wiki exhaustivo.

But the logging fields by themselves wouldn't be effective unless they directly addressed user pain points. By analyzing confusion and errors reported on the team's Slack channel, I identified specific concerns and determined what logging information would be most valuable. As just one example, we added carousel order logging information to increase transparency in the ranking stages, which helped to pinpoint where errors occurred. To make the tool user-friendly, we displayed the logged values in an accessible manner. The main debugging information was clustered into two key modals, separated by carousels and items. Additionally, we made modifications to retailStorePageFeedQuery to reduce latency, adding an enableDebug field that would pass from the front-end to the back-end. Consequently,  debugging information was only retrieved when needed, ensuring optimal tool performance. The result was a robust tool that allows team members to view relevant debugging information directly on the live DoorDash site by simply toggling a debug button. Figures 1 and 2 below show examples of the new debug modals.

Figura 1: Modalidad del depurador ML para carruseles

Muestra detalles clave de cada paso del carrusel de elementos de clasificación vertical en la página para permitir una depuración sencilla de cualquier incoherencia relacionada con la clasificación. Por ejemplo, las puntuaciones de clasificación/modelos ML utilizados para clasificar este carrusel, así como la posición del carrusel después de cada paso del proceso de clasificación.

Figura 2: Modalidad del depurador de clasificación de elementos

Muestra detalles clave de cada paso en la clasificación horizontal de elementos dentro de un carrusel para permitir una fácil depuración de cualquier incoherencia relacionada con la clasificación. Por ejemplo, las puntuaciones de clasificación/modelo ML utilizado para clasificar este elemento, así como la posición del elemento después de cada paso del proceso de clasificación.

Transformar el proceso de depuración

Implementation of the personalization debug tool significantly impacted both the NV team and DoorDash as a whole. The tool reduces the time required for back-end engineers to debug issues by up to two hours, moving engineers away from manual debugging through the ML platform. This not only saves valuable engineering time but also improves the overall efficiency of answering cross-functional partner queries and testing new ML models. In the final weeks of my internship, I focused on enhancing the tool's extensibility and long-term maintainability. I implemented functions that back-end engineers could use to log carousel/item position changes and other crucial features efficiently. I also modified the front-end to adapt seamlessly to new back-end changes, ensuring that any logging or feature information that was added would be reflected automatically without requiring further adjustments. I also investigated using tree metrics for detailed, per-query insights that could enable alternative approaches to overcome potential challenges, such as increased latency and complex logging.


Overall, the personalization debug tool has empowered DoorDash's NV team to maintain effective debugging practices, improve transparency for operators, and ensure the platform's continued reliability and efficiency. This project stands as a testament to the impact that a well-designed tool can have on a large-scale, distributed system.

Sobre los autores

  • Rohan Garg

    Rohan Garg hizo prácticas para DoorDash en el verano de 2024.

  • Thao Nguyen

    Thao Nguyen interned for DoorDash in the summer of 2024.

  • Anastasiya Masalava

    Anastasiya Masalava interned for DoorDash in the summer of 2024.

  • Yufan "Joy" Xiao

    Yufan Xiao interned for DoorDash in the summer of 2024.

  • Shanting Hou

    Shanting Hou interned for DoorDash in the summer of 2024.

Trabajos relacionados

Ubicación
San Francisco, CA; Mountain View, CA; Nueva York, NY; Seattle, WA
Departamento
Ingeniería
Ubicación
San Francisco, CA; Sunnyvale, CA
Departamento
Ingeniería
Ubicación
San Francisco, CA; Sunnyvale, CA; Seattle, WA
Departamento
Ingeniería
ID de trabajo: 3013456
Ubicación
Pune, India
Departamento
Ingeniería
Ubicación
San Francisco, CA; Seattle, WA; Sunnyvale, CA
Departamento
Ingeniería