Como tratar falhas em web services – Idempotent Retry Pattern (parte 1 de 2)

Livro Service Design Patterns - de Ian RobinsonOlá pessoal,

Nos dois posts anteriores vimos alguns padrões para requisição e reposta de serviços, como por exemplo, os padrões síncronos Request/Response e Asynchronous Response Handler e os padrões assíncronos Request/Acknowledge/Pool e Request/Acknowledge/Callback, que foram discutidos em detalhes. Em todos os padrões para requisição e resposta de serviços que vimos, podemos nos deparar com problemas de indisponibilidade, o que levará a uma falha que será percebida pela aplicação consumidora. Se tal falha não for tratada adequadamente, poderemos ter o nível de confiabilidade (reliability) da solução diminuído, além da possibilidade de termos impactos para o negócio.

Neste post veremos como endereçar esta questão através de um padrão para tratamento de falhas de disponibilidade de serviços, também descrito no livro Service Design Patterns, de Ian Robinson.

Infraestruturas em geral muito dificilmente estão disponíveis em 100% do tempo. Comumente encontramos níveis de disponibilidade estabelecidas por SLA’s de 99.9%, 99.8% e 98%, que implicam em 8,76, 17,52 e 175 horas de indisponibilidade por ano, respectivamente. Menos comuns, porém, são infraestruturas estruturadas para 99.99% ou 99.999%, que representam 52,56 e 5,25 minutos de indisponibilidade por ano, respectivamente. Diversos são os recursos envolvidos para se estabelecer uma infraestrutura de alta disponibilidade e o custo associado é proporcionalmente alto. Mesmo em infraestruturas de alta disponibilidade, como as que garantem 99.999%, ainda temos períodos de indisponibilidade acordados em contrato, que podem calhar no momento exato da chamada de um serviço hospedado em tal infraestrutura.

É preciso ainda considerar que mesmo serviços hospedados na nuvem estão sujeitos à impossibilidade de acesso, seja por uma indisponibilidade prevista em um SLA definido pelo próprio provedor da infraestrutura, ou por indisponibilidade de banda da organização consumidora, ou ainda do seu provedor de internet (ISP), por exemplo.

Neste contexto, como garantir que chamadas à web services (sejam síncronas ou assíncronas) sejam bem sucedidas, independentemente de indisponibilidades de infraestrutura (falhas de rede ou de servidores)? Veremos a seguir mais detalhes sobre as possíveis causas de falhas em requisições de serviços e posteriormente possíveis soluções.

Tipos de Falha

Toleráveis

Em determinadas situações, falhas em chamadas de serviços são toleráveis. Considere, por exemplo, um serviço de busca de restaurantes, acionado pela implementação de uma funcionalidade acessada diretamente pelo usuário. Caso a requisição a este serviço não seja bem-sucedida, o usuário poderá ser notificado, podendo, por sua vez, acionar a mesma funcionalidade novamente, até que uma eventual falha temporária seja corrigida e o resultado esperado seja retornado.

Falha no estabelecimento de conexão

Um consumidor de serviço pode não ser capaz de se conectar ao serviço seja por instabilidade de rede – redes possuem intrinsicamente características de baixa confiabilidade – ou indisponibilidade de servidor (aquele que hospeda o serviço, por exemplo). Tais problemas podem ser temporários – uma instabilidade retomada em poucos segundos – ou crônica – uma indisponibilidade de servidor mais séria, por exemplo, como danos à CPU ou ao disco, em uma infraestrutura não projetada para alta disponibilidade.

Perda de conexão

Um consumidor de serviço pode enviar uma requisição ao serviço com sucesso, porém, pode ter sua conexão perdida enquanto o serviço ainda está processando sua requisição. Se o consumidor do serviço considerar que houve uma falha e enviar a mesma requisição novamente, é possível que dados sejam duplicados no provedor do serviço, o que causaria inconsistências e diminuiria a confiabilidade da solução.

Sobrecarga de servidores

Servidores podem estar sobrecarregados de tempos em tempos, de forma que se tais eventos coincidirem com momentos em que os serviços hospedados por eles são requisitados, haverá a possibilidade de o servidor recusar o estabelecimento da conexão ou não ser capaz de processá-la.

Timeout

Seja por sobrecarga de servidores, ou por qualquer falha que faça com que o servidor destino demore mais para responder do que o normal, um timeout poderá ser lançado no consumidor do serviço. A configuração e um tempo condizente de timeout é de extrema importância, para que o consumidor do serviço não fique bloqueado indefinidamente em tais situações. É importante notar que quando um timeout é lançado no consumidor do serviço, não é possível estabelecer se a requisição foi processada com sucesso ou não pelo serviço, uma vez que o processamento pode ter sido bem-sucedido momentos após a perda da conexão.

Indisponibilidade de URI

Uma vez estabelecido o serviço em produção, tal problema é menos comum. Porém, existem cenários de implementação que podem potencializar situações como esta. Serviços que implementam o padrão REST, por exemplo, frequentemente retornam como resposta URI’s para outras funcionalidades / dados. Tais URI’s podem ou ser inválidas por um bug de implementação ou podem ainda não estar disponíveis no momento da sua requisição. Este último cenário é conhecido como “race condition”, onde o consumidor do serviço compete com o serviço em si. Se o cliente for mais rápido, então links providos na comunicação anterior podem ser inválidos. Porém, se o cliente aguardar ou tentar novamente, as mesmas URI’s serão válidas posteriormente.

Possíveis soluções

A utilização de um sistema de enfileiramento de mensagens, como Microsoft Message Queue ou WebSphere MQ, resolveria o problema, uma vez que tais sistemas implementam o que se chama de garantia de entrega. Com a garantia de entrega (ou guaranteed delivery), quando uma fila remota não está disponível ou acessível, as mensagens são guardadas em uma fila local até que a infraestrutura remota seja restabelecida. Uma vez que a infraestrutura de enfileiramento de mensagens remota esteja estabelecida novamente, as mensagens pendentes serão entregues, podendo ser consumidas pelo sistema destino.

O problema com esta abordagem é que ele requer um protocolo de comunicação específico e proprietário, o pode não ser viável ou acessível para qualquer sistema. Ou seja, a interoperabilidade provida por protocolos de comunicação estabelecidos sobre HTTP, como SOAP e REST, não é mantida em tal abordagem. Além disso, a exposição de sistemas de enfileiramento de mensagens diretamente através de um firewall corporativo para consumidores externos à organização pode implicar na necessidade de abertura de portas, o que junto com outras questões, podem implicar em riscos à segurança.

Como endereçar então falhas em requisições de web servies de forma adequada?

Este é tópico do próximo post, onde será detalhado o padrão Idempotent Retry Pattern.

Até lá!

Synchronous x Asynchronous Services – Parte 2

Livro Service Design Patterns

Olá pessoal,

No post anterior vimos alguns padrões para modelos de processamento síncronos de web services. Vimos também os problemas decorrentes destes padrões, como por exemplo, o acoplamento temporal, que está relacionado à dependência que consumidores de serviços síncronos possuem com relação ao tempo de processamento do serviço, para que a operação seja bem sucedida. Problemas com estouro do tempo de resposta previsto (timeout) podem fazer com que mensagens sejam perdidas, diminuindo a confiabilidade da abordagem. Outros problemas relacionados também são, por exemplo, a dependência com relação à disponibilidade de todos os demais sistemas subjacentes ao serviço (sistemas gerenciadores de banco de dados, rede, servidores de aplicação, sistema de arquivos, etc.). Caso haja qualquer indisponibilidade em tais componentes, consumidores de serviços síncronos são diretamente afetados. Além disso, cargas acima do planejado em serviços que implementam o padrão Request/Response comprometem seu funcionamento e o da infraestrutura que o suporta, uma vez que todas as requisições são processadas assim que recebidas, dado o fato de que o número de requisições a serem processadas em paralelo é, em geral, comandado pelo cliente.

Para endereçar tais questões, no livro Service Design Patterns é sugerido à utilização de padrões assíncronos, e a utilização de message queues seria uma alternativa. Tal mecanismo permite que um cliente envie uma mensagem para uma fila remota em qualquer horário, independentemente do estado operacional do sistema destino. Usualmente, mensagens são salvas em filas locais até que as filas destino estejam disponíveis. Consumidores de mensagens podem proteger recursos dos sistemas remotos pela implementação de mecanismos de “throttling” (afunilamento – controle da taxa de Fluxo do padrão Request/Acknowledgeprocessamento de mensagens), desta forma endereçando requisitos de escalabilidade e disponibilidade de forma mais eficiente do que o padrão síncrono Request/Response visto anteriormente.

Se por um lado a utilização de message queues resolve boa parte dos problemas, por outro, novos problemas podem ser introduzidos. O uso de mensageria, em geral, é aconselhado como uma abordagem interna à corporação, ou seja, não deveria ser exposto diretamente além do firewall corporativo, seja por questões de segurança, seja por acoplar consumidores externos às tecnologias específicas dos sistemas de mensageria.

Para endereçar tais questões, é sugerida então a utilização do padrão de web services Request/Acknowledge, no qual um web service recebe uma requisição, a encaminha para um processo em background (uma thread secundária, por exemplo) e então retorna uma mensagem ao consumidor (acknowledgment) contendo um identificador único para referência futura. Veja como isso funciona no diagrama de sequencia ao lado (direito).

Em diversas situações apenas o recebimento de um “acknowledgment” é suficiente para o consumidor saber que sua requisição foi armazenada para processamento posterior. Porém, em outras situações, um cliente pode precisar de uma resposta, seja, por exemplo, de um processo de longa duração iniciado pela requisição inicial. Imagine um cenário em que uma requisição é enviada contendo uma solicitação de compra. Um retorno (acknowledgment) é enviado para consumidor informando que a solicitação foi recebida e que será processada. Um acknowledgment contendo um ID único serve como um protocolo de recebimento, um recibo. Quando todos os processos de aprovação da compra (sejam automáticos ou manuais) forem finalizados, o que pode demorar horas ou dias, dependendo do processo da organização, o cliente deverá ser informado, para que possa tomar outras ações.

Existem três formas no qual o padrão Request/Acknowledge permite prover respostas assíncronas aos consumidores de serviços. Vejamos a seguir.

Request/Acknowledge/Poll

Fluxo do padrão Request/Acknowledge/PollNeste padrão, uma vez que o cliente possui um acknowledge contendo um identificador único da sua requisição, ele fica constantemente consultando um outro serviço pelo resultado do seu processamento. Veja no diagrama de sequencia ao lado (esquerdo) a ilustração do fluxo deste padrão.

Os problemas decorrentes da utilização deste padrão estão relacionados ao intervalo de tempo em que o cliente efetua consultas pelo resultado final da operação. Se o intervalo de tempo for alto, então poderá haver um atraso entre o tempo em que o resultado final está pronto e o tempo em que ele é obtido. Se for baixo, então uma carga excessiva poderá ser colocada nos servidores envolvidos, além de aumentar trafego de rede.

Request/Acknowledge/Callback e Request/Acknowledge/Relay

No padrão Request/Acknowledge/Callback ao invés do cliente ficar constantemente buscando pelo resultado final da operação, ele é avisado através de um serviço que ele deve prover ou através do encaminhamento para outras partes interessadas. Esta última variação descreve o padrão Request/Acknowledge/Relay. A vantagem de tais abordagens com relação ao Request/Acknowledge/Poll está no tempo em que o cliente receberá a resposta e nos recursos consumidos para tal. Veja no diagrama de sequencia a mais abaixo (à direita) a ilustração do fluxo descrito.

Note que a forma pela qual o processador de requests pode saber para qual serviço ele deve retornar o resultado pode ser tanto através de um endereço provido no request inicial, pelo próprio cliente (veja, por exemplo, WS-Addressing), quanto através de configurações que relacionem o tipo de mensagem / processamento aos destinatários interessados (relay). Quando os destinatários de mensagens de callback são especificados pelo consumidor, cuidados especiais devem ser tomados para que eles não sejam alterados no meio do caminho. Segurança no nível de transFluxo do padrão Request/Acknowledge/Callbackporte ou mesmo WS-Security podem ser usados para mitigar este risco.

Algumas considerações devem ser levadas em conta antes de optar por um dos padrões. Em geral, o padrão Request/Acknowledge/Poll é mais simples de se implementar e de se depurar do que o padrão Request/Acknowledge/Callback. O planejamento de capacity também é diferenciado dentre as abordagens. Se o callback for efetuado sempre para um destinatário apenas, então o número de mensagens de resposta deve ser semelhante ao que se teria no padrão Request/Response. Porém, se o número de destinatários for significante e se houver necessidade de transformar mensagens em formatos específicos para cada destinatário, então, os recursos de infraestrutura necessários devem ser maiores, o que pode implicar em investimentos mais significativos.

O padrão Request/Acknowledge/Callback pode não ser viável em cenários em que o cliente não pode ou não está disposto a prover um serviço para receber retornos, seja pela necessidade de abertura de porta para recebimento de trafego de dados, seja pela falta de recursos para prover infraestrutura necessária. Neste caso, a única alternativa possível para o recebimento de retornos seria o Request/Acknowledge/Poll.

Conclusão

Diante de tantos fatores a serem levados em consideração quando da escolha por um dos padrões mencionados, uma “Trade-off Analysis” pode lhe ser útil para ajudar em sua decisão, dado seu contexto de aplicação.

Neste post ficamos por aqui. Até o próximo!

Synchronous x Asynchronous Services – Parte 1

Olá pessoal,

Livro Service Design Patterns

Neste post gostaria de trazer um assunto bastante recorrente em discussões relacionadas à integração, principalmente quando o meio escolhido para a tal é web service: quando que serviços devem ser síncronos ou assíncronos e quais as vantagens e desvantagens de ambas as abordagens. Além disso, discutiremos também, para o caso de serviços assíncronos, quais os padrões que podemos considerar para retornarmos um determinado resultado para o chamador do serviço, uma vez que o processamento tenha sido concluído. Padrões como Request/Response, Asynchronous Response Handler, Request/Acknowledge/Poll e Request/Acknowledge/Callback serão explicados, bem como o impacto da sua adoção na forma como os serviço são estruturados, o que incorre em esforço de desenvolvimento, timing de atualização e recuperação de informações, além de disponibilidade e escalabilidade do serviço provido. Neste primeira parte (parte 1) focarei em em padrões de serviços síncronos (padrão Request/Response e Asynchronous Response Handler) e no seguinte fecharei a comparação com os padrões de implementação de serviços assíncronos (Request/Acknowledge/Poll e Request/Acknowledge/Callback).

Todas estas questões e diversas outras, como padrões de APIs de serviços, padrões de interação client-service (que discutiremos em parte neste artigo), padrões para gerenciamento de requisição e resposta, padrões para implementação de serviços, padrões de infraestrutura de serviços e padrões de evolução de serviços, todos bastante relevantes e úteis em qualquer discussão que envolva web service como meio de integração, podem ser encontradas no livro Service Design Patterns de Robert Daigneau, que conta com prefácio de nada mais nada menos que Martin Fowler, além de Ian Robinson.

Serviços que implementam o padrão Request/Response

Padrão Request/Response

Um serviço que implementa o padrão Request/Response processa requisições assim que elas são recebidas, retornando resultados em uma mesma conexão de um cliente, de forma síncrona. Uma vez que o cliente submeta uma requisição, usualmente ele não continua com seu processamento até que uma resposta seja retornada. Na utilização deste padrão, frequentemente assume-se que o processamento será concluído em apenas alguns segundos. Dentre os padrões que serão abordados, o padrão Request/Response é mais simples de se implementar, depurar e testar, uma vez que funciona como uma chamada remota de uma operação, com parâmetros de entrada e resposta síncrona. Veja a exemplificação do padrão Request/Response no diagrama de sequencia ao lado.

O padrão Request/Response é indicado para casos em que uma resposta imediata seja necessária, como por exemplo, uma página web que proveja uma funcionalidade para consulta de abertura de vagas, cuja consulta das vagas disponíveis seja provida por um serviço.

Acoplamento temporal (temporal coupling)

A adoção do padrão Request/Response incorre em algumas implicações. Acoplamento temporal é uma delas. O acoplamento temporal remete à dependência do tempo de resposta que um serviço que implementa o padrão Request/Response implica para seu consumidor. No padrão Request/Response é assumido que o serviço sempre poderá processar uma requisição quando esta for recebida e que uma resposta será enviada assim que o processamento for encerrado. A implicação neste caso é que todos os sistemas dos quais o serviço depende (banco de dados, servidores de arquivos, etc.) sempre devem estar operacionais e sempre devem estar aptos a processar requisições imediatamente. Se tais sistemas estiverem indisponíveis, seja por uma falha ou por uma parada programada para manutenção, então as requisições dos clientes poderão ser rejeitadas.

Problemas relacionados ao tempo de resposta do serviço podem ainda acontecer mesmo quando todos os recursos dos quais o serviço dependem estão disponíveis. Uma vez que este padrão requer que requisições sejam processadas assim que recebidas, um grande volume de requisições pode comprometer a capacidade do sistema. Ao adotar tal padrão é preciso compreender a carga típica que o serviço deterá ter e projetar a capacidade de servidores, bancos de dados, rede, etc. de forma a endereçar tais cargas. Uma arquitetura tal deve ser projetada para que seja possível escalar horizontal ou verticalmente tais recursos, uma vez que as demandas de requisição aumentem ao longo do tempo. A adoção dos padrões assíncronos Request/Acknowledge/Poll e Request/Acknowledge/Callback, que serão vistos no próximo post, ajuda a mitigar esta necessidade, uma vez que transfere do cliente do serviço para o provedor do serviço o controle das requisições que serão processadas em paralelo.

O acoplamento temporal também traz implicações relacionadas ao tempo em que o consumidor do serviço aguardará por uma resposta antes que um timeout seja lançado. Nestes casos, uma vez que o processamento já tenha sido iniciado pelo serviço, a resposta não seria recebida pelo cliente, implicando em perda de sincronismo ou inconsistência de dados. As razões para que um serviço demore mais para responder do que o tempo planejado são inúmeras. Atividades que requeiram maior I/O, altos níveis de trafego de rede são exemplos comuns. Neste ponto, mais uma vez os padrões de serviços assíncronos são mais vantajosos.

Client-side Blocking / Asynchronous Response Handler

Por padrão, clientes de serviços que implementam o padrão Request/Response aguardam pela resposta do serviço invocado sem realizar outras operações no meio tempo. Esta característica é conhecida como “Client-side Blocking”, uma vez que o cliente fica bloqueado até que uma resposta do serviço chamado seja retornada. Para casos em que se deseje aproveitar o tempo de espera de um serviço processando outras atividades, pode-se utilizar o padrão denominado “Asynchronous Response Handler” em conjunto com o padrão Request/Response, o qual permite que o cliente efetue requisições para um serviço Request/Response, delegando o recebimento da resposta para um thread apartada da thread principal, de forma que outras atividades sejam executadas na thread principal logo após a requisição do serviço. Veja no diagrama de sequencia mais abaixo a ilustração desta implementação.

É importante destacar que este padrão também não garante que respostas não sejam perdidas, como já descrito anteriormente.

Sync Services with Async Response Handler

Por todos os motivos apresentados, podemos concluir que o padrão Request/Response deve ser usado apenas quando for possível garantir que o tempo médio de resposta do serviço seja relativamente baixo, e que o cliente será projetado para tolerar perda de respostas. No próximo post veremos como os padrões assíncronos ajudam a mitigar os riscos relacionados ao acoplamento temporal, à perda de sincronismo e inconsistência de dados, além de permitir que o cliente não fique bloqueado enquanto aguarda o resultado do processamento.

Neste post ficamos por aqui. Até o próximo!

Shortsightedness in IT – Thomas Erl

Olá pessoal!

Oracle Technology Network ArchBeat PodCastQuantas vezes nos deparamos com as frustrantes situações em que uma determinada solução tecnológica, aderente aos padrões corporativos e que melhor atende aos requisitos não-funcionais estabelecidos, não pode ser aplicada em um projeto, seja por não haver tempo hábil, por exemplo, levando a adoção de abordagens que nem sempre trazem bons resultados a longo prazo?

Neste post gostaria de compartilhar um trecho de um podcast publicado pelo Oracle Technology Network, em seu canal ArchBeat Pod Cast, onde Thomas Erl – best selling SOA author, explica como tais situações normalmente se originam. Segundo Thomas, existe o que ele chama de miopia na perspectiva considerada na avaliação dos resultados de projetos, onde acaba-se sendo considerado apenas prazo, orçamento e atendimento dos requisitos funcionais como critérios que definem se um projeto foi ou não bem-sucedido, deixando de lado a qualidade da arquitetura implantada, o que acaba resultando em defasagem tecnológica, projetos que geram silos de informação e aplicações que atendem apenas a um propósito, consequentemente aumentando o custo de propriedade do produto produzido pelo projeto. Confira abaixo.

Miopia em TI

“… the criteria organizations use to evaluate project team performance, I think there still a lot of tactical emphasis on determining what was and what was not a successful project and by that I mean did it come under budget, did it come on time, did it meet functional requirements and those tend to be focal points when projects are assessed and it is easy to lose sight of the importance of what you are designing and the long term implications of what you are building when you are focusing more on the timeline, the budget and meeting the functional requirements within the primitives of that budget and timeline. And it is easier to meet those goals as you are being assessed by bypassing proper technology architecture and just getting developers to build something that works as per the immediate functional requirements and if you as a project manager are not being assessed based on the quality of the technology architecture, its compatibility with the surrounding IT enterprise architecture, its compliance to predefined standards, then there is no means of assessing that or regulating that, then there is no motivation to really emphasize that or make that part of the project cycle, because it will just use up more time and resources and will go against the other points which you are being evaluated. So I think that assessment from a strategic perspective is also lacking in some IT environments and that is to their detriment in the long term, because it is not part of how they assess project, applications, delivery projects, then those projects do became very much silo based, single purpose and then, consequently, impact the subsequent governance and ownership burden that IT enterprise assumes and it is that shortsightedness that I think also leads to situations like that where IT architects are not given the level of responsibility that they should.”

A não mudança de tal cultura leva a geração de conflitos constantes entre os times de projetos e os times de arquitetura, pelos seus diferentes interesses. A convivência em projetos com tais conflitos acaba não sendo saudável para nenhum dos envolvidos, nem tão pouco para o próprio projeto. Decisões de design que deveriam ser facilmente tomadas precisam ser escaladas para a gestão, o que acaba gerando ainda mais desgaste – quando não há politicagem – atrasos e posterior pressa para implementar o design decidido.

E por esta razão, acredito que organizações hoje tenham chegado a um nível de maturidade onde já enxergam a necessidade e os benefícios da adoção das disciplinas de arquitetura, porém, ainda precisam evoluir para um próximo nível, onde estarão aptas a de fato empregar eficientemente tais áreas em seus projetos.

A responsabilidade de um “profissional” de software

Olá pessoal!

Neste artigo gostaria de compartilhar um trecho do livro “The Clean Coder”, de Robert C. Martin (Uncle Bob), que trata de ética e conduta profissional para nós, profissionais de desenvolvimento de software. O trecho aborda dois tópicos de extrema relevância. O primeiro é sobre decisões políticas ou baseadas apenas em questões financeiras de curto prazo e o segundo é sobre a responsabilidade que um profissional de software responsável por decisões técnicas (seja um arquiteto de software ou qualquer outro papel correspondente) tem ao assumir tal papel.

The Clean Coder

Em um projeto, diferentes stakeholders demandam diferentes requisitos não-funcionais, muitas vezes conflitantes entre si. Gerentes de projetos, por exemplo, em geral priorizam o prazo estabelecido com as áreas de negócios (time-to-market). Áreas que manterão o sistema (que aplicação mudanças evolutivas / corretivas, por exemplo), demandam um sistema que seja modificável (modifiability). Um sistema projetado para ser modificável, em geral, leva mais tempo para ser construído. E esta aí o primeiro e mais comum conflito. A figura mais abaixo (extraída de materiais do Software Engineering Institute – SEI) representa este cenário.

Neste contexto, se por um lado um gestor tem a responsabilidade de não tomar decisões baseadas apenas em questões políticas e financeiras de curto prazo, um arquiteto de software tem o dever, a responsabilidade, de apontar de todas as formas possíveis, os possíveis riscos que uma determinada decisão de projeto (seja de design, por exemplo) pode apresentar.

Poor architectA história descrita por Bob Martin fala de uma decisão política / financeira, tomada em um lançamento de uma nave aeroespacial, que não levou em consideração os riscos levantados pelos engenheiros responsáveis, culminando na perda de sete vidas. Veja a seguir.

At 11:39 AM EST on January 28, 1986, just 73.124 seconds after launch and at an altitude of 48,000 feet, the Space Shuttle Challenger was torn to smithereens by the failure of the right-hand solid rock booster (SRB). Seven brave astronauts, including high school teacher Christa McAuliffe, were lost. The expression on the face of McAuliffe’s mother as she watched the demise of her daughter nice miles overhead haunts me to this day.

The Challenger broke up because of hot exhaust gasses in the failing SRB leaked out from between the segments of its hull, splashing across the body of the external fuel tank.

… The engineers at Morton Thiokol who designed the SRB had known that there were problems with the O-rings [SRB component that was identified as the cause of the incident], and they had reported those problems to managers at Morton Thiokol and NASA seven years earlier.

… The engineers had designed a repair for the problem, but implementation of that repair had been long delayed.

… In short, the engineers knew that the risk was too high. The engineers acted on that knowledge. They wrote memos raising giant red flags. They strongly urged Thiokol and NASA managers not to launch. In an eleventh-hour meeting held just hours before the launch, those engineers presented their best data. They raged, and cajoled, and protested. But in the end, the managers ignored them.

… Despite all the protest and memos, and urgings of the engineers, the managers believed they knew better. They thought the engineers were overreacting. They didn’t trust the engineers’ data or their conclusions. They launched because they were under immense financial and political pressure. They hoped everything would be just fine.

These managers were not merely foolish, they were criminal. … They made a decision they had no right to make. They usurped the authority of people who actually knew: the engineers.

But what about the engineers? Certainly the engineers did what they were supposed to do. They informed their managers and fought hard for their position. They went through the appropriate channels and invoked all the right protocols. They did what they could, within the system – and still the managers overrode them.

E por fim, Bob Martin conclui: ”… As an engineer, you have a depth of knowledge about your systems and projects that no managers can possibly have. With that knowledge comes the responsibility to act.”

É claro que como arquitetos de software muito dificilmente estaremos envolvidos em decisões que poderão implicar em vida ou morte de pessoas. Porém, é certo que determinadas decisões mal tomadas implicarão, a médio/longo prazo, em custos de manutenção e de propriedade mais altos, tempos de entrega mais longos (time-to-market) e em requisitos não atendidos. Quando tais problemas perduram, toda uma área de TI passa a ser mais um custo necessário, ao invés de uma área estratégica para o crescimento da companhia.

O que faz um arquiteto de software?

Olá pessoal!

O título deste post pode ser interpretado sob duas perspectivas. Uma possível interpretação é “O que um arquiteto faz em seu dia-a-dia?”. Outra poderia ser “O que forma um arquiteto?”. Ambas as interpretações estão corretas e a resposta para ambas as questões é a mesma: Quality Attributes. Continue lendo e entenda o motivo.

imageNeste post inicio uma série em que abordarei um assunto de extrema importância dentro de arquitetura de software: atributos de qualidade. Sob este nome o tema pode parecer um pouco obscuro, porém, pode se tornar familiar sob outra definição: requisitos não-funcionais.

O conteúdo deste e dos demais posts desta série é baseado principalmente no livro Software Architecture in Practice – Second Edition, já mencionado em posts anteriores, no conteúdo do curso Software Architecture Principles and Practices, ministrado pelo Software Engeneering Institute (SEI), sendo complementado por outros materiais.

O que são atributos de qualidade?

É possível dizer que atributos de qualidade são considerados em praticamente todos os esforços de desenvolvimento de sistemas. Muito provavelmente você (e eu também) considera atributos de qualidade em suas demandas de forma inconsciente. E para provar esta teoria, um exemplo de um sistema que não leva em consideração atributos de qualidade, seria um sistema estruturado de forma monolítica, sem nenhuma estrutura de organização interna. Quantas vezes você considerou esta abordagem nos sistemas que projetou?

Desta forma, percebemos que um sistema não tem como requisito apenas funcionalidades que deve prover (requisitos funcionais). Time-to-market (um atributo de qualidade voltado ao negócio) e modificabilidade são frequentemente atributos de qualidade (ou requisitos não funcionais) que levam a estruturação de um sistema em módulos, de forma que ele possa ser construído em paralelo por mais de uma pessoa (time-to-market), ao mesmo tempo atribuindo responsabilidades de forma coerente (low coupling e high coesion), o que possibilita maior facilidade em modificações futuras (modificabilidade). Estes, portanto, são os motivos que nos levam a não projetar um sistema monolítico: atributos de qualidade.

O mesmo vale quando falamos da opção pela utilização de um padrão MVC, por exemplo. Essa escolha tem (ou pelo menos deveria ter) como motivação não apenas o fato de se estar seguindo uma tendência recente. O padrão MVC possibilita a que um sistema tenha atributos de qualidade como modificabilidade, já que é estruturado em camadas com responsabilidades bem definidas (separation of concerns), permitindo, por exemplo, que alterações no design da aplicação (tela) não necessariamente afetem a lógica de programação, e vice-versa. Testabilidade é outro atributo de qualidade decorrente da utilização deste padrão, já que possibilita a execução de testes unitários na camada de apresentação, por exemplo. Ambos, modificabilidade e testabilidade, trazem como beneficio para o negócio atributos como um baixo time-to-market, já que manutenções evolutivas serão implementadas mais rapidamente, e maior disponibilidade (availability), já que a aplicação de testes unitários tende a reduzir o número de bugs de um sistema, tornando-o mais estável (disponível) para o usuário final.

Podemos entender então que atributos de qualidade são requisitos não-funcionais, ou seja, que não dizem respeito ao que o sistema deve prover em termos de funcionalidade, mas sim, em termos de qualidade. Existem diversas categorias de atributos de qualidade e diversos assuntos relacionados. Availability, modifyability, performance, security, testabiliy, usability, scalability, extensibility, reliability, são exemplos de atributos de qualidade. Existem também alguns conceitos mais difundidos que levam em consideração um subconjunto de atributos de qualidade específicos. Por exemplo:

· FURPS: functionality, usability, reliability, performance, supportability;

· ACID: atomicity, consistency, isolation, durability;

· ISO/IEC 9126: functionality, reliability, usability, efficiency, maintainability;

Por que atributos de qualidade são importantes?

No livro Software Architecture in Practice – Second Edition, é dado um exelente exemplo da importância dos atributos de qualidade:Quality Attributes - Software Engeneering Institute

“Sistemas são frequentemente substituídos ou redesenhados não porque suas funcionalidades são deficientes – as substituições geralmente são idênticas em termos de funcionalidades – mas porque eles são difíceis de manter, portar, escalar, ou porque são muito lentos, ou porque foram comprometidos por hackers” (minha tradução).

E apesar de tal importância, muito frequentemente apenas as funcionalidades são observadas em um ciclo de desenvolvimento de software. Especificações comumente não tratam de atributos de qualidade de forma satisfatória, apesar do fato de que tal detalhamento ser de total interesse dos representantes de negócios de uma organização (veja imagem ao lado – provida pelo SEI). E é ai que o papel do arquiteto torna-se importante dentro de um projeto. É do arquiteto a responsabilidade de delinear os atributos de qualidade de um sistema, caso eles não estejam especificados, de entendê-los, especificá-los segundo o conceito SMART e, posteriormente, de endereça-los através de praticas e padrões arquiteturais (veremos este assunto em detalhes mais adiante).

Por enquanto ficaremos por aqui. Nos próximos posts veremos como analisar, registrar e endereçar atributos de qualidade através de táticas arquiteturais. Depois, partiremos para questões especificas de alguns atributos de qualidade mais relevantes, como por exemplo, availability, performance, security, modifiability e testability. Até lá!

Who gets to be a software architect

Dilbert - ArchitectOlá pessoal!

Neste post gostaria de compartilhar um resumo do conteúdo de um podcast que ouvi recentemente, cujo tema principal era justamente o título deste post: “Who gets to be a software architect”. Acredito que o assunto seja bastante relevante, pois tem sido tema de diversas discussões em diversas comunidades, demonstrando que ainda há pouca maturidade e falta de consenso no mercado.

O podcast foi disponibilizado pelo Oracle Technology Network, no canal ArchBeat, que trata de assuntos relacionados à arquitetura. Para quem ainda não conhece, vale a pena conferir. O canal aborda assuntos diversos relacionados à arquitetura, tecnologias e tendências, como SOA, Cloud Computing, Governança, Enterprise Architecture, Business Architecture, etc.

O podcast consistiu em uma panel discussion, composta por quatro participantes de peso, além do Bob Rhubart, host dos podcasts deste canal. São eles:

  • Ron Batra: Oracle ACE Director, Diretor de desenvolvimento de produtos cloud computing na AT&T;
  • Brian Huff: Oracle ACE Director, Chief Software Architect na Bezzotech, Inc.;
  • Randy Stafford: Membro do Oracle’s A-Team – um grupo de arquitetos que trabalham em um grupo de desenvolvimento Oracle Middleware;
  • Eric Stephens: Enterprise Architecture Director, na Oracle;

A seguir consta o link para mais detalhes do podcast, onde também pode ser baixado o áudio: https://blogs.oracle.com/archbeat/entry/show_notes_who_gets_to_be_a_so.

Separei o conteúdo da discussão em alguns temas, que podem ser conferidos a seguir. Procurei manter o conteúdo fiel ao que foi discutido no podcast, sem incluir opiniões pessoais e sem alterar o sentido ou opinião dos participantes.

O que separa o papel de um desenvolvedor do papel de um arquiteto

Arquitetos caminham na direção de uma liderança técnica, enquanto desenvolvedores estão mais focados em tarefas de codificação. Arquitetos produzem especificações técnicas, diagramas arquiteturais, mas não focam em bits e bytes o tempo todo. O arquiteto estrutura o que deve ser construído. Ao mesmo tempo, arquitetos devem saber programar seu design. Os melhores arquitetos iniciaram sua carreira como desenvolvedores e posteriormente assumiram novas responsabilidades gradualmente.

O fato de estar longe da codificação não exime do arquiteto a responsabilidade de se manter atualizado, contribuindo para o desenvolvimento, o que aumenta sua credibilidade perante o time.

Alguns soft skills diferenciam arquitetos de desenvolvedores. Arquitetos devem saber influenciar, devem ter visão, liderança, devem saber trabalhar com times diversos, comunicar decisões arquiteturais / design.

“The developers are the ones who build skyscrapers, while the architect is someone who designs the city, while enterprise architects are the city planners.“

Diferentes papeis dentro do tema “Arquitetura”

Alguns exemplos de diferentes papeis dentro do tema arquitetura foram citados, demonstrando que ao contrário do que comumente é entendido, não existe apenas o papel do Arquiteto de Aplicações / Sistemas:

  • Infrastructure Architects: focam em detalhes de arquitetura de infraestrutura. Cluster, load balancing, firewalls, virtualização, servidores, etc, são temas recorrentes no seu dia-a-dia;
  • Integration Architects: SOA, EAI e padrões relacionados são suas principais preocupações;
  • Enterprise Architects: Conhecem o mapa de projetos / sistemas / frentes de negócios da corporação, estabelecem roadmaps de tecnologia e lidam com aspectos técnicos e também não-técnicos da organização.
  • Application Architect: Trabalham no nível de projetos. Em geral estabelecem e comunicam visões arquiteturais, que compreendem decisões de design de um projeto.

O título de “Arquiteto” deve ser reservado para aqueles que possuem certificações?IASA Carrer Map

Em geral, certificações mais técnicas focam em um produto ou framework especifico. Neste sentido, um profissional certificado será um excelente profissional para implementação de uma solução e-business, ou para identificar um determinado problema em uma base de dados ou aplicação java. Tais habilidades são extremamente valiosas para desenvolvedores / implementadores de solução, que em geral, procuram certificações para se distinguirem ou se destacarem.

Existem também organizações e certificações voltadas para as diversas segmentações dentro de arquitetura (infrastructure, information, business) e também voltadas à arquitetura corporativa (Enterprise Architecture). O IASA – International Association for Software Architects é uma organização que provê um mapa de carreira com cursos voltados para arquitetos e certificações relacionadas – veja imagem ao lado. O SEI – Software Engineering Institute também provê excelentes materiais e cursos relacionados à arquitetura de software. A Oracle também possui uma certificação voltada a Enterprise Architecture, chamada Oracle Enterprise Architecture Designation, além do Open Group, com o TOGAF.

Para arquitetos, além da competência técnica, habilidades de comunicação são cruciais. Normalmente, um arquiteto deverá passar sua visão para CIO, CTO, CEO, fornecedores, desenvolvedores, etc. Neste sentido, uma certificação não garante que o arquiteto seja competente o suficiente para realizar seu trabalho, já que é muito difícil certificar habilidades comunicacionais. Em geral, o que é levado em consideração na contratação de um arquiteto são suas experiências anteriores bem-sucedidas.

“The person (arquiteto) should have the ability to transcend one technology to the concept.”

Excelentes desenvolvedores podem se tornar arquitetos?

Se você é um excelente vendedor, não significa que você se tornará um excelente gerente de vendas. O mesmo vale para desenvolvedores e arquitetos. Algumas pessoas possuem profundos conhecimentos em bancos de dados, conhecem todas os truques para que o banco de dados ou o java faça exatamtente o que querem, e a forma mais rápida para resolver um problema em um sistema existente. Outras pessoas se dão muito bem quando trabalham em cima de requisitos difusos ou não claros.

É uma questão de mudança de ferramentas. Enquanto que para o desenvolvedor a principal ferramenta de comunicação é o teclado, para o arquiteto sua principal ferramenta deve ser o quadro branco e apresentações power point. Alguns desenvolvedores não gostam de se expor e não há nada de errado nisso. O mais importante é estar fazendo aquilo que se sente bem.

A discussão encerrou com o tema “hot-button issues” (más práticas), comummente cometidas por arquitetos.

  • Decisões “make or buy” devem ser bem pensadas. Por vezes, arquitetos ou pessoas com tal responsabilidade (CIO) decidem por manter e investir em uma ferramenta desenvolvida “in-house”, enquanto que comprar um pacote de mercado e investir em sua implantação pode trazer uma melhor relação custo/beneficio a longo prazo.
  • Um arquiteto não deve optar por tecnologias apenas por possuir conhecimento prévio. O benefício maior para a organização deve ser levado em consideração;
  • Um arquiteto nunca deve misturar diversas visões em apenas um diagrama. É comum encontrar componentes de infraestrutura, fluxo de dados, aplicações, regras e camadas de negócios no mesmo diagrama. Diferentes áreas de conhecimento devem ser representadas em diferentes visões / diagramas.
  • Excelentes comunicadores que não sabem desenvolver seu design não necessariamente são bons arquitetos.
  • Utilizar tecnologias apenas porque todos estão usando, ou utilizar tecnologias recém-lançadas, cedendo ao apelo comercial, não necessariamente é a melhor solução. Arquitetos devem saber selecionar as tecnologias mais apropriadas para o problema em questão, e que melhor se adequem ao cenário da organização.

RDD – Responsibility Driven Design e GRASP – General Responsibility Assignment Software Principles (2 de 2)

Olá pessoal!

Neste artigo veremos os demais padrões GRASP não abordados no anterior. São eles:

Controller – Determina que deve haver uma classe ou camada responsável por receber e tratar eventos da camada de interface com o usuário, delegando as ações para as camadas inferiores, de forma que ela funcione como intermediadora. O padrão também diz que pode ser criada uma controller para cada caso de uso. Ou seja, as funcionalidades providas pela interface, que dizem respeito a determinados casos de uso são delegadas para as controllers correspondentes. O objetivo com a controller é desacoplar (veja Low Coupling) a camada de interface com o usuário – que deve focar em apresentação, estilos, design, etc. – da implementação em si, desta forma aumentando a coesão (veja High Coesion), já que cada camada atenderá apenas a responsabilidades específicas e bem definidas.

Diagrama de classes: Exemplo padrão GRASP Controller

 

Pure Fabrication – Determina que assuntos não diretamente relacionados ao domínio da aplicação devem ser tratados por classes apartadas, denominadas "invenção pura". Ou seja, aquilo que para o domínio da aplicação não faça sentido é considerado e apartado como uma "invenção". Um exemplo desta situação é o encapsulamento de funcionalidades e particularidades para acesso a um banco de dados (componentes que encapsulam o driver de acesso a banco de dados, como por exemplo, o ADO .NET), em classes específicas que possam ser reutilizadas dentre as demais classes que precisam da mesma funcionalidade. Classes utilitárias e diversas funcionalidades providas por frameworks em geral são consideradas invenções puras. Este padrão ajuda no aumento da coesão (veja High Coesion), uma vez que define que as classes de domínio não contenham funcionalidades que vão além das suas reais responsabilidades. Desta forma, o reuso também é favorecido, já que as invenções puras são extraídas do domínio, de forma que possam ser reutilizadas.

Polymorphism – O polimorfismo prega que operações polimórficas sejam utilizadas ao invés de decisões. Para ilustrar este conceito nada melhor que um exemplo. Considere uma classe Pessoa, com os atributos Nome, NumeroCpf, NumeroCnpj e Tipo (Fisica ou Juridica). Neste modelo, todas as classes que precisem obter o documento da pessoa muito provavelmente implementarão um IF com base no atributo Tipo e considerarão ou o NumeroCpf ou o NumeroCnpj como o documento. Segundo o padrão, criar uma operação polimórfica significa criar uma interface Pessoa com o atributo Nome e uma operação ObterDocumento e duas classes que implementam esta interface: PessoaFisica (NumeroCpf) e PessoaJuridica (NumeroCnpj). Cada classe fará sua própria implementação da operação ObterDocumentDiagrama de classes: Exemplo padrão GRASP Polymorphismo, de forma que os demais utilizadores não tenham mais que se preocupar com a regra para obtenção do documento com base no tipo da pessoa. Um benefício desta abordagem é que caso seja necessário adicionar um terceiro tipo de pessoa (PessoaEstrangeira), o impacto seria menor para as classes dependentes, já que a operação polimórfica é a mesma (ObterDocumento).

Indirection – Determina que o sistema não conheça e que não esteja acoplado (veja Low Coupling) às implementações reais e especificas de determinados assuntos. Projetar para indireção pode envolver a criação de camadas que encapsulam determinadas funcionalidades ou que desacoplem outras camadas. O padrão Controller é um exemplo de indireção, já que com ele a user interface não depende diretamente das camadas inferiores (model, por exemplo), e vice-versa. Existem diversas formas de se aplicar a indireção. Além do MVC, outro exemplo de aplicação deste conceito é a Injeção de Dependência, onde as implementações dependem de interfaces que são realizadas em objetos concretos apenas em tempo de execução. Diversos design-patterns também se beneficiam deste conceito, por exemplo: Abstract Factory, Facade, Adapter, Strategy, Proxy, etc. Um exemplo simples e recorrente de indireção é o que o Visual Studio faz quando adicionamos uma referência para um serviço em um projeto. Por traz dos panos são criadas classes Proxy que encapsulam toda a complexidade envolvida no processo de chamar um serviço através do protocolo utilizado (SOAP, p. ex.), serializar e deserializar objetos de transferência, tratar seu retorno, etc. Todo o restante do sistema que utiliza o objeto Proxy criado se quer sabe o que está por traz dele, de forma que se o protocolo de comunicação for alterado, por exemplo, nada será afetado além do Proxy.

Protected Variations – A variação protegida é uma forma de indireção. A diferença é que neste caso o principal objetivo é proteger o sistema ou uma classe de variações previstas ou que tenham grandes possibilidades de ocorrer. Um exemplo deste tipo de situação é quando utilizamos componentes ou serviços de terceiros1 ou mesmo quando precisamos integrar com APIs de pacotes de aplicações. Em todas estas situações a ideia é proteger seu sistema ou sua classe da possibilidade de alteração na interface do componente, do serviço ou da API. As mesmas abordagens e padrões utilizados para a indireção também se aplicam à variação protegida. Conceitos e padrões de EAI (Enterprise Application Integration) e SOA (Service Oriented Architecture) também apoiam a indireção e a variação protegida de uma forma mais ampla.

RDD – Responsibility Driven Design e GRASP – General Responsibility Assignment Software Principles (1 de 2)

158382_4Olá pessoal

Neste post vamos conhecer alguns conceitos de programação orientada a objetos (POO) que nos ajudam a pensar em como estruturar projetos orientados a objetos. Ambos os conceitos abordados neste post estão descritos no livro “Utilizando UML e Padrões – Uma introdução à Análise e ao Projeto Orientado a Objetos e ao Desenvolvimento Iterativo” de Craig Larman – Livro muito bom que trata em detalhes de diversos assuntos bastante pertinentes no nosso dia-a-dia: processos de desenvolvimento iterativos, incrementais e ágeis, papéis e responsabilidades, artefatos, UML, conceitos de programação orientada a objetos, RDD, padrões GRASP, design-patterns (GOF) e outros.

Vamos começar então pelo RDD. Segundo o livro, RDD é uma metáfora geral que nos leva a raciocinar sobre projetos de software orientados a objetos, sob o ponto de vista de responsabilidades. Por responsabilidades, entende-se o que nossas classes de objetos ou mesmo componentes de software devem fazer e saber. Em um modelo de classes o fazer é realizado por métodos e o saber por atributos. Outro conceito envolvido no RDD é o de colaboração. Uma vez definidas as responsabilidades, há de se definir como seus objetos colaboração para que o objetivo seja atingido.

Já o GRASP define nove padrões ou princípios voltados à atribuição de responsabilidades, que apoiam o RDD. Analisando estes conceitos e os padrões GRASP, que veremos em detalhe mais a frente, podemos concluir que ambos apenas endereçam questões básicas de orientação a objetos. E o objetivo é justamente esse. Tanto RDD quanto GRASP servem como uma ferramenta para apoiar no domínio de conceitos básicos de programação orientada a objetos. E quando falamos de conceitos básicos, logo veremos que diversos tópicos abordados fundamentam outros padrões mais específicos, como por exemplo, MVC e os design-patterns do GOF. Isso é interessante, porque para entender estes padrões mais específicos temos que ter os conceitos básicos bem fundamentados. Outro ponto importante é que alguns padrões não se restringe apenas ao mundo de orientação a objetos. Alguns conceitos empregados nos padrões High Coesion, High Coupling, Indirection e Protected Variation são altamente pertinentes e recorrentes em arquiitetura de software. Vamos então aos padrões GRASP.

Diagrama de classes - Composição NotaFiscal - Item

Creator – Este padrão determina quem é responsável por criar quem. Uma das possibilidades a considerar, por exemplo, é que uma classe A deve ser responsável por criar uma classe B caso a classe A tenha uma relação de composição com a classe B. Outra possibilidade citada por este padrão é que a classe A pode ser responsável por criar a classe B caso ela tenha consigo informações suficientes para a inicialização da classe B ou caso use B de maneira muito próxima. Considere, por exemplo, uma relação entre uma classe NotaFiscal e Item, que usualmente denota uma relação de composição. Ou seja, uma nota fiscal é composta por itens de forma que não faça sentido sua existência sem eles. Neste exemplo, a responsabilidade por criar instâncias da classe Item seria da classe NotaFiscal, que poderia fazê-lo através de uma operação “IncluirItem”.

Information Expert – Determina a qual classe deve ser atribuída a responsabilidade de prover uma nova funcionalidade. O padrão diz que a classe que possuir mais informações a respeito da funcionalidade em questão deve ser a responsável por provê-la. Considerando o exemplo anterior (NotaFiscal – Item), caso precisássemos saber a quantidade de itens de uma nota ou o valor total do itens quem deveria ser a classe responsável? A classe NotaFiscal é a classe que tem mais informações sobre seus Itens, já que ela é composta por Itens, logo, as operações ObterQuantidaDeItens e ObterValorTotal é uma responsabilidade da classe NotaFiscal. Note que tanto este quanto o padrão Creator são bem básicos e definem conceitos bastante triviais. O que é importante observar é que ambos definem regras gerais que estão por traz do que fazemos por “intuição” no dia-a-dia.

High Coesion – A alta coesão diz respeito à criação de classes que tratem de assuntos focados e bem definidos. Uma classe não coesa é aquela que trata de diversos assuntos distintos, tornando-se difícil de entender, manter, testar, evoluir e reutilizar. A alta coesão também suporta o baixo acoplamento (veja Low Coupling).

Low Coupling – O baixo acoplamento diz respeito à redução de dependência entre classes de forma que uma necessidade de mudança tenha menor impacto nos objetos dependentes. Projetar para baixo acoplamento envolve a utilização de conceitos de alta coesão (veja High Coesion), pois, classes mais coesas são menos dependentes entre si. Imagine, por exemplo, uma classe que contenha implementações de diversos assuntos diferentes – não coesa. Todos os demais módulos do sistema que dependam dos assuntos contidos nesta classe dependerão de uma mesma classe, de forma que alterações em qualquer um dos assuntos abordados proporcionem maior risco para todos os demais. Projetar para baixo acoplamento também envolve utilização de conceitos de encapsulamento. Encapsular significa esconder do mundo externo particularidades, implementações e informações que não digam respeito diretamente ao negócio / domínio, ou que sejam sujeitas a mudanças. Uma vez que tais informações sejam escondidas atrás de propriedades ou operações, por exemplo, as demais classes não serão afetadas quando houver alterações – ou seja, terão baixo acoplamento. O baixo acoplamento também pode ser atingido através de técnicas utilizadas para indireção (veja Indirection) e variação protegida (veja Protected Variation).

Por enquanto é só. No próximo artigo devo trazer os demais padrões GRASP: Controller, Pure Fabrication, Polymorphism, Indirection e Protected Variation. Até lá.

Uma definição de Arquitetura

The Rational Unified Process An IntroductionOlá Pessoal!

Neste post gostaria de compartilhar um trecho do livro “The Rational Unified Process: An Introduction (3rd Edition)” de Philippe Kruchten, disponível no capítulo 5 (An Architecture-Centric Process), página 84. O texto fala sobre uma definição de Arquitetura, que é um tema bastante pertinente, diante das várias abordagens e interpretações existentes no mercado para o escopo de atuação de uma área de arquitetura ou de um arquiteto.

Basicamente o texto fala que arquitetura presa pela estrutura de um sistema, sua decomposição em elementos, subsistemas e suas interfaces, juntamente com comportamento e colaboração entre elementos. Requisitos não funcionais (ou atributos de qualidade) também fazem parte da lista de itens que a arquitetura de um sistema deve contemplar, como por exemplo, performance, reuso, escalabilidade, resiliência, etc. Outro ponto importante mencionado é que arquitetura engloba não apenas aspectos técnicos, mas também econômicos e sociológicos. Podemos entender como aspectos econômicos os recursos e limite de orçamento disponível em um projeto. Por sociológicos, as pessoas envolvidas e como a arquitetura do sistema pode os afetar, sejam eles desenvolvedores, designers, gerentes de projetos, ou mesmo usuários.

Confira o trecho a seguir.

Many definitions of architecture have been proposed. The Rational Unified Process defines architecture as follows.

Architecture encompasses significant decisions about the following:

  • The organization of a software system
  • The selection of structural elements and their interfaces by which the system is composed, together with their behavior as specified in the collaboration among these elements
  • The composition of these elements into progressively larger subsystems
  • The architectural style that guides this organization, these elements and their interfaces, their collaborations, and their composition

Software architecture is concerned with not only structure and behavior but also context: usage, functionality, performance, resilience, reuse, comprehensibility, economic and technological constraints and trade-offs, and aesthetics.

This definition is long, but it attempts to capture the richness, the complexity, and the multiple dimensions of the concept. We can elaborate on some of the points.

Architecture is part of design: it is about making decisions about how the system will be built. But it is not all of the design. It stops at the major elements—the elements that have a pervasive and long-lasting effect on the qualities of the system, namely, its evolvability and its performance.

Architecture is about structure and about organization, but it is not limited to structure. It also deals with behavior: what happens at the joints, at the seams, and across the interfaces.

Architecture not only looks inward but also looks at the “fit” of the system in two contexts: the operational context (its end users) and the development context (the organization that develops the system). And it encompasses not only a system’s technical aspects but also its economic and sociological aspects.

Architecture also addresses “soft” issues such as style and aesthetics. Can an architecture be pleasing? Yes, to the educated eye it can be. Issues of aesthetics have their place in making a design uniform, easy to understand, and easy to evolve, with minimal surprises for the designers.