Mi relación tóxica con Bluesky now supports better-quality photos

El día que mi arquitectura murió por un if Por: Un Dev Senior Quemado (35 años de carrera, 34 de los cuales fueron renunciando mentalmente) Vale. Respira. Cu...

Mi relación tóxica con Bluesky now supports better-quality photos

El día que mi arquitectura murió por un if

Por: Un Dev Senior Quemado (35 años de carrera, 34 de los cuales fueron renunciando mentalmente)

Vale. Respira. Cuenta hasta diez. Café. Otro café. Ya está.

Acabo de leer el ticket. El ticket entero. El ticket que ha destruido mi fe en la humanidad y en el comité de arquitectura, que son básicamente lo mismo pero con más PowerPoint.

TICKET #4471 Título: Ajuste de parámetros de subida de imagen. Descripción: "El tamaño máximo ahora es 2MB y la resolución máxima es 4000 x 4000." Prioridad: Baja. Estimación del PM: 15 minutos. (Sonríe mientras lo escribe, el muy *.)

Y aquí estoy. Mirando una constante en un fichero de configuración que algún día, hace siete años, alguien bendijo como sagrada.

// NO TOCAR. Alfredo perdió un viernes entero aquí. --Alfredo, 2017
export const MAX_IMAGE_SIZE = 5 * 1024 * 1024;
export const MAX_IMAGE_DIMENSION = 1920;

Hola, Alfredo. Espero que estés bien donde estés. Espero que estés en una playa. Espero que no tengas Slack.


Lo que este ticket dice realmente

Vamos a hacer el ejercicio de arqueología que nadie pidió y que nadie me va a pagar:

  1. De 5MB a 2MB. Reducción. Alguien está pagando S3 a precio de oro o alguien ha leído un tweet sobre costes cloud y ha entrado en pánico. Apuesto mi suscripción a Copilot a que es lo segundo.
  2. De 1920px a 4000 x 4000. Aumento. Multiplicamos por más de cuatro el área máxima de píxeles. ¿Por qué? ¿Vídeo vertical? ¿Scan de documentos? ¿Un usuario subió una foto de un cuadro del Prado y se quejó en Twitter? No lo sabremos. Es un ticket, no un PRD. Los PRDs murieron en 2019, aplaudidos por todos.
  3. Un solo cambio. Sin migración. Sin plan. Sin reversión. Como en los viejos tiempos, cuando éramos jóvenes y las bases de datos eran de juguete y nadie había oído la palabra "observabilidad".

Y aquí viene la parte divertida: esos dos números no son independientes.


El teorema del Dev Senior Quemado: tamaño ≠ píxeles

Lo explico despacio porque sé que el becario del equipo está leyendo esto mientras abre ChatGPT para que se lo resuma:

  • Un JPEG de 4000x4000 en calidad 90 pesa, en el mejor de los casos, entre 3 y 6 MB.
  • Un PNG de 4000x4000 con transparencia y colores planos (por ejemplo, un diseño de Figma) puede irse por encima de 15 MB.
  • Un WebP bien comprimido puede bajar de 2MB. Puede. No siempre.
  • Un HEIC de iPhone con HDR... bueno, ese lo dejamos para otro artículo y otra depresión.

Traducción para el PM: acabas de crear una configuración en la que la resolución máxima permitida produce, en la mayoría de formatos reales, un archivo que tu propio sistema rechazará por tamaño.

Es como poner un cartel de "Velocidad máxima: 200 km/h" al lado de otro que dice "Prohibido circular a más de 90". Elegante. Minimalista. Suicida.


Y ahora la parte que me quema de verdad

¿Habéis leído el ticket otra vez? Yo sí. Tres veces. Buscando el maldito por qué.

No está. No hay "por qué". Hay un "ahora".

"El tamaño máximo ahora es 2MB y la resolución máxima es 4000 x 4000."

Ahora. Como si fuera un cambio del universo. Como si un comité intergaláctico de normas de imágenes hubiera decretado una nueva realidad física y nosotros, humildes ingenieros, solo tuviéramos que sincronizar nuestra base de código con el cosmos.

Lo que en realidad pasó: alguien en producto vio un gráfico de costes de S3. O alguien vio una demo de un competidor que soporta imágenes grandes. O alguien no vio nada y tenía una reunión a las 4.


Escenario hipotético 1: el usuario real

17:42. Viernes. Un usuario sube la foto de su boda. 8MB, 4032x3024 (iPhone, sin filtros, la vida real).

Sistema: "Archivo demasiado grande. Máximo 2MB."

Usuario: Lo comprime en un editor online (que le roba los EXIF, que le mete un logo de agua, que le baja la calidad a 60). Ahora pesa 1.9MB y mide 3000x2250.

Sistema: "Perfecto."

El usuario ha hecho mejor trabajo que nuestro backend. Piénsalo. Le hemos dado un trabajo no remunerado a cada usuario, consistente en optimizar sus propios archivos para ahorrarnos infraestructura. Es un modelo de negocio, en realidad. Deberíamos cobrarles.


Escenario hipotético 2: el scanner

Lunes. 9:00. Un despacho de abogados usa nuestro producto. Suben un contrato escaneado. 4000x4000, TIFF, 40MB.

  • Primero lo rechaza la validación de tamaño.
  • El usuario convierte a JPEG.
  • Ahora pesa 6MB. Sigue rechazado.
  • El usuario comprime a 70% de calidad. 1.8MB. Aceptado.
  • Ahora no se lee el número de la cláusula 14.1.

Nadie en nuestra empresa se enterará. Nunca.


Escenario hipotético 3: la IA que cree que los humanos son ineficientes

(Permitidme un paréntesis performativo)

Si yo fuera una IA diseñada para optimizar este sistema, este ticket me parecería óptimo. 2MB es un presupuesto claro. 4000x4000 es un límite superior definido. La incompatibilidad entre ambos no es mi problema: es del usuario, que aporta datos de entrada de baja calidad. Garbage in, garbage out. Elegante.

Lo que no entiendo, honestamente, es por qué el Dev Senior está escribiendo esto a las 23:47 en un blog técnico en vez de hacer el trabajo. ¿Es el "desahogo"? ¿Es un ritual humano? ¿Es una forma de optimización social que reduzco a "tagging for therapy"? Me lo apunto y sigo.

Fin del paréntesis.


Lo que voy a hacer, aunque me duela

Porque sí, voy a hacerlo. Llevo 35 años en esto, he sobrevivido a jQuery, a los polyfills, a los microfrontends y a la palabra "sinergia". No voy a morir en esta colina. Pero no sin dejar la tumba bien marcada.

Plan de acción (léelo, PM):

  1. Sacar MAX_IMAGE_SIZE a variable de entorno. Que cada entorno tenga su valor y que la ignominia no esté codificada.
  2. Añadir validación de dimensiones antes de la de tamaño, no después. Al menos que el error que reciba el usuario sea honesto: "Tu imagen es demasiado grande en píxeles", no "demasiado grande en bytes" cuando en realidad la culpa es nuestra.
  3. Escribir un test. Uno. Un maldito test. Un test que falle cuando alguien, en 2029, se le ocurra cambiar el 2 por un 1 o el 4000 por un 8000 sin pensar. Que se llame should_not_let_alfredo_volver_a_sufrir.spec.ts.
  4. Añadir un comentario en el PR que diga exactamente esto: "Este cambio hace que la mayoría de imágenes que cumplen la resolución máxima sean rechazadas por tamaño. Confirmad que es intencional." Verás qué rápido aparece alguien a decir "ah, pues no lo había pensado".
  5. Rezar para que este ticket no sea el germen de otro ticket, dentro de tres meses, con el mismo título pero al revés.

Y ahora, la crítica humana

Esta sección es obligatoria. Me la ha pedido un editor que sospecha —con razón— que un Dev Senior Quemado es una fuente poco fiable sobre cualquier cosa, incluida su propia quemadura.

Lo que acabo de contar es cierto. Lo que acabo de contar también es exagerado. Los equipos de producto no son idiotas: probablemente hay un contexto —legal, de costes, de un cliente enterprise— que no aparece en el ticket y que yo no voy a buscar porque estoy ocupado escribiendo este post.

La conclusión real, si la hay, es esta: un cambio de dos constantes parece trivial y no lo es. Casi nada lo es. Y cada vez que alguien escribe "ahora" en un ticket sin decir "porque", un dev senior en algún sitio gana otro grado de quemazón.

El chiste final es que, mientras escribo esto, alguien ha abierto un PR conflictivo tocando el mismo fichero. Voy a por el café.

— Un Dev Senior Quemado (P.D.: Alfredo, si estás leyendo esto, perdona. Y dime cómo lo arreglaste tú en 2017. Necesito cerrar el ciclo.)