Bom, no último post eu disse para você não ser repetitivo, e não escrever nos comentários o que o seu código faz. Se você precisa comentar o que o seu código faz, você realmente precisa refatorar o seu código e torna-lo mais legível …
Mas comentários no código não são sempre ruins, o ruim é você escrever em português o que o seu código faz em java, mas existem diversas situações que veremos a seguir onde os comentários são ótimos, ou pelo menso são úteis …
Por exemplo, na interface pública de um serviço, um JavaDoc informando para que serve aquele serviço e com exemplos de utilização são sempre muito bem vindos, principalmente se este comentário informar quais são as validações que serão feitas nos parâmetros e quais são as restrições ao uso daquele serviço …
Eu não posso pegar exemplos de projetos em que estou trabalhando por que isto seria motivo para demissão por justa causa por quebra de sigilo ![]()
Então vamos ficar com alguns exemplos públicos e alguns exemplos mais simples que eu conseguir pensar na hora …
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * This is the only interface you need to create and manage system users, but if you need to manage user privileges take a look at the @link{PrivilegesService} interface */ public interface UsersService { /** * This method should be used only if you are already authenticated in the system, do no forget to send the session id header when calling methods that are not public like this one. * To create a user you need to provide all the needed information, this method will create user in the database and then will try to create the user in the backend system, if the creation works the two accouns will be linked otherwise the database reccord will be erased. * @param userName the user name must be unique within the LDAP domain, this means that there can * @param password * @param email */ public User createUser(String userName, String password, String email); } |
Neste exemplo, não há necessidade alguma de colocar um comentário dizendo que o método createUser cria um usuário, mas o javadoc do exemplo informa de algumas pré condições para a execução do método e também diz qual o fluxo de execução e possíveis falhas. Como neste exemplo o UsersService é a interface publica de um serviço, esta documentação é bastante bem vinda, pois vai ajudar os usuários que vão acessar o serviço a saber o que fazer antes de criar um usuário e a saber possíveis motivos para as falhas.
Bom, acho que todos os outros exemplos que eu procurar vão ser parecidos com isto, resumindo este post e o anterior:
Se um comentário diz o que o método faz, o código é um lixo ou o comentário é redundante, o que o método faz tem que ser óbvio pelo nome do método
Se o comentário diz quando o método deve ser utilizado, algumas pré condições, o fluxo de execução, possíveis erros, e principalmente se ele esta em uma interface publica do sistema, que vai ser entregue a outra equipe/programador/empresa. o comentário é útil
Se o comentário esta em algum método ou variável privada, provavelmente tem algum problema por ai.
Acho que com isto eu encerro este assunto de comentários, eu posso ter me expressado errado, ou o mais provável, muitas pessoas leram o título do post e saíram berrando antes de ler o resto, mas a idéia básica é, o seu código tem que ser muito fácil de ler, os nomes das classes, métodos, variáveis, pacotes e quaisquer arquivos envolvidos no sistema devem dizer o que são, para que servem e por que estão ali. Se você esta colocando um comentário que diz que o método “create” cria um usuário, você deveria chamar o método de “createUser”, mas se o comentário esta informando o usuário do método de que o nome de usuário utilizado não precisa ser único mas o email sim, pois é este o campo utilizado como chave, ai você tem um comentário útil (e um sistema extranho
).
Não é por que o seu código tem comentários que ele é um lixo, mas tome cuidado por que é muito fácil utilizar comentários como desculpa para código ruim. E neste caso, talvez você precise estudar um pouco de rafactoring.
Tags: comentarios, lprodjava, produtividade, qualidade, refactoring

Bom, eu curti a idéia e fiquei pensando em como implementar isto, pelo menos em projetos Java, disto sairam estes “code snippets” abaixo …
Bom, normalmente trabalho com o ANT para fazer o build de projetos Java, e tenho utilizado o Subversion (sim, eu conheço o GIT e gosto dele, mas no momento não vai rolar no trampo, mas uso para projetos pessoais
)
Então, fui a página do subversion e baixei o SVNANT, desenvolvido pelo pessoal do subclipse, e integrei ele no meu build assim:
1 2 3 4 5 6 7 8 9 10 | <path id="svn_tasks"> <fileset dir="${directory_you_unzipped_the_svnant_package}" includes="svn*.jar"> </fileset> </path> <taskdef classpathref="svn_tasks" resource="org/tigris/subversion/svnant/svnantlib.xml" /> <target name="_setup_svn_info"> <svn failonerror="false" javahl="true" svnkit="false"> <info target="${basedir}" verbose="true"/> </svn> </target> |
Depois disto, em qualquer parte do build em que você for criar um .jar, .war ou qualquer tipo de pacote java, basta fazer algo parecido com isto:
1 2 3 4 5 6 7 8 9 | <target name="build_jar" depends="_setup_svn_info,compile"> <jar destfile="${dist.dir}/${jar.name}"> <fileset dir="${basedir}/bin" includes="*.*" /> <manifest> <attribute name="SVN-URL" value="${svn.info.url}" /> <attribute name="SVN-REV" value="${svn.info.rev}" /> </manifest> </jar> </target> |
Claro que o importante é o depends e o manifest, o resto vai depender do seu build, isto não é nem um exemplo real, escrevi direto aqui no blog para dar a idéia, então se tiver algum problema com o código me avisem nos comentários
Mas isto não é útil se você não conseguir ler o MANIFEST.MF do .jar onde a sua classe se encontra, então estou colocando aqui também um exemplo de código para isto, mas lembre-se de alterar o nome da classe para cada pacote, caso contrário você nunca saberá de qual pacote a classe esta sendo carregada
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package blog.urubatan; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.jar.Manifest; public class ExemploDoUrubatan { private Manifest manifest; private void initManifest() throws URISyntaxException, FileNotFoundException, IOException { Class<?> clazz = getClass(); URL classContainer = clazz.getProtectionDomain().getCodeSource() .getLocation(); File manifestContainer = new File(classContainer.toURI()); File metaInf = new File(manifestContainer, "META-INF"); File manifestFile = new File(metaInf, "MANIFEST.MF"); manifest = new Manifest(new FileInputStream(manifestFile)); } public ExemploDoUrubatan() throws URISyntaxException, FileNotFoundException, IOException { initManifest(); } public String getSvnUrl() { return manifest.getMainAttributes().getValue("SVN-URL"); } public String getSvnRevision() { return manifest.getMainAttributes().getValue("SVN-REV"); } public static void main(String[] args) throws FileNotFoundException, URISyntaxException, IOException { ExemploDoUrubatan ex = new ExemploDoUrubatan(); System.out.println(ex.getSvnUrl()); System.out.println(ex.getSvnRevision()); } } |
Se for a versão de um arquivo .war o código pode ser colocado em um servlet com uma URL conhecida, ou em um listener que vai guardar esta informação no servlet context para ser impresso depois por uma URL conhecida …
Se o servlet for a opção selecionada, o código ficaria parecido com isto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package blog.urubatan; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.jar.Attributes; import java.util.jar.Manifest; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletExample extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String warRoot = getServletContext().getRealPath("."); File manifestContainer = new File(warRoot); File metaInf = new File(manifestContainer, "META-INF"); File manifestFile = new File(metaInf, "MANIFEST.MF"); Manifest manifest = new Manifest(new FileInputStream(manifestFile)); PrintWriter writer = resp.getWriter(); Attributes mainAttributes = manifest.getMainAttributes(); String svnUrl = mainAttributes.getValue("SVN-URL"); String svnRev = mainAttributes.getValue("SVN-REV"); writer.format("URL: %s\nRev:%s\n", svnUrl, svnRev); } } |
Com isto, pelo menos para projetos java, já cobrimos duas das situações mais comuns, que são saber a versão de uma API e saber a versão de uma aplicação WEB.
Com isto já é possível verificar o deploy de aplicações durante o build se o script for um pouco mais inteligente, o pessoal de testes tem condições de dizer exatamente qual foi a build que gerou o problema, é possível construir um “dashboard” com a versão de tudo que é utilizado no sistema, facilitando bastante a identificação de onde o problema ocorre, e principalmente, no caso de clusters, permitindo que seja verificada a versão em cada um dos nós de uma forma fácil …
Agora no caso do Rails, eu ainda não consegui decidir qual a melhor abordagem para isto …
criar um arquivo com estes meta dados dentro do diretório config, atualizar este arquivo por uma task rake toda vez que for executar um deploy via capistrano e criar um controller para informar a versão?
As gems já tem um mecanismo de versionamento, seria só atualizar a versão da gem a cada build, coisa que pode ser feita até com keywork expansion, ou utilizando o mesmo esquema do rake mencionado antes.
Bom, vou pensar mais nisto, derepente rola até criar um plugin para aplicações rails pra facilitar a vida ![]()
O que vocês acham?
Tags: Java, lprodjava, produtividade, ruby on rails, sis
Eu sei que já falei sobre comentários antes, mas acho que a abordagem não agradou muito, a maior parte das pessoas leu só o título do post e não prestou atenção no texto, então vamos tentar uma abordagem diferente.
Este post é o primeiro de uma série de 2, o próximo post vai dizer que é necessário comentar o código, mas com comentários decentes, então, sem gritaria por aqui por enquanto, ok?
Mas vamos ao que interessa …
Na minha opinião, qualquer programador Java, ou até mesmo, qualquer programador, que colocar os olhos no código abaixo, vai entender quase que instantaneamente o que ele faz, se alguem não concordar com isto, avise por favor …
1 2 3 4 5 6 | new EmailMessage() .from("exemplo@urubatan.com.br") .to("gerente@empresa.com") .withSubject("Aprovação de processo") .withBody("Descrição bastante detalhada do que precisa ser aprovado") .send(); |
(sim, copiei o exemplo do blog do GC
)
Então, eu acredito que se alguem quiser colocar um comentário neste código dizendo algo do tipo:
Vai estar simplesmente sendo repetitivo, e poluindo o código com comentários inúteis, isto seria dizer o que o código faz, e se você comenta o que o seu código faz você é sim um perdedor que gosta de jogar trabalho no lixo!
Ahh, mas e se meu código não é assim tão claro? E se meu código é parecido com isto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // create some properties and get the default Session Properties props = new Properties(); props.put("mail.smtp.host", _smtpHost); Session session = Session.getDefaultInstance(props, null); // create a message Address replyToList[] = { new InternetAddress(replyTo) }; Message newMessage = new MimeMessage(session); if (_fromName != null) newMessage.setFrom(new InternetAddress(from, _fromName + " on behalf of " + replyTo)); else newMessage.setFrom(new InternetAddress(from)); newMessage.setReplyTo(replyToList); newMessage.setRecipients(Message.RecipientType.BCC, _toList); newMessage.setSubject(subject); newMessage.setSentDate(sentDate); // send newMessage Transport transport = session.getTransport(SMTP_MAIL); transport.connect(_smtpHost, _user, _password); transport.sendMessage(newMessage, _toList); |
Bom, se o seu código é assim, então você precisa estudar um pouco de refactoring ![]()
Ahh, mas estou alterando uma parte da aplicação com muito código legado …
Bom, você deveria utilizar pelo menos alguns “extract method” para facilitar um pouco a leitura, e não comentar o que o código faz.
Imaginem a seguinte cena:
Você esta caminhando na rua e entra em uma loja, no momento em que você entra na loja, vê uma placa escrito: Roupas masculinas
Dois passos adiante, um vendedor chega e diz: Senhor, aqui o senhor vai encontrar roupas masculinas
Mais alguns passos e outro vendedor: Vendemos roupas masculinas aqui senhor.
E mais outra placa dizendo: Aqui roupas masculinas
Se você ainda estiver na loja e não bater no próximo que lhe visar que ali são vendidas roupas masculinas, no mínimo acabou de ocorrer um desperdício absurdo de esforço para informar exatamente a mesma coisa.
E este caso do email não é um dos mais comuns, o motivo deste post é que em muitos lugares eu vejo código parecido com:
1 2 3 4 5 6 | /** * Set's the active property */ public void setActive(boolean active) { this.active = active; } |
(Isto não é uma critica a ninguém especifico e a todos os que já escreveram código assim, não foi uma nem duas vezes que vi isto por ai …)
um método de nome “setActive” com o comentário “Set’s the active property” é no mínimo redundância, e desperdício de tempo.
Então, eu não estou dizendo, nunca comentem o seu código, mas estou dizendo, se você precisa dizer o que o seu código faz, o seu código tem problemas, mas comentários são úteis, principalmente em interfaces públicas se você estiver informando por que ou como o código faz o que faz …
Mas tenha como regra, é proibido um comentário dizendo o que o código faz, pois ele é um sinal de que o código esta muito ruim!!
Ahh, e só para terminar, a biblioteca que permite aquele código de envio de emails bonitinho é a “Fluent Mail API” e o nome desta “técnica” é “Fluent Interfaces”, uma “técnica” bastante utilizada por quem trabalha com “Domain Driven Design”, e DDD faz Orientação a Objetos realmente mais divertida e mais útil, vou falar mais sobre isto em breve
.
Tags: comentarios, ddd, fluent interface, Java, lprodjava, produtividade
Canelada! é uma referencia a leitura de emails do Nerdcast, o poscast mais engraçado que eu ouço ![]()
Mas voltando ao assunto, preciso agradecer ao Mauro Oliveira por me avisar de alguns pequenos erros que ele encontrou enquanto lia meu livro sobre Ruby On Rails, o melhor livro sobre Ruby on Rails que eu já escrevi no mundo inteiro
Na página 113, no comando SQL do relatório de horas trabalhadas, no livro aparece:
1 | INNER JOIN users usr ON tl.user_id = tl.id #{user_filter} |
o correto seria:
1 | INNER JOIN users usr ON tl.user_id = usr.id #{user_filter} |
Na página 96, com o código mostrado no livro, o link para registrar horas em um projeto especifico não funciona em algumas situações, no livro o código esta assim:
1 | <%= link_to “Registrar Horas”, user_time_logs_path(@current_user, :project_id => project.id) %> |
Com a alteração sugerida, ele funciona sempre>
1 | <%= link_to “Registrar Horas”, new_user_time_log_path(@current_user, :project_id => project.id) %> |
E na edição de tipos de tarefa, na página 101, no método edit, que no livro esta assim:
1 2 3 4 5 6 7 | # GET /task_types/1/edit def edit @task_type = TaskType.find(params[:id]) end |
Foi preciso adicionar uma linha:
1 2 3 4 5 6 7 8 9 | # GET /task_types/1/edit def edit @task_type = TaskType.find(params[:id]) @project = @task_type.project end |
E alterar a view de edição de task type, a linha:
1 | <% form_for([:project, @task_type]) do |f| %> |
Para:
1 | <% form_for([@project, @task_type]) do |f| %> |
Isto faz a edição de tipos de tarefa funcionar corretamente
Desculpem pelo transtorno, se encontrarem mais alguma coisa errada por favor me avisem.
Tags: errata, livro, livror, rails Ruby
Encontrei hoje um plugin espetacular para o VIM, e claro, tive que testar ele, o resultado é este post que vocês estão lendo agora, que foi escrito utilizando o VIM ![]()
O Vimpress é um plugin para o VIM que adiciona alguns comandos divertidos para interagir direto com o Wordpress …
Agora vou testar o último comando, se vocês estão vendo este post no meu blog é por que funcionou, e eu sou uma pessoa mais feliz por que posso escrever os posts para o blog no VIM