Este artigo foi traduzido por máquina.

Padrões e práticas

Você pode depender padrões e práticas

Alex Homer

Conteúdo

Padrões e práticas
Uma mão de orientação
Coping com abstração
Um breve histórico de dependência na Microsoft
Estendendo-se
Resumo

Escrever código de computador usado para ser extremamente difícil. Quando comecei a programação de computadores domésticos mais anos do que se preocupar com lembrar, a única maneira de fazer um programa executado em mais de um rastreamento desultory era gravá-los usando código de máquina. Até mesmo um utilitário de processamento de texto simples poderia levar semanas até criar como meticulosamente planejadas as alocações de memória de variáveis, escrevi rotinas para executar tarefas simples, como caracteres desenho na tela e teclado decodificação entrada e, em seguida, digitado cada instrução de processador individual em um montador.

Hoje em dia, por comparação, criar código eficiente é fácil. Nós levar para concedido o conjunto de ferramentas, linguagens de alto nível, estruturas de tempo de execução, bibliotecas de código e serviços do sistema operacional que possibilitam a criação de aplicativos rapidez e eficiência. No entanto, ao criar o código tornou muito mais fácil, a tarefa de criação de aplicativos não possui. Esperamos que mais de nossos aplicativos modernos que nunca. Deve se comunicar através de redes, interagir com outros aplicativos e serviços, expor interfaces de usuário altamente interativos e responsivo e oferecer suporte a mídia sofisticada e elementos gráficos. E, claro, devem ser robusto, seguros, confiáveis e gerenciáveis.

Na verdade, seria praticamente impossível atender aos requisitos solicitados de nossos aplicativos modernos sem o crescimento contínuo e a evolução de linguagens de programação, sistemas operacionais, serviços de plataforma e estruturas. O enorme aumento em complexidade desses aplicativos também forçou nos Descubra maneiras para simplificar e organizar o código. Com o passar dos anos, várias técnicas de programação e design testadas e testadas evoluíram, como componentization, objeto-orientação, e — mais recentemente, orientação de serviço.

Padrões e práticas

Enquanto os aprimoramentos feitos no ferramentas e estruturas tornam-, mais fácil escrever código mais rapidamente e modernos idiomas e estilos de programação tornam mais fácil escrever um código melhor, a única área que teve o impacto a maioria na nossa capacidade para criar aplicativos nos últimos 10 a 15 anos foi a evolução e aceitação crescente dos padrões de design de software.

Padrões de design Descreva os problemas comuns que ocorrem repetidamente no design de aplicativo e de desenvolvimento e fornecem as técnicas para lidar com esses problemas. Padrões também descrevem a prática de mercado atual para resolver problemas de arquiteturais e para tratamento a complexidade do design solicitada de aplicativos. A organização de elementos de código e a solução no núcleo do design de software hoje em dia, enquanto padrões fornecem nos formas para simplificar e organizar esses elementos — fornecendo oportunidade de melhor para maximizar desempenho, flexibilidade e capacidade de manutenção de aplicativos.

Desde o lançamento do livro quebra início pelos Gang de quatro, Erich gama, Richard Helm, Ralph Johnson e M de John. Vlissides, padrões de design: Elements of Reusable Object-Oriented software (Addison-Wesley, 1996), que documentadas muitas dos padrões de design básico que é tomada para concedido hoje, o número de padrões de design disponíveis para desenvolvedores e designers cresceu a uma taxa phenomenal. Quase todos os aspectos da criação de software tem associados padrões de design e implementação, e documentar todas elas simplesmente se tornou uma tarefa impossível. Em vez disso, designers e desenvolvedores tendem a fragmentar na especialidade e aprender os padrões mais aplicáveis a sua própria área de especialização.

Uma mão de orientação

Em 2002, o grupo Padrões e práticas no Microsoft Corporation publicada a arquitetura do aplicativo para .NET: guia Criando aplicativos e serviços, colocar juntos o conselho de orientação e o especialista em design básico para ajudar arquitetos de criação de aplicativos no Microsoft .NET Framework. No entanto, as tecnologias alterar com o tempo e enquanto os fundamentos da criação e desenvolvimento descrito na guia são igualmente válidos hoje em dia, a guia original não abordar alguns dos novos recursos do .NET Framework ou resolver os problemas de design resultantes para novos tipos de aplicativos.

Para os vários meses últimos, uma equipe abrangente de especialistas do setor e especialistas no assunto, dentro e fora da Microsoft, tem sido colaboração para criar uma nova edição do guia que fornece uma introdução abrangente aos arquitetar e criação de soluções no Microsoft .NET Framework. O guia de arquitetura do aplicativo Microsoft (segunda edição) descreve os princípios de arquiteturais de alto nível e padrões e pensar atual nas práticas de design e desenvolvimento aceitas. Ele também inclui orientações sobre a aplicação desses fatores a tipos específicos de aplicativos e ele fornece uma visão geral de ampla dos muitos serviços de plataforma e bibliotecas de código disponíveis para facilitar a implementação.

Obviamente, a emprestado uma frase usados com freqüência, arquitetura de software e sistema é algo que adota a pergunta de vida, o universo e tudo. Não única publicação pode responder a todas as perguntas possível ou espero fornecer cobertura completamente abrangente de todos os cenários possíveis. No entanto, o nova guia visa fornecer as informações que você precisa se você estiver apenas iniciando out designing.NET aplicativos baseados no Framework, um designer experiente mover para o .NET Framework de outra plataforma, arquiteto realizado procurando informações específicas e conselhos, ou simplesmente interessado em aprender mais sobre os cenários amplos e as oportunidades oferecidas pelo .NET Framework.

Coping com abstração

Para ilustrar as práticas recomendadas do setor, a guia lista os princípios gerais que você deve aplicar ao criar praticamente qualquer tipo de aplicativo. Esses princípios incluem mantendo a separação de questões, o uso de abstração para implementar flexível união entre camadas e componentes, implementação de recursos de local de serviço e gerenciar crosscutting questões como log e de segurança. Embora isso podem parecer seja desejáveis, mas não relacionados objetivos, uma técnica pode ajudar você aplicar vários princípios de design com facilidade. O princípio de inversão de dependência implica em separação de questões através de abstrações em vez de implementações concretas. Em termos de padrões de design, você pode obter isso, aplicando o padrão de inversão de controle (IoC) e seu padrão relacionado, Dependency Injection (DI).

A teoria é bastante simples. Em vez de especificar em tempo de design o tipo concreto real que cada classe ou o componente irá usar para executar algumas atividades ou processo, você organizar para essas classes ou os componentes para recuperar o objeto apropriado de um recipiente que você anteriormente configurado com mapas de tipo e registrado tipos. Por exemplo, conforme ilustrado no aplicativo simples da Figura 1 , o componente de acesso de dados pode requerer os serviços de um componente de log. Como você ter corretamente abstraída seu código crosscutting do código específicos de tarefa e específicas do aplicativo, você pode ter vários componentes de log do qual deseja escolher. Talvez um foi projetado para ser usado ao depurar o aplicativo, outra para uso ao executando o aplicativo internamente em sua própria rede, e uma terceira mais adequado para executando em um sistema de nível empresarial que faz uso de um ambiente monitoramento, como o Microsoft System Center.

fig01.gif

A Figura 1 um aplicativo Simple que faz uso de camadas e um separado de registro de componente

É possível até mesmo o caso que você tenha vários dados componentes de acesso, cada projetados para uso em um ambiente específico ou com um tipo diferente de armazenamento de dados. Portanto, a camada de negócios será necessário escolher o componente de camada de dados apropriadas dependendo o ambiente de implantação ou tempo de execução atual. De modo semelhante, talvez seja necessário serviços que seu aplicativo usa repetidamente, tais como um email enviar serviço ou um serviço de transformação de dados. Inserção de dependência pode atuar como um recurso de local de serviço para ajudar a seu aplicativo recupera uma instância (uma nova instância ou uma instância existente) do serviço em tempo de execução.

Cada um desses exemplos efetivamente descreve uma dependência de uma parte do aplicativo em outro e resolver essas dependências de forma que não acoplar rigidamente os objetos é o objetivo do princípio de inversão de dependência.

Um breve histórico de dependência na Microsoft

Embora os princípios de inversão de dependência já existem por um longo tempo, recursos para ajudar os desenvolvedores implementá-lo em aplicativos em execução na plataforma Microsoft são relativamente recentes. Na verdade, há uma história que um desenvolvedor renowned no mundo Java, ao visitar campus da Microsoft, remarked que a crença geral foi que ninguém da Microsoft pôde soletrar "Dependency Injection". Enquanto isto é, sem dúvida, uma myth Urbano, ele é o caso que ferramentas para ajudar os desenvolvedores implementar muitos dos padrões comuns não foram uma prioridade na maioria das áreas da empresa.

No entanto, o grupo Padrões e Práticas da Microsoft destaca a nossa posição exclusiva de ser dentro da empresa, mas fora das equipes de desenvolvimento de produto principal e divisões. O objetivo de p & p, conforme ilustrado por nosso subtítulo "comprovadas práticas recomendadas para resultados previsíveis," é fornecer aos desenvolvedores de orientações, ferramentas, bibliotecas, estruturas e uma série de outros recursos para ajudá-los a projetar e criar aplicativos melhor na plataforma Microsoft. Rápido rapidamente em nossohome page no MSDNirá ilustrar a ampla variedade de ativos que fornecemos.

Entre esses ativos são vários produtos que usam do padrão de inclusão de dependência, incluindo a Enterprise Library, estruturas de aplicativo composto e fábricas de software. Durante o desenvolvimento desses ativos, em particular o original Composite CAB Application Block (), ficou claro que era necessário um mecanismo de inserção de dependência reutilizáveis e altamente configurável — e para a equipe interno a versão original do construtor de objetos.

Construtor de objeto é quase totalmente configurável e agora é usado em uma grande variedade de produtos em p & p e em qualquer lugar dentro da Microsoft. No entanto, é muito difícil usar. Requer um ótimo vários parâmetros que levam objetos complexos, e ele expõe um intervalo de eventos que você deve tratar para aplicar a configuração desejado. Tenta inicial documento Object Builder como parte do projeto CAB em breve revelou que isso seria uma tarefa uphill. Além disso, Object Builder foi em vez disso, mais de um recipiente de inserção de dependência e parece que funcionou um exagero em termos dos requisitos comuns para implementar os padrões DI e IoC.

Durante o desenvolvimento de Enterprise Library 4.0, o Object Builder foi atualizado — não para simplificar a ele, mas para torná-lo mais rápido e eficiente. Ele também foi ajustar para uso no mecanismo de inserção de dependência principais primeiro da Microsoft que é destinado squarely desenvolvedores que desejam implementar os padrões DI e IoC. Construtor de objeto é a base para Unity, um recipiente de injeção de dependência leve e extensível que oferece suporte a inclusão do construtor, inclusão de propriedade e injeção de chamada de método.

Unidade oferece recursos para a criação do objeto simplificada, especialmente para estruturas de objeto hierárquicos e dependências; abstração de requisitos em tempo de execução ou através da configuração; Gerenciamento de transversais preocupações; simplificado e aumenta a flexibilidade em adiando a configuração do componente para o recipiente. Ele tem uma capacidade de local de serviço e permite que os clientes armazenam ou armazenar em cache o recipiente — até mesmo em aplicativos Web do ASP.NET.

Desde o lançamento da primeira versão Unity no início de 2008, ele encontrou uma casa em muitos p & p ativos como o mecanismo padrão para implementar a inversão de dependência. Unidade também continuou a evoluir enquanto restante compatível com versões anteriores; você pode usá-lo para habilitar os recursos dentro da Enterprise Library, bem como usá-lo como um contêiner de DI autônomo. Na versão mais recente, ele oferece recursos para a instância de implementar e tipo de interceptação (por meio de uma extensão de plug-in) que permitem a implementações de taxa Oriented Programming técnicas como o diretiva de inclusão.

Unidade também foi gerado outras implementações de recipiente DI destinadas a tarefas específicas e requisitos, como uma implementação extremamente simples criado para usar em dispositivos móveis e telefones inteligentes. Enquanto isso, planejados desenvolvimentos futuros na arena do Unity e biblioteca de empresa incluem recursos para abrir a Enterprise Library para outros mecanismos de recipiente de terceiros, enquanto fornece extensões adicionais que habilitam novos recursos para Unity. Aplicação de inversão de dependência

Deixar esse histórica distração e retornar para o aplicativo hipotético, como pode você aplicar o princípio de inversão de dependência para atingir os objetivos, discutidos anteriormente, de separação de questões, abstração e rigidez? A resposta é configurar um recipiente de inserção de dependência, como o Unity, com os tipos adequados e digite mapeamentos e que o aplicativo recupere e inserir instâncias de objetos apropriados em tempo de execução. a Figura 2 ilustra como você pode usar o bloco de aplicativo Unity para implementar esse contêiner. Nesse caso, você preencher o contêiner com mapeamentos de tipo entre definições de interface para os componentes de dados e componentes de log e as concretas específicas implementações dessas interfaces que deseja que o aplicativo para usar.

fig02.gif

A Figura 2 a inserção de dependência pode selecionar os componentes apropriados em tempo de execução com base na configuração do recipiente.

Em tempo de execução, a camada comercial consultará o recipiente para recuperar uma instância do componente camada dados corretos, dependendo do seu mapeamento atual. A camada de dados, em seguida, consultará o recipiente para obter uma instância do componente de log apropriado, dependendo do mapeamento armazenado para esse tipo de interface. Como alternativa, os dados e os componentes de log podem herdar de respectivas classes base e os registros no recipiente podem mapear entre esses tipos base e os tipos de concretos herança.

Essa abordagem orientada de contêiner para resolver tipos e instâncias significa que o desenvolvedor é livre para converter as implementações dos dados e componentes de log, desde que essas implementações fornecem a funcionalidade necessária e expõem a interface apropriada (por exemplo, por implementar a interface mapeada ou herdadas da classe base mapeada). A configuração de recipiente pode ser definida na código em tempo de execução usando métodos do recipiente que registram tipos, mapeamentos de tipo ou instâncias existentes de objetos. Como alternativa, você pode preencher o recipiente, carregar os registros de uma fonte de configuração ou um arquivo, como o arquivo web.config ou o arquivo app.config.

Quando você deseja registrar mais de uma instância de um tipo, você pode usar um nome para definir cada uma e, em seguida, resolver os diferentes tipos, especificando o nome. O registro também pode especificar a vida útil do objeto, torna fácil de obter recursos de local, o estilo de serviço, registrando o objeto de serviço como um singleton ou com uma vida útil específica, como por thread. O exemplo de código a seguir mostra alguns exemplos de registrar mapeamentos de tipo com o recipiente:

C#
// Register a mapping for the CustomerService class to the IMyService interface. 
myContainer.RegisterType<IMyService, CustomerService>();

// Register the same mapping using a mapping name. 
myContainer.RegisterType<IMyService, CustomerService>("Data");

// Register the first mapping, but as a singleton. 
myContainer.RegisterType<IMyService, CustomerService>(
                         new ContainerControlledLifetimeManager());

Observação: os exemplos de código referência classes e tipos usando apenas o nome de classe. Você pode usar as definições de alias de tipo no arquivo de configuração alias dos nomes de tipo totalmente qualificado de classes, que simplifica o registro de recipiente quando você estiver usando um arquivo de configuração.

Para recuperar instância de um objeto, você simplesmente consultar o recipiente, especificando o tipo, o tipo de interface, ou o tipo de classe base (e o nome), se você registrado tipo usando um nome como mostrado no próximo exemplo. O recipiente resolve o tipo, se ele estiver registrado e cria ou retorna uma instância do objeto apropriado. Se não estiver registrado, o contêiner simplesmente cria uma nova instância desse tipo e entrega-lo novamente. Por que você deve resolver itens por meio do recipiente quando não houver nenhum registro para esse tipo de? A idéia é aproveitar os recursos de adicionais e muito útil que Unity e muitos outros DI recipiente mecanismos, fornece — a capacidade de inserir objetos usando o construtor, setter de propriedade e injeção de chamada de método.

C#
// Retrieve an instance of the mapped IMyService concrete class. 
IMyService result = myContainer.Resolve<IMyService>();
// Retrieve an instance by specifying the mapping name. 
IMyService result = myContainer.Resolve<IMyService>("Data");

Por exemplo, quando você cria uma instância de um objeto por meio do contêiner, Unity examina os construtores e automaticamente injetará instâncias do tipo apropriado para os parâmetros do construtor. Voltando ao nosso exemplo de aplicativo simples anterior, o componente de acesso a dados pode ter um construtor que leva uma referência a um componente de log como um parâmetro de sinais. Se este tipo de parâmetro for a interface ou classe base para registrar componentes registrados com o recipiente, Unity será resolver o tipo de mapeada, criar uma instância e passá-lo para o construtor do componente de dados (como mostrado na Figura 3 ). Não faça nada, exceto a registrar os mapeamentos.

A Figura 3 inserindo objetos em parâmetros do construtor

C#
// In main or startup code:
// Register a mapping for a logging component to the ILogger interface.
// Alternatively, you can specify this mapping in a configuration file. 
myContainer.RegisterType<ILogger, MyLogger>();

...

// In data access component:
// Variable to hold reference to logger.
private ILogger _logger = null;

// Class constructor. Unity will populate the ILogger type parameter.
public DataAccessRoutines(ILogger myLogger)
{
  // store reference to logger
  _logger = myLogger;
  _logger.WriteToLog("Instantiated DataAccessRoutines component");
}

Isso significa que você pode alterar o tipo concreto real que o aplicativo usa basta alterar a configuração do recipiente — tanto em tempo de design, em Executar tempo editando a configuração, ou dinamicamente com base em algum valor que seu código de coleta do ambiente e usa para criar ou atualizar o mapeamento no recipiente. Você pode conectar seu componente de log de depuração quando necessário ou conectar um novo componente de log "super rápida" quando você encontrar que o antigo é muito lenta. Enquanto isso, o administrador do sistema pode atualizar a configuração conforme o necessário para monitorar, gerenciar e adaptar o comportamento do aplicativo em tempo de execução para ambientes de alteração de naipe e problemas operacionais.

Da mesma forma, se você tiver uma dependência entre dois objetos, tais como a dependência de uma exibição no seu apresentador ao implementar o padrão Model-View-Presenter (MVP), você pode usar a inserção de dependência para Flexibilize a ligação entre essas classes. Basta defina uma propriedade da classe modo de exibição como o tipo de apresentador ou tipo de classe base e marca a propriedade com uma dependência de atributo, como mostrado no próximo exemplo:

C#
// Variable to hold reference to controller.
private IPresenter _presenter;

// Property that exposes the presenter in the view class. Unity will inject 
// this automatically because it carries the Dependency attribute.
 [Dependency]
public IPresenter MyViewPresenter
{
  get { return _presenter; }
  set { _presenter = value; }
} 

Observação: atributos são a maneira mais rápida para especificar propriedades para inserir. Se você não quiser usar atributos (para evitar a união de suas classes para o recipiente) você pode usar um arquivo de configuração ou a API Unity para especificar quais propriedades devem ser inseridas.

Quando você cria o modo de exibição Resolvendo através o recipiente, Unity detectará o atributo de dependência, automaticamente resolver uma instância da classe apresentador concreto apropriado e definida-lo como o valor dessa propriedade da classe modo de exibição. O exemplo a início rápido incluído Unity demonstra esse método em um aplicativo Windows Forms. Na verdade, ele resolve o formulário principal para o aplicativo por meio de contêiner, que faz com que Unity criar e preencher várias dependências em todo o aplicativo inteiro, uso do construtor e de inclusão do setter de propriedade.

Estendendo-se

Unidade fornece uma profusão de funcionalidades relacionadas DI, mas sempre há algo extra que deseja obter. O desafio com Unity era para mantê-lo genérico o suficiente para satisfazer o número máximo de requisitos, e não extensível para que você pode adaptar a seus próprios requisitos específicos. Isso é conseguido usando extensões de contêiner, que lhe permitem fazer quase tudo em termos de gerenciamento de criação do objeto e recuperação.

Como exemplo, o inicia rápido incluído Unity demonstre uma extensão de contêiner que implementa um mecanismo de Publish\Subscribe orientada de atributo simples. Como Unity cria instâncias de objetos, ele fios manipuladores de eventos para eles com base nos atributos nos arquivos de classe. Outro exemplo gera informações detalhadas do log quando ele cria ou recupera cada tipo por meio do contêiner, que ajuda quando você está depurando aplicativos complexos.

Essa flexibilidade enorme vem sobre porque Unity permite a interação com o mecanismo de Object Builder subjacente através de sua extensão de recipiente. Ah, você pode dizer, mas Object Builder é extremamente difícil usar e não está totalmente documentado. Na verdade, a documentação Unity contêm informações sobre o Object Builder em termos de como interagir com ele de uma extensão de recipiente, e os exemplos de início rápido fornecem muita código de exemplo, você pode usar e modificar.

Resumo

Há várias exibições em arquitetura e o projeto do aplicativo. O 42010:2007 padrão ISO/IEC/IEEE 1471 "recomendável prática para arquitetura descrição de intensivos de software sistemas" descreve a arquitetura de software como "a organização fundamental de um sistema incorporado em seus componentes, suas relações entre si e para o ambiente e os princípios guiar o design e a evolução". No entanto, em seu livro Patterns of Enterprise Application Architecture (Addison-Wesley, 2002), Martin Fowler diz que ".. .in final, arquitetura resume é qualquer as coisas importantes, " uma maneira muito mais simples para capturar o espírito de arquitetura de software!

O guia de arquitetura do aplicativo Microsoft (segunda edição) o ajudará a compreender o que é a coisas importantes para que você pode criar melhor, aplicativos de qualidade superiores mais rapidamente e com mais eficiência. Como ter visto neste artigo, uma área específica — aproveitando os padrões de Dependency Injection e inversão de controle — pode ajudá-lo a atingir muitas das metas de design promovidas por guia. Isso inclui a separação de questões, o uso de abstração para implementar rigidez entre camadas, local do serviço e implementação de recursos para gerenciamento aperfeiçoado de transversais preocupações.

Alex Homer é engenheiro de documentação trabalhando com a equipe de padrões e práticas Microsoft. Seus ravings aleatórios sobre vida, tecnologia e o mundo em geral podem ser encontradas no http://blogs.msdn.com/alexhomer/.