Plataforma não Vence Cultura

Recentemente tive um debate interessante com o Vitor Pamplona no blog dele sobre se o Prevayler oferece uma OO razoável ou não. Hoje estava passeando pelo repositório do java.net quando resolvi baixar o JavaFreeCMS e dando uma olhada rápida nos fontes confirmei que não é porque você tem uma plataforma (persistência, linguagem, VM, etc.) de objetos que você tem objetos.

O Prevayler te induz a um modelo de persistência baseado em Commands. Commands são classes que representam uma unidade de trabalho, como um algoritmo. Na maioria dos casos os Commands viram erroneamente TransactionScripts, que são alternativas muito interessantes para sistemas simples mas são antagônicos a um Domain Model.

Num TransactionScript estruturas de dados são manipuladas pelo algoritmo do Command, o que nós já conhecemos como domínio anêmico. Num Domain Model objetos ‘de verdade’ cooperam para atingir a um fim (implementar um caso de uso/user story).

O exemplo abaixo mostra como um código procedural pode ser produzido neste ambiente:


public class PostComment extends CMSTransaction {
.
public static final long serialVersionUID = 1L;
.
private long idNew;
private Date date = new Date();
private long idComment;
private String desc;
private String author;
private String authorName;
private String page;
private String email;
.
public PostComment(long idNew, String desc, String author, String authorName, String page, String email) {
this.idNew = idNew;
this.idComment =0;
this.desc = desc;
this.author = author;
this.authorName = authorName;
this.page = page;
this.email = email;
}
.
public PostComment(long idNew, long comment, String desc, String authorName, String author, String page, String email) {
this.idNew = idNew;
this.idComment = comment;
  this.desc = desc;
this.author = author;
this.authorName = authorName;
this.page = page;
this.email = email;
}
.
public void executeOn(CMS cms) {
New news = (New)cms.getModule(CMS.NEWS).getItem(idNew);
.
if (news == null) {
return;
}
Comment item = prepare(cms, news, date);
}
.
public Parser getParser(Wiki wiki) {
  return FormatPrevalenceFactory.createDefaultParser(wiki);
}
.
public Comment prepare(CMS cms, New news, Date date) {
Parser parser = getParser(cms.wiki());
.
// Creating the text and identifyng wiki words.
Text textObject = new Text(author, date);
parser.parseText(desc, textObject);
.
Comment comment = news.getComment(idComment);
.
if (comment == null) {
comment = new Comment(0, date);
}
.
comment.setAuthor(author);
comment.setAuthorName(authorName);
comment.setEmail(email);
comment.setPage(page);
comment.setDesc(textObject);
.
news.addComment(comment);
.
return comment;
}
.
}

E qual o problema com este código? Perceba que as estruturas de dados são manipuladas pelo Command que é a classe PostComment. Primeiro se cria o objeto:


// Creating the text and identifyng wiki words.
Text textObject = new Text(author, date);
parser.parseText(desc, textObject);
.
Comment comment = news.getComment(idComment);
.
if (comment == null) {
comment = new Comment(0, date);
}

Depois se popula o objeto com dados:


comment.setAuthor(author);
comment.setAuthorName(authorName);
comment.setEmail(email);
comment.setPage(page);
comment.setDesc(textObject);

Mais a frente dizemos ao objeto o que fazer:

news.addComment(comment);
return comment;

O que acotnece se precisarmos criar um objeto exatamente como o fizemos, porém precisamos que a descrição seja, digamos, precedida por um disclaimer do tipo: “o Forum não se Responsabiliza pela opinião deste usuário”? E se precisarmos fazer isso apenas para usuários da nossa blacklist?

Pelo andar da carruagem vamos criar uma outra classe de Command que faz exatamente o que esta faz mas muda uma linha:


comment.setAuthor(author);
comment.setAuthorName(authorName);
comment.setEmail(email);
comment.setPage(page);
.
if(blackList.contains(author)){
comment.setDesc(DISCLAIMER+textObject);
}else{
comment.setDesc(textObject);
}

Claro que podemos refatorar o Command para que vire um TemplateMethod e esta pequena modificação vire um hook mas… e se precisarmos criar um Comment em outro lugar, digamos quando os dados vêm de uma conexão na rede, ou um WebService REST? Fazemos a classe que cuida disso estender o Command?

O problema neste caso é que a responsabilidade pela criação do objeto não está no lugar correto. Imagine que ao contrário do que temos hoje o objeto Comment tivesse suas próprias regras de negócio (afinal, objetos são dados+funções, estado+comportamento). Ao criar um objeto Comentário ele já se popularia com os dados passados no construtor (o que, aliás, evitaria quebrar a invariante deste objeto, o que acontece no exemplo acima) e que para criar um comentário com disclaimer seja tão simples quanto criar uma subclasse chamada DisclaimeredCommet, que já traz a lógica de negócios. Podemos ter algo como:


Comment newOne = commentFactory.createComment(author, text);

E na Factory:

public Comment createComment(Author author, Text text){
.
Comment created=null;
.
if(blacklist.contains(author)) {
created=new DisclaimeredCommet(author, text);
} else{
created=new CommonComment(author,text);
}
.
return created;
}

A lógica sobre qual comentário criar ficaria no objeto responsável pela criação (a Factory) e não por 500 outros objetos. Para quem exibe não existe diferença entre CommonComment e DisclaimeredComment, eles são instâncias de Comment (Zahl abençoe o polimorfismo). Não importa onde fosse chamado, o código sempre iria produzir o objeto correto.

Claro que este exemplo poderia ser resolvido de mil maneiras diferentes mas é só um exercício sobre pensamento procedural x orientado a objetos. Na verdade nem pensamento procedural porque mesmo este paradigma tem meios para evitar os problemas citados (mais sobre isso em outro post). Mas não se engane: o problema não é o JavaFree, seu CMS muito menos quem o implementou. Só está aqui porque é o único proejto em produção que eu conheço (e tenho acesso aos fontes) usando Prevayler. Se quem criou este design o fez assim fez porque a cultura que impregna nossa comunidade, academia e mercado não é OO. Este mesmo problema acontece em zilhões de outros projetos livres (inclusive de outros fóruns e CMS), projetos comerciais e mesmo em simples exercícios de faculdade.

O problema dos bancos de dados relacionais já foi quase que completamente resolvido com ORMs eficientes como Hibernate e JPA, o problema ainda é, como era há 30 anos, fazer com que os sistemas sigam uma modelagem OO. Como fazer com que as pessoas entendam que objetos não são containeres de dados e sim entidades ‘vivas’ em um sistema. Muitos pensavam que ter uma plataforma OO amplamente difundida faria isso acontecer. java mostrou que falharam. Outros pensaram que ter um SGBD relacional é o problema, tirar o SGBD faz os objetos fluírem, o código acima mostra o contrário.

O problema não é na plataforma, é na cultura.

14 Responses to “Plataforma não Vence Cultura”

  1. Josenaldo says:

    Cara, confesso que ainda não encontrei uma fórmula que ajude um programador novato a entender OO. Eu mesmo me pego às vezes tentado a cometer “procedural-killer” em código que deveria serr OO.

    Calçado, acompanho seu blog faz algum tempo, mas dessa vez tenho que te parabenizar! Belo post!

  2. E o problema não se restringe somente aos programadores. Até hoje, não vi nenhum analista/projetista que fizesse analise/projeto orientado à objetos. E pior ainda, em um projeto relativamente grande, se você resolver adotar uma abordagem um pouco(note, um pouco) mais OO, as chances do resto da equipe olhar atravessado e pensar “o que esse cara pensa que ta fazendo?”.

    Infelizmente, eu acho que vai demorar bastante ainda até que a comunidade, as faculdades e o mercado entendam que programar orientado à objetos não é somente usar Java/.net/whatever e ficar criando classezinha com setter e getter.

  3. Marcos Silva Pereira says:

    Frase muito pertinente de um gerente: “esse negocio de OO só é bonito na teoria, quando chega na pratica dá para ver que não funciona”.

    E eu: “Cuméquié?!”

    No mais, daqui a pouco o Vitor aparece por aqui, ou por lá, no blog dele, para oferecer alguma resposta a esse post. :-)

    valeuz…

  4. Bruno says:

    Sorte sua que só te olham atravessado, Diego. Em geral, devemos ir ao trabalho com um soco inglês para evitar uma discussão mais ‘técnica’.

    Marcos, troque OO por XP, TDD, , Hibernate, Spring, Ruby, Rails… (lista infinita) na frase do teu gerente. Então, tenho certeza de que todo mundo já ouviu uma frase semelhante a dele.

    Shoes, valeu por mais esta referência.

  5. C. Moscoso says:

    @Josenaldo
    O mercado e a academia são os culpados pela má formação do profissional OO de hj.
    Mas pior é convencer o profissional experiente de que houve uma mudança de paradigma, ou ELE MESMO se convence disso ou então na minha opinião, é caso perdido…

    @Marcos
    O pior qnd isso não é dito logo na entrevista. Eu também já passei por isso e gostaria de saber quais as dicas para identificar uma furada. Geralmente na apresentação a equipe é de formação OO mas no dia a dia vem a decepção.. Se houvesse meios de indentificar tal situação numa entrevista não perderíamos nosso tempo!

  6. Leandro Ribeiro says:

    OO é uma arte
    Eu sempre faço um modelo, e já refatoro, nunca consigo de primeira fazer o modelo ideal e fiquei feliz ao saber que esse é o caminho certo.
    Gostaria de saber responder as pessoas quando elas me perguntam como aprender oo. O que tento explicar é que independe da paradigma o bom senso.
    Lendo a apostila de Spring do P. Shoes, aprendi muito, lendo e tentando imaginar este artigo aprendi novamente, então sempre estou aprendendo esses conceitos de oo.

  7. Pois é grande. Infelizmente o JavaFreeCMS não é modelo para OO + Design Patterns. Nem sei se deveria ser e provavelmente não será.

    Refleti muito sobre implementar algo OO com Design Patterns ou algo “para funcionar”. Fiquei no “para funcionar”, o dia que eu precisar de algo mais, eu refatoro.

    Hoje trabalho com C++ e vejo o outro lado da moeda, onde padrões como o State, por exemplo, são complexos d+ para serem adotados em aplicações simples (Leia-se sistemas de informação.) Prometo um post no meu blog sobre isso :).

    Valeu pela crítica. Talvez seja melhor você buscar uma boa implementação para o Prevayler no Priki ( http://wiki.com.br ). Tenho certeza que ainda não é uma perfeição de OO, mas sem dúvidas é bem melhor que o JavaFreeCMS. :)

    []s

  8. Comentário da minha professora na cadeira de “Analise de sistemas 1″ depois de uma longa explicação que ninguem entendeu nada, inclusive eu:

    “Olha pessoal, orientação a objetos é a mesma coisa que fazíamos na programação procedural, mudou só os nomes, se voce pegar um MER vai ver que é a mesma coisa que as classes, seu javabean é uma entidade no modelo relacional”

    MInha cara na hora… O.o … depois dessa perdi todas as esperanças que a universidade possa ser responsável pela formação de um profissional.

    detalhe, a professora é mestre, PMI, certificada RUP e tem mais de 20 anos de experiência no ensino superior na universidade Federal, além de faculdades privadas.

  9. De certa forma, ela está certa :)

    Para sistemas simples (aka, tabelas, cadastros e relatórios) a OO não faz mais do que atrapalhar :)

    Boa reflexão :)

    []s

  10. pcalcado says:

    Pera lá, né Vitor.

    Uma coisa é não usar OO, outra coisa é ensinar errado, seja OO, programação, matemática ou soltar pipa.

    Se você acha isso normal ou mesmo’ certo de certa forma’ só me faz lamentar ainda mais pela universidade brasileira.

  11. [...] Bom, Prevayler em si não é OO, como já discutimos no seu blog e em um post passado aqui neste mesmo, mas ainda que fosse não há problema em ter um Mapper (que é conceito por trás de um DAO) entre dois domínios de objetos diferentes. Na verdade, Eric Evans possui ótimos textos sobre Context Mappers no seu livro que fazem exatamente isso. Quando trabalhei com Hibernate 2 e EJB 2, não consegui imaginar uma forma melhor de se programar do que seguir um fluxo de ida e volta: Locator -> Facade Session Bean -> Transaction -> DAO -> Hibernate Entity. Com VOs circulando entre eles. Aparentemente uma bela estrutura OO, exceto por um problema: os algoritmos continuavam seqüenciais, apenas em objetos diferentes. Os objetos não resolviam os problemas da regra de negócio, mas sim simplificavam o uso da própria tecnologia (EJB). Não haviam objetos inteligentes, apenas os JavaBeans secos, como o Hibernate 2 queria, e VOs secos, com regra de negócio pertinente ao objeto e só. [...]

  12. Leandro Zis says:

    Você mostrou um mal exemplo de uso do prevayler e um bom exemplo opensource do uso hibernate você teria?

  13. jazzPlayer says:

    Deprimente, nao o sistema JFreeCMS, mas a ideia que temos do que e programar orientado a objetos.

    A comecar pela “necessidade” de comparacao com MERs e outras bugingangas relacionais e finalizando com a tristeza de quando, comumente, redefino (redefinimos) o termo “mensagem” para “chame o metodo x”.

    Nao sei o como podemos fazer para mudar ou minimizar o quadro, mas no que me diz respeito, e eu tiro por experiencia propria, ler smalltalk faz bem.

    Errare humanum est.