Conhecimento amaldiçoado
(immich.app)- Compartilhamento de uma lista de conhecimentos amaldiçoados adquiridos durante o desenvolvimento do Immich
- Organização de problemas inesperados encontrados em diferentes ambientes de software e infraestrutura
- Menciona questões de ferramentas e linguagens, incluindo metadados EXIF, tratamento de espaços em branco em YAML, PostgreSQL
- Alguns problemas se conectam diretamente à segurança, compatibilidade de plataforma e dependências de código aberto
- Foca em casos reais e causas que desenvolvedores devem ficar atentos
Visão geral
O time de desenvolvimento do Immich divulgou uma lista de conhecimentos amaldiçoados que não quer mais precisar reaprender durante o projeto. Trata-se de uma relação de armadilhas e problemas inesperados encontrados diretamente em diversas ferramentas, linguagens e plataformas durante o desenvolvimento e operação de serviços reais.
Lista de conhecimento amaldiçoado
-
4 de junho de 2025
- O Actions do Zitadel é uma funcionalidade amaldiçoada
- O recurso de script personalizado oferecido pelo Zitadel é baseado no motor JS, mas mostra limitações por não suportar grupos de captura nomeada em regex
-
30 de maio de 2025
- O Microsoft Entra suporta PKCE, mas não documenta isso no documento de descoberta do OpenID
- Isso causa um problema em que o recurso existente não é detectado no cliente
-
5 de maio de 2025
- As informações de tamanho nos metadados EXIF das imagens podem ser diferentes da imagem real
- Essa diferença pode causar erros em operações de recorte e redimensionamento
-
1 de abril de 2025
- O tratamento de espaços em YAML frequentemente se comporta de modo diferente do esperado
- Por ser sensível à formatação, há risco de interpretação de conteúdo diferente da intenção
-
20 de setembro de 2024
- Arquivos ocultos do Windows não são abertos com a flag "w"
- Combinado com a opção "hide dot files" do SMB, isso aumenta bastante a confusão no listagem e no processamento de arquivos
-
7 de agosto de 2024
- Em scripts Bash, é possível haver problema de carriage return (CRLF)
- Se o Git converter automaticamente LF para CRLF no checkout, isso pode causar erros na execução do script
-
7 de agosto de 2024
- No Cloudflare Workers, o fetch aplica http por padrão mesmo quando o https é especificado
- Isso pode causar problemas de rede, como loops de redirecionamento
-
21 de julho de 2024
- O compartilhamento de GPS em mobile remove silenciosamente os dados de GPS das imagens quando o app não tem permissão de localização
- Impacta a precisão de serviços baseados em localização e a privacidade
-
3 de julho de 2024
- O NOTIFY do PostgreSQL funciona apenas dentro de transações
- Ao usar com socket.io e postgres-adapter, ocorre gravação de WAL a cada 5 segundos, gerando carga
-
3 de julho de 2024
- Cada vez que um script npm é executado, é enviada uma solicitação HTTP ao registro npm
- Portanto, realizar health check via script é ineficiente
-
28 de junho de 2024
- Alguns usuários da comunidade JavaScript forçaram a inclusão de cerca de 50 dependências de pacotes sob o pretexto de retrocompatibilidade
- Todas essas dependências são mantidas pelo mesmo usuário
-
25 de junho de 2024
- A implementação do bcrypt usa apenas os primeiros 72 bytes da string
- Os caracteres após isso são ignorados, tornando senhas longas sem efeito
-
31 de janeiro de 2024
- O objeto Date do JavaScript indexa ano e dia a partir de 1, e o mês a partir de 0
- É uma estrutura fácil de causar confusão
-
9 de janeiro de 2024
- Em projetos CommonJS usando a opção --experimental-vm-modules do Node.js anterior à v20.8,
- ocorre segfault ao carregar novamente módulos CommonJS em módulos ES, fazendo o Node.js crashar
- Em projetos CommonJS usando a opção --experimental-vm-modules do Node.js anterior à v20.8,
-
28 de dezembro de 2023
- O limite de parâmetros do PostgreSQL é 65.535
- Isso gera limitação de desempenho em inserções em massa com grandes conjuntos de dados
-
26 de junho de 2023
- Há APIs da web disponíveis apenas em Secure Contexts
- Especificamente, APIs como a Clipboard funcionam apenas em ambientes https ou localhost
-
23 de fevereiro de 2023
- A implementação do remove do TypeORM afeta os dados de entrada
- Remove também a propriedade id do objeto original
Conclusão
Esse tipo de conhecimento amaldiçoado aparece com frequência em cenários reais de desenvolvimento e operação de serviços. Para desenvolvedores, mapear previamente as restrições e problemas ocultos por ferramenta, linguagem e ambiente ajuda na resolução eficiente de problemas e no desenvolvimento de serviços mais estáveis.
1 comentários
Opinião do Hacker News
Desde que vi isso pela primeira vez, já gostei bastante. Depois de dar uma olhada no commit de exemplo (aqui), passei a gostar ainda mais. O fato de o ‘conhecimento amaldiçoado’ ficar registrado junto com o código que resolveu o problema é especialmente legal. A primeira coisa que me veio à cabeça foi que esse recurso é necessário em todos os projetos. O log não é apenas catártico; ele transforma problemas chatos em uma experiência de aprendizado positiva. Ao ser exposto publicamente, dá para se identificar com pessoas que passaram pelos mesmos problemas e também pode virar uma ferramenta para evitar que se repitam.
Fiquei surpreso com a parte de que “não dá para fazer bind de 65 mil placeholders do PostgreSQL em uma única consulta”. No fim das contas, essa não é uma boa ideia e, por isso, é difícil culpar o PostgreSQL. Pelos comentários de issues no GitHub, parece que a abordagem mais razoável foi refatorar o ORM para quebrar uma consulta grande em várias menores. Pessoalmente, acho que algo em torno de 3.000~5.000 linhas por consulta é adequado. Alguém sugeriu que uma estratégia com tabela temporária e depois join — especialmente
COPY … FROM— dá melhor performance, mas isso exige uma mudança grande no código e, no fim, acabaram desistindo dessa abordagem. No geral, acho que é uma coletânea muito boa de relatos de experiência; serve bem como casos de alerta.Concordo que esse tipo de tentativa já é uma ideia “maldita”. Lendo toda a lista, essa “lista de maldições” parece menos um atalho de armadilha de design e mais um conjunto de lições que o desenvolvedor aprendeu na prática. Claro que a qualidade das informações varia e algumas ainda estão em andamento, mas ela é mais valiosa quando entendida como anotações pessoais de engenharia.
Me trouxe a sensação de processar todos os nomes de arquivos de um sistema de arquivos com ferramentas como
xargssem o caractere NUL. Se houver nomes de arquivo estranhos/quebrados ou memória limitada, isso pode dar ruim. O ideal é usarfind -print0junto comparallel -0/xargs -0. E comsed,grepe similares, cuidado para não causar erros de sequência de multibyte ao usar semLC_ALL=C.Eu mesmo já passei por isso ao fazer upsert em massa com ORM e dar aquele erro de 65 mil bindings. Principalmente quando a tabela tem coluna do tipo array do SQL, cada item inserido precisa ser bindado, então a quantidade de variáveis de bind pode variar. Aí, mesmo que linhas/colunas pareçam iguais em duas execuções, a quantidade de bindings pode mudar.
Outra estratégia é passar valores como argumentos de array (
text[],int[]etc). O PostgreSQL lida bem com isso.ANY()costuma ser um pouco mais lento queIN(), mas permite armazenar vários IDs em um único parâmetro. Talvez o ORM não tenha suporte para isso.Eu também reparei nisso: bindar tantos parâmetros é claramente uma prática amaldiçoada. Para processamento em massa, em geral deveria-se usar
COPY. Para acrescentar mais um caso amaldiçoado do Postgres: nomes de prepared statements são truncados silenciosamente emNAMEDATALEN-1(ondeNAMEDATALENé 64). Isso acontece desde 2001 e já existia antes também. ORMs precisam levar isso em conta. É raro uma pessoa usar prepared statement name com mais de 60 caracteres, mas ORMs costumam fazer isso.O item de “instalar 50 pacotes adicionais” foi realmente chocante. O autor daquele pacote provavelmente inflou bastante o número de downloads. Se a gente pensar no desperdício de banda e espaço em disco global, é uma pena. Fiquei curioso se isso não foi só para ganhar reputação.
O maintainer desse pacote na tal “lista de conhecimento amaldiçoado” é membro do TC39 e já foi figura polêmica em vários projetos conhecidos de JavaScript. Teve alegação de motivação financeira em uma questão específica de polyfill, mas, como o ganho em GitHub Sponsors e Tidelift não é tão grande, achei que talvez ele realmente tenha compatibilidade como um princípio. Em 2025, minha visão sobre isso mudou um pouco. Ele mantém manutenção crítica com consistência e, talvez, o papel de manter opiniões divergentes também seja necessário na comunidade.
Pode ser por fama ou personalidade também, mas há uma interpretação extrema de que isso é uma preparação para um ataque de supply chain de larga escala.
O autor ali é quase certamente o ljharb.
As ADS (Alternate Data Streams) do NTFS do Windows permitem esconder arquivos ilimitados dentro de arquivos existentes.
O macOS, por padrão, cria uma infinidade de arquivos ocultos e temporários em todos os volumes removíveis — incluindo data fork, xattr e indexação do Spotlight (md). Solução:
mdutil -X /Volumes/path/to/volE há telemetria opt-out demais (go, yarn, meilisearch, homebrew, vcpkg, dotnet, Windows, VS Code, Claude Code, macOS, Docker, Splunk, OpenShift, Firefox, Chrome, flutter, e por aí vai).
Telemetria opt-out: no caso do go, os dados de telemetria ficam armazenados localmente por padrão. Só ao pedir permissão do usuário é que um subconjunto aprovado é enviado para telemetry.go.dev. O envio pode ser ligado com
go telemetry one desligado completamente comgo telemetry off(veja a documentação).Só a telemetria opt-out é que parece realmente útil.
Sobre o relato de que “uma requisição HTTP é enviada ao registro do npm toda vez que um script npm é executado”, fiquei em dúvida se isso é verdade. Se for, é um comportamento impensável para um gerenciador de pacotes.
Talvez seja parte da verificação de atualização.
Provavelmente é isso mesmo por conta de update check. Às vezes aparece aquele banner de atualização.
Parece que esqueceu um ponto. O embate sobre tratamento de data/hora em metadados EXIF já é antigo
Issue de referência 1, issue de referência 2, issue de referência 3
Me veio à cabeça o livro “Madness beyond the gates” do Hadoop e Kerberos (link). Esse texto já me salvou várias vezes de chegar perto de surtar. Valeu, Steve, pelo trabalho; dá para imaginar o quanto custou pra extrair esse conhecimento amaldiçoado.
O conceito de reunir conhecimento amaldiçoado num único lugar é ótimo. Também faz sentido o relato de tropeços que só aparecem quando você se aprofunda num projeto. Vou fazer ideia de montar uma lista dessas em cada projeto daqui pra frente.
Esta entrada não é exatamente “conhecimento amaldiçoado”; é uma questão de segurança e privacidade relacionada a permissões em sistemas móveis.
Ótima ideia! Fiquei curioso se outras pessoas também querem compartilhar seus próprios conhecimentos amaldiçoados.
Na minha experiência, o nome de arquivo no MacOS também é amaldiçoado:
file.txteFILE.txtsão equivalentes).Em 1995, com o beta do Windows 95, criamos o primeiro CDDB. Distribuímos nomes de faixas de CDs em arquivo
.ini, e o projeto foi encerrado por causa do limite de tamanho de 64 KB do arquivo.ini.Correto. Se você cria um volume de sistema ou de dados APFS/HFS+ com
case-sensitive, vai dar problema sem dúvida.O item “1” é só configuração padrão. Tanto HFS quanto APFS têm opção
case-sensitive. NTFS também funciona de modo parecido. Esses sistemas de arquivos são case-retentive, então dá para fazer algo assim:O problema real é que o Steam se recusa a instalar em sistemas de arquivos
case-sensitive(mesmo havendo versão Linux).