segunda-feira, março 19, 2007

Arquitetura três camadas é um mito sobre desacoplamento...

Uma coisa que aprendemos desde nosso primeiro "if-else" em programação é que aplicações devem ser feitas em 3 camadas (ou mais), a saber: apresentação, aplicação e persistência. Uma arquitetura muito similar a ela é a popular MVC, que separa as coisas de forma parecida, mas a camada de persistência some dentro do "model" e a camada de aplicação é dividida entre "model" (com regras de negócio) e "controller" (que funciona como "cola" entre View e Model). Hoje em dia, boa parte das arquiteturas pra web é um misto de MVC com 3 camadas, num bororô formado por frameworks de apresentação, controllers temperados com "Dependency Injection" e um mapeador objeto-relacional. Tudo isso somado fornece o melhor nível de desacoplamento possível no sistema. É possível até mesmo trocar de banco de dados Oracle pra SQL-Server trocando apenas umas poucas linhas... Mas será que é desacoplado mesmo? Que tal experimentar o desacoplamento com uma alteração bastante comum como, vejamos... adicionar um campo? Bom, temos que mexer na view pra adicionar o campo, tb temos que mexer na camada de negócio para tratar o campo e validar, aí temos o transporte (V.O.s?) onde temos que adicionar o campo, e finalmente, adicionar no banco (o Hibernate até gera o campo pra vc, só que ele não migra os dados quando acontece a evolução do esquema, é na base da recriação da tabela). Okay, o que temos aqui? Uma simples alteração gerou uma "shotgun surgery" no código, necessitando de alterações em todas as camadas. Agora a questão é, como eu ISOLO isso? E, sendo mais cínico, de que me adianta trocar de banco com uma linha (e muito raramente eu faria isso), se para adicionar um simples campo eu preciso espalhar as alterações pra todo lado? Eu já vi a algum tempo atrás na web alguns artigos com a mesma preocupação, eles tinham até um nome pra isso, mas sinceramente não consigo me lembrar, e por consequência, não acho mais os artigos :( Se alguém achar, me dá um toque.

7 comentários:

  1. Anônimo7:40 PM

    As pessoas confundem muito esse lance de camadas, porque a palavra 'camada' é mapeável para dois termos no inglês, 'layer' e 'tier'.

    Pela definição no artigo da Wikipedia que você referenciou, uma aplicação em Ruby on Rails, por exemplo, é tão '3-tier' quanto uma aplicação J2EE comum.

    'Tier' tem um sentido mais físico, são componentes do sistema executados em máquinas/processos diferentes. Exemplo? browser/Rails/MySQL, ou browser/WebSphere/Oracle.

    Uma arquitetura 3-tier se contrapõe com a antigamente mais comum arquitetura 2-tier, ou cliente-servidor, onde só haviam o cliente - uma aplicação desktop, escrita em Delphi, VB, etc. - e o servidor de banco de dados. A lógica era dividida entre os dois, parte executada no cliente, parte executada no servidor via stored procedures e afins.

    No J2EE 'clássico' (leia-se, que usa EJBs remotos), normalmente se fala em arquitetura 'n-tier' (vide J2EE Blueprints), pois a camada de aplicação é dividida fisicamente. Os famigerados DTOs, ou Data Transfer Objects, ('VO' é viagem dos autores da primeira edição do livro Core J2EE Patterns) seriam necessários apenas nestes casos, onde há uma separação física entre camadas de aplicação, pois aí sim existe a necessidade de otimização da utilização da rede.

    Já 'Layer' tem um sentido mais lógico, com a separação do sistema em camadas lógicas. Esta separação pode ter tem objetivos diversos, como reúso, desacoplamento, organização lógica, etc. Os objetivos em si são louváveis, mas obviamente, o sucesso nestes depende muito da competência do projetista.

    Por exemplo, muitas aplicações utilizam objetos de domínio (Domain Objects) 'burros', que apenas guardam dados carregados do banco para manipulação por uma 'camada de serviços' e exibição na camada de apresentação, sendo que todos estes componentes se localizam (e sempre o farão) no mesmo servidor. A este 'fenômeno' o autor Martin Fowler deu o nome de Modelo Anêmico (Amnemic Model), e muitos chamam de DTOs ou VOs. Note que isto não é exclusividade do mundo J2EE! É perfeitamente possível (e comum, suponho) criar uma aplicação sobre RoR que acumula lógica nos Controllers, e utilizam as entidades apenas para acesso a banco.

    Bem, tudo isso foi só porque os maus exemplos sempre são em Java, sendo que a causa não foi a linguagem em si, mas o fato de que, sendo mainstream, tem muito orelha-seca por aí usando a plataforma pra fazer o que a galera fazia antigamente com VB (ou o inverso absoluto, no caso), e que nem Ruby nem linguagem alguma está livre da incompetência alheia.

    ResponderExcluir
  2. Anônimo5:10 PM

    Recentemente coloquei um post no meu blog sobre esse assunto.

    Pelo que entendo o desacoplamento serve para que uma camada possa ser substituída sem que seja necessário modificação nas demais, ou seja, uma forma de testar se sua aplicação está desacoplada é tentar mudar uma das camadas e ver o impacto na demais. Adicionar um campo impacta em mais de uma camada já que você precisa exibir,persistir e manipular esse novo atributo. Se a lógica de negócio da aplicação estiver nas entidades isso não será tão dolorido agora se a aplicação tiver Vos/Bos/DTO já complica um pouco mais, se tiver action e manager piora ainda mais, junte isso com alguns XML e tá feita a merda.

    http://webdoispontozero.com/blog/?p=75

    ResponderExcluir
  3. Anônimo1:36 PM

    Hahahha!!! Dá vontade de imprimir isso e panfletar na faculdade.

    []'s
    Thiago

    ResponderExcluir
  4. Olá pessoal,

    O leonardo comentou que se utilizar Vos/Bos/DTO complica ainda mais, então gostaria de saber o que utilizar no lugar deles?

    Abraços

    Rafael

    ResponderExcluir
  5. Acho que precisamos compreender - e aceitar - que existem níveis de desacoplamento.

    Por mais que se tente ter independência de tudo (algo que para mim soa como utopia acadêmica) não existe algo que seja viável prover esse nível de "acoplamento" que você levantou.

    É Até possível atuar com geradores baseados em engenharia reversa que reconstruísse parte do código, ou até dependendo do framework, todo o código, mas nunca estaremos falando de desacoplamento completo.

    Porque senão passaríamos a ter liberdade de pensar em rodar todas as linguagens de programação server side em um super interpretador independente de plataforma e totalmente extensível, podendo se comunicar com todos os softwares gerenciadores de bancos de dados, ldap, servidor de arquivos, ftp, servidores web, etc. E mais sendo executado num equipamento acessível ao nosso bolso..

    Então ao meu ver do mesmo modo esse seu comentário considera o termo "descoplamento" da mesma forma equivocada que é interpretado por muitos o conceito de "camada".

    ResponderExcluir
  6. Anônimo11:07 AM

    você disse: "se para adicionar um simples campo eu preciso espalhar as alterações pra todo lado"

    Eu digo: Tenho a solução perfeita para isso, é uma tecnologia que nós (um grupo de usuários do pais inteiro) estamos desenvolvendo é já provamos que é absolutamente viável. Contate-me: maickelbr@yahoo.com.br

    ResponderExcluir
  7. Gilberto Hemmings1:57 PM

    O propósito do desacoplamento não é tratar alterações no domínio da aplicação.

    ResponderExcluir