O “objeto” bom cidadão (Good Citizenship)

Um tópico bem falado quando o assunto é design de software é sobre quebra de encapsulamento e como projetar bem as classes para que elas sejam altamente coesas (tenha um objetivo bem definido) e pouco acopladas (dependam de poucos objetos para funcionar).

Quando se fala sobre relacionamentos entre objetos, um bom tópico para ser estudado é a “boa cidadania” ou Good Citizenship.

Good Citizenship

Um livro que aborda bem o assunto é “The Productive Programmer” [1], de Neal Ford. Nele o autor aborda alguns pontos chaves de maneira bem simples e com exemplos para mostrar o porquê de tamanha preocupação com esses pontos.

Segundo Ford [1], a boa cidadania se refere a objetos que são conscientes do seu estado e atentos aos estados dos outros objetos. Quando se fala em estado de um objeto, significa, de maneira bem simples, as suas variáveis internas.

As variáveis internas de um objetos definem como ele se comporta, geralmente as computações feitas em métodos dos objetos dependem das suas variáveis. Elas também representam o relacionamento do objeto com os outros, indicando as suas dependências. Daí a preocupação com o estado do objeto.

Quebrando a encapsulação

Um dos exemplos mais simples de quebra do princípio da boa cidadania é a quebra de encapsulação. Um post bem conhecido do Paulo Silveira no blog da Caelum [2] fala justamente sobre isso, tanto que o título é “Como não aprender Java e Orientação a Objetos: getters e setters”. Ao invés de copiar e colar o texto aqui, o link está no final do post, leitura obrigatória.

Esse ponto já foi exaustivamente discutido e todo mundo sabe o quão ruim pode ser oferecer getters e setters para todos os atributos dos objetos. Quando vários objetos tem acesso a uma determinada informação fica mais difícil mudar essa informação. E como nós todos sabemos, quase nunca é necessário mudar uma informação em um projeto de software.

Construtores

Esse é um tópico interessante que, eu particularmente, ainda não tinha ouvido falar antes de ler o livro [1]. Como o construtor pode quebrar o princípio da boa cidadania? Como o construtor pode mudar o estado do objeto? É justamente ai que Ford ataca a maneira como os construtores são vistos.

Segundo Ford [1], os construtores são geralmente vistos apenas como um mecansmos para criar objetos, no entanto os construtores dizem para você o que é necessário para que um objeto seja criado com um estado válido. Então qual é o ponto de utilizar um construtor vazio? Se o estado inicial do seu objeto não precisa de nenhuma informação, então tudo bem, mas dificilmente esse é o caso.

Remover os construtores padrões é bem difícil dependendo da linguagem e dos frameworks utilizados. Em C++ existe sempre um construtor padrão que não necessita de argumentos, pode ser por não passar nenhum argumento, ou por utilizar valores padrões para todos eles. Ford [1] também fala sobre a especificação do JavaBeans, que obriga a utilização de um construtor padrão vazio.

Se a linguagem/framework necessitar de construtores padrões é bem difícil que você consiga ir contra, a menos que possa ser substituido por algo diferente. A recomendação é que os construtores padrões sejam tratados evitados pela equipe.

Métodos estáticos

Os métodos estáticos tem como função funcionar como se fossem funções (???), ou seja, eles são utilizados de maneira procedural, sem utilizar nenhum estado ou guardar nenhuma informação dos objetos e de si mesmo. Um bom exemplo são as classes que são responsáveis por cálculos matemáticos, você chama o método sem precisar instanciar ou se preocupar com o que vai acontecer depois.

O grande problema quando um método estático guarda informações é que, diferente de um objeto que é instanciado dentro de um método, o escopo de um método estático é, muitas vezes, todo o programa. Então não existem garantias de controle do estado do objeto, uma vez que qualquer outro lugar do código pode alterá-lo caso necessário.

Esse é o mesmo problema com variáveis globais e com a versão “orientada a objetos” de variáveis globais, também conhecida como Singleton [3]. Um dos problemas com o singleton é que facilmente ele se carrega com várias responsabilidades, pois como você não tem como controlar o estado do objeto, a classe acaba se carregando de responsabilidades para garantir que as computações sejam feitas por completo. E então acaba se relacionando cada vez mais com outros objetos e aumenta a complexidade e no final você fica com outra classe Main e ainda tem a coragem de dizer que usa padrões de projeto orientado a objetos.

No entanto o padrão Singleton não é sinônimo de gambiarra (tá, é sim), o ponto é só lembrar que ele não deve se carregar com responsabilidades. Tente extrair as responsabilidades do objeto utilizando outros padrões de projeto. No entanto esteja atento que é dificil garantir controle sobre o objeto, então pense duas, três ou quantas vezes forem necessárias para se convencer a não utilizar um Singleton.

Utilizando um objeto que não é um bom cidadão

Um último ponto abordado em The Productive Programmer [1] sobre boa cidadania é sobre utilizar um objeto que não é um bom cidadão. O autor cita como exemplo a classe mais odiada do universo: java.util.Calendar.

Além de ferir o senso comum de qualquer pessoa (que os meses NÃO começam em zero), o autor cita como um dos principais problemas o fato de que o Calendar não é capaz de manter controle sobre seu próprio estado. Como por exemplo quando você utiliza os horríveis setters para colocar a data como 31 de Fevereiro. O que deveria acontecer? Um exceção? Não atualizar a informação? Não, é claro que quando você seta a data para 31 de Fevereiro, na verdade você quis dizer 2 de Março =]

A opinião de Ford é: remova o objeto “criminoso”. No caso da Calendar é possível utilizar a biblioteca Joda Time [4] como foi muito bem exemplificado no post do Rafael Lacerda no blog da Caelum [5] falando sobre a dificuldade de cálculos de datas, leitura obrigatória também.

No entanto podemos tomar outras atitudes, caso o objeto não possa ser removido. Talvez a melhor seja encapsular esse objeto dentro de uma outra classe que oferece um maior controle. Um padrão de projeto para isso é o Adapter [6], também conhecido como Wraper. Com ele você pode ter uma instância do objeto criminoso dentro de uma classe que vai oferecer métodos mais amigáveis e garantir que ele se comporte.

Apesar de simples, e até algumas vezes óbvio, é difícil seguir este princípio. No entanto vale a pena “perder” um pouco de tempo pensando sobre o design das suas classes e como elas funcionam atualmente. Como diria Maurício Aniche [7], também da Caelum, você não vai arder no inferno ágil se pensar um pouco antes de escrever testes para esperar o “design emergir”.

Referências:

[1] Neal Ford, The Productive Programmer. O’Reilly, 2008.
[2] Paulo Silveira, Como não aprender Java e Orientação a Objetos: getters e setters. (http://blog.caelum.com.br/nao-aprender-oo-getters-e-setters/)
[3] Marcos Brizeno, Mão na massa: Singleton (https://brizeno.wordpress.com/category/padroes-de-projeto/singleton/)
[4] Joda.org (http://joda-time.sourceforge.net/)
[5] Raphael Lacerda, O eterno problema de calcular a diferença de dias entre duas datas em Java. (http://blog.caelum.com.br/o-eterno-problema-de-calcular-a-diferenca-de-dias-entre-duas-datas-em-java/)
[6] Marcos Brizeno, Mão na massa: Adapter. (https://brizeno.wordpress.com/category/padroes-de-projeto/adapter/)
[7] Maurício Aniche, Métodos ágeis: o que é folclore e o que é real? (http://www.infoq.com/br/presentations/agile-realidade-folclore)

Anúncios

Um comentário sobre “O “objeto” bom cidadão (Good Citizenship)

  1. […] discutido no livro é o principio “Good Citizenship “, que já foi falado aqui no blog (https://brizeno.wordpress.com/2012/11/26/o-objeto-bom-cidadao-good-citizenship/). Também são feitas discussões filosóficas, utilizando assuntos não relacionados com […]

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s