Compartilhar via


Este artigo foi traduzido por máquina.

Padrões na prática

Entrega incremental pelo design contínua

Jeremy Miller

Conteúdo

Entrega incremental dos recursos
Estrutura contínua
O último momento responsável
Reversibility
YAGNI e o Thing mais simples que pode funcionar possibly
Como nível modelagem antes codificação?
O que há à frente

No anteriores padrões em colunas de prática, você me concentrei principalmente em padrões"técnicos", mas neste artigo, abordarei o lado "prática" mais suave do design de software. O objetivo final de projetos de software é fornecer o valor para o cliente e minha experiência é que o design de software é um fator principal como uma equipe pode ministrar com êxito esse valor. Sobre o design, em design, ou apenas simples errado design impede um projeto. Um bom design permite que uma equipe para ser mais bem-sucedido em seus esforços.

Minha experiência é também que os designs melhores são um produto do design contínuo (também conhecido como design emergentes ou evolucionário) em vez do resultado de um esforço que tenta obter todo o design direito com antecedência. No design contínuo, você pode começar com um modicum do design prévio, mas você atrasar confirmar orientações técnicas, contanto que você pode. Essa abordagem permite que você se esforçar para aplicar as lições aprendidas com o projeto para melhorar continuamente o design, instead of se tornando bloqueado em um design errado desenvolvido muito cedo no projeto.

Além disso, acredito firmemente que a melhor maneira de criar valor comercial é por meio de entrega incremental de recursos de trabalho em vez de concentrando-se primeiro na criação de infra-estrutura. Neste artigo, explorarei incremental como entrega de trabalho permite que recursos um projeto de equipe para melhor oferecer valor comercial e como usar design contínuo pode ativar entrega incremental ser mais eficiente e ajudar a criar designs de software melhores.

Previsão versus design reativa

Em primeiro lugar, o que é design de software? Para muitas pessoas, software design significa "criar uma especificação de design antes de codificação inicia" ou "Fase de planejamento/elaboração". Eu gostaria de etapa longe processos formais e documentação intermediária e defina o design de software mais geralmente como "o ato de determinar como o código deve ser estruturado." Dito isso, nós agora imaginar design de software acontecendo em dois modos diferentes: previsão reativa (ou Refletivo se você preferir).

Previsão de projeto é o trabalho de design que fazer antes de codificação. Design de previsão é criação de modelos UML ou CRC, executar sessões de design com a equipe de desenvolvimento no início de iteração e escrever especificações de design. Reativo o design é ajustes feitas com base nos comentários durante ou após a codificação. Refatoração é reativa design. Cada equipe e até mesmo pessoas dentro de uma equipe têm preferências diferentes usando o design de previsão ou reativo. Design contínuo simplesmente coloca mais importância sobre o design reativa que processos de desenvolvimento de software tradicionais.

Entrega incremental dos recursos

Em 2002, meu empregador, em seguida, foi fazer experiências com o recém-minted Microsoft .NET Framework e tinha iniciado um projeto de avaliação usando ASP.NET 1.0. Juntamente com muitos outros, avidamente visto o projeto, esperando sucesso para que nós poderia iniciar usando essa nova estrutura interessante em projetos de nossos próprios. Seis meses depois que o projeto foi cancelado. A equipe certamente estava ocupada e por todos os accounts escrevi muito código, mas nenhum código foi adequado para produção.

A experiência da equipe desse projeto gera algumas lições importantes. A equipe escreveu primeiro uma especificação de design que aparentemente foi bastante completo e conformed aos padrões de nossa organização. Com este documento em mãos, a equipe de iniciado o projeto ao tentar criar a camada de acesso de dados inteira, e a camada de lógica comercial e finalmente a interface do usuário. Quando eles iniciado código as telas de interface do usuário, os desenvolvedores perceberam rapidamente que não o código de acesso a dados existente era exatamente o que eles necessários para criar a interface do usuário, mesmo que esse código conformed os documentos de design. Nesse ponto, gerenciamento de TI e os parceiros comerciais não ver qualquer valor que está sendo entregue pelo projeto e apresentou na toalha em favor de outras iniciativas.

Ironicamente, para mim a empresa pai foi e é um dos exemplos à esquerda do mundo de um fabricante enxuto ou just-in-time. A maioria dos nossos concorrentes usados "envio" fabricação, na qual grandes quantidades de partes são ordenadas para as linhas de fábrica com base na demanda prevista por algum período de tempo. Dificuldades de fabricação de envio são que perder dinheiro sempre que você solicitar mais partes que você pode usar; você precisará pagar extra para armazenar as ações de partes excedente antes que você está pronto para usá-los; e você é vulneráveis a insuficiência de parte no chão de fábrica sempre as previsões são erradas — e previsões são raramente precisas.

Por outro lado, meu empregador, em seguida, usado fabricação de "recepção". Várias vezes ao dia que os sistemas de fábrica agendada os pedidos de clientes eles necessários para criar em horas, próximas determinado as quantidades das partes eles necessário para concluir as ordens e, em seguida, ordenados para entrega imediata exatamente o número e tipo de partes necessário. As vantagens de fabricação de recepção são que por comprar somente o que é necessário, você perder muito menos dinheiro em partes que não pode ser usado; fábricas tem muito menos ações on hand parte para disputar com, fazer um pouco mais eficiente de fabricação; você pode se adaptar a circunstâncias novas e mercado força quando não estão vinculados por previsões feitas há; meses e previsões e estimativas são mais precisas quando feita pela curto prazo em vez de um termo mais rapidamente.

Então, como a recepção versus envio problema se aplica a desenvolvimento de software? O projeto com falha que descrevi anteriormente usado envio design tentando determinar primeiro todas as necessidades de base do sistema e, em seguida, tentando para criar a infra-estrutura de acesso de dados antes de escrever outros tipos de código. A equipe perdido muito esforço para criar, documentar e criação de código que nunca foi usado na produção.

Em vez disso, e se a equipe tinha liquidadas para escrever rapidamente uma especificação de alto nível com detalhes mínimo, prossegui para desenvolver a prioridade mais alta recurso a qualidade de pronto para produção, em seguida, o próximo recurso de prioridade mais alta e assim por diante. Nesse cenário, a equipe criaria somente código de infra-estrutura, como código de acesso de dados, que foi recebido por requisitos de recurso específico.

Pense nisso. O que é um resultado melhor para um projeto no final do seu cronograma agendado?

  1. 1.Clique apenas 50 % dos recursos propostos são completa, mas os recursos mais importantes da proposta de projeto inicial estão prontos para implantar para produção.
  2. 2.Clique a maioria das infra-estrutura de codificação estiver concluída, mas não recursos estão completamente utilizáveis e nada pode ser implantado em produção.

Em ambos os casos a equipe só é aproximadamente metade feito e nenhum resultado é realmente um sucesso em comparação comparado o plano inicial e a agenda. Mas que "failure" seria você em vez disso, explique aos seu chefe? Sei que meu chefe e nossa equipe de vendas preferem definitivamente o primeiro resultado com base na entrega incremental.

As vantagens de chaves de entrega incremental são:

  1. Trabalhando em prioridade de ordem de negócios. Criando incrementalmente pelo recurso dá uma chance melhor de concluir os recursos mais importantes para os negócios. Afinal, por que deve você gasta qualquer tempo qualquer projetar, desenvolver e teste um recurso "interessante ter" antes dos recursos "deve ter" são concluídos?
  2. Atenuação de riscos. Francamente, o maior risco na maioria dos projetos não técnico. O maior risco é que você não fornecer valor comercial ou você entregar o sistema errado. Além disso, a realidade severo é que os requisitos e análise do projeto fornecido apenas como provavelmente estar errado como seu código ou design. Ao demonstrar os recursos de trabalho para os parceiros comerciais logo no início do projeto, você pode obter comentários valiosos sobre os requisitos do seu projeto. Para minha equipe, demonstrações antecipadas a nossa equipe de gerente e vendas do produto foram inestimável para ajustar a usabilidade do nosso aplicativo.
  3. Primeira entrega. Recursos concluídos podem ser colocados em produção antes do restante do sistema para iniciar ganhando alguns retorno sobre o valor.
  4. Entrega flexível. Acredite ou não, os parceiros comerciais e seu gerente de produto, às vezes, alterados suas prioridades. Em vez de rangido de dentes no injustice dele todos os, você pode trabalhar de forma que pressupõe que as prioridades serão alterado. Ao amarrando o código de infra-estrutura para os recursos em execução, você reduz a probabilidade de esforço desperdiçado devido à alteração de prioridades.

Agora, para a desvantagem de entrega incremental: é difícil fazer. No exemplo a fabricação enxuto, recepção fabricação trabalhou apenas porque cadeia de suprimentos da empresa foi ultraefficient e era capaz de fábricas de ações com partes quase sob demanda. O mesmo se aplica para entrega incremental. Você deve ser capaz de criar os elementos dos novos recursos e manter a qualidade da estrutura de código alta o suficiente para que você não faça a criação de futuros recursos mais difícil rapidamente. O que você não tem tempo para fazer é passar semanas ou até mesmo meses por vez trabalhando estritamente em questões de arquiteturais — mas ainda existem essas preocupações de arquiteturais. Você precisará alterar a maneira como você projetar sistemas de software para ajustar o modelo incremental de entrega. É aí que design contínuo entra na imagem.

Estrutura contínua

Proponentes de desenvolvimento tradicional geralmente acreditam que projetos são mais bem-sucedidos quando o projeto pode ser completamente especificado com antecedência para reduzir o esforço desperdiçado em codificação e refazer. O aumento da programação Lean e ágil tem desafiados Noções tradicionais do tempo de design de software introduzindo um processo de design contínuo que ocorre através do ciclo do projeto. Design contínuo propositadamente atrasa compromissos para determinado designs, espalha-se mais trabalho de design sobre o ciclo de vida do projeto e recomenda uma equipe para desenvolver um design como o projeto porta aplicando as lições aprendidas com o código.

Pense dessa maneira. Eu simplesmente não desenvolver o projeto detalhado para um recurso até que é hora de criar esse recurso. Pode tentar criá-lo agora, mas esse trabalho de design não fornece qualquer benefícios até muito mais tarde — e o momento em que minha equipe obtém a esse recurso, estou probabilidade de entender mais sobre nossa arquitetura e o sistema e ser capaz de apresentar um design melhor que eu poderia ter no início do projeto.

Antes que qualquer outra, gostaria de dizer que design contínuo não implica que nenhum trabalho de design ocorre com antecedência. GostoEssa citação do Robert C. (Tio Paulo) Martin: " O objetivo é criar um design inicial pequeno mas capaz, em seguida, manter e evoluir esse design no decorrer do sistema ."

Antes de escrever desativar design contínuo como arriscado e propenso a erros, abordemos como fazer o design contínuo bem-sucedida (em outras palavras, vou tentar convencer que isso não é louco).

A importância de comentários

Muitos projetos são realmente simples, com requisitos de bem-compreendido e estritamente usam tecnologias conhecidas. Design prévio pode funcionar muito bem com esses projetos, mas minha experiência é o oposto. Quase todos os projeto que trabalhei em teve algum grau de novas, na tecnologia usada, as técnicas de desenvolvimento empregadas, ou nos requisitos. Nesses casos, acredito que a melhor maneira seja bem-sucedido é adotar uma atitude de humility e dúvida. Você nunca deve assumir que o que você está fazendo e pensando funciona até que você tenha algum tipo de comentários que verifica o código ou design.

Como design contínuo envolve a evolução da estrutura de código, é ainda mais importante ao usar essa abordagem para criar comentários rápido ciclos para detectar erros iniciais causados por alterações no código. Vamos o modelo de Extreme Programming (XP) do desenvolvimento como um exemplo. XP chama de uma abordagem altamente iterativa para o desenvolvimento permanece controverso. Quase como controverso é o fato que XP Especifica uma série de práticas que são um pouco difíceis aceitar para muitos desenvolvedores e lojas. Especificamente, práticas recomendadas do XP amplamente servem para compensar a taxa rápida de iteração fornecendo ciclos de comentários rápida e abrangente.

  • Propriedade coletiva através de programação do par. Adoro-lo ou odiá-lo, programação par requer que pelo menos dois pares de olhos analise cada linha de código de produção. Par de programação fornece comentários de um design ou código revisão mera segundos depois que o código é gravado
  • Desenvolvimento controlado por testes (TDD), controlado por comportamento testes de desenvolvimento (BDD) e aceitação. Todas essas atividades criar comentários muito rápido. TDD e BDD ajudam a unidade saída defeitos no código quando inicialmente gravados, mas tão importante, o nível alto de cobertura de teste de unidade torna posteriores alterações de design e adições ao código muito mais seguro detectando falhas de regressão de maneira refinada.
  • Integração contínua. Quando combinado com um alto nível de cobertura do teste automatizado e as ferramentas de análise possivelmente estática de código, integração contínua pode localizar rapidamente problemas na base de código de que cada código de tempo check-in.
  • Retrospectives. Isso exige que a equipe de desenvolvimento parar e discuta como o design de software está ajudando ou afeta o esforço de desenvolvimento. Já vi vários aprimoramentos de design vêm de iteração e lançamento retrospectives.

A qualidade e quantidade de mecanismos de comentários muito afetar como você criar. Por exemplo, cobertura de teste automatizado alta com unidade bem escrita testa torna muito mais fácil e mais eficiente de refatoração. Refatoração com pouca ou nenhuma cobertura do teste automatizado provavelmente é muito arriscado. Testes de unidade mal-escrito podem ser quase como inúteis como ter não testa qualquer.

Reversibility do seu código foi muito aperfeiçoado por mecanismos de comentários sólida.

O último momento responsável

Se não com antecedência, quando você faz as decisões de design? Uma das mais importantes lições que você aprender através de design contínuo é ser cognizant das decisões que você tomar sobre o design e decidir conscientemente quando tomar essas decisões. Programação enxuta ensina nos para tomar decisões no "último responsável momento." Acordo com a Mary Poppendieck (em seu livro Lean Software Development), seguir esse princípio significa "atrasar compromisso até … no momento em que deixar de fazer uma decisão elimina alternativa importante."

O ponto é tomar decisões mais tarde possível, pois é quando você tem mais informações com o qual fazer a decisão. Pense volta para o projeto com falha que descrevi no início deste artigo. Essa equipe desenvolvido e confirmados muito cedo para um design detalhado para o código de acesso a dados. Se os desenvolvedores tinham permitem que a interface do usuário e lógica de negócios precisa unidade a forma do código de acesso a dados como eles criado recursos da interface, poderiam ter evitado um pouco de esforço desperdiçado. (Isso é um exemplo de "design controlado por cliente", onde você cria o consumidor de uma API primeiro para definir a forma e assinatura da API propriamente dita.)

Uma das idéias principais aqui é que você deve pensar em frente e propor continuamente a alterações de design, mas você não deve confirmar irremediavelmente para uma direção de design até que você tenha a. Não queremos agir com base no design especulativo. Confirmar início para um design impede a possibilidade de usar uma alternativa mais simples ou melhor que pode apresentar mais tarde no projeto. Para citar um colega anterior, duas Mike fama NUnit 2, "Think em frente Sim, não à frente."

Reversibility

Martin Fowler diz, "Se você pode alterar facilmente suas decisões, isso significa que é menos importante para obtê-los à direita — que simplifica muito a sua vida." Relacionada para o último momento responsável é o conceito de reversibility, que seria descrevo como a capacidade ou incapacidade para alterar uma decisão. É essencial para seguir o princípio do último momento responsável sendo cognizant do reversibility inerente das suas decisões. A primeira decisão minha equipe feita para um projeto recente estava se desenvolver com Ruby on Rails ou fique com uma arquitetura .NET. Escolhendo uma plataforma e linguagem de programação não são uma decisão facilmente reversível e sabíamos que precisávamos tomar essa decisão mais cedo. Em outros projetos, tive de coordenar com grupos externos que necessárias para definir e agendar seus meses de tempo de antecedência. Em casos como essas, minha equipe tinha absolutamente tomar decisões com antecedência para envolver com as equipes externas.

Uma decisão clássica envolvendo reversibility é criar o cache em um aplicativo. Pense em casos onde você não souber com certeza se realmente precisar alguns parte dos dados do cache. Se você estiver receio de que o cache será impossível fazer ajustes posteriormente, você invariavelmente precisa criar esse cache no início — mesmo que isso pode ser um desperdício de tempo. Por outro lado, se você tiver estruturado o código para isolar o acesso a esses dados de tal forma que você pode facilmente ajustes cache o código existente com pouco risco? No segundo caso, você pode com responsabilidade forgo o suporte de cache para o momento e fornecer a funcionalidade mais rápido.

Reversibility também orienta minha equipe em quais tecnologias e técnicas usamos. Pois usamos um processo de entrega incremental (Kanban com práticas de engenharia Extreme Programming), nós definitivamente favorecer tecnologias e práticas que promovem reversibility superior. Nosso sistema provavelmente terá que oferecem suporte a vários mecanismos de banco de dados em algum momento no futuro. Para esse fim, usamos uma estrutura de mapeamento relacional do objeto para amplamente desassociar nossa camada intermediária do mecanismo de banco de dados real. Tão importante, temos um conjunto bastante abrangente de testes automatizados que exercício nosso acesso de banco de dados. Quando tiver tempo para trocar mecanismos de banco de dados, podemos usar esses testes para ter certeza de que nosso sistema funciona com o novo mecanismo de banco de dados — ou pelo menos destaque exatamente onde estamos incompatíveis.

YAGNI e o Thing mais simples que pode funcionar possibly

Para fazer o design contínuo, temos que facilitar o nosso código alterar, mas gostaríamos realmente evitar muita de re-trabalho em nosso código como estamos fazendo alterações a ele. Para fazer entrega incremental, queremos focalize na criação somente os recursos que estão designados para com criando agora, mas não queremos tornar o próximo recurso impossível ou difíceis de desenvolver fazendo o design incompatível com necessidades futuras.

Programação extrema introduziu dois ditados para vernacular desenvolvimento que são relevantes aqui: "você não gonna necessário" (pronuncia-YAGNI, se "yawg-nee") e "A informação de mais simples que possivelmente funcionaria."

Primeiro, YAGNI proíbe que você adicione qualquer código para o sistema agora que não será usado pelos recursos atuais. " Análise paralysis"no desenvolvimento de software é um problema muito real e YAGNI Recorta a esse problema forçando enfocar somente o problema imediato. Lidar com a complexidade é difícil, mas YAGNI ajuda reduzindo o escopo do design de sistema que você precisa considerar a qualquer momento.

É claro, YAGNI pode parecer assustador e ignoradas talvez até mesmo irresponsável porque você pode muito bem precisar o nível de complexidade na primeira vez ao redor. Seguir YAGNI não significa que você eliminar possibilidades futuras. Uma das melhores maneiras de garantir que é empregar "a informação de mais simples que possivelmente funcionaria."

Gosto de definição de Alan Shalloway a coisa mais simples que funcionaria, possivelmente, mostrada na seguinte lista. (A regra de uma vez-e-somente-única se refere à eliminação de duplicação do código; é outra maneira de descrever o princípio de "não repetir-se"). Você deve escolher a solução mais simples que ainda segue estas regras:

  1. Executa todos os testes.
  2. Segue a regra de uma vez-e-somente-única.
  3. Tem alta coesão.
  4. Tem menos rigidez.

Essas qualidades de código estruturais tornam o código mais fácil de modificar posteriormente.

O ponto desses ditados complementares é que cada parte da complexidade tem a ganhar à direita para existe. Pense sobre todas as coisas que podem acontecer quando você escolher uma solução mais complexa em um mais simples:

  1. A complexidade extra claramente é garantida.
  2. A complexidade extra não é necessária e representa esforço desperdiçado em relação a uma abordagem mais simples.
  3. A complexidade extra torna o desenvolvimento mais difícil.
  4. A complexidade extra acontece seja flat-out errado e precisa ser alterado ou substituído.

Os resultados da adição de complexidade incluem três resultados negativos e um resultado positivo. Por outro lado, até que se prove o contrário, uma solução simples pode ser adequada. Mais importante, a abordagem simples provavelmente será muito mais fácil para criar e usar com outras partes do código e se tiver a ser alterado, bem, é mais fácil alterar código simples que código complexo. Na pior das hipóteses é que você precisa jogar fora o código simples e inicie pela, mas por esse tempo que você provavelmente ter um entendimento muito melhor do problema mesmo assim.

Às vezes, uma solução mais complexa será definitivamente ativar a ser justificado e a opção correta, mas mais freqüentemente que não, usando uma abordagem mais simples é melhor no final. Consistentemente seguindo YAGNI e "a coisa mais simples" quando você está em dúvida é simplesmente seguindo as chances de.

Como nível modelagem antes codificação?

Vamos colocar requisitos de documentação reservado para o momento. Eis uma pergunta clássica no desenvolvimento de software: "como muito design e modelagem devo fazer antes de começar a código?" Não há nenhuma resposta definitiva porque cada situação é diferente. O ponto principal aqui é que quando você estiver inseguro como proceder, isso significa que você no modo de aprendizado. Se você fazer algumas modelagem ou primeiro codificação exploratório estritamente depende em qual abordagem ajuda a aprender mais rápido sobre o problema à mão e, claro, preciso repetir esta cotação clássica de Bertrand Meyer: "Bolhas não falhar."

  • Se você estiver trabalhando com uma tecnologia desconhecida ou padrão de design, acho que modelagem não é praticamente tão útil quanto Obtendo sujo com alguns codificação exploratório suas mãos.
  • Se uma idéia de design é muito mais fácil para você visualizar em um modelo que no código, por todos os forma Desenhe alguns modelos.
  • Se você não tem idéia onde começar no código, não apenas stare na janela de IDE esperando inspiração. Sair de uma caneta e papel e anote as tarefas lógicas e responsabilidades para a tarefa que você está trabalhando.
  • Alterne para o segundo que atingir um ponto de diminuição retorna com modelagem de codificação. (Lembre-se de que bolhas não falhar!) Melhor alinhar as caixas do diagrama não ajuda você a escrever um código melhor!
  • Se você fizer saltar diretamente para codificação e começar a dificuldade, pare e voltar para modelagem.
  • Lembre-se de que você pode alternar entre codificação e de modelagem. Muitas vezes quando você estiver confrontados com um problema difícil codificação, a melhor coisa a fazer é selecionar as tarefas mais simples, as do isolamento de código e usar o formulário desse código para ajudar a determinar o que o restante do código deve ter aparência.

Outra coisa em mente é que algumas formas de modelagem são mais leves que outras pessoas. Se UML não ajudá-lo com um problema, vá para fichas CRC ou entidade até mesmo diagramas de relacionamento.

O que há à frente

Este artigo não tinha nenhum código seja, mas sinto fortemente que esses conceitos se aplicam a quase todas as decisões de design. Em uma futura coluna, falarei sobre alguns conceitos específicos e estratégias para desenvolver designs que permitem que você use princípios de design contínuo. Também descreverei muito mais detalhadamente como refatoração se encaixa no design contínuo.

Envie suas dúvidas e comentários parammpatt@microsoft.com.

Jeremy Miller, MVP da Microsoft em translation from VPE for Csharp, também é autor daferramenta de código aberto StructureMapInjeção de dependência com .NET e a serStoryTellerferramenta para teste no .NET de aceitação automatizada. Visite seu blog "Shade Tree Developer"parte do site CodeBetter.