Trampas con las que los desarrolladores deben tener cuidado
(qouteall.fun)- Trampas poco intuitivas en las que suelen caer los desarrolladores: se presenta un resumen con las causas de bugs que aparecen con facilidad
- Se abordan problemas frecuentes en distintas tecnologías como HTML, CSS, Unicode/codificación de texto, punto flotante y tiempo
- Se enfatiza que las diferencias sutiles de sintaxis y comportamiento entre lenguajes y frameworks pueden causar malentendidos o errores
- Se explican con ejemplos trampas que pueden aparecer en entornos reales de producción en áreas clave del backend como concurrencia, redes y bases de datos
- A través de diversos ejemplos y enlaces de referencia, se muestran los problemas, las soluciones y mejoras para comportamientos inesperados
HTML y CSS
-
Valor predeterminado de
min-widthen Flexbox/Gridmin-widthesautopor defectomin-width: autose determina por el tamaño del contenido y tiene prioridad sobreflex-shrink,overflow: hidden,width: 0,max-width: 100%- Recomendación: especificar
min-width: 0
-
Diferencia entre horizontal y vertical en CSS
width: autointenta llenar el espacio del padre, mientras queheight: autose ajusta al contenido- En elementos inline, inline-block y float,
width: autono se expande margin: 0 autocentra horizontalmente;margin: auto 0no permite centrar verticalmente (aunque conflex-direction: columnsí es posible centrar verticalmente)- La fusión de márgenes solo ocurre en vertical
- Si cambia la dirección del layout, como con
writing-mode: vertical-rl, el comportamiento también se invierte
-
Block Formatting Context (BFC)
- Se puede crear un BFC con
display: flow-root(también conoverflow: hidden/auto/scroll,display: table, etc., aunque con efectos secundarios) - Un BFC puede evitar que se superpongan márgenes verticales entre hermanos adyacentes o que el margen de un hijo se “escape” fuera del padre
- Si un padre contiene solo hijos con float, su altura colapsa a 0 → se puede corregir con un BFC
- Si hay
borderopadding, no ocurre la fusión de márgenes
- Se puede crear un BFC con
-
Stacking Context
- Condiciones que crean un nuevo stacking context
- Propiedades de renderizado como
transform,filter,perspective,mask,opacity, etc. position: fixedostickyz-indexespecificado + posicionamientoabsolute/relativez-indexespecificado + elemento dentro de flexbox/gridisolation: isolate
- Propiedades de renderizado como
- Características
z-indexsolo se aplica dentro del stacking context- Las coordenadas de
position: absolute/fixedse basan en el ancestro posicionado más cercano stickyno funciona atravesando un stacking context- Incluso
overflow: visiblese recorta por efecto del stacking context background-attachment: fixedse posiciona con base en el stacking context
- Condiciones que crean un nuevo stacking context
-
Unidades del viewport
- En navegadores móviles, si la barra de direcciones o la barra de navegación desaparece al hacer scroll, el valor de
100vhcambia - Solución moderna: usar
100dvh
- En navegadores móviles, si la barra de direcciones o la barra de navegación desaparece al hacer scroll, el valor de
-
Referencia de Absolute Position
position: absoluteno toma como referencia al padre, sino al ancestrorelative/absoluteo stacking context más cercano
-
Comportamiento de Blur
backdrop-filter: blurno toma en cuenta los elementos alrededor
-
Invalidación de float
- Si el padre es
flexogrid, elfloatde los hijos no tiene efecto
- Si el padre es
-
width/heighten porcentaje- No funcionan si el tamaño del padre no está determinado de antemano (para evitar referencias circulares)
-
Características de los elementos inline
display: inlineignorawidth,height,margin-topymargin-bottom
-
Manejo de whitespace
- Por defecto, los saltos de línea en HTML se tratan como espacios y los espacios consecutivos se reducen a uno solo
- `` evita la reducción de espacios, pero tiene un comportamiento particular al inicio y al final
- En la mayoría de los casos, los espacios al inicio o al final del contenido se ignoran, pero `` es una excepción
- Los espacios o saltos de línea entre
inline-blockse muestran como separación real (no ocurre en flex/grid)
-
text-align- Se aplica a la alineación de texto y elementos inline, pero no a la alineación de elementos block
-
box-sizing- El valor predeterminado es
content-box→ no incluye padding/border - Si se usa
width: 100%junto conpadding, puede desbordar el área del padre - Solución:
box-sizing: border-box
- El valor predeterminado es
-
Cumulative Layout Shift
- Si no se especifican los atributos
widthyheighten ``, la carga tardía de la imagen puede provocar saltos de layout - Recomendación: especificar los atributos para evitar CLS
- Si no se especifican los atributos
-
Solicitudes de red de descargas de archivos en Chrome
- No aparecen en el panel Network de DevTools (se procesan en otra pestaña)
- Si hace falta analizarlas, usar
chrome://net-export/
-
Problemas de parsing de JavaScript dentro de HTML
- En casos como
console.log(''), el primer `` se interpreta como etiqueta de cierre - Referencia: Safe JSON in script tags
- En casos como
Unicode y codificación de texto
-
Code points y grapheme clusters
- Un grapheme cluster es la “unidad de carácter” en la GUI
- En caracteres ASCII visibles, 1 code point = 1 grapheme cluster
- Un emoji puede ser un solo grapheme cluster compuesto por varios code points
- En UTF-8, un code point ocupa de 1 a 4 bytes; la cantidad de bytes no coincide con la cantidad de code points
- En UTF-16, un code point ocupa 2 o 4 bytes (surrogate pair)
- El estándar no limita la cantidad de code points dentro de un cluster, pero las implementaciones sí suelen imponer límites por rendimiento
-
Diferencias en el comportamiento de strings según el lenguaje
- Rust: internamente usa UTF-8 para strings,
len()devuelve la cantidad de bytes, no permite indexación directa,chars().count()devuelve la cantidad de code points, valida estrictamente la validez de UTF-8 - Golang: un string es en la práctica un arreglo de bytes, la longitud y la indexación son por bytes, normalmente usa UTF-8
- Java, C#, JS: basados en UTF-16, miden la longitud en unidades de 2 bytes y también indexan en unidades de 2 bytes; existen surrogate pairs
- Python:
len()devuelve la cantidad de code points, y la indexación devuelve un string que contiene un code point - C++:
std::stringno impone restricciones de codificación, funciona como un vector de bytes y la longitud/indexación son por bytes - Entre los lenguajes mencionados, ninguno mide la longitud ni indexa por grapheme clusters
- Rust: internamente usa UTF-8 para strings,
-
BOM (Byte Order Mark)
- Algunos archivos de texto tienen BOM; por ejemplo, EF BB BF indica codificación UTF-8
- Se usa principalmente en Windows, y el software no Windows puede no procesarlo correctamente
-
Otras consideraciones
- Al convertir datos binarios a cadena, las partes inválidas se reemplazan por � (U+FFFD)
- Existen confusable characters (caracteres que se ven parecidos entre sí)
- Normalización (Normalization): por ejemplo, é puede representarse como U+00E9 (un solo code point) o U+0065+U+0301 (dos code points)
- Existen zero-width characters e invisible characters
- Diferencias de salto de línea: Windows usa CRLF
\r\n, Linux/MacOS usa LF\n - Han unification: caracteres con formas ligeramente distintas según el idioma usan el mismo code point
- La fuente renderiza correctamente incluyendo variantes por idioma
- En internacionalización, es necesario elegir la variante de fuente correcta
Punto flotante (Floating point)
-
Propiedades de NaN
- NaN no es igual a ningún valor, incluyendo a sí mismo (
NaN == NaNsiempre es false) NaN != NaNsiempre es true- El resultado de operaciones que incluyen NaN, en la mayoría de los casos, se propaga como NaN
- NaN no es igual a ningún valor, incluyendo a sí mismo (
-
Valores especiales
- Existen +Inf y -Inf, y son distintos de NaN
- -0.0 es un valor distinto de +0.0
- En comparaciones son iguales, pero en algunos cálculos se comportan distinto
- Ejemplo:
1.0 / +0.0 == +Inf,1.0 / -0.0 == -Inf
-
Compatibilidad con JSON
- El estándar JSON no permite NaN ni Inf
- En JS,
JSON.stringifyconvierte NaN e Inf anull - En Python,
json.dumps(...)imprime NaN e Infinity tal cual (violando el estándar)- Si se usa la opción
allow_nan=False, se produceValueErrorcuando hay NaN/Inf
- Si se usa la opción
- En Golang,
json.Marshaldevuelve error si existen NaN/Inf
- En JS,
- El estándar JSON no permite NaN ni Inf
-
Problemas de precisión
- La comparación directa de punto flotante puede fallar → se recomienda una forma como
abs(a - b) < ε - JS trata todos los números como punto flotante
- El rango seguro de enteros es
-(2^53 - 1)~2^53 - 1 - Fuera de ese rango, la representación de enteros es imprecisa
- Se recomienda usar
BigIntpara enteros grandes - Si JSON incluye enteros fuera del rango seguro, el valor resultante de
JSON.parsepuede ser impreciso - Los timestamps en milisegundos son seguros hasta el año 287,396; en nanosegundos aparecen problemas
- El rango seguro de enteros es
- La comparación directa de punto flotante puede fallar → se recomienda una forma como
-
No aplicación de leyes algebraicas
- Según el orden de las operaciones, por pérdida de precisión, la asociatividad y la distributividad no se cumplen estrictamente
- Las operaciones paralelas (multiplicación de matrices, sumas, etc.) pueden producir resultados no deterministas
-
Rendimiento
- La división es mucho más lenta que la multiplicación
- Si se divide varias veces por el mismo número, se puede optimizar calculando primero su recíproco y multiplicando
-
Diferencias según el hardware
- Compatibilidad con FMA (Fused Multiply-Add): algunos hardware hacen cálculos intermedios con mayor precisión
- Manejo del subnormal range: el hardware moderno lo soporta, pero algunos equipos antiguos lo tratan como 0
- Diferencias en los modos de redondeo
- Existen RNTE (redondeo al par más cercano), RTZ (truncamiento hacia 0), etc.
- En x86/ARM se pueden configurar como estado mutable local al hilo
- En GPU, el modo de redondeo varía según la instrucción
- Diferencias en el comportamiento de funciones matemáticas como trigonométricas y logaritmos
- x86 tiene FPU legacy de 80 bits y per-core rounding mode → no se recomienda usarlo
- Además de esto, varios factores pueden hacer que los resultados de punto flotante difieran según el hardware
-
Métodos para mejorar la precisión
- Construir un grafo de cálculo poco profundo (reducir cadenas continuas de multiplicaciones)
- Evitar casos donde los valores intermedios sean extremadamente grandes o pequeños
- Aprovechar operaciones de hardware como FMA
Tiempo (Time)
-
Segundo intercalar (Leap second)
- El timestamp Unix ignora los segundos intercalares
- Cuando ocurre un segundo intercalar, el tiempo puede alargarse o acortarse en el tramo cercano (Leap smear)
-
Zona horaria (Time zone)
- UTC y el timestamp Unix son comunes en todo el mundo
- La hora legible para personas depende de la zona horaria local
- Se recomienda guardar timestamps en la DB y convertirlos en la UI
-
Horario de verano (DST)
- En algunas regiones el reloj se ajusta una hora durante el verano
-
Sincronización NTP
- Durante la sincronización puede ocurrir que el tiempo "retroceda"
-
Configuración de zona horaria del servidor
- Se recomienda configurar el servidor en UTC
- En sistemas distribuidos, tener zonas horarias distintas por nodo puede causar problemas
- Después de cambiar la zona horaria del sistema, es necesario reconfigurar o reiniciar la DB
-
Reloj de hardware vs reloj del sistema
- El reloj de hardware no tiene concepto de zona horaria
- Linux: trata el reloj de hardware como UTC
- Windows: trata el reloj de hardware como hora local
Java
==compara referencias de objetos; para comparar el contenido del objeto hay que usar.equals- Si no se sobrescriben
equalsyhashcode, en map/set la identidad del objeto se evalúa por referencia - Si se modifica el contenido de un objeto usado como key de un map o como elemento de un set, el comportamiento del contenedor se rompe
- Un método que devuelve
Listpuede retornar, según el caso, unArrayListmutable o unCollections.emptyList()inmutable; si se modifica este último, ocurreUnsupportedOperationException - Existen métodos que devuelven
Optionalpero retornannull(no recomendado) - Si se hace return en un bloque
finally, una excepción ocurrida entryocatchse ignora y se aplica el valor de retorno definally - Existen librerías que ignoran interrupt; el proceso de inicialización de clases, incluyendo IO, puede romperse por un interrupt
- En un thread pool, las excepciones de una tarea enviada con
.submit()no se imprimen en el log por defecto y solo pueden verificarse mediante el future; si se ignora el future, no hay forma de ver la excepción- Las tareas de
scheduleAtFixedRatese detienen silenciosamente si ocurre una excepción
- Las tareas de
- Si un literal numérico empieza con 0, se trata como octal (
0123→ 83) - El debugger llama a
.toString()de las variables locales; algunas clases tienen efectos secundarios entoString(), así que el comportamiento del código puede cambiar durante la depuración (se puede desactivar en el IDE)
Golang
append()reutiliza memoria cuando hay capacidad disponible; al hacer append sobre un subslice, incluso puede sobrescribir la memoria padredeferse ejecuta al retornar de la función, no al salir del scope del bloquedefercaptura variables mutables- Sobre
nil- Un nil slice y un empty slice son distintos
- Un string no puede ser nil; solo existe la cadena vacía
- Un nil map permite lectura pero no escritura
- Comportamiento particular de interface nil: si el data pointer es null pero la type info no es null, no es igual a
nil
- Dead wait: existen casos reales de bugs de concurrencia en Go
- Hay varios tipos de timeout, tratados en detalle en net/http
C/C++
- Si guardas un puntero a un elemento de
std::vectory luego el vector crece, puede haber una reasignación y el puntero queda invalidado - Un
std::stringcreado a partir de una cadena literal puede ser un objeto temporal; llamar ac_str()puede ser riesgoso - Si modificas un contenedor mientras iteras sobre él, se invalidan los iteradores
std::removeno elimina realmente; solo reordena los elementos, para borrar hace faltaerase- Si un literal numérico empieza con 0, se interpreta como octal (
0123→ 83) - Undefined behavior (UB): durante la optimización, el UB puede transformarse libremente, así que es peligroso depender de él
- Acceder a memoria no inicializada es UB
- Convertir
char*a un puntero astructy acceder antes de que comience la vida del objeto es UB; se recomienda inicializar conmemcpy - El acceso inválido a memoria (como un puntero null) es UB
- El overflow/underflow de enteros es UB (en unsigned puede haber underflow por debajo de 0)
- Aliasing: si punteros de tipos distintos referencian la misma memoria, puede producirse UB por la strict aliasing rule
- Excepciones: 1) tipos con relación de herencia 2) conversiones a
char*,unsigned char*,std::byte*(la conversión inversa no aplica) - Para conversiones forzadas se recomienda
memcpyostd::bit_cast
- Excepciones: 1) tipos con relación de herencia 2) conversiones a
- El acceso a memoria desalineada es UB
- Alineación de memoria
- Los enteros de 64 bits deben estar en direcciones divisibles entre 8
- En ARM, el acceso desalineado puede provocar un crash
- Interpretar directamente un buffer de bytes como una
structpuede causar problemas de alineación - La alineación puede introducir padding en una
structy desperdiciar memoria - Algunas instrucciones SIMD (como AVX) solo pueden procesar datos alineados; normalmente requieren alineación de 32 bytes
Python
- Los argumentos por defecto de una función no se crean de nuevo en cada llamada; se conserva el valor inicial
SQL Databases
-
Manejo de Null
x = nullno funciona; hay que usarx is null- Null no es igual ni a sí mismo (similar a NaN)
- Un unique index permite valores Null duplicados (excepto en Microsoft SQL Server)
- En
select distinct, la forma de tratar Null varía según la base de datos count(x)ycount(distinct x)ignoran las filas con valores Null
-
Comportamiento general
- La conversión implícita de fechas puede depender de la timezone
- Un join complejo + distinct puede ser más lento que una consulta anidada
- En MySQL(InnoDB), si un campo string no es
utf8mb4, insertar caracteres UTF-8 de 4 bytes produce error - MySQL(InnoDB) por defecto no distingue mayúsculas de minúsculas
- MySQL(InnoDB) permite conversión implícita:
select '123abc' + 1;→ 124 - El gap lock de MySQL(InnoDB) puede provocar deadlock
- En MySQL(InnoDB), si
group byy las columnas deselectno coinciden, puede devolver resultados no deterministas - En SQLite, si no está en modo
strict, el tipo del campo importa poco - Las foreign keys pueden generar locks implícitos y provocar deadlocks
- El locking puede romper repeatable read isolation según la base de datos
- Las bases de datos SQL distribuidas pueden no soportar locking o tener comportamientos particulares (depende de cada DB)
-
Rendimiento/operación
- El problema de N+1 query no aparece en el slow query log porque cada consulta individual es rápida
- Las transacciones de larga duración pueden causar problemas de locks, etc. → se recomienda terminarlas rápido
- Casos de lock de tabla completa
- En MySQL 8.0+, al agregar un unique index/foreign key normalmente se puede procesar de forma concurrente
- En versiones antiguas de MySQL puede ocurrir un lock de tabla completa
- Si
mysqldumpno lleva la opción--single-transaction, hace un read lock de toda la tabla - En PostgreSQL,
create unique indexoalter table ... add foreign keyprovocan un read lock de toda la tabla- Cómo evitarlo: usar
create unique index concurrently - Para foreign key: usar
... not validy luegovalidate constraint
- Cómo evitarlo: usar
-
Consultas por rango
- Rangos no superpuestos:
- La condición simple
p >= start and p file 2>&1→ stdout+stderr ambos al archivo,cmd 2>&1 > file→ solo stdout al archivo, stderr queda igual
- La condición simple
- Rangos no superpuestos:
-
Los nombres de archivo distinguen mayúsculas y minúsculas (a diferencia de Windows)
-
Los ejecutables cuentan con un sistema de capabilities (se puede verificar con
getcap) -
Riesgo de variables unset: si
DIRno está definido,rm -rf $DIR/puede terminar ejecutandorm -rf /→ se puede prevenir conset -u -
Aplicar el entorno: para aplicar un script al shell actual, usar
source script.sh→ para aplicarlo de forma permanente, agregarlo a~/.bashrc -
Bash hace caché de comandos: si se mueve un archivo dentro de
$PATH, puede aparecerENOENT→ actualizar la caché conhash -r -
Si se usa una variable sin comillas, los saltos de línea se tratan como espacios
-
set -e: termina el script de inmediato ante errores, pero no funciona dentro de condicionales (||,&&,if) -
Conflicto entre K8s livenessProbe y el depurador: un depurador con breakpoints puede detener toda la app y hacer que falle la respuesta al health check → el Pod puede terminarse
React
- Modificar state directamente dentro del código de renderizado
- Usar Hooks dentro de if/loop → viola las reglas
- Omitir valores necesarios en el dependency array de
useEffect - Omitir código de limpieza (clean up) en
useEffect - Trampa de closure: se captura un state antiguo y eso provoca bugs
- Modificar datos en el lugar incorrecto → componente impuro
- Omitir
useCallback→ provoca rerenderizados innecesarios - Pasar valores no memorizados a componentes memorizados invalida la optimización de memo
Git
-
Rebase reescribe el historial
- Después de un rebase, un push normal genera conflicto → es necesario hacer force push
- Si cambia el historial de la rama remota, al hacer pull también se debe usar
--rebase --force-with-leasepuede evitar en algunos casos sobrescribir commits de otros desarrolladores, pero si solo se hace fetch y no pull, no brinda esa protección
-
Problema con revert de merge
- Hacer revert de un merge no revierte completamente sus efectos → al volver a hacer merge de la misma rama no habrá cambios
- Solución: hacer revert del revert o usar un método más limpio (backup → reset → cherry-pick → force push)
-
Precauciones relacionadas con GitHub
- Aunque se sobrescriba con force push un commit que contiene secretos como API keys, GitHub conserva el registro
- Si B es un fork privado de un repo privado A, y A se vuelve público, el contenido de B también queda expuesto (puede seguir siendo accesible incluso después de eliminarlo)
-
git stash pop: si ocurre un conflicto, el stash no se elimina -
.DS_Storelo genera macOS automáticamente → se recomienda agregar**/.DS_Storea.gitignore
Networking
- Algunos routers y firewalls cierran silenciosamente conexiones TCP inactivas → pueden invalidar los pools de conexiones de clientes HTTP o DB → solución: configurar TCP keepalive
- Los resultados de
traceroutetienen baja confiabilidad → en algunos casostcptraceroutepuede ser más útil - TCP slow start puede aumentar la latencia → se puede resolver desactivando
tcp_slow_start_after_idle - Problema de sticky packets en TCP: el algoritmo de Nagle retrasa el envío de paquetes → se puede resolver activando
TCP_NODELAY - Al colocar un backend detrás de Nginx, hay que configurar la reutilización de conexiones → si no se configura, en alta carga pueden fallar conexiones por falta de puertos internos
- Nginx hace buffering de paquetes por defecto → puede provocar retrasos en SSE (EventSource)
- El estándar HTTP no prohíbe body en solicitudes GET o DELETE → algunos lo usan, pero muchas librerías y servidores no lo soportan
- Se pueden alojar varios sitios web en una sola IP → la distinción la hacen el header HTTP
Hosty el SNI de TLS → hay sitios a los que no se puede acceder solo con la IP - CORS: cuando una solicitud se hace a otro origin, el navegador bloquea el acceso a la respuesta → el servidor debe configurar el header
Access-Control-Allow-Origin- Si también se envían cookies, se requiere configuración adicional
- Si frontend y backend usan el mismo dominio y puerto, no hay problema de CORS
Other
-
Precauciones con YAML
- YAML es sensible a los espacios →
key:valuees un error,key: valuees lo correcto - Si el código de país
NOse escribe sin comillas, puede interpretarse comofalse - Si un hash de commit de Git se escribe sin comillas, puede convertirse en número
- YAML es sensible a los espacios →
-
Problemas de Excel con CSV
- Al abrir un CSV, Excel hace conversiones automáticas
- Conversión de fechas:
1/2,1-2→2-Jan - Conversión inexacta de números grandes:
12345678901234567890→12345678901234500000
- Conversión de fechas:
- La causa es que Excel maneja internamente los números como floating point
- Existe un caso en el que el nombre de un gen, SEPT1, fue modificado incorrectamente por este problema
- Al abrir un CSV, Excel hace conversiones automáticas
1 comentarios
Opinión de Hacker News
Algunos routers y firewalls pueden cerrar silenciosamente conexiones TCP inactivas sin enviar ninguna señal a la aplicación; el código que mantiene pools de conexiones TCP, como las librerías cliente HTTP o los clientes de bases de datos, puede sufrir que una conexión quede inválida sin ninguna advertencia. Para resolverlo, se puede configurar
TCP keepalivedel sistema o, en HTTP, usar los headersConnection: keep-alive,Keep-Alive: timeout=30, max=1000. Una vez establecida una conexión TCP, los routers intermedios no conservan estado; el problema son los timeouts de sesión del firewall o del NAT. En ese caso tampoco llega un paquete RST. En entornos K8s, hubo casos donde la configuración del móduloconntrackestaba demasiado baja. Incluso si se usa HTTP Keep-Alive, eso solo ayuda a reutilizar la conexión y no a mantener viva la conexión en la red (enlace explicativo); HTTP Keep-Alive en realidad no genera paquetes, solo retrasa el cierre. En cambio, TCP Keep-Alive sí genera paquetes de forma periódica para reiniciar el temporizadorUn método que devuelve
Optional<T>puede devolvernull; esa práctica es demasiado confusa. Si tuviera suficiente serenidad emocional, habría propuesto un JEP para introducir una anotación como@java.lang.NonNullReference. Querría que, al declarar un tipo con esa anotación, el compilador tratara como error cualquier asignación denull; por ejemplo,Alphapodría aceptar asignación denull, peroBetadaría error. También parece que habría que revisar la especificación para entender cómo funciona realmente la eliminación de código muerto enjavac; por ejemplo, enif (true)la parte dondeb = nullen la práctica se omite, y legalmente podría ser código permitidoEn Kotlin eso ya da error de compilación, sin necesidad de ninguna anotación
Me pregunto si realmente hace falta usar
Optional<T>en un lenguaje connull; como en Python, donde el valor de retorno de una función se expresa simplemente comoT | Noney no como un objetoOptional, si al final hay que hacer la misma verificación, no queda tan clara la diferencia del framework. A menos que uses un estilo monádico particular, la comprobación termina siendo la mismaSe dijo que Java, C# y JS codifican los strings en memoria como algo tipo UTF-16, pero en Java eso no es correcto; en C# y JS podría pasar lo mismo. Si el tipo string de un lenguaje es lo bastante opaco, la representación en memoria es un detalle de implementación. En Java eso quedó claro desde la versión 9 (JEP relacionado). Esa también es una de las razones por las que, cuando existe FFI, es difícil cambiar detalles de implementación. Además, sobre los números en JS se dice que el entero máximo representable con exactitud es
2^53−1, pero en realidad enteros mayores como2^100también pueden representarse exactamente.2^53−1significa quen-1,nyn+1se representan todos con exactitud en undoubleIEEE; por eson == n-1yn == n+1dan ambosfalseEn C# la representación en memoria está muy fijada; como es común acceder directamente al buffer con
ReadOnlySpan<char>oraw char*,chares un tipo de punto de código UTF-16. Tal vez en JS se pueda esquivar de alguna maneraPreferiría decir
max safe integeren vez demax accurate integer(Sobre codificación base64) Respecto a que los strings en memoria de Java, C# y JS no sean de tipo UTF-16, puede que técnicamente sea cierto, pero sí hay casos donde, si codificas en base64 un string en un lenguaje basado en UTF-8 y luego lo decodificas en Java, surgen problemas por la representación UTF-16 de Java
Parece que los tips o la información en formato de manual solo se entienden más rápido cuando ya los conocías o casi los conocías. La mayoría de los manuales sirven más para organizar y repasar que para aprender desde cero, y son poco eficientes para enseñar a personas que no saben nada del tema
Leí “Traceroute Isn’t Real” con muchísimo interés. Ya venía sintiendo que los datos de traceroute eran muy inexactos o parecían carecer de sentido, y fue útil entender por qué (enlace original). Si alguien tiene información más actual, estaría bueno conocerla
Este texto no es tanto una lista de trampas reales como una recopilación de pequeños tips que su autor aprendió por experiencia. Muchas cosas solo aplican en contextos muy específicos, pero ese contexto no queda claro, y algunas incluso parecen incorrectas. Así que no hace falta tomar todo el texto al pie de la letra; conviene verlo más como una especie de flujo de ideas o notas
Lo de que en Python los valores por defecto de los argumentos no se crean de nuevo en cada llamada, sino que son valores almacenados, es algo que definitivamente hay que saber al usar variables
datetimesetvacío cuando no se pasara uno como argumento, pero elsetse reutilizaba y eso provocó un bug. Me tomó bastante tiempo entender la causaEn la primera “trampa” de la página se decía que
min-width: autodetermina el ancho mínimo según el contenido, pero eso no es cierto fuera de flex/grid. Según MDN, enblock,inline,table, etc.,autose ajusta a0(documentación oficial)La verdadera primera trampa es que “no se puede leer ninguna propiedad de CSS de forma aislada”. Tal como indica el propio nombre
cascading, los valores por defecto y el resultado de múltiples reglas terminan combinándose en algún punto, así que el contexto de todo el documento importaLa
cascadede las propiedades de texto en CSS todavía se puede entender. Pero el layout de CSS es demasiado difícil de entender desde cualquier perspectiva: diseñador de la página, implementador o usuario. No logro empatizar con para quién está hecho ese diseñoEn general es una buena lista. Tengo algunas observaciones.
-0.0y+0.0(cero negativo y cero positivo) se consideran iguales en comparaciones de punto flotante, pero hay formas de distinguirlos; por ejemplo, por su patrón de bits o por el resultado de1.0/-0.0 = -infinitoy1.0/0.0 = +infinito(low + high) / 2por riesgo de overflow y reemplazarlo porlow + (high - low) / 2, pero silowohighpueden ser negativos, eso podría simplemente mover el rango del overflow. Es un tema importante en la búsqueda binaria comúnrebasepuede cambiar el history, perorebasees, por definición, un command que reescribe el historyAunque los usuarios de ambos idiomas reconozcan conceptualmente el mismo carácter, no hay que descartarlo como una simple “variante tipográfica”. Que el code point de Unicode sea el mismo no significa que el reemplazo del carácter sea seguro; desde la perspectiva de un usuario japonés, ese tipo de sustitución puede incluso ser motivo para rechazar el uso de un producto
En realidad no se distingue entre la A inglesa y la A francesa, pero sí existen casos como
А(cirílica) yA(latina), que se ven igual aunque tengan code points distintos. Además, la unificación Han a menudo agrupa como uno solo caracteres con formas bastante diferentes, así que quienes estudian japonés o chino realmente pueden confundirse. Por ejemplo, el carácter '喝' (drink) puede verse bastante distinto según el caso, como se muestra en este enlace; incluso al copiarlo, la forma puede cambiar de inmediato, así de complejo es el tratamiento. La unificación Han es, en la práctica, un tema bastante complicadoSe mencionó que hay diferencias sutiles entre
numpyypytorch, pero sin explicar casos concretos no resulta muy útil y la información queda demasiado incompleta como para sentirlo como una trampa real