Eu tentei planejar as coisas com antecedência, mas não consigo realmente prever tudo até começar a elaborar algum código.
É tentador pensar que o planejamento perfeito fornecerá a arquitetura / arquitetura de software perfeitas, no entanto, isso é categoricamente falso. Há dois grandes problemas com isso. Primeiro, "no papel" e "o código" raramente correspondem, e o motivo é que é fácil dizer como deve ser feito, em vez de realmente fazê-lo . Em segundo lugar, mudanças imprevistas nos requisitos tornam-se aparentes no final do processo de desenvolvimento que não poderiam ter sido pensadas desde o início.
Você já ouviu falar do movimento Agile? É uma maneira de pensar em que valorizamos "reagir à mudança" em vez de "seguir um plano" (entre outras coisas). Aqui está o manifesto (é uma leitura rápida). Você também pode ler sobre o Big Design Up Front (BDUF) e quais são as armadilhas.
Infelizmente, a versão corporativa do "Agile" é um monte de falsos (mestres de scrum certificados, processo pesado em nome de "Agile", forçando o scrum, forçando 100% de cobertura de código etc.) e geralmente resulta em mudanças de processo asininas porque os gerentes pense que o Agile é um processo e uma bala de prata (do qual não é nem um). Leia o manifesto ágil, ouça pessoas que iniciaram esse movimento, como tio Bob e Martin Fowler, e não se deixe levar pela versão sem sentido de "corporate Agile".
Em particular, você geralmente pode se dar bem apenas com o TDD (Test Driven Development) em código científico , e há uma boa chance de que seu projeto de software seja muito bom. Isso ocorre porque o código científico de sucesso tem principalmente interfaces ultra-utilizáveis, com desempenho como uma preocupação secundária (e às vezes concorrente), e assim você pode se dar bem com um design mais "ganancioso". O tipo TDD força seu software a ser ultrautilizável , porque você escreve como deseja que as coisas sejam chamadas (idealmente) antes de implementá-las. Também força pequenas funções com pequenas interfaces que podem ser chamadas rapidamente de uma maneira simples, "entrada" / "saída", e coloca você em uma boa posição para refatorar caso os requisitos mudem.
Acho que todos podemos concordar que numpy
é um software de computação científica bem-sucedido. Suas interfaces são pequenas, super utilizáveis e tudo funciona bem juntas. Observe que numpy
o guia de referência recomenda explicitamente o TDD: https://docs.scipy.org/doc/numpy-1.15.1/reference/testing.html . Eu usei o TDD no passado para o software de imagem SAR (Synthetic Aperature Radar): e também posso afirmar que funciona extremamente bem para esse domínio em particular.
Advertência: A parte de design do TDD funciona menos bem em sistemas onde uma refatoração fundamental (como decidir que você precisa que seu software seja altamente simultâneo) seria difícil, como em um sistema distribuído. Por exemplo, se você tivesse que projetar algo como o Facebook, onde você tem milhões de usuários simultâneos, fazer TDD (para orientar seu design) seria um erro (ainda aceitável para usar depois de um design preliminar e apenas "testar o primeiro desenvolvimento" "). É importante pensar nos recursos e na estrutura do seu aplicativo antes de entrar no código. O TDD nunca o levará a um sistema distribuído e altamente disponível.
Como evitar sempre a sensação de que, se eu reconstruísse completamente meu programa do zero, faria muito melhor?
Dado o exposto, deve ser um pouco evidente que um design perfeito é realmente impossível de alcançar; portanto, perseguir um design perfeito é um jogo de tolos. Você realmente pode apenas chegar perto. Mesmo se você acha que pode redesenhar do zero, provavelmente ainda existem requisitos ocultos que não se mostraram. Além disso, as reescritas levam pelo menos o tempo necessário para desenvolver o código original. Quase certamente não será mais curto, pois é provável que o novo design tenha problemas próprios imprevistos, além de você ter que reimplementar todos os recursos do sistema antigo.
Outra coisa a considerar é que seu design realmente importa quando os requisitos mudam .Não importa o quão ruim é o design, se nada mudar (supondo que seja totalmente funcional para os casos de uso atuais). Eu trabalhei em uma linha de base que possuía uma instrução de troca de 22.000 linhas (a função era ainda mais longa). Foi um design terrível? Caramba, sim, foi horrível. Nós consertamos isso? Não. Funcionou muito bem do jeito que estava e essa parte do sistema nunca realmente causou falhas ou bugs. Ele só foi tocado uma vez nos dois anos em que estive no projeto e alguém, você adivinhou, inseriu outro caso no comutador. Mas não vale a pena arrumar tempo para consertar algo que é tocado com pouca frequência, simplesmente não é. Deixe o design imperfeito como ele é e, se não estiver quebrado (ou constantemente quebrado), não o conserte. Então talvez você possa fazer melhor ... mas valeria a pena reescrever? O que você vai ganhar?
HTH.