Eu sou um estudante do ensino médio que trabalha em um projeto C # com um amigo meu com o mesmo nível de habilidade que eu. Até agora, escrevemos aproximadamente 3.000 linhas de código e 250 linhas de código de teste em um intervalo de 100 confirmações. Devido à escola, adiei o projeto por alguns meses e recentemente pude recuperá-lo novamente.
No momento em que o recuperei, eu entendi que o código que havia escrito era mal projetado, como inclusão de encadeamentos excessivos no renderizador, prevenção deficiente de condições de corrida na interação entre CPU, GPU e cartucho de jogo emulados , bem como código que é simplesmente redundante e confuso.
O problema é que eu não terminei nem a principal funcionalidade do meu programa, por isso não posso refatorar de verdade e me sinto desencorajado por continuar perfeitamente ciente de que o design do meu código é defeituoso. Ao mesmo tempo, não quero abandonar o projeto; uma quantidade substancial de progresso foi feita e o trabalho não deve ser desperdiçado.
Sinto como se tivesse algumas opções: simplesmente finalizar a funcionalidade contornando o design deficiente e refatorando quando tudo estiver funcionando, interrompendo tudo e trabalhando para desemaranhar tudo antes que o restante da funcionalidade possa ser concluído, iniciando o projeto tudo de novo, para que eu esteja novamente em minha mente ou abandone o projeto devido ao seu tamanho excessivo (essencialmente "voltando à prancheta").
Com base na experiência dos outros em tais projetos, qual é o recurso para me colocar de volta no caminho certo? A partir das respostas neste site, o consenso geral é que a reescrita geralmente não é necessária, mas é uma opção disponível se o código não puder ser mantido sem custos excessivos. Eu realmente gostaria de prosseguir com esse projeto, mas, como está, meu código não foi projetado o suficiente para que eu possa continuar, e um sentimento de desânimo me impede de continuar.
Respostas:
Se eu estivesse no seu lugar, provavelmente tentaria assim:
primeiro, finalize o projeto atual - pelo menos parcialmente - o mais rápido possível, mas em um estado de funcionamento . Provavelmente você precisa reduzir seus objetivos originais, pense na funcionalidade mínima que realmente precisa ver na "versão 1.0".
então, e só então pense em reescrever do zero (vamos chamar isso de "versão 2.0"). Talvez você possa reutilizar parte do código da V1.0. Talvez depois de dormir de novo com a situação, você tome a decisão de refatorar a V1.0 e salvar a maior parte dela. Mas não tome essa decisão antes de não ter uma "prova de conceito V1.0" em mãos.
Um programa de trabalho "1.0" é algo que você pode mostrar a outras pessoas, mesmo quando o código é ruim (com o qual ninguém mais se incomodará, exceto você). Se, no meio da criação da V2.0, você perceber que está ficando sem tempo, ainda terá a V1.0 como um sucesso parcialmente, o que será muito melhor para o seu moral. No entanto, se você não concluir a V1.0 primeiro, há uma grande chance de você nunca concluir a V2.0 porque, no meio do caminho, haverá um ponto em que você não ficará satisfeito com o design novamente, e então? Você abandonará a V2.0 novamente e trabalhará na V3.0? Existe um alto risco de entrar nesse círculo sem fim, nunca chegando ao fim.
É melhor aproveitar isso como uma oportunidade de aprender a atingir objetivos intermediários, em vez de aprender a deixar projetos em um estado inacabado para trás.
fonte
Better take this as an opportunity to learn how to achieve intermediate goals, instead of an opportunity to learn how to leave projects in an unfinished state behind.
Os projetos de TI concluídos, mesmo os defeituosos, são muito melhores que os inacabados.
Os inacabados também podem ensinar muito, mas não tanto quanto os acabados.
Você pode não vê-lo agora, mas obtém uma enorme quantidade de valor trabalhando mesmo com código defeituoso.
Meu voto é para terminar e depois refatorar - se necessário. Quando você começa a trabalhar com mais projetos, verá que, surpreendentemente, a parte que "deveria ser refatorada" permanece intocada por anos, enquanto outras são estendidas.
Do ponto de vista do emprego, na maioria dos casos, você recebe mais elogios por um projeto concluído.
fonte
Felizmente, eu começaria o projeto novamente.
Você é um estudante e ainda está aprendendo. Isso coloca você em uma posição muito diferente da pergunta à qual você vinculou.
Você não tem responsabilidade profissional pelo seu código; se você excluir o projeto inteiro agora e sair, não sofrerá repercussões. Esta é uma enorme vantagem para um desenvolvedor. Na pergunta que você vinculou, esses desenvolvedores estão tentando manter um software pelo qual as pessoas estão pagando, e até pequenos bugs podem causar grandes problemas aos clientes, o que torna perigoso escrever do zero. Você não tem esse problema.
Como um projeto pessoal, esta é a oportunidade perfeita para experimentar coisas novas e aprender com seus erros. É ótimo que você reconheça que seu código antigo tem problemas, porque isso significa que você aprendeu a fazer melhor. A experiência por tentativa e erro pode ser inestimável para programadores iniciantes.
Seu projeto é relativamente pequeno e você basicamente não tem testes. Pode demorar algumas noites para escrever 3000 linhas a partir do zero, especialmente porque você já tem idéias sobre o que fazer melhor da próxima vez.
Trabalhar em uma base de código quebrada será uma perda muito maior de moral do que uma reescrita.
Como um aparte, essa pode ser uma ótima chance de tentar escrever um programa mais modular com testes de unidade. Isso facilita muito a compreensão do código se você voltar após um longo intervalo e ajuda a evitar erros que você pode introduzir acidentalmente devido ao esquecimento.
Finalmente, aqui está uma opinião sobre a sabedoria de, às vezes, dar passos para trás para dar passos maiores adiante.
fonte
Você provavelmente ainda está na parte "aprendendo rápido" do seu desenvolvimento. Há uma boa chance de que, daqui a alguns meses, você descubra que seu novo e incrível design está terrivelmente quebrado de maneiras que você nem sabia quando começou.
Faça as coisas - essa é a coisa mais importante que você precisa aprender. Acredite, eu conheço muitas pessoas (não apenas programadores) que estão presas no ciclo "continue recomeçando desde que aprendi muito antes de iniciar esse projeto". O problema é que isso nunca acaba - até você parar de aprender coisas novas, o que não é um bom lugar para se estar :)
Também é importante para poder realmente terminar qualquer coisa. Começar de novo é emocionante, legal, divertido ... mas se você aprender isso, nunca poderá terminar nada. Novamente, essa não é uma habilidade muito útil, e na verdade não parece tão boa quanto criar algo útil (ou divertido). A vida é curta, o tempo é limitado, e você não pode continuar praticando sem resultados tangíveis - você ficará louco com isso. Se você não conseguir começar a trabalhar porque simplesmente não consegue decidir qual abordagem adotar, já está na zona de perigo.
Sempre haverá impulsos para recomeçar. Mesmo em um ambiente de aprendizado, essas são provavelmente uma má idéia. Isso não significa que você precise transportar todos os protótipos para um aplicativo pronto para produção, longe dele. Mas você precisa pelo menos chegar a uma fase de protótipo funcional - provavelmente ajudará sua moral, e é uma característica muito útil para qualquer desenvolvedor de qualquer tipo. Faça as coisas . E a parte divertida é que você verá rapidamente que há um milhão de coisas mais divertidas ou úteis que você pode fazer com seu protótipo, em vez de "reescrevê-lo do zero" - e, em muitos casos, até refatorá-lo. Tudo o que você faz tem um custo - no mínimo, você poderia estar fazendo outra coisa nesse meio tempo.
fonte
Sigo a ideologia "Faça funcionar, faça certo, faça rápido" no desenvolvimento de software.
No momento, você não concluiu a etapa 1. Faça com que funcione primeiro e, em seguida, você pode se preocupar com o quão feio é o seu código. Na verdade, criar um produto funcional é uma das coisas mais difíceis para os novos desenvolvedores, porque eles ficam tão envolvidos na tentativa de aperfeiçoar seu código na primeira vez e ficam presos no inferno da otimização e nunca chegam ao fim implementando todos os recursos. Você precisa aprender a deixar de lado todas as preocupações com refatoração e otimização para poder se concentrar apenas em fazer o software funcionar. Depois de obter mais experiência, naturalmente você fará mais coisas da primeira vez, portanto, menos refatoração é necessária.
Lembre-se: a otimização prematura é a raiz de todos os males (consulte esta excelente pergunta sobre Programadores.SE para uma boa discussão). Se você gasta muito tempo pensando em como melhorar seu código, fica paralisado na paralisia da análise . Isso mata o projeto. É melhor concluir o projeto antes de começar a otimizá-lo.
Para citar um ótimo palestrante motivacional: basta fazê-lo .
Como sempre, há um xkcd relevante:
fonte
Reescreva-o. O código não útil tem pouco valor e três mil linhas não são muito código. Não demorará tanto tempo para escrever o código que você possui atualmente, e será muito melhor. Muitas vezes joguei quinhentas ou mil linhas de código ruim, e muitas vezes a reescrita é um quinto do comprimento.
A maioria das noções em torno de "não reescrever" refere-se a sistemas grandes fazendo coisas importantes e passando por constantes mudanças para atender aos requisitos em evolução. Reescritas de sistemas complexos em uso raramente são bem-sucedidas.
Sua situação é o oposto completo. Você tem um aplicativo pequeno sem usuários e os únicos requisitos são os que você escolhe implementar. Então vá em frente e reescreva-o.
fonte
Reiniciar do zero geralmente é uma má jogada em projetos da vida real, principalmente porque os projetos da vida real acumulam correções de bugs que um desenvolvedor novato não tem conhecimento (por exemplo, consulte Coisas que você nunca deve fazer , de Joel no blog Software ).
No entanto, os projetos escolares não herdam essa história e geralmente começam por codificar e projetar ao mesmo tempo, com conhecimento parcial da computação e falta de experiência. Eu consideraria sua primeira versão como um protótipo, usada como uma prova de conceito que falhou, e eu a descartaria alegremente (consulte Quais são as diferenças entre os protótipos descartáveis e evolutivos? Para uma discussão sobre prototipagem descartável vs. evolutiva).
O design correto amadureceu na sua cabeça e não deve demorar muito tempo para anotá-lo no código.
fonte
Eu respeitosamente discordo das sugestões de que reescrever é uma má ideia.
No âmbito do ciclo de vida do software, geralmente é aceito que o tempo e o esforço necessários para corrigir um erro aumentem em uma ordem de magnitude em cada camada do ciclo de vida. Ou seja, se levar 1 hora para corrigir um erro no nível de requisitos, levará 10 horas no design, 100 horas no teste de codificação e 1000 horas como uma correção de bug. Esses números podem parecer ultrajantes, mas são aceitos pelo setor como sendo aproximadamente corretos. Obviamente, menos em um projeto menor, mas a idéia geral permanece. Se o seu projeto possui uma falha básica de design, é mais apropriado chamar isso de experiência de aprendizado e voltar, revisar seus requisitos iniciais e redesenhar.
Eu também encorajaria a consideração de um modelo de Desenvolvimento Orientado a Testes usando testes de unidade estruturados. Eles são uma dor e inicialmente parecem uma perda de tempo, mas sua capacidade de descobrir erros, especialmente quando se integra ao código de outra pessoa, não pode ser exagerada.
fonte
Você me perdeu nesta frase:
Eu acredito no princípio (declarado na sistemática ) de que
Então, escrever um sistema complexo inclui
... ou seja, os seguintes passos:
Observe que a etapa 3 pode envolver:
Além disso, a Etapa 2 "Teste para garantir que funcione" pode envolver alguma reescrita, se não funcionar.
Se eu estivesse construindo uma base de código podre, não seria inclinado a adicionar mais funcionalidades. Então, eu estaria inclinado a agendar algo como "simplificar a implementação de encadeamento existente" como o próximo trabalho a ser implementado. Supondo que você esteja testando à medida que avança, você deve tratar isso como um exercício de refatoração. Os critérios de sucesso / saída para esta fase de trabalho seriam:
Aliás, "testá-lo para garantir que funcione" não significa necessariamente "testes de unidade" - quando a estrutura da equipe é simples, você pode testar um sistema (simples) usando testes de sistema (simples) (em vez de testes de unidade) .
fonte
Um dos problemas que você enfrenta ao se deparar com um problema como esse é que você está emocionalmente ligado ao código que você escreveu até agora, de uma maneira ou de outra.
Um colega me disse que estava escrevendo um programa enquanto estava na universidade, enquanto recebia lições de um professor famoso (acredito que era Dijkstra). Ele pediu ao professor que olhasse o código em que trabalhava há mais de um mês. O professor perguntou se ele tinha feito um backup, ele respondeu que não. O professor excluiu todo o seu código e disse-lhe para escrevê-lo novamente.
Ele estava chateado, mas três dias depois ele terminou o programa, com código mais limpo e menos erros e menos linhas de código.
Tente fazer uma estimativa honesta de qual opção é melhor no tempo disponível para o projeto.
As 3 opções são
Sou programador profissional há mais de 10 anos e, na minha linha de trabalho, concluí que a última opção é na maioria das vezes a escolhida, mas nem sempre é a melhor opção.
fonte
Parece que suas habilidades cresceram substancialmente nesse período. Talvez o trabalho nesse projeto tenha contribuído para ele. Projetá-lo novamente como uma experiência de aprendizado proposital seria proveitoso.
Lembre-se, isso não é algo que você precisa fornecer como um programa de trabalho para um cliente. Foi escrito especificamente para a prática. Portanto, a menos que você queira praticar problemas de remessa e entrega incorreta, acho que atualmente você está em uma fase de desenvolvimento em que trabalhar seus "músculos do design" seria proveitoso.
Ao fazer isso, concentre-se no processo e no planejamento do design, pense nas coisas existentes e reflita sobre o que você está entendendo melhor.
fonte
Refatorar. Refatorar. Refatorar! REFATOR !!!!
Honestamente, não importa o quão experiente você seja, isso é um problema comum. Você escreveu o código, aprendeu alguma coisa e deseja usar o novo conhecimento no código antigo. Você deseja comparar o código antigo com o novo conhecimento.
Isso simplesmente não vai funcionar. Se você fizer isso, seu aplicativo / jogo nunca será concluído. Em vez disso, tente alocar seu tempo no projeto para que algumas de suas "tarefas" refatem o código incorreto. Digamos, por exemplo, que você tenha um método horrível de salvar o jogo. Continue trabalhando no jogo em si, mas encontre tempo para refatorar (substituir) esse método horrível. Tente manter os refatores pequenos, e isso não deve ser um problema.
Quando você chega à maior parte do aplicativo que precisa de um refator, está fazendo algo errado, sério. Quebre essa refatoração em partes menores. Tente passar sete horas escrevendo código e uma hora refatorando.
Quando você terminar o projeto e pressionar o congelamento de recursos, poderá passar um tempo massivo refatorando. Por enquanto, conclua o jogo, mas tente refatorar alguns. É o melhor que você pode fazer.
Sempre haverá algo para refatorar.
fonte
Eu diria que depende um pouco do tipo de código que você tem agora e onde exatamente estão os problemas. Ou seja, se suas fundações são boas (design de classe adequado na maioria das partes, boa dissociação / coesão etc., apenas algumas más escolhas, como as linhas que você mencionou), então, por todos os meios, obtenha um 1.0 básico e refatorie como não há amanhã.
Por outro lado, se é realmente apenas um monte de arquivos de texto feios que de alguma forma passam pelo compilador, sem estrutura discernível etc. (em outras palavras, um protótipo de prova de conceito de aprendizado no trabalho), então eu prefiro excluí-lo e começar de novo.
Na sua próxima versão, faça uma abordagem ágil: defina um cronograma fixo e repetitivo, como 2 semanas ou o que for mais adequado à sua programação. No início de cada bloco (vamos chamá-lo de sprint), defina metas que são alcançáveis nas 2 semanas. Vá em frente e faça-os, tente o seu melhor para fazê-lo funcionar. Defina suas metas para que, a cada 2 semanas, você tenha algo que possa ser mostrado a um amigo, não apenas um trabalho interno abstrato. Google "scrum" e "objetivo inteligente". Tudo isso é muito fácil de fazer, se você estiver sozinho, apenas um pedaço de papel com alguns marcadores rapidamente anotados.
Se você pode fazer isso, então começar de novo é bom. Se você sabe lá no fundo que, depois de começar de novo, provavelmente acabará onde está agora, de qualquer maneira, fique com o seu código e faça com que ele funcione.
fonte
Você tem que se colocar no lugar do empregador.
Para a maioria dos recrutadores, você seria o mais valioso se seguisse este caminho: - Finalize com 100% de testes no novo código que você escreve. - Adicione testes para o código antigo (mal projetado). - Refatorar para alcançar o que você queria como design.
Faça tudo isso com um bom processo de versão, ramificações e tags.
Reescrever muitas vezes é uma ideia sexy, mas muitas vezes é uma ideia que os novatos têm, o que é meio perigoso na vida real. Mostrando que você está mais disposto a melhorar a qualidade do trabalho que já fez, em vez de começar do zero é um bom sinal de que você é uma pessoa séria.
Obviamente, você pode reescrevê-lo, mas criar outro projeto.
fonte
Apenas para adicionar um pouco da minha experiência passada à mistura. Estou trabalhando em um projeto paralelo há mais de um ano, sempre que recebo alguns minutos livres. Este projeto passou de uma simples mesa de teste para uma classe estática e passou a ser um design fino e orientado a objetos.
Durante todas essas alterações, mantive a mesma funcionalidade do código, excluindo correções de bugs e benefícios de desempenho (precisa ser o mais rápido possível). A mesma base de código, embora refatorada, permaneceu a mesma e, como tal, eu a melhorei bastante sem precisar reescrever o código do zero e perder tempo.
Isso significa que fui capaz de melhorar o código a uma taxa mais rápida do que antes. Também significava que, como eu estava indo, era mais fácil dizer o que precisava ser removido, ou seja, aulas desnecessárias e o que poderia ficar mais fácil do que reescrever com a velha idéia que ainda estava em minha mente.
Portanto, meu conselho seria refatorar seu código e seguir em frente, fazendo as melhorias necessárias. Embora lembre-se, se você decidir reescrever do zero, deve pegar as boas idéias do projeto antigo e examiná-las de perto para ver onde elas são defeituosas. Ou seja, não basta copiar o código antigo para o novo projeto.
fonte
A resposta depende de algo que eu gosto de chamar de "teto da complexidade". À medida que você adiciona cada vez mais a uma base de código, há uma tendência para que ela se torne cada vez mais complexa e cada vez menos organizada. Em algum momento, você atingirá um "limite de complexidade", momento em que o progresso futuro se torna muito difícil. Em vez de tentar continuar se movendo com força bruta, é melhor fazer backup, reorganizar / reescrever e continuar seguindo em frente.
Então, sua base de código é tão ruim que você está chegando a um limite de complexidade? Se você sentir que é, leve um tempo para limpar e simplificar antes de continuar. Se a maneira mais fácil de limpar é reescrever algumas peças, tudo bem.
fonte
Nem? Ambos?
Continue em frente, gaste algum tempo revisando o design existente e adicionando novas funcionalidades.
Se você tiver interações atrativas, esse pode ser um bom ponto de partida ("threads excessivos no renderizador" parece uma ineficiência, e não algo que poderia causar problemas de correção). Veja se você consegue descobrir uma maneira geral de se afastar das corridas (e possivelmente impasses) ou pelo menos várias maneiras específicas de fazê-lo.
Não sei até que ponto coisas como detectores de impasse e corrida estão disponíveis para C #, mas, se existirem, podem ser úteis para identificar quais problemas existem e verificar se suas correções estão funcionando.
Acho que, em geral, estou mais motivado para corrigir problemas com o código que faz algo útil, em vez de jogá-lo fora e começar novamente do zero. Há casos em que o desenvolvimento de campos queimados (em analogia ao greenfield e brownfield ...) é mais satisfatório, mas geralmente é para coisas em que a abordagem existente está tão longe de onde deveria estar que não está mais errada.
fonte
Se o seu código for modular, você poderá concluir o restante do código em torno dos componentes gravados incorretamente e depois reescrever os componentes gravados incorretamente, sem afetar o restante do código.
Nesse caso, você decide quando reescreve os componentes mal escritos. Se os componentes mal gravados são tão mal gravados que o código finalizado não funcionará com eles como estão, será necessário reescrevê-los antes que você possa concluir o restante do código.
fonte
A primeira pergunta que você deve se perguntar é "quão ruim é a falha?"
O que exatamente você fez de errado?
Se algo é tão ruim que você gasta muitas horas tentando trabalhar com o problema, expõe dados confidenciais (senhas / cartões de crédito) ou causa uma vulnerabilidade ruim, talvez seja necessário editá-lo, mas na maioria das vezes você pode pegue o que você tem, termine e corrija o problema mais tarde.
Os programadores adoram aprimorar seus aplicativos, querendo que eles sejam "o melhor que podem ser", mas essa não é a abordagem correta.
SE você liberar seu aplicativo o mais rápido possível, mesmo que não seja 100%, todos os bugs e todos, você receberá o FEEDBACK de outras pessoas, enquanto terá tempo para corrigir os bugs e outras coisas da versão 1.1. Outras pessoas poderão ajudá-lo a melhorar o aplicativo e você pode ter perdido tempo fazendo algo que as pessoas podem não gostar.
Portanto, no seu caso, divulgue-o, obtenha algum feedback e, em seguida, você pode estruturar a versão 2.0 com todas as alterações e corrigir a falha que você possui.
Outra coisa a lembrar é que estamos constantemente melhorando. Há um ditado que diz que se você pode olhar seu código de um ano atrás e ver que está ruim, isso significa que você ainda está melhorando, e isso é ótimo.
fonte
Depende de como o seu código está estragado.
Se você cometeu erros reais de n00b que tornam seu código excessivamente complexo ou detalhado, recomendo reescrever essas partes.
Se você acha que possui bugs sérios que precisará corrigir de qualquer maneira, escreva alguns testes de unidade para verificar se o bug foi corrigido (... já que você ainda não pode iniciar o programa). É melhor corrigir erros mais cedo, e definitivamente é melhor corrigir erros enquanto você ainda se lembra do que o código faz.
Se você não gosta do que os métodos são chamados, ou a qual classe eles pertencem, ou pequenas coisas assim, basta usar o IDE. (Lembre-se de que é C #, e não javascript, python, perl, php etc.) Quando você trabalha com código que usa o componente afetado e tem uma imagem clara do que esse componente deve fazer, refatore-o se o seu IDE o tornar indolor.
Caso contrário, faça-o funcionar e aprimore suas habilidades no próximo projeto.
fonte
Como outros sugeriram, como este é um projeto pessoal, não (ainda) um projeto profissional, eu consideraria seriamente uma reescrita.
No entanto, você pode aproveitar o método científico aqui, realizando um experimento. Primeiro, conceba uma hipótese. A minha seria: "provavelmente é hora de reescrever". Para economizar tempo, reduza o custo da falha e, de certa forma, limite o viés a priori, antes de fazer mais a programação, decida um período de tempo ("caixa de tempo"). Eu sugeriria talvez quatro horas de relógio de parede. Decida também sobre uma metodologia para avaliar a hipótese. Como as apostas são baixas, eu sugeriria como metodologia, simplesmente se pergunte: "estou feliz por ter feito isso?" Agora comece o experimento. Após o horário escolhido, qual é a avaliação da hipótese? Por exemplo, no meu exemplo, você está feliz por ter começado a reescrever agora que passou 4 horas fazendo isso? Então provavelmente é a escolha certa.
Você pode pedir todos os conselhos do mundo, mas não há nada como testar uma hipótese empiricamente.
Alguns motivos para considerar a seleção de uma reescrita como sua experiência:
Terminar algo é uma boa ideia, mas não no vácuo. Se você começar a reescrever, poderá optar por terminar algo finalizando um submódulo específico. Você pode definir isso como um primeiro objetivo, após o experimento acima. Acabar não precisa significar terminar seu projeto principal inicial ainda. Depois de terminar um módulo, termine outro, etc., até terminar de reescrever todo o escopo do seu projeto original, se desejar.
fonte