Desenvolvimento de software, independente do paradigma, seja ele estrutural, orientado a objeto, componentizado, web, client-server e etc, nunca foi um trabalho trivial e com uma espécie de receita de bolo para o sucesso. Costumo dizer que a arte de construir sistemas duráveis e com retorno de investimento é muito árduo e as chances são mais favoráveis ao insucesso do que ao sucesso. Construção de software voltado ao paradigma de orientação a serviço traz riscos ainda maiores.
Isso ocorre porque uma arquitetura SOA geralmente se estende por várias áreas de negócio e requer uma análise inicial bem considerável. Como arquitetura SOA faz parte da evolução dos modelos arquiteturais, digo isso porque para existir SOA precisava primeiramente existir o conceito de componentes distribuídos, arquitetura modular, conceito de reutilização fortemente apoiada na programação orientada a objetos, protocolos interoperáveis favorecidos pela web e por aí vai. Portanto, toda as boas práticas de engenharia para construção de software continua existindo e sendo ainda mais cobrado e exigido para se obter uma arquitetura SOA funcional e de sucesso. Thomas Erl em seu livro SOA Principles of Service Design categorizou 8 princípios fundamentais para guiar a construção de serviços, no qual alguns deles já faziam parte da velha academia, mas que consolidado com outras regras se tornam um conjunto de regras básicas para SOA (guideline).
1. Standardized service contract
Contrato padronizado é um princípio aplicado dentro do paradigma de design de serviços, que fornece por meio de um padrão, que os serviços sejam registrados em inventários. Um contrato de serviço representa um artefato fundamental, no qual através dele serviços interagem uns com os outros e com potenciais consumidores. Portanto, existe uma forte necessidade de padronizar os contratos de serviços, a fim de tornar os serviços reutilizáveis, recompostos e interoperáveis. Exemplo de padrão é o XML Schema WSDL, contrato de serviço WS* que contém a descrição do serviços com documento(s) de política, para que se possa ser compreendido em tempo de design fornecendo as 03 áreas de um contrato, veja abaixo:
Padronização de expressão funcional |
Operações de serviço devem ser definidos com nomenclatura padronizadas, extendendo-se para os nomes de entrada, saída das mensagens e seus tipos correspondentes. Isso ajuda na interpretação do contrato, que por sua vez aumenta a reutilização e interoperabilidade de serviços evitando duplicidade por falta de entendimento. |
Padronização do modelo de dado |
Como reutilização é um dos pilares, provavelmente utilizaremos uma estrutura de dados que atende um requisito de negócio em lugares diferentes, exemplo: pedido de venda. Para que essa entidade não tenha estruturas diferentes em contextos diferentes, precisamos que o mesmo tenha uma estrutura padrão que represente o requisito funcional e seja centralizado para reutilização corporativa e elimine qualquer sobrecarga de transformação, facilitado a interoperabilidade e compartilhamento, bem como o uso de schemas. |
Padronização de política |
Políticas representam os termos de uso de um serviço. Para que um serviço seja reutilizável, seus requisitos de comportamento precisam ser exposto de forma consistente com uso de políticas padronizadas, baseadas nos padrões da indústria. Este tipo de padronização promove maior separação das políticas de contratos de serviços em documentos de políticas. |
2. Service loose coupling
Dentro do paradigma de design, baixo acoplamento é um princípio de projeto que é aplicado aos serviços para garantir que o contrato de serviço não esteja fortemente ligado aos consumidores, nem com a lógica de serviço subjacente e a sua implementação. Isso resulta em contratos de serviços que possam ser evoluídos livremente, sem afetar os consumidores de serviços ou a sua implementação.
Contract-to-logic |
Quando o contrato é gerado com base em lógica existente, às vezes até por meio de ferramentas automatizadas. Isso inibe a evolução do contrato de serviço, pois o contrato não está concebido de forma independente de acordo com as normas de concepção e é ditada pela lógica subjacente. |
Contract-to-implementation |
Quando os contratos são projetados de forma que eles se baseiam nos detalhes de implementação subjacentes, por exemplo, uso de modelos de dados utilizados no banco de dados subjacente. Desta forma, uma alteração na implementação subjacente exige uma alteração correspondente no contrato de serviço. Uma forma de evitar esse acoplamento é o uso de uma service façade. |
Contract-to-technology |
Contrato que expõe elementos de tecnologia utilizada pelo serviço. Exemplo: contrato baseado em WCF ou EJB. Dessa forma os consumidores estão acoplados a uma tecnologia particular, dificultando a capacidade do serviço em ser interoperável. |
Contract-to-functional |
Quando o contrato do serviço é desenvolvido para um determinado consumidor em mente. Exemplo: serviços construídos para permitir a comunicação com um parceiro, serviço que executam uma parte da lógica do processo ou é um serviço controlador de uma composição de serviços que executa a lógica do processo de negócios. |
Consumer-to-implementation |
Quando os consumidores acessam o serviço diretamente através da lógica ou implementação. Isso pode acontecer quando os consumidores acessam o serviço através de interfaces de implemetação antes que o contrato se torna-se uma serviço propriamente. Contract-Centralization soluciona esse problema. |
Consumer-to-contract |
Este é um tipo de acoplamento que ajuda a evoluir o serviço sem impactar os seus consumidores. Mas é importante que este acoplamento seja restrito ao contrato de serviço e não vaze para a arquitetura, caso contrário o consumidor do serviço pode facilmente tornar-se acoplado à implementação do serviço, a lógica ou tecnologia. |
3. Service abstraction
Um contrato de serviço que contém detalhes sobre o que é, pode acabar sendo utilizado de uma maneira particular devido o alto conhecimento sobre o funcionamento do serviço por parte do consumidor. Isso pode afetar a evolução do contrato de serviço, pois o consumidor está indiretamente acoplado à implementação do serviço, que pode precisar ser substituído no futuro. De certa forma, isso aumenta o acoplamento do tipo consumidor-contrato, que, embora seja um tipo positivo de acoplamento, demasiadamente impacta de forma negativa na evolução, tanto do prestador de serviços como o consumidor.
Functional abstraction |
Esse princípio visa um contrato otimizado que maximiza o potencial de reutilização do serviço. Na orientação a objetos, uma classe só iria expor métodos público que considere ser importante para seus objetos, os métodos auxiliares que não são relevantes para os objetos são mantidos em oculto. Um contrato de serviço que não tenha sido submetido a este princípio poderia ser denominado como um “contrato detalhado”, que revela muito de regras de negócios e da lógica de validação. |
Technology information abstraction |
Qualquer informação sobre a tecnologia interna utilizada deve ser abstraída. Esta informação adicional pode resultar em consumidores que visam uma implementação particular, desenvolvendo assim acoplamento consumidor-implementação. |
Logic abstraction |
Os detalhes sobre a programação da lógica precisa ser abstraído, como o conhecimento sobre como o serviço realmente executa sua funcionalidade pode resultar em consumidores que são projetados sob essas premissas. Isso pode dificultar seriamente os esforços refatoração e pode ser considerado como um anti-pattern. |
Quality abstraction |
Abstração de qualidade relaciona-se com os detalhes fornecidos no prazo de SLA que acompanha o serviço. É importante concentrar-se apenas no tipo de informação que seria realmente útil em determinar a confiabilidade e a disponibilidade do serviço. Nenhuma outra informação deve ser incluída, expondo detalhes desnecessários. Por exemplo, detalhes de como funciona um serviço permanece dentro do processo global de negócios, bem como outros serviços que são utilizados para cumprir a sua funcionalidade. Apenas pessoas autorizadas devem ter acesso e uma política de QoS e detalhes do ambiente/tecnologia ou maiores detalhes do projeto. |
4. Service reusability
Serviços reutilizáveis são projetados para que sua lógica seja independente de qualquer processo de negócio específico ou tecnologia. Reutilização relaciona-se quando o serviço é utilizado para automatizar vários processos de negócio. Essa reutilização elimina a necessidade de criar um novo serviço completo e se torna uma parte de vários processos de negócios, sem fazer parte de qualquer processo de negócio particular. O princípio de reutilização de serviços aborda esses equívocos, fornecendo um conjunto de diretrizes que ajudam a projetar serviços que contêm lógica que não está ligada a qualquer processo de negócio em particular e, portanto, poderiam ser reutilizados em toda a empresa para a automatização de vários processos de negócio. Aplicação com composição de serviços, captação de serviços e serviços levemente acoplados ajudam a desenvolver serviços combináveis.
5. Service autonomy
Autonomia de serviços é um princípio que visa fornecer serviços com independência de seu ambiente de execução. Isso resulta em maior confiabilidade, já que os serviços podem operar com menos dependência de recursos sobre os quais há pouco ou nenhum controle. Confiabilidade é crítico para garantir a longevidade do serviço.
Design-time autonomy |
Autonomia em tempo de design se refere à independência que os serviços tem de modo que, possam ser evoluídos sem impactar nos seus consumidores. Esse tipo de autonomia é importante para manter baixo acomplamento, assim refatorações ou mudanças internas não impliquem em modificações no contrato do serviço. |
Run-time autonomy |
Autonomia em tempo de execução refere-se ao controle que um serviço tem sobre a forma como a lógica da solução é processado pelo ambiente de tempo de execução. Quanto mais controle um serviço tiver sobre seu ambiente de tempo de execução, mais previsível é o seu comportamento. Autonomia de tempo de execução é obtido por meio de recursos de processamento dedicados. Por exemplo, se a lógica do serviço tem um uso intenso de memória, o serviço poderia ser usufruir de um servidor com recursos adicionais. |
Service types |
Serviços precisam ser priorizados para que a sua autonomia possa ser abordada de acordo com o seu valor para o negócio. Isso pode ser feito analisando o contexto funcional do serviço. Serviços cujos contextos funcionais são independentes de qualquer processo de negócio em particular, por exemplo, serviços que oferecem funcionalidades que é de interesse para os diferentes tipos de consumidores. Por outro lado, os serviços específicos de processos de negócios, por exemplo, tarefas e tarefa orquestradas, são menos reutilizáveis e dependem da autonomia individual dos seus serviços compostos. |
6. Service statelessness
Interação entre softwares ou requisitos de negócio muitas vezes exigem o esforço de manter e gerenciar o controle do estado das informações entre as operações. Isso se torna mais importante em arquiteturas distribuídas onde o cliente e o servidor não estão fisicamente na mesma máquina. Numa composição de serviço, um serviço pode armazenar dados específicos da atividade em memória enquanto ele espera um outro serviço completar seu processamento. Gestão eficiente da atividade de serviço relacionado aos dados se torna mais importante como um serviço que visa a reutilização do mesmo. As diretrizes de arquitetura SOA é construir serviços stateless, deslocando a sobrecarga de gerenciamento de estado dos serviços para um outro componente/middleware externo. Isso ajuda ainda mais na escalabilidade global da solução.
7. Service discoverability
O potencial de reutilização de um software não pode ser conseguido se não se sabe ainda se existe ou não, por isso ser detectável é algo muito importante. Não somente detectável, mas que também seja corretamente compreendido, ou seja, depende da qualidade da meta-informação. No caso de uma solução orientada a serviços, por causa da ênfase dada à reutilização de serviços, é muito claro que as oportunidades devem existir para a sua reutilização, o que só é possível se forem descobertos. Para tornar os serviços detectáveis, precisamos algumas atividades:
– Documentar os o serviço de forma consistente.
– Armazenar a informação documentada em um repositório pesquisável (UDDI).
– Habilitar a procurar da informação documentada de uma maneira eficiente.
Além de aumentar o potencial de reutilização dos serviços, o mecanismo de descoberta também é necessário para evitar o desenvolvimento de uma solução que já está contida em um serviço existente. Para projetar os serviços que não são apenas detectáveis, mas também fornecer informações interpretáveis sobre suas capacidades, o princípio de descoberta do serviço fornece diretrizes que poderiam ser aplicados durante a fase de análise do processo de prestação de serviços.
8. Service composability
Desenvolvimento de software a partir de componentes independentementes incentivam o conceito de composição. Este é o um conceito implícito na orientação a objetos, onde o produto final é composto de vários objetos interligados que têm a capacidade de se tornar parte de múltiplas soluções. O mesmo conceito de composição é utilizado em SOA por meio de um processo de negócio automatizado, através da combinação de vários serviços, Exemplo: BPEL. O princípio de modularidade de serviço fornece considerações de design que ajudam na concepção de serviços combináveis com o objetivo de incentivar a reutilização o máximo possível. A diretriz é que um serviço esteja sempre pronto para participar de composições de serviços sem a necessidade de quaisquer alterações no design.