Baixe o app para aproveitar ainda mais
Prévia do material em texto
Arquitetura de Software 1 P ó s- G ra d u aç ão a D is tâ n ci a Arquitetura de Software Professor Luciano Gaspar Professora Elisamara de Oliveira Arquitetura de Software 2 Arquitetura de Software 3 SUMÁRIO Apresentação 5 Capítulo 1 – Fundamentos de Arquitetura de Software 5 Definição de Arquitetura de Software 5 Mas, o que é arquitetura de software? 6 Modelagem de aplicações de softwares 6 Tarefas Acidentais e Essenciais 7 Aspectos essenciais na produção de software 8 Princípios SOLID 11 Princípio de Responsabilidade Única 12 Princípio Aberto-Fechado 12 Princípio de Substituição de Liskov 13 Princípio Segregação de Interface 14 Princípio de Inversão de Dependência 14 Polimorfismo e Herança em OO 15 Capítulo 2 – Padrões de Arquitetura de Software 16 Definição de Padrão Arquitetural 16 Padrão de Arquitetura em Camadas 17 Padrão de Arquitetura Pipes and Filters ou Pipeline 19 Padrão de Arquitetura Blackboard 21 Model-View-Controller (MVC) 23 Padrão de Arquitetura Microkernel 26 Padrão de Arquitetura Reflection 29 Exercícios do Capítulo 2 30 Capítulo 3 – Design Patterns – Padrões de Criação 31 Conceitos de Padrões de Projeto 31 Definição de Padrões de Criação 36 Padrão Abstract Factory 37 Padrão Builder 38 Padrão Factory Method 40 Padrão Prototype 41 Padrão Singleton 42 Exercícios do Capítulo 3 43 Capítulo 4 – Design Patterns – Padrões Estruturais 43 Definição de Padrões Estruturais 43 Padrão Adapter 44 Padrão Bridge 44 Arquitetura de Software 4 Padrão Decorator 46 Padrão Façade 47 Padrão Proxy 47 Exercícios do Capítulo 4 48 Capítulo 5 – Design Patterns – Padrões Comportamentais 48 Definição de Padrões Comportamentais 48 Padrão Chain of Responsability 49 Padrão Mediator 50 Padrão Observer 51 Padrão Strategy 52 Padrão Visitor 53 Exercícios do Capítulo 5 54 Considerações finais 55 Glossário de Siglas 58 Bibliografia 58 Arquitetura de Software 5 Apresentação Os Sistemas de Informação são provedores de solução para as mais diversas áreas do conhecimento e impulsio- nam a indústria, o comércio, os serviços e, em especial, segmentos de mercado dependentes de tecnologia ou mesmo novos negócios que surgem apoiados em software. Segundo Laudon (2010), empresas apoiam seus proces- sos de gestão nas tecnologias, com o objetivo de gerenciar suas operações, desenvolver novos produtos e serviços, es- treitar relacionamento com clientes e fornecedores, auxiliar na tomada de decisões e obter vantagem competitiva. A importância crescente do software, aliado ao maior conhecimento (desde 1967) sobre como construí-lo, resul- tou na necessidade de uma formação mais ampla para o programador. Este deve se preocupar em aplicar técnicas e métodos especializados para projetar, construir, testar e manter os produtos de software. Uma parte considerável destes conhecimentos pertence à área de Engenharia de Software. Após a “crise do software” uma longa série de inovações passaram a ser adotadas nas práticas de desenvolvimento, incluindo modularidade, programação estruturada, diagra- mas de fluxo de dados, proteção de informações (informa- tion hiding), abstração de dados, reutilização de softwa- re, programação visual, programação orientada a objeto, padrões de projetos, ferramentas CASE. Porém tudo isso trouxe ganhos modestos e não transformou a Engenharia de Software em algo sistemático, disciplinado e quantifi- cável para o desenvolvimento, operação e manutenção do software. A Engenharia de Software possui peculiaridades que tal- vez nenhuma outra área do conhecimento tenha. Isso nos faz refletir sobre quais competências um profissional que atue em desenvolvimento de sistemas de software tenha que adquirir. Assim, prezado aluno, esse material foi elaborado para chamar sua atenção e trazer uma reflexão sobre os prin- cipais aspectos que têm afetado diretamente a produção do software. Além disso, vamos apontar os princípios liga- dos à arquitetura e aos padrões de projeto que podem ser seguidos, de forma a trazer um diferencial na carreira do desenvolvedor de soluções em software, pois conhecer as dificuldades inerentes a esta área tornará mais fácil o tra- balho quando elas surgirem. Luciano Gaspar Elisamara de Oliveira Capítulo 1 – Fundamentos de Arquitetura de Software Caro aluno, neste capítulo abordaremos concei- tos iniciais sobre o projeto de arquitetura de software e as consequências de um software não arquitetado. Será discutido o papel do arquiteto de software, assim como as barreiras e princípios de modelagem que devem ser levados em consideração na concep- ção de uma arquitetura. Definição de Arquitetura de Software Caro aluno, para entendermos a necessidade de se ar- quitetar um software alguns conceitos serão introduzidos, assim como os desafios que um profissional desta área deverá lidar. Historicamente o número fracassos de projetos de sof- twares são da ordem de 84% de falhas e os fatores críti- cos de sucesso estão relacionados à natureza complexa e intangível do software. O software é visto pelas áreas de negócios como algo flexível e adaptável, porém sabemos que um software não arquitetado pode dificultar sua manutenção, escalabilida- de e reuso. Desta forma, desenvolver soluções arquitetadas é uma prática que tornará nosso trabalho, a longo prazo, menos reativo e estressante. Arquitetura de Software 6 Mas, o que é arquitetura de software? Bass et al (2003) definem arquitetura de sof- tware como a estrutura do sistema composta por elementos de software (componentes, conectores ou dados), com propriedades externamente visíveis destes elementos e os relacionamentos entre eles. Uma arquitetura registra informações sobre como os elementos de software se relacionam uns com os outros, ocultando ou explicitando elementos do software que de- vem ou não existir em diferentes níveis de abstração. As figuras 1 e 2 ilustram um projeto arquitetado e um não arquitetado. Reflita sobre as principais características entre eles. Figura 1: Bairro Planejado Fonte: http://blogdelancamentos-hbc.lopes.com.br/2009/05/ realize-seu-sonho-no-parque-dos-sonhos.html Figura 2: Crescimento desordenado Fonte: http://olhosinquietos.blogspot.com/2012/01/ crescente-e-diversificada.html Reflita: Os softwares que estamos desenvol- vendo são mais parecidos com a figura 1 ou com a figura 2? Nossas aplicações possuem um pa- drão arquitetural? São concebidos para aceitar novas funcionalidades? Permitem o reuso e es- calabilidade? Para aqueles que possuem vivência na área de de- senvolvimento de software sabem que muitas vezes uma mudança ou um novo requisito tem impacto estrutural e demanda grande esforço de desenvolvimento e é realizada sem planejamento desencadeando efeitos colaterais em todo software. Modelagem de aplicações de softwares Caro aluno, como estudado na disciplina Engenharia de Software e de Requisitos, um aplicativo possui um ciclo de vida. Ao longo deste ciclo muitas mudanças são realizadas e geram impactos no código escrito nas primeiras versões do software. O software é afetado por um fenômeno de degradação que impacta sua confiabilidade, estrutura e sua consistên- cia. Sua documentação é desatualizadadificultando sua manutenção, tornando-a onerosa. Sabemos que um processo de desenvolvimento defi- nido que favoreça a obtenção e validação dos requisitos pode minimizar esses impactos, porém o fato do software ser visto como algo flexível torna a definição de uma arqui- tetura um elemento fundamental para o desenvolvimento de software em larga escala. O uso de modelos apoiam o entendimento e definição da arquitetura do software, assim como a identificação das regiões críticas que podem degradar-se ao longo do tem- po. Se você já desenvolveu algum software ou até mesmo uma planilha eletrônica com várias referências a fórmulas em diferentes arquivos, já percebeu que existe um limite para a capacidade humana para compreender, ao longo do tempo, aquilo que foi produzido, tornando esta uma ativi- Arquitetura de Software 7 dade complexa.O software possui uma natureza complexa crescente seja pelo número de linhas de código ou pela sua intangibilidade. Logo, a criação de modelos torna-se indispensável para compreensão do que está sendo de- senvolvido. No processo de criação de modelos muitos problemas podem ser antecipados e decisões são tomadas a fim de minimizar seu impacto ao longo do tempo. Blaha e Rumbaugh (2006) definem modelo como uma abstração de algo que facilita seu en- tendimento antes de construí-lo. Abstração é um processo mental básico que permite lidar com a complexidade, omitindo detalhes não essenciais. A abstração permite a simplificação de algo complexo, como no exemplo na figura 3. Fonte: http://www.mundodastribos.com Fonte: http://paraconstruir.wordpress.com Figura 3: Abstração de uma casa No processo de produção do software, criam-se mode- los para descrever a estrutura e o comportamento de um software para posterior implementação. Estas descrições de modelos guiam a construção e mantém registros das decisões tomadas na sua concepção. Para os criadores da UML- Unified Modeling Language, Booch, Rumbaugh e Jacobson, nenhum modelo único é suficiente. Qualquer sistema não-trivial será melhor inves- tigado por meio de um conjunto de modelos quase inde- pendentes com vários pontos de vista. Um ou mais modelos podem servir de inspiração para dar origem a uma arquitetura que sustente as necessida- des do que está sendo modelado. De acordo com Zachman (1997) arquitetura é o conjunto de artefatos ou um descritivo relevante de um objeto, de forma que este possa ser construído de acordo com os requisitos (de qualidade), bem como mantido ao longo da sua vida útil. Neste sentido modelar um sistema significa de- terminar e representar um conjunto de informações arquitetadas sob diferentes vistas que servirão de guia de referência para a produção de algo concreto (código fonte). Cada área de conhecimento adota tipos específicos de modelos. Na engenharia de software contemporânea, se- gundo Booch, Rumbaugh e Jacobson (2006) adota-se uma perspectiva orientada a objetos, onde a UML é empregada para a visualização, a especificação, a construção e a do- cumentação de artefatos que orientam o desenvolvimento do software. Para entender a importância de controlar esta comple- xidade, no próximo tópico, vamos analisar o trabalho de Brooks (1987) que faz uma classificação dos aspectos que estão sob nosso controle e aqueles que fogem do controle impactando o cronograma, o custo e a equipe de projeto do software. Tarefas Acidentais e Essenciais Independentemente do processo de desenvolvimen- to de software adotado, um conjunto de tarefas são or- ganizadas e realizadas. Tais tarefas são classificadas por Brooks (1987) como tarefas acidentais e essenciais. • As tarefas acidentais estão relacionadas à im- plementação do software e as principais preocu- pações estão ligadas à sintaxe das linguagens, aos limites de hardware, aos ambientes e ferra- mentas de desenvolvimento e demais aspectos técnicos. Estes aspectos são facilmente superados com treinamentos, leituras ou a consulta a um profissional mais experiente. Arquitetura de Software 8 • As tarefas essenciais estão relacionadas ao processo mental de criação de um conjunto de conceitos que se interligam. Tanto as tarefas acidentais quanto as essenciais criam barreiras para o desenvolvimento de software, porém grande parte das barreiras acidentais foram transpostas na última década e as principais falhas de projetos estão relacionadas às atividades essenciais que criam barreiras que dificilmente são domináveis. De forma análoga, e neste contexto, pode-se comparar o processo de desenvolvimento de software ao processo de criação de um texto, onde as tarefas acidentais estão relacionadas ao domínio de uma ferramenta de edição de textos e a sintaxe e semântica da língua. Tais tarefas po- dem criar barreiras para a produção do texto, mas serão superadas com algum nível de estudo ou apoio de ter- ceiros, porém não garantem que o texto escrito atenderá critérios de qualidade. Logo, o domínio de tarefas acidentais não garante a qualidade do que está sendo produzido. A qualidade será definida pela forma peculiar de criação e organização das ideias atuando sobre a construção mental e essencial que serão descritos de forma textual. Aspectos essenciais na produção de software Brooks (1987) elenca quatro aspectos essenciais que impactam na produção do software, são eles: complexi- dade, conformidade, flexibilidade e intangibilidade. Estes aspectos são descritos a seguir. • Complexidade Entidades de software possuem uma natureza com- plexa e aumentar sua escala não é meramente repetir os mesmos elementos em tamanho maior. É necessário um aumento do número de elementos diferentes amplificando a complexidade do todo de forma não linear. Queremos dizer que existe uma grande diferença entre fazer um software com poucas linhas de código e desen- volver um software com um número maior de requisitos. Para um software mais robusto, não bastaria aumen- tar as linhas de código, teremos que incluir elementos de software para facilitar o entendimento das linhas já produ- zidas, a manutenção, a inclusão de novas funcionalidades, aumento da equipe, a padronização, inclusão de interfa- ces, dentre outras demandas que um software de maior escala exige. Imagine um artesão trabalhando na produção de um vaso de barro e você, de passagem em turismo pelo local, ado- rasse aquele vaso. Em função disso solicitasse que o artesão produzisse 1.000 unidades, pois presentearia seus familiares e venderia o restante dos vasos na sua cidade de origem. Reflita: O processo e as ferramentas de produ- ção adotados pelo artesão seriam suficientes para atender sua encomenda? Bastaria apenas aumen- tar em quantidade a matéria prima do artesão? Contratar mais artesões garantiria a beleza do vaso Arquitetura de Software 9 apreciada por você? O processo para produzir uma unidade é o mesmo para produzir 1.000 unidades? Acredito que chegará facilmente à conclusão que novos elementos deverão ser inseridos no processo de produção do vaso. Talvez o uso de formas para garantir o padrão, a contratação de novos artesões, uma sequência ordenada de tarefas, a criação de modelos que serão submetidos a testes, dentre outras ações. Agora reflita: O que diferencia a produção de um software de 1.000 linhas com um de 15.000 linhas? Será só a quantidade de linhas? Softwares com 1.000 linhas de códigos, no pior caso, podem ser refeitos gastando apenas mais alguns dias de trabalho; porém reescrever um sistema mais complexo le- varia meses ou anos. Portanto,cuidar da arquitetura no início reduz os problemas futuros. A figura 4 exibe os impactos da complexidade na pro- dução do software. Da complexidade vem a dificuldade de entender e se comunicar com os membros da equipe de desenvolvimento levando à deficiência do produto, que aumenta os custos, que afeta o cronograma e a confiabili- dade. Da complexidade da estrutura vem a dificuldade de entender o comportamento e ampliar os programas sem criar efeitos colaterais, tornando árdua a atividade de ge- renciar estes problemas. Figura 4: Impactos da complexidade no desenvolvimento de software Provavelmente muitos dos programadores já passaram por situações de não conseguir ou demorar para entender um código, seja ele gerado por terceiros ou até mesmo um código próprio. Sabe-se que a complexidade do código é crescente e existe um limite que o cérebro humano consegue geren- ciar, impactando na quantidade de novas linhas de código que podem ser acrescentadas a um programa ao longo do tempo. [BROOKS,1987] A figura 5 mostra a relação produtividade no desen- volvimento versus tempo. À medida que o software vai sendo implementado, ou seja, linhas de código são inseri- das, consequentemente sua complexidade crescente afeta a produtividade ao longo do tempo. Figura 5 - Tempo versus produtividade Fonte: Martin [2009] • Conformidade e flexibilidade Outras áreas do conhecimento também lidam com a complexidade crescente, mas, como o software não está suscetível às leis naturais, é visto como algo flexível e de fácil adequação. Pelo menos se comparado à Física e ou- tras ciências... Brooks (1997) afirma que, em decorrência da sua com- plexidade, a versão inicial de um software muitas vezes não atende aos requisitos na sua plenitude, necessitando de constantes mudanças, ou seja, que todo software de sucesso acaba por ser modificado. Assim, um sistema de software deve ser concebido para mudar. Caso você já atue na área de desenvolvimento de sof- tware, deve ter percebido que a mudança dos requisitos Arquitetura de Software 10 é algo constante. Isso não significa que as mudanças são correções de erros, mas podem decorrer de novas fun- cionalidades para atender às necessidades de negócios. Vale dizer que a TI deve impulsionar os negócios e não ser gargalo para novas oportunidades. Logo, caro aluno, precisamos desenvolver software no qual uma mudança não afete toda a estrutura já desenvolvida. Nosso código deve “aceitar” mudanças com certa fle- xibilidade, comunicar claramente suas responsabilidades, facilitar a manutenção e proporcionar o reuso. Esse é o grande desafio! • Intangibilidade Software é intangível, portanto, é difícil se criar uma representação visual objetiva e comum para ele. Ao tentar diagramar uma estrutura de software, descobre-se que ela não é apenas um, mas sim, vários diagramas superpostos um aos outros, sem hierarquias ou relações diretas entre seus elementos forçando cortes que eliminam conexões nas diferentes vistas do modelo. Para Brooks (1987) esses cortes prejudicam não só o processo de projeto do software, mas também a comunicação entre os membros da equipe. Vocês já estudaram a UML - Unified Modeling Language, na disciplina “Análise e Modelagem de Objetos”. Como viram, essa linguagem é uma poderosa ferramenta para tangibilizar as descrições de implementação do arquiteto de software. Um arquiteto de software deve apoiar-se em descrições de modelos para comunicar suas decisões de implementação. Um diagrama UML, analogamente, pode ser comparado com uma planta hidráulica ou elétrica que um engenheiro civil ou eletricista utiliza para tangibilizar um modelo mental e comunicar seu projeto. Portanto, a descrição de modelos de software apoiados em diagramas é uma ferramenta essencial para um arquiteto de software e um dos elementos que o difere do programador. UML (Unified Modeling Language) - Um breve histórico A UML surgiu da união de três metodologias de modelagem: o método do americano Grady Booch, o método OMT (Object Modeling Technique) do sue- co Ivar Jacobson e o método OOSE (Object-Oriented Software Engineering) do americano James Rum- baugh. Estas eram até meados da década de 1990, as três metodologias de modelagem orientada a ob- jeto mais populares. A união dessas tecnologias con- tou com o apoio da Rational Software, que incentivou e financiou a união das três metodologias. O esforço inicial do projeto começou com a união do método de Booch com o método OMT de Jacob- son, o que resultou no lançamento do Método Unifi- cado no final de 1995. Logo em seguida, Rumbaugh juntou-se a Booch e Jacobson na Rational Software e seu método OOSE começou a ser incorporado à nova metodologia. O trabalho de Booch, Jacobson e Rumbaugh conhecidos popularmente como "os três amigos", resultou no lançamento, em 1996, da pri- meira versão da UML propriamente dita. Assim que a primeira versão foi lançada, diver- sas grandes empresas atuantes na área de software passaram a contribuir com o projeto, fornecendo su- gestões para melhorar e ampliar a linguagem. Final- mente a UML foi adotada pela OMG (Object Manage- ment Group) em 1997, como a linguagem padrão de modelagem. Atualmente a UML está na versão 2.0. Fonte: http://www.dsc.ufcg.edu.br/~sampaio/cursos/2007.1/ Graduacao/SIII/Uml/historia_uml/historia_uml.htm Antes de prosseguir, convém você recordar o que é o paradigma orientado a objetos (OO) e alguns de seus con- ceitos mais importantes. Volte ao material da disciplina“Análise e Modelagem de Objetos” e leia o quadro Saiba Mais que se segue. Arquitetura de Software 11 Princípios SOLID Em 1995 Robert C. Martin iniciou uma discussão so- bre um conjunto de princípios de modelagem de software orientado a objetos. Estes princípios ajudavam a lidar com os problemas oriundos da natureza do software discutidos até aquele momento. Booch, Rumbaugh e Jacobson (2006) definem que, em OO, “responsabilidade é um contrato ou obrigação de um tipo ou classe”. Os autores afirmam que há dois tipos de responsabilidades dos objetos: • De conhecimento (knowing): sobre dados privati- vos e encapsulados; sobre objetos relacionados; sobre coisas que pode calcular ou derivar. • De realização (doing): em fazer alguma coisa em si mesmo; iniciar uma ação em outro objeto; con- trolar e coordenar atividades em outros objetos. Responsabilidades são atribuídas aos objetos durante o projeto do software OO. A tradução de responsabilida- des em classes e métodos depende da granularidade da responsabilidade. Os métodos são implementados para cumprir responsabilidades. Uma responsabilidade pode ser cumprida por um único método ou por uma coleção de métodos trabalhando em conjunto. Responsabilidades do tipo knowing geralmente são inferidas a partir do modelo conceitual (são os atributos e relacionamentos). Um dos pontos que levam à degradação do código ao longo do tempo é o alto acoplamento entre os objetos (que é o foco nesta disciplina) que deve ser gerenciado, reduzindo a dependência entre eles. No paradigma orientado a objetos uma das principais preocupações é o acoplamento. Um acoplamento pode ocorrer de diferentes formas. O acoplamento pode ocorrer quando: • uma classe A possui um atributo que referencia o objeto B ou a própria classe B; • um objeto A chama um método de um objeto B; • um objeto A tem um método que referencia um objeto B ou a própria classe B, tipicamente carac- terizado por um parâmetro ou variável local do tipo B ou um objeto retornado de uma mensagem sendouma instância de B. Tais formas de acoplamento podem ser mitigadas com mudanças no código fonte. Uma boa prática no desenvol- vimento de software OO é criar estruturas com baixo acopla- mento entre objetos para que a atribuição de responsabi- lidades seja feita de forma que sua alocação não aumente o acoplamento de um objeto com outros. Ainda dentro de um projeto OO, existe outro conceito mui- to importante que é a coesão. Coesão é uma medida de quão fortemente estão relacionadas e focadas as responsabilidades de um dado elemento. Um elemento que esteja altamente especializado e que não realize uma grande quantidade de tarefas é considerado com alta coesão, ou seja, possui um alto grau de coesão. Assim, uma classe com baixa coesão, geralmente exe- cuta muitas funções pouco relacionadas entre si, realizan- do um trabalho excessivo. Classes deste tipo são altamen- te indesejáveis num projeto, pois acumulam os seguintes problemas: • são de difícil compreensão; • não conseguem ser reutilizadas; • são de difícil manutenção; • são constantemente afetadas por qualquer modi- ficação no projeto. Baixo acoplamento (low coupling) e alta co- esão (high cohesion) são conceitos relevantes que devem ser considerados e preservados sempre du- rante os processos de tomada de decisão em um projeto orientado a objetos. São conceitos que estão intimamente ligados ao desenvolvimento de softwa- res que priorizam uma arquitetura que favorece a manutenção e a construção de objetos reusáveis. Arquitetura de Software 12 O gerenciamento de dependência entre objetos é um problema que certamente já foi enfrentado por quem desenvolve ou desenvolveu um aplicativo OO. Não se preocupar com o gerenciamento de dependência leva a um código confuso, difícil de mudar e não reutilizável. Os princípios abaixo concentram-se na gestão de de- pendências dos objetos de um sistema OO e são conheci- dos como SOLID. São estes os princípios SOLID: S Single Responsability Principle (Princípio de Res- ponsabilidade Única) O Open Close Principle (Princípio Aberto-fechado) L Liskov Substitution Principle (Princípio de Substi- tuição de Liskov) I Interface Segregation Principle (Princípio de Se- gregação de Interface) D Dependency Inversion Principle (Princípio Inver- são de dependência) Cada um destes princípios será detalhado no que se segue. Princípio de Responsabilidade Única O Princípio de Responsabilidade Única, também conhe- cido como SRP - Single Responsability Principle estabelece que uma classe deve ter um e somente um motivo para mudar. Se uma classe é responsável por efetuar várias ações dentro de um determinado contexto, ela está ferindo este princípio. Vamos analisar o exemplo: A classe Retangulo da figura 6 possui os métodos Area () que calcula a área do retângulo e Desenhar()que desenha o retângulo. Essa classe fere o princípio SRP, pois se a forma de cálculo for alterada ou uma interação com a interface gráfica tiver que ser alterada, ambas afetam a classe Retangulo. Ou seja, as linhas de código escritas nesta classe possuem duas formas de serem impactadas. Figura 6: Classe Retangulo Para atender o princípio SRP devemos separar as res- ponsabilidades em duas classes diferentes, sendo uma para calcular a área e outra para desenhar o retângulo. Neste caso teremos as classes RetanguloDes e RetanguloCal, cada uma com seus métodos, conforme mostra a figura 7: Figura 7: Classes para cálculo da área e desenho de retângulos Princípio Aberto-Fechado O princípio Aberto-Fechado ou simplesmente OCP- Open Close Principle, estabelece que uma classe deve estar “aberta” para extensão, porém fechada para modifi- cação, ou seja, devemos organizar as classes para possibi- litar o crescimento, porém sem alterar o código das classes existentes. Vejamos o exemplo da figura 8: Figura 8: Classe Pagamento Arquitetura de Software 13 A classe Pagamento possui os métodos que têm as instruções para pagamentos dos tipos Parcelado, Avista, Debito e Credito. Como você implementaria isso? Certamente em determinado trecho de código utilizaria uma instrução IF ou CASE e de acordo com a forma de pagamento selecionado pelo usuário chamaria um método específico. Caso você venha desenvolvendo software desta forma, lembre-se que o princípio OCP está sendo ferido. O resultado em não respeitar este princípio é que, para cada nova forma de pagamento, o código da classe Pagamento deverá ser alterado com a inclusão do novo método de pagamento e a inclusão de mais um parâmetro na instrução IF ou CASE. Para atender o princípio OCP deve-se separar as formas de pagamento em sub-classes. Desta forma, uma nova forma de pagamento não afetaria a classe Pagamento, ou seja, o código estaria fechado para alteração e aberto para extensão. A figura 9 ilustra simplificadamente as classes para atender o OCP, neste exemplo. Figura 9: Classes e sub-classes para formas de pagamento Aplicando o princípio Aberto-Fechado, os problemas apontados são evitados, porque a classe Pagamento não pre- cisa mais ser alterada quando uma nova forma de pagamento for inserida, basta a inclusão de uma subclasse com a nova forma de pagamento com os métodos específicos deste tipo de pagamento. Desta forma as classes serão mais simples e não estarão sobrecarregadas de atribuições. Princípio de Substituição de Liskov O princípio de Substituição de Liskov, ou simplesmente LSP - Liskov Substitution Principle, estabelece que as classes derivadas devem ser substituídas por suas classes base. Se utilizarmos um objeto e, através do uso de polimorfismo, manipulá-lo como sendo do seu tipo base, ele deve funcionar e se comportar da mesma forma como se comportaria se ele realmente fosse daquele tipo. Retomando o exemplo ilustrado na figura 9 temos uma classe Pagamento (base) e subclasses derivadas (Parcelado, Avista, Debito e Credito). Respeitar o princípio LSP significa dizer que posso usar qualquer classe derivada como se fosse a classe Base Pagamento, sem alterar o comportamento da classe base. Arquitetura de Software 14 Princípio Segregação de Interface O princípio de Segregação de Interface ou ISP- Interface Segregation Principle estabelece que interfaces sejam de “fina granularidade”, para que sejam específicas para quem vai utilizá-las. Uma interface não deve ter inúmeras funcio- nalidades. Deve ser o mais “enxuta” possível, seguindo o princípio SRP, porém voltado para a interfaces. Princípio de Inversão de Dependência Com o objetivo de reduzir o acoplamento entre objetos o Princípio de Inversão de Dependência ou DIP- Dependency Inversion Principle estabelece que sempre devemos depender de classes abstratas e nunca de classes concretas. Se um objeto depender de classes concretas, qualquer alteração que ocorrer nesta classe, afeta todas que dependerem dela. Observe a figura 10, elaborada com o software BlueJ (www.bluej.org), que mostra 4 classes distintas, cuja relação entre elas se dá na forma de classes concretas. Figura 10: Relação entre Classes A figura 11 representa, por meio de marcações hachuradas, as classes que são afetadas quando a classe Canvas é alterada. Observe que uma alteração em Canvas afeta todas as demais classes relacionadas a ela. Figura 11: Classes afetadas após alteração em Canvas Arquitetura de Software 15 A figura 12 representa uma implementação onde existe uma relação entre as classes, porém todas dependem da classe abstrata Figure. Observe que esta classe impede a propa gação da alteração realizada em Canvas. Figura 12: Diagrama com classe abstrata Ouça o podcast sobre princípios SOLID, dispo- nível em: http://podcast.dotnetarchitects.net/2009/11/podcast-8-principios-s-o-l-i-d/ Polimorfismo e Herança em OO Polimorfismo: significa que a mesma operação pode atuar de modos diversos em classes diferen- tes. Uma operação é uma ação ou transformação que um objeto executa ou a que ele está sujeito. Right-justify (justificar à direita), display (exibir) e move (mover) são exemplos de operações. A operação move (mover), por exemplo, pode atuar de modo diferente nas classes Janela e Peça de Xadrez. Uma implementação específica de uma opera- ção por uma determinada classe é chamada de método. Quando uma operação baseada em obje- tos é polimórfica, pode haver mais de um método para a sua implementação. No mundo real uma operação é simplesmen- te uma abstração de um comportamento análo- go entre diferentes tipos de objetos. Cada objeto "sabe” como executar suas próprias operações. Entretanto, uma linguagem de programação ba- seada em objetos seleciona automaticamente o método correto para implementar uma operação com base no nome da operação e na classe do objeto que esteja sendo operado. O usuário de uma operação não precisa saber quantos métodos existem para implementar uma determinada ope- ração polimórfica. Novas classes podem ser adi- cionadas sem que se modifique o código existen- te, são fornecidos métodos para cada operação aplicável nas novas classes. Herança: é o compartilhamento de atributos e operações entre classes com base num relaciona- mento hierárquico. Uma classe pode ser definida de forma abrangente e depois ser refinada em sucessivas subclasses mais definidas. Cada sub- classe incorpora, ou herda, todas as proprieda- des da sua superclasse e acrescenta suas próprias e exclusivas características. As propriedades da superclasse não precisam ser repetidas em cada subclasse. Por exemplo, Janela Rolante e Janela Fixa são subclasses da superclasse Janela. Estas duas subclasses herdam as propriedades de Ja- nela, como uma região visível na tela. Janela Ro- lante acrescenta uma barra de rolagem e limites de rolagem. A capacidade de identificar proprie- dades comuns a várias classes de uma superclas- se comum e de fazê-las herdar as propriedades da superclasse pode reduzir substancialmente as repetições nos projetos e programas e é uma das principais vantagens dos sistemas baseados em objetos. Fonte: [BLAHA ; RUMBAUGH, 2006] Arquitetura de Software 16 Exercícios do Capítulo 1 1 – Descreva brevemente como uma mudança de re- quisitos pode afetar o projeto arquitetural de um software. 2 – Como os princípios SOLID contribuem para evitar a degradação do código fonte? 3 – O Princípio de Responsabilidade Única contribui para a organização e entendimento do código fonte? Explique. 4 – Quais recursos um arquiteto de software pode utili- zar para tangibilizar a arquitetura de um software? 5 – Explique porquê consideramos que um software possui a complexidade crescente. 6 – O que significa dizer que um conjunto de classes de um projeto de software está fechado para altera- ção e aberto para extensão? Capítulo 2 – Padrões de Arquitetura de Software Caro aluno, neste capítulo descreveremos os padrões arquiteturais e exemplos de aplicação serão apresentados, bem como os benefícios da sua utilização em diferentes casos. Definição de Padrão Arquitetural Caro aluno, um padrão arquitetural determina a estru- tura de um projeto de software. Portanto, se trata de um conceito amplo que aborda questões como limitação de hardware, alta disponibilidade de uso e risco de negócio [BUSCHMANN et al, 1996]. Como sabemos, o desenvolvi- mento de algoritmos visa resolver problemas com o auxílio do computador. Já houve uma época em que os programa- dores tinham muita dificuldade com a escrita e compilação do código. Esta dificuldade já foi superada com a ajuda de ferramentas que auxiliam o programador na sintaxe e semântica das linguagens de programação. Fonte:http://cebracnailha.blogspot.com/2011_04_01_archive.html Temos agora um problema de segunda ordem que está relacionado à como organizar as linhas de código. Muitas vezes sabemos quais linhas de código atenderão um de- terminado requisito de negócio, porém ainda precisamos saber qual a melhor organização das linhas de código que evitará a degradação da aplicação. O uso de padrões ar- quiteturais pode ser um dos direcionadores desta orga- nização. Um único padrão pode auxiliar na solução das necessidades ligadas à organização do código ou pode-se usar uma combinação destes padrões. Vale lembrar que o conceito de padrões arquiteturais diferencia-se de padrões de projetos e ambos são assun- tos tratados neste material de ensino. Arquitetura de software é um conjunto de decisões significativas sobre a organização de um sistema, a seleção dos elementos estruturais e das suas interfaces, junto ao seu comportamento espe- cificado nas colaborações entre esses elementos, a composição desses elementos estruturais e com- portamentais em subsistemas mais abrangentes, e o estilo arquitetural que guia essa organização – esses elementos e suas interfaces, suas colabora- ções e sua composição. [BOOCH et al., 1999] Arquitetura de Software 17 De uma maneira mais simplificada, Pressman (2010) define arquitetura de software como “estrutura do sistema que abrange os componentes de software, as propriedades externamente visíveis destes componentes e as relações entre eles”. As seções a seguir descrevem os principais padrões arquiteturais, suas vantagens e desvantagens. Vale lembrar que existem muitos outros padrões possíveis, simples ou compostos, mas vamos nos ater aos mais utilizados nesta abor- dagem. Padrão de Arquitetura em Camadas De acordo com Buschmann (1996), camadas são grupos de componentes reutilizáveis, similares e inter-relacionados, responsáveis por um nível de abstração particular, ou seja, as camadas executam tarefas específicas da aplicação consumindo e fornecendo recursos entre si. • Objetivo Este padrão tem por objetivo decompor a aplicação em módulos reutilizáveis, organizados por funcionalidades espe- cíficas, como por exemplo, acesso a dados, lógica de negócio, construção da interface etc. • Contexto São mais utilizados em sistemas grandes e complexos que necessitam de decomposição, pois frequentemente são compostos por operações de baixo e alto nível. Deste modo, o agrupamento de tarefas comuns aumenta a escalabilida- de e facilita a manutenção de camadas distintas. • Estrutura Cada camada pode ser definida pela sua função e pelos vínculos que ela mantém com as outras camadas da apli- cação. A estrutura desta arquitetura pode ser dividida em N-camadas, de acordo com a necessidade da aplicação. No entanto, o padrão mais utilizado é o de 3 camadas: interface com o usuário, lógica de negócio e acesso a dados. A figura 13 ilustra este modelo. Figura 13: Modelo de arquitetura em 3 camadas Arquitetura de Software 18 • Aplicabilidade Caro aluno, o padrão de arquitetura em camadas deve ser utilizado quando: • Tarefas similares podem ser agrupadas para facilitar a manutenção; • A manutenção de um componente não deve afetar os outros; • As partes do sistema podem ser substituídas de modo independente; • Há a possibilidade de utilizar recursos do sistema atual em projetos futuros; • Componentes complexos precisam ser decompostos; • O limite entre os componentes é bem definido. • Consequências Vantagens: • Boa reusabilidade devido ao encapsulamento; • Suporte à padronização com a criação de frameworks; • As dependências são restritas à camada; • Recursos intercambiáveis entre aplicações distintas. Desvantagens: •Queda de desempenho proporcional ao número de camadas; • Alterações de comportamento podem provocar efeito cascata e causar gargalos. • Exemplo de aplicação Considere o seguinte cenário: uma empresa possui diversas bases de dados alimentadas de modo independente e deseja fornecer informações processadas por uma única regra de negócio para diferentes plataformas de acesso. Neste caso a arquitetura em 3 camadas pode ser implementada permitindo o desenvolvimento de componentes espe- cíficos para bases distintas, interfaces adequadas para cada dispositivo e uma regra de negócios centralizada e comparti- lhada, conforme ilustrado na figura 14. Arquitetura de Software 19 Figura 14: Arquitetura em camadas para o exemplo de múltiplas bases e múltiplas plataformas. Padrão de Arquitetura Pipes and Filters ou Pipeline Caro aluno, o padrão arquitetural Pipes and Filters, também denominado Pipeline, permite um processamento sequencial através de etapas encapsuladas em componentes chamados Filters que, por sua vez, são acoplados por meio de conexões conhecidas como Pipes. [BUSCHMANN, 1996] A figura 15 ilustra este padrão. Figura 15: Arquitetura Pipes and Filters Arquitetura de Software 20 • Objetivo O padrão tem por objetivo decompor o sistema em etapas independentes com o propósito de reutilizar esses módulos separadamente e facilitar a manutenção. • Contexto Sistemas que processam sequências de dados e exe- cutam a mesma operação várias vezes, podem fazer uso deste padrão para encapsular tarefas e reutilizá-las como etapas independentes na mesma pipeline ou em outras. • Estrutura De acordo com Buschmann (1996), e conforme ilustra- do na figura 15, a estrutura deste padrão é composta da seguinte forma: • Filters: são componentes responsáveis por trans- formar dados de entrada. O processamento de um filter deve depender apenas desses dados, a fim de permitir sua utilização no desenvolvimento de outros sistemas; • Pipes: são as conexões entre Filters, e são res- ponsáveis pela transferência de dados e pela sin- cronização entre os componentes acoplados; • Data Source: fonte de dados sequenciais padro- nizados; • Data Sink: processo responsável por coletar o re- sultado final da sequência de processamento rea- lizada pelos Filters. • Aplicabilidade Caro aluno, o padrão Pipes and Filters pode ser aplicado nas seguintes condições: • Dados de entrada e saída padronizados; • Necessidade de processar dados sequenciais; • Etapas paralelas não devem compartilhar infor- mação; • Deve ser viável realizar atualizações através de substituição parcial ou recombinação de Filters. • Consequências Vantagens: • Reutilização de Filters em aplicações distintas; • Flexibilidade através da troca e recombinação de Filters; • Possibilidade de processamento paralelo. Desvantagens: • Compartilhamento de estado intricado; • Complexidade no tratamento de erros em casca- ta; • Perda de desempenho no processamento dos da- dos em sequencias com muitas etapas. • Exemplo de aplicação Considere o seguinte cenário: um banco realiza diversas transações financeiras através do processamento de arqui- vos texto padronizados. Cada transação possui uma confi- guração específica para os dados de entrada. No entanto, várias operações são comuns em transações distintas. Neste exemplo, toda entrada de dados será realizada através de arquivos texto, portanto, podemos utilizar um único componente para “Leitura de Arquivos”. Contudo, as regras de negócio para cada transação são independentes e devem ser empregados componentes específicos confor- me a necessidade. Em uma etapa seguinte todas as transações geram re- latórios através de outro componente compartilhado. Por fim, o componente de “Leitura de Arquivos” é utilizado novamente para processar o conteúdo dos relatórios e dis- ponibilizá-lo ao Data Sink. A figura 16 ilustra este exemplo. Arquitetura de Software 21 Figura 16: Arquitetura Pipes e Filters para transação financeira com múltiplas entradas e processos compartilhados. Acesse o link e saiba mais sobre o padrão arquitetural Pipes and Filters. http://elemarjr.net/2011/03/22/architectural-patterns-pipes-and-filters/ Padrão de Arquitetura Blackboard Caro aluno, o padrão Blackboard é utilizado para tratar problemas não determinísticos, como por exemplo, sistemas de Inteligência Artificial e Reconhecimento de Padrões. Neste padrão arquitetural, de acordo com Buschmann (1996), diversos subsistemas unem seus conhecimentos para gerar uma possível solução parcial ou aproximada. Algoritmo determinista: o resultado de cada operação é definido de forma única. Algoritmo não-determinista: capaz de escolher uma dentre as várias alternativas possíveis a cada passo. Algoritmos não-deterministas contém operações cujo resultado não é unicamente definido, ainda que limitado a um conjunto especificado de possibilidades. • Objetivo O objetivo do padrão arquitetural Blackboard, é dividir um problema não determinístico entre subsistemas especia- lizados para solucionar o objetivo de modo cooperativo. Arquitetura de Software 22 • Contexto Este padrão pode ser aplicado em domínios imaturos ou complexos, compostos por diversos fatores sem solu- ção algorítmica conhecida ou viável. • Estrutura Este padrão é composto pelos seguintes itens: • Blackboard: central de armazenamento de dados; as possíveis soluções e os dados de controle são armazenados aqui. • Fontes de conhecimento: subsistemas indepen- dentes que resolvem aspectos específicos do pro- blema. Nenhum deles pode resolver a tarefa do sistema sozinho, uma solução global só pode ser construída através da integração dos resultados de várias fontes de conhecimento. • Central de controle: Monitora as alterações no Blackboard, coordena as funções das Fontes de Conhecimento e decide a tomada de ações de acordo com a estratégia da aplicação. A estratégia é definida de acordo com as informações obtidas sobre o domínio. • Aplicabilidade Caro aluno, o padrão Blackboard pode ser aplicado nas seguintes condições: • O problema possui dados incertos e admite solu- ções aproximadas; • A pesquisa completa do espaço de soluções possí- veis não é viável em um tempo razoável; • O problema global pode ser resolvido através de soluções parciais, seguindo a abordagem “dividir para conquistar”; • Os dados de entrada e saída, parcial ou global, têm representações distintas e os algoritmos de- vem ser implementados de acordo com paradig- mas específicos. • Consequências Vantagens: • Em domínios imaturos há a possibilidade de expe- rimentar diferentes algoritmos para mesma subta- refa sem afetar as demais; • Algoritmos disjuntos induzem a aplicação de pa- ralelismo potencial, ou seja, as fontes de conheci- mento podem ser exploradas em paralelo, porém, o acesso a central de dados deve ser sincronizado e compartilhado; • Torna possível a experimentação com algoritmos distintos e também permite que diferentes heurís- ticas de controle sejam empregadas; • Suporta mutabilidade e manutenção, porque as fontes de conhecimento, a central de controle e a estrutura de dados central são rigorosamente separadas; • As fontes de conhecimento independentes são es- pecializadas em tarefas específicas e podem ser reutilizadas em outras aplicações; • Tolerância a falhas e conclusões duvidosas. Desvantagens: • Testes complexos, devido à dificuldade de repro- duzir resultados não determinísticos; • Não há garantia de uma solução ótima; • Dificuldade para estabelecer uma boa estratégia de controle; • Baixo desempenhocomputacional; • Grande esforço no processo de desenvolvimento; • Não suporta paralelismo integral; • Exemplo de aplicação Considere o seguinte cenário: uma aplicação de reco- nhecimento de voz deve interpretar comandos, reconhecer Arquitetura de Software 23 o usuário e executar ações. Neste contexto são empregados agentes distintos com as seguintes funções: interpretação de palavras isoladas; interpretação de comandos compostos como frases; reconhecimento de sinal de voz. Este problema pode ser modelado da seguinte forma: um codificador repassa o sinal para um agente de reco- nhecimento, que por sua vez, verifica as permissões de acesso para o usuário. Caso o acesso seja liberado, o sinal é encaminhado para o interpretador de palavras, que transforma o sinal em texto e envia o conjunto de palavras para a verificação de comandos compostos. Nesta etapa um agente verifica se o padrão formado pelo conjunto de palavras extraídas do sinal é compatível com algum comando armazenado na estrutura de dados central. Esta sequência de controle pode ser induzida através de heurística ou inferida com o auxílio de algoritmos de aprendizado. A figura 17 ilustra este exemplo. Figura 17: Arquitetura Blackboard para reconhecimento de comandos de voz. Model-View-Controller (MVC) O padrão MVC é um modelo de camadas específico que divide a aplicação em três componentes: • o Model, ou Modelo, que contém as funções básicas e o acesso aos dados; • a View, ou visualizador, que exibe os dados para o usuário; e Arquitetura de Software 24 • o Controller, ou controlador, que gerencia a inte- ração entre as entradas do usuário e os dados do sistema. • Objetivo O objetivo do padrão MVC é garantir a coerência entre a interface do usuário e o modelo de dados da aplicação. • Contexto As aplicações interativas com uma interface homem- -computador flexíveis, podem fazer uso deste padrão ar- quitetural. • Estrutura Este padrão é composto da seguinte forma, de acordo com Buschmann (1996): • Model: encapsula o acesso aos dados e funções básicas da aplicação, fornecendo ao usuário pro- cedimentos que executam tarefas específicas; • View: exibe para o usuário os dados fornecidos pelo controle e estabelece uma interface para in- teração entre o usuário e a aplicação; • Control: interpreta eventos de entrada e envia re- quisições para o modelo de dados. Em seguida, processa os dados carregados a partir do modelo e envia para o visualizador. • Aplicabilidade Caro aluno, o padrão MVC é muito flexível e pode ser aplicado em diversas situações. Como, por exemplo, nos casos em que: • O projeto da interface deve ser desenvolvido se- paradamente; • A mesma informação deve ser exibida em formas diferentes; • A interface e o comportamento da aplicação de- vem refletir os dados do modelo em tempo real; • Alterações de interface devem ser simples e per- mitir mudanças em tempo real; • Haja necessidade de implementar um mecanismo de propagação de mudança para manter a coe- rência entre o modelo e a interface; • Seja necessário suportar diferentes plataformas sem a necessidade de alterar a base da aplicação. • Consequências Vantagens: • Múltiplas interfaces para o mesmo modelo; • Mecanismo de propagação de alteração entre o modelo e a interface; • Interfaces e controladores intercambiáveis em tempo real; • Criação de um possível Framework. Arquitetura de Software 25 Desvantagens: • Aumento de complexidade; • Propagação de atualizações excessiva; • Alta dependência entre interface e controlador: • Interfaces e controladores podem ser altamente dependentes do modelo; • Interfaces e controladores podem ser altamente dependentes da plataforma; • Ineficiência de acesso a dados através de interfaces com múltiplas requisições. • Exemplo de aplicação Considere um sistema de gerenciamento que atende todos os departamentos de uma determinada empresa, da produção até a presidência. Vários funcionários fornecem e consomem informações simultaneamente através de plata- formas e dispositivos distintos, como computadores, celulares e tablets. Porém, para cada setor as informações devem ser visualizadas da forma mais conveniente. Ou seja, os operadores têm acesso a informações específicas do seu tra- balho, os gestores controlam planilhas detalhadas da sua equipe e a diretoria visualiza apenas os balancetes. A figura 18 ilustra esta situação. Figura 18: Arquitetura MVC aplicada à modelagem de um sistema de gerenciamento com base compartilhada e visualização personalizada. Arquitetura de Software 26 Acesse o link e veja um simples exemplo de implementação em Java. http://www.dsc.ufcg.edu.br/~jacques/cur- sos/map/html/arqu/mvc/mvc.htm Para ver um exemplo em C# acesse: http://www.macoratti.net/10/07/asp_mvc1. htm Padrão de Arquitetura Microkernel O padrão arquitetural Microkernel se aplica a sistemas de software que devem ser capazes de se adaptar às ne- cessidades de mudança do sistema. Ele separa um núcleo funcional mínimo de recursos estendidos e partes específi- cas. Este padrão também serve como um gerenciador para conectar essas extensões e coordenar a sua colaboração. [BUSCHMANN, 1996] • Objetivo O padrão Microkernel visa permitir o desenvolvimento de várias aplicações que utilizam interfaces de programa- ção semelhantes e que compartilham as mesmas funcio- nalidades. • Contexto Aplicações baseadas em módulos independentes po- dem utilizar o padrão Microkernel para gerenciais recursos adicionais. • Estrutura A estrutura deste padrão é composta da seguinte forma: • Microkernel: é o principal componente deste padrão. Ele implementa serviços centrais como comunicação e gerenciamento de recursos. Os módulos acoplados ao sistema podem utilizar as funcionalidades forne- cidas pelo Microkernel. • Servidores internos: componentes adicionais que estendem as funcionalidades do Microkernel. Ser- vidores internos podem, portanto, encapsular al- gumas dependências no hardware subjacente ou sistema de software. • Servidores externos: componentes que utilizam os recursos do Microkernel para executar suas próprias interfaces. • Clientes: aplicativos associados a um servidor ex- terno. Eles só acessam os recursos disponibiliza- dos pelo servidor. • Adaptadores: proporcionam uma interface entre clientes e servidores externos, permitindo que os clientes acessem os serviços fornecidos indepen- dentemente da plataforma. • Aplicabilidade Caro aluno, o padrão Microkernel pode ser aplicado nos seguintes casos: • A aplicação deve suportar módulos diferentes em uma única plataforma; • Os módulos podem ser categorizados em grupos que usam o mesmo núcleo funcional de diferentes maneiras; Arquitetura de Software 27 • A plataforma de aplicações deve lidar com o hardware e contínua evolução do software; • A plataforma de aplicação deve ser portável, extensível e adaptável para permitir uma fácil integração de tec- nologias emergentes; • O núcleo funcional da aplicação deve ser separado em um componente com tamanho mínimo, e os módulos devem ser adicionados conforme a necessidade. • Consequências Vantagens: • Portabilidade: na maioria dos casos apenas o Microkernel precisa ser reescrito e alterações de hardware deman- dam modificações apenas em suas dependências específicas; • Flexibilidade e extensão: uma das maiores vantagens desta arquitetura é a capacidade de extensão e adapta- ção do sistema através da inclusão de novos módulos sem a necessidade de alterações no núcleo; • Separação de mecanismos e políticas: o Microkernel controla apenasos mecanismos básicos e permite que os módulos implementem suas políticas específicas; • Escalabilidade: altamente adaptável em sistemas distribuídos; • Confiabilidade: a tolerância a erros pode ser facilmente suportada porque os sistemas distribuídos permitem que se ocultem as falhas de um usuário; • Transparência: em sistemas distribuídos a arquitetura Microkernel permite que cada componente acesse outros serviços sem a necessidade de saber a sua localização. Desvantagens: • Desempenho: softwares monolíticos com foco específico são mais eficientes que a arquitetura Microkernel; • Complexidade de concepção e implementação: a separação entre mecanismos e políticas requer um profundo conhecimento de domínio e um esforço considerável durante a análise de requisitos. Além de exigir uma espe- cificação meticulosa dos recursos disponibilizados pelo Microkernel. • Exemplo de aplicação Suponha que você pretende desenvolver um novo sistema operacional para celulares que deverá atender os seguintes requisitos: fácil portabilidade para qualquer aparelho, integração simplificada de novas aplicações e possibilidade de executar aplicativos de outros sistemas similares. Arquitetura de Software 28 Figura 19: Arquitetura Microkernel aplicada ao projeto de um sistema operacional Neste caso você deverá implementar uma estrutura elementar mínima que permita a expansão dos recursos com a inclusão de módulos. A execução de aplicativos externos poderá ocorrer através de adaptadores ou emuladores, que tenham acesso aos recursos do núcleo principal do sistema operacional. A figura 19, ilustra a estrutura deste exemplo. Acesse o link (em inglês) e veja um simples exemplo de implementação em Java. http://www.vico.org/pages/PatronsDisseny/Pattern%20MicroKernel/ Leia o artigo de Elemar Jr Architectural Patterns: Microkernel, publicado em 17/03/2011 em http://elemarjr.net/2011/03/17/architectural-patterns-microkernel/ Arquitetura de Software 29 Padrão de Arquitetura Reflection O padrão Reflection fornece um mecanismo para alte- rar a estrutura e o comportamento de sistemas de forma dinâmica. Neste padrão a arquitetura é divida em duas partes. Um nível meta, que provê informações sobre as propriedades do sistema. E um nível base que inclui a ló- gica da aplicação. Alterações realizadas em informações contidas no nível meta afetam o comportamento do nível base. [BUSCHMANN, 1996]. • Objetivo O padrão Reflection visa à criação de sistemas que suportem a sua própria modificação sem a necessidade de alterar a estrutura lógica da aplicação. • Contexto Sistemas que dependem de adaptações frequentes po- dem implementar este padrão arquitetural para facilitar o processo de modificação. • Estrutura Este padrão é composto pelos seguintes itens: • Nível Base: implementa a lógica da aplicação. Seus componentes representam os serviços fornecidos pelo sistema, o modelo de dados e a interface de usuário. E também específica a comunicação en- tre estas estruturas. • Nível Meta: é composto por um conjunto de ob- jetos que encapsulam informações específicas sobre um único aspecto da estrutura, comporta- mento ou estado do Nível de Base. • Aplicabilidade Caro aluno, o padrão Reflection pode ser aplicado nos seguintes casos: • Adaptações constantes; • Possibilidade de alterações parametrizadas; • Necessidade de minimizar os efeitos colaterais de alterações invasivas. • Consequências Vantagens: • Não há alterações explícitas no código fonte; • Alterações no sistema são simplificadas por parâ- metros; • Suporte para vários tipos de alterações parame- trizadas. Desvantagens: • Modificações incorretas nos parâmetros do nível Meta podem causar falhas; • Aumento do número de componentes proporcio- nal à quantidade de parâmetros utilizados no nível Meta; • Baixa eficiência causada pela interpretação dos parâmetros em tempo de execução; • Nem todas as alterações são suportadas por pa- râmetros; • Nem todas as linguagens de programação supor- tam esta arquitetura. • Exemplo de aplicação Considere uma aplicação que necessita ler páginas HTML de um site para armazenar informações contidas entre tags específicas. O layout desse site, assim como a estrutura das suas páginas, variam frequentemente demandando alterações constantes na aplicação. Neste caso, é possível definir um nível Meta capaz de parametrizar a extração de informa- ções do site permitindo que a aplicação seja adaptada sem alterações específicas no código fonte. Arquitetura de Software 30 A figura 20 ilustra este exemplo para a arquitetura Reflection. Figura 20: Arquitetura Reflection aplicada ao projeto de um sistema para extração de informações em websites com estrutura volátil. Acesse o link http://www.guj.com.br/articles/10 e veja um exemplo de implementação em Java. Para ver um exemplo Asp.Net em C# acesse: http://www.linhadecodigo.com.br/artigo/1518/entendendo- -o-reflectionaspnet_csharp.aspx Exercícios do Capítulo 2 1 - Qual arquitetura deve ser aplicada em problemas não-determinísticos e por quê? 2 - Assinale V (Verdadeiro) ou F (Falso), nas afirmativas abaixo: ( ) A arquitetura em camadas é limitada a três níveis ( ) MVC é uma arquitetura em camadas com níveis específicos ( ) No padrão Pipers and Filters, os Filters não são reutilizáveis ( ) O modelo Microkernel é simples de conceber e implementar; ( ) No padrão Reflection qualquer alteração pode ser realizada através do nível Meta 3 - Cite um objetivo comum a todas as arquiteturas apresentadas neste capítulo e compare os exemplos. Arquitetura de Software 31 Capítulo 3 – Design Patterns – Padrões de Criação Caro aluno, neste capítulo definiremos o que é um padrão de projeto, quais são os padrões ado- tados pela comunidade de desenvolvedores e como eles são classificados. Depois definiremos o que são padrões de criação e apresentaremos os principais padrões de criação, bem como exemplos de uso. Conceitos de Padrões de Projeto Fonte:http://www.selectorweb.com/design_patterns.html Os primeiros registros de design patterns ou padrões de projeto foram publicados por Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides em 1994 no livro Design Patterns: elements of reusable object-oriented software. Estes padrões ficaram conhecidos como padrões GoF - Gang of Four, em referência aos 4 autores. Além dos padrões GoF, há diversos outros padrões de projeto. Craig Larman, em 2004, no seu livro “Applying UML and Patterns” reuniu um conjunto de padrões sob o acrônimo GRASP- General Responsibility Assignment Sof- tware Patterns (Padrões de Software para Atribuição de Responsabilidade Geral), que funcionam como um guia no desenvolvimento orientado a objetos apoiando a organiza- ção por responsabilidades. O GRASP reúne 9 padrões relevantes para o desenvol- vimento de sistemas OO dirigidos por responsabilidades. Os 9 padrões que compõem o GRASP são: creator (cria- dor); information expert (especialista); low coupling (bai- xo acoplamento); controller (controlador); high cohesion (alta coesão); polymorphism (polimorfismo); pure fabri- cation (pura invenção); indirection (indireção); protected variations (variações protegidas). Os padrões de projeto descrevem os princípios fun- damentais da atribuição de responsabilidades a objetos (como vimos no capítulo 1). Esses padrões exploram os princípios fundamentais de sistemas OO. Embora a adoção de padrões não seja trivial para um programador iniciante, atualmente este conceito tem sido adotado pela comunidade de desenvolvedores e cada vez mais exigidopor líderes nas fábricas de software. Como visto anteriormente, um código fonte de um pro- grama pode degradar-se ao longo de sua vida. Por prin- cípio, os padrões buscam isolar as partes do código que são estáveis daquelas que são/serão mais suscetíveis a mudanças. O resultado que se espera é ter aplicações nas quais seja mais fácil se efetuar procedimentos de manuten- ção, cujo código seja mais facilmente compreendido pela equipe do projeto e que favoreçam o reuso de código, aumentado seu tempo de vida e postergando o início da degradação. Os Design Patterns são uma coleção de padrões de pro- jeto de software, que oferecem soluções para problemas conhecidos e recorrentes no desenvolvimento de software. Um pattern descreve uma solução comprovada para um problema recorrente, dando ênfase ao contexto em que o problema ocorre e mostrando as consequências e o impacto de sua solução. Assim, os patterns são dispositivos que permitem que os programadores compartilhem conhecimento sobre o seu projeto. Como desenvolvedores, sabemos que quando programamos, encontramos muitos problemas que ocor- Arquitetura de Software 32 rem, ocorreram e irão ocorrer novamente. A pergunta que sempre fazemos é: “como vamos solucionar este problema desta vez?”. Documentar um padrão é uma maneira de podermos reusar e possivelmente compartilhar uma informação que aprendemos em relação à melhor maneira de se resolver um determinado problema de software. As vantagens de se utilizar design patterns são muitas e incluem as seguintes: • Os padrões já foram provados e refletem a experiência, o conhecimento e as soluções dos desenvolvedores que tiveram sucesso usando-os em seus trabalhos. • Os padrões são reusáveis e provêem uma solução pronta que pode ser aplicada a diferentes problemas. • Os padrões provêem um vocabulário comum que pode expressar muitas soluções, de forma sucinta e objetiva. Mas é importante lembrar que os padrões, por si só, não garantem o sucesso do seu uso. A descrição do padrão indi- ca quando ele pode ser aplicado, mas apenas a experiência pode determinar quando um padrão particular irá melhorar o projeto do sistema. O principal objetivo de um Design Pattern é criar uma abstração de um problema recorrente e apresentar uma solução viável, além de poder compartilhar este conhecimento para que outras pessoas se beneficiem dele. Assim, a documentação de um Design Pattern deve ser feita de uma forma muito bem definida. De uma maneira geral, a docu- mentação de um padrão inclui a definição dos seguintes itens: • Objetivos ou pré-requisitos que devem ser satisfeitos antes de se decidir aplicar um padrão; • A motivação ou o contexto em que o padrão se aplica; • Uma descrição da estrutura do programa em que o padrão será definido; • Consequências do uso do padrão, positivas e negativas; • Exemplos de uso e aplicação do padrã A figura 21 apresenta o Mapa de Padrões de Projetos proposto pela Gang of Four (GoF). Parte destes padrões será abordada nesta disciplina. Arquitetura de Software 33 Figura 21: Mapa de padrões de projetos GoF Fonte: http://knol.google.com/k/padr%C3%B5es-de-software# Arquitetura de Software 34 O catálogo de padrões do GoF contém 23 padrões e está, basicamente, dividido em três seções: • Creational (Padrões de Criação) • Structural (Padrões Estruturais) • Behavioral (Padrões Comportamentais) Os padrões de projeto do GoF são soluções para problemas recorrentes no desenvolvimento de sistemas de software orientado a objetos. A figura 22 mostra a divisão destes padrões, no contexto da programação orientada a objetos. Os padrões de criação se referem à instanciação de objetos, os estruturais estão ligados com a composição de classes ou objetos e os comportamentais procuram caracterizar formas de interação entre classes e objetos. Um padrão GoF também é classificado segundo o seu escopo em 2 outros grupos: • Padrões com escopo de classe : definido por relacionamentos de herança e em tempo de compilação. • Padrões com escopo de objeto : encontrados no relacionamento entre os objetos definidos em tempo de exe- cução. Figura 22: Divisão dos padrões GoF Fonte: http://www.linhadecodigo.com.br/artigo/2573/desing-patterns-na-pratica---desvendando-misterios-parte-1.aspx Neste capítulo trataremos dos padrões de criação e nos capítulos seguintes apresentaremos os padrões estruturais e os comportamentais. Mas, antes de prosseguirmos, um pouco de humor... Arquitetura de Software 35 Ainda para manter o bom humor, leia sobre “Princípios Comuns de Design” Disponível em: http://www.princiweb.com.br/blog/programacao/o-que-sao-design-patterns/ “Há diversos princípios comuns de design, que, assim como os design patterns, se tornaram boas práticas através dos anos e ajudaram que software de fácil manutenção pudessem ser construídos. Abaixo, segue um resumo dos princípios mais conhecidos: Keep It Simple Stupid (KISS) Mantenha Isto Estupidamente Simples Um problema comum em programação de software é a necessidade de complicar demais a solução. O objetivo do princípio KISS é manter o código simples, mas não simplista, assim evitando complexidade desnecessária. Don’t Repeat Yourself (DRY) Não Repita Você Mesmo Arquitetura de Software 36 O princípio do DRY é evitar a repetição de qualquer parte do sistema abstraindo as coisas que são comuns entre si e colocá-las em um lugar único. Esse princípio não se preocupa somente com o código, mas qualquer lógica que está duplicada no sistema. Tell, Don’t Ask Fale, não pergunte O principio Tell, Don’t Ask está estreitamente alinhado com o encapsulamento e a atribuição de responsabilida- des para as suas classes corretas. O princípio afirma que você deve dizer aos objetos quais ações você quer que eles realizem, ao invés de fazer perguntas sobre o estado do objeto e então tomar uma decisão por si próprio em cima da ação que você quer realizar. Isso ajuda a alinhar as responsabilidades e evitar o forte acoplamento entre as classes. You Ain’t Gonna Need It (YAGNI) Você Não Vai precisar Disso O princípio YAGNI se refere à necessidade de adicionar somente as funcionalidades que são necessárias para a aplicação e deixar de lado qualquer tentação de adicionar outras funcionalidades que você acha que precisa. “ Definição de Padrões de Criação Fonte: http://jutalala.wordpress.com/2011/07/17/e-nisso-que-da-competir-com-o-deus-da-criacao/ Caro aluno, padrões de criação auxiliam na concepção de sistemas independentes do modo como os objetos são gerados, compostos e representados. Este tipo de padrão abstrai o processo de instanciação, alterando a classe instan- ciada através e herança. [GAMMA, 1995] Arquitetura de Software 37 Assim, os padrões de criação concentram-se na composição de objetos complexos e no encapsulamento do com- portamento de criação. Dessa forma, pretende-se evitar código embutido definindo pequenos grupos de características fundamentais capazes de compor estruturas mais complexas. Os padrões de criação podem ser competitivos ou cooperativos. Algumas técnicas se complementam enquanto outras executam funções similares de formas distintas. As cinco abordagens presentes no modelo GoF serão apresentadas a seguir. Padrão Abstract Factory • Objetivo Fonte: http://justintarte.blogspot.com/2010/07/if-you-have-ever-walked-into-factory.html De acordo com Gamma (1995), o objetivo do padrão Abstract Factory é fornecer uma interface para criar grupos de objetos relacionados aos dependentes sem especificar suas classes concretas. • Contexto Produtos portáveis utilizam o conceito abstrato deste padrão para desvincular código fundamental da aplicaçãode recursos que são dependentes da plataforma. • Estrutura Este padrão é composto pelos seguintes elementos: • AbstractFactory: declara uma interface para operações que criam objetos abstratos; • ConcreteFactory: implementa operações específicas para criar objetos concretos; • AbstractProduct: declara uma interface para cada tipo de objeto; • ConcreteProduct: implementa uma interface de AbstractProduct para definir um objeto que pode ser criado por sua ConcreteFactory correspondente; • Client: utiliza as interfaces declaradas pelo AbstractFactory e AbstractProduct, sem se preocupar com as implemen- tações concretas. Arquitetura de Software 38 • Aplicabilidade O padrão Abstract Factory pode ser empregado nos seguintes casos: • Um sistema deve ser independente do modo como seus objetos são criados, compostos e re- presentados; • Um sistema deve ser configurado com vários grupos distintos de objetos; • Alguns objetos relacionados foram projetados para serem utilizados em conjunto, e você precisa impor essa restrição; • Você quer fornecer uma biblioteca de classes e pre- tende revelar apenas suas interfaces, não suas im- plementações. • Consequências Vantagens: • Isola as classes concretas e ajuda a controlar as classes de objetos que um aplicativo cria. • Torna fácil a troca de implementações específicas, pois a classe ConcreteFactory aparece apenas onde é instanciada na aplicação; • Promove a consistência entre produtos, pois faci- lita a implementação de objetos que foram proje- tados para trabalhar juntos. Desvantagens: • Alta complexidade para suportar novos produtos. Este processo requer alteração do Abstract Fac- tory e todas as subclasses. • Exemplo de aplicação Considere um sistema de diagnóstico para telefones celulares. Os componentes principais executam funções si- milares, no entanto, cada fabricante emprega sua própria arquitetura de hardware e software. Neste caso, é possível desenvolver uma biblioteca abstrata genérica e implemen- tar classes concretas adequadas para cada aparelho. Fonte:http://www.opencs.com.br/site/index. php?page=caracteristicas-tecnicas-m-trusted Padrão Builder Fonte: http://houstonagentmagazine.com/builder- confidence-posts-highest-monthly-gain-in-19-months/ • Objetivo O objetivo do padrão Builder é separar a construção de um objeto complexo da sua representação, de modo que o mesmo processo de construção possa criar diferentes representações. [GAMMA, 1995] • Contexto Sistemas capazes de gerar ações indeterminadas para uma única aplicação, utilizam a estrutura modular deste padrão para permitir a implementação de soluções alternativas que utilizem recursos oriundos de uma fonte única. • Estrutura Este padrão é composto pelos seguintes elementos: • Builder: especifica uma interface abstrata para a criação de módulos do sistema; Arquitetura de Software 39 • Concretebuilder: cria e executa módulos através da interface do Builder; controla a representação criada e fornece um meio para obtenção dos resultados; • Director: constrói o objeto principal utilizando a interface do Builder; • Product: representa um módulo alternativo que inclui interfaces para geração do resultado final. • Aplicabilidade Este padrão pode ser empregado nas seguintes situações: • O algoritmo para a criação de um objeto complexo deve ser independente dos módulos que compõem o sis- tema e como eles são montados; • O processo de construção deve permitir diferentes representações para o objeto construído. • Consequências Vantagens: • Permite variar o resultado gerado por um sistema. Como o sistema é construído através de uma interface abs- trata, tudo que você precisa fazer para mudar a representação interna é definir um novo tipo de construtor; • Isola o código para a construção e representação. O padrão Builder melhora a modularidade, encapsulando a maneira como um objeto complexo é construído e representado; • Proporciona um melhor controle sobre o processo de criação de objetos, pois carrega o sistema passo a passo sob o controle do Director. Desvantagens: • Pelo fato de ser um padrão bastante flexível, pode resultar no uso redundante e mal planejado, impactando no entendimento do código gerado. • Exemplo de aplicação Considere um sistema para tratamento de imagens. Atualmente existem diversos recursos e todos os anos surgem novos algoritmos que fornecem funções inovadoras. No entanto, o conceito fundamental dessas ferramentas é único: uma imagem original é fornecida e uma imagem tratada é obtida no final do processo. Portanto, a base do sistema precisa implementar apenas essas funções e a cada novo algoritmo que surge um novo módulo deve ser desenvolvido com suas características específicas. Arquitetura de Software 40 Fonte: http://www.ibm.com/developerworks/br/library/os-datavis2/index.html Padrão Factory Method • Objetivo De acordo com Gamma (1995), o objetivo do padrão Factory Method é definir uma interface para criação de objeto que permita que as subclasses decidam qual classe será instanciada. • Contexto Sistemas que manipulam um número variável de tipos de objetos podem utilizar este modelo devido à sua flexibili- dade. O Factory Method permite que a aplicação final implemente o suporte aos objetos necessários. • Estrutura O padrão Factory Method é composto pelos seguintes elementos: • Product: define a interface dos objetos criados por este padrão; • ConcreteProduct: implementa a interface do Product; • Creator: declara o método que retorna o objeto do tipo esperado; • ConcreteCreator: sobrescreve o método original para retornar uma instancia do objeto esperado, ou seja o ConcreteProduct. Arquitetura de Software 41 • Aplicabilidade Este padrão pode ser usado nas seguintes situações: • A aplicação não pode antecipar os tipos de obje- tos que devem ser criados; • Uma classe espera que suas subclasses especifi- quem o tipo de objeto a ser criado; • As classes delegam a responsabilidade a uma das subclasses e você quer identificar de qual subclas- se advém o conhecimento. • Consequências Vantagens: • Provê meios para as subclasses estenderem as funções básicas; • Conecta hierarquias de classes paralelas que com- partilham o conhecimento da operação. • Exemplo de aplicação Considere uma aplicação que carrega vários tipos de arquivos distintos. As funções básicas de busca, leitura e gravação são as mesmas em qualquer situação. Contudo, cada arquivo possui características particulares que são definidas por subclasses específicas. Portanto, o aplicativo não sabe qual classe deve ser instanciada até a subclasse, associada a um arquivo, informá-lo. Padrão Prototype Fonte:http://allthecars.wordpress.com/2009/07/22/lotus-projeta- compacto-urbano-movido-a-eletricidade/lotus-city-car-prototipo-04/ • Objetivo O objetivo do padrão Prototype é especificar o tipo dos objetos através de uma instância-protótipo e criar novos objetos através da cópia dessa instância. [GAMMA, 1995]. • Contexto A estrutura deste padrão permite a implementação de variações de uma classe sem o uso de subclasses, através da criação de instâncias-protótipo com características es- pecíficas pré-definidas. • Estrutura A estrutura deste padrão é composta pelos seguintes itens: • Prototype: declara uma interface para autoclona- gem; • ConcretePrototype: implementa a operação de autoclonagen; • Client: cria objetos solicitando um clone ao pro- tótipo. • Aplicabilidade O padrão Prototype pode ser empregado nas seguintes situações: Arquitetura de Software 42 • As classes a serem instanciadas são
Compartilhar