{"id":318,"date":"2026-09-11T21:58:48","date_gmt":"2026-09-12T04:58:48","guid":{"rendered":"https:\/\/www.mariatech.com.mx\/blog\/?p=318"},"modified":"2026-09-11T21:58:49","modified_gmt":"2026-09-12T04:58:49","slug":"el-bug-que-no-estaba-en-el-codigo-cuando-el-despliegue-depende-de-que-alguien-se-acuerde","status":"publish","type":"post","link":"https:\/\/www.mariatech.com.mx\/blog\/javascript\/el-bug-que-no-estaba-en-el-codigo-cuando-el-despliegue-depende-de-que-alguien-se-acuerde\/","title":{"rendered":"El bug que no estaba en el c\u00f3digo: cuando el despliegue depende de que alguien se acuerde"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Hay una categor\u00eda de fallas que no se detectan en revisi\u00f3n de c\u00f3digo, no las atrapan las pruebas automatizadas y no aparecen en los registros del servidor. El c\u00f3digo est\u00e1 bien. El despliegue sali\u00f3 bien. Y aun as\u00ed, el usuario ve el sistema roto.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Son las fallas que dependen de que una persona recuerde hacer algo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hace poco nos topamos con una de manual mientras trabaj\u00e1bamos en la reestructuraci\u00f3n de un sistema administrativo. Vale la pena contarla, no por lo ingenioso de la soluci\u00f3n, sino por lo contrario: porque la soluci\u00f3n correcta result\u00f3 ser la m\u00e1s aburrida de las tres que ten\u00edamos sobre la mesa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">El s\u00edntoma<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El escenario es conocido para cualquiera que haya desplegado una aplicaci\u00f3n web. Se corrige un error en un archivo JavaScript, se sube el cambio a producci\u00f3n, se verifica en el navegador y todo funciona. Al d\u00eda siguiente, un usuario reporta que el error sigue ah\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No sigue ah\u00ed. Lo que pasa es que su navegador guard\u00f3 una copia del archivo viejo y no tiene ninguna raz\u00f3n para pedir una nueva. Para el navegador, <code>app.js<\/code> es <code>app.js<\/code>: mismo nombre, misma direcci\u00f3n, no hay motivo para volver a descargarlo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La soluci\u00f3n cl\u00e1sica es agregarle un n\u00famero de versi\u00f3n a la direcci\u00f3n del archivo, algo como <code>cart.js?v=1.0.0<\/code>. Cuando el archivo cambia, se sube el n\u00famero, la direcci\u00f3n deja de ser la misma y el navegador descarga la copia nueva.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eso es exactamente lo que el sistema hac\u00eda. Y ah\u00ed estaba el problema.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">El mecanismo exist\u00eda y no serv\u00eda<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Al revisar el c\u00f3digo encontramos tres cosas:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uno de los archivos llevaba <code>?v=1.0.0<\/code>. Otro llevaba <code>?v=1.0.2<\/code>. Un tercero, tan cr\u00edtico como los anteriores, no llevaba nada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El n\u00famero se sub\u00eda a mano. Es decir, el mecanismo funcionaba siempre y cuando quien modificara el archivo se acordara de abrir otro archivo distinto, buscar la l\u00ednea correcta y cambiar un d\u00edgito. En la pr\u00e1ctica, casi nunca pasaba. Uno de los archivos hab\u00eda cambiado varias veces desde la \u00faltima vez que alguien toc\u00f3 su n\u00famero de versi\u00f3n.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Esto es lo interesante del caso: el mecanismo no faltaba. Estaba ah\u00ed, escrito, visible, aparentemente funcionando. Y era completamente in\u00fatil, porque su correcto funcionamiento depend\u00eda de la memoria de una persona en un momento en que esa persona est\u00e1 pensando en otra cosa.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un mecanismo de seguridad que depende de que alguien se acuerde no es un mecanismo de seguridad. Es una sugerencia.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Las tres opciones<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Al plantear la correcci\u00f3n aparecieron tres caminos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>El sofisticado.<\/strong> Incorporar los archivos al proceso de compilaci\u00f3n del framework, que genera nombres con una huella digital del contenido, resuelve el problema de ra\u00edz y de paso minifica los archivos. Es la respuesta que da cualquier gu\u00eda moderna.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>El intermedio.<\/strong> Compilar los archivos, pero seguir public\u00e1ndolos como hasta ahora, con el n\u00famero de versi\u00f3n resuelto por otro medio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>El aburrido.<\/strong> Dejar los archivos exactamente donde est\u00e1n y calcular el n\u00famero de versi\u00f3n a partir de la fecha de \u00faltima modificaci\u00f3n del propio archivo. Una l\u00ednea de c\u00f3digo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La primera opci\u00f3n era la recomendaci\u00f3n inicial. La descartamos por razones que no tienen que ver con la elegancia t\u00e9cnica.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Por qu\u00e9 gan\u00f3 el aburrido<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>La compilaci\u00f3n agrega un paso del que depende que el sitio no se caiga.<\/strong> Si el proceso de compilaci\u00f3n no se ejecuta en un despliegue, o se ejecuta mal, el sistema no encuentra los archivos y devuelve una pantalla en blanco. No en una secci\u00f3n: en todas, porque estos archivos se cargan desde una plantilla compartida. Cambi\u00e1bamos un problema silencioso y acotado por uno ruidoso y total.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>El archivo compilado es ilegible.<\/strong> Ese proyecto se estaba revisando pieza por pieza antes de aprobar cada cambio, y cada entrega habr\u00eda tra\u00eddo un bloque de miles de caracteres en una sola l\u00ednea junto al cambio real. Cuando revisar se vuelve dif\u00edcil, se revisa menos. Ese costo no aparece en ninguna estimaci\u00f3n y se paga durante meses.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Incorporar un solo archivo a un proceso que ning\u00fan otro usa deja el sistema m\u00e1s inconsistente de lo que estaba.<\/strong> Esa migraci\u00f3n tiene sentido cuando se hace completa, y ese momento ten\u00eda que ver con otras prioridades del proyecto, no con este problema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La soluci\u00f3n que qued\u00f3 calcula la fecha de modificaci\u00f3n del archivo y la usa como n\u00famero de versi\u00f3n. Cuando el archivo cambia, la fecha cambia, la direcci\u00f3n cambia y el navegador descarga la copia nueva. Cuando no cambia, todo sigue igual y el navegador usa lo que ya tiene.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sin proceso nuevo. Sin dependencias nuevas. Sin nada que recordar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La verificaci\u00f3n fue igual de directa: modificar uno de los archivos y comprobar en el navegador que efectivamente se descarg\u00f3 una copia nueva, con la herramienta de rendimiento del navegador confirmando que el archivo baj\u00f3 de la red y no de la cach\u00e9. Tambi\u00e9n que modificar un archivo no alteraba el n\u00famero de versi\u00f3n de los otros dos, para asegurar que cada uno llevara su propio control.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El bloque completo se hab\u00eda estimado entre cuatro y ocho horas. Cerr\u00f3 en aproximadamente una.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Lo que nos llevamos<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Buscar los mecanismos que dependen de la memoria de alguien.<\/strong> En cualquier sistema con algo de historia hay varios. Se reconocen por una pregunta: si la persona que hace este cambio estuviera distra\u00edda, \u00bfel sistema fallar\u00eda en silencio? Si la respuesta es s\u00ed, eso no est\u00e1 resuelto, est\u00e1 pendiente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Que un mecanismo exista no significa que funcione.<\/strong> Ver <code>?v=1.0.0<\/code> en el c\u00f3digo da una falsa sensaci\u00f3n de que el tema est\u00e1 atendido. La pregunta \u00fatil no es si el mecanismo est\u00e1, sino si alguien lo ejerci\u00f3 la \u00faltima vez que deb\u00eda.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>La soluci\u00f3n correcta no siempre es la m\u00e1s avanzada.<\/strong> La compilaci\u00f3n de assets es una buena pr\u00e1ctica y en muchos proyectos es lo que corresponde. Aqu\u00ed habr\u00eda resuelto el problema y creado uno mayor. La pregunta no es cu\u00e1l es la mejor herramienta en abstracto, sino cu\u00e1l resuelve este problema sin traer otros en este contexto y en este momento del proyecto.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Y la m\u00e1s barata merece evaluarse en serio, no descartarse por simple.<\/strong> Una l\u00ednea de c\u00f3digo que resuelve el problema completo, sin agregar dependencias ni pasos de despliegue, es un resultado mejor que una arquitectura correcta que nadie mantiene.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hay una categor\u00eda de fallas que no se detectan en revisi\u00f3n de c\u00f3digo, no las atrapan las pruebas automatizadas y no aparecen en los registros del servidor. El c\u00f3digo est\u00e1 bien. El despliegue sali\u00f3 bien. Y aun as\u00ed, el usuario ve el sistema roto. Son las fallas que dependen de que una persona recuerde hacer [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":319,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[],"class_list":["post-318","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript"],"_links":{"self":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/posts\/318","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/comments?post=318"}],"version-history":[{"count":0,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/posts\/318\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/media\/319"}],"wp:attachment":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/media?parent=318"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/categories?post=318"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/tags?post=318"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}