66 pontos por GN⁺ 2025-08-18 | 1 comentários | Compartilhar no WhatsApp
  • Armadilhas nada intuitivas em que desenvolvedores costumam cair são organizadas para apresentar as causas de bugs que tendem a ocorrer com facilidade
  • Aborda problemas frequentes em várias tecnologias, como HTML, CSS, Unicode/codificação de texto, ponto flutuante e tempo
  • Enfatiza que diferenças sutis de sintaxe e comportamento em cada linguagem e framework podem gerar mal-entendidos ou erros
  • Explica com exemplos as armadilhas que podem surgir em ambientes reais de produção em áreas centrais de backend, como concorrência, redes e bancos de dados
  • Por meio de vários exemplos e links de referência, orienta sobre situações problemáticas, formas de resolvê-las e melhorias para comportamentos inesperados

HTML e CSS

  • Valor padrão de min-width em Flexbox/Grid

    • min-width é auto por padrão
    • min-width: auto é determinado pelo tamanho do conteúdo e tem precedência sobre flex-shrink, overflow: hidden, width: 0, max-width: 100%
    • Recomendação: declarar min-width: 0
  • Diferença entre horizontal e vertical no CSS

    • width: auto tenta preencher o espaço do elemento pai, enquanto height: auto se ajusta ao conteúdo
    • width: auto de elementos inline, inline-block e float não se expande
    • margin: 0 auto centraliza na horizontal, margin: auto 0 não centraliza na vertical (mas em flex-direction: column, a centralização vertical é possível)
    • Colapso de margem só ocorre na vertical
    • Se a direção do layout mudar, como em writing-mode: vertical-rl, o comportamento também se inverte
  • Block Formatting Context (BFC)

    • É possível criar um BFC com display: flow-root (também é possível com overflow: hidden/auto/scroll, display: table etc., mas há efeitos colaterais)
    • Um BFC pode evitar que margens verticais de irmãos adjacentes se sobreponham ou que a margem do filho “vaze” para fora do pai
    • Se o pai contiver apenas filhos com float, sua altura colapsa para 0 → isso pode ser corrigido com BFC
    • Se houver border ou padding, não ocorre colapso de margem
  • Stacking Context

    • Condições que criam um novo stacking context
      • Propriedades de renderização como transform, filter, perspective, mask, opacity etc.
      • position: fixed ou sticky
      • z-index definido + posicionamento absolute/relative
      • z-index definido + elemento dentro de flexbox/grid
      • isolation: isolate
    • Características
      • z-index só se aplica dentro do stacking context
      • As coordenadas de position: absolute/fixed se baseiam no ancestral posicionado mais próximo
      • sticky não funciona atravessando o stacking context
      • Mesmo overflow: visible é recortado pelo stacking context
      • background-attachment: fixed é posicionado com base no stacking context
  • Unidades de viewport

    • Em navegadores móveis, quando a barra de endereço/barra de navegação some da tela ao rolar, o valor de 100vh muda
    • Solução mais recente: usar 100dvh
  • Referência para Absolute Position

    • position: absolute não se baseia no pai, mas no ancestral relative/absolute ou stacking context mais próximo
  • Comportamento do blur

    • backdrop-filter: blur não leva em conta os elementos ao redor
  • Float sem efeito

    • Se o pai for flex ou grid, o float do filho não tem efeito
  • width/height em porcentagem

    • Não funciona se o tamanho do pai não tiver sido definido previamente (para evitar referência circular)
  • Características de elementos inline

    • display: inline ignora width, height, margin-top e margin-bottom
  • Tratamento de whitespace

    • Por padrão, quebras de linha em HTML são tratadas como espaço, e espaços consecutivos são reduzidos a um só
    • `` evita a redução de espaços, mas tem um comportamento peculiar no início/fim
    • Em geral, espaços no início/fim do conteúdo são ignorados, mas `` é uma exceção
    • Espaços/quebras de linha entre inline-block aparecem como espaçamento real (isso não ocorre em flex/grid)
  • text-align

    • Aplica-se ao alinhamento de texto e elementos inline, mas não ao alinhamento de elementos block
  • box-sizing

    • O valor padrão é content-box → não inclui padding/border
    • Com width: 100% + padding, o elemento pode ultrapassar a área do pai
    • Solução: box-sizing: border-box
  • Cumulative Layout Shift

    • Se `` não tiver os atributos width e height, o atraso no carregamento da imagem pode causar instabilidade no layout
    • Recomendação: definir os atributos para evitar CLS
  • Requisições de rede de download de arquivos no Chrome

    • Não aparecem no painel Network do DevTools (são processadas em outra aba)
    • Se precisar analisar, use chrome://net-export/
  • Problemas de parsing de JavaScript dentro de HTML

    • Em casos como console.log(''), o primeiro `` é interpretado como tag de fechamento
    • Referência: Safe JSON in script tags

Unicode e codificação de texto

  • Code points e grapheme clusters

    • Grapheme cluster é a “unidade de caractere” na GUI
    • Em caracteres ASCII visíveis, 1 code point = 1 grapheme cluster
    • Um emoji pode ser um único grapheme cluster composto por vários code points
    • Em UTF-8, um code point ocupa de 1 a 4 bytes, e a quantidade de bytes não coincide com a de code points
    • Em UTF-16, um code point ocupa 2 ou 4 bytes (par substituto, surrogate pair)
    • O padrão não impõe limite ao número de code points dentro de um cluster, mas implementações costumam ter limites por desempenho
  • Diferenças no comportamento de strings por linguagem

    • Rust: internamente usa strings UTF-8, len() retorna número de bytes, indexação direta não é possível, chars().count() retorna o número de code points, valida rigorosamente a validade do UTF-8
    • Golang: string é, na prática, um array de bytes; comprimento e indexação são em bytes; UTF-8 é o mais usado
    • Java, C#, JS: baseados em UTF-16, medem comprimento em unidades de 2 bytes, e a indexação também é nessa base; há surrogate pairs
    • Python: len() retorna o número de code points, e a indexação retorna uma string contendo um code point
    • C++: std::string não impõe restrições de codificação, funciona como um vetor de bytes, e comprimento/indexação são em bytes
    • Entre as linguagens mencionadas, nenhuma mede comprimento/faz indexação por grapheme cluster
  • BOM (Byte Order Mark)

    • Alguns arquivos de texto têm BOM; por exemplo, EF BB BF indica codificação UTF-8
    • É usado principalmente no Windows, e softwares fora do ecossistema Windows podem não conseguir lidar com BOM
  • Outros cuidados

    • Ao converter dados binários em string, partes inválidas são substituídas por � (U+FFFD)
    • Existem confusable characters (caracteres que parecem muito semelhantes entre si)
    • Normalização (Normalization): por exemplo, é pode ser representado como U+00E9 (um único code point) ou U+0065+U+0301 (dois code points)
    • Existem zero-width characters e invisible characters
    • Diferença de quebra de linha: no Windows é CRLF \r\n, no Linux/MacOS é LF \n
    • Unificação de Han (Han unification): caracteres com formas ligeiramente diferentes em cada idioma usam o mesmo code point
      • A fonte renderiza corretamente incluindo variantes por idioma
      • Em internacionalização, é necessário selecionar a variante de fonte correta

Ponto flutuante (Floating point)

  • Propriedades de NaN

    • NaN não é igual a nenhum valor, incluindo ele mesmo (NaN == NaN é sempre false)
    • NaN != NaN é sempre true
    • O resultado de operações que incluem NaN geralmente se propaga como NaN
  • Valores especiais

    • Existem +Inf e -Inf, diferentes de NaN
    • -0.0 é um valor distinto de +0.0
      • Em operações de comparação eles são iguais, mas em alguns cálculos se comportam de forma diferente
      • Exemplo: 1.0 / +0.0 == +Inf, 1.0 / -0.0 == -Inf
  • Compatibilidade com JSON

    • O padrão JSON não permite NaN nem Inf
      • Em JS, JSON.stringify converte NaN e Inf em null
      • Em Python, json.dumps(...) imprime NaN e Infinity como estão (violando o padrão)
        • Com a opção allow_nan=False, ocorre ValueError se houver NaN/Inf
      • Em Golang, json.Marshal retorna erro se houver NaN/Inf
  • Problemas de precisão

    • Comparação direta de ponto flutuante pode falhar → recomenda-se a forma abs(a - b) < ε
    • Em JS, todos os números são tratados como ponto flutuante
      • O intervalo seguro de inteiros é -(2^53 - 1) ~ 2^53 - 1
      • Fora desse intervalo, a representação de inteiros fica imprecisa
      • Para inteiros grandes, recomenda-se usar BigInt
      • Se JSON contiver inteiros além do intervalo seguro, o valor resultante de JSON.parse pode ser impreciso
      • Timestamps em milissegundos são seguros até o ano 287.396; em nanossegundos já causam problema
  • Leis de operação que não se aplicam

    • Dependendo da ordem das operações, por perda de precisão, associatividade e distributividade não valem estritamente
    • Operações paralelas (multiplicação de matrizes, soma etc.) podem produzir resultados não determinísticos
  • Desempenho

    • Divisão é muito mais lenta que multiplicação
    • Ao dividir várias vezes pelo mesmo número, é possível otimizar calculando primeiro o recíproco e multiplicando
  • Diferenças conforme o hardware

    • Suporte a FMA (Fused Multiply-Add): alguns hardwares fazem cálculos intermediários com maior precisão
    • Tratamento de subnormal range: hardwares modernos suportam, mas alguns antigos tratam como 0
    • Diferenças de modo de arredondamento
      • Existem modos como RNTE (arredondar para o par mais próximo), RTZ (truncar para 0) etc.
      • Em x86/ARM, isso pode ser configurado como estado mutável local à thread
      • Em GPU, o modo de arredondamento varia por instrução
    • Diferenças no comportamento de funções matemáticas como trigonométricas e logaritmos
    • x86 tem FPU legada de 80 bits e rounding mode por núcleo → não recomendado usar
    • Além disso, vários outros fatores podem fazer o resultado de ponto flutuante variar conforme o hardware
  • Como melhorar a precisão

    • Montar um grafo de cálculo mais raso (reduzir cadeias longas de multiplicação)
    • Evitar casos em que valores intermediários fiquem muito grandes ou muito pequenos
    • Aproveitar operações de hardware como FMA

Tempo (Time)

  • Segundo intercalar (Leap second)

    • O timestamp Unix ignora segundos intercalares
    • Quando ocorre um segundo intercalar, o tempo pode se alongar ou encurtar na região ao redor (Leap smear)
  • Fuso horário (Time zone)

    • UTC e timestamp Unix são comuns no mundo todo
    • Horários legíveis por humanos dependem do fuso horário local
    • Recomenda-se armazenar timestamps no banco de dados e converter na UI
  • Horário de verão (DST)

    • Em algumas regiões, o relógio é ajustado em 1 hora durante o verão
  • Sincronização NTP

    • Durante a sincronização, pode acontecer de o tempo “voltar para trás”
  • Configuração de fuso horário do servidor

    • Recomenda-se configurar servidores em UTC
    • Em sistemas distribuídos, diferenças de fuso entre nós causam problemas
    • Após mudar o fuso do sistema, pode ser necessário reconfigurar ou reiniciar o banco de dados
  • Relógio de hardware vs relógio do sistema

    • O relógio de hardware não tem conceito de fuso horário
    • Linux: trata o relógio de hardware como UTC
    • Windows: trata o relógio de hardware como horário local

Java

  • == compara referências de objetos; para comparar o conteúdo do objeto, é preciso usar .equals
  • Se equals e hashcode não forem sobrescritos, a identidade do objeto em map/set é julgada com base na referência
  • Se o conteúdo de um objeto usado como chave de map ou elemento de set for alterado, o comportamento do contêiner quebra
  • Métodos que retornam List podem, dependendo do caso, retornar um ArrayList mutável ou Collections.emptyList() imutável; ao modificar o segundo, ocorre UnsupportedOperationException
  • Existem métodos que retornam Optional mas devolvem null (não recomendado)
  • Se houver return em um bloco finally, uma exceção ocorrida em try ou catch é ignorada e o valor retornado por finally prevalece
  • Existem bibliotecas que ignoram interrupt, e a inicialização de classes, incluindo IO, pode ser quebrada por interrupt
  • Em thread pool, exceções de tasks passadas com .submit() não são registradas em log por padrão e só podem ser verificadas via future; se o future for ignorado, não há como ver a exceção
    • Tarefas scheduleAtFixedRate param silenciosamente quando ocorre exceção
  • Se um literal numérico começa com 0, ele é tratado como octal (0123 → 83)
  • O depurador chama .toString() de variáveis locais, e toString() em algumas classes tem efeitos colaterais, então o comportamento do código pode mudar durante a depuração (pode ser desativado na IDE)

Golang

  • append() reutiliza memória quando há folga de capacity; ao fazer append em um subslice, é possível sobrescrever até a memória do pai
  • defer é executado quando a função retorna, não quando o escopo do bloco termina
  • defer captura variáveis mutáveis
  • Sobre nil
    • nil slice e empty slice são diferentes
    • string não pode ser nil, só existe string vazia
    • nil map permite leitura, mas não escrita
    • comportamento peculiar de nil em interface: se o data pointer é null mas a type info não é null, então não é igual a nil
  • Dead wait: existem casos reais desse tipo de bug de concorrência em Go
  • Existem vários tipos de timeout, tratados em detalhe em net/http

C/C++

  • Ao armazenar ponteiros para elementos de std::vector, se o vector crescer pode ocorrer realocação, invalidando os ponteiros
  • Um std::string criado a partir de uma string literal pode ser um objeto temporário; chamar c_str() nesse caso é arriscado
  • Modificar um contêiner durante a iteração pode invalidar iterators
  • std::remove não remove de fato os elementos, apenas os reorganiza; para remover é preciso usar erase
  • Se um literal numérico começa com 0, ele é tratado como octal (0123 → 83)
  • Undefined behavior (UB): durante a otimização, UB pode ser alterado livremente, então depender disso é perigoso
    • Acesso a memória não inicializada é UB
    • Ao converter char* para ponteiro de struct, acessar antes do início da vida útil do objeto é UB; recomenda-se inicializar com memcpy
    • Acesso inválido à memória (como ponteiro nulo) é UB
    • Overflow/underflow de inteiro é UB (tipos unsigned podem sofrer underflow abaixo de 0)
    • Aliasing: se ponteiros de tipos diferentes referenciam a mesma memória, pode ocorrer UB pela strict aliasing rule
      • Exceções: 1) tipos em relação de herança 2) conversão para char*, unsigned char*, std::byte* (a conversão inversa não se aplica)
      • Para conversão forçada, recomenda-se memcpy ou std::bit_cast
    • Acesso a memória não alinhada é UB
  • Alinhamento de memória
    • Inteiros de 64 bits devem estar em endereços divisíveis por 8
    • Em ARM, acesso não alinhado pode causar crash
    • Interpretar diretamente um buffer de bytes como struct pode gerar problemas de alinhamento
    • O alinhamento pode criar padding em structs e desperdiçar memória
    • Algumas instruções SIMD (como AVX) só conseguem processar dados alinhados, normalmente exigindo alinhamento de 32 bytes

Python

  • Argumentos padrão de função não são recriados a cada chamada; o valor inicial fica armazenado

SQL Databases

  • Tratamento de Null

    • x = null não funciona; deve-se usar x is null
    • Null não é igual a si mesmo (semelhante a NaN)
    • Índices unique permitem Null duplicado (exceto no Microsoft SQL Server)
    • Em select distinct, a forma de tratar Null varia conforme o banco
    • count(x) e count(distinct x) ignoram linhas com valor Null
  • Comportamento geral

    • Conversão implícita de datas pode depender de timezone
    • Join complexo + distinct pode ser mais lento do que consulta aninhada
    • No MySQL(InnoDB), se um campo string não estiver em utf8mb4, inserir caracteres UTF-8 de 4 bytes causará erro
    • O MySQL(InnoDB) por padrão não diferencia maiúsculas de minúsculas
    • O MySQL(InnoDB) permite conversão implícita: select '123abc' + 1; → 124
    • Gap lock no MySQL(InnoDB) pode causar deadlock
    • No MySQL(InnoDB), quando group by e as colunas de select não batem, o resultado pode ser não determinístico
    • No SQLite, se não estiver em modo strict, o tipo do campo tem pouca importância
    • Foreign key pode gerar locks implícitos e causar deadlock
    • O locking pode quebrar o isolamento repeatable read dependendo do banco
    • Bancos SQL distribuídos podem não oferecer suporte a locking ou ter comportamentos peculiares (varia conforme o banco)
  • Desempenho/operação

    • O problema de N+1 query não aparece no slow query log porque cada query individual é rápida
    • Transações de longa duração podem causar problemas de lock etc. → recomenda-se encerrá-las rapidamente
    • Casos de lock na tabela inteira
      • No MySQL 8.0+, ao adicionar unique index/foreign key, na maioria dos casos o processamento concorrente é possível
      • Versões antigas do MySQL podem causar lock da tabela inteira
      • Se mysqldump não usar a opção --single-transaction, ocorre read lock na tabela inteira
      • No PostgreSQL, create unique index ou alter table ... add foreign key causam read lock na tabela inteira
        • Como evitar: usar create unique index concurrently
        • Para foreign key, usar ... not valid e depois validate constraint
  • Consultas de intervalo

    • Intervalos que não se sobrepõem:
      • A condição simples p >= start and p file 2>&1 → stdout+stderr vão para o arquivo; cmd 2>&1 > file → só stdout vai para o arquivo, stderr permanece como está
  • Nomes de arquivo diferenciam maiúsculas de minúsculas (diferente do Windows)

  • Arquivos executáveis têm um sistema de capabilities (getcap para verificar)

  • Risco com variável unset: se DIR estiver unset, rm -rf $DIR/ pode virar rm -rf / → dá para evitar com set -u

  • Aplicação do ambiente: para aplicar um script no shell atual, use source script.sh → para aplicar permanentemente, adicione em ~/.bashrc

  • O Bash faz cache de comandos: ao mover arquivos dentro de $PATH, pode ocorrer ENOENT → atualize o cache com hash -r

  • Ao usar variáveis sem aspas, quebras de linha são tratadas como espaços

  • set -e: encerra o script imediatamente em caso de erro, mas não funciona dentro de condicionais (||, &&, if)

  • Conflito entre livenessProbe do K8s e debugger: um debugger com breakpoint pode parar o app inteiro e fazer o health check falhar → o Pod pode ser encerrado

React

  • Modificar state diretamente no código de renderização
  • Usar Hook dentro de if/loop → violação das regras
  • Omitir valores necessários no dependency array do useEffect
  • Omitir o código de clean up no useEffect
  • Armadilha de closure: bugs causados por capturar um state antigo
  • Alterar dados no lugar errado → componente impuro
  • Deixar de usar useCallback → rerenderizações desnecessárias
  • Passar valores não memoizados para componentes memoizados invalida a otimização de memo

Git

  • Rebase reescreve o histórico

    • depois de um rebase, um push normal gera conflito → é necessário fazer force push
    • ao mudar o histórico de uma branch remota, também use pull --rebase
    • --force-with-lease pode, em alguns casos, evitar sobrescrever commits de outros desenvolvedores, mas se você só fizer fetch e não pull, essa proteção não funciona
  • Problema ao reverter merge

    • reverter um merge tem efeito incompleto → ao fazer merge da mesma branch novamente, pode não haver mudança alguma
    • solução: reverter o revert ou usar um método mais limpo (backup → reset → cherry-pick → force push)
  • Cuidados relacionados ao GitHub

    • mesmo que você sobrescreva com force push após commitar um secret como chave de API, o histórico continua no GitHub
    • se um repositório privado B for fork de um privado A, e A virar público, o conteúdo de B também fica público (e continua acessível mesmo após a exclusão)
  • git stash pop: se houver conflito, o stash não é removido

  • .DS_Store é criado automaticamente pelo macOS → recomenda-se adicionar **/.DS_Store ao .gitignore

Networking

  • Alguns roteadores e firewalls encerram silenciosamente conexões TCP ociosas → isso pode invalidar pools de conexão de clientes HTTP e DB → solução: configurar TCP keepalive
  • O resultado do traceroute tem baixa confiabilidade → em alguns casos, tcptraceroute é mais útil
  • TCP slow start pode aumentar a latência → pode ser resolvido desativando tcp_slow_start_after_idle
  • Problema de sticky packet no TCP: o algoritmo de Nagle atrasa o envio de pacotes → pode ser resolvido ativando TCP_NODELAY
  • Ao colocar um backend atrás do Nginx, é necessário configurar a reutilização de conexões → sem isso, em ambientes de alta carga, conexões podem falhar por falta de portas internas
  • O Nginx faz buffering de pacotes por padrão → isso pode causar atraso em SSE (EventSource)
  • O padrão HTTP não proíbe body em requisições GET e DELETE → alguns usam body, mas muitas bibliotecas e servidores não oferecem suporte
  • É possível hospedar vários sites em um único IP → a distinção é feita pelo header HTTP Host e pelo SNI do TLS → há sites que não funcionam com acesso direto por IP
  • CORS: ao fazer requisições para outra origin, o navegador bloqueia o acesso à resposta → o servidor precisa definir o header Access-Control-Allow-Origin
    • configurações adicionais são necessárias ao incluir envio de cookies
    • se frontend e backend estiverem no mesmo domínio e porta, não há problema de CORS

Other

  • Cuidados com YAML

    • YAML é sensível a espaçoskey:value é erro; key: value é o correto
    • o código de país NO, se usado sem aspas, pode ser interpretado como false
    • um hash de commit do Git sem aspas pode ser convertido em número
  • Problemas de CSV no Excel

    • ao abrir um CSV, o Excel faz conversões automáticas
      • conversão de data: 1/2, 1-22-Jan
      • conversão imprecisa de números grandes: 1234567890123456789012345678901234500000
    • isso acontece porque o Excel trata números internamente como floating point
    • há casos em que isso alterou incorretamente o nome de gene SEPT1

1 comentários

 
GN⁺ 2025-08-18
Comentários no Hacker News
  • Alguns roteadores e firewalls podem encerrar silenciosamente conexões TCP ociosas sem dar qualquer sinal à aplicação; por isso, códigos que mantêm pools de conexões TCP, como bibliotecas cliente HTTP ou clientes de banco de dados, podem sofrer com conexões invalidadas sem aviso algum. Para resolver isso, é possível configurar o TCP keepalive do sistema ou, no caso de HTTP, usar os cabeçalhos Connection: keep-alive, Keep-Alive: timeout=30, max=1000. Depois que uma conexão TCP é estabelecida, os roteadores intermediários não mantêm estado; o problema está no timeout de sessão do firewall ou do NAT. Nesses casos, também não chega pacote RST. Em ambiente K8s, já houve caso em que a configuração do módulo conntrack estava baixa demais. Mesmo usando HTTP Keep-Alive, isso só ajuda na reutilização da conexão e não mantém a conexão de rede ativa (link explicativo); HTTP Keep-Alive na prática não gera pacotes, apenas adia o encerramento, enquanto TCP Keep-Alive gera pacotes periodicamente para resetar o temporizador

    • TCP Keep-Alive pode não funcionar bem em dispositivos móveis; sistemas operacionais móveis às vezes só conseguem rastrear ou gerenciar individualmente pacotes de keep-alive gerados no nível da aplicação. Como o TCP Keep-Alive opera abaixo da camada da aplicação, ele pode ser desativado em certos casos, e mesmo assim o app continuar acessível
  • Métodos que retornam Optional<T> podem devolver null, e essa prática é confusa demais. Se eu estivesse com paciência emocional, teria proposto um JEP introduzindo uma anotação como @java.lang.NonNullReference. A ideia seria declarar tipos com essa anotação para que o compilador tratasse atribuições de null como erro; por exemplo, em Alpha a atribuição de null seria permitida, mas em Beta geraria erro. Acho que também valeria olhar a especificação para entender como o dead code elimination realmente funciona no javac; por exemplo, em if (true) a parte b = null na prática é eliminada, e talvez legalmente esse código ainda seja permitido

    • Em Kotlin isso já vira erro de compilação, sem precisar de anotação

    • Fico na dúvida se faz sentido usar Optional<T> em uma linguagem que já tem null. Se no Python o retorno de função é escrito simplesmente como T | None, e ainda assim você precisa fazer checagem em vez de receber um objeto Optional, a diferenciação do framework fica meio nebulosa. A menos que se use um estilo monádico específico, no fim a checagem acaba sendo a mesma

  • Foi dito que Java, C# e JS codificam strings em memória como algo do tipo UTF-16, mas isso está errado no caso de Java; C# e JS talvez também. Em qualquer linguagem, se o tipo string for suficientemente opaco, a forma de representação em memória é detalhe de implementação. Em Java isso ficou claro a partir da versão 9 (JEP relacionado), e esse também é um dos motivos pelos quais, quando há FFI, fica difícil mudar detalhes de implementação. Também foi dito que o max accurate integer de JS é 2^53−1, mas na verdade inteiros bem maiores, como 2^100, também podem ser representados com exatidão. O ponto de 2^53−1 é que n-1, n e n+1 são todos representáveis exatamente em IEEE double; portanto, tanto n == n-1 quanto n == n+1 resultam em false

    • Em C#, a representação em memória é bem fixa. Há muitos casos de acesso direto ao buffer usando ReadOnlySpan<char> ou raw char*, então char é um tipo de code point UTF-16. Talvez em JS ainda dê para escapar disso de algum jeito

    • Eu preferiria o termo max safe integer em vez de max accurate integer

    • (Sobre codificação base64) Quanto à ideia de que strings em memória de Java, C# e JS não são do tipo UTF-16, isso pode até ser tecnicamente correto, mas há casos em que, se uma string codificada em base64 em uma linguagem baseada em UTF-8 for decodificada em Java, surgem problemas por causa da representação UTF-16 do Java

  • Parece que dicas ou informações em formato de manual só aceleram o entendimento daquilo que a pessoa já sabe ou quase sabia. A maioria dos manuais funciona melhor para organização e revisão do que para o aprendizado em si, e é ineficiente para ensinar quem não sabe absolutamente nada

    • Um manual existe, em essência, para registrar informação sem depender apenas da memória. A maioria dos manuais Unix é assim. Você já sabe o que um software faz, mas consulta o manual quando esquece detalhes de uso. Já um iniciante completo precisa de tutorial ou guia para aprender os conceitos. O manual funciona mais como preparação para fazer perguntas melhores
  • Li com muito interesse o texto “Traceroute Isn’t Real” e gostei de finalmente entender por que os dados de traceroute tantas vezes parecem imprecisos ou sem sentido (link original). Se alguém tiver informações mais atualizadas, seria ótimo saber

  • Este texto não é bem uma lista de armadilhas reais, mas sim uma coleção de pequenas dicas que o autor aprendeu na prática. Muita coisa só se aplica em contextos específicos e estreitos, mas o contexto não fica claro, e parte do conteúdo até parece incorreto. Então não é preciso levar o texto todo ao pé da letra; vale mais como fluxo de pensamento ou anotações

  • Essa história de que valores padrão de argumentos em Python não são recriados a cada chamada, mas sim valores armazenados, é algo essencial de saber ao usar variáveis datetime

    • Eu não era alguém que usava Python o tempo todo, mas nesta semana sofri bastante por causa desse comportamento de valores padrão armazenados. Eu queria atribuir um set vazio quando nenhum set fosse passado como argumento, mas o set acabou sendo reutilizado e gerou bug. Demorei bastante até descobrir a causa
  • Na primeira “armadilha” da página, foi dito que min-width: auto define a largura mínima com base no conteúdo, mas isso não é verdade fora de flex/grid. Segundo o MDN, em block, inline, table etc., auto é ajustado para 0 (documentação oficial)

    • A verdadeira primeira armadilha é que “não dá para ler nenhuma propriedade CSS de forma isolada”. Como o próprio nome cascading sugere, os valores padrão e o resultado de várias regras acabam se combinando em algum ponto, então o contexto do documento inteiro importa

    • Até dá para entender a cascade dos atributos de texto em CSS, mas layout em CSS é difícil demais de entender, seja do ponto de vista do designer da página, de quem implementa ou de quem usa. É difícil ter empatia com um design assim e pensar para quem ele foi feito

  • No geral é uma boa lista, embora eu tenha algumas observações.

    • Sobre unificação Unicode, o fato de um mesmo caractere com o mesmo significado em várias línguas usar o mesmo code point e aparecer de forma diferente conforme a fonte não é uma armadilha. Os hanzi/kanji do exemplo são usados de forma quase idêntica tanto em chinês quanto em japonês, e usuários de ambas as línguas reconhecem as outras variantes como o mesmo caractere conceitual. O autor fala como se a letra “A” precisasse ser definida separadamente para inglês e francês, mas não é assim. Veja o verbete Han unification
    • -0.0 e +0.0 (zero negativo e zero positivo) são tratados como iguais em comparações de ponto flutuante, mas há formas de distingui-los, por exemplo pelo padrão de bits ou pelos resultados 1.0/-0.0 = -infinito e 1.0/0.0 = +infinito
    • Concordo muito com a recomendação de usar UTC como fuso horário do servidor. Use UTC em servidores, logs, armazenamento de fotos e qualquer lugar que exija preservação ou timestamps precisos; hora local deve ficar só para conversa
    • Foi dito que, em inteiros, (low + high) / 2 tem risco de overflow e por isso se deve usar low + (high - low) / 2, mas se low ou high puderem ser negativos isso pode apenas deslocar a faixa do overflow. É uma questão importante em buscas binárias em geral
    • Também é uma grande armadilha usar incorretamente tipos e operações inteiras em C/C++; veja este guia relacionado
    • Foi dito que rebase pode mudar o histórico, mas rebase é, por definição, um comando que reescreve o histórico
    • Embora usuários das duas línguas reconheçam conceitualmente o mesmo caractere, não dá para tratar isso como mera “variação de fonte”. O fato de o code point Unicode ser o mesmo não significa que a substituição de caracteres seja segura; para usuários japoneses, esse tipo de troca pode até ser motivo para rejeitar o uso de um produto

    • De fato, não se distingue A em inglês de A em francês, mas há casos como А (cirílico) e A (latino), que parecem iguais, mas têm code points diferentes. A unificação Han também costuma agrupar em um único ponto caracteres com aparência bem diferente, o que pode confundir estudantes de japonês ou chinês na prática. Por exemplo, o caractere '喝' (drink) pode aparecer de formas bastante diferentes, como mostra este link, e às vezes até parece mudar de forma imediatamente ao copiar e colar, de tão complexo que é o tratamento. Han unification é, na prática, um tema bastante espinhoso

  • Foi mencionado que há diferenças sutis entre numpy e pytorch, mas sem exemplos concretos isso não é muito útil e fica informação insuficiente para parecer uma armadilha real