.NET

10 out, 2013

.NET – Design Patterns – Identificando e aplicando padrões – Parte 01

Publicidade

Antes de iniciar falando de padrões de projetos, vamos falar da base que deu origem aos mesmos. Vamos falar um pouco sobre os princípios de design ou projeto de software conhecidos também como boas práticas no desenvolvimento de software.

Quais são os princípios de projeto de software?

Princípios de projeto ou design de software representam um conjunto de diretrizes que nos ajudam a evitar que tenhamos um projeto ruim. Os princípios de design estão associados à Robert Martin, que agrupou essa informação em “Desenvolvimento Ágil de Software: Princípios, Padrões e Práticas”. De acordo com Robert Martin, há três características importantes de um projeto ruim que devem ser evitadas:

  1. Rigidez – É difícil mudar, porque cada mudança afeta muitas outras partes do sistema;
  2. Fragilidade – Quando você faz uma alteração, partes inesperadas do sistema ‘quebram’;
  3. Imobilidade – É difícil reutilizar noutra aplicação, porque não pode ser desembaraçada da aplicação atual.

Os princípios de um projeto de software formam as bases sob as quais os padrões de projeto foram construídos. Eles são mais fundamentais que os padrões de projeto. Toda vez que você seguir os princípios de projeto, sua base de código vai se tornar mais flexível e adaptável a mudanças, bem como mais fácil de ser mantida. Vamos introduzir brevemente alguns dos princípios de concepção de software mais amplamente conhecidos e uma série de princípios conhecidos como o princípios S.O.L.I.D.

Princípios de projeto de software

Existe uma série de princípios comuns de projeto que, assim como os padrões de projeto, se tornaram as melhores práticas ao longo dos anos e ajudou a formar uma base sobre a qual a criação e manutenção de software pode ser construída. Vejamos os princípios mais importantes:

Keep It Simple, Stupid (KISS)

Keep It Simple é um princípio geral que valoriza a simplicidade do projeto e defende que toda a complexidade desnecessária seja descartada. Assim, este princípio nos guia a manter as coisas simples.

Don’t Repeat Yourself (DRY)

O princípio DRY visa evitar a repetição de qualquer parte de um sistema, abstraindo as coisas que são comuns e colocando-as em um único local. Este princípio não se preocupa apenas com código, mas com qualquer lógica que esteja duplicada em um sistema, em última análise deve existir apenas uma representação para cada pedaço de conhecimento em um sistema. Em suma, o princípio busca reduzir a duplicação de código e os problemas de manutenção resultantes.

Tell, Don’t Ask

O princípio Tell, Don’t ASK (Diga, não pergunte) está estreitamente alinhado com o encapsulamento e a atribuição de responsabilidades às suas classes. O princípio, afirma que você deve dizer aos objetos quais ações você deseja que eles realizem, em vez de realizar perguntas sobre o estado de um objeto e depois fazer uma decisão sobre a ação que você deseja realizar. Isso ajuda a alinhar as responsabilidades e evitar forte acoplamento entre as classes.

You Ain’t Gonna Need It (YAGNI )

O princípio YAGNI refere-se à necessidade de incluir apenas a funcionalidade que é necessária para a aplicação e adiar qualquer tentação de adicionar outros recursos que você pode pensar que você precisa. A metodologia de projeto que adere ao YAGNI é o desenvolvimento orientado a testes (TDD). O TDD versa sobre a escrever primeiro os testes que comprovam a funcionalidade de um sistema e, em seguida, escrever apenas o código para obter o teste.

Separation of Concerns (SoC) – Separação das responsabilidades

O princípio SoC é o processo de dissecação de um pedaço de software em características distintas que encapsulam comportamento único e dados que podem ser utilizados por outras classes. Geralmente uma responsabilidade representa uma característica ou o comportamento de uma classe. O ato de separar um programa em responsabilidades discretas aumenta significativamente a reutilização de código, manutenção e testabilidade.

Princípios de projeto S.O.L.I.D

A palavra SOLID é um acróstico onde cada letra significa a sigla de um princípio: SRP, OCP, LSP, ISP e DIP. Os princípios SOLID para programação e projeto orientados a objeto são de autoria de Robert C. Martin (mais conhecido como Uncle Bob) e datam do início de 2000.

Obs: Os acrósticos são formas textuais onde a primeira letra de cada frase ou verso formam uma palavra ou frase.

Na tabela abaixo vemos cada sigla, o seu significado e um resumo do princípio a que se refere no original e em uma tradução livre.

SRP The Single Responsibility Principle
Principio da Responsabilidade Única
Uma classe deve ter um, e somente um, motivo para mudar.
A class should have one, and only one, reason to change.
OCP The Open Closed Principle
Princípio Aberto-Fechado
Você deve ser capaz de estender um comportamento de uma classe, sem modificá-lo.
You should be able to extend a classes behavior, without modifying it.
LSP The Liskov Substitution Principle
Princípio da Substituição de Liskov
As classes derivadas devem ser substituíveis por suas classes base.
Derived classes must be substitutable for their base classes.
ISP The Interface Segregation Principle
Princípio da Segregação da Interface
Muitas interfaces específicas são melhores do que uma interface geral
Make fine grained interfaces that are client specific.
DIP The Dependency Inversion Principle
Princípio da inversão da dependência
Dependa de uma abstração e não de uma implementação.
Depend on abstractions, not on concretions.

Os princípios SOLID devem ser aplicados no desenvolvimento de software de forma que o software produzido tenha as seguintes características:

  • Seja fácil de manter, adaptar e se ajustar às constantes mudanças exigidas pelos clientes;
  • Seja fácil de entender e testar;
  • Seja construído de forma a estar preparado para ser facilmente alterado com o menor esforço possível;
  • Seja possível de ser reaproveitado;
  • Exista em produção o maior tempo possível;
  • Que atenda realmente as necessidades dos clientes para o qual foi criado.

Dependency Inversion Principle (DIP) – O princípio da injeção de dependência (DIP)

O princípio DIP versa sobre como isolar suas classes de implementações concretas e fazendo-as depender de classes abstratas ou interfaces. Ele promove o mantra de codificar para uma interface ao invés de fazê-lo para uma implementação, o que aumenta a flexibilidade dentro de um sistema garantindo que o mesmo não está fortemente acoplado a um implementação.

Dependency Injection (DI) and Inversion of Control (IoC) – Injeção de dependência e Inversão de Controle

Intimamente ligados ao principio DIP temos os princípio DI e o princípio IoC.

O principio DI é o ato de fornecer um baixo nível ou classe dependente através de um construtor, método ou propriedade. Utilizado em conjunto com DI, estas classes dependentes podem ser invertidas para interfaces ou classes abstratas que levarão a sistemas com um baixo acoplamento altamente testáveis e de fácil manutenção. Assim a DI isola a implementação de um objeto da construção do objeto do qual ele depende.

No príncipio IoC, o fluxo de um sistema de controle é invertido em relação à programação procedural. Como exemplo podemos citar um recipiente IoC, cujo objetivo é injetar serviços no código de cliente sem que o código do cliente tenha especificado a implementação concreta.

Padrões de projetos

Depois de apresentar os princípios de projeto e os princípios SOLID, vamos falar dos padrões de projeto. Eles são modelos de soluções abstratas de alto nível. Pense neles como modelos para soluções e não como soluções em si mesmo.

Infelizmente não existe nenhum framework que aplique de forma automática os padrões de projetos à sua aplicação. Ao invés disso, você normalmente faz isso refatorando o seu código e generalizando o seu problema e não abrindo um manual de receitas e copiando soluções.

Os padrões de projeto não são a panaceia universal ou a bala de prata que vai resolver tudo para você. Você tem que compreender plenamente o seu problema, generalizá-lo e, em seguida, aplicar um padrão que se ajuste ao seu cenário. No entanto, nem todos os problemas requerem um padrão de projeto. É verdade que os padrões de projeto podem ajudar a tornar simples problemas complexos, mas eles também podem tornar complexos problemas simples.

Muitos desenvolvedores após lerem um livro de padrões, caem na armadilha de tentar aplicar padrões para tudo que estão fazendo, conseguindo exatamente o oposto do que os padrões se propõem: fazer as coisas simples.

Não existe mágica: a melhor maneira de aplicar padrões é identificar o problema fundamental que você está tentando resolver e procurar uma solução que se encaixa ao seu problema, levando em conta o seu cenário que pode ser uma aplicação web, desktop, com acesso a dados, etc.

Repito mais uma vez: você não é obrigado a usar os padrões de projeto em todos os seus projetos. Se você chegou a uma solução para um problema que é simples, clara e de fácil manutenção, mas ela não se encaixa em nenhum dos 23 padrões de projeto catalogados, não se apavore; você fez a coisa certa. Se você seguir outro caminho, apenas por modismo, isso vai complicar o seu projeto.

Eu sei que apesar de todo o conhecimento que se pode ter de padrões de projeto sempre fica aquela dúvida: Como escolher e como aplicar um padrão de projeto? Bem, não existe uma receita pronta, mas podemos facilitar a nossa decisão seguindo alguns conselhos.

Você pode escolher dentre muitos padrões de projetos já existentes e catalogados. Como então identificar aquele que é mais apropriado para o seu problema?

Para saber qual padrão de projeto você pode usar e como aplicar o modelo ao seu problema específico é importante compreender e utilizar alguns conceitos:

  1. Você não pode aplicar padrões sem conhecê-los bem. O primeiro passo a dar é expandir o seu conhecimento e estudar os padrões e princípios na forma concreta e abstrata. Você pode implementar padrões de projetos de muitas formas e quanto mais você conhecer sobre as diferentes implementações possíveis mais você irá compreender sobre o real objetivo do padrão e de como um padrão pode possuir diferentes implementações.
  1. Você precisa introduzir a complexidade de um padrão de projeto no seu aplicativo? É comum para os desenvolvedores tentar usar um padrão para resolver todos os problemas quando eles estão estudando padrões. Você sempre precisa parar e pesar o tempo inicial necessário para implementar um padrão e o benefício que isso vai dar. Lembre-se do princípio KISS: Keep It Simple, Stupid ou seja mantenha as coisas simples.
  1. Generalize o seu problema. Identifique os problemas que você está enfrentando de forma mais abstrata. Veja a forma como a intenção de cada padrão e princípio está escrito, e veja se o seu problema se encaixa com o problema que um determinado padrão ou princípio está tentando resolver. Lembre-se que padrões de projetos são soluções de alto nível. Tente abstrair o seu problema e não se concentre demais nos detalhes de seu problema específico.
  1. Olhe para os padrões de natureza semelhante e para os padrões no mesmo grupo. Só porque você utilizou um padrão antes não significa que ele será sempre a escolha correta quando for resolver um problema.
  1. Encapsule o que varia. Olhe para o que provavelmente vai mudar com a sua aplicação. Se você sabe que um algoritmo vai mudar ao longo do tempo, olhe para um padrão que vai ajudar você a alterá-lo sem afetar o resto de sua aplicação.
  1. Depois de ter escolhido um padrão de projeto, esteja certo em usar a linguagem de seu padrão ao longo com a linguagem do domínio ao nomear os participantes em uma solução. Por exemplo, se você está usando o padrão Strategy para fornecer uma solução procure utilizar nomes adequados usando um vocabulário padrão em comum com a linguagem de seu domínio, isso tornará o seu código mais legível e compreensível para outros desenvolvedores com conhecimento de padrões.
  1. Quando se trata de padrões de projeto, não há substituto para estudar. Quanto mais você saber sobre cada um dos padrões, melhor equipado você estará em aplicá-los. Procure captar a intenção de cada padrão para refrescar sua memória para quando você tiver um problema e estiver procurando uma solução.
  1. Um exercício de aprendizado é tentar identificar os padrões aplicados na plataforma .NET. Por exemplo, o recurso de cache no ASP.NET usa o padrão Singleton, a criação de um novo GUID usa o padrão Factory, as classes que tratam XML usam o padrão Factory, etc. Isso ajuda no seu entendimento de como aplicar os padrões.

Estes são alguns conselhos práticos que podem ajudar você a melhor compreender como usar e aplicar os padrões de projeto, mas existe um caminho mais adequado: sujar as mãos.

Na segunda parte deste artigo eu vou mostrar um exemplo prático de como podemos identificar e aplicar padrões de projetos usando um cenário básico de um situação real.