Cómo escalan las cosas: una introducción al diseño de software escalable del mundo real

Dec 03 2022
La intención detrás de esta publicación es exponer algunos fundamentos del diseño de sistemas de software, con un énfasis adicional en el aspecto del diseño. Responde a una pregunta, a través de un ejemplo de caso real, que muchos ingenieros se hacen: ¿Cómo empiezo a diseñar un sistema? Descubrí que demasiados recursos en línea se enfocan en las herramientas y en el enfoque de "ensuciarse las manos".

La intención detrás de esta publicación es exponer algunos fundamentos del diseño de sistemas de software, con un énfasis adicional en el aspecto del diseño .

Responde a una pregunta, a través de un ejemplo de caso real, que muchos ingenieros se hacen: ¿ Cómo empiezo a diseñar un sistema?

Descubrí que demasiados recursos en línea se enfocan en las herramientas y en el enfoque de "ensuciarse las manos".

Si bien dominar las herramientas es importante, nos saltamos, más a menudo de lo que nos gustaría admitir, la pieza central del rompecabezas; el pensamiento de alto nivel de cómo funcionan las cosas incluso antes de que intentemos codificarlas en nuestros llamados lenguajes de programación.

En esencia, “el arte de programar es el arte de organizar la complejidad” (Farley, David. Modern Software Engineering).

La complejidad de la organización debe venir antes de comenzar a escribir cualquier código (¡o tal vez incluso pensar en los sistemas informáticos!).

Por lo tanto, nos sumergiremos en un ejemplo de caso real de cómo podemos usar conceptos que garantizarán que una instancia particular de nuestro sistema pueda escalar e identificar cuáles son estos conceptos.

¡Cinturón de seguridad!

Déjame darte un poco de contexto sobre Creator Now .

En el corazón de nuestro negocio, necesitamos gamificar la información sobre los canales de YouTube de los creadores para brindarles las mejores experiencias de aprendizaje y crecimiento para su viaje como creadores.

Eso significa que, por cada nuevo usuario registrado, debemos confiar en gran medida en la API de YouTube para extraer información sobre la vida de su creador.

Queremos asegurarnos de que esta información se mantenga actualizada con la mayor frecuencia posible. Después de todo, no tiene sentido mantener un producto donde la información central que impulsa la experiencia del usuario está rezagada con respecto a la realidad del "mundo real".

Este es nuestro principal desafío:

¿Cómo podemos escalar si tenemos que depender de una API de terceros con límites que están fuera de nuestro control?

Primero, comprendamos cómo funciona la API de YouTube y dónde radica realmente el problema usando una analogía del mundo real.

Imagina que la API de YouTube es una gran oficina que contiene los datos de todos los canales y todo lo relacionado con YouTube.

Cada vez que alguien en Internet quiere consultar información sobre un canal específico, va allí. En resumen, todos necesitan enviar a alguien a este edificio para solicitar esa información.

El flujo es bastante simple: alguien entra por la puerta principal. Presentan sus credenciales al portero. Una vez que se les permite entrar, son atendidos por un feliz empleado de YouTube:

  • Hola señor; ¿Cuál es la información que deseas?
  • ¿ Puede consultar la información más reciente en el canal CatsAreAmazing ?
  • ¡Por supuesto, déjame revisar nuestros archivos! <obtiene los datos del canal y entrega un informe de una página>
  • ¡Gracias, buen señor!
  • ¡Espero que las oficinas de YouTube sean más nuevas que esto!

Pero YouTube ha experimentado una cantidad abrumadora de personas que piden cosas.

Dado que todos intentan obtener mucha información todo el tiempo, decidieron establecer algunas reglas ( esto no refleja las reglas del mundo real de la API de YouTube ):

  1. Solo puede solicitar un máximo de 50 canales / videos de información cada visita a la oficina
  2. Solo puede entrar a la oficina 10 veces por minuto, 10,000 veces por día
“¡Nooooooo! ¡Tenía muchas ganas de obtener toda la información sobre todos los canales del mundo!”

Bien, entonces tenemos que ser inteligentes con esto.

Hagamos algunos cálculos rápidos para averiguar la cantidad máxima de información del canal que podemos solicitar por minuto (y por día).

Si podemos ir a la oficina 10 veces/minuto y cada vez, podemos pedir 50 canales: 10 x 50 = 50 canales/min. Haciendo un cálculo similar, nos damos cuenta de que podemos solicitar 10 000 x 50 = 50 000 canales/día.

Si amplía esto un poco más, se dará cuenta de que podemos usar toda nuestra cuota en 16 horas y 40 minutos, es decir, ese es el tiempo que tomará si solicitamos 50 canales/min para aumentar nuestra cuota de 50k canales/día.

Entonces, la pregunta de oro aquí es:

¿Cómo podemos mantener nuestra aplicación actualizada de manera más eficiente con la información más reciente de los usuarios (incluso si tenemos más de 50k usuarios)?

Primero, establezcamos algunas reglas básicas para nosotros mismos que nos ahorrarán algunos viajes a la oficina de YouTube y nos aseguraremos de seguir sus reglas. Dividamos las responsabilidades de esta tarea principal en tareas más pequeñas que son ejecutadas por diferentes departamentos de nuestra empresa:

  1. Llamemos a nuestro departamento responsable de comunicarse con la oficina de YouTube, el Scraper .
  2. No necesitamos solicitar nueva información del canal si ya obtuvimos información en las últimas 24 horas (estamos de acuerdo con un retraso de 24 horas para actualizar los canales).
  3. Esto significa que debemos recordar la última información sobre un canal de alguna manera y la hora en que la recuperamos; llamemos a esto nuestro Gabinete .
  4. Probablemente queramos tener más de una persona capaz de ir a la oficina; dado que YouTube tiene un límite de 50 por minuto, podemos optimizar nuestro proceso contratando a 50 personas para ejecutar este trabajo (llamémosles Runners ) .
  5. Necesitamos tener algún tipo de control sobre cuántas visitas hacemos a su oficina en un minuto determinado y en un día determinado (¿quizás podamos escribirlo en alguna parte? Llamémoslo Registro de corredores ) .
  6. Eso también significa que cada vez que nuestros corredores quieren salir y obtener nueva información del canal, debemos verificar si no corren el riesgo de perder su viaje debido a que extrapolamos nuestra cuota de minutos/día. Este centro de control centralizado se denominará Departamento de Corredores .
El borrador inicial de nuestro flujo de trabajo

Ahora, ¿qué tiene de especial este flujo además del hecho de que nos da una solución inicial a (la mayoría) de nuestros problemas?

Proporciona una clara separación de preocupaciones :

  • The Scraper solo se preocupa por obtener información para un canal de YouTube (no importa cómo)
  • El Gabinete solo se preocupa por almacenar/recuperar información para un canal
  • El Departamento de Corredores solo se preocupa de manejar las carreras a la oficina de YouTube
  • El registro de corredores solo se preocupa por almacenar/recuperar información para las carreras
  • El corredor asignado solo se preocupa por hacer la carrera por sí mismo.

Este es también el llamado concepto de Modularización vinculado con Loose Coupling .

Ampliemos un poco sobre el acoplamiento suelto y cómo esto hace que nuestro sistema sea mucho más escalable. Para entenderlo, necesitamos entender por qué las interfaces (contratos) entre módulos son importantes.

Tomemos la interacción entre el Rascador y el Gabinete , por ejemplo.

Ambos deben ponerse de acuerdo sobre cómo van a hablar entre ellos: ¿El Gabinete va a recibir las solicitudes por una llamada telefónica? ¿Un mensaje de texto? — También deben acordar cómo el Gabinete devolverá la información al Scraper: ¿es una carpeta con archivos? ¿Un archivo adjunto por correo electrónico?

Todo lo que importa es que necesitan tener un acuerdo, una interfaz, un contrato.

¿Por qué?

Una vez que se establece esa línea, no importa cuán compleja sea la estructura interna del Gabinete : para todos los cuidados de Scraper , puede ser una operación de una sola persona o un ejército de edificios de cinco tiendas.

Mientras el Gabinete pueda cumplir con su contrato de manera confiable, todo está bien.

Esto nos permite a nosotros y a nuestro equipo de desarrollo trabajar de forma independiente en cada uno de estos módulos, tomando las mejores decisiones para su desempeño interno.

Podemos paralelizar el trabajo de cada uno de ellos, porque al final, lo único que importa es que sepan hablar entre ellos.

Este concepto se aplica incluso en nuestra vida cotidiana: cada vez que pides algo online, ¿normalmente te importa quién es el transportista? ¿Sabes cómo funciona internamente una calculadora para devolverte los resultados? ¿Acaso te importa?

Que belleza, eh?

¿Qué pasa si tenemos más solicitudes de las que podemos manejar?

Dispara, eso no resuelve uno de nuestros problemas centrales, ¡todavía! ¡Construiremos un retraso que el Departamento de Corredores quizás no pueda abordar a tiempo!

eh, oh Eso no parece divertido.

Parece que necesitamos tener algún tipo de sistema para asegurarnos de que tenemos una acumulación de estas operaciones y manejarlas de la manera más eficiente que podamos, ¡sin dejar ninguna solicitud pendiente indefinidamente!

Propongamos algunas reglas para escalar el número de solicitudes al Departamento de Corredores .

Algunas cosas ( reglas ) que se nos pueden ocurrir son:

  1. Por orden de llegada: tratamos las solicitudes como una cola. Esto garantiza que, en algún momento, se atenderá la solicitud de obtener información para un canal específico. Simplemente no podemos garantizar cuándo.
  2. Priorizar canales de los que no tenemos datos (nuevos canales en nuestra app). Esta podría ser una estrategia inteligente: un canal del que no tenemos ningún dato significa que el usuario probablemente no pueda usar la aplicación. es decir, tener datos desactualizados es mejor que no tener ningún dato.
  3. Asegúrese de que no tengamos solicitudes duplicadas en nuestro backlog: si ya hay una tarea pendiente para un canal específico, podemos descartar más solicitudes.

Veamos un ejemplo para ver si todo eso tiene sentido.

Comenzamos nuestro día con una pizarra limpia: no hay solicitudes pendientes en la cartera de pedidos.

De repente, tenemos una afluencia de 7000 solicitudes: ¡la aplicación está desesperada por obtener información sobre 7k canales! Dada la lógica que describimos anteriormente, nosotros:

  1. Elimine cualquier solicitud de canal duplicada que pueda estar en este lote
  2. Compruebe para qué canales no tenemos información anterior; mover estos canales al principio de la cola
  3. Guarda la cola en nuestro Registro de corredores

Nuevamente, aquí está la belleza de la modularización nuevamente: este es un cambio interno en la forma en que opera el Departamento de Corredores .

El Scraper seguirá funcionando de la misma manera: seguirá pidiendo información sobre los canales (¡como un niño mimado que es!). Es problema del Departamento de Corredores almacenar y manejar esta cola internamente.

Recuerde: ¡todos los demás módulos son importantes para los contratos y las interfaces!

¡Uf!

Muy bien, amigo, eso fue mucho, pero espero que haya tenido tanto sentido para ti como para mí al escribir esto.

Ahora debería tener una muy buena comprensión de por qué son importantes la modularización, el acoplamiento flexible y las abstracciones.

Ahora también sabe cómo podemos, incluso antes de comenzar a escribir código, pensar en diseñar un sistema que se pueda escalar de forma independiente.

La próxima vez que comience a diseñar un sistema, intente responder las preguntas fundamentales de cómo puede diseñar módulos independientes y débilmente acoplados, incluso antes de apresurarse a comenzar a escribir el código.

De lo contrario, ¡podría terminar desarrollando el código heredado del mañana que nadie entiende y/o quiere tratar!