Quando a complexidade deve ser removida?


14

Introduzir prematuramente a complexidade implementando padrões de design antes que eles sejam necessários não é uma boa prática.

Mas se você seguir todos (ou até a maioria dos) princípios do SOLID e usar padrões de design comuns, introduzirá alguma complexidade à medida que os recursos e requisitos forem adicionados ou alterados para manter seu design tão fácil de manter e flexível quanto necessário.

No entanto, quando essa complexidade é introduzida e funciona como um campeão, quando você a remove?

Exemplo. Eu tenho um aplicativo escrito para um cliente. Quando originalmente criado lá, onde várias maneiras de dar aumentos aos funcionários. Usei o padrão de estratégia e a fábrica para manter todo o processo agradável e limpo. Com o tempo, certos métodos de aumento foram adicionados ou removidos pelo proprietário do aplicativo.

O tempo passa e o novo proprietário assume o controle. Este novo dono é um nariz duro, mantém tudo simples e só tem uma maneira única de dar um aumento.

A complexidade necessária para o padrão de estratégia não é mais necessária. Se eu codificasse isso a partir dos requisitos como estão agora, não introduziria essa complexidade extra (mas certifique-se de poder introduzi-lo com pouco ou nenhum trabalho, se necessário).

Então, removo a implementação da estratégia agora? Eu não acho que esse novo proprietário jamais mude como os aumentos são feitos. Mas o próprio aplicativo demonstrou que isso poderia acontecer.

É claro que este é apenas um exemplo em um aplicativo em que um novo proprietário assume e simplificou muitos processos. Eu poderia remover dezenas de classes, interfaces e fábricas e tornar todo o aplicativo muito mais simples. Observe que a implementação atual funciona muito bem e o proprietário está feliz com ela (e surpreso e ainda mais feliz por eu poder implementar suas alterações tão rapidamente devido à complexidade discutida).

Admito que uma pequena parte dessa dúvida é porque é altamente provável que o novo proprietário não me use mais. Realmente não me importo que outra pessoa assuma o controle, uma vez que não foi um grande gerador de renda.

Mas eu me importo com duas coisas (relacionadas)

  1. Preocupo-me um pouco com o fato de o novo mantenedor ter que pensar um pouco mais ao tentar entender o código. Complexidade é complexidade e não quero irritar o psicopata maníaco que vem atrás de mim.

  2. Mas ainda mais me preocupo com um concorrente vendo essa complexidade e pensando que apenas implemento padrões de design para manter minhas horas de trabalho. Então espalhei esse boato para ferir meu outro negócio. (Eu ouvi isso mencionado.)

Então...

Em geral, a complexidade necessária anteriormente deve ser removida, mesmo que funcione e haja uma necessidade historicamente demonstrada da complexidade, mas você não tem indicação de que será necessária no futuro?

Mesmo que a pergunta acima seja geralmente respondida "não", é aconselhável remover essa complexidade "desnecessária" se entregar o projeto a um concorrente (ou estranho)?

Respostas:


7

De certa forma, acho que essa é basicamente uma decisão de negócios e não necessariamente baseada no próprio código. Algumas coisas a considerar:

  • Você está sendo pago para fazer as alterações?
  • O código atualmente funciona como esperado?
  • Há algum problema de segurança ou desempenho com o código como está?
  • O montante da dívida técnica supera o custo de corrigi-la?
  • O que é realista de acontecer se você deixar o código como está?
  • Quais são os problemas futuros que podem surgir com ou sem uma refatoração?
  • Quanto de uma responsabilidade é o código para você e sua empresa?

Você está na melhor posição para responder a essas perguntas. No entanto, com base na sua descrição, não sei se me incomodaria em refatorar e simplificar as coisas, pois não parece que valerá a pena. Se atualmente funcionar, o cliente fica satisfeito e você não gosta de ser pago por atualizar tudo, deixe estar e trabalhe em uma atividade geradora de receita.

Em resumo, faça uma análise de custo-benefício e uma avaliação de risco dos dois caminhos e tome o curso de ação mais seguro, mais eficiente e mais lucrativo.


6

Não está removendo esse código e substituindo-o por algo simples para facilitar a codificação futura de um recurso que o cliente precisa considerar e pagar?

Você pode ter algo útil que outro desenvolvedor possa aprender, mas as chances de encontrar o aplicativo de outro cliente para conectá-lo não são prováveis.

Fofocar sobre o código do concorrente não é algo que você possa impedir. Eles parecerão tolos tentando recrutar negativamente clientes.


+1 para "e pague". Se você solicitar ao cliente que pague pela alteração, permita que ele decida se deseja fazer a alteração. Observe que deixar o sistema flexível adiciona uma certa quantia ao valor de revenda da empresa, pois permitirá que o PRÓXIMO proprietário faça as alterações com mais facilidade.
John R. Strohm

3

Um ditado comum é: "Se não está quebrado, não conserte".

Existem vários fundamentos por trás dessa regra. Alguns deles podem ser que a "simplificação" arrisca a introdução de novos bugs, diferentes e possivelmente maiores, pode levar uma quantidade crescente de tempo de desenvolvimento para longe de outros empreendimentos mais valiosos e pode ser completamente a mudança errada para alguma oportunidade de negócios futura inesperada que surge.

Se houver um valor comercial suficiente para esse código ser portátil e mais sustentável, decida se esse valor é realmente suficiente para considerar o código atual "quebrado". Pode ser que, se houver uma grande expansão de negócios planejada, ou você suspeite de um bug latente oculto na complexidade que poderia prejudicar os negócios.


2

Primeiro, se o aplicativo já foi assumido por um novo proprietário, isso pode acontecer novamente. E o próximo proprietário pode novamente começar a usar essa complexidade que não é beneficiada no momento.

Além disso, alterações não triviais no código de trabalho sempre envolvem um risco, portanto (como outros observaram) o cliente deve concordar com (e pagar) por eles. Se a complexidade "extra" atual não causar nenhuma desvantagem perceptível e mensurável (como problemas de desempenho), não há motivos fortes para removê-la.

Os clientes (potenciais) que (não) o contratam com base apenas nos boatos dos concorrentes não valem a pena ter de qualquer maneira, a menos que você esteja precisando desesperadamente de renda. Você tem razões boas e lógicas para implementar o aplicativo da maneira como implementou e qualquer cliente sério provavelmente entenderá isso. Alguém que não o faz - ou nem se incomoda em perguntar a você - provavelmente causará mais problemas ao longo do caminho do que vale a pena o trabalho.


1

Em geral, a complexidade necessária anteriormente deve ser removida, mesmo que funcione e haja uma necessidade historicamente demonstrada da complexidade, mas você não tem indicação de que será necessária no futuro?

Não.

Mesmo que a pergunta acima seja geralmente respondida "não", é aconselhável remover essa complexidade "desnecessária" se entregar o projeto a um concorrente (ou estranho)

Não. Por que desperdiçar seu tempo para corrigir a prioridade baixa funciona assim? Nenhum dano para o código ficar lá.

Quanto à sua pergunta: quando a complexidade deve ser removida?

Minha opinião é que, se não estiver quebrado, não conserte .


0

Para poder remover a complexidade, o seguinte deve ser verdadeiro:

  1. A peça removida deve ser independente do programa. Se houver alguma dependência do programa circundante para o código em questão, apenas remover a complexidade não funcionará.
  2. Infelizmente, se parecer com complexidade, é muito provável que as peças não sejam independentes e as dependências quebrem seu programa quando você as remover.
  3. A remoção de todas as dependências levará tempo, portanto, esse tempo precisará ser considerado quando você estimar se a operação vale o esforço
  4. Na maioria das vezes, não vale a pena, mas você decide não fazer nenhum código novo usar o antigo

Eles são independentes e eu os removi e os testes de unidade / integração / regressão foram aprovados. A complexidade é simplesmente uma implementação da Estratégia requer pelo menos uma interface e uma implementação concreta dessa interface. Nas duas dezenas de lugares em que o novo proprietário simplificou tudo isso, isso poderia ser feito com uma única classe.
ElGringoGrande

0

Eu acho que há algo maior em ação aqui ... Escalabilidade

O que você está falando é chamado de escalabilidade . Não importa se o código é complexo, importa se o aplicativo pode evoluir com base em novas regras de negócios ou regras de negócios alteradas. O que acontece se o próximo proprietário quiser algo totalmente diferente.

Então, digo manter o código e documentá-lo. É uma característica de como o aplicativo pode ser utilizado.


0

Em geral, a complexidade necessária anteriormente deve ser removida, mesmo que funcione e haja uma necessidade historicamente demonstrada da complexidade, mas você não tem indicação de que será necessária no futuro?

Há um esforço e risco para remover a complexidade. Se isso for maior do que o esforço adicional e o risco de manter o código excessivamente complexo, mantenha-o. Caso contrário, você o remove. É difícil estimar esses riscos, no entanto.

Eu acrescentaria que você pode reduzir o risco de manutenção mais difícil documentando por que você usou o padrão de design Strategy em primeiro lugar, no código. Pessoalmente, acredito que qualquer padrão de design deve ser rastreável a um requisito explícito (funcional ou não funcional).

Mesmo que a pergunta acima seja geralmente respondida "não", é aconselhável remover essa complexidade "desnecessária" se entregar o projeto a um concorrente (ou estranho)?

Seu cenário de ser criticado pela concorrência por horas de preenchimento é precisamente o motivo pelo qual você deve documentar a complexidade. Se você documentar e justificar (com um requisito específico do cliente) o uso de qualquer padrão, estará coberto. Se você não pode justificar um padrão com os requisitos de um cliente, parece um excesso de design ou padronização.

Se os requisitos forem alterados, você poderá justificá-lo, devido ao risco de poder quebrar o código (ou a quantidade de trabalho para remover cirurgicamente o padrão).


Eu acho que é bom distinguir entre complexidade acidental e complexidade essencial , já que os padrões geralmente envolvem ambos.

Ou seja, seu requisito para suportar algoritmos variados para decidir aumentos é uma complexidade essencial (parte do problema a ser resolvido). A manutenção do seu código é facilitada pelo padrão Estratégia, mas a alternativa codificada se / então à Estratégia ainda funcionará. Fiz exercícios nos meus cursos de mestrado, onde os alunos encontram oportunidades de aplicar a Estratégia em projetos de código aberto. A complexidade não é necessariamente melhor / pior ao aplicar a Estratégia (porque é uma complexidade essencial ). Às vezes, pode ser ainda mais difícil entender a estratégia, porque o código é dividido em várias classes com polimorfismo, em vez de um grande bloco if / then / else.

Idealmente, um padrão funciona quando os benefícios que ele supera o custo de suas desvantagens. Novamente, quantificar essas coisas é difícil. Freqüentemente, um padrão deixa o desenvolvedor feliz (não apenas porque facilita a adição de uma nova estratégia de aumento, mas também faz com que o desenvolvedor fique empolgado ao saber que um padrão foi aplicado). É difícil mostrar aos clientes como os beneficia.

O cliente não se importa ou mesmo entende os detalhes. No caso do novo proprietário aplicando o KISS em seus processos, é ela reduzindo a complexidade essencial , o que também deve ter um impacto na solução de software.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.