segunda-feira, agosto 27, 2007

"Pseudo" encapsulamento

Junto com "herança" e "polimorfismo", "encapsulamento" é o terceiro pilar da programação orientada a objetos. Aliás, tentar fazer da programação um aglomerado de "caixas pretas" é uma coisa que tentamos desde que inventaram o Assembly. A idéia sempre foi ocultar detalhes para que se possa modificar o programa facilmente ou, no mínimo, não esquentar a cabeça com detalhes. Um dos melhores patterns que já vi sobre o assunto faz parte de um catálogo de patterns do Brian Foote chamado "The Selfish Class". Ele não foca exatamente sobre mudança, mas sobre facilidade de uso. Mas no fim da contas, fazer muito através de uma interface mínima é o melhor ponto sobre encapsulamento. O que vemos muito por aí é encapsulamento "pra inglês ver". Só funciona na teoria, porque na prática, é igual tentar se esconder tampando os olhos, no melhor estilo: "se eu não o vejo, ele também não me vê". Ao longo do tempo, comecei a encarar alguns items como bad smell de "encapsulamento pra inglês ver" e gostaria de compartilhar eles: Métodos de acesso : Talvez o bad smell mais comum e o mais polêmico. Métodos de acesso (gets e sets) quebram encapsulamento. Não sou o único a pensar assim (procure no google, você vai achar mais alguns doidos, inclusive com muito mais cacife que eu). Basicamente a idéia é a seguinte: você está expondo seus dados internos, mesmo que seja atráves de um método. Isso não é muito problema, desde que, em 90% do tempo, você trate o objeto como um todo ao invés de ficar cutucando seus dados (do objeto, não os seus) Mas quando você começa a pegar os dados de uma tela web e jogar campo a campo no seu objeto, isso significa que você quebrou o encapsulamento. Uma maneira "caixa preta" de fazer isso seria jogar os dados todos pra dentro do objeto e ele pegar o que precisa OU fazer a atribuição via reflexão. O ponto é o seguinte: se você alterar um campo e tiver que mexer em algum lugar que não seja tela, banco ou regra de negócio, então seu encapsulamento está quebradão. Caso típico é quando você precisa ficar"repassando" os campos. Não concorda? Não tem problema, é um feeling meu (e de alguns outros doidos). Coloca o seu aí, então, ué :) Delegate : Delegates são uma ótima forma de diminuir o número de objetos que você tem que trabalhar. Mas quando você começa a delegar TUDO, ou então os mesmo dados (parâmetros e retorno) são simplesmente passados sem alteração ou qualquer outro comportamento por 2 ou 3 métodos... hmmm... tem algo estranho. Já vi isso sendo usado como uma forma de manter as coisas no lugar quando se está em uma arquitura com muitas camadas. Mas sinceramente, isso é só uma maneira muito esquisita de violar camadas, não de preservá-las. Se você precisa de algo lááá do fundo em uma camada da frente, sem alterações, melhor repensar sua arquitetura nesse ponto. Iteradores externos : (essa vai fazer alguém querer comer meu fígado... sem tempero!!!) Essa viola a máxima do "Tell, don't ask" sem dó nem perdão. A moral da história é a seguinte, ao invés de pedir para as coleções trabalharem para você, somos obrigados a pedir licença, pegar tudo o que elas têm e ficar item a item vendo o que precisa ser feito. A solução para isso seriam iteradores internos, implementados lindamente com closures (viva Smalltalk, 30 anos atrás já fazia isso!). À primeira vista, quem não conhece vai achar que dá na mesma, só quando você olha mais de perto vê que várias operações básicas que fazemos todos os dias podem ser encapsuladas com isso. Tais como "selecionar o primeiro que satisfaz uma condição", "fazer um 'de->para' com os objetos da coleção", "acumular valores segundo uma fórmula qualquer", e por aí vai. "Data Transfer Objects" ou "Value Objects" : Essa viola o "objetos devem ter comportamento". Veja bem, um Objeto (com "O" maíusculo) é justamente a junção de DADOS + FUNCIONALIDADE (comportamento), se você tem dados em um objeto, então a funcionalidade que atua sobre esse objetos está em outro lugar... separando dados e funcionalidades voltamos a programação procedural (ou funcional). E no que isso viola encapsulamento? Viola porque outros objetos precisam conhecer os detalhes do seu DTO para poderem trabalhar com ele. Trocando em miúdos, esse "pseudo-objeto" está com suas estranhas completamente expostas e a mercê de outros objetos malignos que querem comer seu coração (do objeto, não o seu). Okay, como tudo na vida, existem lugares onde DTOs são legais e bemvindos. Mas quando eles começam a aparecer demais, aí dá pra começar a ficar desconfiado. Se a gente realmente caprichar no uso dos DTOs, vamos acabar com um sistema OO com a cara de um ASP dos antigos, mas com mais camadas... No geral, são esses meus bad smells de encapsulamento. E são realmente bad smells, ou seja, pode ser que não seja nada e que o uso esteja correto, mas não custa dar uma verificada. Outra coisa é que encapsulamento é legal, mas não é nenhuma vaca sagrada (é?). Violo ela com muito gosto e uma pitada de sal se for para deixar meu sistema mais simples. Infelizmente, normalmente é o contrário... :)

Nenhum comentário:

Postar um comentário