semana_groovy_logo

Semana Groovy 31!

Última semana para se inscrever na primeira turma aberta de Grails da itexto!

Está sendo muito boa a procura pela nossa primeira turma aberta de Grails! O treinamento será iniciado no dia 3 de agosto e as inscrições poderão ser feitas até o dia 31 de julho.

Mais detalhes sobre o curso neste link: http://formacao.itexto.com.br

Links da semana

Criando uma aplicação Android com Groovy – http://www.tothenew.com/blog/creating-android-application-with-groovy/

Lidando com stored procedures usando o plugin Migration – http://www.tothenew.com/blog/migrating-stored-procedures-with-grails-database-migration-plugin/

Lições aprendidas na escrita da segunda edição do livro “Groovy in Action” – http://www.jworks.nl/2015/07/13/learnings-of-writing-groovy-in-action-second-edition/

Como externalizar e recarregar as configurações do Log4J em aplicações Grails – http://www.tothenew.com/blog/externalize-and-reload-grails-log4j-configuration/

Indo do Rails ao Grails: diferenças e similaridades - http://www.redwindsw.com/blog/2014-01-15-moving-from-rails-to-grails-differences-and-similarities

Dica de livro muito interessante sobre sistemas legados

Muito provavelmente você precisa lidar com algum tipo de sistema legado. Esta semana terminei a leitura de um livro excelente (e gratuito) sobre o assunto. Se chama“Object-Oriented Reengineering Patterns”, publicado sob a licença Creative Commons.

É uma excelente leitura: vai muito além do simples refatorar código. Apresenta alguns padrões de projeto formidáveis para se lidar com a equipe envolvida em um projeto deste tipo também.

Você pode baixar o PDF neste link: http://scg.unibe.ch/download/oorp/OORP.pdf

Contribua com a nossa newsletter

Viu algum texto legal que gostaria de compartilhar? Vai ministrar algum treinamento? Alguma notícia interessante? Nos envie usando este formulário.

semana_groovy

Semana Groovy 30 – a volta!

A volta da Semana Groovy

A você que acompanha esta newsletter, antes de mais nada gostaria de lhe pedir desculpas por mais este hiato. Espero que no futuro estes se tornem cada vez mais raros, no entanto, como você verá nas duas primeiras notícias, dois novos projetos da itexto acabaram me tomando boa parte do tempo.

Bom, de volta às notícias!

Formação itexto

Após muita pesquisa, finalmente conseguimos chegar a um formato de treinamentos online que, acredito, realmente agrega valor aos participantes. Trata-se do projeto Formação itexto: iremos lecionar aquelas tecnologias que sabemos agregar um valor imenso a desenvolvedores independentes e empresas. Claro: vamos começar com Groovy e Grails.

Serão aulas ao vivo (gravadas para que você possa assistir depois) focadas na prática (pouquíssimos slides, MUITO código) e com uma metodologia própria bastante diferente. Sabemos que será uma experiência fantástica e a primeira turma já está aberta. Se estiver interesse, corra, pois o tamanho é limitado a apenas 15 alunos.

Mais detalhes no site oficial: http://formacao.itexto.com.br

/dev/All

Enquanto a Formação itexto foi lançada semana passada, /dev/All está completando daqui a pouco seu segundo mês. Trata-se de um agregador de blogs relacionados a desenvolvimento de software, TI e tecnologias.

A ideia é criar este ponto de acesso no qual possamos acompanhar diariamente o que se produz sobre nossos assuntos de interesse. Caso você tenha um blog, é inclusive um local bastante interessante para que você o divulgue se cadastrando.

Você pode acessar o /dev/All neste link: http://www.devall.com.br

Links interessantes

Um dos objetivos do /dev/All era divulgar quem escreve sobre Groovy e Grails. E não é que deu certo? Segue alguns artigos em português de alguns blogs cadastrados que achei realmente interessantes.

Grails: internacionalização em banco de dados e arquivos – http://www.willcrisis.com/site/2015/06/19/grails-internacionalizacao-em-banco-de-dados-e-arquivos/

Descubra os novos métodos do Groovy para ordenação e remoção de duplicações -http://santograils.org/2015/06/12/descubra-os-novos-metodos-do-groovy-para-ordenacao-e-remocao-de-duplicacoes/

Groovy e seu selo de nerd – http://santograils.org/2015/06/22/groovy-e-o-seu-selo-de-nerd/ 

Grep e a ciência por detrás do switch do Groovy – http://santograils.org/2015/06/03/grep-e-a-ciencia-por-detras-do-switch-do-groovy/

Todos os links de /dev/All sobre Groovy e Grails

Posts sobre Groovy – http://devall.com.br/blog/busca?busca=groovy

Posts sobre Grails – http://devall.com.br/blog/busca?busca=grails

Slack do Grails!

Esta foi uma IMENSA novidade: a equipe responsável pelo desenvolvimento do Grails criou um hub no Slack através do qual podemos entrar em contato com ela e trocar muitas idéias.

Inscreva-se já! http://grails.slack.com

Contribua com esta newsletter

Soube de algo legal relacionado a Groovy, Grails, Spring, Java ou qualquer outra tecnologia e gostaria de divulgar aqui? Talvez seja um evento, ou mesmo um treinamento que você tenha criado. Basta entrar em contato conosco!

Basta nos enviar seu conteúdo preenchendo este formulário: https://docs.google.com/forms/d/1IDZ2MNo22FyQpan-UaFkuCzc3uFRWeXTzqHu1M6Xw8U/viewform?usp=send_form

Há também uma forma indireta: caso possua um blog, cadastre-o no /dev/All: assim, todo conteúdo em português irá ser divulgado por aqui também. http://devall.com.br

formacao_itexto

Nosso novo projeto: Formação itexto!

Pessoal, é com muita alegria que anuncio o nosso novo projeto: “Formação itexto“. Trata-se dos cursos online da itexto sobre tecnologias que sei agregarem real valor a empresas e desenvolvedores independentes.

Após muita pesquisa finalmente cheguei a um formato que, acredito, trás muito mais para nossos alunos e pessoas interessadas em obter excelente produtividade e qualidade no desenvolvimento de sistemas.

Nosso primeiro treinamento será sobre Groovy e Grails (previsível :) ). As turmas são limitadas, e maiores detalhes podem ser vistos no site da “Formação itexto”: http://formacao.itexto.com.br

Aguardo vocês lá!

multibot

Choque de cargos: o que eu e você somos?

Apesar da minha vida acadêmica ser bastante conturbada, sempre soube o que queria ser: programador. E a imagem que tinha desta profissão é muito próxima da imagem abaixo, usada em tantos memes:

basic_programming_color_cart

Era uma visão bastante ingênua por razões óbvias (eu tinha menos de 10 anos), mas confesso que ainda a tenho ao menos em parte. Computação é minha musa e bandeira que defendo até as últimas consequências.

Curiosamente não fui direto para o mercado de TI: fui trabalhar em livrarias, depois para a faculdade de Filosofia e os programas que escrevia eram (e ainda são em grande parte) criados por puro prazer. Anos depois finalmente larguei a Filosofia (e livrarias) e entrei no mercado: foi um choque.

O choque dos cargos

De repente vi as pessoas atuando como programadores mas se chamando de “desenvolvedores”, “arquitetos”, “fullstack developer” (este último, mais recente) e raríssimas vezes como programadores. Aliás, eu via outro nome curioso: implementador. Aonde estavam os programadores?

Me perguntava: era ruim ser programador? Era inferior? Conheci arquitetos fantásticos: aqueles caras projetavam soluções completas e, logo em seguida, davam massa às suas idéias escrevendo seu código. E então ouvia que programadores de torre de marfim era algo negativo e toda aquela história que vários de vocês já devem ter ouvido.

Conforme o tempo ia passando mais choques apareciam: pra começar não bastava ser um programador, você era um developer e um developer X, aonde X correspondia ao nome de uma tecnologia como Java, PHP, C, Delphi, .net ou qualquer outra.

O que eu era? Quando entrei no mercado já “dominava” algumas linguagens: C, Pascal, Delphi, Visual Basic, Java, PHP, Javascript, VBScript… E em todas estas conhecia gente que criava coisas fantásticas. Que tipo de “gênio” eu queria (e poderia) ser? Queria todos.

Indo além, via também as diferentes atividades: havia o sujeito que projetava o sistema (e depois o implementava), aquele que testava, outro que programava, o sujeito que coletava requisitos, tinha também “o figura” que gerenciava e aquele outro que coordenava. Tantas atividades, que na teoria aparentavam ser tão distintas, mas que na prática deveriam interagir entre si mas acabavam ignorando-se umas às outras.

Eu via, por exemplo, o analista de requisitos que não conseguia entender como o programador pensava, o arquiteto “Niemeyer”, que projetava coisas quase impossíveis para os programadores “engenheiros” construírem, o programador que não entendia como o sujeito do teste pensava e acabavam pipocando conflitos, aquele gerente que buscava um Santo Graal da produtividade…

Ainda pior: cada programador focado em uma única tecnologia pensando de forma completamente diferente e, para meu horror, ignorando as soluções presentes em outras plataformas por pura e simples futilidade, vaidade ou ignorância. Programador que não entende programador???

Ficava óbvio pra mim que por mais que se tentasse a especialização, o especialista não podia ser um solipsista. A pessoa do QA precisa entender como pensam o programador, cliente, arquiteto, analista de requisitos, etc. E o mesmo para todas as outras áreas de atuação.

E aí virei “empresário”

A visão que tinha até então era a do funcionário e neste ano comecei a ver “o outro lado”: eu, como empregador, como vejo estes cargos? itexto é uma empresa de computação: não me interessa se vou lidar com C, Lisp, Java, C#, Delphi ou Clipper. A fundei para criar um estilo de vida profissional a ser compartilhado.

Meu objetivo é ajudar os profissionais de computação a se tornarem melhores  e as empresas a tirar melhor proveito dos seus recursos e necessidades computacionais com nossa consultoria. Aonde entra o especialista estrito? Neste momento apenas se for para nos ensinar sua especialidade.

O especialista é caro (especialmente quando sua empresa é pequena). E estou usando o sentido estrito do termo: o que ele me dará é pouco comparado ao que iremos investir. Ainda pior: há aqueles que criam barreiras a qualquer solução que sua especialidade não abrace e acaba por nos limitar intelectualmente. Não basta ter um retorno mínimo: muitas vezes causa dano.

Claro: alguma especialidade é necessária. A minha é software, não administração: resolvemos com a Maria Angélica, que nos liberou para poder fazer aquilo que sei. Mas o especialista não poderia dizer o mesmo, digo, que faz apenas X dentro do processo de software por ser apenas “aquilo que sabe fazer bem”?

Respondo: você pode até fazer apenas aquilo, mas obrigatoriamente deve conhecer as outras áreas para se tornar realmente útil a nós. Um sujeito .net que apenas critique Java (e vice-versa) e não reconhece as suas vantagens é nocivo. Um testador que chama de “preguiçoso” o programador por que este “se esqueceu” de executar um teste o vejo como um tóxico (negativo). Um gerente de projetos que joga prazos absurdos por acreditar que a equipe está “enrolando” não passa pela minha porta. O arquiteto que projeta algo ignorando as capacidades da sua equipe e do seu cliente para nós fede.

Software é uma atividade interdisciplinar em sua essência, negar este fato é dar tiro no pé. Mais que interdisciplinar, geramos produtos baseados não em uma tecnologia, mas várias, cada qual nos oferecendo um ou mais caminhos para resolver os problemas que nossos clientes enfrentam. Fordismo quando o assunto é software não rola.

Esta nova realidade abriu muito meus olhos: é impressionante a dificuldade que temos em contratar. É tanta gente se rotulando e com isto reduzindo suas possibilidades de mercado que me assusta, cargos como “CTO”, por exemplo, que soam tão imponentes mas na prática acabam se mostrando inúteis, o cara “fullstack” que só conhece uma linguagem de programação (JavaScript), gente que sonha em ser “chefe” e se torna de cara “gerente de projeto” sem nunca ter visto um sistema ser criado, arquiteto que nunca programou e está buscando o primeiro projeto… Quanta gente “cara”!

Cegos guiando (ou gerando) cegos?

bruegel_blinds

Será que estas pessoas sabem o que de fato estes rótulos significam, se é que significam alguma coisa? Confesso que sempre tive dificuldade em saber o que de fato EU sou.  Programador? Arquiteto? Empresário? Consultor? Talvez “programador” me soe melhor aos ouvidos, mas sei que não é uma boa definição para meu caso. Prefiro “profissional de computação”.

Recentemente estive em um evento no qual o palestrante levantou o seguinte questionamento: “existe programador velho? Alguém se aposenta como tal?” (ele não respondeu, mas sua postura claramente respondia que “não”).

Achei curiosa a definição de velho (mais de 30 (sou um ancião portanto)), ainda mais interessante a ideia de programador (não havia). Aquilo me incomodou (muito): pessoas em início da carreira na platéia, vendo um cego que acreditava enxergar usando termos como developer, fullstack developer, architect e tantos outros em inglês.

Um cego guiando outros (pior: gerando cegueira), provavelmente formado por outro (cego (talvez sua cegueira se chame arrogância)). Senti duas coisas naquele dia: alegria por estar na itexto e a obrigação moral de questionar estas coisas.

java_logo_2

Projete boas APIs com Java exceptions

No meu último post falei um pouco sobre um dos meus recursos favoritos do Java que são as exceptions. Lá falei um pouco sobre como as exceções nos ajudam a pensar contratos, mas agora gostaria de ir um pouco além. Agora vou mostrar como tornar suas APIs muito mais ricas usando exceptions.

Mas o que é uma API mesmo?

Não vou dourar a pílula, sendo assim vou definir de uma forma bem direta:

é a parte executável do seu programa que você irá expor a outros programadores para que eles a executem

Repare que não usei a palavra “sistema” aqui, mas sim “programa”. Quando você projeta uma classe que possuirá métodos públicos, pensados para que outros programadores a usem, você está criando uma API (mesmo que você seja este outro programador).

Existe algum programa que não crie uma API Kico? Yeap: pense nos scripts que você escreve para automatizar suas tarefas. É aquele tipo de programa que você apenas quer que seja executado. Softwares feitos apenas para uso direto normalmente não expõem uma API.

Ah, mas aí, se outro programa o chamar, eu posso dizer que aquilo ali é uma API? Aí você relativizou a coisa e este post não sai. :)

Falaremos aqui não de APIs REST, mas sim aquela que se manifesta sob a forma de código executável, ou seja, os métodos públicos que você declara em suas classes ou os abstratos em suas interfaces.

O que é uma boa API?

Uma boa API é aquela que nos diz exatamente o que será feito. Tudo começa a partir do nome escolhido pelo programador para aquele método, que deverá expor de forma evidente a intenção daquele código.

Um bom nome já nos deu boa parte do que precisamos, o segundo componente são os parâmetros que a API espera. Idealmente devem ser poucos e com uma granularidade adequada. Vamos começar com um exemplo simples que iremos ir melhorando durante o post (sim, é código real):

int cadastrarPessoa(int id, String nome, String sobrenome, Date dataNascimento)

Reparou como a granularidade está errada? Por que não simplesmente passar um objeto do tipo Pessoa a ser persistido, tal como a versão melhorada que mostrarei a seguir? Ainda não é uma API perfeita, mas é inegavelmente mais simples (e o programador sofre menos no momento em que for digitar seu código):

class Pessoa {
int cadastrarPessoa(Pessoa pessoa) (...)
}

Há outro aspecto na API que deve ser levado em consideração: o tipo de retorno. Nossa versão anterior retorna um valor inteiro, que representa o identificador do registro no banco de dados. Se houver um erro, ela poderia simplesmente nos retornar um valor negativo: “-1: sem id, -2: sem nome, -3: sem sobrenome” e por aí vai. O valor de retorno terá então duplo sentido: o óbvio (retornar o identificador) e identificar um erro (quebra de contrato).

Um cliente da API então escreveria código similar ao exposto a seguir para lidar com erros:

switch (cadastrarPessoa(pessoa) {
case -1:
System.out.println("Opa! Sem o ID que deve ser preenchido antes!");
break;
case -2:
(...)
}

Sofrimento eterno que poderia ser um pouco aliviado incluindo algumas constantes, mas ainda seria um sofrimento eterno. Vimos alguns bons pontos na definição de uma API:

  • Um bom nome
  • Uma boa definição de parâmetros
  • Um valor de retorno que seja significativo (e possua uma única função)

Falta algo: os limites da API, ou seja, as condições para que ela funcione. É muito difícil tornar isto explícito em uma API REST, mas com código executável, especialmente em linguagens que possuam um recurso como as exceptions do Java, não. Como seria uma terceira versão da nossa API?

class PessoaNegocio {
void cadastrar(Pessoa pessoa) throws Validação (...)
}

Não preciso mais retornar um valor inteiro: se a persistência for bem sucedida, o próprio método já vai preencher o atributo “id” do objeto que passei como parâmetro. E se algo der errado? Uma exceção chamada Validação (evite caracteres especiais no seu código) será disparada, e nesta se encontrarão os detalhes a respeito do que deu errado.

A exceção é parte do contrato: ela nos diz algo como:

Ok, vou cadastrar esta pessoa no banco de dados, mas apenas se o objeto tiver valores válidos para todos os atributos.

Nossa API agora tem um limite bem definido: você lê a assinatura do método e sabe que somente objetos válidos, ou seja, aqueles cujo estado interno esteja de acordo com o que se espera, será persistido no banco de dados.

O programador agora pode escrever código ainda mais interessante:

try {
// o fluxo principal fica BEM isolado
negocio.cadastrar(pessoa);
} catch (Validação erroValidacao) {
// eu sei que meu problema é de validação
// talvez eu possa projetar algum comportamento
// de retentativa, ou mesmo informar melhor o
// usuário final a respeito da bobagem que está
// tentando fazer
}

E aqui entra mais um ponto que você deve levar em consideração quando for escrever sua API: os erros que talvez seus clientes não consigam aliviar. Uma falha no seu SGBD. Será que seria legal tentar melhorar um pouco mais nossa API tal como no exemplo abaixo?

void cadastrar(Pessoa pessoa) throws Validação, JDBCException

Antes eu sabia que objetos inválidos não seriam persistidos: agora também sei que uma falha no banco de dados pode ocorrer. Mais do que isto, sei que é um banco de dados relacional (JDBCException). Aqui entra o seu contexto.

Você quer que os usuários da sua API saibam que por trás dos panos está um SGBD relacional? Se sim, ok. Se não, trate internamente estes problemas e dispare uma exceção do tipo RuntimeException ou derivadas. Você estará aqui expondo detalhes de uma camada inferior sem necessidade alguma, e ainda tornando mais difícil a vida dos usuários da sua API.

Agora, se você quer expor este aspecto do sistema, perfeito: há aqui uma delegação de responsabilidade. O cliente da sua API terá de lidar explicitamente com erros provenientes da camada inferior do sistema.

Uma rápida menção ao Groovy

groovylogo

Groovy é uma linguagem que visa desburocratizar o trabalho do desenvolvedor. Uma das formas que faz isto é através do modo como lidamos com exceções do tipo checked.

Enquanto no Java, código que irá chamar um método que dispara uma exceção obrigatoriamente deve envolver a chamada ao método em um bloco catch ou incluir a declaração da exceção no método que o chamará, em Groovy este não é o caso. Então, código Java similar ao exposto abaixo:

try {
negocio.cadastrar(pessoa);
} catch (Validação ex) {
// trato aqui
}

ou

void executaAlgo() throws Validação {
(...)
negocio.cadastra(pessoa);
(...)
}

Em Groovy eu apenas chamo o método e o incluo em um bloco try… catch ou adiciono uma declaração do tipo throws  se eu quiser. Ok, ignoro então as exceptions? Não.

Se você vai projetar uma API, tudo o que disse em relação ao Java também se aplica ao Groovy, pois exceptions nos ajudam a explicitar os limites da mesma.

Concluindo

Meu objetivo neste post foi ir além do uso padrão das exceptions como uma ferramenta que nos possibilita escrever código mais robusto. Como puderam ver, elas também nos ajudam a implementar melhores APIs: com contrato melhor explicitado, mais fáceis de usar e que, consequentemente, acabarão por criar sistemas também mais robustos.

java_logo_2

Exceções do Java são úteis: talvez você é que não saiba usá-las

Semana passada escrevi sobre como os programadores complicam o código Java. Volto este tema agora para falar um pouco sobre um recurso extremamente útil da linguagem que, acredito, é muito mal compreendido: as exceptions.

Uma visão histórica

Acredito que para dominar uma linguagem de programação um dos primeiros passos que devemos tomar é buscar entender o que motivou e quais princípios guiaram sua criação. Uma abordagem histórica cai muito bem neste momento, sendo assim recomendo que você leia o capítulo sobre exceções tal como redigido na especificação do Java 1.0, acessível neste link (observem a ironia).

A leitura desta especificação é muito interessante, especialmente quando vemos de forma explícita os principais objetivos dos designers na criação da linguagem naquele momento: prover portabilidade e robustez. Ao falarmos de exceções o que realmente nos interessa é o segundo princípio. Como esta robustez é obtida?

Antes um pouco de semântica: uma exception, como o próprio nome já nos diz, denota uma condição anormal que ocorre durante o fluxo de execução dos nossos programas.

 

A vida sem exceptions

Muitas linguagens de programação simplesmente finalizam a execução do software (pense em C ou Pascal) quando algo assim ocorre e não há alguma forma de tratamento do erro padronizada, outra alternativa é apenas retornar um código de erro que pode facilmente ser ignorado pelo programador (pense na função read do C retornando o valor -1, por exemplo).

Vamos a um exemplo rápido usando “pseudo C”. A linguagem possuí uma função chamada read (mencionada acima) que lê bytes em uma fonte de dados e a armazena em um buffer. Ela retorna o valor -1 caso algo de errado ocorra, 0 se chegamos ao final do arquivo e um valor positivo nos informando quantos bytes foram lidos. Veja o código abaixo:

char buffer[128];
read(arquivo, buffer, 128);
printf("Serei impresso?");
// operações importantes seriam executadas na sequência

Este é um código muito comum: o programador espera que o arquivo sempre exista, sendo assim, possuí a “certeza” de que a saída “Serei impresso?” sempre irá ser exposta em seu terminal. Mas nem sempre é assim: e se o arquivo imaginário sumir? Nosso ingênuo programador irá enfrentar problemas pois a execução do seu programa terminaria em algum ponto após esta impressão.

Talvez nosso programador pudesse escrever o código acima de uma forma diferente tal como no exemplo a seguir:

char buffer[128];
int resultadoLeitura = read(arquivo, buffer, 128);
if (resultadoLeitura < 0) {
     // tento corrigir a situação aqui
}

É uma alternativa, o código se tornou mais robusto, mas sua leitura não torna claro o que de fato ocorreu para termos um erro. O arquivo foi apagado? Seria um problema de permissão? Ainda pior: o código que motivou a escrita do programa, o fluxo principal (em condições ideais de temperatura e pressão) agora se encontra mesclado ao código de tratamento de erros.

Java veio com uma solução mais interessante. Visto que nossas classes são uma interface, por que não alertar seus clientes a respeito do que pode dar errado e, ainda melhor: força-los a tratar estas situações (o problema está neste “força-los”)?

Pensando como Gosling, Joy e Steele

java_language_spec

Clareza na escrita

Por mais incrível que possa parecer a diversos críticos atuais da linguagem, naquela época um dos objetivos era ter código menos verboso. O ideal é que o programador pudesse ver o fluxo principal do seu programa de uma forma simples, e o tratamento dos erros isoladamente, tal como no exemplo a seguir:

String conteudoArquivo(File arquivo) {
          try {
                // meu fluxo principal entra aqui
          } catch (FileNotFoundException ex) {
               // o que eu faço se o arquivo não existir?
         } catch (EOFException ex) {
              // e se o arquivo chegar ao fim antes do imaginado?
         } catch (IOException ex) {
              // e se for algum outro erro de I/O que não previ e
             // não seja como os que mostrei antes?
        }
}

É interessante como agora você sabe o quê pode ter dado errado, e consegue diferenciar de forma clara como tratar cada uma daquelas situações. Ainda melhor: o que realmente importa, o fluxo principal, está claramente isolado.

Uma exception é na realidade um desvio de fluxo. Talvez você lide com erros do tipo FileNotFound e IOException da mesma forma. Neste caso, como a primeira exception é uma subclasse da segunda, basta colocar um único bloco catch para esta.

Exceptions como contrato

 

Mais do que isto, acredito que muitos programadores simplesmente não saibam interpretar o código que encontram: imagine uma declaração de método como a abaixo:

void processeArquivos(File[] arquivos) throws FileNotFoundException

O método me diz:

“Recebo uma lista de arquivos em uma matriz como parâmetro. Conseguirei executar meu trabalho quando todos os arquivos forem acessíveis a mim. Se me passar algum deles que não seja, repasso a você, que me chamou, a responsabilidade de lidar com este problema para mim.”

O método, é um contrato, e a exception, uma validação de que o mesmo será cumprido. Se não for o caso, o fluxo deverá ser alterado para que o seja ou a responsabilidade para se resolver o problema, repassada a outro objeto (talvez o cliente do cliente).

Mais do que isto: um contrato válido é aquele bem definido. Fica fácil perceber quando quem escreveu o código não tem muita ideia a respeito do que está fazendo. Observe a declaração de método abaixo:

void processeArquivos(File[] arquivos) throws Throwable

O que este método me diz?

“Recebo uma lista de arquivos para serem processados, alguma coisa pode dar errado, mas não sei o que.”

Temos um meio contrato aqui: apenas sabemos que devemos enviar arquivos para este método. Não sei se todos devem realmente estar acessíveis, apenas os envio.

Exceptions checadas e não checadas. Pra quê?

Por que há as tais “checked exceptions” e “unchecked exceptions”? O que diferencia uma de outra? Uma interpretação rápida seria:

“Checked exception é aquela que é uma subclasse de java.lang.Exception e que, se eu disparar no corpo do meu método, tenho de incluir uma clausula throws. A outra não, eu apenas a disparo lá dentro e não aviso ninguém a respeito pois é uma subclasse de RuntimeException ou Error.”

O que não responde quase nada além de expor uma hierarquia de classes incompleta. A resposta é mais simples: há erros que são tratáveis e outros nem tanto. Erros tratáveis são aqueles que definem um contrato e os clientes conseguem ao menos tentar resolve-los quando ocorrem.

Por exemplo: um arquivo inacessível é um erro tratável. Se topei com um erro do tipo FileNotFound, talvez seja possível criar um novo arquivo para em seguida chamar aquela função ou procedimento novamente.

Por outro lado, se houver um crash do meu sistema operacional ou meu sistema de arquivos desaparecer, não há muito o que eu possa fazer. É um erro de tempo de execução (runtime). E a quantidade de problemas deste tipo que podem ocorrer é praticamente infinita: seu HD pode pegar fogo, ou seu HD pode ser removido, ou seu sistema operacional pode desaparecer, ou sua rede pode se tornar inacessível, ou alguém pode desligar o servidor, ou….

Por que as exceções do tipo Runtime não são “checked”? Vou pedir para Gosling, Joy e Steele uma força. Veja o que é dito na seção 11.2.2 da especificação:

“A informação disponível para o compilador Java, e o nível de análise que este executa, raramente são  suficientes para se descobrir que erros de tempo de execução poderão ocorrer, mesmo sendo óbvio para o programador. Obrigar o programador a declarar todas estas exceções seria apenas uma tarefa irritante para o desenvolvedor.” (tradução minha)

É interessante também ver o que os autores dizem na especificação ao nos dizerem por que a outra categoria de erros (java.lang.Error) não são checados (11.2.1):

“São problemas que podem ocorrer em inúmeros pontos de um programa e cuja solução é difícil ou impossível. Um programa escrito em Java que precisasse lidar com todos estes erros seria uma zona e sem sentido algum” (tradução minha)

Sendo assim, ao invés de obrigar o desenvolvedor a tratar cada um destes problemas, por que não força-lo a lidar apenas com o que pode ser tratado? Este é um dos principais motivadores: te forçar a escrever menos código e, quem sabe, escrever código de melhor qualidade.

Isto não quer dizer que você deva escrever código como o a seguir:

try {
    // aqui está meu fluxo principal
} catch (Throwable t) {
    // aqui lidarei com todos os problemas possíveis e impossíveis
    // dos multiversos
}

Quando escrevemos algo como “catch (Throwable)” estamos com uma das seguintes ideias na cabeça:

  • Vou ignorar qualquer tipo de erro que venha a ocorrer.
    (me faz lembrar do “on error resume next” do VB)
  • Todos os erros são iguais, sendo assim os tratarei todos da mesma forma.

Se um dos princípios norteadores da criação do Java foi a robustez, e estamos usando Java (ignore sua linguagem favorita por um momento), escrever código deste tipo é corromper a linguagem e se induzir ao erro.

Mais do que isto: checked exceptions permitem ao compilador verificar se você está lidando com as situações anômalas definidas no contrato das suas interfaces.

Como uso bem as exceções?

O principal motivador para a escrita deste post são as críticas que ouço a respeito do modo como a linguagem Java lida com exceções. É interessante como muitas pessoas se esquecem que o recurso foi incluído na linguagem para facilitar a vida do programador, e não complicá-la.

Curiosamente, a esmagadora maioria das críticas que vejo são motivadas pelo mal uso ou compreensão do recurso. Sendo assim, seguem algumas dicas:

  • Pense na declaração de exceções como a definição de um contrato bem definido: elas definem premissas, ou seja, aquilo que não deve ocorrer para que o código possa ser executado com sucesso.
  • Tire proveito da precisão: um “catch (Throwable)” não te possibilita lidar com as diferentes situações ou quebras de contrato que podem ocorrer durante a execução do sistema, você estará apenas criando um bloco catch que, no futuro, pode se tornar um verdadeiro monstrinho.
  • Entenda a diferença entre checked e unchecked exceptions.
  • Uma declaração de método que contém uma instrução throws seguida de 293847 tipos de exceção e algo como um “throws Throwable” são a mesma coisa.
  • Se checked exceptions são um problema para você, considere linguagens como Groovy que torna o tratar de exceções uma tarefa opcional

Espero com este texto ter clarificado alguns pontos a respeito de um dos aspectos mais interessantes da linguagem Java.