tag:blogger.com,1999:blog-20355728608196630462024-02-20T19:43:25.257-03:00Qualidade garantida ou seu bug de volta!Unknownnoreply@blogger.comBlogger29125tag:blogger.com,1999:blog-2035572860819663046.post-86406531703944386512019-06-15T08:22:00.000-03:002019-06-15T08:27:42.762-03:00Mais 2 textos publicados no Medium!Olá, pessoal!<br />
<br />
Publiquei mais dois textos no <a href="https://medium.com/@dherik" target="_blank">Medium</a>:<br />
<ul>
<li><a href="https://medium.com/@dherik/aposentando-o-termo-dto-do-nome-das-suas-classes-vari%C3%A1veis-e-m%C3%A9todos-78c94e151085?source=---------2------------------" target="_blank">Aposentando o termo “DTO” do nome das suas classes, variáveis e métodos</a></li>
<li><a href="https://medium.com/@dherik/como-n%C3%A3o-usar-o-optional-do-java-d7ccf51cbf2e?source=---------3------------------" target="_blank">Como não usar o Optional do Java</a></li>
</ul>
<div>
Queria aproveitar e fazer um comentário sobre meus últimos textos.</div>
<div>
<br /></div>
<div>
Meus últimos textos não tratam de assuntos complexos, obviamente. Minha inspiração para estes textos vem de conceitos e problemas que vejo com certa frequência em projetos. Então estes mesmos textos acabam servindo para elucidar melhor alguns pontos que trago para as equipes, contribuindo para que elas produzam um código melhor.</div>
<div>
<br /></div>
<div>
Espero que gostem!</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-24189939772205440402019-02-07T21:01:00.000-02:002019-02-07T21:03:42.232-02:00Mais um texto no Medium! Agora sobre testes unitáriosOlá!<br />
<br />
Disponibilizei mais um texto no meu Medium:<br />
<br />
<ul>
<li><a href="https://medium.com/@dherik/diferen%C3%A7as-nos-testes-unit%C3%A1rios-entre-inje%C3%A7%C3%A3o-de-depend%C3%AAncia-por-construtor-e-por-campo-qual-%C3%A9-8316eb903d0a" target="_blank">Diferenças entre testes unitários usando injeção por construtor e por campo</a>. </li>
</ul>
<br />
Também criei <a href="https://pt.stackoverflow.com/questions/19020/como-efetuar-tdd-na-camada-service/361021#361021" target="_blank">uma resposta</a> bem interessante no StackOverflow sobre o mesmo assunto, mas voltado ao TDD.<br />
<br />
Confira!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-41511436925639026072018-11-05T19:46:00.000-02:002018-11-05T19:46:00.663-02:00Novos textos no MediumOlá!<br />
<br />
Estou com dois novos textos na minha conta no Medium:<br />
<br />
<ul>
<li><a href="https://medium.com/cwi-software/boas-pr%C3%A1ticas-o-porqu%C3%AA-de-fazer-um-teste-unit%C3%A1rio-para-cada-bug-encontrado-c5385fa708ed" target="_blank">Boas práticas: o porquê de fazer um teste unitário para cada bug encontrado</a></li>
<li><a href="https://medium.com/@dherik/os-benef%C3%ADcios-de-usar-inje%C3%A7%C3%A3o-por-construtor-8cd442884adc" target="_blank">Os benefícios de usar injeção por construtor</a></li>
</ul>
<div>
Estou publicando lá os textos pois consigo, assim, publicá-los no blog da <a href="https://cwi.com.br/" target="_blank">CWI Software</a>.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-7363217101145400642018-02-28T20:02:00.001-03:002018-02-28T20:02:05.436-03:00Implementação do RabbitMQ DLQ com exception ou com 'default requeue rejected'Olá!<br />
<br />
Disponibilizei no meu Github uma implementação de filas do RabbitMQ no qual as mensagens com erro caem em uma fila DLQ (Dead Letter Queue).<br />
<br />
Podem baixar o projeto aqui <a href="https://github.com/dherik/spring-rabbitmq-dead-letter-example" target="_blank">neste link</a>.<br />
<br />
Deu um pouco de trabalho pois não há muitos exemplos completos na Internet, principalmente para o caso de optar pela flag "default requeue rejected" e por não separarem o Produtor do Consumidor, o que causa confusão para quem está começando a entender o conceito de filas.<br />
<br />
Espero que gostem!<br />
<br />
<br />
<br />
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-30875913091664484062018-02-06T20:28:00.004-02:002018-02-17T19:59:42.487-02:00Por que todo desenvolvedor deveria ter uma conta ativa no Stack Overflow?Olá!<br />
<br />
Hoje gostaria de falar um pouco deste site que faz parte do cotidiano dos desenvolvedores de software: <a href="https://stackoverflow.com/" target="_blank">Stack Overflow</a>.<br />
<br />
Creio que uma das maiores revoluções da nossa área foi ter acesso a uma ferramenta como esta. Imagine a quantidade de tempo e dinheiro que os milhões de desenvolvedores do mundo economizaram tendo acesso a um local onde a maioria das respostas para suas dúvidas técnicas podem ser, na maioria dos casos, facilmente encontradas.<br />
<br />
Há mais de 4 anos atrás percebi a importância deste site e resolvi fazer o que eu considerava o mínimo: criar uma conta no site. O objetivo da conta era, principalmente, positivar as <a href="https://stackoverflow.com/users/2387977/dherik?tab=votes&sort=all&page=111" target="_blank">perguntas e respostas</a> que me ajudavam ou que eram simplesmente interessantes. Mas eu também sentia que poderia contribuir, e logo comecei a tentar responder <a href="https://stackoverflow.com/questions/16565540/how-can-i-see-what-files-git-is-going-to-push-to-the-server-in-xcode/16577952#16577952" target="_blank">algumas perguntas</a>. E não demorei muito para fazer minha <a href="https://stackoverflow.com/q/17847289/2387977" target="_blank">primeira pergunta</a>.<br />
<br />
Também tento fazer o mesmo no<a href="https://pt.stackoverflow.com/users/4492/dherik" target="_blank"> Stack Overflow em português</a>, que foi lançado anos depois da versão em inglês. Não consigo ser tão ativo lá quanto eu gostaria, mas sempre que tenho um tempo dou uma olhada lá e tento responder alguma pergunta.<br />
<br />
Hoje incentivo todo desenvolvedor que tenho contato, independente da idade ou experiência, a abrir uma conta no site. Os argumentos para incentivar nunca falham: retribuição. É só estimular a reflexão: "Quantas vezes você usou o Stack Overflow? O que acha de dar algum retorno para esta comunidade?". Eu sempre repito que o mínimo que todo desenvolvedor de software precisa fazer é criar uma conta no site e positivar as perguntas e respostas que o ajudam. Por isto sempre me mantenho logado no site durante o trabalho, pois é o momento que mais estaremos procurando por soluções, fazendo as perguntas e descobrindo as respostas.<br />
<br />
Criada uma conta no site e exercendo ativamente sua retribuição, naturalmente vem uma outra etapa: a contribuição. Confesso que ganhar reputação no site não é uma tarefa fácil e não existem atalhos. Você precisa ser ativo o tanto quanto pode, fornecer boas respostas e fazer boas perguntas. Mas creio que todo desenvolvedor que acessa o site é capaz de responder alguma pergunta ou fazer alguma pergunta que é a de muitos outros.<br />
<br />
O site consegue estar sempre muito ativo por três motivos: senso de comunidade, <i>gamification </i>e ofertas de trabalho.<br />
<br />
O senso de comunidade pode soar poético, mas é verdade: para muitos compartilhar conhecimento já é o próprio benefício. Caso contrário, não existiriam até hoje os fóruns de discussão na Internet. Pessoalmente, sou uma prova disto e entendo que este processo de entrar no Stack Overflow foi natural. Desde os 15 anos de idade eu já era fã de fóruns de discussão e respondia perguntas de desconhecidos sem ganhar nada em troca. Na época não sabia programar, então as discussões eram sempre sobre Hardware/Software de computador e Linux :).<br />
<br />
O <i>gamification </i>do site funciona bem e é um sistema bem justo, refinado ao longo de vários anos. Quanto mais contribui, mais pontos ganha e melhor você fica no <a href="https://stackexchange.com/leagues/1/quarter/stackoverflow/2018-01-01/2387977#2387977" target="_blank">ranking do site</a>. Confesso que gosto bastante de abrir o site e ver um <b><span style="background-color: lime;">+10</span></b> dentre as notificações recebidas.<br />
<br />
A parte de ofertas de trabalho é mais comum lá fora do que no Brasil, mas já recebi ofertas de trabalho de profissionais que vieram pelo meu perfil no Stack Overflow. Então fica a dica: se está procurando trabalhar fora do país, sua reputação no site pode te ajudar muito. Há até quem <a href="http://www.yegor256.com/2017/02/14/stackoverflow-is-your-tool.html" target="_blank">não contrate desenvolvedores</a> que não sejam ativos no site. O próprio site conta com uma área de <a href="https://stackoverflow.com/jobs" target="_blank">busca de empregos</a> mas, novamente, não faz muito sucesso no Brasil ainda.<br />
<div>
<br /></div>
Enfim, espero ter ajudado a convencer você, desenvolvedor, a abrir uma conta no site e começar a retribuir e, quem sabe, contribuir. Até a próxima!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-66084870076740173042017-11-06T20:22:00.003-02:002017-11-06T20:46:43.484-02:00Programação defensiva com Decorator: simplificando a verificação de nulos.Olá, pessoal!<br />
<br />
Muitas vezes nos deparamos sempre com os mesmos problemas simples e não paramos para pensar em como resolvê-los de forma mais eficiente. Já dei um <a href="https://qualidadegarantida.blogspot.com.br/2014/03/dica-rapida-como-trabalhar-com.html" target="_blank">exemplo</a> assim aqui no blog de como um problema simples pode ter inúmeras soluções diferentes.<br />
<br />
Agora, que tal aprender a fazer um:<br />
<br />
<script src="https://gist.github.com/dherik/d3f8bddfc8b6ce20aa43088034fd0ba5.js"></script><br />
Apenas instanciando a mesma classe?<br />
<br />
<h1>Problema</h1><br />
Vamos começar então. Imaginamos que tenhamos uma classe de nome Pessoa e que ela tenha um parâmetro nome:<br />
<br />
<script src="https://gist.github.com/dherik/c3a829e0fa883ca495516d78fb6f5733.js"></script><br />
<br />
E agora você deseja que o nome não seja nulo. Usualmente, a dúvida de muitos desenvolvedores é se o if será colocado no construtor, no <i>set</i> ou ainda em alguma classe de serviço responsável por criar pessoas.<br />
<br />
Então, não é comum terminarmos com uma solução assim:<br />
<br />
<script src="https://gist.github.com/dherik/48a89eec91b3886073d80c8359b9643a.js"></script><br />
<br />
Se depois aparecer um objeto Endereco, será a mesma coisa. Se aparecer um objeto Rua, será a mesma coisa. Ainda que apareça um parâmetro novo para Pessoa, como um sobrenome, teremos o mesmo caso. Logo verá que o código ficará bem repetitivo:<br />
<br />
<script src="https://gist.github.com/dherik/2e2a62e384252a3b19987fecc2bf8050.js"></script><br />
<br />
Sendo que tudo que queremos, afinal, é garantir que nome, sobrenome e cidade não sejam nulos.<br />
<br />
<h1>Alternativa</h1><br />
Como alternativa, se não queremos objetos nulos, podemos criar um objeto NotNull, desta maneira:<br />
<br />
<script src="https://gist.github.com/dherik/add78c3a969810c0877e899a0f0f1912.js"></script><br />
<br />
Esta classe usa generics, permitindo aceitar qualquer tipo de objeto como parâmetro e fazendo a esperada condição de verificar se o objeto é nulo.<br />
<br />
Desta maneira, podemos simplificar nossa classe Pessoa, fazendo com que ela receba nome, sobrenome e cidade não nulos, determinando isto já no contrato da classe Pessoa:<br />
<br />
<script src="https://gist.github.com/dherik/82a4755146a46db8afdd1d9a09e76e7a.js"></script><br />
<br />
E para instanciar uma classe Pessoa, basta:<br />
<br />
<script src="https://gist.github.com/dherik/1c604800aba6a6ca8db3d6f106508f96.js"></script><br />
<br />
Podemos também criar outras classes de verificação: NotEmpty, NotNegative (para números), ValidDate (para parse de datas), etc, e podemos combinar várias delas umas com as outras. Por exemplo, você pode querer que nome não seja nulo, não seja vazio e não contenha caracteres especiais, resultando em uma chamada parecida com esta:<br />
<br />
<script src="https://gist.github.com/dherik/4765ae06065a0f4ca165972be1f41229.js"></script><br />
<br />
Usando assim o poder do Decorator :). Trarei mais exemplos desta natureza em um futuro texto. <br />
<br />
Dúvidas ou sugestões, usem os comentários. Obrigado!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-83031121707945439792017-07-27T21:11:00.004-03:002017-11-10T10:06:19.872-02:00Teclado mecânico Alfawise V1 (ABNT 2): recomendo!Olá, pessoal!<br />
<br />
Faz um bom tempo que não escrevo (embora tenha vários rascunhos de textos... rs). E, infelizmente, não falarei de código agora mas sim de uma ferramenta muito boa para produzi-lo: o teclado. Não qualquer teclado, mas um teclado mecânico chamado <b>Alfawise V1</b>.<br />
<br />
Este texto aqui é para dar uma ideia da qualidade do teclado e apresentar alguns atalhos dele para alterar a intensidade da iluminação, cores e efeitos (algo que tive dificuldade de encontrar na Internet!).<br />
<br />
Enfim, fazia muito tempo que namorava a compra de teclado mecânico, mas a maioria dos modelos disponíveis e mais em conta não eram no padrão ABNT2. Assim, preferi aguardar que uma boa opção de teclado mecânico ABNT2 aparecesse com excelente custo-benefício. Afinal, o Motospeed Inflictor CK104 já estava por aí algum tempo, mostrando que é possível sim existir um teclado mecânico muito bom por um preço justo. <br />
<br />
Finalmente, este dia chegou.<br />
<br />
<h1>A compra</h1><br />
Através do <a href="https://adrenaline.uol.com.br/forum/threads/gearbest-teclado-mecanico-alfawise-v1-abnt2-portugues-r-143-92.614115/">fórum da Adrenaline</a> fiquei sabendo do teclado Alfawise V1 modelo ABNT2. Quando realizei a minha compra, havia poucas pessoas no tópico falando do teclado e poucas reviews no site da GearBest. Mas do pouco que li e vi, estava convencido que valia à pena arriscar e, literalmente, pagar para ver.<br />
<br />
Comprei o teclado na <a href="http://www.gearbest.com/keyboards/pp_631000.html">GearBest</a> por apenas 135 reais (com taxas e impostos!). O teclado demorou 1 mês e meio para chegar e estou com ele faz poucos dias, mas posso adiantar: adorei o teclado!<br />
<br />
<h1>Usando</h1><br />
O teclar de um teclado mecânico é bem diferente, pois exige menos força e o "feedback" da tecla é bem melhor durante a digitação. Com o Alfawise não é diferente. Por ele usar o blue switch, confesso que ele é mais barulhento do que eu imaginava, mas já esperava que isto pudesse ocorrer, pois é uma característica do blue switch. Confesso que dá até gosto escrever mais linhas de código com ele, rs.<br />
<br />
Como bom teclado mecânico e moderno que ele é, ele inclui iluminação em LED abaixo de cada tecla, que pode assumir diferentes cores e vários efeitos de iluminação. Vou deixar abaixo uma lista de atalhos para alternar entre estas diferentes configurações de cor e iluminação, tudo isto sem precisar instalar qualquer software!<br />
<br />
<h1>Conclusão</h1><br />
A intenção deste texto não foi fazer uma análise. Foi mais para divulgar este excelente teclado mecânico que, seguramente, foi uma das melhores compras que já fiz.<br />
<br />
E vamos aos atalhos!<br />
<br />
<h4>Atalhos de iluminação do Alfawise V1</h4><br />
<ul><li>Fn + INS: alternar entre diferentes modos de iluminação</li>
<li>Gn + DEL: alterna entre diferentes cores</li>
<li>Fn + PRT (Print Screen): desliga toda a iluminação</li>
<li>Fn + 1: Modo de jogo 1 (FPS)</li>
<li>Fn + 2: Modo de jogo 2 (CF)</li>
<li>Fn + 3: Modo de jogo 3 (COD)</li>
<li>Fn + 4: Modo de jogo 4 (LOL)</li>
<li>Fn + 5: Modo de jogo 5 (QQ race)</li>
<li>Fn + baixo: diminui o brilho</li>
<li>Fn + cima: aumenta o brilho</li>
<li>Fn + Esc: reinicia as funções do teclado</li>
<li>Fn + Win: bloqueia a tecla do windows e deixa ela na cor vermelha.</li>
</ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-45420428919809650222016-09-08T20:58:00.004-03:002016-09-08T21:01:54.622-03:00Implementação de Máquina de Estados disponível no meu GithubOlá, pessoal!<br />
<br />
Como podem notar, estou sem publicar faz algum tempo. Não é por falta de vontade, tenho vários rascunhos de textos, mas não consegui concluir nenhum deles ainda...<br />
<br />
Para não ter o risco de ficar sem postar em 2016, adianto que <a href="https://github.com/dherik/state-machine">publiquei no meu Github</a> uma implementação de máquina de estados que gostei. Vou incluir mais outras máquinas de estado ainda, só estou pensando se colocarei no mesmo repositório ou criarei outro. Assim que isto ocorrer, volto a postar no blog a novidade!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-27156112193372571502016-09-08T20:58:00.003-03:002016-09-08T21:01:07.237-03:00Implementação de exemplo de máquina de estados disponível!Olá, pessoal!<br />
<br />
Como podem notar, estou sem publicar faz algum tempo. Não é por falta de vontade, tenho vários rascunhos de textos, mas não consegui concluir nenhum deles ainda...<br />
<br />
Para não ter o risco de ficar sem postar em 2016, adianto que <a href="https://github.com/dherik/state-machine">publiquei no meu Github</a> uma implementação de máquina de estados que gostei. Vou incluir mais outras máquinas de estado ainda, só estou pensando se colocarei no mesmo repositório ou criarei outro. Assim que isto ocorrer, volto a postar no blog a novidade!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-79726754987916128142015-11-23T23:23:00.000-02:002015-11-25T22:44:42.739-02:00Os perigos que o EAGER pode trazer para a sua aplicação (parte 1)Olá, pessoal!<br />
<br />
Embora o JPA tenha muito anos de estrada e inúmeros projetos já tenham nascido utilizando este útil e famoso padrão para persistência de dados, vejo com mais frequência do que eu gostaria o uso indiscriminado de um recurso simples, aparentemente até inofensivo, mas que pode ser o seu principal problema de performance no futuro.<br />
<br />
Qual recurso? O famoso <b>EAGER</b>.<br />
<br />
Acredito que uma parte significativa dos desenvolvedores utilizam o EAGER sem entender o que ele realmente faz por trás dos bastidores ou, mesmo quando sabe, não tem dimensão do impacto dele.<br />
<br />
Sem mais delongas, vamos falar um pouco do que é o EAGER para entendermos o motivo dele ser tão perigoso.<br />
<br />
<h1>O que é o EAGER no JPA</h1><br />
Para explicar como o EAGER funciona no JPA, vamos começar mostrando esta entidade Pessoa:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #555555; font-weight: bold;">@Entity</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Pessoa</span> <span style="color: #333333;">{</span>
<span style="color: #555555; font-weight: bold;">@Id</span>
<span style="color: #008800; font-weight: bold;">private</span> Long id<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@Column</span>
<span style="color: #008800; font-weight: bold;">private</span> String nome<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@OneToMany</span>
<span style="color: #008800; font-weight: bold;">private</span> List<span style="color: #333333;"><</span>Endereco<span style="color: #333333;">></span> enderecos<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@ManyToOne</span>
<span style="color: #008800; font-weight: bold;">private</span> Endereco enderecoPrincipal<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre></div><br />
E esta classe Endereco:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #555555; font-weight: bold;">@Entity</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Endereco</span><span style="color: #333333;">{</span>
<span style="color: #555555; font-weight: bold;">@Id</span>
<span style="color: #008800; font-weight: bold;">private</span> Long id<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@Column</span>
<span style="color: #008800; font-weight: bold;">private</span> String logradouro<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@Column</span>
<span style="color: #008800; font-weight: bold;">private</span> String numero<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@ManyToOne</span><span style="color: #333333;">(</span>fetch <span style="color: #333333;">=</span> FetchType<span style="color: #333333;">.</span><span style="color: #0000cc;">LAZY</span><span style="color: #333333;">)</span>
<span style="color: #008800; font-weight: bold;">private</span> Pessoa pessoa<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre></div><br />
Quando fazemos uma busca pela entidade Pessoa no banco de dados, o JPA vai carregar sempre os atributo id e nome da Pessoa. Mas, quando há relacionamento entre 2 tabelas, como ocorre com <b>enderecos</b> (representado por uma lista de endereços da pessoa) e o <b>enderecoPrincipal</b> (um único endereço, o principal endereço da pessoa), existem 2 formas de obter estas as informações destas entidades no JPA:<br />
<ul><li>Carregar a(s) entidade(s) já na busca de Pessoa, assim como ocorre com os outros atributos básicos (id e nome) de Pessoa. Este é o método EAGER.</li>
<li>Carregar a(s) entidade(s) quando ela for necessária. Ou seja, quando for solicitada. Este é o método LAZY.</li>
</ul><br />
No exemplo de mapeamento de entidade Pessoa e Endereco, mostrado acima, temos ambos os casos (EAGER e LAZY) com os relacionamentos entre Pessoa e Endereco.<br />
<br />
Vamos, então, falar um pouco do método EAGER e sua relação com com os mapeamentos via anotações @OneToOne, @ManyToOne, @OneToMany e @ManyToMany.<br />
<br />
<h3>O mapeamento *ToOne: o EAGER ninja</h3><br />
Silencioso e fatal, todo relacionamento no JPA do tipo *ToOne (OneToOne e ManyToOne), por <u>padrão</u>, é do tipo EAGER.<br />
<br />
Isto quer dizer que <b>sempre</b> que ao consultar uma Pessoa no nosso exemplo, o framework que estiver usando (seja Hibernate<a href="#fn1" id="ref1"><sup>1</sup></a>, OpenJPA, etc) vai trazer também o endereço principal da pessoa.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #555555; font-weight: bold;">@ManyToOne</span> <span style="color: #888888;">// deste jeito, este cara é sempre EAGER!</span>
<span style="color: #008800; font-weight: bold;">public</span> Endereco enderecoPrincipal<span style="color: #333333;">;</span>
</pre></div><br />
Assim, se fizermos uma consulta JPQL como esta:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span> pessoa <span style="color: #008800; font-weight: bold;">FROM</span> Pessoa pessoa
</pre></div><br />
E tivermos um mapeamento configurado como EAGER, conforme ocorre com o endereço principal, teremos um SQL parecido com este sendo gerado no momento da consulta JPA:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span>
p.id, p.nome, <span style="color: #888888;">-- informações de pessoas</span>
e.id, e.logradouro, e.numero <span style="color: #888888;">-- informações de endereço</span>
<span style="color: #008800; font-weight: bold;">FROM</span> Pessoa <span style="color: #008800; font-weight: bold;">as</span> p
<span style="color: #008800; font-weight: bold;">JOIN</span> Endereco e <span style="color: #008800; font-weight: bold;">ON</span> p.enderecoPrincipal_id <span style="color: #333333;">=</span> e.id;
</pre></div><br />
Para entender o perigo que isto representa para o seu mapeamento de tabelas, veja a seguir este caso bem comum.<br />
<br />
<h4>EAGER em dose dupla: o que ocorre quando um usuário é relacionado a pessoa</h4><br />
Considerando a classe Pessoa mostrada anteriormente, imagine que uma nova funcionalidade foi adicionada ao sistema e temos agora a entidade Usuario. Cada usuário é representado por uma pessoa, então é natural criarmos um relacionamento entre as entidades Usuario e Pessoa:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #555555; font-weight: bold;">@Entity</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Usuario</span><span style="color: #333333;">{</span>
<span style="color: #555555; font-weight: bold;">@Id</span>
<span style="color: #008800; font-weight: bold;">private</span> Long id<span style="color: #333333;">;</span>
<span style="color: #888888;">//outros atributos de Usuario</span>
<span style="color: #555555; font-weight: bold;">@ManyToOne</span>
<span style="color: #008800; font-weight: bold;">private</span> Pessoa pessoa<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre></div><br />
Temos agora mais um mapeamento @ManyToOne no sistema que, como já dissemos, é EAGER por padrão.<br />
<br />
Agora sempre que consultarmos um inocente usuário:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span> usuario <span style="color: #008800; font-weight: bold;">FROM</span> Usuario usuario
</pre></div><br />
Vamos ter a pessoa relacionada a este usuário também sendo carregada! A consulta SQL gerada seria parecida com esta:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span>
u.id, u.<span style="color: #333333;">*</span> <span style="color: #888888;">-- informações de Usuario</span>
p.id, p.nome, <span style="color: #888888;">-- informações de Pessoa</span>
e.id, e.logradouro, e.numero <span style="color: #888888;">-- informações de Endereco</span>
<span style="color: #008800; font-weight: bold;">FROM</span> Usuario <span style="color: #008800; font-weight: bold;">as</span> u
<span style="color: #008800; font-weight: bold;">JOIN</span> Pessoa <span style="color: #008800; font-weight: bold;">as</span> p <span style="color: #008800; font-weight: bold;">ON</span> u.pessoa_id <span style="color: #333333;">=</span> p.id
<span style="color: #008800; font-weight: bold;">JOIN</span> Endereco e <span style="color: #008800; font-weight: bold;">ON</span> p.enderecoPrincipal_id <span style="color: #333333;">=</span> e.id;
</pre></div><br />
Pode não parecer, mas temos um grande problema nascendo.<br />
<br />
Como podem notar, quando fazemos agora uma simples busca pela entidade Usuario não temos mais um único EAGER, <b>temos 2 EAGERs</b>:<br />
<ul><li>de usuario para pessoa</li>
<li>de pessoa para o endereço principal</li>
</ul><br />
Quando ocorrer uma consulta por Usuario, ele vai trazer sempre a Pessoa por causa do relacionamento ManyToOne (que é EAGER por padrão) que, por sua vez, vai trazer sempre o endereço principal da Pessoa (que também está com um relacionamento do tipo EAGER).<br />
<br />
Momento de reflexão: pense agora como as várias entidades dentro de um sistema podem se relacionar assim, cada uma com várias colunas, com campos de texto de tamanhos consideráveis... Você logo chegará a conclusão que o impacto deste comportamento pode ser <b>bem</b> significativo. Com alguns EAGERs, você pode correr o risco de trazer uma porção de informações do banco de dados que você não vai utilizar em 90% das vezes.<br />
<br />
Eu arrisco dizer que o uso indiscriminado de EAGER é o principal problema de performance em sistemas que usam um framework JPA.<br />
<br />
Se isto já parece um problema sério o bastante para você, há um outro cenário comum em projetos envolvendo EAGER que tem impacto <b>muito pior</b> no desempenho. Mas falaremos dele no próximo texto :).<br />
<br />
<br />
<sup id="fn1">1. No <i>Hibernate Mapping Files</i>, que não segue a especificação JPA, todos os mapeamentos estarão configurados como LAZY por padrão, o que eu considero o comportamento mais correto. É no JPA que está especificado que os mapeamentos *ToOne devem ser EAGER por padrão e, por esta razão, o Hibernate (e demais frameworks JPA) são assim.<a href="#ref1" title="Voltar para texto.">↩</a></sup>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-74793144938588235952015-03-09T22:04:00.000-03:002015-03-09T22:08:53.649-03:00O que é uma branch no Git?Olá, pessoal!<br />
<br />
Vamos falar hoje de como o Git organiza internamente as branches criadas no repositório. Embora soe como um assunto complicado, veremos que é muito simples e que irá esclarecer várias dúvidas sobre o próprio Git.<br />
<br />
O Git realiza a organização dos commits por meio de uma estrutura de grafos, conforme foi <a href="http://qualidadegarantida.blogspot.com.br/2014/01/git-rebase-vs-merge-diferencas-e-qual.html" target="_blank">dito e explicado</a> em um texto anterior aqui no blog. Entendendo este conceito, podemos agora falar de como o Git usa esta estrutura em grafo para saber onde começa (e termina) uma branch e em qual branch o usuário está dentro de um repositório.<br />
<br />
<h3>
As branches: o que elas realmente são</h3>
<br />
Para o Git saber onde estão as branches, em qual branch o usuário está e até para criar tags dentro do repositório, o Git usa uma única coisa: ponteiros.<br />
<br />
Uma branch no Git é um ponteiro para um commit.<br />
<br />
Sim, é tão simples quanto isto. Agora, como ele consegue "se virar" apenas com um único ponteiro?<br />
<br />
Imaginemos que criamos um repositório novo e fizemos o nosso primeiro commit! Como ficaria a árvore de grafos do Git? Vejamos:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> M01</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">Bem, isto não nos diz muita coisa ainda. Como este repositório é novo e todo repositório novo tem obrigatoriamente uma branch <b>master</b><a href="#fn1" id="ref1"><sup>1</sup></a>, o Git precisa saber que o M01 faz parte da branch master. Assim, o Git cria um ponteiro para o commit M01:</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> M01</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;">|MASTER|</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span><span style="font-family: inherit;">O |MASTER| é o nome do ponteiro criado pelo Git para indicar qual commit faz parte da branch master.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Digamos que o usuário faz um novo commit na branch master</span><span style="font-family: inherit;">:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> M01<---M02</span><br />
<br />
<span style="font-family: inherit;">O que o Git irá fazer com relação ao ponteiro |MASTER|? Vai duplicá-lo no M02? </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Não, o ponteiro de uma branch é sempre único! Ocorrerá o seguinte:</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> M01<---M02</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span><span style="font-family: inherit;">O que ocorreu? O Git moveu o ponteiro |MASTER| para o commit M02. Assim, o Git determina que tudo para trás do M02 pertence a branch master. Se fizermos mais 2 commits, a estrutura de grafos do repositório Git ficaria assim:</span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="font-family: inherit;">Simples assim :). </span><br />
<span style="font-family: inherit;"><br /></span><span style="font-family: inherit;">Digamos que, agora, queremos criar uma nova branch chamada de <b>hotfix</b> para este repositório. Esta branch será criada a partir do último commit da branch master.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Ao criar uma nova branch chamada hotfix, teremos um novo ponteiro chamado |HOTFIX|. Veja:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> |HOTFIX|</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><br /></span><span style="font-family: inherit;">Temos agora 2 branches (master e hotfix) apontando para o mesmo commit M04.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Digamos que quero fazer um commit na branch hotfix. Logicamente, este commit só deve pertencer a branch hotfix e não pertencer a branch master.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Fazendo um commit M05 na branch hotfix, vamos ter o seguinte grafo:</span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> |HOTFIX|</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .---M05</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> /</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04<--´</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
Como é possível observar, o ponteiro do master permaneceu apontando para o mesmo commit que antes, o M04. Do M04 para trás temos a branch master. O ponteiro do hotfix moveu-se para o novo commit M05. Do M05 para trás temos a branch hotfix.<br />
<br />
Agora, vamos fazer um commit M06 na master! Como ficará o grafo? Vejamos:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> |HOTFIX|</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .---M05</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> /</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04<--´-----M06</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">Como ocorreu com o hotfix, o ponteiro do master moveu-se para o novo commit, o M06. Tanto o M05 como o M04 tem como commit "pai" o M04. Agora do M06 para trás (observe o grafo!) temos a branch master, na qual não incluirá o commit M05, que pertence neste momento unicamente a branch hotfix.</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
<h3>
Onde estou? Conheça o ponteiro HEAD</h3>
<br />
No exemplo anterior, mencionamos que o usuário poderia estar na branch master ou hotfix quando realizava os seus commits. Mas, como o Git sabe em qual branch o usuário está?<br />
<br />
Agora temos na jogada um outro ponteiro, o HEAD. O HEAD nos diz onde você está dentro da estrutura de grafos de commits do Git, e ele pode apontar para uma branch, tag<a href="#fn2" id="ref2"><sup>2</sup></a> ou um commit específico.<br />
<br />
Quando faço o comando para mudar de branch:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">git checkout master</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
Estou alterando o ponteiro HEAD para apontar para a branch master. Temos no grafo então:<br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> |HOTFIX|</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .---M05</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> /</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04<--´-----M06</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> |</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> |</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> <HEAD></span><br />
<br />
Assim como se eu fizer um:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">git checkout hotfix</span><br />
<br />
Estou alterando o ponteiro HEAD para a hotfix.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> <HEAD></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> |</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> |</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> |HOTFIX|</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .---M05</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> /</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04<--´-----M06</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<br />
Você também pode fazer um checkout para qualquer commit específico. Se quisermos fazer um checkout para o M03:<br />
<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> |HOTFIX|</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> <HEAD> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> | .---M05</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> | /</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M01<---M02<---M03<---M04<--´-----M06</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |MASTER|</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
Acredito que com este texto tenha ficado mais claro como o Git organiza-se para controlar as branches do repositório e de como ele controla em qual branch o usuário está no momento.<div>
<br /></div>
<div>
<br />
Nos próximos textos pretendo falar um pouco de alguns comandos interessantes (para dizer o mínimo), como o stash, squash, tag, etc.
<br /><br />
</div>
<sup id="fn1">1. O master é uma branch como qualquer outra dentro do Git.<a href="#ref1" title="Voltar para texto.">↩</a></sup>
<br />
<sup id="fn2">2. A tag é usada para marcar algum commit relevante dentro do repositório (como a entrega de uma versão, por exemplo). Tal como uma branch, a tag também é um ponteiro, tanto que uma tag não pode ter o mesmo nome de uma branch já existente no repositório.<a href="#ref2" title="Voltar para texto.">↩</a></sup>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-80200567162964337842015-02-13T22:11:00.001-02:002015-02-18T10:26:52.173-02:00Entendendo os JOINs no Entity FrameworkOlá, pessoal!<br />
<br />
Para quem leu os meus posts anteriores, estou agora me aprofundando na plataforma <a href="http://en.wikipedia.org/wiki/.NET_Framework" target="_blank">.NET</a> e gostaria de compartilhar um pouco do que aprendi. E, como seria possível imaginar para quem veio do mundo Java com Hibernate, logo minha curiosidade voltou-se ao principal framework de persistência da plataforma. Por esta razão, venho hoje para falar um pouco do <a href="https://msdn.microsoft.com/pt-br/data/ef.aspx" target="_blank">Entity Framework</a>.<br />
<br />
Uma dificuldade inicial que tive foi de entender como funcionavam os JOINs no Entity Framework. Não pela complexidade no entendimento em si, mas pela falta de um texto que sintetizasse bem as dúvidas de como o Entity Framework gerava os SQLs nas consultas montadas com LINQ e expressões Lambda. Como desenvolvedor, é importante eu saber como e quando o framework faz um LEFT JOIN, quando quero especificar mais de uma condição em um JOIN, como posso retornar apenas alguns valores, etc.<br />
<br />
<h3>
O JOIN, LEFT JOIN e Include</h3>
<br />
Como exemplo, vamos considerar o relacionamento entre 2 entidades: Pessoa e Endereço. Neste exemplo, uma Pessoa <b>precisa</b> ter um Endereço. O mapeamento seria:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;">modelBuilder.Entity<Pessoa>()
.HasRequired(x => x.Endereco)
.WithMany()
.HasForeignKey(x => x.EnderecoID);
</pre>
</div>
<br />
Podemos observar no mapeamento que especifiquei o relacionamento como <b>HasRequired</b>. Assim, estou dizendo ao Entity Framework que toda Pessoa deve ter, obrigatoriamente, Endereço. Ou seja, se eu fizer uma busca como esta:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #333399; font-weight: bold;">var</span> pessoas = context.Pessoas
.Include(p => p.Endereco)
.ToList();
</pre>
</div>
<div>
<br /></div>
<div>
Terei como resultado uma lista de pessoas com o endereço de cada uma <a href="https://www.blogger.com/blogger.g?blogID=2035572860819663046#fn1" id="ref1"><sup>1</sup></a>.</div>
<div>
<br /></div>
<div>
Quando utilizo o "Include", o Entity Framework faz o JOIN no SQL entre Pessoa e Endereço. A consulta SQL gerada seria algo parecido com esta:</div>
<div>
<div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">select</span> p.<span style="color: #333333;">*</span>, e.<span style="color: #333333;">*</span> <span style="color: #008800; font-weight: bold;">from</span> Pessoa p
<span style="color: #008800; font-weight: bold;">JOIN</span> Endereco e <span style="color: #008800; font-weight: bold;">ON</span> p.EnderecoID <span style="color: #333333;">=</span> e.ID
</pre>
</div>
</div>
<div>
<br /></div>
<div>
Mas, digamos que eu não quero um JOIN, pois o Endereço na Pessoa é opcional. Há pessoas que não tem endereço e eu gostaria de trazê-las também no resultado da consulta. Se é opcional, então não usamos HasRequired, e sim <b>HasOptional</b> no mapeamento:</div>
<div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;">modelBuilder.Entity<Pessoa>()
.HasOptional(x => x.Endereco)
.WithMany()
.HasForeignKey(x => x.EnderecoID);
</pre>
</div>
<br />
Com este mapeamento, a mesma consulta anterior vai fazer um LEFT JOIN entre Pessoa e Endereço:<br />
<div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">select</span> p.<span style="color: #333333;">*</span>, e.<span style="color: #333333;">*</span> <span style="color: #008800; font-weight: bold;">from</span> Pessoa p
<span style="color: #008800; font-weight: bold;">LEFT</span> <span style="color: #008800; font-weight: bold;">JOIN</span> Endereco e <span style="color: #008800; font-weight: bold;">ON</span> p.EnderecoID <span style="color: #333333;">=</span> e.ID
</pre>
</div>
<br />
Ou seja, quando fazemos o famoso "Include", o Entity Framework vai decidir se vai usar o JOIN ou LEFT JOIN olhando se o mapeamento entre as entidades está HasRequired ou HasOptional, respectivamente.<br />
<br />
No próximo texto vou falar de como montar uma consulta com LINQ e expressões Lambda para fazer um JOIN ou LEFT JOIN caso precise "desrespeitar" o mapeamento vigente entre e entidades, mostrar como fazer um JOIN/LEFT JOIN com mais de uma condição, <i>eager loading</i>, <i>lazy loading</i> entre outras coisas. Até mais!<br />
<br />
<h3>
Bônus: use o WithMany com sabedoria</h3>
<br />
Outro comentário importante, que vai mais como um bônus, é no uso do <b>WithMany</b>. Já observei que muitas pessoas sempre configuram o WithMany sem pensar na razão de estarem fazendo isto, pois não é obrigatório no mapeamento. O WithMany nada mais é do que o mapeamento do "outro lado" do relacionamento. Ou seja, ainda usando nosso exemplo entre Pessoa e Endereço, poderíamos ter:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;">modelBuilder.Entity<Pessoa>()
.HasOptional(x => x.Endereco)
.WithMany(y => y.Pessoas)
.HasForeignKey(x => x.EnderecoID);
</pre>
</div>
<br />
No mapeamento acima, a entidade de Endereço tem uma lista de pessoas. Mas, digamos que para o nosso sistema não faz sentido saber quais pessoas pertencem a determinado Endereço. Neste caso, qual a vantagem de fazer o relacionamento dos 2 lados?<br />
<br />
Nenhuma. Na verdade, há desvantagens como: poluir o código, aumentar a complexidade e até mesmo criar problemas de performance.<br />
<br />
Sim, problemas de performance. Não pelo mapeamento em si, mas pelo risco de isto acontecer por uso indevido. Explico.<br />
<br />
Digamos que você está em um sistema bancário que tem a entidade Movimentacao e ContaCorrente. Faz perfeitamente sentido a Movimentacao pertencer a uma ContaCorrente e ter este relacionamento mapeado no sistema. Porém, é muito perigoso o inverso: a ContaCorrente ter uma lista mapeada de Movimentacao, afinal, pode haver milhares de movimentações! Deixar algo assim facilmente "acessível" no mapeamento, podendo ser carregado na memória a qualquer instante, pode gerar sérios problemas na aplicação.<br />
<br />
<sup id="fn1">1. Para quem vem do mundo Hibernate, esta consulta mostrada tem um comportamento igual ao de um FETCH JOIN.<a href="https://www.blogger.com/blogger.g?blogID=2035572860819663046#ref1" title="Voltar para texto.">↩</a></sup><br />
<br /></div>
</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-87693075753312919192014-11-13T20:33:00.003-02:002015-02-14T00:00:07.001-02:00C#, .NET Open Source, Visual Studio, Window Phone... quanta coisa!Olá, pessoal!<br />
<br />
Sei que faz tempo que não posto nada no blog e não vim aqui para dar desculpas, então... vamos ao que interessa! :D<br />
<br />
Neste período que fiquei afastado do blog algumas coisas interessantes aconteceram. E a última delas ocorreu ontem. Se você trabalha com desenvolvimento e mora neste planeta, deve ter visto a notícia de que o <a href="http://goo.gl/FruZ94" target="_blank">.NET é Open Source</a> agora e, inclusive, já está <a href="https://github.com/Microsoft/dotnet" target="_blank">disponível no Github</a>.<br />
<br />
Outra excelente notícia da Microsoft, que veio de carona com a do .NET Open Source, foi o lançamento do <a href="http://www.visualstudio.com/products/visual-studio-community-vs" target="_blank">Visual Studio 2013 Community</a>, que tem todas as características do Visual Studio 2013 "full" e ainda por cima é de uso <u>irrestrito</u> para equipes pequenas (de até 5 pessoas). Para mais detalhes, dê uma olhada <a href="http://techcrunch.com/2014/11/12/microsoft-makes-visual-studio-free-for-small-teams/" target="_blank">aqui</a>.<br />
<br />
E por qual motivo eu apareci no blog falando de Microsoft e .NET?<br />
<br />
Mais ou menos na época do meu último post no blog, eu já estava estudando um pouco da plataforma do Windows Phone. Havia 2 motivos para isto:<br />
<br />
<ul>
<li>Eu estava prestes a trabalhar em um projeto com C# e precisava ficar mais familiar com a linguagem</li>
<li>Eu tenho um Lumia 520 com Windows Phone e eu me identifiquei muito com o conceito de simplicidade do sistema operacional (pretendo criar um post sobre isto no futuro!);</li>
</ul>
<div>
<br /></div>
<div>
Foi então que resolvi "aprimorar" meu C# criando um aplicativo para Windows Phone. O aplicativo é para apontamento de horas trabalhadas, integrado ao sistema de gerenciamento de apontamentos da empresa na qual trabalho, a <a href="http://www.dextra.com.br/" target="_blank">Dextra</a>. Sei que não é útil para a maioria das pessoas, mas foi uma forma de criar um aplicativo no qual tivesse uso para mim. O código-fonte do aplicativo está disponível no meu <a href="http://dherik.github.io/pmadex/" target="_blank">Github</a>, sendo que ele ainda está em desenvolvimento!</div>
<div>
<br /></div>
<div>
Bem, este post também é para mantê-los informados da pequena mudança de direção do blog. Nada me impede de voltar a falar dos assuntos que já abordei, como Git e Hibernate, mas creio que mais posts sobre C#, .NET e Windows Phone aparecerão a partir de agora. </div>
<div>
<br /></div>
<div>
Aliás, falando em C#, recomendo darem uma olhada na linguagem para quem ainda não a conhece. A linguagem por si só já oferecia diversas vantagens sobre o Java e agora, com o .NET tornando-se Open Source, a principal desvantagem de não ser multiplataforma tende a sumir, ainda mais com a ajuda certa do <a href="http://www.mono-project.com/" target="_blank">projeto Mono</a> para que isto ocorra o mais rápido possível.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-3915483133707696142014-05-22T11:22:00.000-03:002014-05-22T11:22:27.382-03:00Refatoração e prazos: como conciliar?<p>Olá, pessoal!</p>
<p>Escrevi um novo texto para o blog da Dextra!</p>
<blockquote><i>Hoje vou falar um pouco da importância da refatoração (refactoring) de código. Para alguns, um assunto tão natural que não mereceria nem uma discussão longa do seu valor. Mas, infelizmente, ainda temos pessoas que não compreendem totalmente esta técnica de melhoria de código. Porém, hoje não falaremos deste assunto na linha técnica, mas na comportamental.</i></blockquote>
<p>Leia mais aqui: <a href="http://www.dextra.com.br/refatoracao-e-prazos-como-conciliar/">http://www.dextra.com.br/refatoracao-e-prazos-como-conciliar/</a></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-76245490958787222032014-04-30T21:00:00.002-03:002014-05-01T17:54:11.438-03:00Cuidado ao realizar consultas com JOIN FETCH e WHERE no HibernateOlá, pessoal!<br />
<br />
Gostaria hoje de falar um pouco sobre os cuidados que precisamos ter ao usar FETCH JOIN no JPA/Hibernate. Apesar de ser um recurso muito útil, a falta do seu completo entendimento pode trazer confusões e surpresas nada agradáveis. Mas que, para nossa sorte, podem ser facilmente contornadas.<br />
<br />
Mas antes, uma introdução rápida sobre o que faz um JOIN FETCH em uma consulta. O JOIN FETCH é um recurso do JPA no qual permite que uma <u>única</u> consulta (em JPQL) à determinada entidade também traga outras entidades associadas. Podemos dizer que o JOIN FETCH é uma alternativa ao mapeamento entre entidades com o fetch em EAGER, tendo a grande vantagem de podermos escolher quando vamos aplicar este "EAGER" na entidade.<br />
<br />
Vamos a um exemplo. Imagine que temos as entidades Pessoa e Endereco:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #555555; font-weight: bold;">@Entity</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Pessoa</span> <span style="color: #333333;">{</span>
<span style="color: #555555; font-weight: bold;">@Id</span>
<span style="color: #008800; font-weight: bold;">private</span> Integer id<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@Column</span>
<span style="color: #008800; font-weight: bold;">private</span> String nome<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@OneToMany</span><span style="color: #333333;">(</span>mappedBy<span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">"pessoa"</span><span style="color: #333333;">)</span>
<span style="color: #008800; font-weight: bold;">private</span> Set<span style="color: #333333;"><</span>Endereco<span style="color: #333333;">></span> enderecos<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
<span style="color: #555555; font-weight: bold;">@Entity</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Endereco</span> <span style="color: #333333;">{</span>
<span style="color: #555555; font-weight: bold;">@Id</span>
<span style="color: #008800; font-weight: bold;">private</span> Integer id<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@Column</span>
<span style="color: #008800; font-weight: bold;">private</span> String rua<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@Column</span>
<span style="color: #008800; font-weight: bold;">private</span> Integer numero<span style="color: #333333;">;</span>
<span style="color: #555555; font-weight: bold;">@JoinColumn</span><span style="color: #333333;">(</span><span style="background-color: #fff0f0;">"pessoa_id"</span><span style="color: #333333;">)</span>
<span style="color: #008800; font-weight: bold;">private</span> Pessoa pessoa<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
<i>Explicação rápida: as entidades Pessoa e Endereço contém um atributo "id", identificador único de cada entidade<a href="#fn1" id="ref1"><sup>1</sup></a>. A Pessoa pode ter mais de um Endereco cadastrado, e cada Endereco contém a chave estrangeira para a Pessoa que reside naquele Endereco.</i><br />
<br />
Assim, com o FETCH JOIN, podemos fazer uma consulta na Pessoa que nos traga todos os Endereços dela de uma só vez! É para isto que ele é utilizado. Podemos fazer este JPQL desta maneira:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span> pessoa <span style="color: #008800; font-weight: bold;">FROM</span> Pessoa pessoa <span style="color: #008800; font-weight: bold;">JOIN</span> <span style="color: #008800; font-weight: bold;">FETCH</span> enderecos endereco
</pre>
</div>
<br />
Agora, temos a vantagem de consultar as pessoas com os seus endereços, não precisando ir novamente no banco de dados para recuperar apenas os endereços!<br />
<br />
Mas, se estendermos este exemplo para algo mais elaborado, temos que prestar atenção. Ao escrevermos o JPQL, temos que levar em conta um aspecto especial com o JOIN FETCH.<br />
<br />
Digamos que agora você deseja trazer todas as pessoas com endereço no qual a rua contenha a palavra "Alameda". Em uma consulta SQL, escreveríamos:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span> <span style="color: #333333;">*</span> <span style="color: #008800; font-weight: bold;">from</span> Pessoa pessoa
<span style="color: #008800; font-weight: bold;">JOIN</span> Endereco endereco <span style="color: #008800; font-weight: bold;">ON</span> endereco.pessoa_id <span style="color: #333333;">=</span> pessoa.id
<span style="color: #008800; font-weight: bold;">WHERE</span> endereco.rua <span style="color: #008800; font-weight: bold;">LIKE</span> <span style="color: #aa6600;">"%Alameda%"</span>
</pre>
</div>
<br />
Esta consulta traria todas as pessoas que tem endereço no qual a rua contém a palavra "Alameda".<br />
<br />
Agora, com a facilidade do JPQL, você quer fazer o mesmo: trazer as Pessoas com Endereco onde a rua contém a palavra "Alameda", mas com todos os seus endereços carregados em uma única consulta, conforme o primeiro exemplo em JPQL. No final das contas, você só quer adicionar um inocente WHERE.<br />
<br />
Deste modo, é natural pensar que o JPQL ficaria da maneira abaixo (estou abstraindo o setParameter(), para simplificar):<br />
<br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span> pessoa <span style="color: #008800; font-weight: bold;">FROM</span> Pessoa pessoa
<span style="color: #008800; font-weight: bold;">JOIN</span> <span style="color: #008800; font-weight: bold;">FETCH</span> enderecos endereco
<span style="color: #008800; font-weight: bold;">WHERE</span> endereco.rua <span style="color: #008800; font-weight: bold;">LIKE</span> <span style="color: #aa6600;">"%Alameda%"</span>
</pre>
</div>
<br />
Esta consulta vai executar? Vai. Trará resultados? Trará. O resultado vai ser o que você queria? Provavelmente não!<br />
<br />
Esta consulta irá trazer todas as Pessoas que tem Endereco que contenham a palavra "Alameda" na rua, contudo não irá trazer os demais endereços que não contenham "Alameda" para esta mesma pessoa! Por exemplo, se a Pessoa tiver um Endereco contendo "Alameda" e outro "Avenida", ele vai trazer a Pessoa apenas com o Endereco com "Alameda" no nome da rua.<br />
<br />
O que fazer neste caso? Agora vem o "jump of the cat": o correto é fazer outro JOIN sem FETCH. Desta maneira:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">SELECT</span> pessoa <span style="color: #008800; font-weight: bold;">FROM</span> Pessoa pessoa
<span style="color: #008800; font-weight: bold;">JOIN</span> <span style="color: #008800; font-weight: bold;">FETCH</span> enderecos
<span style="color: #008800; font-weight: bold;">JOIN</span> enderecos endereco
<span style="color: #008800; font-weight: bold;">WHERE</span> endereco.rua <span style="color: #008800; font-weight: bold;">LIKE</span> <span style="color: #aa6600;">"%Alameda%"</span>
</pre>
</div>
<br />
Agora a consulta é realizada com a condição no JOIN no qual não tem o FETCH associado. O JOIN com FETCH ficará encarregado de trazer as Pessoas com todos os seus Enderecos. Percebam que também removi o alias do "JOIN FETCH enderecos", que existia no JPQL anterior, pois não é necessário<a href="#fn2" id="ref2"><sup>2</sup></a>.<br />
<br />
<sup id="fn1">1. Evite o uso de chaves compostas quando puder, pois elas complicam as consultas com o JPA. Se você não for o responsável pelo banco de dados, negocie com o DBA a criação de chaves simples nas tabelas, mesma aquelas que a chave composta pareça a solução correta para o banco, pois a criação de uma <i>constraint</i> ou <i>unique index</i> resolverá na maioria dos casos para o DBA.<a href="#ref1" title="Voltar para texto.">↩</a></sup><br />
<br />
<sup id="fn2">2. Alguns frameworks JPA não permitem o alias para JOIN FETCH, exatamente para evitar este problema que ilustramos. O Hibernate permite, mas recomendo não utilizar alias com JOIN FETCH.<a href="#ref2" title="Voltar para texto.">↩</a></sup>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2035572860819663046.post-23400019632351741022014-03-21T09:41:00.003-03:002018-06-15T12:50:57.775-03:00Dica rápida: como saber se há itens duplicados em um List no Java?Olá, pessoal!<br />
<br />
A pergunta pode parecer muito simples, mas acredite, ela pode ter soluções e desdobramentos interessantes!<br />
<br />
Estava eu desenvolvendo normalmente, e apareceu um pequeno problema em que eu precisaria evitar que elementos duplicados estivessem em um List (ArrayList). Quando encontro problemas simples que podem ter diferentes soluções, eu costumo fazer uma pesquisa no Google, no qual costumo sempre parar no <a href="http://stackoverflow.com/" target="_blank">StackOverFlow</a>, para saber o quão criativo e eficiente podem ser as soluções de outros desenvolvedores. Sempre aprendo algo novo e, o melhor, normalmente não é com a solução mais votada!<br />
<br />
Inclusive, se um dia me acompanharem programando, vão se deparar comigo digitando no Google por soluções para questões tão básicas como esta... =P<br />
<br />
Surpreendido após o resultado da minha pesquisa, fiz a pergunta a alguns de meus colegas e pedi para eles dizerem a primeira solução eficiente que vierem à cabeça de cada um. Apareceram várias soluções:<br />
<br />
<ol>
<li>Ordenar a lista e percorrê-la, identificando se o próximo elemento da lista era igual ao atual.</li>
<li>Percorrer a List, adicionando cada elemento em uma nova lista, verificando se o elemento que está sendo adicionado já não existe nesta nova lista.</li>
<li>Transformar a List em um Set, para depois voltar para List .</li>
</ol>
<br />
Acredito que tenham ocorrido mais algumas ainda!<br />
<br />
Posteriormente, fiz outra pergunta:<br />
<br />
<h4>
Se eu quiser não removê-los, mas apenas saber se existem elementos duplicados?</h4>
<br />
Outras soluções apareceram e um deles já indicou uma das formas mais elegantes de o fazê-lo, que é copiar uma List para Set e verificar se o tamanho da List original difere do tamanho do Set.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;">List<span style="color: #333333;"><</span>Integer<span style="color: #333333;">></span> list <span style="color: #333333;">=</span> <span style="color: #333333;">...;</span>
Set<span style="color: #333333;"><</span>Integer<span style="color: #333333;">></span> set <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> HashSet<span style="color: #333333;"><</span>Integer<span style="color: #333333;">>(</span>list<span style="color: #333333;">);</span>
<span style="color: #008800; font-weight: bold;">if</span><span style="color: #333333;">(</span>set<span style="color: #333333;">.</span><span style="color: #0000cc;">size</span><span style="color: #333333;">()</span> <span style="color: #333333;"><</span> list<span style="color: #333333;">.</span><span style="color: #0000cc;">size</span><span style="color: #333333;">()){</span>
<span style="color: #888888;">/* There are duplicates */</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
Assim, fiz a última pergunta:<br />
<br />
<h4>
E se eu quiser saber qual elemento é o duplicado?</h4>
<br />
A solução 2 parecia ser a mais correta agora. Mas, o interessante é a forma como podemos implementá-la... Depois que mostrei esta solução para os meus colegas, foi muito interessante ver a reação deles. Por mais que você entenda de coleções em Java, poucos pensariam <a href="http://stackoverflow.com/a/600319/2387977" target="_blank">nisto</a>:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; background: #ffffff; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #333333;"><</span>T<span style="color: #333333;">></span> <span style="color: #333399; font-weight: bold;">boolean</span> hasDuplicate<span style="color: #333333;">(</span>Iterable<span style="color: #333333;"><</span>T<span style="color: #333333;">></span> all<span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
Set<span style="color: #333333;"><</span>T<span style="color: #333333;">></span> set <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> HashSet<span style="color: #333333;"><</span>T<span style="color: #333333;">>();</span>
<span style="color: #888888;">// Set#add returns false if the set does not change, which</span>
<span style="color: #888888;">// indicates that a duplicate element has been added.</span>
<span style="color: #008800; font-weight: bold;">for</span> <span style="color: #333333;">(</span>T <span style="color: #997700; font-weight: bold;">each:</span> all<span style="color: #333333;">)</span> <span style="color: #008800; font-weight: bold;">if</span> <span style="color: #333333;">(!</span>set<span style="color: #333333;">.</span><span style="color: #0000cc;">add</span><span style="color: #333333;">(</span>each<span style="color: #333333;">))</span> <span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">true</span><span style="color: #333333;">;</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">false</span><span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
Eu sei que é simples, mas não é legal? =)<br />
<br />
Querem uma outra dica? Façam uma pesquisa sobre remover elementos duplicados de um List preservando a ordem dos elementos (lembrando que qualquer transformação de List para HashSet altera a ordenação).Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-47590426744101641672014-01-06T22:14:00.000-02:002014-01-14T09:21:58.568-02:00Git rebase vs merge: diferenças e qual escolher em cada situaçãoOlá, pessoal!<br />
<br />
Muito se discute sobre qual é a melhor maneira de realizar o merge das alterações de uma branch para outra com o <a href="http://git-scm.com/">Git</a>. Como opções, temos o merge e rebase. De fato, ambas tem sua utilidade, mas quando devemos usar uma solução em detrimento da outra?<br />
<br />
Primeiro, vamos explicar o que cada uma delas faz.<br />
<br />
Comecemos com um exemplo simples. Imagine que você está fazendo commits na branch master com outras pessoas da sua equipe. Para simplificar o cenário<a href="#fn1" id="ref1"><sup>1</sup></a>, vocês estão usando o Github para sincronizar todos os commits da branch master, usando-o como repositório principal.<br />
<br />
Sendo assim, digamos que existem os seguintes commits neste momento no master do Github.<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">M1<---M2<---M3</span><br />
<br />
<br />
(Podem notar que representei os commits como um grafo não-cíclico, pois é desta maneira que o Git organiza os commits internamente.)<br />
<br />
Após fazer o clone do repositório, você faz mais 2 commits locais (C1 e C2). Na sua máquina, o repositório ficará parecido com o seguinte:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> .---C1<---C2<br /> /<br />M1<---M2<---M3<-´</span><br />
<br />
<br />
Contudo, no Gibhub, outros desenvolvedores já fizeram o push de mais 3 commits no master enquanto você tem ainda seus 2 commits que estão apenas no seu repositório local. No master do Github, teremos então a seguinte situação:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">M1<---M2<---M3<---M4<---M5<---M6</span><br />
<br />
<br />
Agora chegamos ao ponto crucial: como suas alterações farão merge com as alterações dos outros desenvolvedores?<br />
<br />
Com o <b>git merge</b>, o Git vai gerar um novo commit que concentra as alterações que ocorreram frutos deste merge dos commits C1 e C2 com os commits M4, M5 e M6.<br />
<br />
Se o usuário fizer um git fetch<a href="#fn2" id="ref2"><sup>2</sup></a>, irá receber as alterações e terá no seu repositório a seguinte situação:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> .---C1<---C2</span><br />
<span style="font-family: Courier New, Courier, monospace;"> /</span><br />
<span style="font-family: Courier New, Courier, monospace;">M1<---M2<---M3<-´---M4<---M5<---M6</span><br />
<br />
<br />
Ao fazer o merge, obterá o commit M7, resultado deste merge:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> .----C1<---C2<----.<br /> / \<br />M1<---M2<---M3<-´---M4<---M5<---M6<---`M7</span><br />
<br />
<br />
Como podem notar, o conceito é simples. Agora, o que ocorre quando fazemos um rebase?<br />
<br />
O <b>git rebase</b> é uma espécie de merge também, mas usa uma lógica diferente. Ao invés de gerar um novo commit, ele reaplica cada um dos commits da branch local "em cima" do último commit da branch remota.<br />
<br />
Ou seja, se temos 2 commits (C1 e C2), eles serão aplicados a partir do commit M7. <br />
<br />
Sendo assim, ao realizar o rebase, temos a situação:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> .----C1’<---C2’</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> /</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">M1<---M2<---M3<-´---M4<---M5<---M6<---M7<-´</span><br />
<br />
<br />
Notem que chamei o C1 e C2 agora de C1’ e C2’. Motivo? Após o rebase, estes commits não são os mesmos commits originais. Serão commits totalmente novos, até mesmo com o SHA (identificador único e hash) diferentes. <br />
<br />
No entanto, o conteúdo destes commits serão muitos similares aos dos originais. Mas, por qual motivo são similares e não exatamente iguais?<br />
<br />
Ao realizar o merge de cada commit local (C1 e C2), ocorrerão merges e até conflitos com os commits remotos (M4, M5 e M6), que podem modificar o conteúdo original dos arquivos envolvidos nos commits C1 e C2. O resultado deste merge e resolução de conflitos, portanto, serão o C1’ e C2’.<br />
<br />
<h3>
Entendendo as diferenças entre as 2 opções, quando usar rebase ou merge?</h3>
<br />
O rebase é muito útil para não “sujar” o histórico do repositório. Se não fizer o rebase, o git quase sempre<a href="#fn3" id="ref3"><sup>3</sup></a> vai criar um novo commit para o merge dos commits locais com os commits remotos. Este commit extra pode parecer inofensivo, mas torna-se um pequeno estorvo ao visualizar e entender a árvore de commits do git entre as várias branches.<br />
<br />
No mais, tirando ocasiões especiais, não recomendo o uso do rebase. Como rebase faz um merge para cada um dos commits da branch, o número de merges necessários é mais alto assim como o de conflitos (se ocorrer), e este trabalho aumenta a cada novo commit na branch. Se ainda não estiver convencido que esta opção é custosa, recomendo a leitura <a href="http://stackoverflow.com/questions/457927/git-workflow-and-rebase-vs-merge-questions/11219380#11219380">deste comentário no StackOverFlow</a>.<br />
<br />
Outro contra do rebase, para algumas pessoas, é que quando vocês faz um rebase <a href="http://paul.stadig.name/2010/12/thou-shalt-not-lie-git-rebase-ammend.html">você está "mentindo"</a> sobre o que está acontecendo no histórico do seu repositório.<br />
<br />
Mas o problema mais grave com o rebase não são estes. O rebase, muitas vezes por falta de conhecimento, é usado em branches remotas nos quais há desenvolvedores trabalhando ativamente nelas. Esta é a <a href="http://git-scm.com/book/ch3-6.html#The-Perils-of-Rebasing">receita para o desastre</a>. Porém, se ninguém está trabalhando na branch com commits pendentes, o rebase pode ser feito na branch remota de maneira segura.<br />
<br />
Depois destas considerações, na maioria dos casos é recomendado usar o merge: único momento de merge de alterações, único momento para resolver conflitos, não há risco de afetar o trabalho de outras pessoas, preserva a ordem real dos eventos no histórico mas com o efeito colateral de poluí-lo um pouco.<br />
<br />
O rebase é interessante apenas para ser aplicado no seu repositório local, onde temos normalmente poucos commits e apenas o próprio usuário realiza commits nela. No restante das situações, avalie com muito cuidado e tenha completo entendimento do que irá fazer. <br />
<br />
Esta última dica pode ser estendida, inclusive, para qualquer coisa que pretenda fazer com o Git: o entendimento da árvore de commits dele, ao meu ver, é essencial para entendimento e resolução de problemas. Deixe a decoreba de comandos do git para depois.<br />
<br />
<br />
<sup id="fn1">1. No git não há o conceito de repositório central. O que acontece é que a equipe acaba elegendo um dos repositórios para concentrar as alterações que podem gerar versões do sistema. Quando utiliza-se o Github, o intuito acaba sendo dele virar este repositório.<a href="#ref1" title="Voltar para texto.">↩</a></sup>
<br />
<sup id="fn2">2. Ao fazer git pull, o git por trás dos bastidores faz exatamente um git fetch (recebe os novos commits do repositório remoto) e em seguida faz o git merge (merge dos commits remotos com os commits locais).<a href="#ref2" title="Voltar para texto.">↩</a></sup>
<br />
<sup id="fn3">3. Quando é possível fazer um fast-forward.<a href="#ref3" title="Voltar para texto.">↩</a></sup><br />
<br />
<br />Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2035572860819663046.post-79942638009087397392013-11-12T22:37:00.001-02:002013-11-12T22:38:46.149-02:00Boas práticas ao criar testes com SeleniumOlá, pessoal!<br />
<br />
Publiquei mais um texto no blog da Dextra: <a href="http://www.dextra.com.br/boas-praticas-ao-criar-testes-com-selenium/" target="_blank">Boas práticas ao criar testes com Selenium</a>:<br />
<blockquote>
<i>Testes automatizados são um assunto de suma importância para um sistema. Uma das ferramentas de grande destaque nesta área, quando estamos falando de sistemas web, é o <a href="http://www.seleniumhq.org/">Selenium</a>. </i></blockquote>
<blockquote>
<i>É importante ter o entendimento de como usar da melhor maneira o Selenium, evitando trilhar caminhos perigosos no seu uso e extraindo o que há de melhor dele. Sendo assim, este texto segue com algumas dicas de utilização do Selenium que podem poupar o desenvolvedor de alguns problemas. </i></blockquote>
<blockquote>
<i>Mas, de quais problemas estamos falando?</i></blockquote>
Espero que gostem!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-2150920932929007562013-10-30T22:31:00.000-02:002013-11-08T21:16:24.680-02:00Textos de minha autoria no blog da Dextra!Olá, pessoal!<br />
<br />
Agora também estou publicando textos no <a href="http://www.dextra.com.br/category/blog/" target="_blank">blog da Dextra</a>! Já foram 2 publicados!<br />
<br />
O <a href="http://www.dextra.com.br/hibernate-onetoone-e-como-conseguir-ou-nao-um-lazy/" target="_blank">primeiro</a> fala de uma característica (ou bug?) do Hibernate ao realizar mapeamentos @OneToOne em determinadas condições. Importante leitura para todo desenvolvedor que usa Hibernate!<br />
<br />
O <a href="http://www.dextra.com.br/serie-de-dicas-para-jpahibernate-comecando-com-nao-retorne-desnecessariamente-a-entidade/" target="_blank">segundo</a> publicado foi o primeiro de uma série de vários textos com dicas de uso do Hibernate, que vão das simples até as mais avançadas. A maioria deles serão publicados no <a href="http://www.dextra.com.br/category/blog/" target="_blank">blog da Dextra</a>, mas deixarei o link de cada um deles aqui no blog também.<br />
<br />
Espero que gostem!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-80041354029579968942013-10-23T20:47:00.004-02:002013-12-04T11:48:49.363-02:00Comparando Enumerators no JavaOlá, pessoal!<br />
<br />
Estou aqui novamente, agora para falar dos Enumerators no Java.<br />
<br />
Trabalhando com Enumerators, é normal precisarmos comparar um Enumerator com outro Enumerator. Existem 2 formas de fazer isto:<br />
<ul>
<li>usando equals();</li>
<li>usando == ;</li>
</ul>
<div>
<br />
O uso que vejo mais comum é do equals(). Acredito que seja mais usado pelo fato do equals() ser adotado em qualquer comparação de objeto, pois o uso do == realiza a comparação de endereço na memória (que é o que raramente precisamos na aplicação).</div>
<div>
<br /></div>
<div>
Tão raro mas... faz todo sentido no caso dos Enumerators! Com uma vantagem: previne NullPointerException. Como isto é possível? Vamos aos exemplos.</div>
<div>
<br /></div>
Vamos pensar em um Enumerator chamado TipoDocumento, que contém as seguintes constantes: CPF e CNPJ:<!-- HTML generated using hilite.me --><br />
<br />
<div style="background: #ffffff; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">enum</span> TipoDocumento <span style="color: #333333;">{</span>
CPF<span style="color: #333333;">,</span> CNPJ<span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
Digamos que uma classe Pessoa tenha um atributo TipoDocumento:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Pessoa</span> <span style="color: #333333;">{</span>
<span style="color: #008800; font-weight: bold;">private</span> TipoDocumento tipoDocumento<span style="color: #333333;">;</span>
<span style="color: #888888;">//getters e setters</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<pre></pre>
<pre></pre>
<pre></pre>
<br />
Dado 2 instâncias de Pessoa (vamos chamá-las de pessoa1 e pessoa2), podemos comparar seus tipos de documento com equals():<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">if</span><span style="color: #333333;">(</span>pessoa1<span style="color: #333333;">.</span><span style="color: #0000cc;">getTipoDocumento</span><span style="color: #333333;">().</span><span style="color: #0000cc;">equals</span><span style="color: #333333;">(</span>pessoa2<span style="color: #333333;">.</span><span style="color: #0000cc;">getTipoDocumento</span><span style="color: #333333;">())</span> <span style="color: #333333;">{</span>
<span style="color: #888888;">//...</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
ou usando == :<br />
<br />
<div style="background: #ffffff; overflow: auto; overflow: auto; padding: .2em .6em; width: auto; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">if</span><span style="color: #333333;">(</span>pessoa1<span style="color: #333333;">.</span><span style="color: #0000cc;">getTipoDocumento</span><span style="color: #333333;">()</span> <span style="color: #333333;">==</span> pessoa2<span style="color: #333333;">.</span><span style="color: #0000cc;">getTipoDocumento</span><span style="color: #333333;">()</span><span style="color: #333333;">)</span> <span style="color: #333333;">{</span>
<span style="color: #888888;">//...</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
<div>
Reforçando, as 2 soluções são corretas!<br />
<br />
Contudo, a segunda solução tem a vantagem de não estar tão sujeita a um NullPointerException quanto na primeira, pois se o getTipoDocumento da pessoa 1 estiver nulo na primeira solução, ocorrerá um NullPointerException.<br />
<br />
A segunda solução também funciona pois o CPF e CNPJ são constantes do TipoDocumento, portanto, terão sempre o mesmo endereço na memória da aplicação. Por esta razão, podemos utilizar o operador == para comparação. Uma última vantagem da segunda abordagem é que ela deixa o código mais legível, o que é sempre bem-vindo.<br />
<br />
Enfim, uma dica simples, mas útil =).</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-87542052509789369852013-09-07T00:17:00.001-03:002013-10-31T23:46:38.959-02:0010 livros para desenvolvedores Java experientesOlá pessoal!<br />
<br />
Saiu no blog <a href="http://www.javacodegeeks.com/" target="_blank">Java Code Geeks</a> um <a href="http://www.javacodegeeks.com/2013/09/top-10-books-for-advanced-level-java-developers.html" target="_blank">post sobre os melhores 10 livros para desenvolvedores Java experientes</a>. Vale conferir, mesmo que você não se considere tão experiente assim!<br />
<br />
Já tive a oportunidade de conferir o <a href="http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683" target="_blank">Effective Java</a> e <a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" target="_blank">Clean Code</a>! Vocês ouvirão eu falar destes livros aqui algumas vezes. Outro livro que também está na lista do blog, e que será minha próxima leitura, é o <a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672" target="_blank">Refactoring: Improving the Design of Existing Code</a>, do Martin Fowler.<br />
<br />
Tudo a ver com qualidade!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-25388988201106011322013-08-30T19:00:00.000-03:002013-12-16T09:23:20.428-02:00Mão na massa! Como retornar coleções em métodos?Depois dos primeiros textos sobre qualidade, que focavam mais no aspecto comportamental com relação ao novato, equipe, chefe, cliente e empresa, vamos agora começar a falar de código!<br />
<br />
Como estamos começando o assunto no blog, de início não vou partir para nada mais avançado em termos de qualidade de código, como <i><a href="http://en.wikipedia.org/wiki/Software_design_pattern" target="_blank">design patterns</a></i>. Vou começar a demonstrar pequenas práticas, com foco na linguagem Java, que podem ser facilmente incorporadas no código produzido diariamente pelo desenvolvedor. Em princípio, acredito que serão muito úteis para os desenvolvedores <u>novatos</u>.<br />
<br />
Um bom programador deve dominar o conhecimento de práticas simples na construção de código. Livros como <a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=sr_1_1?s=books&ie=UTF8&qid=1377385443&sr=1-1&keywords=Code+Complete" target="_blank">Code Complete</a>, <a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" target="_blank">Clean Code</a> e <a href="http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683/ref=sr_1_1?s=books&ie=UTF8&qid=1377385472&sr=1-1&keywords=effective+java" target="_blank">Effective Java</a> exploram muito bem estas práticas, só que este conteúdo parece não alcançar grande parte dos desenvolvedores, pois observo que pouco se fala e se exercita qualidade de código no Brasil, ainda mais quando falamos da parte de testes. Obviamente, teste é primordial para conquista de qualidade, mas ele sozinho está longe de resolver seu problema de qualidade. Como diria Steve McConnell, no livro Code Complete:<br />
<br />
<blockquote class="tr_bq">
[...] trying to improve software quality by increasing the amount of testing is like trying to lose weight by weighing yourself more often.</blockquote>
<br />
Sendo assim, vamos para uma pequena e simples prática:<br />
<br />
<ul>
<li>Ao invés de retornar <i>null</i> para métodos que retornam uma coleção (um <i>List</i>, por exemplo), retornar uma coleção vazia;</li>
</ul>
<div>
<br />
Vamos a um exemplo. Imagine que você tem o seguinte método:</div>
<div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> List<span style="color: #333333;"><</span>String<span style="color: #333333;">></span> <span style="color: #0066bb; font-weight: bold;">consultarListaDeAlgumaCoisa</span><span style="color: #333333;">()</span> <span style="color: #333333;">{</span>
<span style="color: #888888;">//metodo fazendo alguma logica para retornar alguma coisa</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">null</span><span style="color: #333333;">;</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
Evite fazer isto! Se ocorre algo na lógica do seu código onde a lista poderá vir sem elementos, retorne uma lista vazia ao invés de null:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> List<span style="color: #333333;"><</span>String<span style="color: #333333;">></span> <span style="color: #0066bb; font-weight: bold;">consultarListaDeAlgumaCoisa</span><span style="color: #333333;">()</span> <span style="color: #333333;">{</span>
<span style="color: #888888;">//metodo fazendo alguma logica para retornar alguma coisa</span>
<span style="color: #008800; font-weight: bold;">return</span> Collections<span style="color: #333333;">.</span><span style="color: #0000cc;">emptyList</span><span style="color: #333333;">();</span>
<span style="color: #333333;">}</span>
</pre>
</div>
<br />
Assim, quando alguém chamar este método, não precisará verificar se a lista está nula ou não. Isto significará menos código a ser escrito, lido e chances menores de NullPointerException na aplicação.<br />
<br />
É claro, existem raras ocasiões que o retorno de uma lista nula pode significar algo na lógica da aplicação, diferente de uma coleção vazia. Mas temos que admitir que este tipo de situação é exceção, e não regra.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-39788340937094256832013-08-24T19:40:00.005-03:002013-08-24T19:40:46.406-03:00A empresa e a qualidade de código - Parte FinalEnfim, usei todo este discurso para chegar ao ponto que gostaria. Um software de qualidade vai além do código-fonte, pois envolve também a satisfação do cliente. E se a empresa busca qualidade em seus softwares, ela vai ter que flexibilizar o processo de desenvolvimento de alguma forma e seus empregados precisam estar dispostos e preparados para isto.<br />
<br />
Este tipo de movimento começa desde a fase de proposta do projeto pela equipe comercial da empresa. Os clientes em potencial também precisam entender como é o processo de desenvolvimento de software. Alguns deles, infelizmente, entendem que software é um produto simples que você pergunta quanto é, paga e ele atenderá as suas necessidades ao final. Mas a realidade não é esta. O cliente precisa estar envolvido do começo ao fim do desenvolvimento. Só assim ele terá um produto, na visão dele, com qualidade: regras de negócio contempladas, sem bugs preocupantes, com os ajustes que ele gostaria e com a aprovação do usuário final do produto.<br />
<br />
E a empresa pode fazer algo com relação a qualidade do código em si? Claro! Se sua empresa incentiva a busca pela qualidade, já temos meio caminho andado, pois este incentivo abrirá portas para que a equipe faça refatorações no código, use de <i>pair programming</i> e <i>code review</i>, dedique tempo para testes e integração contínua, dentre outras ações voltadas a qualidade que poderiam ser barradas em algumas empresas por pura ignorância.<br />
<br />
A empresa pode ir um pouco além e capacitar as pessoas, incentivando membros mais experientes a realizarem palestras e <i>workshops </i>sobre qualidade de software, envolvendo assuntos que iremos tratar aqui no blog.<br />
<br />
Bem, chega ao fim esta "série" sobre qualidade. Meu intuito foi demonstrar o envolvimento na qualidade do software pelos diferentes papéis na empresa. Como podem ter notado, gosto de conversar sobre assuntos comportamentais e organizacionais, então creio que vamos ver com alguma frequência este tipo de texto por aqui, mas o foco daqui em diante será código e mais código!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-16250305226418488692013-06-06T19:50:00.001-03:002013-06-21T21:32:40.003-03:00A empresa e a qualidade de código - Parte 1Depois de falarmos do papel do <a href="http://qualidadegarantida.blogspot.com.br/2013/05/o-novato-e-qualidade-de-codigo.html" target="_blank">novato</a>, da <a href="http://qualidadegarantida.blogspot.com.br/2013/05/a-equipe-e-qualidade.html" target="_blank">equipe</a>, <a href="http://qualidadegarantida.blogspot.com.br/2013/05/seu-chefe-o-cliente-e-qualidade.html" target="_blank">do chefe e do cliente</a> com relação a qualidade de código, vamos falar finalmente do papel da empresa.<br />
<br />
Não sou exatamente um empresário do ramo de software, então deem uma aliviada no que vou dizer agora. Pelo que consigo observar nos meus anos de experiência, os principais objetivos de uma empresa de desenvolvimento de software incluem: ver seus clientes utilizarem o software o mais cedo possível, ficarem satisfeitos com o produto entregue, procurarem a empresa novamente para novos projetos e sempre cobrarem um preço justo do cliente, o suficiente para gerar lucro para a empresa.<br />
<br />
Para estes 4 objetivos serem alcançados, todos eles passam pela qualidade do software:<br />
<br />
<ol>
<li>utilizarem o software o mais cedo possível: o software precisa estar nas mãos dos usuários do cliente o quanto antes. De preferência, se assim for possível, o software deve estar o quanto antes em ambiente de produção.</li>
<li>satisfeitos com o produto entregue: o software faz exatamente o que o cliente quer. Foi o produto que o cliente imaginou e que foi entregue</li>
<li>procurarem a empresa novamente: o software não só atendeu perfeitamente os anseios do cliente, como o mesmo gostou da experiência e preço da empresa, procurando-a novamente em projetos futuros.</li>
<li>lucro para a empresa: a empresa conseguiu atender a demanda do cliente e conseguiu lucrar conforme o planejado.</li>
</ol>
<div>
<br /></div>
Para conquistar estes objetivos, podemos descartar de início algum processo de desenvolvimento "travado", pouco ágil, que comumente encaixa-se no termo "fábrica de software". Embora processos não-ágeis possam garantir a qualidade do código gerado, são processos <b>muito</b> caros (indo contra o item 4), demorados pela burocracia envolvida que agrega pouco ou nenhum valor (indo contra o item 1) e que tem um risco alto da entrega não atender o que o cliente deseja (indo contra o item 2). No final disto, o item 3 dificilmente pode ser alcançado.<br />
<br />
Em geral, uma metodologia ágil acaba sendo a escolha mais natural, pois consegue contemplar melhor os objetivos acima e manter a qualidade do código. Contudo, a empresa precisa permitir que os softwares sejam construídos desta maneira.<br />
<br />
É muito comum encontrar empresas com cultura de anos atrás, de "fábrica de software", onde os empregados são chamados de "recursos" e os seus gestores acreditam que este modelo é o único que funciona. Aliás, não só gestores podem ser resistentes a mudanças nesta cultura dentro da empresa, mas também os desenvolvedores, que se acomodaram com o que sabem e não vão em busca de atualizar seus conhecimentos. Este desconhecimento de outras metodologias e tecnologias por estes profissionais são praticamente um reflexo do atraso da empresa na área de desenvolvimento de software.<br />
<br />
No próximo texto vou explicar a relação do que foi escrito acima com qualidade, encerrando (finalmente!) a "série"!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2035572860819663046.post-23163625479714660032013-05-28T22:50:00.005-03:002013-05-28T22:50:56.941-03:00Seu chefe, o cliente e a qualidadeNa área de desenvolvimento, muitos desenvolvedores são abençoados em ter gerentes que já foram desenvolvedores ou compreendem os processos envolvidos na construção de um software. Mas não raro é possível encontrar chefes que não entendem o trabalho que a equipe de desenvolvimento realiza.<br />
<br />
Um desenvolvedor já precisa lidar no dia-a-dia com a pressão do cliente. Este não tem a obrigação de entender nos detalhes como é o processo de desenvolvimento de um software, mas estará sempre de prontidão para pressionar a equipe de desenvolvimento para realizar as entregas de funcionalidade. É comum que esta pressão passe antes pelo gerente da equipe. Se o seu gerente tem consciência de como é o processo de desenvolvimento de um software com qualidade, que exige algumas tarefas "incompreensíveis", como refatoração e testes, ele defenderá a equipe e irá absorver este pressão adequadamente.<br />
<br />
Mas se o seu chefe não entende, a equipe ganha mais uma dor-de-cabeça.<br />
<br />
Todos sabemos como funciona: "Isto precisa entrar amanhã!", "Precisamos disto para ontem!", "Por que ainda não terminamos?", "é pouca coisa, dá para fazer rapidinho e entregar"...<br />
<br />
O recomendado é tentar fazer com que o seu chefe e cliente entendam o trabalho de desenvolvimento. É o desenvolvedor que é o profissional que vai construir o software, e ele deveria saber mais do que ninguém como fazer isto da melhor maneira possível.<br />
<br />
Se alguém (gerente ou cliente) pedir a entrada de uma funcionalidade Y para amanhã, converse antes para saber o motivo. Em uma conversa, muitas coisas podem ser reveladas:<br />
<br />
<ul>
<li>O seu chefe, ou cliente, não tem total consciência das consequências no sistema do pedido;</li>
<li>Deixe claro que as atividades que estão sendo realizadas neste momento serão atrasadas; alguns clientes tem a ilusão que ao pedir mais alguma coisa para determinada data, as que já estão em desenvolvimento não terão qualquer impacto.</li>
<li>Enfim, muitas coisas são urgentes quando, depois de uma boa conversa, deixam de ser;</li>
</ul>
<div>
<br /></div>
Se o consenso é que este pedido é importante, e que a data na qual esta funcionalidade precisa entrar não vai encaixar-se no processo adequado de desenvolvimento, deixe claro:<br />
<br />
<ul>
<li>A funcionalidade Y será entregue na data prometida, mas no próximo dia um dos desenvolvedores deixará de continuar a trabalhar na funcionalidade X para refatorar o código ruim, escrito às pressas, deixado pela funcionalidade Y.</li>
<li>Se a conversa chegou no assunto "horas extras", seja prudente; nenhum ser humano é uma máquina que pode trabalhar por longas horas.</li>
</ul>
<div>
<br /></div>
<div>
Agindo assim, tanto o seu chefe quanto o cliente não criarão a ilusão que podem realizar qualquer pedido para a equipe sem <u>compartilhar</u> as consequências negativas deste caminho. Até porque, se a equipe de desenvolvimento não corrigir o código ruim deixado, ou tomar qualquer outra ação para preservar a qualidade do software, as consequências serão muito piores para todos no futuro. É importante fazê-los entender que um código ruim hoje, fica pior ainda amanhã. Já dizia o Uncle Bob (Robert Martin):</div>
<div>
<br /></div>
<blockquote class="tr_bq">
No matter who. No matter what. No matter when. Short term. Long term. Any term. Writing good code is always faster than writing bad code.</blockquote>
<br />
No próximo texto vou falar do papel da empresa. Depois, podemos ir para a parte divertida: o código!Unknownnoreply@blogger.com0