Como você faz a transição de um programa do desenvolvimento para o lançamento?

67

Em algum momento, um programa está em desenvolvimento. Os recursos estão sendo adicionados, removidos ou alterados o tempo todo. Toda versão não passa de um protótipo. Portanto, não perco muito tempo escrevendo código super limpo nesse momento, porque nunca sei quanto tempo algo dura. É claro que tento manter a qualidade do código em certos padrões, mas o tempo é sempre um problema.

Depois, chega o momento em que o programa termina e o (s) tomador (es) de decisão diz "é isso aí". Eu tenho um protótipo funcional neste momento, mas o código interno é um pouco confuso de todas as partes durante a fase de desenvolvimento. Espera-se que eu comece o teste / depuração final, mas meu instinto diz que agora devo de alguma forma limpar e / ou reescrever as coisas para fornecer uma arquitetura adequada que facilite a manutenção, etc.

Depois que o material é testado e aprovado, não faz sentido reescrevê-lo. Em uma base regular, eu permaneço lá com um protótipo 'pronto' em funcionamento e recebo um erro durante o teste e vejo que é o resultado de uma codificação não inteligente que é o resultado de todo o processo de desenvolvimento. Estou no meio de testes e a correção seria uma reescrita ... está uma bagunça!

Existem maneiras melhores / manuais, tenho certeza. Mas eu tenho que trabalhar em um ambiente de trabalho real, onde nem tudo é livro.

Então, como faço a transição do meu protótipo de trabalho para uma versão de lançamento com uma base de código estável? Talvez eu não deva considerar o desenvolvimento concluído assim que o fizer e realmente o vejo como a fase de limpeza ... Não sei, preciso de ajuda aqui.

EDITAR

Eu quero esclarecer algumas coisas.

  • Estou 100% do lado de fazê-lo logo antes e não depois, código limpo e legível. Mas eu também tenho que fazer as coisas e não consigo sonhar com a beleza do código, tudo limpo e brilhante. Eu tenho que encontrar um compromisso.

  • frequentemente, um novo recurso é realmente apenas algo que queremos experimentar e ver se faz sentido implementar algo assim. (especialmente em aplicativos móveis, para obter uma aparência real em um dispositivo real) Portanto, é algo pequeno que (imho) não justifica muito trabalho em uma primeira iteração "vamos ver". No entanto, às vezes, surge a questão QUANDO pago esta dívida técnica? É disso que se trata esta questão.

Se eu souber que metade dos recursos serão descartados um dia depois (já temos experiência suficiente em nossa empresa), acho realmente difícil acreditar que a melhor maneira de abordar meu problema é, no entanto, investir tempo extra para escrever tudo limpo, mesmo que a maior parte será descartada logo depois. Parece-me que economizarei tempo se fizer uma grande limpeza quando a coisa estiver sólida, daí a minha pergunta.

NikkyD
fonte
68
Sua pergunta é: "Eu me enterrei em um buraco; como saio?" A resposta padrão é, obviamente, o primeiro passo, PARE DE DIGGAR MAIS PROFUNDO. Seu processo de desenvolvimento pode ser resumido como "gerar enormes quantidades de dívida técnica e depois ignorá-la no vencimento". Se isso for um problema, altere seus processos de desenvolvimento. Faça o check-in apenas de códigos limpos, funcionais, depurados e cuidadosamente revisados ​​que atendam às especificações cuidadosamente escritas. Não se endivide e você não terá que sair da dívida.
Eric Lippert
11
@ NikkyD Se você não tiver tempo para a implementação adequada, precisará conversar com seu gerente sobre o impacto na qualidade do software. Entenda o que todo mundo aqui está lhe dizendo: não investir tempo antecipadamente está prejudicando sua capacidade de trabalhar com eficiência mais tarde. Outra questão que você quer abordar: se você sair da empresa (ou "for atropelado por um ônibus"), seria extremamente caro para os novos desenvolvedores se familiarizarem com o código. O dinheiro que eles pensam que estão economizando agora lhes custará mais tarde.
jpmc26
32
Se você está criando um pequeno ramo de recurso para simular uma interface de usuário proposta para um recurso, isso é ótimo. Torne isso o mais rápido e sujo possível, mostre-o ao cliente e exclua essa ramificação . Quando as montadoras fabricam carros de barro e papel para simular um novo design, eles não tentam colocar um motor no modelo de barro. O processo para determinar se vale a pena fazer o recurso deve ser barato. Depois de decidir fazer o recurso, verifique se você está começando com um código limpo e sempre produzindo um código limpo, porque esse código agora é um código de produção .
Eric Lippert
10
"não posso sonhar com a beleza do código limpo e brilhante" Este é um mal-entendido fundamental sobre o que "código limpo" significa. Código limpo não significa que você passa uma tarde alinhando suas guias para poder imprimir e enquadrar o código. Código limpo é um bom código e bom código é um código limpo. Código limpo é aquele que funciona corretamente, pode ser depurado e pode ser entendido. Se você não tem tempo para escrever um código limpo desde o início, definitivamente não tem tempo para escrever um código confuso e também corrigi-lo mais tarde. É exatamente quanto tempo a tarefa leva.
GrandOpener 9/03/16
8
"Eu também tenho que fazer as coisas e não posso sonhar com a beleza do código, tudo limpo e brilhante. Tenho que encontrar um compromisso." Um compromisso significa um meio termo "bom o suficiente" para os dois lados. Se o seu código estiver bagunçado - especialmente se estiver bagunçado o suficiente para você achar que terá problemas em mantê-lo -, isso não será "bom o suficiente" e você precisará encontrar um compromisso melhor.
Anaximander 10/03/16

Respostas:

98

Portanto, não perco muito tempo escrevendo código super limpo nesse momento, porque nunca sei quanto tempo algo dura.

Não saber quanto tempo dura algo nunca deve ser uma desculpa para negligência - muito pelo contrário. O código mais limpo é o IMHO, aquele que não entra no seu caminho quando você precisa alterar alguma coisa. Portanto, minha recomendação é: sempre tente escrever o código mais limpo possível - especialmente ao codificar um protótipo. Porque será muito mais fácil adaptá-lo quando algo tiver que ser alterado (o que certamente acontecerá).

Não me interpretem mal - minha compreensão do "código mais limpo" não tem nada a ver com tornar o código bonito por uma questão de beleza. Isso é realmente algo que pode atrasá-lo. No meu ponto de vista, o código limpo é um código que é autoexplicativo (não há necessidade de escrever tantos documentos - causa aceleração), fácil de entender (menos erros, menos necessidade de depuração - aceleração, menos tempo necessário para encontrar a solução correta). lugar para alterar - aceleração), resolve o problema fornecido com a menor quantidade de código necessário (menos código para depuração - aceleração óbvia), é SECO (apenas um lugar para mudar quando algo precisa ser alterado - aceleração - e menos risco de introdução novos bugs esquecendo de mudar um segundo lugar), segue os padrões de codificação (coisas menos complicadas para se pensar - aceleração), usa pequenos,

Espero iniciar o teste / depuração final, mas meu instinto diz que agora devo, de alguma forma, limpar e / ou reescrever as coisas para fornecer uma arquitetura adequada que facilite a manutenção, etc.

Fazer "limpeza" depois nunca funciona. Considere a limpeza antes de implementar um novo recurso ou quando começar a implementá-lo, mas não depois. Por exemplo, sempre que você começar a tocar em um método para um recurso e perceber que ele tem mais de 10 linhas, considere refatorá-lo para métodos menores - imediatamente , antes de concluir o recurso. Sempre que você detecta uma variável ou nome de função existente, não sabe exatamente o que isso significa, descubra para que serve e renomeie a coisa antes de fazer qualquer outra coisa. Se você fizer isso regularmente, mantenha seu código pelo menos em um estado "suficientemente limpo". E você começa a economizar tempo - porque precisa de muito menos tempo para depuração.

Estou no meio do teste e a correção de erros seria uma reescrita

... que é a prova real do que escrevi acima: estar "sujo" assombra imediatamente quando você começa a depurar seu código e o torna mais lento.

Você pode evitar isso quase completamente se fizer a limpeza imediatamente. Em seguida, as correções de bugs significarão pequenas alterações no código, mas nunca uma grande alteração na arquitetura. Se você realmente detectar evidências de um aprimoramento da arquitetura durante o teste, adie-o, coloque-o no seu sistema de rastreamento de problemas e implemente-o na próxima vez em que precisar implementar um recurso que beneficia dessa alteração ( antes de começar com esse recurso).

Isso requer alguma disciplina e alguma experiência em codificação, é claro. É uma idéia semelhante à idéia por trás do "desenvolvimento orientado a testes", fazer essas coisas antes, em vez de fazê-las depois (o TDD também pode ajudar, mas o que eu escrevi funciona mesmo quando você não usa o TDD). Quando você faz isso consequentemente, não precisará de nenhuma "fase de limpeza" especial antes de liberar.

Doc Brown
fonte
40
@NikkyD As sugestões feitas por Doc Brown são hábitos que, na verdade, diminuem o tempo gasto e são muito realistas a longo prazo. Pense em quanto tempo você economiza se não precisar examinar seu código para descobrir como não quebrá-lo toda vez que precisar alterá-lo . Os ganhos são semelhantes a mudar da digitação "caçar e beijar" para aprender a digitar. Pode levar mais tempo inicialmente, como você está aprendendo, mas uma vez que o hábito existe, é inegavelmente melhor e o beneficiará pelo resto de sua carreira. Se você optar por não tentar, nunca chegará lá.
Daniel
44
@ NikkyD: Não incha o prazo. O prazo já estava inchado; você simplesmente não foi responsável pelo inchaço quando escreveu o software e assumiu uma dívida técnica que não havia orçado.
Eric Lippert
7
@ NikkyD: Apresento o Ídolo com Feet of Clay e o conceito de Dívida técnica . O primeiro significa que você pode criar um software de som em fundações instáveis; o segundo é sobre o "interesse" (custo adicional) experimentado pelos recursos que você tenta adotar quando a estrutura não é sólida.
Matthieu M.
10
@ NikkyD: não, sugiro que você escreva seu código de maneira semelhante à de um especialista em bilhar: cada tiro parece simples para quem está de fora, pois após o tiro as bolas param na posição de um novo "tiro simples". E no bilhar ou codificação, isso leva alguns anos de prática ;-)
Doc Brown
16
@ NikkyD: para minha experiência, quando "adicionar um pequeno recurso requer muita refatoração", o código já está uma bagunça, e a necessidade de "muita refatoração" vem do fato de você precisar alterar uma função ou classe que você fez Não mantenha limpo o suficiente no passado. Não deixe que as coisas cheguem tão longe. Mas se você estiver nessa situação, encontre um compromisso. Pelo menos siga "a regra do escoteiro" e deixe o código para trás em um estado melhor do que era antes de você adicionar o recurso. Portanto, mesmo que o recurso seja removido na próxima semana, o código deve estar em melhor forma do que estava antes.
Doc Brown
22

Você tem dois problemas separados, ambos com o mesmo sintoma (código incorreto):

Problema nº 1: Controle insuficiente de requisitos Não quero dizer que suas partes interessadas os alterem com muita frequência, mas você está permitindo alterações nos requisitos durante um ciclo de correção / teste de bug. Mesmo as metodologias ágeis não suportam isso; você constrói, você testa, entrega, injeta novos requisitos.

Problema 2: Você acredita que o que está escrevendo é "apenas por agora" No código do desenvolvimento de software "por agora" é realmente extremamente raro. Você percebeu que, depois de atender a um requisito do usuário, os rigores da oferta e da demanda dificultam a justificação de voltar e reimplementar um recurso "pronto". Então o que fazer sobre isso? Sempre escreva o código de produção. Funcionalmente para você, isso significa que suas estimativas para as partes interessadas precisam ser substancialmente maiores, para que você tenha tempo para fazer o que é certo.

Além disso, entenda que você está trabalhando na posição mais difícil como desenvolvedor: leia a opinião de Joel Spolsky sobre a vida de um desenvolvedor interno . Então, você precisa ser extremamente vigilante se quiser manter sua sanidade intacta.

Gus
fonte
21

É um problema comum - especialmente ao criar o que é essencialmente um balão de teste de software , por assim dizer.

Existem várias abordagens que podem ajudar. Em primeiro lugar, a abordagem TDD pode ajudar a reduzir a base de código à estritamente necessária. Se seus testes andam de mãos dadas com seu código, você pode pelo menos ter alguma certeza de que seu código se comporta como deveria.

Tire um tempo para refatorar à medida que avança. Uma vez que você tenha um protótipo e o cliente esteja ansioso para colocar as mãos nele, é uma venda difícil dizer que você precisa de tempo para polir o que (para eles) está completo. Eu gosto de fazer check-in diariamente, seguido de um refator, mas YMMV.

Os desenvolvedores que escrevem código rapidamente são frequentemente requisitados - tivemos um desenvolvedor desse tipo no meu último departamento. Todo time o queria porque ele trabalhava super rápido. Porém, quando chegou a hora de testar e liberar seu código, as rodas rapidamente se soltaram. Coisas codificadas, hacks e atalhos em todos os lugares. Suas ações logo caíram - maciçamente.

Cortar o código de produção desde o início pode parecer uma chatice, mas dependendo do seu ambiente, existem muitas ferramentas que podem facilitar o desenvolvimento, como o Ghostdoc e o Stylecop .

Vale a pena entrar na mentalidade de desenvolvimento correta desde o início. Você ficaria surpreso com a quantidade de sistemas de pacote de cigarros que deveriam ser apenas soluções de abertura de lacunas que se tornam aplicativos de base.

Robbie Dee
fonte
Você quer dizer todas as soluções que já foram escritas, certo?
precisa
4
Um ótimo ponto sobre justificativa para o cliente. Tenho muita experiência com clientes que pensam que, quando a GUI parece concluída, o aplicativo também é feito. Aprendi a fazer a GUI parecer incompleta enquanto o código em segundo plano ainda não está pronto e, consequentemente, fazer apenas o que o cliente vê parecer polido quando o código (e a lógica de negócios) estiver. É muito difícil explicar que o que parece finalizado para o cliente ainda levará um ou dois meses para ser entregue.
Luaan 11/03/16
11

Continuamente

A velocidade do desenvolvimento é o principal motivo para escrever um código limpo, legível e testável; não é feito pela beleza, nem por outros valores abstratos. Por que eu negaria isso a mim mesmo e só o faria depois para algum programador futuro?

Claro que pode haver mudanças que são principalmente cosméticas e, portanto, não essenciais; Eu diria que é muito mais útil ter um código moderadamente bom agora, durante o desenvolvimento, do que ter uma bagunça agora e esperar torná-lo perfeito mais tarde (o que, vamos encarar, isso nunca vai acontecer, mesmo se você tivesse A Hora).

Thanos Tintinidis
fonte
6
+1 e, do ponto de vista pessoal, achei muito difícil mudar de rumo para invadir projetos pessoais em casa e escrever código de produção em meu trabalho diário. Escrever código profissional em meus projetos de hobby pagou dividendos imediatos - o código era mais fácil de ler e havia muito menos erros.
Robbie Dee
Uma razão pela qual isso nunca vai acontecer é que você (melhor) melhora o que faz ao longo do tempo. Portanto, se você esperar meio ano para "limpar" alguma coisa, não apenas esquecerá todas as minutas necessárias para fazer a limpeza com segurança, como também será um programador melhor do que antes e provavelmente ficará tentado apenas jogar tudo fora e começar de novo. E já que é tanto trabalho (e muitas vezes é uma péssima ideia), você provavelmente vai pular a limpeza novamente.
Luaan 11/03/16
"Por que eu negaria isso a mim mesmo e só o faria depois para algum programador futuro?" Revelação! E adivinha? Você às vezes (e às vezes, frequentemente) é o futuro programador.
Radarbob
@RobbieDee, observação superlativa! Em uma entrevista, Malcom Gladwell - o cara que trouxe a "regra das 10.000 horas" à conscientização popular (no livro Outliers ) - disse que deve ser "prática deliberada" ou está apenas perdendo tempo. Significado foco na melhoria, especificidades prática com a intenção de melhorar esse aspecto específico de uma habilidade, etc.
radarbob
@ThanosTintinidis, existe o problema "nenhuma boa ação fica impune". Depois de escrever esse código limpo, alguém inevitavelmente o atrapalha. Verifique se você é o revisor de código quando outra pessoa tocar no seu código limpo. Um método simples adicionado expandiu o encapsulamento e a coerência que foram documentados até em linha . Fiquei furioso por uma semana; e um ano depois, toda vez que vejo esse código.
Radarbob
4

Você faz isso diferenciando entre o código "Estou apenas tentando isso para ver como funciona" e o código "isso está direcionado para o produto". Existem várias maneiras de fazer isso.

Um deles é ramificado ou qualquer que seja a palavra em seu sistema de controle de origem. Você cria uma ramificação para o novo relatório ou o novo layout de importação ou o que for. Se as pessoas gostarem, o trabalho de devolvê-lo à ramificação principal é um trabalho rastreável e separado. Ele pode ser atribuído a alguém e relatado e não se espera que aconteça magicamente no dia em que o gerenciamento (ou vendas) concorda que o recurso pertence ao produto.

Outro são picos. Você não faz essa alteração no produto. Você entra em algum aplicativo separado, super simples, que existe apenas para você ter um lugar para colocar código. Você pode ser tão confuso quanto quiser, porque está apenas explorando a nova API ou o que quer. E, novamente, se você voltar e informar "sim, nós podemos fazer isso, eu descobri como" existe uma tarefa rastreável, reportável e atribuível de escrever código pronto para o produto para fazer o que você deseja.

Nos dois casos, pronto para o produto significa legível, limpo, seguindo os padrões de nomenclatura, com testes e aderindo ao seu estilo de código e metas de desempenho. Nos dois casos, você torna esse trabalho visível. Concordo que você não deseja fazer todo esse trabalho toda vez que alguém provavelmente retira o recurso do produto. Mas você também não quer deixar esse trabalho invisível. Trabalhar em cópias separadas do produto ou em um produto não relacionado que seja pouco mais do que um equipamento de teste permite que você aplique o trabalho para criar um código pronto para o produto assim que alguém decidir que deseja algo.

A desvantagem é que eles não podem decidir que desejam algo e enviá-lo (ou seja, a meia-versão meia-boca, bagunçada, não testada, não documentada e possivelmente lenta, que você implementou como prova de conceito) amanhã. Na primeira vez em que você se opõe a essa questão, basta perguntar se você deve fazê-lo da maneira mais longa (mais cara) todas as vezes, diminuindo o caminho para recursos rejeitados. Se você perguntar corretamente, você receberá um "não".

Kate Gregory
fonte
1

Realmente acho que você já entende o problema. O problema é que seu estilo de codificação exige que você faça muito retrabalho. O motivo pelo qual é necessário muito retrabalho é que: (a) ele é acompanhado de previsão e planejamento insuficientes; e (b) os patches incrementais de curto prazo regularmente colocados durante o desenvolvimento aumentam combinatoriamente a complexidade de qualquer retrabalho necessário.

A resposta, portanto, é

(a) mude seu estilo de desenvolvimento um pouco mais para o cascata e um pouco menos ágil. Não vá até o fim, porque a cachoeira clássica tem suas próprias armadilhas. Há um equilíbrio saudável a ser tido. Eu sei que pode ser preocupante apenas pensar nas coisas por alguns dias, às vezes, como se nenhum desenvolvimento estivesse sendo feito, mas você precisa confiar no processo. Na engenharia, você não pode simplesmente unir as coisas e depois unir as coisas por cima e esperar ter uma solução elegante. Se não há ninguém fazendo arquitetura e design técnico de nível superior, isso significa que é seu trabalho. Você está pagando o preço de negligenciar esse trabalho.

(b) tente evitar consertar as coisas. Não pense a longo prazo apenas quando chegar a hora de fazer o controle de qualidade. Realmente, você deve testar cada pedacinho que constrói, o tempo todo, e cobrindo todos os casos de entrada, aqueles que não estão no caminho feliz também. Um patch / hack é quase por definição uma correção de curto prazo, que pode muito bem ter um custo de longo prazo, atinge o Custo Total de Propriedade do cliente no sistema. Novamente, a pressão está alta para liberar o código, então é preciso haver equilíbrio. Mas tente não implementar correções de curto prazo, esp. aqueles que acoplam firmemente componentes que realmente devem ser fracamente acoplados. Haverá retrabalho, faça-o CEDO para torná-lo muito mais fácil, para evitar hacks e patches que se acumularão com o tempo e se tornarão incontroláveis.

Brad Thomas
fonte
2
Apenas uma observação - ágil não significa "mudanças frequentes sem pensar" ou "menos design". Na verdade, acho que o ágil requer muito mais design do que as pessoas costumam chamar de cascata. A falta de bom design é uma das razões pelas quais a cascata não funciona bem na prática - se você realmente investe no design corretamente, ele funciona muito bem; também fica muito mais caro que o ágil. Se você pular a parte do design de maneira ágil, estará apenas inserindo o código à vontade, e isso não funcionará melhor do que qualquer outra prática que evite o design.
Luaan 11/03/16
O foco ágil em iterações curtas, sprints etc, ficando protótipos para fora rapidamente, necessariamente coloca mais pressão sobre negligenciar projeto suficiente up front
Brad Thomas
Não, ele se concentra no design de peças menores. Mas, no geral, você deve criar muito, caso contrário, apenas produzirá um produto horrível. A chave é tornar as coisas pequenas, bem projetadas e intercambiáveis. Se você projeta menos com agilidade, está fazendo um desserviço a si mesmo (e a seus clientes). As iterações curtas são o benefício do uso do agile, não o pré-requisito ou apenas parte do processo - uma vez que você obtém tudo de bom o suficiente, pode repentinamente pagar as iterações curtas, e não o contrário.
Luaan
Colocar mais ênfase no design de peças menores é um grande problema, quando, na verdade, a imagem maior geralmente é a causa mais significativa de retrabalho. Eu vi muito mais dinheiro desperdiçado no negócio de repente dizendo "mas precisamos fazer isso", que requer uma ampla revisão do que eu já vi na mudança de um design de um pequeno componente de baixo acoplamento
Brad Thomas
Sim, mas nesse ponto você já perdeu (e independentemente de estar tentando agile ou cascata). Quando o seu "quadro geral" é composto por muitas partes pequenas relativamente isoladas, a única revisão abrangente que você obtém é quando precisa substituir praticamente tudo. Que abordagem não faz você perder tudo quando precisa começar do zero? Até os níveis de design da NASA levam a que de vez em quando "precisamos mudar tudo". Ao manter-se flexível e adaptável, você obtém mais espaço de manobra para acomodar mudanças, pequenas ou grandes.
Luaan 11/03/16
0

Você escreve:

Toda versão não passa de um protótipo. Portanto, não perco muito tempo escrevendo código super limpo nesse momento, porque nunca sei quanto tempo algo dura. ...

Depois, chega o momento em que o programa termina e o (s) tomador (es) de decisão diz "é isso aí". Eu tenho um protótipo funcional neste momento, mas o código interno é um pouco confuso de todas as partes durante a fase de desenvolvimento.

Uma versão com check-in pode ser um "protótipo", na medida em que faltam recursos ou alguns recursos não são detalhados, mas todo o código verificado deve ser um código de qualidade de produção que não precise ser limpo necessariamente.

Eu acho que você está adiando sua "limpeza" para muito.

Minha regra de ouro é:

  • Comece com o (sub) recurso
  • sinta-se à vontade para escrever coisas incompletas e incompletas, talvez alguns c & p para ter uma ideia do que estou implementando ou se tiver que riscar a (s) última (s) hora (s) de codificação (observe que isso pode ser acompanhado de TDD / testes, é que tudo é atenuado um pouco para obter um feedback rápido do espaço de implementação que estou explorando)
  • O sub-recurso "funciona" o suficiente por enquanto
  • Agora faça a limpeza: antes de uma confirmação do SCC .
    • Olhe o código para ver o que é óbvio
    • Faça um diff vs last commit para revisar alterações e talvez pegar alguns problemas
    • Corrija as coisas que anotei no meu bloco de notas
  • Agora eu faço o commit - essa qualidade de código está pronta para ser enviada

Nesse ponto, o código confirmado ainda pode conter algumas soluções alternativas ou "dívida técnica" que seria bom limpar, e talvez eu o limpe quando for o mais natural a fazer para um sub-recurso a seguir, mas ficará bem se esse código for liberado como está.

Martin Ba
fonte