Como a separação de código e dados se tornou uma prática?

29

Por favor, leia a pergunta com atenção: ela pergunta como , não por quê .

Recentemente, deparei com esta resposta , que sugere o uso de um banco de dados para armazenar dados imutáveis:

Parece que muitos dos números mágicos que você descreve - principalmente se dependem de parte - são realmente dados, não código. [...] Pode significar um banco de dados do tipo SQL ou simplesmente um arquivo de texto formatado.

Parece-me que, se você tem dados que fazem parte do que o seu programa faz, então a coisa a fazer é colocá-los no programa . Por exemplo, se a função do seu programa é contar vogais, o que há de errado em ter vowels = "aeiou"nela? Afinal, a maioria das linguagens possui estruturas de dados projetadas exatamente para esse uso. Por que você se incomodaria em separar os dados colocando-os em um "arquivo de texto formatado", conforme sugerido acima? Por que não apenas tornar esse arquivo de texto formatado na sua linguagem de programação preferida? Agora é um banco de dados? Ou é código?

Tenho certeza que alguns vão pensar que esta é uma pergunta idiota, mas eu pergunto com toda a seriedade. Eu sinto que "código e dados separados" estão emergindo culturalmente como algum tipo de verdade auto-evidente, junto com outras coisas óbvias, como "não dê nomes enganosos às suas variáveis" e "não evite usar espaços em branco apenas porque sua linguagem considera insignificante ".

Tomemos, por exemplo, este artigo: O problema com a separação de dados do código fantoche . O problema ? Que problema? Se o Puppet é uma linguagem para descrever minha infraestrutura, por que não pode também descrever que o servidor de nomes é 8.8.8.8? Parece-me que o problema não é que códigos e dados sejam misturados, 1 mas que o Puppet carece de estruturas de dados suficientemente ricas e de maneiras de interagir com outras coisas.

Acho essa mudança perturbadora. A programação orientada a objetos disse "queremos estruturas de dados arbitrariamente ricas" e, portanto, dotou as estruturas de dados com poderes de código. Você obtém o encapsulamento e a abstração como resultado. Até os bancos de dados SQL possuem procedimentos armazenados. Quando você sequestra dados em YAML ou arquivos de texto ou bancos de dados burros, como se estivesse removendo um tumor do código, perde tudo isso.

Alguém pode explicar como surgiu essa prática de separar dados de código e para onde está indo? Alguém pode citar publicações de luminares ou fornecer alguns dados relevantes que demonstrem "código separado dos dados" como um mandamento emergente e ilustrem sua origem?

1: se alguém pode fazer essas distinções. Estou olhando para você, programadores Lisp.

Phil Frost
fonte
5
Sinta-se à vontade para enterrar todos os html e css no seu idioma preferido.
JeffO
3
Acho que o autor da citação quis dizer é que os números mágicos não são realmente imutáveis.
Pieter B
4
Não há nada errado em codificar as vogais. Se seu aplicativo for usado apenas para contar as vogais em inglês.
Michael Paulukonis
3
Um grande motivo técnico para separar código e dados é não precisar recompilar o código quando os dados são alterados. Portanto, eu questionaria se isso se aplica na mesma extensão às linguagens de script.
user16764
1
@ MichaelPaulukonis: E colocá-lo em um banco de dados é uma solução falsa. Mudanças necessárias para o holandês? Zero (nem mesmo uma alteração no banco de dados). Alterações necessárias para francês / alemão? Pelo menos suporte ISO-8859-1. (Mais que DB). Alterações necessárias para grego / russo? Suporte Unicode (mais que DB). Na verdade, não consigo pensar em nenhuma linguagem em que esse banco de dados seja de alguma ajuda.
MSalters 25/02

Respostas:

22

Existem muitas boas razões para separar os dados do código e outras não. A seguir, lembre-se.

Oportunidade. Quando o valor dos dados é conhecido? É no momento em que o código é gravado, quando é compilado, vinculado, liberado, licenciado, configurado, iniciado ou em execução. Por exemplo, o número de dias em uma semana (7) é conhecido com antecedência, mas a taxa de câmbio USD / AUD será conhecida com atraso.

Estrutura. Esse é um período único de dados definido de acordo com uma única consideração ou pode ser herdado ou parte de uma coleção maior de itens? Idiomas como YAML e JSON permitem a combinação de valor de várias fontes. Talvez algumas coisas que inicialmente pareçam imutáveis ​​sejam melhor acessadas como propriedades em um gerenciador de configuração.

Localidade. Se todos os itens de dados estiverem armazenados em um número limitado de locais, será muito mais fácil gerenciá-los, principalmente se alguns precisarem ser alterados para novos valores (imutáveis). A edição do código-fonte apenas para alterar os valores dos dados apresenta o risco de alterações e bugs inadvertidos.

Separação de preocupações. Para que os algoritmos funcionem corretamente, é melhor separar a consideração de quais valores de dados usar. Os dados são necessários para testar algoritmos, não para fazer parte deles. Consulte também http://c2.com/cgi/wiki?ZeroOneInfinityRule .

Em resposta à sua pergunta, isso não é algo novo. Os princípios básicos não mudaram em mais de 30 anos e foram escritos repetidamente sobre esse período. Não me lembro de nenhuma publicação importante sobre o assunto, pois geralmente não é considerado controverso, apenas algo para explicar aos recém-chegados. Há um pouco mais aqui: http://c2.com/cgi/wiki?SeparationOfDataAndCode .

Minha experiência pessoal é que a importância dessa separação em um pedaço específico de software se torna maior ao longo do tempo, e não menos. Os valores codificados são movidos para os arquivos de cabeçalho, os valores compilados são movidos para os arquivos de configuração, e os valores simples tornam-se parte de estruturas hierárquicas e gerenciadas.

Quanto às tendências, não vi grandes mudanças de atitude entre programadores profissionais (mais de 10 anos), mas o setor está cada vez mais cheio de jovens e muitas coisas que eu pensava serem conhecidas e decididas a continuar sendo desafiadas e reinventadas, às vezes fora de moda. idéias, mas às vezes por ignorância.

david.pfx
fonte
2
Você poderia expandir a história e a tendência dessa prática? Se todos fizessem essas considerações, eu não teria feito a pergunta. A premissa da pergunta é que as pessoas não estão considerando cuidadosamente para onde seus dados devem ir (constantes compiladas, bancos de dados externos, YAML ...), mas pensam apenas em "CÓDIGO E DADOS MISTURADOS! Por que ou quando isso se tornou uma coisa?
Phil Frost
Não faz parte da minha experiência, então não posso lhe contar. Adicionei alguns parágrafos à minha resposta.
David.pfx
Eu acho que o "afluxo de jovens" é uma explicação válida, mas estou impedindo de aceitar porque gostaria de ouvir alguns desses jovens para ver de onde eles tiraram a idéia. Claramente eles conseguiram a parte "código e dados separados", mas não acho que tenham conseguido o resto. Eles leram em uma postagem no blog? Um livro? Onde e quando?
Phil Frost)
Você sempre terá "_____ RUIM! GROSSO!" - isso não significa que é verdade. Freqüentemente esse tipo de coisa (por exemplo, "'GOTO' RUIM! HASH SMASH!") É ensinado aos iniciantes, sem ensinar a eles por que ou quais são as exceções.
AMADANON Inc.
Localitytambém funciona de maneira inversa: acabamos com um tipo de sistema do tipo plug-in devido a requisitos personalizados para diferentes clientes e, após vários anos de tentativa e erro, aprendemos a manter suas constantes (até tabelas, por meio de listas de dictos) fora do banco de dados e no código. Tanto porque usá-lo em qualquer lugar que não seja esse "plug-in" está incorreto e porque as alterações são versionadas automaticamente quando ocorrem alterações.
Izkata 25/02
8

Os dados são dimensionados muito melhor e podem ser consultados e modificados com muito mais facilidade, quando separados do código. Mesmo que seus dados sejam de natureza codificada - por exemplo, seus dados representam regras ou comandos - se você pode armazenar representá-lo como dados estruturados, poderá aproveitar os benefícios de armazenar separadamente:

permissões

Se os dados estiverem codificados, você precisará editar o arquivo de origem para editar esses dados. Isso significa que:

  • Somente desenvolvedores podem editar dados. Isso é ruim - a entrada de dados não é algo que requer as habilidades e o conhecimento do desenvolvedor.

  • Não desenvolvedores podem editar o arquivo de origem. Isso é ruim - eles podem danificar o arquivo de origem sem nem mesmo saber!

  • Os dados são codificados em arquivos de origem separados, e os não desenvolvedores têm acesso apenas a esses arquivos. Mas isso realmente não conta - agora os dados são separados do código e armazenados em seus próprios arquivos ...

edição

Portanto, sobre quem pode editar os dados, é melhor armazená-los separadamente. Que tal como eles editarão os dados? Se você tem muitos dados, digitá-los manualmente é entediante e elimina erros. Ter alguma interface para isso é muito melhor! Mesmo que você ainda precise digitar tudo, não precisará digitar a placa do formato, portanto há menos chances de você estragar o formato e estragar o arquivo inteiro!

Se os dados estiverem codificados, a criação dessa interface significa que uma ferramenta automatizada editará os arquivos de origem manuscritos. Deixe isso acontecer - uma ferramenta automatizada abrirá seus arquivos de origem, tentará descobrir onde os dados devem estar e modificar esse código. Brrr ... A Microsoft introduziu classes parciais no C # apenas para evitar essas coisas ...

Se os dados estiverem separados, sua ferramenta automatizada precisará apenas editar arquivos de dados. Prefiro acreditar que programas de computador editando arquivos de dados não são tão incomuns hoje em dia ...

escala

O código e os dados são dimensionados de maneira muito diferente. À medida que seu código cresce, você deseja separá-lo em mais classes e métodos (ou estruturas e funções de dados), mas seus dados - não importa quanto cresça - você deseja mantê-lo em um só lugar. Mesmo se você precisar separá-lo em vários arquivos, deseje agrupá-los de alguma forma, para que seja mais fácil acessar esses dados a partir do código.

Então, imagine que você tenha milhares de linhas de dados dentro de um arquivo de origem. O compilador / intérprete precisa passar por todos esses dados cada vez que lê o arquivo e analisá-lo com o caro lexer & parser - mesmo que você não acesse esses dados nesta execução específica do programa. Além disso, quando você edita o código real nesse arquivo, precisa analisar os dados, o que dificulta todo o processo. Além disso, os arquivos de dados podem ser indexados. Dados codificados? Não muito...

procurando

Você tem muitos dados - é natural que você queira pesquisá-los.

  • Se você o armazenar em um banco de dados - poderá usar o idioma de consulta do banco de dados.

  • Se você o armazenar em um arquivo XML, poderá usar o XPath.

  • Se você o armazenar em JSON / YAML - poderá carregá-lo no REPL da sua linguagem de script favorita e pesquisá-lo.

  • Mesmo que você o armazene em um arquivo de texto antigo simples, já que ele possui uma estrutura que seu programa pode reconhecer, você pode usar grep / sed / awk para pesquisá-lo.

Embora seja verdade que você também possa grep / sed / awk através de dados codificados em um arquivo de origem, isso não funciona tão bem, pois sua consulta pode corresponder a outras linhas não relacionadas ou linhas perdidas que foram escritas de maneira diferente porque a sintaxe de representação de dados da linguagem de programação permite isso.

Existem ferramentas para pesquisar no código, mas são boas para encontrar declarações, não dados codificados.

Dito isto ...

É muito importante distinguir entre dados e código. Só porque algo está escrito como código não significa que não possa ser dados. E só porque algo é escrito com uma representação de dados não significa que não seja, de fato, código.

Eu tive uma aula quando tínhamos regras muito rígidas sobre "números mágicos" - não podíamos ter números em nosso código. Isso significa que tivemos que fazer coisas como:

#define THE_NUMBER_ZERO 0
//....
for(int i=THE_NUMBER_ZERO;i<cout;++i){
//....

o que é totalmente ridículo! Sim, 0são tecnicamente "dados", mas fazem parte do código como o resto do forloop! Assim, mesmo que possa representá-lo como dados e separá-lo do código, isso não significa que deve . Não porque queremos deixar dados dentro do código, mas porque não são realmente dados - não mais do que o restante do código, que também é compilado em zeros e uns ...

Idan Arye
fonte
7

Eu acho que há alguma confusão acontecendo. Você está misturando duas coisas: "Separando código e dados" e "expressando o comportamento do programa como dados".

No seu caso, você está realmente preocupado com o segundo e misturando o primeiro nele. Quando você expressa o comportamento do programa como dados, facilita a extensão. No seu exemplo com vowels = "aeiou", adicionar uma nova vogal é tão simples quanto adicionar um caractere. Se você tiver esses dados externamente, poderá alterar esse comportamento sem precisar recompilar o programa.

E quando você pensa sobre isso, OOP é uma extensão desse pensamento. A ligação de dados e comportamento em conjunto permitirá alterar o comportamento do programa com base nos dados do programa.

Eufórico
fonte
2
Porque naturalmente, a lista de vogais vai mudar.
cHao 19/02
13
@cHao Assim que o i18n entra, é
Restabeleça Monica
2
O i18n pode quebrar sua cabeça - veja alguns exemplos perversos em Java em javaspecialists.eu/archive/Issue209.html
Rory Hunter
2
@ Angle: Assim que o i18n entra, você está ferrado de qualquer maneira . Você precisa de código para isso; a solução ingênua é incapaz de lidar com todos os casos, mesmo em inglês. (Esqueça o ïpor um segundo; 'Vamos Conversar' sobre ye w!) Mover a lista para um banco de dados não vai consertar isso, e é realmente prejudicial - é complexidade que vai ser inútil se feito errado, mas você não vai sabe mesmo o que "errado" é a menos que você está projetando para i18n a partir do zero. Nesse ponto, você já está percebendo que uma lista de vogais simplesmente não será suficiente.
cHao
1
@ BenLee: Eu não ficaria nem um pouco surpreso, na verdade. Atualmente, estou trabalhando para alterar um código como esse enquanto falamos. Mas terceirizar tudo para o banco de dados é algo de uma sorte. Se você ainda não sabe se algo precisará ser modificado - e, mais importante, se você ainda não sabe como precisará ser modificado -, na IMO é melhor esperar até que você precise dessa flexibilidade antes de adicioná-lo .
cHao 24/02
5

Por exemplo, se a função do seu programa é contar vogais, o que há de errado em ter vogais = "aeiou"?

Armazenar a configuração externamente permite que você tenha uma versão do código que funcione com muitas configurações; a alternativa é manter muitas versões do software que diferem apenas pela configuração.

Você mencionou vogais = "aeiou", e se eu quiser "y", devo reconstruir o programa inteiro? Posso atualizar versões facilmente agora que modifiquei o código? Se houver um erro, eu o causei ou o programa está quebrado?

Se isso estiver dentro do seu programa, isso implica que ele não espera que os usuários alterem a definição de vogais sem escanear o código para ver os possíveis efeitos colaterais. Se a definição for armazenada externamente, isso implica que o programa não deve ser interrompido por nenhum valor razoável definido na configuração.

Quando você seqüestra dados em YAML ou arquivos de texto ou bancos de dados burros, como se estivesse removendo um tumor do código

Alguns vêem o contrário, ou seja, você está removendo o tumor do código de seus dados preciosos, veja: A citação de Torvalds sobre um bom programador

FMJaguar
fonte
4
A citação de Torvalds refere-se a estruturas de dados, não a dados.
user949300
O OP afirma: "A programação orientada a objetos disse" queremos estruturas de dados arbitrariamente ricas "e, portanto, dotamos as estruturas de dados com poderes de código".
FMJaguar 19/02
1
Se você fizer uma alteração fundamental na definição do que é uma vogal, precisará executar novamente todos os testes automatizados. Os sistemas raramente têm a capacidade de executar novamente os testes quando um arquivo de configuração é alterado em um sistema implantado. Portanto, essas definições precisam ser incorporadas ao sistema; talvez como dois conjuntos codificados com uma opção de configuração para selecionar entre eles.
soru
+1 para a cotação de Torvalds. Concordo com este sentimento: no exemplo do fantoche, acho que a questão é que o fantoche não possui uma boa estrutura de dados para representar as informações que as pessoas desejam colocar nele. Em vez de consertar as estruturas de dados, os desenvolvedores de marionetes afirmaram que "dados em código" é o problema (por quê? Essa é a questão!) E desenvolveram o hiera , que considero pouco mais do que mover o problema para outro lugar e, além disso, impossibilitá-lo associar comportamento a dados.
Phil Frost
2

Eu estava em um projeto em que o líder insistiu em colocar dados de referência em pequenas tabelas, e achei que isso era bobagem. Mas como já tínhamos nossa infraestrutura de persistência e conectividade configuradas, acabou sendo um custo bastante baixo, além das outras operações de persistência que estávamos realizando.

Agora, ainda acho que foi uma decisão tola e, se não tivéssemos a infraestrutura disponível, simplesmente não a teríamos.

Mas alguns dos argumentos a favor que vejo são:

  • Se você tem uma mentalidade de banco de dados, a inserção de dados de referência no banco de dados SQL permite que você se junte a ele para gerar relatórios.
  • Se você tiver um utilitário de administração ou acesso ao banco de dados, poderá ajustar os valores em tempo de execução. (Embora isso possa estar brincando com fogo.)

Além disso, às vezes a política atrapalha as práticas de codificação. Por exemplo, trabalhei em várias lojas nas quais enviar um arquivo .xml é A-OK, enquanto tocar em uma linha no código requer um ciclo de regressão completo e talvez um teste de carga. Portanto, havia uma equipe em que meus arquivos .xml do projeto eram extremamente ricos (e talvez -heh- possa conter algum código).

Sempre me pergunto se vou aproveitar o benefício de inserir dados do código em um repositório de dados externo, mesmo que seja apenas um arquivo de texto, mas trabalhei com pessoas que vêem dessa maneira o primeiro impulso.

Roubar
fonte
3
Um bom comentário sobre os procedimentos da loja, em que editar XML é "ok", mas editar a mesma coisa no código é um grande aborrecimento.
user949300
trabalhou em uma loja onde tudo estava no banco de dados que poderia estar, até os textos na tela. Além do código de interface do usuário, a única coisa que não no banco de dados foi o local banco de dados e credenciais ...
jwenting
3
sempre soa bobo até que, um dia, alguém pergunta "podemos reconfigurar isso para o usuário X que está exigindo" e, depois, não parece tão bobo? Clientes malditos :)
gbjbaanb
2
... e se esse dia é "nunca", então isso é uma longa sensação tempo tola
Rob
2

Deixe-me fazer uma contra-pergunta completamente séria: qual, na sua opinião, é a diferença entre "dados" e "código"?

Quando ouço a palavra "dados", penso em "estado". Os dados são, por definição, o que o próprio aplicativo foi projetado para gerenciar e, portanto, o que o aplicativo nunca pode saber em tempo de compilação. Não é possível codificar os dados porque, assim que você os codifica, eles se tornam comportamento - não dados.

O tipo de dados varia de acordo com o aplicativo; um sistema de faturamento comercial pode armazenar informações de clientes e pedidos em um banco de dados SQL e um programa de gráficos vetoriais pode armazenar dados e metadados de geometria em um arquivo binário. Nos dois casos e em todas as etapas, há uma separação clara e inquebrável entre o código e os dados. Os dados pertencem ao usuário , não ao programador, portanto nunca podem ser codificados.

O que você parece estar falando é usar a descrição tecnicamente mais precisa disponível para o meu vocabulário atual: informações que governam o comportamento do programa que não estão escritas na linguagem de programação primária usada para desenvolver a maioria do aplicativo.

Mesmo essa definição, que é consideravelmente menos ambígua do que apenas a palavra "dados", tem alguns problemas. Por exemplo, e se partes significativas do programa forem escritas em diferentes idiomas? Eu pessoalmente trabalhei em vários projetos que são cerca de 50% C # e 50% JavaScript. O código JavaScript é "data"? A maioria das pessoas diria que não. E o HTML, são esses "dados"? A maioria das pessoas ainda diz não.

E o CSS? São dados ou código? Se pensarmos no código como algo que controla o comportamento do programa, o CSS não é realmente um código, porque apenas (bem, principalmente) afeta a aparência, não o comportamento. Mas também não são realmente dados; o usuário não é o proprietário, o aplicativo nem mesmo é o proprietário. É o equivalente ao código para um designer de interface do usuário. É como código , mas não é exatamente código.

Eu poderia chamar CSS de um tipo de configuração, mas uma definição mais prática é que é simplesmente código em uma linguagem específica de domínio . É isso que seu XML, YAML e outros "arquivos formatados" geralmente representam. E a razão pela qual usamos uma linguagem específica de domínio é que, de um modo geral, é simultaneamente mais concisa e mais expressiva em seu domínio específico do que codificando as mesmas informações em uma linguagem de programação de uso geral como C ou C # ou Java.

Você reconhece o seguinte formato?

{
    name: 'Jane Doe',
    age: 27,
    interests: ['cats', 'shoes']
}

Tenho certeza que a maioria das pessoas faz; é JSON . E aqui está a coisa interessante sobre o JSON: no JavaScript, é claramente um código e, em qualquer outra linguagem, são dados claramente formatados. Quase toda linguagem de programação convencional possui pelo menos uma biblioteca para "analisar" o JSON.

Se usarmos exatamente a mesma sintaxe dentro de uma função em um arquivo JavaScript, não poderá ser outra coisa senão código. E, no entanto, se pegarmos esse JSON, empurrá-lo em um .jsonarquivo e analisá-lo em um aplicativo Java, de repente são "dados". Isso realmente faz sentido?

Argumento que o "data-ness" ou "configuration-ness" ou "code-ness" é inerente ao que está sendo descrito, não como está sendo descrito.

Se o seu programa precisar de um dicionário de 1 milhão de palavras para, por exemplo, gerar uma senha aleatória, você deseja codificá-lo da seguinte forma:

var words = new List<string>();
words.Add("aa");
words.Add("aah");
words.Add("ahhed");
// snip 172836 more lines
words.Add("zyzzyva");
words.Add("zyzzyvas");

Ou você simplesmente colocaria todas essas palavras em um arquivo de texto delimitado por linhas e instruiria seu programa a ler? Realmente não importa se a lista de palavras nunca muda, não é uma questão de saber se você está codificando ou codificando (que muitos consideram corretamente um anti-padrão quando aplicado de maneira inadequada), é simplesmente uma questão de qual formato é mais eficiente e facilita a descrição do "material", qualquer que seja o "material". É bastante irrelevante se você chama de código ou dados; são as informações que seu programa requer para executar e um formato de arquivo simples é a maneira mais conveniente de gerenciá-lo e mantê-lo.

Supondo que você siga as práticas apropriadas, todo esse material está entrando no controle de origem, então você pode chamá-lo de código, apenas codificar em um formato diferente e talvez muito minimalista. Ou você pode chamá-lo de configuração, mas a única coisa que realmente diferencia o código da configuração é se você o documenta ou não e diz aos usuários finais como alterá-lo. Talvez você possa inventar algum argumento falso sobre a configuração que está sendo interpretada no momento da inicialização ou no tempo de execução e não no tempo de compilação, mas então você começaria a descrever várias linguagens de tipo dinâmico e quase certamente qualquer coisa com um mecanismo de script incorporado nela (por exemplo, maioria dos jogos). Código e configuração são tudo o que você decide rotulá-los como, nada mais, nada menos.

Agora, não é um perigo para a externalização de informação que não é realmente seguro para modificar (veja o link "soft codificação" acima). Se você externalizar sua matriz de vogais em um arquivo de configuração e documentá-lo como um arquivo de configuração para seus usuários finais, estará oferecendo a eles uma maneira quase infalível de interromper instantaneamente seu aplicativo, por exemplo, colocando "q" como vogal. Mas esse não é um problema fundamental da "separação de código e dados", é simplesmente um mau senso de design.

O que digo aos desenvolvedores juniores é que eles devem sempre externalizar as configurações que eles esperam mudar por ambiente. Isso inclui coisas como cadeias de conexão, nomes de usuário, chaves de API, caminhos de diretório e assim por diante. Eles podem ser os mesmos na sua caixa de desenvolvimento e na produção, mas provavelmente não, e os administradores de sistemas decidirão como eles querem que seja na produção, não nos desenvolvedores. Portanto, é necessário ter um grupo de configurações aplicadas em algumas máquinas e outras aplicadas em outras máquinas - ergo, arquivos de configuração externos (ou configurações em um banco de dados etc.)

Mas enfatizo que simplesmente colocar alguns "dados" em um "arquivo" não é o mesmo que externalizá-los na configuração. Colocar um dicionário de palavras em um arquivo de texto não significa que você deseja que os usuários (ou TI) o alterem, é apenas uma maneira de tornar muito mais fácil para os desenvolvedores entenderem o que está acontecendo e, se necessário, tornar mudanças ocasionais. Da mesma forma, colocar as mesmas informações em uma tabela de banco de dados não conta necessariamente como externalização de comportamento, se a tabela é somente leitura e / ou os DBAs são instruídos a nunca se ferrar com ela. A configuração implica que os dados são mutáveis, mas, na realidade, são determinados pelo processo e pelas responsabilidades, e não pela escolha do formato.

Então, para resumir:

  • "Código" não é um termo rigidamente definido. Se você expandir sua definição para incluir linguagens específicas de domínio e qualquer outra coisa que afete o comportamento, grande parte desse aparente atrito simplesmente desaparecerá e tudo fará sentido. Você pode ter um "código" DSL não compilado em um arquivo simples.

  • "Dados" implica em informações pertencentes ao (s) usuário (s) ou pelo menos a alguém que não seja o desenvolvedor, e que geralmente não estão disponíveis em tempo de design. Não poderia ser codificado, mesmo que você quisesse. Com a possível exceção do código auto-modificável , a separação entre código e dados é uma questão de definição, não de preferência pessoal.

  • A "codificação suave" pode ser uma prática terrível quando aplicada em excesso, mas nem toda instância de externalização constitui necessariamente uma codificação flexível, e muitas instâncias de armazenamento de informações em "arquivos simples" não são necessariamente uma tentativa genuína de externalização.

  • A configuração é um tipo especial de soft-de codificação que é necessário por causa do conhecimento que o aplicativo pode precisar executar em ambientes diferentes. A implantação de um arquivo de configuração separado junto com o aplicativo é muito menos trabalhosa (e muito menos perigosa) do que a implantação de uma versão diferente do código em todos os ambientes. Portanto, alguns tipos de soft-coding são realmente úteis.

Aaronaught
fonte
1

Sugiro a leitura deste artigo clássico de Oren Eini (também conhecido como Ayende Rahien)

http://ayende.com/blog/3545/enabled-change-by-hard-coding-everything-the-smart-way

Meu argumento principal é focar na simplicidade e legibilidade. Isso pode significar que é improvável que coisas que provavelmente não serão reconfiguradas sejam deixadas codificadas (de forma legível). Isso permite que você use a sintaxe completa de uma linguagem de programação para expressar os parâmetros, além de obter efeitos colaterais benéficos, como conclusão de código e erros de compilação no uso indevido.

Dessa forma, você potencialmente evita as complexidades de analisar / interpretar ("mas alguém analisa meu YAML / JSON" - mapear o texto analisado nas chamadas específicas da API pode ser uma forma de interpretação) e evitar a complexidade de outra etapa entre os "dados "e seu uso.

Alguns casos se prestam a serem expressos em dados, mesmo em um cenário como este: por exemplo, especificar milhares de pontos no espaço 3D pode ser mais adequado para um arquivo de texto do que código, embora em alguns idiomas, incluindo C usando inicializadores de estrutura, código pode ser apropriado mesmo para isso.

orip
fonte
1

Ok, vamos supor que você queira escrever algum tipo de programa c ++ para seu lazer. Você sabe exatamente o que tem que fazer e o que nunca precisará fazer. Agora pegue qualquer livro sobre "design de software moderno". Aqui está a regra do jogo: para todas as classes do seu projeto e para todos os casos tão pequenos, você deve implementar todos os padrões sofisticados que você encontrar descritos nesse livro para tornar seu código um "design limpo". Bem, "injeção de dependência" será suficiente para muitas pessoas, eu acho. (É c ++, não java!) A programação é ensinada de um ponto de vista cada vez mais teórico. Não é suficiente que você faça o trabalho, você precisa escrever um código que possa ser mantido, que seja tolo ... tudo bem e certo. O problema começa quando pessoas. pare de pensar sobre o motivo real, os padrões de design foram inventados e se tornaram dogmáticos.

Deixe-me impedi-lo de escrever sua ferramenta de contagem de letras usando (acima) um único princípio simples de design: Quando você escreve um código que executa um determinado trabalho em dados de entrada de um determinado tipo, verifique se ele é capaz de executar essa tarefa em qualquer entrada. dados desse tipo. - Quando você deseja escrever uma ferramenta de contagem de letras, faz sentido escrevê-la de uma maneira, para que não apenas seja possível contar vogais, mas "qualquer letra". - Como você talvez não saiba qual é o corpus que está analisando, também pode escolher uma codificação muito geral (UTF-16) e cobrir a maioria (todos?) Dos idiomas escritos e seus símbolos.

Até esse ponto, temos uma função com dois argumentos (o corpus e as letras a serem contadas). Estamos preocupados apenas em encontrar um "tipo" ou "classe" razoavelmente geral que as letras também pertençam: certamente podemos fazer melhor que os símbolos ASCII!

Digite um demônio que empunhe o dogma "generalização e reutilização": - Por que não contar qualquer símbolo de qualquer classe em um fluxo de entrada dessa classe? (resumo de letras para seqüências de bits de tamanho arbitrário, mas finito, pois é o mais geral que você pode obter com um computador ...) - Espere, mesmo assim ainda estamos contando em números naturais. No entanto, a contagem pode ser generalizada como um mapeamento de um conjunto contável para ele mesmo, cumprindo os axiomas ... [você entendeu]

Agora esse exemplo pode ser bobo, mas se você considerar tarefas de design mais complexas do que uma ferramenta de contagem, poderá encontrar toda a oportunidade de introduzir abstração adicional necessária de acordo com algum tipo de padrão de design encontrado em seu livro.

A separação de "dados" e "código" provavelmente será trivial (argumentos da função) ou você se encontrará tratando os invariantes como variáveis ​​("dados").

Se houver alguma confusão, é provável que "interfaces" e "serviços" e todos os detalhes de classe (por exemplo, tipos) sejam subitamente "dados", ou seja, dependências a serem injetadas externamente. Eu sinto que os cursos de informática ministrados na universidade se tornaram muito parecidos com aulas de filosofia e há menos tempo para projetos reais, para que os alunos possam adquirir experiência em como criar software que funcione. Se você já se perguntou por que precisa usar um padrão incrivelmente complexo em vez de uma solução óbvia, esse desenvolvimento é (provavelmente) como esse requisito foi "criado" ...

Para o seu problema específico: 1. Se você pudesse 1.) escrever um programa com o máximo de código fixo para o seu caso específico e depois 2.) generalizar a partir desse código de maneira direta, por exemplo. introduzindo mais argumentos de função e usando outros "padrões triviais", você pode ter certeza de que está separando código e dados, da maneira óbvia, como foi feito desde que a programação funcional foi inventada. (ofc você pula 1. e faz 2. instantaneamente ...)

Qualquer coisa não óbvia aqui provavelmente é um caso de "impasse teórico": como escrever uma interface referindo-se a uma interface e mais uma interface ... e, no final, você possui um pequeno arquivo xml para configurar todas essas interfaces e as dependências a serem injetadas na sua confusão de interface de classe.

Vamos apenas torcer para que o xml-parser que você precisa não precise de um xml-config para funcionar ...

bhak
fonte