Feed Artigos Comentários


Agile &Desenvolvimento &TI André Dourado em 22 dez 2008

O design está morto? (Tradução por Bruno Pedroso)

Por Bruno Pedroso
5 de Outubro de 2008

Começo com esse post a tradução de um dos melhores artigos que conheço a respeito de design ágil de software: “Is design dead?” do Martin Fowler.

Vou traduzir o texto em vários posts, para preservar um pouco do meu tempo, e pra adaptar o discurso longo a um formato mais curto, mais apropriado ao blog.

Para os que já conhecem, é uma ótima oportunidade para recordar. Pra quem nunca leu, meu conselho é que corra logo e leia a versão em inglês no blog do autor (que com certeza é bem melhor que a minha tradução).

Mas se ainda não mexi com sua curiosidade o bastante para vencer a preguiça, acompanhe a série de posts que farei aqui, ou espere até o final da tradução e confira o texto completo, que será publicado junto às outras traduções.

Se por acaso alguém achar que a tradução não ficou boa, e quiser deixar alguma sugestão, será muito bem vinda nos comentários.

Vamos à seção que introduz o artigo, apresentando sua questão central.

(apenas a titulo de registro, estou traduzindo a versão de maio de 2004)

O design está morto?

Para muitos que têm seu primeiro contato com Extreme Programming, parece que XP prevê a morte do design de software. Não somente a maioria das atividades de design é ridicularizada como “Big Design Up Front”, mas ainda técnicas como UML, frameworks flexíveis, e até mesmo design patterns são pouco enfatizadas ou totalmente ignoradas. Na verdade XP envolve muito design, mas o faz de um modo diferente dos processos de software estabelecidos. XP rejuveneceu a noção de design evolutivo com práticas que tornam a evolução uma estratégia de design viável. Ela também apresenta novos desafios e habilidades já que os designers precisam aprender como fazer um design simples, como usar refactoring para manter um design limpo, e com usar patterns em um estilo evolucionário.

(Esse artigo foi escrito para minha apresentação na conferência XP 2000 e sua forma original foi publicada como parte dos anais.)

* Design planejado e evolucionário
* As práticas habilitadoras de XP
* O valor da simplicidade
* O que diabos é simplicidade, afinal
* Refatoração viola YAGNI?
* Patterns e XP
* Cultivando uma arquitetura
* UML e XP
* Sobre metáforas
* Você quer ser um arquiteto quando crescer?
* Reversibilidade
* A vontade de projetar
* Coisas que são difíceis de refatorar
* O design está ocorrendo?
* Então o design morreu?
* Créditos
* Histórico de revisões

Extreme Programming (XP) desafia muitas das suposições sobre desenvolvimento de software. Uma das mais controvérsas é sua rejeição a esforços significativos em design prévio, em favor de uma abordagem mais evolucionária. Para seus criticos isso é um retorno ao desenvolvimento “code and fix” – normalmente conhecido como hackear. Para seus fãs é frequentemente visto como uma rejeição das técnicas de design (como a UML), princípios e padrões. Não se preocupe com design, se você escutar o seu código um bom design surgirá.

Eu me encontro no centro desse argumento. Grande parte da minha carreira envolveu linguagens gráficas de design – a linguagem de modelagem unificada (UML) e seus precursores – e padrões de projeto. Eu escrevi livros sobre ambos: UML e patterns. O meu envolvimento com XP significa minha renúncia ao que escrevi sobre esses assuntos, livrando minha mente de todos esses conceitos contra-revolucionários?

Bem, não vou conseguir mantê-los nesse suspense. A resposta curta é não. A resposta longa é o resto desse artigo.

Design planejado e evolucionário

Nesse artigo vou descrever dois estilos como design é feito em desenvolvimento de software. Talvez o mais comum seja design evolucionário. Essencialmente design evolucionário significa que o design do sistema cresce à medida em que o sistema é implementado. Design é parte do processo de programação e à medida em que o programa evolui o design muda.

Em seu uso comum, design evolucionário é um desastre. O design acaba virando a agregação de um monte de decisões táticas ad-hoc, onde cada uma delas torna o código mais difícil de alterar. Em muitos sentidos, você poderia argumentar que isso é ausência de design, é claro que normalmente isso leva a um design pobre. Como Kent costuma dizer, o design existe para possibilitar que você continue mudando o software facilmente no longo prazo. Quando o design deteriora, vai junto sua habilidade de fazer mudanças efetivamente. Chega-se ao estado de entropia de software, ao longo do tempo o design torna-se pior e pior. Isso não apenas torna o software mais difícil de mudar, mas também torna os bugs mais fáceis de se reproduzirem e mais difíceis de achar e matar de forma segura. Esse é o pessadelo do “code and fix”, onde os bugs se tornam exponencialmente mais caros de corrigir à medida em que o projeto evolui.

Design planejado é um remédio para isso, e contém uma noção nascida em outros ramos da engenharia. Se você quer construir uma casinha de cachorro, basta pegar um pouco de madeira e construir uma forma rude. Todavia, se você quer construir um arranhacéus, você não pode trabalhar assim – ele vai simplesmente desabar antes que se chegue na metade. Então você começa com desenhos de engenharia, feito em um escritório de engenharia como aquel em que minha esposa trabalha no centro de Boston. Enquanto ela faz o design ela considera todos os detalhes, parcialmente por meio de análises matemáticas, mas principalmente usando códigos de construção. Códigos de construção são regras sobre como desenhar estruturas baseado em experiência do que funciona (e alguma matemática subjacente). Uma vez que o design está pronto, então a companhia de engenharia dela pode passar o design para outra empresa construir.

Design planejado em software deveria funcionar da mesma forma. Designers pensam as grandes questões antecipadamente. Eles não precisam escrever software porque não estão construindo o software, eles estão projetando. Então eles podem usar técnicas de design como UML que deixam de fora alguns detalhes de programação e permitem que os designers trabalhem em um nível mais abstrato. Uma vez pronto o design, eles podem passá-lo para um outro grupo (ou até outra empresa) para construir. Já que os designers estão pensando em larga escala, eles podem evitar toda a série de decisões táticas que levam à entropia de software. Os programadores podem seguir as diretrizes do design e, uma vez que sigam o design, chegar a um sistema bem feito.

Então a abordagem do design planejado vem sendo usada desde a década de 70, e um monte de gente a usou. Ela é melhor em muitos sentidos que o design evolucionário “code and fix”. Mas ela tem algumas falhas. A primeira é que é impossível pensar em todos os detalhes com que se precisa lidar na hora de programar. Então é inevitável que na hora de programar você encontre coisas que questionem o design. Entretanto, se os designers já tiverem terminado e se engajado em outro projeto, o que acontece? Os programadores começam a codificar por fora do design e a entropia se estabelece. Mesmo se o designer não tiver ido embora, leva tempo para organizar as questões de design, e então mudar o código. Normalmente faz-se um conserto mais rápido pela pressão. Entropia (de novo).

Ademais, há normalmente um problema cultural. Designers se fazem designers pela habilidade e experiência, mas eles estão tão ocupados trabalhando nos designs que não têm mais tanto tempo para codificar. No entanto, as ferramentas e materiais de desenvolvimento de software mudam rapidamente. Quando você não programa mais, não apenas fica defasado com o fluxo tecnológico, mas também perde o respeito daqueles que programam.

Essa tensão entre os construtores e designers acontece na construção civil também, mas é mais intensa em software. Isso porque existe uma diferença chave. Em construção civil existe uma divisão clara entre aqueles que projetam e aqueles que constróem, mas em software não é bem assim. Qualquer programador trabalhando em ambientes de alto design precisam ser muito habilidosos. O bstante para questionar as decisões de design, especialmente quando o designer conhece menos sobre a realidade do dia a dia e a plataforma de desenvolvimento.

Agora veja, esses problemas podem ser corrigidos. Talvez consigamos lidar com a tensão humana. Talvez consigamos designers habilidosos o bastante para lidar com a maioria dos problemas e tenhamos um processo disciplinado o suficiente para mudar os desenhos. Há ainda outro problema: mudanças de requisitos. Mudanças de requisitos são a causa número das enxaquecas nos projetos de software.

Uma forma de lidar com mudanças de requisitos é embutir flexibilidade no design de modo que se possa mudá-lo facilmente à medida que os requisitos mudam. No entanto isso requer insight sobre que tipos de mudanças se espera. Um design pode ser planejado para lidaar com áreas de volatilidade, mas enquanto isso pode ajudar para as mudanças previstas, não pode ajudar (e pode atrapalhar) as mudanças imprevistas. Então é preciso entender os requisitos suficientemente bem para separar as áreas voláteis, e a minha experiência é que isso é muito difícil.

Alguns desses problemas de requisitos são causados por não entender os requisitos de forma clara o suficiente. Então um monte de gente se foca em processos de engenharia de requisitos para obter requisitos melhores, na esperança que isso previna a necessidade de mudar o design depois. Mas até esse caminho pode não levar a uma cura. Muitas mudanças de requisitos imprevistas ocorrem devido a mudanças no negócio. Essa não podem ser evitada, por mais cuidadoso que seja o seu processo de engenharia de requisitos.

Tudo isso portanto faz o design planejado parecer impossível. Certamente esses são grandes desafios. Mas não estou convencido de que o design planejado é pior que o design evolucionário, da forma como é normalmente praticado de maneira “code and fix”. Então eu prefiro design planejado a “code and fix”. No entanto, estou ciente dos problemas do design planejado e estou procurando um novo caminho.

As práticas habilitadoras de XP

XP é controversa em muitos sentidos, mas uma das bandeiras vermelhas em XP é que ela advoga design evolutivo ao invés de design planejado. Como sabemos, design evolutivo não pode funcionar devido ás decisões ad hoc e à entropia de software.

Na raiz do entendimento desse argumento está a curva de mudanças do software. A curva de mudanças diz que, à medida que o projeto decorre, torna-se exponencialmente mais caro fazer mudanças. A curva de mudanças é normalmente expressa em termos de fases “uma mudança feita durante a análise por $1 custaria milhares para consertar em produção”. É irônico que a maioria dos projetos ainda trabalhe em um processo ad-hoc que não possui uma fase de análise, mas a exponenciação ainda está lá. A curva de mudanças exponencial significa que o design evolutivo não pode funcionar. Também indica o motivo pelo qual o design planejado precisa ser feito cuidadosamente, porque qualquer erro no design se depara com a mesma exponenciação.


Curva de Mudanças de Kent Beck

A premissa fundamental a respeito de XP é que é possível nivelar a curva o suficiente para fazer o design evolutivo funcionar. Esse nivelamento é tanto habilitado por XP como explorado por XP. Isso é parte do acoplamento existente entre as práticas de XP: especificamente não se pode fazer aquelas partes de XP que exploram a curva nivelada sem fazer aquelas que habilitam o nivelamento. Essa é uma fonte comum de controvérsia sobre XP. Muitas pessoas criticam a exploração sem entender a habilitação. Frequentemente as críticas surgem da própria experiência dos críticos onde não usaram as práticas habilitadoras que permitam que as praticas exploradoras funcionem. O resultado é que eles se queimam e quando vêem XP eles lembram das chamas.

Existem muitas partes para as práticas habilitadoras. No centro estão as práticas de Testes e Integração Contínua. Sem a segurança provida pelos testes, o resto de XP seria impossível. Integração contínua é necessária para manter a equipe em sincronia, de modo que se possa fazer mudanças sem aborrecimentos para integra-la com os outros. Juntas essas práticas podem ter um grande efeito na curva de mudanças. Me recordei disso mais uma vez aqui na ThoughtWorks. Introduzir testes e integração contínua trouxe melhoras significativas no esforço de desenvolvimento. Certamente o suficiente para questionar a assertiva de XP de que você precisa de todas as práticas para obter uma grande melhoria.


Curva de Mudanças para o Desenvolvimento Ágil

Refactoring possui um efeito similar. Pessoas que refatoram seu código da forma disciplinada sugerida pela XP vêem uma diferença significativa em sua efetividade compara a fazer reestruturações de forma mais frouxa e ad hoc. Essa foi minha experiência quando Kent me ensinou a refatorar corretamente. Afinal, apenas uma mudança forte me motivaria a escrever um livro completo sobre isso.

Jim Highsmith, em seu excelente resumo sobre XP, usa a analogia de um conjunto de escalas. Em uma bandeja está o design planejado, na outra refactoring. Em abordagens mais tradicionais o design planejado domina porque a premissa é que não se pode mudar de idéias depois. À medida em que o custo das mudanças diminui, você passa a poder fazer a maioria do seu design mais tarde como refactoring. O design planejado não some completamente, mas agora existe uma balança de duas abordagens de design para se trabalhar. Pra mim, é como se antes do refactoring eu estivesse fazendo todo o meu design com uma mão só.

Essas práticas habilitadoras de integração contínua, testes e refactoring provêem um novo ambiente que torna plausivel o design evolutivo. Entretanto, uma coisa que ainda não conseguimos visualizar é para onde a balança deve apontar. Tenho certeza de que, tirando a impressão de quem está de fora, XP não é apenas testa, codifica, e refatora. Existe espaco para projetar antes da codificação. Parte dele se faz antes de se existir qualquer código, a maioria ocorre nas iterações antes de codificar uma tarefa em particular. Mas existe uma nova balança entre o design up-front e o refactoring.

O valor da simplicidade

Dois dos maiores gritos de guerra em XP são os slogans “faça a coisa mais simples que poderia possivelmente funcionar”, e “você não vai precisar disso” (conhecido como YAGNI – “You Aren´t Going to Need It”). Ambos são manifestações da prática XP chamada Design Simples.

O modo como YAGNI é normalmente descrita diz que você não deveria adicionar nenhum código hoje que será usado apenas por funcionalidades que serão necessárias amanhã. Diante disso, parece simples. O problema surge com coisas como frameworks, componentes reusáveis, e design flexível. Essas coisas são complicadas de construir. Você paga um custo extra antecipado para construi-los, na esperança de receber de volta mais tarde. Essa idéia de construir flexibilidade antecipadamente é vista como uma parte chave do design de software efetivo.

Todavia, o conselho de XP é que você não construa componentes e frameworks flexíveis para o primeiro caso que necessite deles. Deixe essas estruturas crescerem à medida em que são necessárias. Se preciso hoje de uma classe Dinheiro que trate adição, mas não multiplicação, então eu construo apenas a adição na classe Dinheiro. Mesmo que eu tenha certeza de que vou precisar da multiplicação na iteração seguinte, saiba como fazê-la facilmente, e pense que será realmente rápido fazer, ainda assim vou deixá-la para a próxima iteração.

Uma razão para isso é econômica. Se eu tenho que fazer qualquer trabalho que somente será necessário amanhã, significa que eu perco o esforço das funcionalidades que precisam ser feitas nessa iteração. O plano da release diz o que precisa ser feito para essa iteração, trabalhar em outras coisas para o futuro é contrário ao acordo que os desenvolvedores tem com o cliente. Existe um risco de que as histórias dessa iteração possam não ser concluídas. Mesmo que as histórias dessa iteração não estejam em risco, é o cliente quem deve decidir qual trabalho extra deveria ser feito – e isso pode não incluir a multiplicação.

Esse des-incentivo é composto pela chance de que podemos não ter entendido a funcionalidade direito. Por mais certo que possamos estar sobre como essa funcionalidade deveria funcionar, podemos ainda assim estar errados – especialmente já que não temos os requisitos detalhados ainda. Trabalhar na solução errada cedo é um desperdício ainda maior do que trabalhar na solução certa cedo. E os XPerts normalmente acreditam que somos muito mais propensos a errar do que acertar (e eu concordo com esse sentimento.)

A segunda razão para o design simples é que um design complexo é mais difícil de entender que um design simples. Portanto qualquer modificação do sistema é feita com mais dificuldade pela complexidade adicionada. Isso adiciona um custo durante o período desde que o design mais complicado foi adicionado até quando ele foi necessário.

Agora, esse conselho parece totalmente sem sentido para um monte de gente, e eles estão certos por pensarem assim. Certos, dado que você imagine o mundo usual do desenvolvimento onde as práticas habilitadoras de XP não estão presentes. Entretanto quando, o balanço entre o design planejado e evolutivo é obtido, então YAGNI se torna uma boa prática (e somente então).

Portanto, para sumarizar. Você não quer desperdiçar esforço adicionando nova capacidade que não será usada até uma iteração futura. E mesmo se o custo for zero, você ainda assim não quer adiciona-la porque ela aumenta o custo de modificação, mesmo que não custe nada para colocá-la. Entretanto, você apenas pode se comportar assim quando você está usando XP, ou uma técnica similar que reduza o custo das mudanças.

O que diabos é a simplicidade, afinal ?

Então queremos que nosso código fique o mais simples possível. Não parece muito difícil argumentar a favor disso, afinal, quem quer ser complicado? Mas é claro que isso levanta a questão “O que é simples?”

No XPE Kent indica quatro critérios para um sistema ser simples. Em ordem (o mais importante primeiro):

* Executa todos os Testes
* Revela toda sua intenção
* Não há duplicação
* Menor número de classes e métodos

Executa todos os testes é um critério bastante simples. Sem duplicação é também bem direto, embora um monte de desenvolvedores precisem de orientação sobre como atingi-la. O mais estranho tem a ver com revelar a intenção. O quê exatamente isso significa?

O valor básico aqui é a clareza do código. XP atribui um alto valor ao código que é fácil de ler. Em XP “código claro” é um termo em abuso. O que é a intenção de uns revelando código é a clareza para outros.

Em seu artigo da XP 2000, Josh Kerievsky aponta um ótimo exemplo disso. Ele analisa possivelmente o código XP mais público de todos – JUnit. Junit usa decoradores para adicionar funcionalidades opcionais aos casos de teste, coisas como sincronização concorrente e código de setup de batch. Separar esse código em decoradores permite que o código genérico seja mas claro do que ele normalmente seria.

Mas você deve perguntar-se se o código resultante é realmente simples. Pra mim é, mas eu sou familiarizado ao padrão de decoradores. Mas para muitos que não são, é bastante complicado. Similarmente JUnit usa métodos plugáveis que, conforme notei, a maioria das pessoas iniciantes acha qualquer coisa, menos claro. Então devemos concluir que o design do JUnit é mais simples para designers experientes, mas mais complicado para pessoas menos experientes.

Eu acho que o foco na eliminação de duplicação, tanto do “Once and Only Once” do XP, como do DRY (Don’t repeat yourself) do Pragmatic Programmer, é uma daquelas óbvias e maravilhosamente poderosas peças de bom conselho. Apenas seguindo ela sozinha já pode te levar bem longe. Mas isso não é tudo, e simplicidade é ainda uma coisa complicada de encontrar.

Recentemente, estive envolvido fazendo algo que bem poderia ser over-designed. O código foi refatorado e certa flexibilidade foi removida. Mas, como um dos desenvolvedores disse, “é mais fácil refatorar código over-designed do que refatorar código sem design.” É melhor ser um pouco mais simples do que você precisa ser, mas não é um desastre ser um pouco mais complicado.

O melhor conselho que já ouvi sobre isso vem do Tio Bob (Robert Martin). Seu conselho era não ficar muito preocupado com o que é o design mais simples. Afinal você pode, deve e vai refatorar ele depois. No final a disposição para refatorar é muito mais importante que saber qual o design mais simples de primeira.

Refactoring viola YAGNI?

Esse tópico surgiu na lista de XP recentemente, e é importante discuti-lo já que estamos revendo o papel do design em XP.

Basicamente, a questão começa com o ponto que refactoring toma tempo mas não adiciona funcionalidade. Uma vez que o ponto em YAGNI é que deveria-se projetar para o presente, não para o futuro, isso é uma violação?

O ponto em YAGNI é que você não adiciona complexidade que não é necessária para as histórias atuais. Isso faz parte da prática do design simples. Refactoring é necessário para manter o design o mais simples possível, então você deve refatorar sempre que perceber que pode tornar as coisas mais simples.

Design simples tanto explora as práticas de XP como é também uma prática habilitadora. Apenas se você tiver teste, integração contínua e refactoring, é possível praticar design simples efetivamente. Mas, ao mesmo tempo, manter o design simples é essencial para manter a curva de mudanças estável. Qualquer complexidade desnecessária torna o sistema mais difícil de mudar em todas as direções, exceto naquela em que você antecipou com a flexibilidade complexa que colocou. No entanto, as pessoas não são boas em antecipar, então é melhor esforçar-se pela simplicidade. Mas não se consegue a coisa mais simples de primeira, então você precisa refatorar para chegar mais perto do objetivo.

Continua…

Fonte: eXPresso Capital

Post visualizado 994 vezes.

Um comentário para “O design está morto? (Tradução por Bruno Pedroso)”

  1. em 23 fev 2009 às 15:34 1.reversibilidade.net - blog.adsystems.com.br » O design está morto? (Tradução por Bruno … escreveu …

    [...] Extreme Programming (XP) desafia muitas das suposições sobre … Veja o post completo clicando aqui. Post indexado de: [...]

Trackback esse post | Subscreva os comentários pelo RSS Feed

Deixe um comentário