Tag Archives: Design Patterns

Desenvolver em Java em pleno 2012, mesmos erros de 2005

Post já nasce datado, mas só faz sentido para agora mesmo. Passei uns 10 anos da minha vida programando na linguagem Java e nos últimos 3 anos eu peguei poucos projetos, mas o que me impressiona nesses poucos projetos é que as coisas não mudam, inclusive a tara por patterns desnecessários e antipatterns.

Comecemos por Nomenclatura

Se voce chama sua classes de WhateverController, WhateverService e ou WhateverDAO, voce está usando notação hungara desnecessária e complicando a modelagem do seu negócio. Se o seu framework te obriga a nomear as classes com sufixos ou prefixos, ele está errado e é melhor procurar uma solução.

Se voce chama classes como WhateverModel ou WhateverEntity aí voce está estragando a amizade, se mate.

Se voce tem uma classe chamada Whatever e tem propriedades como nameWhatever, leia urgente Clean Code.

 

BOLOVO

As pessoas criavam entidades chamadas WhateverManager por não saberem orientação a objetos, se existe isso no seu projeto na maioria das vezes não tem muito o que fazer, mude de emprego ou de projeto. Mas… se for corajoso comece a refatorar isso guiado por testes, o livro “Growing Object-Oriented Software, Guided by Tests” vai te ajudar bastante. O Paulo Silveira e o Phillip Calçado nomearam esse anti-pattern de BOLOVO.

DAO

DAO é o pattern inútil quando falamos de negócios, principalmente CRUD. A não ser que você esteja codando Framework ou comittando em projetos como o Hibernate, voce não precisa escrever DAO. Voce usa Hibernate, a Session é seu DAO.

Se voce precisa de uma entidade para agrupar alguma lógica de ORM mais complexa no seu negócio – como algumas transações com rollback lógicos, uma alternativa é Repository. Mas por favor, leia o artigo do Phillip primeiro e não faça WhateverRepository. Não há problema nenhum voce ter Criteria dentro de um controller por exemplo, afinal isso é um pattern bem estabelecido e o mapeamento um-pra-um com outra entidade só vai complicar e não traz ganho algum.

Só uma dica aproveitando o tema ORM, o Hibernate trabalha e sempre trabalhou com convenções usando anotações, então não precisa mapear tudo. Basta um @Entity na maioria das vezes. Nos relacionamentos observe se ele já não mapeia tranquilo apenas com o @ManyToOne e diminua o ruído.

Em termos de Patterns, por mais caduco que já esteja, o PoEAA do Fowler ainda reina.

 

Interface e Implementação

Existe uma boa prática como guia que é desenvolver orientado a interface, só que isso não é lei e deve ser usado o bom senso como sempre. A maioria dos desenvolvedores criam a Interface Whatever e uma – e apenas uma – implementação WhateverImpl. Isso é desnecessário e muita gente nem sabe que o Spring sempre funcionou injetar em classes concretas e não apenas em Interface. Deixe a Interface gritar na sua cara para refatorar.

Service e Domain Driven Design

Aqui que mora o perigo, sempre quando eu vejo WhateverService a implementação dessa classe é o mesmo código do antigo WhateverManager. Depois que Domain Driven Design fez sucesso todo mundo finje que modela o domínio.

As classes do seu domínio devem e podem ter métodos de negócios, se ela apenas tem propriedades é sinal do BOLOVO e representa uma tabela do banco de dados vitaminada. Um Service não é a parte de negócios do seu domain, a grosso modo de explicar o código dele explodiu na sua cara por manipular duas ou mais entidades e não ser responsabilidade de nenhuma delas.

ANUNCIO EM LETRAS GARRAFAIS

Cuidado com os livros que eu indiquei, quando foram escritos o Hibernate e o Spring estavam nascendo ou ainda não tinham nascidos, portanto leia com moderação. Várias coisas já forma implementadas pelos Frameworks e não vá fazer uma roda por cima de outra roda.

TL;DR

Cuidado com o código que voce escreve, faça-o guiado por testes, leia bons livros de Orientação a objetos e Patterns. Não escreva código igual aos outros porque é assim que todo mundo faz.

Typically chemist’s shop can sale to you with discreet treatments for various soundness problems. There are numerous of safe online pharmacies that will deliver medications to your address. There are divers medicines for each afflictions. Learn more about “viagra manufacturer coupon“. Maybe “viagra discount coupons” is a extremely complicated problem. Matters, like “coupons for viagra“, are united numerous types of health problems. If you need to take recipe medications, ask your pharmacist to check your testosterone levels before. Sometimes the treatment options may include erectile dysfunction remedies or a suction device that helps get an hard-on. Keep in mind web-site which is ready to sell erectile dysfunction drugs like Viagra without a recipe is fraudulent. When you purchase from an unknown web-site, you run the risk of getting counterfeit remedies.

Frameworks Caseiros 2: A missão

Eu participei como desenvolvedor de 4 projetos em Java nos últimos 12 meses, 3 deles tinham algo em comum: tinham uma arquitetura de referência, mais de 4 anos, baseados no struts 1.x, framework caseiro desenvolvido em cima do struts, modicações caseiras em APIs conhecidas sem contribuição com o projeto original [fork antigo ainda por cima], código altamente acoplado e sem coesão, arquitetura baseada em BOLOVO e principalmente sem testes [o último até que estava com uma tentativa de testes de aceitação com o Selenium mas com grandes dificuldades por conta de todos os problemas].

Em projetos antigos é comum encontrarmos esse tipo de situação, eu mesmo já criei meu framework caseiro em coisa por volta de 6 anos atrás, mas hoje em dia isso não só é algo abominável como um desrespeito pelos profissionais, ainda mais após tanta evolução nos últimos 10 anos.

Conversando com um amigo que trabalha em uma grande empresa de planos de saúde, ele me falou que o “arquiteto java” dessa empresa [conhecido por sua fama de criador de “Framearras”] convenceu a diretoria sobre um projeto recente que se baseia no desenvolvimento de um framework específico para a empresa [eles já possuem um framework caseiro que é um terror e bem conhecido por grande parte dos desenvolvedores locais].

É impressionante como não acaba essa tara de desenvolvimento de frameworks caseiros, qual a necessidade de uma empresa que tem TI como meio [e não como fim] de desenvolver um framework para desenvolvimento de software?

Olha que não é de hoje que eu falo sobre os perigos de frameworks caseiros, mas parece que os defensores desse tipo de abominação se reproduzem como coelhos.

Engraçado que no último projeto que participei eu recebi um treinamento de um dos criadores do framework caseiro que deveríamos usar na construção, alias na continuação de um sistema que está há 5 anos em desenvolvimento sem sinal de algo ir para a produção.

Os argumentos que ele usou foram os seguintes [anotei a frase para não esquecer]:

“Amigos, é importante um framework criado pela propria empresa para padronizarmos o desenvolvimento, diminuindo a curva de aprendizado e ganharmos na produtividade, utilizando padrões consagrados, obtendo reuso nos componentes de negócio e garantindo a manutenibilidade pela fácil criação de código, principalmente CRUD.”

Segredo do fracasso

Vou expor algumas considerações sobre essa frase dele:

Curva de aprendizado

Se algo é complexo de entender por quem conhece os padrões daquilo que se deseja desenvolver, é porque não serve mesmo. Não há como comparar um software opensource consagrado no mercado onde centenas de milhares de desenvolvedores já aperfeiçoaram com algo feito em casa.

Ganho na produtividade

A desculpa número um de todo framework caseiro é a famosa produtividade, sendo que voce sempre perde produtividade porque insere algo fora da normalidade no cotidiano do desenvolvedor. Além do que é insano voce ter uma produtividade no inicio – se fosse o caso, já que não é – comprometendo todo o ciclo de vida restante da aplicação por conta disso.

Porque é isso que acontece, todos esses frameworks caseiros são pensados e desenvolvidos para facilitarem a construção de CRUDs no inicio da aplicação e você tem que sacrificar todo o resto para satisfazer esse capricho que pode ser automatizado facilmente com tecnologias atuais.

Utilização de padrões

Ninguem pode saber que padrão utilizar antes de saber qual o problema, isso é impossível. Ou vai usar um martelo para furar uma parede ou uma furadeira para pregar um prego.

Reuso de componentes

Não existe reuso de objetos de negócios, nenhum processo é semelhante nem que seja na mesma organização ainda mais tentando reusar código por meio ide interface gráfica comum em projetos com dificuldade incial até de separação de pacotes.

Uma alternativa geralmente usada é se comunicar via API ou uma estrutura de serviço como WS, JMS, whatever e não aproveitando uma tela em um sistema distinto.

Aumento da manutenibilidade

Sistema como Frameworks caseiros sempre são dificeis de manutenção por que falta documentação, gente que conheça realmente [além dos próprios criadores], código sempre acoplado, falta de testes, maturidade, e principalmente propósito real [como não haver um existente no mesmo segmento].

Em todos os frameworks caseiros que trabalhei e não foram poucos, a manutenção é algo punitivo porque temos que satisfazer o framework e não o negócio.

Garantia da qualidade

Não há qualidade alguma em frameworks caseiros, pelo contrário, pelo conjunto de más práticas já expostas, o que acontece na realidade é que os sitemas desenvolvidos com esse tipo de ferramenta apresentam uma qualidade baixíssima.

Fork em frameworks do mercado

Problema em fazer um merge no futuro, voce não terá tempo e recurso suficiente para isso. Melhor solução seria submeter patch e codigo para o framework original e acompanhar o desenvolvimento deste. Deixa o desenvolvimento preso a versões antigas.

Associado a cascata.

Quase impossível você encontrar um framework caseiro em uma equipe ágeil, até porque isso fere vários dos valores e princípios.

Menos codificação

Na verdade duplica a codificação para satisfazer o framework.

Extensão de classes genericas

Acoplamento, referencia cíclica, etc… dá até preguiça de escrever.

CRUD Driven Design

Quebra o principio do XP que é fazer o mais importante e crucial primeiro, CRUD nunca é o mais importante. Se voce faz o CRUD primeiro, cria a regra de negócio e refaz todo o CRUD depois.

Geração de codigo sempre reescreve as informações, merge manual.

Frameworks caseiros são #ESFM. Vão complementando com as más práticas…

Typically chemist’s shop can sale to you with discreet treatments for various health problems. There are numerous of safe online pharmacies that will deliver medications to your address. There are divers medicines for each afflictions. Learn more about “viagra manufacturer coupon“. Maybe “viagra discount coupons” is a very much complicated matter. Matters, like “coupons for viagra“, are coupled numerous types of heartiness problems. If you need to take prescription medications, ask your pharmacist to check your testosterone levels before. Sometimes the treatment options may switch on erectile dysfunction remedies or a suction device that helps get an erection. Keep in mind web-site which is ready to sell erectile dysfunction drugs like Viagra without a prescription is fraudulent. When you purchase from an unknown web-site, you run the risk of getting counterfeit remedies.

Retrabalho e prejuízo

Em todos os projetos que trabalhei até hoje no mercado local [Ceará] existem profissionais mais ou menos qualificados a partir de uma base mínima de qualidade que um profissional tem que possuir dentro do modelo “Enterprisey” – que estamos acostumados e que responde pela quase totalidade dos projetos de software.

Essa base mínima eu proponho que seja – dentro do modelo exposto –  raciocínio lógico. O resto ele pode aprender.

Raciocínio lógico está ligado diretamente a noção de avaliar a situação, encontrar um padrão, investigar soluções existentes e implementar a solução, além claro de bom senso.

Não adianta pregarmos que os profissionais deveriam ser melhor escolhidos assim ou assado porque a realidade é que as empresas não tem como medir satisfatoriamente quem é ou não competente e mais cedo ou mais tarde você se deparará com indivíduos em sua equipe vindos por diversas nuances administrativas, seja aquele superqualificado cheio de títulos ou o primo do diretor da empresa.

Aonde quero chegar com essa história?

Precisamos avaliar os riscos necessários com bastante antecedência para que toda a equipe e consequentemente o projeto não sejam lesados e paguem o preço da incompetência às vezes de um único elemento. Parece óbvio? Acredite, não é!

Temos um projeto em um cliente – uma Alfândega – que precisamos refatorar todo o código criado por um determinado profissional com apenas dois ou três meses pronto. O projeto ainda está no início e já temos que refazer código.

Convenhamos, tudo bem que o código de meia hora atrás já é legado, mas código tão recente não deveria já ser refatorado sem mudança na lógica de negócio ou arquitetural. Algo muito errado aconteceu.

Mudanças não funcionais acontecem, surge um novo paradigma ou framework que reduz o tempo de desenvolvimento e convenientemente é adequado sua mudança, isso é comum durante a manutenção de um software já em produção com um meio século de uso – que em informática dura cerca de 4 ou 5 anos.

O nosso em questão não há motivos. Projeto novo, sem restrição ou adequação à “Arquitetura de Referência”, Frameworks de última milha na plataforma Java como JSF, Spring e Hibernate. Testes unitários – mas não TDD.

Como dito, separei um exemplo em código para demonstrar aonde quero chegar. Tem uma lógica bastante simples, existe um processo de apreensão de mercadorias na alfândega e liberação dessa mercadoria.

Há 3 tabelas que representam isso no modelo E/R: TB_DEVOLUCAO, TB_ITEM_APREENSAO, TB_ITEM_DEVOLUCAO. Segundo a lógica relacional, a TB_ITEM_DEVOLUCAO é uma tabela de junção entre a devolução e os itens apreendidos para indicar que item será devolvido.

Seguindo minha definição, um profissional com raciocínio lógico encontraria fácil a solução do mapeamento entre essas entidades apenas lendo a documentação, ele saberia que o Hibernate tem um mapeamento de OneToMany com Join Table Uni ou Bidirecional.

Mas não, ele criou essa bizarrice:

@Entity
@Table(name="TB_DEVOLUCAO")
public class Devolucao {

	@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	@JoinColumn(name="SEQ_ITEM_DEVOLUCAO")
	@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private List itensDevolucao = 
		new ArrayList();
	
}

@Entity
@Table(name="TB_ITEM_DEVOLUCAO")
public class ItemDevolucao { //Para que essa entidade?

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="SEQ_ITEM_DEVOLUCAO", columnDefinition="NUMERIC")
	private Integer codigo;

	@OneToOne
	@JoinColumn(name="SEQ_ITEM_APREENSAO")
	private ItemApreensao itemApreensao;
	
}

Esse profissional em questão é graduado em computação, tem mestrado em uma federal, certificação como arquiteto Java e diversas outras certificações e pasme, anos de experiência em projetos. Mas não tem o básico, raciocínio lógico. Não investiga e não sabe desenvolver software de qualidade.

O código em questão pode parecer bobagem até mas isso se repete em todo o código criado por esse profissional.

Um profissional responsável em refatorar o código com apenas curso técnico e uma mísera certificação de programador java refatorou assim [como deve ser]:

@Entity
@Table(name="TB_DEVOLUCAO")
public class Devolucao {
	
	@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	@JoinTable(name="TB_ITEM_DEVOLUCAO",
		joinColumns = @JoinColumn(name="SEQ_ITEM_DEVOLUCAO"),
		inverseJoinColumns = 
				@JoinColumn(name="SEQ_ITEM_APREENSAO")
	)
	@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private List itensDevolvidos = 
				new ArrayList();
	
}

Ad Hominem da minha parte? Tomar uma exceção pela regra? nada disso, eles são legião! Isso é meu cotidiano.

O prejuízo que esse profissional acarreta a todos os envolvidos é enorme e até difícil de ser mensurado porque envolve custos e humor da equipe que impacta em outros custos imperceptíveis na conta final que é a “fodisse” dos caras que tiveram que refatorar, ou seja, fizeram o seu e o trabalho alheio.

Ah, mas XP não prega o código coletivo? ir lá e consertar? Mas quebra o principal valor que é “Respeito”. Além do mais o projeto em questão seque o velho Cascata – mas culpa do cliente que exigiu ser assim, exigiu não, obriga.

Pela minha experiência de nada adianta você jogar um Clean Code nas mãos dele e pedir para estudar, ele vai continuar escrevendo nmDesc em uma propriedade ou IRepository em uma Interface. Ele foi treinado assim e sem raciocínio lógico no máximo que voce vão conseguir é retreiná-lo para conseguir comer a banana por outro túnel.

Um projeto sem um líder técnico responsável com aptidão e experiência necessária aliado a método baseado em BDUF sem um processo restritivo [como TDD] com modelagem ultrapassada com papéis de analista de sistemas “UMLizados” deixa esse tipo de profissional cometer esses pecados e prejudicar a todos os envolvidos retrabalho desnecessário.

É fácil resolver isso? É! O problema maior é que não podemos simplesmente aceitar que “o cliente quer assim”, temos um dever ético com nossa profissão de não permitir que o paciente escolha como ele quer ser operado e ceder médicos que não tenham capacidade de operá-lo.