Conteúdo


Arquitetura Evolucionária e Design Emergente

Arquitetura evolucionária

Considerações e técnicas para arquitetura ágil

Conteúdos da série:

Esse conteúdo é a parte # de # na série: Arquitetura Evolucionária e Design Emergente

Fique ligado em conteúdos adicionais dessa série.

Esse conteúdo é parte da série:Arquitetura Evolucionária e Design Emergente

Fique ligado em conteúdos adicionais dessa série.

Voltando à primeira parte desta série, eu sugeri algumas definições para arquitetura no mundo do software. Entretanto, caso esteja lendo toda esta série (e se você não for minha mãe, eu lhe agradeço por isso!), você deve ter observado que passei boa parte do tempo falando de design. Fiz isso por uma série de motivos. Primeiro, muitas definições de arquitetura existem no mundo do software (para o bem ou para o mal), embora o design emergente atualmente desfrute de menos fama. Segundo, muitas das preocupações em design têm soluções concretas menos contextualizadas. A arquitetura sempre envolve muito acoplamento com a infraestrutura física e lógica das organizações, o que torna muito mais difícil falar disso isoladamente.

Esta parte corrige a falta de material sobre a arquitetura ágil. Aqui, eu falo sobre como distinguir a arquitetura do design, abordo algumas considerações mais amplas sobre arquitetura e toco no assunto do espaço da arquitetura orientada a serviço (SOA) ágil, com uma discussão sobre a versão de terminais.

Distinguindo arquitetura de design

A definição de arquitetura de Martin Fowler (a partir de conversas com ele) é a minha favorita:

Arquitetura é aquela coisa que é difícil de mudar depois. E deve existir o mínimo possível dessa coisa.

É possível pensar na interação entre arquitetura e design como o relacionamento mostrado na Figura 1:

Figura 1. Relacionamento entre arquitetura e design
image of stacked boxes
image of stacked boxes

A arquitetura de um sistema de software forma a base de tudo, representada na Figura 1 como caixas cinzas. Os elementos de design ficam acima da arquitetura, como mostram as caixas vermelhas. Sendo mais fundamentais, os elementos de arquitetura são mais difíceis de mover e substituir porque será preciso mover todas as coisas que estão acima deles para acomodar as mudanças. Essa distinção facilita a identificação do design em comparação com a arquitetura. Por exemplo, a estrutura da Web usada é um elemento de arquitetura difícil de substituir. Entretanto, nessa estrutura da Web, é possível usar diferentes padrões de design para expressar metas específicas, o que sugere que a maioria dos padrões de design formais de fato faz parte do design em vez da arquitetura.

A conclusão para a definição de arquitetura de Fowler é que você deve construir os elementos de arquitetura para que sejam mais fáceis de substituir caso seja realmente necessário. Mas como é possível assegurar isso? Eis um exemplo aqui.

Várias estruturas tentam seduzi-lo a usar algumas de suas classes em vez das mais gerais que vêm com JDK ou de um elemento de corpo de padrões abertos (como OASIS). Esse é o modelo de acoplamento "viciador": se você se render à tentação, ficará preso à estrutura para sempre. A abordagem geral dessas estruturas é tornar algo bem mais fácil se você usar suas classes. Um exemplo perfeito disso vem da estrutura da Web Apache Struts (consulte Recursos).

As classes no seu aplicativo que contêm regras de negócios e outros códigos que não são de infraestrutura são as classes de domínio: elas têm as informações interessantes sobre o seu domínio com problema. Uma das classes auxiliares excelentes inclusas em Struts é a ActionForm. Se você herdar os objetos de domínio de ActionForm, todos os tipos de mágica ocorrerão no seu aplicativo. Você obtém preenchimento automático de campos de formulário a partir de parâmetros, validação automática (nas camadas de servidor e da Web) e outras coisas que oferecem praticidade. Tudo o que precisa ser feito é definir a classe ActionForm de Struts como subclasse, como mostrado na Figura 2:

Figura 2. Usando a classe ActionForm de Struts
illustrating coupling of domain classes to Struts
illustrating coupling of domain classes to Struts

Na Figura 2, a caixa com o rótulo Model tem o objeto de domínio. Ele estende ActionForm de Struts, tornando essa estrutura difícil de ser alterada posteriormente. Se, em algum ponto no futuro, você decidir que ScheduleItem também precisa funcionar em um aplicativo Swing, você estará perdido. Você ficará diante de duas soluções igualmente intragáveis: arrastar todos os Struts para o aplicativo Swing (e não usá-lo) ou se livrar da dependência de Struts.

A melhor alternativa usa composição em vez de herança, como ilustrado na Figura 3:

Figura 3. Desmembrando sua classe de domínio por meio de composição
illustration of composition rather than inheritance
illustration of composition rather than inheritance

Nessa versão, a classe de domínio (em amarelo) inclui uma interface que define a semântica de um item de planejamento. O ScheduleItem original implementa essa interface, que é também implementada por ScheduleItemForm, forçando a semântica das duas classes sempre a concordar. ScheduleItemForm, por sua vez, tem uma instância do objeto de domínio ScheduleItem, e todos os acessadores e mutadores de ScheduleItemForm passam para os acessadores e mutadores subjacentes do ScheduleItem encapsulado. Isso lhe permite aproveitar as vantagens dos recursos excelentes de Struts enquanto você se mantém desmembrado da estrutura.

A regra prática é esta: é bom a estrutura saber de você, mas não é bom você saber da estrutura. Enquanto for possível manter o relacionamento, você impede o acoplamento do código à infraestrutura, permitindo a realização de alterações na arquitetura e no design com mais facilidade. Às vezes, é necessário um pouco mais de trabalho para fazer isso, mas, no final, você tem flexibilidade aprimorada. Struts não é a única estrutura a oferecer essas economias tentadoras. Praticamente, toda estrutura tem alguns auxiliares que o vincularão à estrutura. Se você alguma vez importar pacotes de uma estrutura ou fornecedor em suas classes de domínio, você provavelmente estará arrumando dor de cabeça futura.

Algumas considerações sobre arquitetura

Além da definição de arquitetura, uma grande quantidade de preocupações surge em configurações corporativas típicas. Mencionarei apenas algumas das abordagens de arquitetura ágil aqui.

Política de arquitetura

A política corporativa é uma das primeiras coisas desagradáveis que você encontra quando promovido para a posição de arquiteto. Como o arquiteto é geralmente a posição técnica mais alta nas empresas, você se torna o porta-voz (e o defensor) de todas as decisões que ocorrem no departamento de TI, para o bem ou para o mal. Na verdade, você leva a culpa por todas as coisas ruins que acontecem e não leva nenhum crédito pelas boas. Alguns arquitetos mais novos tentam ignorar isso (que parecia funcionar muito bem enquanto você estava nas trincheiras técnicas), mas isso não funcionará mais em sua nova posição.

Lembre-se de que a comunicação é mais importante do que a tecnologia na maioria dos projetos de software. Se você alguma vez esteve em um projeto de software que deu errado, considere os motivos de ele ter falhado. Isso ocorreu devido à tecnologia ou a um problema de comunicação? Na maioria das vezes, é de comunicação em vez de tecnologia. Os problemas tecnológicos têm soluções. (Às vezes, as soluções são difíceis, mas os problemas tecnológicos têm uma solução.) Os problemas sociais são muito mais confusos e difíceis de resolver. Uma das famosas citações do livro Peopleware (consulte Recursos) é:

É sempre um problema de pessoas.

Mesmo para as decisões de tecnologia mais simples, a política sempre exercerá influência, especialmente se você estiver na posição de aprovar compras de ferramentas corporativas. (O lado positivo do negócio é que você talvez precise participar de uma partida exótica de golfe, uma cortesia de um dos fornecedores de ferramentas.) Lembre-se de que, como arquiteto, você não só precisa tomar decisões importantes, mas defendê-las também. Às vezes, as pessoas com quem você conversa têm suas próprias agendas que não fazem sentido logicamente falando, mas fazem sentido no teste da política corporativa. Não fique frustrado e lembre-se do porquê da decisão que tomou em primeiro lugar.

Construir versus comprar

Nas questões comuns que surgem em grandes empresas na decisão de construir ou comprar: para os requisitos atuais, devemos comprar COTS (Commercial Off-the-Shelf Software) ou construí-lo nós mesmos? A motivação para essa decisão é compreensível — se a empresa puder encontrar algum software já pronto que faça exatamente o que é necessário, isso poupará tempo e dinheiro. Infelizmente, vários fornecedores de software entendem esse desejo e criam um software em pacote que poderá ser personalizado se não fizer exatamente o que o cliente precisar. Eles são motivados a criar o software mais genérico que puderem porque ele provavelmente servirá na maioria dos ecossistemas. Mas, quanto mais genérico forem, mais personalização será necessária. É quando um exército de consultores aparece, às vezes levando anos para concluir o trabalho de codificação personalizada.

A questão de comprar COTS ou não realmente leva a outra pergunta: o processo de negócios é suportado por um software estratégico ou de custo adicional? A aquisição de COTS fará sentido perfeitamente se o processo de negócios em questão for meramente um custo adicional. Exemplos desse tipo de software incluem recursos humanos, finanças e outros processos de negócios comuns. O software estratégico proporciona uma vantagem competitiva no seu campo de negócios. Essa vantagem competitiva não deve ser descartada de imediato.

O fluxograma na Figura 4 foi projetado para ajudá-lo a decidir entre construir e comprar:

Figura 4. Fluxograma de decisão de construir versus comprar
build vs. buy flowchart
build vs. buy flowchart

Nesse fluxograma, a primeira decisão que deve ser tomada toca no assunto da distinção importante entre estratégico e custo adicional. Se a necessidade for estratégica, você deverá sempre construir a sua própria solução. Caso contrário, você estará propositalmente se colocando no mesmo nível de seus concorrentes em vez de criar algo exatamente voltado para as suas necessidades atuais e futuras. O software em pacote pede personalização, mas essa personalização tem limites. Se você criar o seu próprio software, isso levará mais tempo, mas você terá uma plataforma em que poderá criar coisas que o diferenciem de seus concorrentes.

A segunda decisão no fluxograma pergunta se o software em pacote é útil imediatamente. Uma armadilha comum na compra de software em pacote é não entender exatamente quanto tempo levará para ele se adaptar ao seu processo de negócios; a maioria das empresas negligencia isso bastante. Quanto mais você o personalizar, mais tempo ele levará para entrar em operação. Pior ainda, algumas empresas permitem que seu processo de negócios mude para acomodar o software. Isso é um erro porque, para o bem ou para o mal, seu processo de negócios deve ser diferente do processo de seus concorrentes.

A terceira etapa na árvore de decisão pergunta se o pacote é extensível em vez de personalizável. Os sistemas extensíveis têm formas bem-definidas de estender a funcionalidade sem precisar tirar nada do lugar. Esses pontos de extensão incluem APIs bem-definidas, chamadas SOAP e similares. A personalização significa que você precisar "trapacear" para fazer com que o pacote faça o que você quer. Por exemplo, se abrir um arquivo WAR para que possa substituir um arquivo com o nome index.gif por uma imagem diferente (que deve ter o nome index.gif), você estará personalizando, não estendendo. O teste final é se as suas alterações têm ou não alguma chance de sobreviver a uma atualização. Se tiverem, você estendeu o pacote; caso contrário, você o personalizou. A personalização o desestimula a manter o pacote atualizado porque você percebe quanto esforço é necessário para se efetuar as mesmas alterações para a nova versão. Dessa forma, a tendência não é atualizar, deixando você quatro ou cinco versões para trás da mais recente, o que o coloca em risco de perder o suporte para a versão antiga que está usando.

O que é custo adicional para algumas empresas é estratégico para outras. Por exemplo, eu prestei alguns serviços de consultoria para uma financeira, cujo processo de contratação é considerado uma de suas principais vantagens estratégicas. Eles contratam os melhores e os mais brilhantes, gastando bastante tempo e esforço para encontrar a pessoa certa. Certa vez, eles pediram meu conselho sobre a compra de um sistema de recursos humanos COTS, e eu desaconselhei isso: por que eles deveriam se colocar no mesmo nível de seus concorrentes? Portanto, em vez de comprar um sistema COTS, eles seguiram meu conselho e desenvolveram seu próprio sistema de RH. Esse desenvolvimento levou mais tempo, mas, quando estava pronto, eles tinham uma plataforma que facilitou as tarefas que, para seus concorrentes, necessitavam de mais mão-de-obra. A contratação é simplesmente um custo adicional para muitas organizações, mas, para essa empresa, era estratégica.

Tipificação na arquitetura

Um tópico mais técnico (menos orientado a processo) que surge geralmente nas iniciativas SOA tem a ver com a tipificação e a versão de sistemas distribuídos. Essa é mais uma das armadilhas comuns nesses tipos de projetos. Ambas são comuns porque é fácil seguir um caminho definido pelos fornecedores de ferramentas e porque leva um tempo para um problema se manifestar — e os problemas mais difíceis surgem do fato de não se saber o que você não saber nas etapas iniciais de um projeto.

O debate sobre se devem ser criado ou não sistemas "corporativos" com linguagens tipificadas dinamicamente é longo, e os argumentos agora são suficientes. Entretanto, esse debate informa uma consideração importante para sistemas distribuídos com relação à tipificação dos terminais. Por terminais, estou me referindo ao portal de comunicação entre dois sistemas distintos. Os dois estilos de tipificação concorrentes são SOAP, que geralmente produz tipificação forte usando padrões como Web Services Description Language (WSDL) e Representational State Transfer (REST), que favorece uma abordagem voltada para documentos tipificada fracamente (consulte Recursos). Os prós e contras de SOAP versus REST estão fora do escopo do artigo; aqui, eu quero principalmente falar sobre os benefícios da tipificação fraca no nível de terminal, o que você pode conseguir com qualquer um dos estilos.

A tipificação mais dinâmica é importante em terminais porque esses terminais formam uma API de integração publicada entre sistemas que geralmente evoluem em passos diferentes. Você quer evitar assinaturas específicas de acoplamento firme (tipos e nomes de parâmetros) entre esses sistemas, o que tornaria cada lado da conversa frágil e propenso a quebra, dificultando sua capacidade de criar versão dos dois aplicativos de maneira independente.

Eis um exemplo aqui. Na integração de estilo SOAP tradicional, você usa um tipo de protocolo RPC, utilizando WSDL para definir os detalhes da conversa entre os dois aplicativos. Isso está ilustrado na Figura 5:

Figura 5. Usando chamadas de estilo RPC entre aplicativos
RPC style endpoints
RPC style endpoints

A integração de estilo RPC usa WSDL para usar uma chamada de método "regular" e subtraí-la para SOAP. Dessa forma, cada classe mapeia para um tipo em WSDL, incluindo os tipos de todos os seus parâmetros. Essa abordagem une firmemente os dois lados da conversa porque eles contam com WSDL para definir o que é enviado e o que é esperado. O problema está nessa definição estrita. E se você precisar modificar um dos aplicativos para que sejam usados parâmetros diferentes ou alterar o tipo de um existente, não sendo possível dessa forma modificar os dois aplicativos ao mesmo tempo? Como você cria a versão do terminal? Diversas formas são possíveis, mas todas elas têm sérios comprometimentos. Por exemplo, é possível criar outro terminal com a nova definição de WSDL. Se o terminal original tiver o nome addOrder, você poderá criar outro terminal com o nome addOrder2. Você pode ver a que incerteza isso leva. Em breve, você terá dezenas de terminais levemente diferentes, com código duplicado em toda parte, lidando com uma situação de cada vez porque é difícil de antecipar como as pessoas usarão o ponto de integração quando ele estiver publicado. Jogos podem ser executados com resolução de terminal com o uso de ferramentas como Universal Description, Discovery, and Integration (UDDI) (ou apenas um mapa de hash), mas a escala não fica boa. O problema fundamental é o acoplamento forte entre os terminais, o que os impede de evoluir em um ritmo natural e independente.

Uma abordagem alternativa é trata os terminais de integração como tipificados fracamente, como mostrado na Figura 6:

Figura 6. Usando tipificação fraca em terminais de integração
Document centric integration
Document centric integration

No envio das informações interessantes ao terminal dentro de um documento, pode-se deixar a definição de terminal inalterada nas atualizações grandes e pequenas para qualquer lado da conversa. Em vez de contar com WSDL para definir de modo convincente o que espera, você tem a opção de flexibilidade. Agora, o terminal usa um documento que encapsula os tipos de coisas de que o terminal precisa.

Para manipular a versão do terminal, a primeira etapa de resolução do terminal é descompactar o documento, determinar o que foi passado e reconciliar isso com o que é esperado. Eu geralmente uso uma combinação dos padrões de design Fábrica e Estratégia (consulte Recursos) para determinar se estou conseguindo o que espero, como mostrado na Figura 7:

Figura 7. Descompactando o conteúdo dentro do terminal para determinar os tipos
Strategies to determine typing
Strategies to determine typing

A primeira tarefa do terminal é olhar o manifesto do documento e determinar o que ele contém. Em seguida, ele usa uma fabrica para instanciar a estratégia correta, a fim de extrair essas informações do documento. Quando todas as partes tiverem sido verificadas (com o uso de WSDL, se necessário), os objetos desserializados serão enviados adiante para processamento de negócios.

Inúmeros benefícios aparecem nessa abordagem. Primeiro, é uma má ideia ter um mecanismo com duas tarefas ortogonais, embora seja isso o que a RPC tradicional considere: o terminal é responsável por fornecer a API publicada para integração e para verificar a tipificação. Como ele tem dois comportamentos, você tende a misturar o código, tornando a sua compreensão e a sua manutenção mais difíceis. Segundo, agora é possível ter qualquer número de usuários nesse terminal, todos usando versões um pouco diferentes dele. Quando tiver uma estratégia, você poderá oferecer suporte a qualquer versão (incluindo versões antigas de aplicativos de atualização lenta) com o mesmo terminal. Isso lhe permite efetuar as alterações necessárias, e você não precisa se preocupar em forçar o restante dos aplicativos da empresa a acompanhar as suas alterações. Eles podem mudar e usar novas versões de documento em suas próprias escalas de tempo.

Não existe (ainda) nenhuma ferramenta ou estrutura disponível que permita implementar essa abordagem de maneira trivial, mas um pouco mais de trabalho proporciona os benefícios já mencionados. É possível implementar esse estilo usando SOAP ou REST (embora isso seja mais fácil em REST porque REST é inerentemente voltado para documentos). Quando se cria um ecossistema tipificado fracamente, é possível permitir que grupos de desenvolvimento diferentes sigam no seu próprio ritmo, permitindo que toda a empresa use aplicativos para seguir adiante com a menor dificuldade possível. É essa a essência da arquitetura evolucionária: estabelecer uma base que permita uma mudança sem dificuldades no ritmo mais rápido possível sem comprometer os recursos.

Conclusão

A arquitetura é um tópico grande e complexo em software; nesta parte, eu tentei tocar em vários assuntos diferentes, desde política até os detalhes de implementação para versão de terminais em SOA. Em partes futuras, mostrarei mais dessas ideias sobre arquitetura em geral e algumas abordagens de arquitetura novas para criar uma SOA que possa ser expandida sem a necessidade de pagar milhões a fornecedores.


Recursos para download


Temas relacionados

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=472264
ArticleTitle=Arquitetura Evolucionária e Design Emergente: Arquitetura evolucionária
publish-date=01192010