Enlace de la presentacion:

@darking360

https://slides.com/darking360/pycon2020#/

@darking360

Hola PyCon 2020

@darking360

@darking360

Hola PyCon Colombia 2020 ❤️

Miguel Bolivar 🇻🇪

Ingeniero en Informatica 🤓

 

@darking360

Agenda

Caso de estudio

>

Empezar en un nuevo trabajo

>

Backend de la aplicacion ⚙️

>

Moralejas 🧙

@darking360

Nuevo trabajo 💻

@darking360

Lo logramos 🎉

Proyecto nuevo 😱

@darking360

@darking360

Proyecto iniciado 😱

>

Funcionando por 3 años 😱

>

Mantiene a unos 10.000 usuarios 🙃

¿Cierto? 😅

@darking360

@darking360

La historia

>

Decisiones

>

Preguntas 

>

Contexto 

No es un silver bullet ⚠️

@darking360

Iniciando la historia 🔥

Pixel art semi realista del ingeniero G ☝️ 

Legacy 💀

@darking360

Legacy ☠️

@darking360

Mordor 🔥
Frontend + React 👇

@darking360

Backend ⚙️

Pixel art semi realista del ingeniero K ☝️ 

💕

@darking360

@darking360

Pruebas 💡

>

Probar caminos normales

>

Probar caminos anomalos

Las pruebas buenas, son las que fallan

@darking360

Blindando la aplicación

>

Pruebas unitarias

>

Pruebas end-to-end

@darking360

Mocks! 

>

Sobreescribimos funciones

>

Cuándo fue llamada

>

Con qué parametros

>

Cuántas veces

@darking360

¿Pero por qué?

@darking360

¿Era suficiente?

@darking360

Eventos

>

No solo almacenamientos tradicionales

>

Datos para validar la aplicacion

>

Respaldo mediante eventos

>

Acciones principales cubiertas

@darking360

Segment

class SegmentAnalyticsContext():

    def __init__(self, action='', category='', event_name=None):
        event_name = 'GENERIC_SEGMENT_EVENT' if not event_name else event_name
        self.event_name = event_name
        self.segment_event_data = {'properties': {
            'source': 'python-api',
            'category': category,
            'action': action
        }}
    
    def send_event(self):
        analytics.track(
            event=self.event_name,
            user_id=self.segment_event_data['user_id'],
            anonymous_id=self.segment_event_data['anonymous_id'],
            properties=self.segment_event_data['properties'],
        )

@darking360

¿Era suficiente?

@darking360

Replicacion 🔥

>

Respaldo de los eventos y mejores consultas

@darking360

A donde vamos 🚋

>

Correos

>

Firmas

>

Almacenamiento externo

>

Búsquedas

@darking360

Separando ⛈️

@darking360

Qué usamos 🤔

💕

INSTALLED_APPS  = [
    integraciones1,
    integraciones
    # ... integraciones
]

@darking360

Exito! 🌠

@darking360

Pero todo va creciendo 🏗️

>

Más clientes

>

Más demanda

>

Más trafico

>

Más problemas

¿Cómo escalar? 🧗

@darking360

Delegar 💅

>

Workers

>

Estado de las tareas

>

¿Qué pasa si van mal?

>

Reintentar tareas

@darking360

Escogiendo 🧐

Servicios de terceros 💀

Celery

Rápido, probado, seguro, confiado por miles 💕

@darking360

Escogimos MRQ 😅 

>

Más facil que Celery

>

Tablero con estados

>

Mecanismos de reintento

>

Colas personalizadas 🤯

@darking360

Colas 🐿️

💕

@darking360

Pero era lo suficientemente rápido? 🤔

@darking360

💡 Eureka 💡

Handshake 250 milisegundos a 10 segundos 😱

Por cada solicitud 💀

Encolemos en el API y desencolemos en las integraciones 🔥

@darking360

Explorando 🗺️

>

Rápido entre ambas aplicaciones

>

Todos los beneficios de MRQ

>

Mecanismos de reintento

@darking360

Crecer y crecer 👵

Yo llegando a la empresa ☝️

@darking360

Deuda técnica 💸

@darking360

Mutabilidad 💀

DEFAULT_PARAMS = {"parse": False}
DEFAULT_PARAMS = {"parse": False}

def mutability_on(new_params):
  updated_params = DEFAULT_PARAMS
  updated_params.update(new_params)
  # Explosion de aqui hacia abajo 💣

@darking360

Watch and refactor 👾

>

Eventos de Segment al rescate

from copy import deepcopy

DEFAULT_PARAMS = {"parse": False}

def mutability_on(new_params):
  updated_params = deepcopy(DEFAULT_PARAMS)
  updated_params.update(new_params)
DEFAULT_PARAMS = {"parse": False}

def mutability_on(new_params):
  updated_params = { **DEFAULT_PARAMS }
  updated_params.update(new_params)
  # Python 3 en adelante

@darking360

Moralejas 🍎

@darking360

Herendando en Flask 👵

# Cool imports

class PostObject():
  
  def post_commit():
    pass
  
class PostNote(PostObject): # Herencia
  
  def post_commit():
    segment_data(self.note, "created")
  
  def handle_request():
    modify_data()
    self.post_commit()

@darking360

Composición 🏗️ 

# Cool imports

class PostObject():
  
  def post_commit():
    pass
  
class PostNote(PostObject): # Herencia
  
  self.schema = note_schema # Composicion
  
  def post_commit():
    segment_data(self.schema.dump(self.note).data, "created")
  
  def handle_request():
    modify_data()
    self.post_commit()

@darking360

Mutabilidad y funciones puras 🔍

resultado = lambda a, b : a + b
x = 2;
 
def add(y):
  x += y;
 
add(4);

@darking360

Moralejas del Backend ⚙️

@darking360

¿Por qué separar? 🧐

>

Aplicaciones monolíticas

>

Separación de preocupaciones

>

Una no afecta a la otra

@darking360

El encolado 🤯

MRQ

🤔

@darking360

Mongo y Redis 🤝

@darking360

Comunicación mediante colas 🌠

Yo cuando la comunicación entre aplicaciones funcionó ☝️

@darking360

Ahora sí la moraleja 😅

¿En busca de trabajo o empezando? 🙋

>

Pregunten M U C H O! 

>

Conozcan el proyecto

@darking360

Frameworks van y vienen 🍂

@darking360

Finalmente...

Se requiere algo de ingeniería para servir a 41679 usuarios 🚀

@darking360

BTW...

@darking360

Estamos contratando 😱

>

Python Developer

>

Full Stack Python + React

Apploi's Dev Team ❤️

@darking360

🎉

🎉

🎉

🎉

🎉

🎉

PyCon Colombia 2020
Muchas gracias 💞

@darking360

Preguntas 🤔

PyCon Colombia 2020 🇨🇴 ❤️ Se requiere algo de ingeniería para servir a 41679 usuarios

By Miguel Alejandro Bolivar Portilla

PyCon Colombia 2020 🇨🇴 ❤️ Se requiere algo de ingeniería para servir a 41679 usuarios

  • 882