Archive for the ‘orientacao.a.objetos’ Category

DAO e Repository

Tuesday, June 5th, 2007

Tópico quente no GUJ. Muita gente está atrás de Domain-Driven Design hoje em dia e não tem a menor noção do que é um repositório.

Re-colando o trecho para a lista de DDD:

On 5/19/07, Phillip Calçado wrote:
> The main thing to keep in mind while working with Repositories is that
> they’re a domain concept, while a DAO or any other Mapper between
> objects and tables aren’t. The domain classes knows that repositories
> are where business objects instances remain. As a business concept it
> can and will be handled, received as a parameter, etc. by those
> business domain classes like services and entities.
>
> A DAO doesn’t fit in a Repositories place directly, this would break
> layered archtiecture of a application, but generally a Repository is
> just something that when invoked will call a DAO.
>
> To avoide the tortures of creating a brinless delegator as a
> Repository you can use the Dependency Inversion principle, by Uncle
> Bob, and make Repository an interface implemented by the DAO class.
> This way your domain classes won’t end up dependent on infrastructures
> classes (like DAOs) while you avoid creating Repository classes that
> acts just like delegators.
>
> I’ve used this approach more than once. In a recent project I’ve used
> this Dao<>Repository strategy and suddenly was requested
> that before checking the database I’d have to first check a enterprise
> search engine (something like google appliances or a dedicated Lucene
> server). I used to have:
>
> Domain Object –<>–> Repository <--<>– DAO
>
> And changed to:
>
> Domain Object –<>–> Repository
>
> Repository <--<>– RepositoryImpl –<>–> DatabaseDao
>
> –<>–>SearchEngineDao
>
> The RepositoryImpl was the class responsible for looking for the
> instance persisted in one of the two deta repositories. The domain
> classes that just relied on the Repository concept, not its
> implementation, weren’t affected.
>
> cheers
>
>
> On 4/25/07, Nick wrote:
> > I’ve just completed my third project using DDD principles and I think
> > I’m ready to move away from the repository pattern (though still
> > giving it some thought). In theory, I think it’s great. However, it
> > just causes so much code explosion, I find it’s just not practical.
> > For example, for the customer aggregate root I have:
> >
> > Domain.ICustomerRepository
>
>
>
> –
> Phillip Calçado
> http://www.fragmental.com.br

O DQO também colaborou.

“Necessidades Reais”

Wednesday, May 30th, 2007

Dando continuidade no assunto,temos mais uma vez o argumento “o cliente não quer saber em que foi feito, se é OO ou não, ele quer que atenda as suas expectativas.

Perfeito, só que o cliente também não quer saber que por sua decisão arquitetural e de design ser ineficientevocê vai ter que mexer em 300 arquivos e testar todo o sistema para implementar uma funcionalidadezinha boba. Minha mãe não tem o menor interesse em saber como a Microsoft implementa o Windows, mas após ter que me chamar centenas de vezespara reinstalar o sistema dela após problemas ela está procurando alternativas. O que ela quer é um sistema que faça exatamente a mesma coisa mas que não seja tão inflexível, tão custoso.

Em 2007 não existem CRUDs em abundância. toda aplicação tem o potencial de ser integrada em uma rede de aplicações e eu mesmo já fiz vários trabalhos de consultoria para empresas queprojetaram ” aplicaçõezinhas simples de cadastro” que de repente tiveram que crescer. Ainda que existisse esta abundância com certeza elas seriam muito mais eficientes se implementadas emoturas plataformas que não java ou C#, que não foram criadas com este tipo de coisa em mente. Tudo deve ser pesado e um arquiteto profissional deve saber tirar estas medidas e escolher a solução mais adequada.

O que não dá é repetir sempre o mesmo “as necessidades reais tem que ser atendidas e pro cliente não importa como”. Claro que importa! O profissional de software tem que estar pronto para oferecer um leque de soluções, considerando a eficiência e eficácia de cada uma no cenário específico.

Seja OO, projeto estruturado, funcional, RAD… não importa. O importante é dar um mínimo de qualidade ao projeto.

A Culpa é da Marvada

Tuesday, May 22nd, 2007

O Vitor respondeu meu post, eu tentei colocar um comentário mas ficou muito grande, então vamos tentar retrucar por aqui mesmo :)

Eu entendi que ele quis dizer algo como “em >coloque -um-valor-muito-alto-aqui<% dos casos usar OO é overhead” e, como disse, concordo em parte, mas acho que mais uma vez houve uma certa ênfase errada.

Para começar, acho que mudou bastante de idéia. Em Fevereiro você disse:

Como um bom amante da Orientação a Objetos pura eu odeio os bancos de dados tradicionais e acho os frameworks de O/R um saco (além de ser uma grande gambiarra)! Por isso eu uso Prevayler. :D

Que foi o que começou este debate todo. Bom, vamos lá.

Por exemplo, com o BabaXP eu forcei a implementação de um DAO, mesmo usando o Prevayler. Achei que era possível criar um DAO OO, algo bonito, que abstraísse as diferenças entre Prevayler e um banco relacional qualquer. Me enganei. É impossível fazer algo nesse nível só por causa de uma única diferença entre as duas tecnologias, o acesso direto a memória dos dados.

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ó.

Ahm? Por que o Hibernate fazia você usar DTOs? Eu usei Hibernate com objetos de negócio nesta versão e não tive nenhum problema, poderia explicar melhor? Mesmo os tão mal-falados EJBs podem ser utilizados com objetos. Não não é tão fácil quanto em JPA/Hibernate 3, mas também não é difícil.

E não, DTOs/VOs/TOs ou como estejamos chamando esta semana não fazem um bom modelo OO, muito pelo contrário.

Uma estrutura semelhante foi criada com o JavaFreeCMS, uma arquitetura Action Based não poderia gerar outro resultado do que uma implementação Action Based, que é um nome mais bonito para implementação seqüencial. Por mais que eu quisesse implementar algo OO, tinha algo que me prendia ao modelo relacional. Cultura? É, foi sim. O JavaFreeCMS foi baseado no phpNuke, no qual é muito fácil adicionar módulos e componentes. Lá basta você adicionar um .php e criar a tabela, pronto. Tentei fazer algo semelhante, mas orientado a objetos. Acabei descobrindo que o esforço para implementar tal flexibilidade era tamanha que eu precisaria de uma equipe para desenvolver um Simples e Idiota CMS OO. Acabei chutando o balde e implementando o mais simples possível.

Foi então que comecei a suspeitar da utilidade da Orientação a Objetos e dos Design Patterns. Como falei antes, até então eu considerava que o problema era eu. Que eu era incapaz de fazer algo bom utilizando o melhor da OO e dos design patterns. Afinal, tanta gente mais experiente falava bem dos patterns e tals, alguma utilidade eles deveriam ter, não é? No entanto, hoje eu vejo que não é bem assim.

Antes de mais anda não existe nenhum vínculo entre OO e Design Patterns, um existe sem o outro. Depois, existem diversos CMS OO por aí para provar que não é bem o paradigma que tem problemas. Em boa parte deles adicionar ou remover módulos é simples, provavelmente o design que se fez para este caso do JavaFreeCMS em específico não foi adequado (aliás o Prevayler prega um paradigma Action-based em suas transações).

Não adianta você querer implementar a sua estrutura de dados com o melhor da orientação a objetos se você vai acabar migrando esses dados para um sistema relacional. Você tem um esforço considerável para identificar várias heranças, composições, agregações, relacionamentos uni e bi-direcionais e após isso mais um esforço para migrar essa estrutura para o ambiente relacional. Para variar, não existe nenhum framework de O/R que consiga mapear atributos específicos de cada abordagem sem perder em performance, em simplicidade ou produtividade. Até hoje eu nunca vi ninguém conseguir implementar um sistema completo OO e somente depois de tudo criado integrar com alguma forma de persistência de maneira transparente. A OO aplicada, com todos os seus recursos e ideologias, neste tipo de aplicação, só serve para complicar as coisas, trazer mais trabalho e problemas para o desenvolvimento.

Você está ignorando simplesmente décadas de técnicas de mapeamento Objeto-Relacional e, mais uma vez colocando problemas no Hibernate e JPA que eles não possuem. Pode explicar por que eles não fazem este mapeamento?

Segundo este conceito podemos chegar à conclusão que linguagens de Assembly foram uma coisa muito ruim, já que elas apenas adicionam uma abstração em cima do modelo “real”, de linguagem de máquina. Será que elas não trazem benefícios?

A mesma coisa pode-se dizer das aplicações request-response, que mudam de nome a cada ano, mas continuam a mesma coisa. Muitos frameworks não nos deixam fazer muita coisa da OO. Você recebe uma lista de parâmetros e devolve uma lista de resultado. Lista == tabela == relacional. Para provar, pense no seguinte, a cada resposta que um sistema como esse dá, ele carrega todos os relacionamentos de cada objeto, ou carrega apenas a parte que interessa ou que a aplicação cliente usaria? Agora outra pergunta, para isso utiliza-se VOs específicos para cada request ou um único VO com sistema de lazy loading? Implementar um VO para cada requisição é dose. Deixar por conta de um lazy loading também muitas vezes falha (ou a conexão fica aberta e bloqueia outros acessos ao banco ou ela se fecha e se o usuário pedir algum objeto, irá ter um belo “session closed”). Alguém já ouviu falar no conceito de “páginas” com Orientação a Objeto? Não né. Por que esse conceito foi criado pelos bancos de dados e implementado graciosamente com a instrução “limit” no SQL.

Acho que você confundiu um pouquinho listas de estruturas de dados com álgebra relacional. Em um programa eu posso ter listas de qualquer coisa, e elas não precisam obedecer aos princípios de álgebra relacional. Por um acaso bancos hierárquicos ou em rede não implementam listas? Por um acaso uma HashTable é relacional? Prevayler trabalha com listas de objetos, ele é relacional então, certo? Sua prova… bem, não condiz com a realidade.

2007. Faz pelo menos 3 anos que VOs são completamente desnecessários em java, se é que algum dia foram. Lazy loading funciona muito bem, obrigado. O problema de sessão aberta é contornável facilmente com algumas técnicas, apesar de sim, ser um problema real, mas nada impede que eu tenha paginação em uma consulta OO via Hibernate, basta eu fazer eager fetching (que pode, inclusive, contar com consultas polimórficas) antes.

Mas… putz…dizer que páginas foram criadas nos bancos de dados é ignorar solenemente os diversos usos de paginação em memória e outras estruturas uhm… não relacionais.

Pense na seguinte frase: Os dados saem de uma base relacional, são transformados em objetos, executam uma regra de negócio simples (Somas, médias, grupos, contatores, etc), são transformados em relacional novamente e exibidos. Esse é o fluxo de muitas aplicações web e desktop. Se é assim, para que diabos alguém adicionaria aquela transformação e destransformação para OO no meio do processo?
Não parece. É, uma coisa desnecessária. Se a regra é simples, se a arquitetura que você utiliza dificulta o processo ou se os objetivos da aplicação são “relacionais”, para que ficar inventando moda? Os Design Patterns também não escapam. Em várias ocasiões eu vi que era possível implementar padrões um pouco mais complexos diretamente na regra de negócio, como o State por exemplo. No entanto, o State é tão complexo e chato de manter que não vale apena trocar por um campo de “situação” e mantê-lo com o próprio objeto.

Sua aplicação é simples? Ótimo! Pode abrir mão do bom uso de OO e ainda assim manter uma estrutura legível e com manutenção razoável? Excelente! Só não tome isso como regra geral. Se você acredita que a complexidade de criar um programa com estruturas de dados de objetos quase nunca é justificável eu realmente não entendo o que te faz não utilizar uma linguagem que permita este design e ainda traga mais vantagens, como ASP clássico, ColdFusion, PERL+CGI ou PHP. Java pra quê?

Quanto á confusão com Patterns vou considerar respondida acima.

Obviamente, nem toda a aplicação web é tão simples assim, mas minha intuição me diz que 98% do mercado brasileiro segue essa estrutura. Apenas 2% das aplicações merecem ter boas implementações de OO e Design Patterns.

Mais ou menos concordo (mais sobre isso abaixo), mas existe um problema intrínseco aí. Como você frequentou a academia mais tempo acredito que saiba melhor que eu que existe algo chamado programação estruturada e suas variantes, dentre elas programação OO e procedural. Agora, dado que a grande bibliografia de Yourdon, Page-Jones e seus amigos mostra que fazer programas em paradigma procedural exige várias técnicas (fan-in, fan-out, coesão, divisão de módulos, controle de flags, acoplamento… lembra?) para manter um programa… hmm… editável… acho que você está saindo da programação estruturada pura e simplesmente, certo? Segundo este princípio crie classes apenas com atributos públicos sendo manipulados por funções estáticas, aliás, por UMA GRANDE função estática :P

Eu concordo em gênero, número e grau que OO pode ser um overhead tremendo quando se tem um domínio simples, e inclusive defendo arduamente o uso de DSLs simplificadas para construção de sistemas, mas simplesmente largar o paradigma OO em favor de algo que não é OO nem Procedural é retroceder para antes de Dijkstra. Só falta um GOTO.

Entre esses 2% estão, em geral, aplicações com baixa quantidade de informação do usuário: compiladores, ferramentas de BI, diagramadores de interface, toolkits gráficos, aplicações como diagramadores vetoriais, gimp, blender, engines de jogos, browsers, IDEs, etc. Aquelas aplicações de sistemas de informação que seguem a estrutura de frameworks, o estilo de linguagens ou APIs, definitivamente não precisam de mais padrões ou mais OO. Você está preso a ela, portanto faça o que ela mandar e você será produtivo, invente moda e já era! Tente trabalhar de uma forma diferente da MVC com o Swing, e você se verá enrascado. Tente transformar as entities do EJB em Business Objects e estarás f.u.d.i.d.o. :)

Sei não. Ou minha realidade é muito diferente ou a sua é meio..exótica. Nos últimos anos trabalhei em sistemas de gestão de previdência privada, billing de telefonia, análise de risco, gestão de malha ferroviária, gestão de passageiros, conteúdo multimídia, gerenciadores de conteúdo (sim! e alguns deles)… e boa parte das pessoas que eu conheço ficam com sistemas parecidos. Todos eles tinham lógica a modelar como objetos

Fiz também muito destes CRUDs simples na vida mas eles definitivamente não são 98% nem do que eu fiz nem do que as pessoas que conheço fizeram. Se alguém só faz CRUDzinhos simples que nem um Domain Model se justifica a primeira sugestão é deixar Java de lado e trabalhar com algo mais produtivo como PHP4. O problema é que sistemas crescem, se integram e mudam, e acho que é este ponto que você ainda não entendeu que um bom design, seja ele OO ou não, faz diferença.

Caindo nos bons designs você irá ver um bom design procedural e perceber que existem práticas que são melhor implementadas num modelo de objetos, como quando você precisa proteger uma estrutura de dados de acesso indevido, ou sua invariante. Foi assim que o design de aplicações evoluiu até hoje.

Concluindo, nos dias de hoje, em grande parte dos sistemas de informação, a estrutura relacional atuando sozinha é perfeita! Ninguém precisa de Objetos para tais atividades, a não ser, é claro, que você utilize um banco de dados Orientado a Objeto, aí a coisa muda de figura. Mas como muita gente tem medo deste recurso… Hoje, está bem claro para mim: Aplicações com mais regra de negócio do que informação, utiliza-se orientação a objetos. Para sistemas de informação, onde há mais dados do que regras, vai do banco. Bancos relacionais, aplicações relacionais, SQLs e etc. Com bancos OO, aplicações OO.

Isso é complicado. Se você coloca o banco de dados no centro do universo é bom colocar as regras de negócio lá também, cheia de Stored Procedures, e ficar apenas com front-ends em linguagens de programação convencionais. Do contrário o que você faz quando duas aplicações tentam compartilhar o mesmo conceito? Se eu tenho um conceito formado por um join entre duas tabelas o conhecimento sobre este formato deve ser espalhado por todas as aplicações que utilizam o conceito, e quando eu mudar a implementação das tabelas tenho que mudar TODOS os sistemas, ou criar malditas views para segurar o legado.

O modelo de SGBD como centro do universo já foi substituído há quase vinte anos, uma boa lida sobre componentes e serviços vai te dar uma luz neste tema.

No entanto, se você puder escolher que tipo de abordagem usará, saiba que o que vale é a sua intuição. Não force as coisas. Não deixe de implementar a sua estrutura OO só porque alguém te disse que deveria ser implementado o Design Pattern Xyz. Utilizando o mesmo exemplo do State, se você quer fazer uma enumeração e ficar controlando no teu objeto, faça, se achar melhor cair no mundaréu de leis do State, vá em frente. Tudo se resume a sua intuição. Se alguém disser que pode ser feito de um jeito melhor, sem atrair complexidade e dificuldade de manutenção, mande o cara refatorar o teu código e pronto! Mas, não se assuste em ver gente complicando as coisas sem a mínima necessidade :)

Sim, cada caso é um caso mas acredito que o que deve guiar a escolha técnica não é a intuição e sim a razão, derivada da experiência e estudo das diversas técnicas e práticas, arquiteturais e de design, que foram desenvolvidas pela comunidade de desenvolvedores, acadêmicos, pensadores e práticos por todas estas décadas.

Eu tenho certeza absoluta que você pode me mostrar um monte de coisas super-simples sobre sua área de engines gráficas que eu vou achar mega-complexas sem estudar o motivo pelos quais as coisas são desta ou daquela forma. Por isso que não adianta, plataforma não vence cultura.

Update:

O Vitor colocou um follow-up no blog dele. Como não traz nenhum novo argumento aos pontos aqui levantados além de fazer um bashing sem nenhum argumento concreto em cima de AOP e OO (poxa, até o BileBlog usa alguns argumentos), e cisas estranhas como “eu disse que era impossível porque não faz nenhum sentido gastar tempo e simplicidade implementando esse tipo de coisa”, questionamentos vazios como “por que HQL não implementa todas as funcionalidades da OO?” (Como se Java os implementasse…), tratar um ERP, coração de qualquer empresa, como “coisa menor”, não saber o que é eager fetching e detaching e ainda assim achar os criticar, e, principalmente, este trecho:

Shoes, pergunte para alguém das antigas se ele leu Yourdon e Page-Jones para poder programar. Não leram. Se você for olhar o fonte de alguém das antigas perceberá que tem uma organização. Não é uma OO, mas é tão organizado quanto, e certamente não baixa a produtividade da equipe. Hoje só para programar uma boa OO precisamos ler várias bibliografias, conhecer Design Patterns, e várias outras coisas que você conhece bem. Porquê? Para desenvolver um sistema onde o cara vai cadastrar e ler dados? No máximo um relatório com algumas aglutinações, somas, consultas, limites e etc?

Que me preocupa muito vindo de um estudante de mestrado (além de ser bravata, já que a maioria dos engenheiros de sistems de verdade em algum momento tiveram seu contato com análise struturada/essencial e projeto estruturado).

Eu realmente adoraria ter um debate sadio mas a falta de argumentos e o excesso de factóides, evidências anedotas, falácias e achismos não deixa. Eu realmente tentei mas fico por aqui.

Eu já vi este ponto de vista várias vezes e na grande maioria delas um pouco mais de leitura e experiência ao manter sisteminhas “simples” “de cadastro” que viraram bombas-relógio, vivem mais tempo do que deviam e têm que ser integrados, entendidos, estendidos ou meramente consertados mudaram a perspectiva. Provavelmente é só questão de tempo.

Plataforma não Vence Cultura

Thursday, May 10th, 2007

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.

Ele Não Aguenta Mais Arroz Com Ovo

Monday, May 7th, 2007

Continuando na nossa série de alertas (não, não era uma série mas acabo de inventar isso) chegamos a um excelente texto sobre o futuro de java x .Net no infoQ. Deste eu destaco:

When .NET was first released in 2000/2001, the Java community considered it a “clone” of Java, both language and standard library. Comparing simple code samples surely support this impression. However, MS profited from many years of experience with Java, and managed to solve some issues that Sun only now realizes as problems. The impression that the .NET and the CLR are evolving faster than Java is not lost on the Java community.

Other examples of this are modularization and versioning, which.NET solved by choosing the assembly, a collection of classes, as the basic deployment unit. Assemblies are equipped with metadata such as version information, unlike Java’s Jar file which lack versioning metadata. This is troublesome for increasingly large applications, which load many libraries. OSGi now provides a solution for this, Sun is busy adding something similar to Java 7.

The Java language keeps on catching up with C#, adding features such as Generics and features such as AutoBoxing, Enumerated types or Annotations. C# now has anonymous expression support, which forms the underpinning of the LINQ technology. LINQ can be thought of a statically typed query language for many different types of data sources, such as XML, relational databases, but also arbitrary object graphs. The Java space, meanwhile, debates language minutiae such as language support for properties and which of four types of anonymous function to include in the language.

The Java space doesn’t really any of the mentioned items, except for the hosting interface, which was added in Java 6, under the name of JSR 223. This is basically just framework to add new language runtimes and initialize and access them in a standardized way.

Jim Hugunin continues with a detailed explanation of how dynamic method dispatch is handled, which makes use of extension methods and other existing CLR systems. The only comparable initiative is JSR 292, which among other things wants to add a new bytecode invokedynamic .This effort was started by Gilad Bracha, who soon after the creation of the JSR, left Sun, and is now not convinced that this project will bring any short term solutions:

Exceto a bizarrice do LINQ, este texto só mostra algo que vem sendo visto diariamente. Provavelmente a JVM e a CLR vão disputar como VMs de linguagens dinâmicas e de DSLs, e tudo mostra uma vantagem técnica para a MSFT. Acordemos.

Workshop IEEE

Tuesday, May 1st, 2007

Acabo de voltar de Porto Alegre onde participei do Workshop do SPIN-RS sobre tendências no desenvolvimento de software, realizado pelo IEEE. Foi um evento fantástico com apresentação de pessoas do porte de Philippe Kruchten, Stephen J. Mellor e Rebecca Wirfs-Brock, certamente o melhor conteúdo técnico que já vi em um evento nacional.

A única crítica que teria ao evento não é a este em si mas sim a cultura nacional. Muitas e muitas vezes vemos pessoas se despencando até São Paulo ou onde for e pagando várias centenas de reais para ver meia dúzia de pessoas que fazem apenas propaganda sobre uma dada ferramenta. Quando finalmente temos um evento onde pessoas importantes estão falando sobre temas importantes ficamosrestritos aos poucos que ouvem falar e têm coragem de ir ao local. Parabéns a organização do evento e aos presentes por mostrar que este país não é feito (apenas) de arrastadores de caixinhas.

A Linha Tênue entre o Hackin’ e a Gambiarra

Monday, April 2nd, 2007

Dia desses estava programando em par com um amigo quando encontramos um problema. Estávamos utilizando o excelente XStream para transformar um domain model em algo que pudesse ser consumido via webservices de arquitetura REST quando percebemos que nossos XMLs iam ficar enormes e com uns 40% de informações repetidas. Simplesmente haviam dados que eram comuns a várias entidades sendo serializadas em uma lista e se repetíssemos os dados para cada entidade serializada teríamos um grande problema.

Conversando com o Guilherme, ficamos sabendo que o XStream possibilita o uso de referências. Infelizmente também descobrimos que isso só funciona se você tem várias referências para o mesmo objeto (ou seja: tem que ser ==, não basta ser equals()). Seguindo indicações do Guilherme, vimos que para alterar este comportamento deveríamos mexer em uma classe específica que, a princípio, poderia ser estendida por uma subclasse nossa.

Aí a falta que faz seguir o Open-Closed Principle (OCP. E não, não é a ) se faz cruel. O OCP foi difundido por Bertrand Meyer, um dos papas da OOP, e diz:

Um módulo (uma classe, por exemplo) deve ter uma interface rígida e encapsulada para uso por outros módulos e ao mesmo tempo ser aberta e flexível apra ser estendida por estes.

Basicamente isso te dá uma diretiz para que crie métodos bem-definidos, não deixando vazar muita informação sobre o que sua classe faz mas ao mesmo tempo faça com que se alguém tiver que estender esta classe isso seja um processo sem dor. Se você não está interessado em deixar que outras pessoas estendam sua classe marque-a como final e acabe com o mal pela raiz.

Bom, ainda que seja uma biblioteca (não, não é uma API!) fantástica, o XStream peca neste quesito. A classe que faz esta comparação é inserida dentro de outra como atributo private e sem setter public ou protected. A primeira tentativa foi utilizar reflection para injetar os atributos ‘na marra’, a reflection em si funcionou mas… descobrimos que tratava-se de uma classe estática definida dentro de outra. Depois de ler algumas dezenas de linhas de código e escrever outras desistimos.

Percebemos um problema porque a quantidade de código que necessitávamos para adaptar o módulo foi crescendo muito. Eram várias horas de desenvolvimento e ainda não tínhamos uma solução aceitável, mas a base de código só crescia. Todos aquele código tomou tempo para ser criado (utilizando TDD) e demandaria ainda mais tempo para ser mantido no decorrer do projeto.
Simplesmente estávamos horas envoltos em código que não tinha nada a ver com a aplicação que estávamos desenvolvendo, nossa missão não era criar um serializador de XML mais flexível e sim transformar meia dúzia de objetos em XML utilizando uma ferramenta de mercado.

Daí, para a infelicidade de nossos egos de programadores, decidimos partir para uma solução simples (manter uma lista no contexto de marshalling do que já havia sido serializado e modificar nossos adapters) que atendia nossas necessidades. Não era tão cool, não usava recursos obscuros da linguagem… mas nos permitiu voltar a fazer o que somos pagos para fazer: aplicações.

Todo programador gosta de hackear uma biblioteca, um subsistema ou qualquer coisa que tenha sido feita por terceiros. Aliás, eu diria que bons programadores obrigatoriamente gostam disso. O problema é que existe um ponto em que a brincadeira deixa de ser produtiva e passa a ser mera masturbação tecnológica.

Múltiplas Fontes de Dados, uma Engine ORM

Friday, March 30th, 2007

O Tiago postou no seu blog sua percepção sobre como o Hibernate Search é um tiro no pé. Ele afirma que justo agora que o problema do mapeamento objeto-relacional está ficando irrelevante estão criando outro problema, que ele chamou de object-indexed.

Eu concordo que existe um novo problema no horizonte e que a estrutura simplificada de metadados para persistência não está pronta para este tipo de coisa, mas não acho que seja perda de tempo esta engine, na verdade acho que pode ser muito útil. Em um projeto recente utilizei a tecnologia que meu cliente adquiriu para fazer buscas em conteúdo, uma plataforma cara e famosa de busca. Apesar de eventuais problemas com APIs, a coisa se mostrou bem interessante.

Neste sistema eu utilizo o banco de dados para fazer buscas por objetos quando os quero processar e em um caso específico (o “resultado de busca”) eu preciso destes mesmos objetos vindos da engine de busca. Não importa qual a origem, os dados representam o mesmo objeto. As Camadas de Apresentação e de Negócios estão prontas para lidar com este objeto, apenas a Camada de Persistência deve saber de onde vieram.

Eu fiz todo este trabalho na mão e isso é bem trabalhoso. No final das contas criei um código relativamente reutilizável, que pode ser empacotado numa rquivo JAR e está sendo utilizado em outros projetos com necessidades parecidas.

A grande vantagem em termos objetos que podem vir de fontes estruturadas como um SGBD ou flat como uma engine de busca é que num ambiente como o meu atual onde a base de dados é o centro do universo fazer consultas ao banco é muito caro. Muitas vezes faz mais sentido pesquisar na engine de busca, que apesar de não trazer informações e relacionamentos completos possui informação para leitura facilmente encontrável.

Independência de persistência é algo que sempre existiu. Neste caso ainda é mais simples porque os dados são de somente-leitura em uma base, ela age simplesmente como um cache. O memcached, aliás, está sendo utilizado no meu projeto atual e é tratado de maneira persistente pela aplicação através de filtros no Spring.

Os dados vêm de todo lugar, uma interface única e poderosa como do Hibernate/JPA são muito úteis no cenário moderno.

Exemplos Simples

Thursday, March 29th, 2007

A partir do momento que você resolve utilizar uma tecnologia deve fazer o possível para entendê-la. Hoje eu estava conversando com um amigo e percebi que por mais que estejam espalhados os conceitos ainda não são entendidos. Falávamos sobre JPA e sobre como misturar lógica de negócios com metadados de persistência pode se tornar um problema em longo prazo. O argumento em favor da mistura foi “mas sua lógica de negócios não precisa ficar anotada, apenas seus dados”. Aí eu percebi que a discussão, na verdade, precisava passar por algo mais fundamental.

Eu expliquei o problema de usar VOs e BOs (que ele não chamava por estes nomes mas aplicava os conceitos) através de um exemplo simples.

Vamos supôr que exista uma função que define o novo salário de um funcionário (pseudo-codigo):

public void aumentaSalario(Funcionario f, Valor v){
Valor salario = v + calculaTaxasCargo(f.getCargo());
f.setSalario(salario);
}

E vamos supor que exista um tipo de funcionário chamado Gerente. O Gerente possui uma lógica de cálculo de salário um pouco diferente, dada pela formula:

salario = v + calculaTaxasCargo(f.getCargo()) + (f.getDepartamento().getOrcamento().getBonus() / 10)

Como adaptamos o código acima para que isso seja possível? Uma forma é criar um novo método:

public void aumentaSalario(Funcionario f, Valor v){
Valor salario = v + calculaTaxasCargo(f.getCargo());
f.setSalario(salario);
}
public void aumentaSalarioGerente(Gerente f, Valor v){
Valor salario = calculaSalario(f,v) + (f.getDepartamento().getOrcamento().getBonus() / 10);
f.setSalario(salario);
}

Mas desta forma nós sempre precisamos saber se estamos lidando com um gerente ou funcionário para saber qual função chamar. Se temos uma lista como a abaixo (que pode ser retornada do banco de dados, por exemplo) precisamos verificar cada tipo:

List<Funcionario> lista = new ArrayList<Funcionario>();
.
lista.add(new Gerente("João"));
lista.add(new Funcionario("Lucia"));
.
//aumentando o salario de todo mundo em 1000 dinheiros
for(Funcionario f: lista){
if(f instanceof Gerente){
aumentaSalarioGerente(f,1000);
}
else{
aumentaSalario(f,1000);
}
}

De que adianta ter uma abstração na forma de herança entre Funcionario e Gerente se cada vez que eu preciso manipulá-las eu preciso quebrar esta abstração com um if? Ok, é fácil de resolver isso criando uma função única:

public void aumentaSalario(Funcionario f, Valor v){
Valor salario = v + calculaTaxasCargo(f.getCargo());
.
if(f instanceof Gerente){
salario = calculaSalario(f,v) + (f.getDepartamento().getOrcamento().getBonus() / 10);
}
f.setSalario(salario);
}
.
//Aumentando salarios:
List>Funcionario> lista = new ArrayList>Funcionario>);
.
lista.add(new Gerente("João"));
lista.add(new Funcionario("Lucia"));
.
//aumentando o salario de todo mundo em 1000 dinheiros
for(Funcionario f: lista){
aumentaSalario(f,1000);
}

Mas o que eu fiz foi simplesmente mudar o problema de lugar, não acabar com ele (por isso minha métrica do if).

E qual a solução? Polimorfismo.

class Funcionario{
.
public void aumentaSalario(Valor v){
Valor salario = v + calculaTaxasCargo(this.getCargo());
this.salario = salario;
}
.
}
.
class Gerente extends Funcionario{
.
public void aumentaSalario(Valor v){
super.aumentaSalario(v);
//soma o bonus de gerente ao salario
f.setSalario(salario);
this.salario = this.salario+ (getDepartamento().getOrcamento().getBonus() / 10);
}
.
}

Daí nossa lista de aumento em massa pode fazer simplesmente:

//Aumentando salarios:
List>Funcionario> lista = new ArrayList>Funcionario>();
.
lista.add(new Gerente("João"));
lista.add(new Funcionario("Lucia"));
.
//aumentando o salario de todo mundo em 1000 dinheiros
for(Funcionario f: lista){
f.aumentaSalario(1000);
}

Porque cada objeto tem em si a lógica necessária para realizar a operação. Claro que este é um exemplo acadêmico, já identifiquei uma penca de refactorings necessários para o código ficar aceitável, mas a idéia está expressa nessa simples divisão de responsabilidade.

Aí é hora de alguém postar um comentário dizendo: “mas estes objetos ‘gordos’ têm toda a lógica? Fazem persistência?” a resposta é não. Objetos são ‘animais sociais e colaborativos’, o que significa que eles agem em conjunto com outros objetos para chegar a um fim. No exemplo acima, o cálculo sobre quanto é o bônus não é feito pelo funcionário, nem pelo gerente mas sim sobre quem é “dono” do conceito (dica: esta parte pode ser refatorada se você ler sobre o Princípio de Deméter).

Objetos dividem as responsabilidades e agem em conjunto para executar as regras de negócio de um sistema. Parece simples mas cada vez mais eu acho que as pessoas não gostam de conceitos simples :(

O Futuro na JAOO

Tuesday, March 20th, 2007

Ótimo painel sobre o futuro da programação no JAOO. Especialmente o comentário do PragDave:

Dave: I’d like to predict that the current stacks of software by 10-15 years are going to be in a much worse legacy and more of a nightmare to maintain. You’re going to have employment forever maintaining this stuff. C++, Java code, C# code, this stuff is very complicated and very brittle with all these class libraries and frameworks. We’re digging ourselves in a really big hole and there will be a lifetime of opportunities for you people to maintain this stuff that you’re creating.

Prepare-se e pense nisso antes de comprar aquela ferramenta mágica ou criar mais um framework que faz a mesma coisa que todos os outros.