Codificação rígida.
A codificação rígida embute dados como caminhos, credenciais ou alíquotas no código-fonte, de modo que alterá-los exige editar e recompilar o programa.
A codificação rígida (hard coding) é a prática de desenvolvimento de software que consiste em embutir dados diretamente no código-fonte de um programa ou de outro objeto executável, em vez de obter os dados de fontes externas ou gerá-los em tempo de execução.
Dados codificados de forma rígida normalmente só podem ser modificados editando o código-fonte e recompilando o executável, embora possam ser alterados na memória ou em disco usando um depurador ou um editor hexadecimal.
Dados codificados de forma rígida são mais adequados para informações que não mudam, como constantes físicas, números de versão e elementos de texto estáticos.
Dados codificados de forma flexível (soft coding), por outro lado, codificam informações arbitrárias por meio de entrada do usuário, arquivos de texto, arquivos INI, respostas de servidores HTTP, arquivos de configuração, bancos de dados, argumentos de linha de comando, e são determinados em tempo de execução. Macros de pré-processador e constantes definidas em um cabeçalho ou módulo separado não são codificação flexível nesse sentido: elas dão ao valor um nome e um lugar único, mas ele continua fixado em tempo de compilação, e alterá-lo exige recompilar.
Visão geral
A codificação rígida exige que o código-fonte do programa seja alterado sempre que os dados de entrada ou o formato desejado mudam, quando poderia ser mais conveniente para o usuário final alterar esse detalhe por algum meio externo ao programa.
A codificação rígida muitas vezes é necessária, mas também pode ser considerada um antipadrão. Os programadores podem não ter elaborado uma solução de interface de usuário dinâmica para o usuário final, mas ainda assim precisam entregar o recurso ou lançar o programa. Isso costuma ser temporário, mas resolve, no curto prazo, a pressão para entregar o código. Mais tarde, a codificação flexível é feita para permitir que um usuário forneça parâmetros que deem ao usuário final uma forma de modificar os resultados ou o desfecho.
O termo "hard-coded" (codificado de forma rígida) foi inicialmente usado como uma analogia à fiação direta de circuitos e pretendia transmitir a inflexibilidade que resulta de seu uso no projeto e na implementação de software. No contexto de ambientes colaborativos de desenvolvimento extensíveis em tempo de execução, como os MUDs, a codificação rígida também se refere a desenvolver o núcleo do sistema, responsável por tarefas de baixo nível e pela execução de scripts, em oposição à codificação flexível, que consiste em desenvolver os scripts de alto nível interpretados pelo sistema em tempo de execução, com valores de fontes externas, como arquivos de texto, arquivos INI, bancos de dados, argumentos de linha de comando, respostas de servidores HTTP, arquivos de configuração e entrada do usuário. Nesse caso, o termo não é pejorativo e se refere ao desenvolvimento em geral, em vez de especificamente embutir dados de saída.
Backdoors
Codificar credenciais de forma rígida é uma maneira comum de criar uma backdoor. Credenciais codificadas de forma rígida normalmente não são visíveis em arquivos de configuração nem na saída de comandos de enumeração de contas e não podem ser facilmente alteradas ou contornadas pelos usuários. Se descoberta, um usuário pode conseguir desativar essa backdoor modificando e recompilando o programa a partir de seu código-fonte (se o código estiver disponível publicamente), descompilando ou fazendo engenharia reversa do software, editando diretamente o código binário do programa ou instituindo uma verificação de integridade (como assinaturas digitais, proteção contra adulteração e anti-trapaça) para impedir o acesso inesperado, mas tais ações costumam ser proibidas por um contrato de licença de usuário final.
Caminho de instalação fixo
Se um programa Windows é programado para presumir que está sempre instalado em C:\Program Files\Appname e alguém tenta instalá-lo em uma unidade diferente por motivos de espaço ou organização, ele pode falhar ao instalar ou ao executar após a instalação. Esse problema pode não ser identificado no processo de testes, já que o usuário comum instala na unidade e no diretório padrão, e os testes podem não incluir a opção de alterar o diretório de instalação. No entanto, é aconselhável que programadores e desenvolvedores não fixem o caminho de instalação de um programa, pois o caminho de instalação padrão depende do sistema operacional, da versão do SO e das decisões do administrador de sistemas. Por exemplo, muitas instalações do Microsoft Windows usam a unidade C: como seu disco rígido principal, mas isso não é garantido.
Pastas especiais
Alguns sistemas operacionais Windows têm as chamadas pastas especiais, que organizam os arquivos de forma lógica no disco rígido. Há problemas que podem surgir envolvendo a codificação rígida:
Caminho do perfil
Alguns programas Windows codificam de forma rígida o caminho do perfil para locais definidos pelo desenvolvedor, como C:\Documents and Settings\Username, o padrão no Windows 2000 e no Windows XP, ou C:\Users\Username, o padrão desde o Windows Vista. Um caminho assim deixa de funcionar quando o programa roda em outra versão do Windows ou quando o perfil está armazenado em uma rede ou foi realocado de outra forma. A maneira correta de obtê-lo é chamar a função GetUserProfileDirectory ou resolver a variável de ambiente %userprofile%. Outra suposição que os desenvolvedores costumam fazer é que o perfil está localizado em um disco rígido local.
Caminho da pasta Meus Documentos
Alguns programas Windows codificam de forma rígida o caminho para My Documents como ProfilePath\My Documents. Esses programas funcionariam em máquinas que rodam a versão em inglês, mas em versões localizadas do Windows essa pasta normalmente tem um nome diferente. Por exemplo, nas versões em italiano a pasta My Documents chama-se Documenti. My Documents também pode ter sido realocada usando o Redirecionamento de Pasta na Diretiva de Grupo no Windows 2000 ou superior. A maneira adequada de obtê-lo é chamar a função SHGetKnownFolderPath (SHGetFolderPath em versões anteriores ao Windows Vista).
Solução
Uma referência indireta, como uma variável dentro do programa chamada "FileName", poderia ser expandida acessando uma janela de diálogo de "selecionar arquivo", e o código do programa não precisaria ser alterado se o arquivo fosse movido.
A codificação rígida é especialmente problemática ao preparar o software para tradução para outras línguas.
Em muitos casos, um único valor codificado de forma rígida, como o tamanho de um vetor, pode aparecer várias vezes no código-fonte de um programa. Isso seria um número mágico. Isso costuma causar um bug no programa se algumas das ocorrências do valor forem modificadas, mas não todas. Esse tipo de bug é difícil de encontrar e pode permanecer no programa por muito tempo. Um problema semelhante pode ocorrer se o mesmo valor codificado de forma rígida for usado para mais de um valor de parâmetro, por exemplo, um vetor de 6 elementos e um comprimento mínimo de cadeia de entrada de 6. Um programador pode, por engano, alterar todas as instâncias do valor (muitas vezes usando o recurso de localizar e substituir de um editor) sem verificar no código como cada instância é usada. Ambas as situações são evitadas definindo constantes, que associam nomes aos valores, e usando os nomes das constantes para cada ocorrência no código.
Um caso importante de codificação rígida é quando cadeias de caracteres são colocadas diretamente no arquivo, o que obriga os tradutores a editar o código-fonte para traduzir um programa. (Existe uma ferramenta chamada gettext que permite deixar as cadeias de caracteres nos arquivos, mas deixa os tradutores traduzi-las sem alterar o código-fonte; ela efetivamente remove a codificação rígida das cadeias.)
Codificação flexível (soft coding)
A codificação flexível (soft coding) é um termo de programação que se refere a obter um valor ou função de algum recurso externo, como arquivos de texto, arquivos INI, arquivos de configuração, argumentos de linha de comando, bancos de dados, entrada do usuário e respostas de servidores HTTP. É o oposto da codificação rígida, que se refere a codificar valores e funções no código-fonte.
Prática de programação
Evitar a codificação rígida de valores que costumam ser alterados é uma boa prática de programação. Os usuários do software devem poder personalizá-lo conforme suas necessidades, dentro do razoável, sem precisar editar o código-fonte do programa. Da mesma forma, programadores cuidadosos evitam números mágicos em seu código para melhorar sua legibilidade e facilitar a manutenção. Essas práticas geralmente não são chamadas de codificação flexível.
O termo é geralmente usado quando a codificação flexível se torna um antipadrão. Abstrair valores e recursos em excesso pode introduzir mais complexidade e problemas de manutenção do que se teria ao alterar o código quando necessário. A codificação flexível, nesse sentido, foi destaque em um artigo no The Daily WTF.
Problemas potenciais
No extremo, programas com codificação flexível desenvolvem suas próprias linguagens de script mal projetadas e implementadas, além de arquivos de configuração que exigem habilidades avançadas de programação para serem editados. Isso pode levar à produção de utilitários para auxiliar na configuração do programa original, e esses utilitários muitas vezes acabam eles próprios usando codificação flexível.
A fronteira entre a configurabilidade adequada e a codificação flexível problemática muda conforme o estilo e a natureza de um programa. Programas de código fechado precisam ser muito configuráveis, pois o usuário final não tem acesso ao código para fazer qualquer alteração. Software interno e software com distribuição limitada podem ser menos configuráveis, pois distribuir cópias alteradas é mais simples. Aplicações web feitas sob medida costumam ser melhores com configurabilidade limitada, pois alterar os scripts raramente é mais difícil do que alterar um arquivo de configuração.
Para evitar a codificação flexível, considere o valor para o usuário final de qualquer flexibilidade adicional que você ofereça e compare-o com o aumento de complexidade e os custos contínuos de manutenção relacionados que a configurabilidade adicionada envolve.
Alcançando flexibilidade
Existem vários padrões de projeto legítimos para alcançar a flexibilidade que a codificação flexível tenta proporcionar. Uma aplicação que exige mais flexibilidade do que é apropriado para um arquivo de configuração pode se beneficiar da incorporação de uma linguagem de script. Em muitos casos, o projeto apropriado é uma linguagem específica de domínio integrada a uma linguagem de script estabelecida. Outra abordagem é mover a maior parte da funcionalidade de uma aplicação para uma biblioteca, fornecendo uma API para escrever rapidamente aplicações relacionadas.
Exemplo
Este módulo embute no código-fonte o endereço do banco de dados, as credenciais e a alíquota do imposto. Rodar o mesmo build contra um banco de homologação, trocar a senha ou acompanhar uma mudança tributária exige editar e reimplantar o código — e a senha acaba no controle de versão.
def connect():
return Database(host="10.0.0.12", user="admin", password="s3cr3t!")
def price_with_vat(amount):
return amount * 1.2
Valores que variam entre ambientes ou mudam com o tempo agora vêm do ambiente; o código mantém apenas a lógica (veja também Configuração Hardcoded).
import os
from dataclasses import dataclass
@dataclass(frozen=True)
class Settings:
db_host: str
db_user: str
db_password: str
vat_rate: float
@classmethod
def from_env(cls) -> "Settings":
return cls(
db_host=os.environ["DB_HOST"],
db_user=os.environ["DB_USER"],
db_password=os.environ["DB_PASSWORD"],
vat_rate=float(os.environ["VAT_RATE"]),
)
def connect(settings: Settings):
return Database(host=settings.db_host, user=settings.db_user, password=settings.db_password)
def price_with_vat(amount, settings: Settings):
return amount * (1 + settings.vat_rate)
Adaptado do artigo da Wikipédia “Hard coding” (revisão 1355219913), disponível sob a licença CC BY-SA 4.0; o texto foi traduzido e editado, e exemplos foram adicionados.