Todo já nos deparamos, em algum projeto ou outro, com tomada decisões de arquitetura e design com as quais não nos sentimos confortáveis. Ha um peso de que temos que escolher logo porque o desenvolvimento não pode ficar parado enquanto pensamos na melhor forma de fazer. Somos obrigados a escolher. E em arquitetura somos obrigados a escolher algo que não fique obsoleto antes do projeto terminar. Como decidir ? Como eliminar as opções ruins e escolher a melhor para ser implementada ? A resposta é : não precisamos eliminar , não precisamos saber qual é a melhor.
Vamos usar como exemplo a necessidade de colocar gráficos num sistema web. Imagine-se em 2000 quando o ajax ainda era desconhecido , e o canvas não existia. Como adicionar esta funcionalidade ? Podemos usar applets. Podemos usar flash. Podemos usar AWT/Swing e desenhar o gráfico na mão e enviar para png, ou podemos usar o JFreeChart e produzir imagens dos gráficos em png. Então escolhemos JFreeChart. Simplesmente geramos o gráfico em formato de imagem e mostramos num tag img do html. Funciona. E o que pode ser mais baba que isso ?
Agora imagine-se de volta em 2012. Você ainda usaria este modelo ? seus clientes o achariam atraente ? Seria possivel em 2000 que anos mais tarde gostaríamos mudar ? Não gostaria de usar uma API javascript , baseada em JQuery , por exemplo. Ou quiça uma que use HTML 5 e canvas ?
Que pena. Não pode mais.
Quando a opção foi feia para usar jfreechat+img fechamos as portas para todas as outras opções. Inclusive as opções da época como applets e flash. Foi uma decisão de tencologia de geração de gráficos, não uma decisão de arquitetura de como desenhar o componente de gráficos. É por termos fechado a porta, que anos mais tarde estaremos impossibilitados de alterar a renderização dos gráficos sem mexer na lógica de negócio. Sim, claro, podemos refazer tudo de novo, a lógica de negócios, a renderização etc, usando uma nova tecnologia. E daqui a 10 anos, teremos que refazer de novo ? Não parece uma solução econômica.
É justo dizermos que esta foi uma má escolha e que o arquiteto deveria ter deixado opções mesmo se naquele tempo não se sabia o que vinha a seguir ? Podemos.
Nós não sabemos o futuro. Nem sabemos prevê-lo. Mas uma coisa que temos a certeza é que a tecnologia irá mudar. Então temos a certeza que novas opções irão aparecer.O que é bom hoje , será obsoleto amanhã. Isto nos leva à primeira regra da arquitetura [1]: não faça escolhas irrevogáveis. Ou seja, não faça escolha que fecham as portas para outras opções. No exemplo, sabíamos que applet era uma opção, e flash também. Isto nos diz que jfreechar+img não é a única opção, que existem outras. Mas isso não significa que temos que implementar a opção flash, a applet e com o tag img e depois decidir pela melhor. Não. Significa que temos que nos valer de ferramentas técnicas de forma a que possamos manter os conceitos e mudar as implementações. Mais que isso, precisamos de ferramentas que estejam provadas como soluções ao nosso problema. Precisamos de usar padrões (patterns) sejam de arquitetura ou de design. Os padrões nos dizem como solucionar problemas como este: como implementar um mecanismo de geração e renderização de gráficos sem fechar as opções presentes e futuras?
No caso, a resposta é o padrão de componentes de ui que nada mais é que MVC. Sabemos que queremos um componente de mostre gráficos. É queremos inclui-lo nas nossas páginas. Então podemos encapsulá-lo em um tag lib ou um tag file. Isso nos permitirá usar o componente nas páginas sem ter que explicitar o como realmente irá funcionar. Isto é o Controler. Depois queremos que os dados que alimentam o gráfico não estejam presos à opção escolhida. Criamos objetos que sejam capazes de prover os dados sem realmente saber de onde (o clássico uso de interfaces) . Isto é o Modelo. Da mesma forma que estamos habituados a passar um objeto List para um tag <c:for> podemos pensar em passar um objeto Chart para um <ui:chart> onde ui é a nossa lib de tags. Nada de novo aqui e não fizemos nenhuma escolha que nos prende ou impede de implementar qualquer das opções. Podemos usar qualquer framework de controle de servlets que podemos sempre assegurar que teremos um objeto Chart para usar ; ou seja, se quisermos mudar algo, mudaremos a implementação do tag, não a aplicação. Mudaremos um componente, não o sistema.
A implementação do tag é agora live de escolher como irá apresentar a sua view. E podemos pensar até em view intercambiáveis usando outros padrões como Factory. Podemos aumentar a flexibilidade do compoente. O ponto é que conseguimos chegar na mesma implementação que antes jfreechart+img e ainda iremos implementar a mesma coisa e obter o mesmo resultado, mas não fechamos nenhuma porta. Não fizemos nenhuma decisão irrevogável. As decisões que fizemos nem sequer foram nossas. Apenas seguimos um padrão que é bem estabelecido e provado. Se um dia, no futuro, quisermos mudar a renderização mudaremos a implementação interna dos componentes, e nada mais.
Se entendeu até aqui, deve estar pensando que a resposta a todos os problemas é flexibilidade. Sim, é. Mas a flexibilidade é também um gerador de problemas. Não ha limite para o quão flexível você pode fazer um design. Nem sempre precisamos de todas essas flexibilidade. Precisamos apenas de flexibilidade q.b. (quanto baste). Nem muita, nem pouca. Não podemos torna flexível o quanto quisermos. Temos que tornar flexível o quanto precisarmos. Mas onde é horizonte ? O que “muito” ou “pouco” flexível significa ? É aqui que entra outro principio [2] : Pense Grande, faça pequeno.
Pensar Grande significa que devemos pensar em casos o mais genéricos e abstratos possível de forma a englobar todas as opções. O que se chamar obter a “visão de águia” do problema. O “big picture”. Depois que identificamos o que ha de opções, estabelecemos um caminho e executamos apenas o menor esforço possível. A águia após encontrar a presa faz o menor esforço possível apenas se deixando cair sobre a vitima. A gravidade faz todo o esforço e apenas basta pequenos ajustes de navegação para caçar a presa. Em arquitetura queremos um único design matador que não feche as portas as nenhuma opção. Um exemplo clássico da utilização diste principio é a lib de tags do struts 1. Quando o struts saiu, a ideia de usar tags que interagiam de forma simples e renderizavam os componentes foi tentadora para muitos. Mas estes componentes são pouco flexíveis. Eles fecham a porta a poder modificar o como é feita a renderização. Contudo a flexibilidade que bastava na época era simplesmente poder usar css. Com uma capacidade de templating ou algum tipo de injeção de renderizadores, poderíamos fazer o mesmo, deixando a porta aberta para quem quiser mudar, quando quiser mudar.
Pensar grande, é considerado errado por muita gente. Com base em um mito de que “em ágil não se modela arquitetura e vai-se criando quando se precisa” as pessoas ignoram este passo. Isso cria sistemas complexos que são muito difíceis de manter. Não ha componentes reaproveitáveis, aliás não ha componentes nenhuns. Só existe um grande sistema.
Pensar grande,representa um grande design logo no inicio (Big Design Up Front) . Sim. Precisa mesmo. E isso não é mau. O que é mau é um Big Implementation Up Front onde perdemos tempo implementando coisas que não iremos usar. Criar uma interface para o modelo não apenas é rápido como é a prática padrão ( Programe para Interfaces). Não demora. Criar um tag , não demora. E mesmo que criemos uma classe abstrata para dar suporte ao tag, é simples. E apenas precisamos implementar uma das opções. Dai o “Pensar grande, fazer pequeno”.
Repare que é “pensar grande” e não “desenhar grande” ou “documentar grande”. Para pensar grande basta ser humano e pensar. Algumas pessoas usam papel e lápis , ou quadro branco para ajudar a pensar, mas ainda estamos só pensando. Não estamos decidindo. É um brainstorm que se pretende amplo, que explore todas as opções, inclusive as mais remotas. Depois iremos , com base nesse palco, criar um design que permita o máximo de opções sem fechar portas. Nem sempre isso é possível. Na prática você terá que fechar algumas opções. Mas quando for tiver mesmo que fazer isso, tenha a certeza que não outra opção, que não ha outro design possível. Utilize-se de padrões. E quando tiver mesmo que fechar, feche algumas janelas e claraboias, não portas. Finalmente execute pequeno, ou seja, use o design para implementar uma das opções. No final você irá apenas implementar uma opção.
O trabalho, o esforço da implementação é exatamente o mesmo da solução fechada mas apenas com um pouco mais de cuidado técnico seguindo um padrão. A velocidade para fazer a primeira vez e deixar mais flexível não tem que ser menor que a solução fechada para qualquer desenvolvedor sênior. Talvez para um júnior o padrão ainda seja desconhecido ou não bem entendido, mas mesmo assim a programação do código em si, é praticamente a mesma na solução fechada e na aberta. O trabalho de manutenção será reduzido e teremos uma peça flexível no nosso arsenal.
Arquitetura sempre foi, e sempre será, sobre saber imaginar “O big picuture”, o “grande plano” e dai isolar os componentes necessários. Se diz que o Michael Ângelo pintou o teto da capela Sistina e é lindo e por isso ele é excelente artista e pintou. Não. Ele não pintou ele mesmo. Ele delegou a outros. Ele é um grande artista porque tinha a visão do todo. E porque consegui delegar a outros pintores a sua visão. Pessoas que trabalhavam isoladas , mas que eram guiadas pelo “grande plano”. O arquiteto precisa saber ver o macro e o micro e saber navegar entre as escalas. Para aqueles que não sabemos tudo isto, pelo menos podemos seguir regras simples como não tomar decisões irrevogáveis que fecham todas as portas e todas as janelas. Pensar é algo que os seres humanos fazem muito depressa e o padrões ajudam a acelerar ainda mais esse processo ou mesmo tempo que dão a confiança que não estamos indo por caminhos escusos.
Quando você precisar decidir o seu próximo passo no seu novo design, deixe a decisão aberta. Considere o macro, devida em componentes, aplique padrões, mantenha a flexilidade – não tenha medo de refatorar para a obter – e deixe as suas opções aberta. Mas nunca tenha mais trabalho do que teria se implementasse apenas uma das opções. Porque é isso que você está realmente fazendo : implementar uma opção de entre todas as possíveis, mas mantendo o fato que as outras ainda continuam possíveis.
[…] do projeto em termos de abstrações, tentando deixar o código o mais flexível possível adiando decisões o […]
[…] A adaptação acontece em vários níveis. Existe a adaptação a novos requisitos como exemplifiquei, a adaptação a um novo modelo de domínio, a adaptação a uma nova regra, a adaptação a um novo design, a adaptação a uma nova arquitetura, a adaptação a uma nova forma de distribuição, a adaptação a um novo mercado, etc… A adaptação é, como a inspeção, constante e presente em todos os detalhes. Sabendo que a adaptação é necessária e irá acontecer, não iremos desperdiçar forças tentando resistir a ela. A mudança é inevitável, e portanto, a Adaptação também.Este principio está presente tanto no conceito de Refactoring, como no Manifesto : “Responder a mudanças“, como no conceito de Arquitetura Aberta. […]