Arquitetura Evolucionária e Design Emergente: Arquitetura evolucionária

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

Esta parte da arquitetura evolucionária e o design emergente lida com uma variedade de tópicos relacionados à arquitetura evolucionária, incluindo a distinção importante entre design e arquitetura (e como mencioná-los separadamente), alguns problemas que surgem quando se cria arquitetura em nível corporativo, e a diferença entre a tipificação estática e dinâmica em arquiteturas orientadas a serviço.

Neal Ford, Application Architect, ThoughtWorks Inc.

Neal FordNeal Ford é um arquiteto de software e Meme Wrangler, na ThoughtWorks, uma consultoria global de TI. Projeta e desenvolve aplicativos, materiais de instrução, artigos para revistas, treinamentos e apresentações em vídeo/DVD, e é autor ou editor de livros que abordam uma variedade de tecnologias, inclusive The Productive Programmer Seu enfoque é o projeto e construção de aplicativos corporativos de grande porte. Também é orador internacionalmente aclamado nas conferências de desenvolvedores ao redor do mundo. Conheça seu Web site.



19/Jan/2010

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.

Sobre esta série

Esta série visa prover uma nova perspectiva sobre conceitos de arquitetura e design de software frequentemente discutidos, mas elusivos. Por meio de exemplos concretos, Neal Ford oferece a você um embasamento sólido nas práticas ágeis da arquitetura evolucionária e do design emergente. Por adiar decisões importantes sobre arquitetura e design até o último momento responsável, é possível impedir a complexidade desnecessária oriunda da subavaliação dos projetos de software.

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

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

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

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.

Evite a armadilha

Lembre-se: nem todos os processos de negócios podem ser transformados em bens, e há os que variam de uma empresa para outra. Não caia na armadilha de acreditar nos fornecedores que dizem já ter uma solução pronta para o seu processo de negócios. Se eles tiverem, você pode apostar que estão vendendo essa mesma solução para os seus concorrentes também.

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

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

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

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

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

Aprender

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


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