Guías prácticas y perennes para desarrolladores. Cada una se apoya en comandos reales y ejemplos que funcionan, y dice con claridad cuándo no usar lo que explica.
Abajo está todo, de lo más reciente a lo más antiguo.
Guías prácticas y perennes para desarrolladores. Cada una se apoya en comandos reales y ejemplos que funcionan, y dice con claridad cuándo no usar lo que explica.
Abajo está todo, de lo más reciente a lo más antiguo.
Cierra la sesión de un usuario en una app basada en sesiones y el servidor lo olvida en la siguiente petición. Cierra la sesión en una app basada en JWT y, a menos que hayas montado un mecanismo extra, el token que tiene en la mano sigue siendo válido hasta que expira. Esa diferencia es la decisión real detrás de “JWT vs sesión”. El resto se deriva de ahí. Qué guarda realmente una sesión Una sesión mantiene el estado del usuario en el servidor y al navegador solo le pasa una clave de búsqueda. ...
Busca “cachorro” en un sistema que solo compara palabras clave y un documento sobre el entrenamiento de perros no aparecerá, aunque cualquiera que leyera ambos los consideraría estrechamente relacionados. La búsqueda por palabras clave compara cadenas de texto. No sabe que “cachorro” y “perro” significan casi lo mismo. Los embeddings resuelven justo eso. Convierten un texto en una lista de números, un vector, ubicado de forma que los textos con significado parecido queden cerca de otros textos con significado parecido, sin importar qué palabras usen. ...
Envuelve una llamada fetch() en un try/catch, apunta a un endpoint que responde con un 404, y el bloque catch nunca se ejecuta. La promesa se resuelve. res.json() analiza el cuerpo que haya devuelto el servidor, muchas veces un payload de error como {"error": "user not found"}, y el resto de la función lo trata como el registro que pedía. Sin excepción, sin aviso en consola. El dato incorrecto sigue viajando hasta que algo más se rompe con él. ...
Una función que se llama a sí misma tiene una profundidad máxima, y es más pequeña de lo que la mayoría espera: 1.000 llamadas en CPython por defecto, entre 10.000 y 15.000 en Node y en los motores de los navegadores, según cuánto pese cada frame. Pasarse de ese límite no hace que el programa vaya más lento: lo hace fallar. Python lanza RecursionError: maximum recursion depth exceeded; JavaScript lanza RangeError: Maximum call stack size exceeded. ...
Estás montando un dashboard: un header, un sidebar, un área de contenido principal y un footer. Recurres a Flexbox porque es la herramienta de layout que conoces, y veinte minutos después tienes tres contenedores display: flex anidados, un sidebar que no mantiene su ancho sin un número mágico, y un footer que flota a mitad de página cuando el contenido es corto. Nada de eso es un bug de Flexbox. Estás usando una herramienta unidimensional para un problema bidimensional. ...
Pon go delante de una llamada a función y esa función se ejecuta en concurrencia con el resto del programa, gestionada por el runtime de Go en lugar del sistema operativo. Lanzarla es la parte fácil. La difícil es conseguir que dos goroutines se pasen un resultado sin pisarse el estado mutuamente, y de eso se encargan los channels. ¿Qué es una goroutine? Una goroutine es una función que corre de forma independiente de la que la lanzó, gestionada por el runtime de Go y no por el sistema operativo. Un thread del sistema operativo reserva un megabyte o más de stack y le cuesta al kernel tiempo real planificarlo. Una goroutine arranca con un stack de unos 2KB que crece según lo necesita, y el runtime multiplexa muchas goroutines sobre un puñado de threads del sistema operativo. Lanzar miles de ellas es normal. ...
Una clase que guarda un usuario en la base de datos, le manda un correo de bienvenida y da formato a un recibo: basta un cambio para romper dos funcionalidades que no tienen nada que ver entre sí. Tocas la plantilla del correo y arriesgas la escritura en la base de datos. Tocas el diseño del recibo y arriesgas el correo. SOLID son cinco reglas que atacan ese tipo de enredo desde ángulos distintos, y comparten una idea: una clase debe cambiar por un solo motivo, y el resto del código debe depender de lo que algo promete hacer, no de cómo lo hace. ...
Dos peticiones llegan al mismo endpoint “retirar 100€” con medio milisegundo de diferencia. La cuenta tiene 150€. Ambas peticiones leen ese saldo, ambas ven fondos suficientes, ambas aprueban, ambas restan 100€. La cuenta acaba en -50€, y ninguna rama del código debería haber permitido eso. Eso es una race condition: el resultado depende de qué operación termina primero, y “primero” nunca fue algo que el código decidiera. ¿Qué causa una race condition? Hacen falta dos ingredientes a la vez: estado mutable compartido, y más de un camino de ejecución que lo toca sin coordinarse. Los caminos pueden ser threads, tareas async, procesos, o dos servidores accediendo a la misma fila de base de datos. Quita cualquiera de los dos ingredientes y el bug desaparece. Un solo thread no puede competir contra sí mismo, y un estado inmutable no puede corromperse por leerse dos veces. ...
Un buscador que lanza una petición en cada pulsación manda cinco peticiones para “redis”, y cuatro llegan obsoletas antes de que vuelva la respuesta. Un handler de scroll que recalcula el layout se ejecuta cientos de veces por segundo y hace que la página se trabe. El mismo problema en los dos casos: el evento del DOM se dispara mucho más a menudo de lo que el handler necesita ejecutarse. Debounce y throttle lo resuelven de dos formas distintas. ...
Qué le hace realmente un decorador a tu función Quieres medir el tiempo de cada función que llama a una API externa lenta. Puedes pegar llamadas a time.perf_counter() en cada una, o escribir la medición una sola vez y aplicarla en todas partes. Un decorador es la segunda opción: es una función que toma otra función, la envuelve en un comportamiento adicional y devuelve la versión envuelta con el mismo nombre original. ...