quinta-feira, 7 de agosto de 2008

Princípios de Design Orientado a Objetos

A etapa de arquitetura de software é crucial para o futuro de qualquer projeto de sistema. Ela é feita logo antes da fase de construção do projeto e se bem planejada, ajudará bastante o projeto ser bem sucedido. Porém, uma arquitetura mal planejada é garantia de um projeto com problemas em diversas fases, desde a construção até a manutenção.
Em grandes projetos existe uma separação clara de papéis que define quem deverá ser responsável pela tarefa de definir a arquitetura do software, que geralmente é feita por uma pessoa especializada nisso, o Arquiteto de Software. Porém, em projetos ou empresas menores, observamos que essa tarefa geralmente é realizada por outras pessoas, como o Analista de Sistemas ou o próprio Desenvolvedor. Desta forma, estudar arquitetura de software é essencial não só aos que são (ou pretendem ser) arquitetos de software.
Neste post pretendo apresentar uma introdução à arquitetura de software orientada a objetos, essencial para quem deseja (ou precisa) arquitetar um software.

Quando decidimos desenvolver um software utilizando o paradigma da orientação a objetos, o fazemos com dois objetivos principais em mente, que são:

Diminuir o acoplamento
Ou seja, deixar as partes do sistema fáceis de de ser trocadas ou utilizadas por outras partes.
Aumentar a coesão
Ou seja, fazer com que as partes do sistema tenham excelência em fazer aquilo que se propõem sem depender de outras partes.

Robert Martin, em seu livro Agile Software Development: Principles, Patterns, and Practices, nos mostra alguns princípios que se bem observados na arquitetura do software orientado a objetos, trazem agilidade no desenvolvimento, estabilização, implantação e manutenção dos projetos.

Estes princípios nos ajudam a atingir os nossos dois objetivos tentando remover do software as seguintes características:

Rigidêz
Que é a dificuldade de fazer uma alteração numa parte do software porque ela afetaria muitas outras partes.
Fragilidade
Que é o surgimento de erros em diversas partes do software quando você altera alguma parte.
Imobilidade
Que é a impossibilidade de reutilizar partes do software porque não é possível "desencaixá-las" de todo o resto.

Sabendo isso, vamos aos princípios:

Princípio Aberto-Fechado

Classes, módulos e funções devem ser abertas para extensão, mas fechadas para modificações.
Ou seja: ao criar um sub-classe, por exemplo, você não deverá alterar nada no comportamento da classe base, ela deve permanecer intacta.Utilizar classes abstratas ou interfaces ajudam a reforçar este princípio.

Princípio da Inversão de Dependência

Partes de mais alto nível não devem depender das partes de menor nível. Ambas devem depender de abstrações; e
Abstrações não devem depender de detalhes. Os detalhes é que devem depender de abstrações;
Ou seja: Entre as classes de alto nível e as classes de baixo nível, devemos introduzir classes abstratas.
Isso permite que troquemos facilmente as classes de baixo nível sem afetar as de alto nível.
Para fazer isso, a parte abstrata deve ser definida e depois não mais alteradas (Aberto-Fechado), isso significa que devemos fazer as classes específicas (detalhes) seguindo as abstrações e caso a abstração não sirva, devemos extendê-la: nunca alterá-la.

Princípio da Segregação de Interfaces

Clientes não devem ser forçados a depender de iterfaces que eles não usam
Ou seja: devemos tomar cuidado ao criar interfaces para não colocarmos métodos nela que não são realmente necessários para qualquer classe que implemente essa interface.
Interfaces com métodos desse tipo são chamadas de interfaces poluídas. Devemos evitá-las.

Princípio da Responsabilidade Única

Uma classe deve ter uma única razão para mudar
Ou seja: uma classe deve ter uma única razão para mudar. Se identificarmos que ela está com mais de uma razão para mudar, devemos separá-la em duas classes.

Princípio da Substituição de Liskov

Sub-tipos devem ser completamente substituíveis por seu tipo-base
Ou seja: isso reforça o princípio Aberto-Fechado. Se você utilizar um objeto e através do polimorfismo manipulá-lo como sendo do seu tipo base, ele deve funcionar corretamente e deve se comportar da mesma forma como se comportaria se ele realmente fosse daquele tipo.

Os Design Patterns, tão falados atualmente, são "receitas" de como resolver determinados problemas corriqueiros seguindo os princípios aqui apresentados.
Seguindo estes princípios, com certeza ganhamos agilidade no desenvolvimento de software, além de aumentarmos, e muito, a qualidade dele. Uma coisa importante que não podemos deixar de ter em mente é que princípios não são regras, nós devemos sempre saber quando abrir mão de um princípio para não deixarmos o software desnecessariamente complexo.

Espero que isto possa ajudar a quem está se deparando com a tarefa de definir a arquitetura de um software e não sabe por onde começar. Abrasssss!

2 comentários:

Rodrigo disse...

Eai Henrique, parabéns pelo post cara, está muito bom, isso ajuda bastante.

Rodrigo Melo.

Daniel San disse...

Muito bom seu resumo. Contudo, a palavra FUNÇÕES em (..) Classes, módulos e funções devem ser abertas para extensão, mas fechadas para modificações.(..) não é muito bem vista entre os fãs da orientação a objetos. Acredito que a palavra MÉTODO caberia melhor ali.