Um dos princípios mais básicos e amplamente aceitos do desenvolvimento de software é o DRY (não se repita). Também está claro que a maioria dos projetos de software requer algum tipo de gerenciamento.
Agora, quais são as tarefas fáceis de gerenciar (estimativa, cronograma, controle)? Certo, tarefas repetitivas, exatamente as tarefas que devem ser evitadas de acordo com o DRY.
Portanto, do ponto de vista do gerenciamento de projetos, é ótimo resolver uma tarefa, copiando algum código existente 100 vezes e fazendo algumas pequenas adaptações em cada cópia, conforme necessário. Em todo o momento, você sabe exatamente quanto trabalho fez e quanto resta. Todos os gerentes vão amar você.
Se, em vez disso, você aplicar o princípio DRY e tentar encontrar uma abstração que elimine mais ou menos o código duplicado, as coisas serão diferentes. Geralmente existem muitas possibilidades, você precisa tomar decisões, pesquisar, ser criativo. Você pode encontrar uma solução melhor em menos tempo, mas também pode falhar. Na maioria das vezes, você não pode realmente dizer quanto trabalho resta. Você é o pior pesadelo de um gerente de projetos.
Claro que estou exagerando, mas obviamente há um dilema. Minhas perguntas são: Quais são os critérios para decidir se um desenvolvedor está exagerando no DRY? Como podemos encontrar um bom compromisso? Ou existe uma maneira de superar completamente esse dilema, não apenas encontrando um compromisso?
Nota: Esta pergunta é baseada na mesma idéia que a anterior, Quantidade de trabalho de rotina no desenvolvimento de software e seu efeito na estimativa , mas acho que isso torna meu argumento mais claro, desculpe-me por me repetir :).
fonte
Respostas:
Você parece assumir que o objetivo principal do gerenciamento de projetos é produzir estimativas exatas. Este não é o caso. O objetivo principal do gerenciamento de projetos é o mesmo dos desenvolvedores: agregar valor ao proprietário do produto.
Um produto que utiliza muitos processos manuais lentos em vez de automação pode, em teoria, ser mais fácil de estimar (embora eu duvide), mas não fornece valor ao dinheiro ao cliente, por isso é simplesmente um mau gerenciamento de projetos. Não há dilema.
É sabido que a estimativa de projetos de software é difícil, e vários livros foram escritos e vários processos foram desenvolvidos para gerenciá-lo.
Se o único objetivo do PM fosse produzir estimativas exatas, seria fácil. Apenas reduza as estimativas para 10X e deixe os desenvolvedores jogarem pelo resto se terminarem mais cedo. Isso seria realmente melhor do que sua sugestão de usar o trabalho copiar-colar para diminuir o tempo, pois jogar não reduzirá a manutenção do produto.
Mas, na realidade, o proprietário do produto deseja estimativas úteis e um produto de qualidade entregue o mais rápido e barato possível. Essas são as restrições reais que um PM terá para navegar.
De qualquer forma, discuto sua suposição de que o trabalho manual repetitivo é mais previsível do que automatizado. Toda a experiência mostra que o trabalho manual repetitivo é mais propenso a erros. E se um bug for descoberto no código copiado e colado? De repente, o custo de consertar um bug é multiplicado pela quantidade de repetição, o que faz a incerteza explodir.
fonte
Você está certo - copiar e colar funciona muito bem e o DRY não faz sentido em que sua tarefa é produzir um programa para o qual o modelo copiado ou a cópia não precisarão ser mantidos ou evoluídos no futuro. Quando esses dois componentes de software têm um ciclo de vida completamente diferente, acoplá-los ao refatorar o código comum em uma lib comum que está em desenvolvimento pesado pode de fato ter efeitos imprevisíveis para o esforço. Por outro lado, ao copiar seções de código dentro de um programa ou sistema de programa, todas essas partes normalmente terão o mesmo ciclo de vida. Ilustrarei abaixo o que isso significa para DRY e gerenciamento de projetos.
Sério, existem muitos programas por aí: por exemplo, a indústria de jogos de computador produz muitos programas que precisam ser mantidos por um curto período de alguns meses ou um ano no máximo, e quando esse tempo termina, copiar e colar código antigo de um jogo anterior em que o período de manutenção é excedido, a base de código de um novo jogo é perfeitamente adequada e pode acelerar as coisas.
Infelizmente, o ciclo de vida da maioria dos programas com os quais tive que lidar nos últimos anos é muito diferente disso. 98% dos requisitos ou solicitações de correção de erros que me chegaram foram solicitações de alteraçãopara programas existentes. E sempre que você precisar alterar algo em um software existente, "gerenciamento de projetos" ou planejamento funcionará melhor quando seus esforços de teste e depuração forem muito baixos - o que não será o caso se você alterar algo em um só lugar, mas devido à cópia lógica de negócios bem planejada, você esquece facilmente que também precisa mudar uma dúzia de outros lugares na base de código. E mesmo que você consiga encontrar todos esses lugares, o tempo para alterá-los todos (e testar as alterações) provavelmente é muito maior, como se você tivesse apenas um lugar para trocar. Assim, mesmo você pode fazer uma estimativa precisa da mudança, tendo os custos uma dúzia de vezes mais altos do que o necessário, podendo facilmente colidir com o orçamento do projeto.
TLDR - sempre que você desenvolver um programa em que não haja necessidade ou responsabilidade pela correção de erros e manutenção do original ou da cópia, fique à vontade para copiar. Mas se você, sua equipe ou sua empresa for ou puder se tornar responsável, aplique DRY sempre que puder.
Exemplo
Como adendo, deixe-me explicar o que significa "correção e manutenção de bugs" e como isso leva a imprevisibilidade no planejamento, especialmente dentro de um produto, por um exemplo do mundo real. Eu realmente vi esse tipo de coisa acontecer na realidade, provavelmente não com 100 instâncias, mas os problemas podem começar quando você tem apenas uma instância duplicada.
A tarefa: criar 100 relatórios diferentes para um aplicativo, cada relatório parecendo muito semelhante, algumas diferenças de requisitos entre os relatórios, alguma lógica diferente, mas, no geral, poucas diferenças.
O desenvolvedor que obtém essa tarefa cria a primeira (digamos que leva três dias). Após algumas alterações ou pequenas correções de erros devido ao controle de qualidade e à inspeção do cliente, parece que está funcionando bem. Então ele começou a criar o próximo relatório copiando e colando a coisa toda, depois o próximo, e para cada novo relatório ele precisa de aproximadamente 1 dia em média. Muito previsível, à primeira vista ...
Agora, depois que os 100 relatórios estiverem "prontos", o programa será produzido de maneira real e ocorrerão alguns problemas que foram ignorados durante o controle de qualidade. Talvez haja problemas de desempenho, talvez os relatórios falhem regularmente, talvez outras coisas não funcionem conforme o esperado. Agora, quando o princípio DRY foi aplicado, 90% desses problemas poderiam ser resolvidos alterando a base de código em um único local. Mas, devido à abordagem de copiar e colar, o problema deve ser resolvido 100 vezes em vez de uma vez. E devido às alterações já aplicadas de um relatório para outro, o desenvolvedor não pode copiar e colar rapidamente a correção do primeiro relatório para o outro 99. Ele deve examinar todos os 100 relatórios, lê-los, traduzir a alteração para o modificado relatório, teste e talvez depure cada um individualmente. Para o PM, isso começa a ficar muito difícil - ele pode, naturalmente, dedicar um tempo para uma correção de erro "regular" (digamos, 3 horas) e multiplicar por 100, mas, na verdade, essa é provavelmente uma estimativa incorreta, algumas das correções podem ser mais fácil de fazer do que outros, outros podem ser mais difíceis. E mesmo que essa estimativa esteja correta, o custo da depuração 100 vezes mais alto do que era necessário custará muito dinheiro à empresa.
O mesmo acontecerá na próxima vez em que o cliente solicitar a alteração da cor do emblema da empresa em todos esses relatórios, para tornar o tamanho da página configurável ou por algum outro novo requisito que afete todos os relatórios de maneira semelhante. Portanto, se isso acontecer, você pode fazer uma estimativa dos custos e cobrar do cliente 100 vezes o preço que ele teria que pagar quando o código estivesse SECO. No entanto, tente isso algumas vezes e, em seguida, o cliente cancelará o projeto porque provavelmente não estará disposto a pagar seus custos exorbitantes de desenvolvimento. E talvez nesse momento alguém faça a pergunta por que isso aconteceu e aponte com o dedo a pessoa que tomou a decisão para esta programação de copiar e colar.
O que quero dizer é: quando você produz software para terceiros, sempre tem pelo menos por um curto período de tempo a responsabilidade de fazer a coisa funcionar, corrigir bugs, adaptar o programa às mudanças de requisitos etc. Mesmo em um projeto de campo verde, essas as peças podem adicionar rapidamente muito mais do que o esforço de desenvolvimento planejado inicialmente. E especialmente quando todo o seu código copiado e colado está dentro de um produto, o período de responsabilidade é o mesmo para todas as partes, o que é bastante diferente da situação em que você copiou um código antigo de um projeto morto que não é mais sob manutenção ativa.
fonte
Sua afirmação básica está incorreta.
O que diferencia o software de outras profissões é que você está criando algo novo todos os dias. Afinal, nenhum cliente pagará para você construir algo que outra pessoa já fez. Os gerentes de projeto podem gostar de previsibilidade, mas seus chefes gostam de valor . Se você é apenas copiar e colar código com pequenas variações, não está fornecendo muito valor para a empresa.
Eventualmente, a empresa perceberá que pode fazer o mesmo trabalho em uma fração do tempo contratando um bom programador. E se não o fizerem, seus concorrentes o farão.
fonte
A programação recortar e colar eventualmente leva ao software abandonado. Eu era um contratado em um sistema para solicitar serviços de telefonia fixa de uma companhia telefônica muito grande. O sistema foi recortado e colado ad nauseum porque todos os testes eram manuais e eles não queriam alterar nenhum código de trabalho. O menor aprimoramento pode resultar em uma nova cópia de centenas de linhas de código. Originalmente, o aplicativo foi escrito para lidar com contas de até doze linhas físicas. Obviamente, essa limitação foi feita em centenas de locais no código. Após cerca de quatro anos, os negócios perguntaram à equipe o que seria necessário para lidar com contas maiores. Eles estimaram cerca de US $ 18 milhões. Nesse ponto, o projeto foi entregue a uma equipe offshore para manutenção mínima. A equipe existente foi demitida.
Organizações que pensam assim estão sendo esmagadas por empresas com melhor tecnologia.
fonte
Uma máxima frequentemente esquecida que se aplica aqui é a regra de 3 . Ele afirma que não há problema em copiar o código uma vez, mas além disso deve ser substituído pelo código genérico.
3 pode parecer um número arbitrário, mas um cenário comum é onde dados e lógica são duplicados em um aplicativo e banco de dados. Um exemplo frequentemente citado é o local em que há uma tabela de pesquisa no banco de dados e um lado do cliente de enumeração. A diferença de paradigmas não permite que isso seja prontamente armazenado em um único local e, portanto, as informações geralmente aparecem nos dois locais.
Embora seja bom ter código DRY, pode haver momentos em que a lógica de negócios dita uma exceção e, portanto, você deve criar dois ou mais bits de código a partir da fonte que era genérica antes.
Então o que fazer? Código para o status quo (afinal, YAGNI ). Embora o código deva ser escrito para facilitar a modificação, escrever uma série de sinos e assobios para algo que pode não ser necessário é apenas incendiar o dinheiro.
fonte
Na sua pergunta, você lista apenas três funções do gerenciamento de projetos - estimativa, cronograma e controle. O gerenciamento de projetos visa atingir metas dentro das restrições do projeto. Os métodos usados para atingir objetivos dentro das restrições de um projeto são diferentes para projetos de software que muitos outros tipos de projetos. Por exemplo, você deseja que os processos de fabricação sejam altamente repetíveis e bem compreendidos. No entanto, o desenvolvimento de software é principalmente trabalho de conhecimento- não é rotineiro e requer pensar, em vez de seguir instruções e procedimentos rígidos. As técnicas usadas para iniciar, planejar, executar, monitorar e controlar e fechar um projeto de software precisarão levar em consideração o tipo de trabalho que precisa ser feito em um projeto de software - especificamente, trabalho não rotineiro que não pode ser realizado instruções e procedimentos específicos.
Acho que o outro problema é que você está usando o DRY, um conceito relacionado à repetição de informações, e tentando aplicá-lo ao gerenciamento de tarefas. DRY simplesmente diz que você deve ter apenas uma representação autorizada de informações. Os gerentes de projeto devem estar adotando isso, pois significa que todos saberão para onde buscar as informações, a comunicação de mudanças será fácil e as mudanças poderão ser controladas e gerenciadas bem. O DRY, através de peças reutilizáveis, ajuda a manter baixos os custos a longo prazo, ajuda a manter cronogramas a longo prazo e a melhorar a qualidade - três peças para o Triângulo de Gerenciamento de Projetos . É preciso haver algum investimento de tempo e dinheiro gasto para efetivamente tornar as coisas SECA, mas o trabalho do gerente de projeto é compensar tempo, custo, cronograma e qualidade.
fonte
Escrever novo código é apenas uma pequena parte da tarefa
Sua sugestão facilitaria a estimativa da parte da escrita inicial do novo código. No entanto, para realmente trazer algo novo (não importa se é um sistema totalmente novo, uma adição de recurso ou uma alteração de funcionalidade), isso não é suficiente e é apenas uma minoria de trabalho - as estimativas vistas na literatura dizem que, na prática, parte é algo como 20% -40% do trabalho total.
Portanto, a maior parte do trabalho (que inclui a adaptação do seu desenvolvimento inicial ao que realmente era necessário, integração, teste, reescrita e re-teste) não fica mais fácil de estimar; ao contrário, evitar intencionalmente o DRY apenas tornou essa parte muito maior, mais difícil e com estimativas mais variáveis - esse bug ou necessidade de mudança que requer a alteração de todas as partes clonadas pode não acontecer, mas se acontecer, suas estimativas vai estar totalmente errado.
Você não obtém melhores estimativas melhorando sua qualidade de estimativa de uma pequena parte do trabalho, mas piorando em grande parte do trabalho; portanto, não é realmente uma troca, mas uma situação de perda e perda em que você obtém uma produtividade pior, mas também estimativas piores.
fonte
O DRY é útil, mas também é superestimado. Algumas pessoas podem levar isso muito longe. O que muitos desenvolvedores não conseguem perceber é que sempre que você implementa o DRY para usar o mesmo método para duas finalidades (ligeiramente) diferentes, você está introduzindo um tipo de acoplamento muito rígido entre os diferentes usos. Agora, toda vez que você altera o código para o primeiro caso de uso, também é necessário verificar se ele regride o segundo caso de uso. Se esses são casos de uso amplamente independentes, é muito questionável se eles devem ser fortemente acoplados - provavelmente não deveriam ser.
O uso excessivo de DRY também pode levar a métodos de Deus que explodem em complexidade para lidar com todos os diferentes casos de uso em que são colocados, quando métodos atômicos geralmente menores que replicam algum código seriam muito mais sustentáveis.
No entanto, eu sugeriria que a pergunta não é realmente relevante no nível de gerenciamento de projetos. Um gerente de projeto realmente não vai querer se preocupar com esse nível de detalhe da implementação. Se são, provavelmente é microgerenciamento. Realmente ... como as coisas são implementadas é mais responsabilidade do desenvolvedor e líder técnico. O gerenciamento de projetos está mais preocupado com o que é feito e quando .
EDIT: por comentário, eu concordo no entanto que, na medida em que facilita a estimativa do tempo de desenvolvimento, evitar o DRY às vezes pode reduzir a quantidade de incerteza. Mas acredito que essa é uma questão insignificante em relação às questões mais prementes de (1) quanto tempo até que os requisitos de negócios sejam atendidos, (2) qual dívida técnica é levada em conta no processo e (3) riscos para o custo total de a propriedade das escolhas arquitetônicas feitas - ficar seco ou não em muitos casos é uma escolha de design que deve se basear mais em risco / recompensa a esses fatores do que em tornar um pouco mais fácil fornecer aos gerentes de projeto informações mais precisas .
fonte
Eu acho que você está entendendo mal DRY.
Vamos usar um exemplo:
vs.
Substituindo a classe B por C, seguimos o princípio DRY e reduzimos a duplicação de código. Mas não aumentamos as incógnitas ou os riscos para o projeto (a menos que você nunca tenha herdado antes).
Acho que o que você quer dizer quando fala sobre DRY é algo mais parecido com uma tarefa de design. Ou seja:
!!! Nova exigência! Alguns clientes precisam ser capazes de multiplicar duplos !!
vs.
Aqui (supondo que funcione), projetamos uma solução que pode lidar tanto com o antigo quanto com o novo requisito, essencialmente tentando criar um modelo matemático do problema da vida real ou das regras de negócios. Na vida real, o sistema que estamos modelando será obviamente muito mais complicado, nosso modelo não se encaixará exatamente e os casos extremos e resultados inesperados levarão tempo para encontrar e corrigir.
Então, devemos usar a versão B ou A 2 neste caso?
B será mais específico para a alteração real solicitada com menos efeitos colaterais e será mais fácil de estimar e mais rápido.
Uma versão 2 resultará em menos código geral no futuro e será a solução mais elegante
Mais uma vez, vou dizer que tudo se resume à qualidade da especificação e dos requisitos.
Se tivermos especificações muito claras que abrangem os casos extremos e a compatibilidade com versões anteriores, podemos ter certeza de que entendemos o sistema suficientemente bem para refatorar o modelo sem produzir bugs.
Se tivermos uma solicitação de emergência para um único cliente, onde o único requisito é que o comportamento mude para esse cliente sem considerar o sistema geral; depois 'aperfeiçoar' o modelo refatorando A traz um risco substancial. Tanto para quebrar outros clientes quanto para ultrapassar o prazo devido ao tempo extra desconhecido necessário para projetar e testar a solução.
fonte
Parágrafo por parágrafo
Corrigir.
Tarefas repetitivas devem ser automatizadas, obrigatórias . Eles são chatos, propensos a erros, quando feitos à mão.
Eu acho que você pode mudar a palavra "adaptação" com "configuração". Considere que você tem um bug neste pedaço de código que deve ser copiado. Um erro que aparece sob condições específicas. Se não estiver corrigido na fonte original e for copiado, haverá muitos locais a serem corrigidos. Isso pode ser ruim, mas alguém precisa:
A remoção de duplicações leva ao ponto único de falha. Se algo falhar, você pode ter certeza de onde isso acontece. Os padrões SOLID e Design estão lá para ajudar a corrigir exatamente esse problema. Prazos muito curtos tendem a provocar um estilo processual de "codificação". Mais tempo investido em um projeto para criar algo reutilizável significa que deve haver uma quantidade mínima de tempo gasto no próximo projeto em que o recurso será reutilizado, mas deve ser configurável em primeiro lugar.
Muitas pessoas apontaram que não há dilema aqui. Sim e não.
Se você tem algo altamente experimental que nunca foi feito antes - não há dilema. Caso contrário, se você precisar fazer algo novamente, como o novo sistema de reservas, você já possui abstrações, depende apenas do que você precisa.
Eu acho que o dilema é - devemos implementar algo em um recurso, se é improvável que seja solicitado. Implemente algo quando solicitado. Ninguém precisa de uma infraestrutura enorme que não será usada.
fonte
É absolutamente sobre design. Talvez não reutilize por si só, mas mesmo assim projete.
Experiência e seu ambiente / situação existente. Para um determinado problema, você terá uma forte noção do Princípio do Prado ao tentar obter maiores graus de SECA. Então, de repente, as considerações de gerenciamento vêm à tona. Tempo, objetivos, cliente, gerenciamento de código de longo prazo (alguém disse dívida técnica ) etc. informarão seu plano de ataque.
Uh ... design? Refatorar é design, bem deveria ser. O escopo do DRYing pode se expandir facilmente como uma super nova do loop, para o método, para as classes. Estive lá, fiz isso. Mas você realmente não pode saber até estudar o problema - isso é design.
Como não pode ser um problema de design? Você deve considerar o problema mais amplamente do que o código duplicado imediato em questão. Esta é uma atividade de design, seja um código existente ou uma folha em branco; seja "método de extração" ou criando novas classes e módulos.
Epílogo
Gerenciamento típico, ignorando o tempo de design. Idealmente, teríamos projetado a repetitividade supérflua redundante antes da codificação. Em vez disso, a gerência pensa que o desenvolvimento (e correções de bugs) é um único evento olímpico - codificação - quando na verdade é um decatlo. E medem 1/1000 de segundo porque pensam que é tudo analógico.
Eu tive essa experiência: "Passei dois dias escrevendo esta linha (de um formulário da GUI) e duas horas escrevendo o restante do formulário". Quero dizer que dediquei tempo para identificar classes reutilizáveis - DRY sendo um efeito colateral natural - a linha de formulário da GUI e com algumas outras. Uma vez depurados, eles eram usados, individualmente e em composição, em todo o formulário que agora codificava muito rápido e o teste era excepcionalmente rápido, apesar da complexidade da construção. E também passou por testes formais com uma taxa de erros incrivelmente baixa.
Eu também não sabia, mas acreditava que o esforço inicial de design valeria a pena. Todos dizemos isso, mas a gerência em particular não confia. A gerência pensaria que eu estava brincando. "Dois dias e você nem tem 2% do código ainda!"
Em um caso, mantivemos o controle quando a administração disse "você está gastando muito tempo em design, vá em frente". E colegas de trabalho dizendo "são muitas aulas". Bem, um subprojeto muito menos complexo deveria levar cerca de 1 mês (eu pensei que era bom palpite), mas levou 5 meses. Três meses disso foram testados / corrigidos porque era um POS. "Mas não tivemos tempo para projetar!". Eles realmente disseram isso.
Mostre à gerência como ela funciona. Capture alguns dados. Compare com outro trabalho, especialmente o de seus colegas de trabalho que fazem o trabalho rápido e rápido. Essa pilha de falhas sempre parece perder a corrida, ficando paralisada nos testes e depois do lançamento, repetidas vezes para corrigir mais bugs.
fonte