Primeiro um pouco de fundo. Estou codificando uma pesquisa de Idade -> Taxa. Existem 7 faixas etárias, portanto, a tabela de pesquisa é composta por 3 colunas (de | a | taxa) com 7 linhas. Os valores raramente mudam - são taxas legisladas (primeira e terceira colunas) que permaneceram as mesmas por três anos. Achei que a maneira mais fácil de armazenar esta tabela sem codificá-la é no banco de dados em uma tabela de configuração global, como um valor de texto único contendo um CSV (então "65,69,0.05,70,74,0.06" é como as camadas 65-69 e 70-74 seriam armazenadas). Relativamente fácil de analisar e usar.
Então percebi que, para implementar isso, eu teria que criar uma nova tabela, um repositório para envolvê-la, testes de camada de dados para o repositório, testes de unidade em torno do código que descompacta o CSV na tabela e testes em torno da própria pesquisa. O único benefício de todo esse trabalho é evitar a codificação da tabela de pesquisa.
Ao conversar com os usuários (que atualmente usam a tabela de pesquisa diretamente - olhando para uma cópia impressa), a opinião é praticamente de que "as taxas nunca mudam". Obviamente, isso não está correto - as taxas foram criadas apenas três anos atrás e, no passado, coisas que "nunca mudam" têm o hábito de mudar - então, para eu programar isso de forma defensiva, eu definitivamente não devo armazenar a tabela de consulta em a aplicação.
Exceto quando penso YAGNI . O recurso que estou implementando não especifica que as taxas serão alteradas. Se as taxas mudarem, elas ainda mudarão tão raramente que a manutenção nem sequer é considerada, e o recurso não é realmente crítico o suficiente para que qualquer coisa seja afetada se houver um atraso entre a alteração da taxa e o aplicativo atualizado.
Decidi praticamente que nada de valor será perdido se eu codificar a pesquisa e não estiver muito preocupado com minha abordagem desse recurso em particular. Minha pergunta é: como profissional, justifiquei adequadamente essa decisão? A codificação dos valores é um design ruim, mas o problema de remover os valores do aplicativo parece violar o princípio YAGNI.
EDIT Para esclarecer a questão, não estou preocupado com a implementação real. Preocupa-me que eu possa fazer algo rápido e ruim e justificá-lo dizendo YAGNI, ou posso adotar uma abordagem mais defensiva e de alto esforço, que, mesmo na melhor das hipóteses, traz benefícios baixos. Como programador profissional, minha decisão de implementar um projeto que eu sei que é falha simplesmente se resume a uma análise de custo / benefício?
EDIT Embora todas as respostas tenham sido muito interessantes, pois acho que isso se resume às escolhas de design de um indivíduo, acho que as melhores respostas foram @ Corbin e @EZ Hart, pois trazem à tona coisas que eu não havia considerado na pergunta:
- a falsa dicotomia de 'remover corretamente valores codificados' movendo-os para o banco de dados vs 'aplicando YAGNI' de forma eficiente 'usando codificação embutida. Havia uma terceira opção de colocar a tabela de pesquisa na configuração do aplicativo, o que não implica a sobrecarga da maneira correta e sem a eficiência do YAGNI. Geralmente, não estamos limitados a decisões ou decisões e, em seguida, tudo se resume a uma decisão de custo / benefício.
- a geração de código pode reduzir a sobrecarga de mover os valores codificados para o banco de dados e de uma maneira que também elimina minha decisão de engenharia de processar um CSV na tabela. Potencialmente, isso também adiciona um problema de manutenção a longo prazo ao código gerado, se os requisitos básicos mudarem para o método de pesquisa. Tudo isso afeta apenas a análise de custo / benefício, e é provável que, se eu tivesse essa automação disponível, nem sequer consideraria a codificação embutida algo assim.
Estou marcando a resposta de @ Corbin como correta, pois altera minhas suposições de custo de desenvolvimento e provavelmente adicionarei algumas ferramentas de geração de código ao meu arsenal no futuro próximo.
Respostas:
Você encontrou uma falha no seu processo de desenvolvimento. Quando é difícil fazer a coisa certa (criar a tabela, repo, repo testes, nivelar testes ...), os desenvolvedores encontrarão uma maneira de contornar isso. Isso geralmente envolve fazer a coisa errada. Nesse caso, é tentador tratar os dados do aplicativo como lógica do aplicativo. Não faça isso. Em vez disso, adicione automações úteis ao seu processo de desenvolvimento. Usamos o CodeSmith para gerar o código chato e padronizado que ninguém deseja escrever. Depois de criar uma tabela, executamos o CodeSmith e ele gera os DAOs, DTOs e elimina os testes de unidade para cada um.
Dependendo das tecnologias que você está usando, você deve ter opções semelhantes. Muitas ferramentas ORM geram modelos a partir de um esquema existente. As migrações de trilhos funcionam na direção oposta - tabelas de modelos. A metaprogramação em linguagens dinâmicas é particularmente forte na eliminação do código padrão. Você precisará trabalhar um pouco mais para gerar tudo o que precisa se tiver um aplicativo complexo de várias camadas, mas vale a pena. Não deixe que o sentimento "uau, isso é uma dor no pescoço" o impeça de fazer a coisa certa.
Ah, e não armazene seus dados em um formato que exija processamento adicional (CSV). Isso apenas adiciona etapas extras que requerem sua atenção e testes.
fonte
Para encerrar e estender a resposta de Thorbjørn Ravn Andersen: Manter o cálculo / pesquisa em um só lugar é um bom começo.
Seu processo de pensamento defensivo contra YAGNI é um problema comum. Nesse caso, sugiro que seja informado por mais duas coisas.
Em primeiro lugar - como foi apresentado o requisito do usuário? Eles especificaram a capacidade de edição das taxas? Caso contrário, a complexidade adicionada faz parte de algo que você pode cobrar ou não? (ou se você faz parte da equipe, pode dedicar seu tempo a outros trabalhos?) Em caso afirmativo, vá em frente e entregue o que foi razoavelmente solicitado.
Em segundo lugar, e talvez mais importante, é improvável que a mera editabilidade cumpra um requisito real diante de uma mudança legislada. Se e quando as taxas mudarem, é provável que haja uma data de transição e algum processamento antes e depois que tenha que acontecer. Além disso, se essa mesma interface precisar executar qualquer tipo de processamento de reivindicações com data anterior, a taxa correta poderá ter que ser pesquisada com base na data efetiva da entrada, e não na data real.
Em resumo, estou observando que um requisito editável real pode muito bem ser bastante complexo, portanto, a menos ou até que seja desenvolvido, o simples é provavelmente melhor.
Boa sorte
fonte
Tornar a pesquisa real uma função de biblioteca. Você pode ver todo o código usando essa pesquisa no seu repositório de origem, para saber quais programas precisam ser atualizados quando as taxas mudam.
fonte
PensionRateLookup
classe, talvez) que será usada globalmente. Eu faria isso independentemente de ser armazenado fora do aplicativo ou codificado permanentemente, dessa forma, apenas a implementação daPensionRateLookup
classe precisa ser mantida. Meu problema é como eu usei o YAGNI para concluir que a codificação embutida da tabela de pesquisa é aceitável.Deixe-me ver se entendi sua pergunta. Você tem duas opções para implementar um recurso: ou codifica um valor e seu recurso é fácil de implementar (mas você não gosta da parte do código rígido) ou faz um grande esforço para "refazer" muitas coisas que são feitas para que você possa desenvolver seus recursos de maneira limpa. Isso está correto?
A primeira coisa que me vem à cabeça é "A coisa mais importante sobre conhecer as boas práticas é saber quando você está melhor sem elas".
Nesse caso, o esforço é muito alto para que você possa fazer isso de maneira limpa, as chances de efeito colateral dessa mudança são grandes e o retorno que você obterá é pequeno (como você explicou, parece provável que não mudança).
Eu usaria a abordagem de código rígido (mas a prepararia para ser flexível no futuro) e, em caso de alteração dessa taxa no futuro, aproveitaria a oportunidade para refatorar toda essa seção de design incorreto do código. Portanto, o tempo e o custo podem ser estimados corretamente e o custo da alteração do valor codificado seria mínimo.
Esta seria a minha abordagem :)
fonte
Este é um item que "não mudará" até que isso aconteça. É inevitável que isso mude, mas esse tempo pode estar um pouco distante.
Sua justificativa está correta. No momento, o cliente não solicitou a capacidade de alterar facilmente essas taxas. Como tal, YAGNI.
No entanto, o que você não quer é o código que acessa suas taxas e interpreta os resultados espalhados por toda a base de código. Um bom design de OO faria você encapsular a representação interna de suas taxas em uma classe e expor apenas os um ou dois métodos necessários para usar os dados.
Você precisará desse encapsulamento para evitar erros de copiar e colar, ou ter que executar uma refatoração em todo o código que usa as taxas quando precisar fazer uma alteração na representação interna. Quando você toma essa precaução inicial, a abordagem mais complicada pode ser uma simples troca e substituição para a versão mais destacada.
Além disso, chame a limitação do design atual para o cliente. Diga a eles que, no interesse de manter a programação, você codificou os valores - o que requer uma alteração na codificação para atualizá-los. Dessa forma, ao tomar conhecimento das alterações de taxa pendentes devido à nova legislação, eles podem optar por simplesmente atualizar a tabela de pesquisa ou executar as alterações mais complicadas naquele momento. Mas coloque essa decisão no colo deles.
fonte
Divida a diferença e coloque os dados da taxa em uma configuração. Você pode usar o formato CSV que você já possui, evitar a sobrecarga desnecessária do banco de dados e, se a alteração for necessária, será uma alteração que o cliente poderá fazer sem precisar recompilar / reinstalar e sem mexer no banco de dados - eles podem apenas editar o arquivo de configuração.
Geralmente, quando você olha para uma escolha entre dois extremos (viola o YAGNI x os dados dinâmicos codificados), a melhor resposta está em algum lugar no meio. Cuidado com falsas dicotomias.
Isso assume que toda a sua configuração está em arquivos; se for um lugar difícil como o registro, você provavelmente deve desconsiderar este conselho :)
fonte
Acabei de criar uma tabela de banco de dados. (Você estava pensando em armazenar uma mesa inteira em um arquivo, ficou louco?)
A tabela precisa de 2 campos, NÃO de 3. Idade e taxa. Esta próxima linha contém o valor superior! Você está desnormalizando sem nem mesmo saber!
Aqui está o Sql para obter a taxa para alguém com mais de 67 anos.
Não se preocupe em fazer uma tela de manutenção, pois ela está fora de escopo. Se eles solicitarem mais tarde, emita uma solicitação de alteração e faça-a.
EDIT: Como outros disseram manter o código, a taxa fica centralizada, caso toda a estrutura da taxa seja alterada.
fonte
Eu concordo com a maioria das respostas dadas. Eu também acrescentaria que a consistência com o restante do aplicativo é importante. Se este é o único local no código que possui valores codificados, provavelmente surpreenderá os mantenedores. Isto é especialmente verdade se for uma base de código grande e estável. Se é um pequeno programa mantido por você, a decisão é menos importante.
Tenho uma memória distante de ler um conhecido cara ágil / OOP (como Dave Thomas ou Kent Beck ou alguém) dizendo que a regra geral para duplicação de código era duas e apenas duas: não refatorar a primeira vez que você duplicar algo desde você pode escrever apenas duas vezes na sua vida. Mas a terceira vez ...
Isso não trata exatamente da questão, já que você está questionando a YAGNI, mas acho que ela fala da flexibilidade geral das regras ágeis. O ponto do ágil é se adaptar à situação e seguir em frente.
fonte
Código rígido em uma função.
fonte