Como vocês sabem que estão escrevendo o código mais robusto possível sem o excesso de engenharia?
Eu me pego pensando demais em todos os caminhos possíveis que meu código pode seguir, e às vezes parece uma perda de tempo. Acho que depende do tipo de programa que você está escrevendo, mas não quero usar muito do meu tempo levando em consideração situações que nunca acontecerão.
self-improvement
programming-practices
Fran Sevillano
fonte
fonte
Respostas:
O que você considera código robusto? Código que já é à prova do futuro e tão poderoso que pode lidar com qualquer situação? Errado, ninguém pode prever o futuro! E errado de novo, porque será uma bagunça complicada e inatingível.
Sigo vários princípios: Primeiro e acima de tudo YAGNI (ainda) e KISS , para não escrever código desnecessário. Isso também evita efetivamente a superengenharia. Refatoro o aplicativo quando são necessárias extensões. As modernas ferramentas de refatoração permitem criar interfaces com facilidade e trocar implementações posteriormente, quando você precisar delas.
Então tento tornar o código que escrevo o mais robusto possível, que inclui a eliminação de quantos caminhos o programa seguir (e também declara) quanto possível e um pouco de programação espartana . Uma grande ajuda são as funções / métodos "atômicos" que não dependem de estados externos ou, pelo menos, não deixam o programa em um estado inconsistente quando falham. Se você fizer isso bem, também é muito improvável que você acabe com um código de espaguete, e também é uma benção para a manutenção. Além disso, no design orientado a objetos, os princípios do SOLID são um ótimo guia para código robusto.
Eu realmente descobri que muitas vezes você pode reduzir a complexidade, por exemplo, explosões combinatórias de caminhos ou estados de programas, pensando profundamente em como você pode projetá-lo como o caminho mais reto possível. Tente manter no mínimo as combinações possíveis, escolhendo a melhor ordem de suas sub-rotinas e projetando-as para esse fim.
Código robusto é quase sempre código simples e limpo, mas a simplicidade é uma característica que nem sempre é alcançada com facilidade. No entanto, você deve lutar por isso. Sempre basta escrever o código mais simples possível e adicionar complexidade apenas quando você não tiver outra escolha.
A simplicidade é robusta, a complexidade é frágil.
Complexidade mata.
fonte
Eu tento manter um equilíbrio, focando
É uma área de fronteira confusa - às vezes eu consigo fazer um trabalho desnecessário, às vezes deixo de fazer algo que acaba sendo necessário mais tarde. Se as falhas não são grandes, eu estou bem. De qualquer forma, eu me esforço para aprender com meus erros.
fonte
A diferença entre engenharia robusta e superengenharia é a diferença entre lidar com todos os casos de uso possíveis, mesmo os casos de uso bizarros e marginais que NÃO DEVEM acontecer. Quando digo graciosamente, quero dizer, o usuário entra em um caso de exceção bizarro ou se depara com uma situação que exige um recurso não suportado ou não especificado que não foi definido e o código sai normalmente sem travar ou informa o usuário sobre a funcionalidade não suportada.
A superengenharia, por outro lado, poderia cair no campo da implementação completa de recursos que não eram necessários ou solicitados (alguns recursos que o cliente PRECISA, mas nunca foram solicitados!) OU pode ser definido derivando um design excessivamente complexo ou excessivamente complexo. código para lidar com um problema relativamente simples.
fonte
1) Obtenha requisitos.
2) Escreva um código mínimo para atender aos requisitos. Se algo for ambíguo, faça um palpite. Se for super ambíguo, volte para 1.
3) Enviar para teste.
4) Se os testadores considerarem bom, documente a aprovação. Se algo estiver errado, volte para 1.
Concentre-se em passar nos testes, não em prever os testes. Se você não possui testadores ... obtenha testadores! Eles são essenciais não apenas para verificar a correção do código, mas para todo o processo de desenvolvimento.
fonte
Em primeiro lugar, mantenha os dados normalizados (não redundantes) o máximo que puder. Se os dados estiverem totalmente normalizados, nenhuma atualização única poderá torná-los inconsistentes.
Você nem sempre pode manter os dados normalizados; em outras palavras, talvez não seja possível eliminar a redundância; nesse caso, eles podem ter estados inconsistentes. O que se deve fazer é tolerar a inconsistência e repará-la periodicamente com algum tipo de programa que varre e corrige o problema.
Há uma forte tendência para tentar gerenciar a redundância com força por meio de notificações. Estes não são apenas difíceis de garantir que estão corretos, mas podem levar a enormes ineficiências. (Parte da tentação de escrever notificações surge porque na OOP elas são praticamente incentivadas.)
Em geral, qualquer coisa que dependa da sequência temporal de eventos, mensagens etc. será vulnerável e exigirá toneladas de codificação defensiva. Eventos e mensagens são característicos dos dados com redundância, porque estão comunicando alterações de uma parte para outra, tentando evitar inconsistências.
Como eu disse, se você precisar de redundância (e as chances são muito boas), é melhor ser capaz de: a) tolerar eb) reparar. Se você tentar impedir a inconsistência apenas por meio de mensagens, notificações, gatilhos, etc., será muito difícil torná-la robusta.
fonte
erros vai vir para cima ao longo do caminho, mas eles vão (felizmente) ser localizada e eles vão (na maioria dos casos) mostram-se muito cedo no teste. o outro benefício da reutilização é que o cliente / responsável pela chamada pode salvar a maior parte da verificação / andaime de erros usando o que é trazido pela implementação.
seus testes definirão os recursos de seu programa e quão robustos eles são - continue adicionando testes até que você esteja satisfeito com as taxas e contribuições de sucesso; melhorar, estender e fortalecer conforme necessário.
fonte
Eu faço essa distinção escrevendo código com um comportamento bem definido, mas não necessariamente ideal, para passagens de execução muito improváveis. Por exemplo, quando tenho certeza (comprovada, mas não testada) de que uma matriz será positiva definida, insiro uma asserção ou exceção no programa para testar o estado, mas não escrevo um caminho de código próprio para ela. Assim, o comportamento é definido, mas subótimo.
fonte
Robustez: o grau em que um sistema continua funcionando na presença de entradas inválidas ou condições ambientais estressantes. (Código completo 2, p464)
A questão importante aqui é perguntar o quão importante é a robustez para você. Se você é o Facebook, é realmente importante que seu site continue funcionando quando alguém coloca caracteres especiais na entrada e que seu servidor permaneça ativo quando 100 milhões de usuários estiverem conectados simultaneamente. Se você estiver escrevendo um script para executar uma operação comum que somente você faz, não se importa muito. Entre existem muitos níveis. Julgar quanto de robustez você precisa é uma das habilidades importantes que um desenvolvedor deve aprender.
O princípio do YAGNI se aplica à adição de recursos que um programa pode precisar. Mas esse princípio não se aplica à robustez. Os programadores tendem a superestimar a probabilidade de que uma determinada extensão futura seja necessária (especialmente se for legal), mas subestimam a probabilidade de que algo dê errado. Além disso, se um recurso omitido for necessário depois, o programador poderá escrevê-lo mais tarde. Se uma verificação de erro omitida for necessária, o dano pode ser causado.
Portanto, é realmente melhor errar ao fazer verificações de condições de erro incomuns. Mas existe um equilíbrio. Algumas das coisas a considerar neste equilíbrio:
Não esqueça que as pessoas podem - e vão - tentar usar seu programa de maneiras inesperadas. É melhor se algo previsível acontecer quando isso acontecer.
Como última linha de defesa, use a declaração ou o desligamento. Se acontecer algo que você não saiba como lidar com isso, encerre o programa. Isso geralmente é melhor do que permitir que o programa continue e faça algo imprevisível.
fonte