Os três principais problemas da Concorrência

September 21st, 2011

Ultimamente se tornou inevitável desenvolver programas que funcionam de maneira concorrente, já que os processadores com multiplos cores já estão em todo lugar, até mesmo nos celulares. E ao mesmo tempo que é extremamente prazeroso ver o seu software muito mais rápido graças a concorrência, também se pode perder muitas noites de sono com os problemas causados por erros no desenvolvimento de software concorrente. Neste post eu pretendo falar de maneira breve dos três principais problemas que podem surgir quando se desenvolve software concorrente. São eles: Starvation, Deadlocks e Race Conditions.

Starvation

Starvation ocorre quando uma thread fica esperando uma resposta pra prosseguir e essa resposta nunca chega, logo, a thread permanece viva, ocupando recursos, mas não produzindo nada de útil para o software. Uma boa forma de tratar esse problema é sempre trabalhar com timeout e fluxo de exceção, para que caso a resposta não chegue em um determinado tempo seja seguido o fluxo de exceção e a thread possa finalizar o seu trabalho.

Deadlocks

Deadlock ocorre se duas ou mais threads ficam aguardando uma a outra para realizar alguma ação ou liberar algum recurso, por exemplo, a thread A ficar aguardando a thread B liberar algum recurso e B ficar aguardando A terminar alguma ação pra liberar esse recurso, logo, ambas vão permanecer eternamente esperando. Não existe uma solução simples pra resolver esse problema como o timeout para o problema de Starvation, mas se a aplicação não possuir locks explicitos e estados mutáveis então ela estará a salvo de deadlocks, então esse pode ser um bom caminho a se seguir.

Race Conditions

Race Condition ocorre se duas threads concorrem para usar o mesmo recurso ou dado. É um problema bem difícil de tratar pois o comportamento da aplicação se torna imprevisível e uma Race Condition pode ocorrer depois de meses do software em produção. Pra piorar, este problema não ocorre apenas quando duas threads tentam modificar o mesmo dado, ele pode correr quando uma thread tenta gravar um dado e a outra está tentando apenas ler este mesmo dado. Pra piorar ainda mais, existem casos aonde se o código não é otimizado com O JIT(Just In Time) Compiler a Race Condition não aparece, mas se o código é elegível ao JIT e é compilado então a Race Condition surge, basicamente porque a JVM passa a usar cache para acessar algumas variáveis e se outra thread muda o valor da variável, esse valor não é replicado para o cache. Neste caso citado a solução seria usar volatile e/ou synchronized.

Novamente não usar objetos mutáveis evitaria o problema de Race Conditions, por isso que imutabilidade tem sido um tema tão comentado ultimamente, e linguagens que pregam essa técnica tem ganhado cada vez mais força.

Para se aprofundar mais no assunto, inclusive com um código de exemplo que mostra uma Race Condition causada pelo JIT, recomendo a leitura do livro “Programming Concurrency on the JVM”.

Manifesto conta o uso abusivo de Checked Exceptions

November 20th, 2010

Resolvi escrever este post porque vejo que existe muita confusão, e talvez até mesmo desinformação da comunidade Java quando o assunto são exceções.

Pra esclarecer as dúvidas resolvi ir até uma das maiores fontes de informação sobre boas práticas do Java que existe, o livro Effective Java.

Pra começar, no item 40 do livro é dito “Use Checked Exceptions for recoverable conditions”. Infelizmente eu vejo que em muitos projetos por aí Checked Exceptions viraram padrão e todas as exceções do projeto são deste tipo. Isso é um ERRO que deixa o projeto chatissimo pra manter, porque com isso toda vez que você precisa chamar um método ou você tem que colocar ele dentro de um try/catch, ou senão tem que dar um throws na exceção. Da próxima vez que você precisar lançar uma exceção, por favor, pense por alguns momentos no seguinte: “O cara que pegar essa minha exceção vai poder fazer alguma coisa pra trata-lá?”. Se a sua reposta por NÃO, então você não deve usar uma Checked Exception.

Lidar com exceções em Java não é um assunto fácil, e no próprio livro o Joshua Bloch fala que não existe uma receita de bolo que resolva todos os casos. Mas de toda maneira, parece que um comodismo se instalou nos programadores Java, e ao invez de pensar no cenário, o que se tem feito é lançar uma Checked Exception e pronto, possivelmente incentivado por um pensamento do tipo “Se o cara quiser fazer alguma coisa ele faz, senão ele ignora, pelo menos eu fiz a minha parte”. No item 41 é dito “Avoid unnecessay use of checked exceptions”. É um desprazer trabalhar com uma API ou sistema cheio de checked exceptions.

Checked Exceptions são excelentes quando usadas na hora certa, pois dá poder pra você corrigir algo que deu errado, mas são péssimas se usadas na hora errada!

Eu poderia tentar explicar mais sobre exceções, mas definitivamente é melhor ler o Effective Java, e a Bani traduziu esse capítulo de exceçõe, e disponibilizou no blog dela no seguinte link: http://vanessas.sites.uol.com.br/java/ej6.html . Minha recomendação é: LEIAM! É de graça, é pouca coisa, e com certeza você se tornará um programador melhor depois de ler, e vai pensar melhor antes de sair lançando checked exceptions por aí.

A linguagem certa para cada problema! (Problema do Sudoku)

September 12th, 2010

Cada vez mais na área de programação aquela história de se especializar em uma linguagem, e resolver todos os problemas com ela está sendo questionada. E realmente, como vocês verão neste post, esse questionamento faz todo sentido. Existe uma linguagem mais adequada para resolver cada problema, e por isso, é obrigação do programador conhecer diversas linguagens, no mínimo uma de cada paradigma, para poder escolher qual linguagem se encaixa melhor para determinado problema.

Considere o problema de implementar um resolvedor de Sudoku, ou seja, você deve implementar um programa que dado um tabuleiro do jogo parcialmente preenchido, seu programa deve devolver o tabuleiro totalmente preenchido.

Não sei se é a melhor que existe, mas a melhor linguagem que eu conheço pra resolver este problema é Prolog. Sim, aquela linguagem de programação que a gente vê na faculdade no curso de Inteligência Artificial. Prolog é uma linguagem de programação declarativa, baseada em lógica de primeira ordem. Em Prolog temos:

    -Fatos: Uma afirmação básica. (Ex: Azalão é um cavalo; cavalo gosta de grama.)

    -Regras: É uma inferência sobre um fato. (Ex: Um animal gosta de grama se ela é um cavalo.)

    -Query: Uma questão (Ex: Azalão gosta de grama?)

E é isso, ou seja, bem diferente de uma linguagem de programação imperativa, como Java por exemplo.

Agora vamos definir as regras para verificar se um jogo de Sudoku é valido, e embaixo de cada regra vamos definir o código em Prolog para implementar tal regra. São elas:

Supondo que nosso problema é definido como:

sudoku(Entrada, Solucao)

Regra 1) Para um jogo resolvido, os números na entrada e na saída devem ser os mesmos.

sudoku(Entrada, Solucao) :- Solucao = Entrada.

Regra 2) Um tabuleiro de Sudoku é uma grade de 81 elementos, com valores de 1-9.

Entrada = [S11, S12, S13, S14, S15, S16, S17, S18, S19,
		  S21, S22, S23, S24, S25, S26, S27, S28, S29,
		  S31, S32, S33, S34, S35, S36, S37, S38, S39,
		  S41, S42, S43, S44, S45, S46, S47, S48, S49,
		  S51, S52, S53, S54, S55, S56, S57, S58, S59,
		  S61, S62, S63, S64, S65, S66, S67, S68, S69,
		  S71, S72, S73, S74, S75, S76, S77, S78, S79,
		  S81, S82, S83, S84, S85, S86, S87, S88, S89,
		  S91, S92, S93, S94, S95, S96, S97, S98, S99],
	fd_domain(Solucao, 1, 9).

Regra 3) Um tabuleiro tem 9 linhas, 9 colunas e 9 quadrados.

Row1 = [S11, S12, S13, S14, S15, S16, S17, S18, S19],
Row2 = [S21, S22, S23, S24, S25, S26, S27, S28, S29],
Row3 = [S31, S32, S33, S34, S35, S36, S37, S38, S39],
Row4 = [S41, S42, S43, S44, S45, S46, S47, S48, S49],
Row5 = [S51, S52, S53, S54, S55, S56, S57, S58, S59],
Row6 = [S61, S62, S63, S64, S65, S66, S67, S68, S69],
Row7 = [S71, S72, S73, S74, S75, S76, S77, S78, S79],
Row8 = [S81, S82, S83, S84, S85, S86, S87, S88, S89],
Row9 = [S91, S92, S93, S94, S95, S96, S97, S98, S99],

Col1 = [S11, S21, S31, S41, S51, S61, S71, S81, S91],
Col2 = [S12, S22, S32, S42, S52, S62, S72, S82, S92],
Col3 = [S13, S23, S33, S43, S53, S63, S73, S83, S93],
Col4 = [S14, S24, S34, S44, S54, S64, S74, S84, S94],
Col5 = [S15, S25, S35, S45, S55, S65, S75, S85, S95],
Col6 = [S16, S26, S36, S46, S56, S66, S76, S86, S96],
Col7 = [S17, S27, S37, S47, S57, S67, S77, S87, S97],
Col8 = [S18, S28, S38, S48, S58, S68, S78, S88, S98],
Col9 = [S19, S29, S39, S49, S59, S69, S79, S89, S99],

Square1 = [S11, S12, S13, S21, S22, S23, S31, S32, S33],
Square2 = [S14, S15, S16, S24, S25, S26, S34, S35, S36],
Square3 = [S17, S18, S19, S27, S28, S29, S37, S38, S39],
Square4 = [S41, S42, S43, S51, S52, S53, S61, S62, S63],
Square5 = [S44, S45, S46, S54, S55, S56, S64, S65, S66],
Square6 = [S47, S48, S49, S57, S58, S59, S67, S68, S69],
Square7 = [S71, S72, S73, S81, S82, S83, S91, S92, S93],
Square8 = [S74, S75, S76, S84, S85, S86, S94, S95, S96],
Square9 = [S77, S78, S79, S87, S88, S89, S97, S98, S99].

Regra 4) Não pode haver números repetidos nas linhas, colunas e quadrados.

valid([]).
valid([Head | Tail]) :-
	fd_all_different(Head), valid(Tail).

valid([Row1, Row2, Row3, Row4, Row5, Row6, Row7, Row8, Row9,
     Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9,
     Square1, Square2, Square3, Square4, Square5, Square6, Square7, Square8, Square9]).

E pronto, acredite ou não, o problema está resolvido. Como vocês viram, a única coisa que fizemos foi definir as regras do problema e pronto, o Prolog resolve o problema pra você. Agora pense como você resolveria esse problema em Java por exemplo. Com certeza definir as regras acima seria apenas o começo.

Mas muitos devem estar se perguntando: “Tá, mas meu programa é feito em Java, o que eu vou fazer com esse código em Prolog?”. Mas é aí que entra o principal ponto, é possível integrar código em Prolog com diversas outras linguagems, por isso que hoje em dia não é mais preciso resolver todos os problemas de um sistema com a mesma linguagem.

E aí, animou a conhecer mais Prolog?

Segue abaixo o código completo do problema. Para rodar essa implementação é necessário o gprolog, já que usamos algumas funções pré-definidas existentes apenas nesta ferramenta.

valid([]).
valid([Head | Tail]) :-
	fd_all_different(Head), valid(Tail).

sodoku(Puzzle, Solution) :-
	Solution = Puzzle,
	Puzzle = [S11, S12, S13, S14, S15, S16, S17, S18, S19,
		  S21, S22, S23, S24, S25, S26, S27, S28, S29,
		  S31, S32, S33, S34, S35, S36, S37, S38, S39,
		  S41, S42, S43, S44, S45, S46, S47, S48, S49,
		  S51, S52, S53, S54, S55, S56, S57, S58, S59,
		  S61, S62, S63, S64, S65, S66, S67, S68, S69,
		  S71, S72, S73, S74, S75, S76, S77, S78, S79,
		  S81, S82, S83, S84, S85, S86, S87, S88, S89,
		  S91, S92, S93, S94, S95, S96, S97, S98, S99],
	fd_domain(Solution, 1, 9),

	Row1 = [S11, S12, S13, S14, S15, S16, S17, S18, S19],
	Row2 = [S21, S22, S23, S24, S25, S26, S27, S28, S29],
	Row3 = [S31, S32, S33, S34, S35, S36, S37, S38, S39],
	Row4 = [S41, S42, S43, S44, S45, S46, S47, S48, S49],
	Row5 = [S51, S52, S53, S54, S55, S56, S57, S58, S59],
	Row6 = [S61, S62, S63, S64, S65, S66, S67, S68, S69],
	Row7 = [S71, S72, S73, S74, S75, S76, S77, S78, S79],
	Row8 = [S81, S82, S83, S84, S85, S86, S87, S88, S89],
	Row9 = [S91, S92, S93, S94, S95, S96, S97, S98, S99],

	Col1 = [S11, S21, S31, S41, S51, S61, S71, S81, S91],
	Col2 = [S12, S22, S32, S42, S52, S62, S72, S82, S92],
	Col3 = [S13, S23, S33, S43, S53, S63, S73, S83, S93],
	Col4 = [S14, S24, S34, S44, S54, S64, S74, S84, S94],
	Col5 = [S15, S25, S35, S45, S55, S65, S75, S85, S95],
	Col6 = [S16, S26, S36, S46, S56, S66, S76, S86, S96],
	Col7 = [S17, S27, S37, S47, S57, S67, S77, S87, S97],
	Col8 = [S18, S28, S38, S48, S58, S68, S78, S88, S98],
	Col9 = [S19, S29, S39, S49, S59, S69, S79, S89, S99],

	Square1 = [S11, S12, S13, S21, S22, S23, S31, S32, S33],
	Square2 = [S14, S15, S16, S24, S25, S26, S34, S35, S36],
	Square3 = [S17, S18, S19, S27, S28, S29, S37, S38, S39],
	Square4 = [S41, S42, S43, S51, S52, S53, S61, S62, S63],
	Square5 = [S44, S45, S46, S54, S55, S56, S64, S65, S66],
	Square6 = [S47, S48, S49, S57, S58, S59, S67, S68, S69],
	Square7 = [S71, S72, S73, S81, S82, S83, S91, S92, S93],
	Square8 = [S74, S75, S76, S84, S85, S86, S94, S95, S96],
	Square9 = [S77, S78, S79, S87, S88, S89, S97, S98, S99],

	valid([Row1, Row2, Row3, Row4, Row5, Row6, Row7, Row8, Row9,
	       Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9,
	       Square1, Square2, Square3, Square4, Square5, Square6, Square7, Square8, Square9]).

Segue um exemplo de entrada:

sodoku([9,4,_,1,_,2,_,5,8,
 6,_,_,_,5,_,_,_,4,
 _,_,2,4,_,3,1,_,_,
 _,2,_,_,_,_,_,6,_,
 5,_,8,_,2,_,4,_,1,
 _,6,_,_,_,_,_,8,_,
 _,_,1,6,_,8,7,_,_,
 7,_,_,_,4,_,_,_,3,
 4,3,_,5,_,9,_,1,2], Solution).

Abraços e até a próxima!

O que esperar das linguagens de programação para o futuro?

July 24th, 2010

Dizem que os melhores perfumes são aqueles que estão nos menores frascos. Ao menos pelo show que o Rod Pike do Google deu quando falou no OSCON 2010, parece que isso vale para palestras também. Foram doze minutos e meio de um conteúdo riquissímo pra fazer qualquer programador refletir.

Nesta palestra, o Rod tentou mostrar como as principais linguagens que dominam o mercado hoje são burocráticas e chatas de trabalhar. Ele deixa claro que são linguagens robustas e de qualidade, isso é um fato inquestionável, mas elas podiam ser mais amigáveis.

O Rod usou a conhecida do frase do Norvig que diz “patterns are a a demonstration of weakness in a language” para embassar seus argumentos, e também não deixou de mostrar muitos códigos para comprovar o quão verboso é fazer algumas coisas em linguagens como o Java por exemplo. Além disso, também foi falado que o hardware evoluiu muito esses últimos anos, hoje em dia qualquer um tem um computador com dois cores no mínimo, mas nas linguagens de programação tradicionais por assim dizer, não é nada trivial fazer uso deste poder.

Após mostrar todos esses pontos, o Rod expõe quais são os objetivos das linguagens de programação para o futuro. Ou seja, o que precisa ser feito para que elas se tornem melhores, e no final, puxa um pouquinho a sardinha pro lado dele, falando um pouco da Go, a linguagem de programação do Google.

Um fato importante é que para conseguir ver tudo isso que o Rod viu e falou, é preciso pensar fora da caixa como dizem por aí, e aprender novas linguagens de programação. Eu atualmente tenho dado uma olhada mais profunda em duas: Python e Haskell, e não estou me arrependendo. O pessoal pode falar: “Mas aonde você vai usar Haskell profissionalmente?”. Bom, talvez eu nunca use Haskell profissionalmente, mas com certeza seja qual for a linguagem que eu trabalhar, aprender Haskell e programação funcional me tornará um programador melhor.

Enfim, para quem ainda não viu, não deixe de ver essa palestra. E viva a internet, aonde você consegue ter acesso a uma palestra de um evento de fora do país quase que no mesmo dia em que a palestra foi dada.

Participação no Y! Hack Day 2010

March 22nd, 2010

Esse fim de semana eu participei do Yahoo Hack Day Brasil. Foi definitivamente o melhor evento de computação que eu já fui, perfeito, e o melhor de tudo, foi de graça. O objetivo do evento foi construir uma aplicação qualquer usando as APIs que o Yahoo disponibiliza, excelentes APIs, diga-se de passagem.

Eu formei um time com dois amigos do UOL(Rafael e Wandi) e um amigo feito no Rails Summit(Marcos Sousa).

Falando um pouco do nosso projeto, ele consistiu de um site no qual o usuário informava um endereço da cidade de São Paulo, e a partir disso o site retornava dados sobre a criminalidade na região daquele endereço. Pra chegar nisso, a gente fez o seguinte:

1) Recuperamos todos os endereços de delegacias da cidade de São Paulo e pra cada um obtivemos a latitude e a longitude usando a API do Yahoo Maps. Depois salvamos na nossa aplicação essas informações.

2) Dado o endereço do usuário nós usamos a API do Yahoo Maps para obter a latitude e longitude do endereço.

3) Calculamos qual a delegacia mais próxima do endereço informado usando os dados da latitude e longitude que tinhamos na mão.

4) Depois de encontrada a delegacia mais próxima nós vamos em um site de dados da secretaria de segurança da cidade de São Paulo, e usamos a fantástica API YQL para obter os dados daquela delegacia. Os dados no site da secretaria de segurança ficam expostos em uma tabela HTML, então o YQL ajuda muito para filtrar estes dados.

5) Com os dados na mão é só exibir para o usuário o indice de criminalidade naquela região.

Bom, quem quiser conferir o endereço do nosso projeto é:

http://violenciasp.appspot.com

O layout tem algumas falhas, principalmente em browsers no Windows, mas não se esqueçam que é um projeto feito em 24hs. hehehe Quem sabe no futuro a gente de um tapa e melhore o site.

Infelizmente o nosso hack não nos rendeu nenhum prêmio, mas com certeza o aprendizado que o evento proporcionou valeu muito! E pra quem não conhece, eu recomendo muito dar uma olhada nas APIs do Yahoo, especialmente nesse tal de YQL que é show de bola!

Até a próxima!

Simulador de algoritmos de geometria computacional escrito em Python

January 17th, 2010

No semestre passado eu tive a oportunidade de fazer um projeto muito bacana no mestrado. Eu cursei uma matéria chamada Geometria computacional, que como o próprio nome diz, estuda algoritmos clássicos para resolver problemas geométricos. Como projeto final, tivemos que criar um “simulador visual” de um dos problemas geométricos que estudamos. A idéia era implementar o algoritmo força-bruta que resolve o problema e um algoritmo assintoticamente mais rápido, tudo isso de uma forma que o usuário pudesse ver o que o algoritmo está fazendo a cada instante.

Eu e mais um colega de classe resolvemos implementar os algoritmos que resolvem o problema de localizar intersecção de segmentos no plano, ou seja, dado um conjunto de n retas no plano localizar quais delas se intersectam. O Alexis, um ex-aluno do ime-usp, desenvolveu no ano que ele fez essa matéria toda uma interface gráfica bem modular para esse tipo de projeto feita em Python. Como Python é uma linguagem muito massa e seria bem mais simples usar essa interface que ele desenvolveu do que criar uma nossa do zero, resolvemos usar ela para o nosso projeto.

Implementamos um algoritmo conhecido como Shamos & Hoey(SH) que encontra a primeira interseção em um conjunto de n segmentos de reta. Esse algoritmo possui complexidade O(nlgn), e para atingir essa complexidade ele requer uma estrutura de dados que busca um elemento em um conjunto de n elementos em tempo O(lgn). Sendo assim, resolvemos implementar o algoritmo com três sabores: Com Árvore de Busca Binária Balanceada, Árvore de Busca Binária Sem Balanceamento e Skip List. A idéia resumida do algoritmo é analisar todas as retas, mas ao invés de testar a intersecção de cada uma com todas as outras, ele testa apenas a reta logo acima e a logo abaixo da que está sendo analisada, pois obviamente, se estas duas não intersectam a reta, nenhuma outra intersecta, dada uma linha de varredura sobre o eixo x. Além disso, implementamos a versão Força-Bruta que consome tempo O(nˆ2), já que pra cada reta analisada, ele verifica a intersecção com todas as outras.

Segue abaixo alguns screenshots com o resultado final:

Tela inicial

Após execução do algoritmo

No exemplo mostrado, como a árvore de busca não crescia muito, o tempo entre a execução com árvore balanceada e não balanceada foram equivalentes, mas em casos onde a árvore cresce(existem exemplos deste no código) é bem bacana ver a diferença que dá usar uma árvore balanceada. A diferença entre o algoritmo de SH e o Força-Bruta então é gritante. Um programa como esse é legal para abrir os olhos daqueles que não dão valor para Analise de Algoritmos. Se você não acredita o quanto um algoritmo O(nlgn) é melhor que um O(nˆ2), agora você pode ver e comprovar. =)

Coloquei o código no GitHub para caso alguém se interesse por olhar e/ou rodar o programa. Está em http://github.com/luizhespanha/geometry-algorithms-simulation

Repositório de códigos de campeonatos de programação

December 4th, 2009

Como muitos que me conhecem sabem, eu sou um grande fã de campeonatos de programação. Na época da graduação eu participei por 2 anos consecutivos da Maratona de Programação, e hoje em dia, mesmo não podendo mais participar, ainda me divirto resolvendo problemas em sites como: TopCoder, br.spoj.pl e uva.

No próximo ano eu pretendo participar do Google Code Jam pra valer, pra conseguir um resultado honroso. E pra isso, eu estipulei uma meta de resolver um problema por dia útil da semana, ou seja, aproximadamente 20 problemas por mês.

A partir dessa idéia surgiu uma outra de disponibilizar o códigos desses problemas que eu resolver em um repositório. Dessa idéia surgiu o: http://github.com/luizhespanha/maratona-programacao.

A idéia de disponibilizar os códigos não é muito bem vista pela comunidade que gosta destes campeonatos, pois isso acaba tirando a graça do desafio de outras pessoas, porém, o Google Code JAM disponibiliza o código de todos os concorrentes, e eu achei muito bacana, porque mesmo tendo resolvido um problema, eu tive a oportunidade de ver os códigos do ACRush, e ver como ele programa, algo que com certeza vale a pena. Logo, cabe a quem se interessar avaliar se é interessante ou não olhar um código do repositório sem tentar resolver primeiro.

Espero que consiga manter minha meta. Para problemas mais elaborados também pretendo criar um post com algumas explicações.

Até a próxima!

Rumo ao JBoss World 2009, Chicago, USA

August 25th, 2009

Na próxima semana estarei pela primeira vez indo para os EUA participar do Jboss World. Como no projeto que eu estou atualmente aqui no UOL nós usamos 4 ferramentas da Jboss: JBoss AS, JBoss Drools, JBoss jBPM e Hibernate, a empresa acredita que é interessante a minha ida ao evento para estar acompanhando as últimas novidades do mundo JBoss.

Pretendo postar aqui as coisas bacanas que eu ver, e estarei em real-time twittando o que eu ver de legal por lá, então, se alguém tiver interesse e quiser me seguir, o meu twitter é luiz_hespanha.

Monitorando arquiteturas JMS

June 30th, 2009

Qualquer sistema sério precisa de monitoração, isso é um fato. Existem vários pontos para serem monitorados dentro de um sistema, o pessoal da Globo.com fez uma excelente apresentação sobre isso no FISL. Veja em: http://www.slideshare.net/denao/fisl-monitoracao-inteligente

No sistema que eu trabalho aqui na empresa, usamos muito JMS, então para nós, é imprecindível uma monitoração em cima dessa tecnologia.

Para quem não sabe, uma aplicação tenta enviar uma mensagem JMS um número configurado de vezes, caso a aplicação que recebe essa mensagem tenha problemas para receber a mensagem. Após o número X de vezes, a mensagem é enviada para uma DLQ, que traduzindo para o português é “fila-morta”. É este o ponto que estamos monitorando na nossa aplicação.

Criamos um método JMX que é chamado pelo Nagios de tempos em tempos, e que retorna OK se não existe nenhuma mensagem na DLQ, e NOK cc.

Caso retorne NOK, a minha equipe é avisada para que entre em ação e investigar o porquê da mensagem ter ido para a DLQ, e após isso, resgatar a mensagem da DLQ caso necessário.

O código para fazer isso é o seguinte:

public String validateMessagesSentToDLQ() {
   logger.info("+++++ Validando se ha ou nao mensagens na DLQ +++++");
   ObjectName name = null;
   List<SpyMessage> listMessages = null;
   String ret = RETURN_NOK;

   try {
      name = new ObjectName("jboss.mq.destination:service=Queue,name=DLQ");
      listMessages = (List<SpyMessage>) getRmiAdaptor().invoke(name, "listMessages", null, null);
      logger.info("Quantidade de mensages na DLQ: " + listMessages.size());
      if (listMessages.size() == 0) {
         ret = RETURN_OK;
      }
   } catch (Exception e) {
      logger.error("Problemas ao verificar se há mensagens na DLQ!", e);
   }
   return ret;
}

Este código funciona no JBoss 4.0.4. Não sei dizer se funciona em outros servidores ou versões do JBoss, mas se não funcionar, não deve ser difícil adaptar ele.

Bom, tá aí a dica! Recomendo essa monitoração. Já nos ajudou bastante aqui no UOL!

Respeite seu cliente! Mantenha compatibilidade entre versões.

June 17th, 2009

Hoje tive uma surpresa extremamente desagradável. Temos um framework de uma empresa ˜conceituada” que é o responsável pelo core de um sistema crítico que temos aqui na empresa. A empresa responsável lançou recentemente uma nova versão deste framework que possui diversas coisas importantes que estavamos querendo a tempos. Então lá fui eu feliz e contente baixar a nova versão para colocar no projeto. Faço o download e vou ver o README.txt para ver como fazer a migração da versão antiga para a nova versão. Para a minha surpresa leio o seguinte:

“Esta versão é totalmente incompátivel com a versão antiga. Mudamos a API, mudamos as tabelas no banco de dados, ou seja, mudamos tudo. Ah, também não existe nenhuma ferramenta para ajudar na migração”

Ou seja, basicamente um “Dane-se você, se vira se quiser migrar”

Na minha opinião, isso é o cúmulo da falta de respeito com o seu cliente, que usa a sua ferramenta. Tá na hora das empresas entenderem que é uma obrigação manter a compatibilidade entre versões. Eu até entendo que existem mudanças que necessitam quebrar tudo, mas então, nesse caso, a empresa fornecedora deveria ter o dever de prover ferramentas e guias para orientar os clientes em migrações.

Estamos em uma situação delicadissima no projeto. Migrar versões em um projeto que é responsável pelo billing da empresa é sempre um drama. Nessa condições então, onde a empresa fornecedora lavou as mãos então.

Nesse aspecto, eu respeito bastante a Sun e a Oracle. Essas empresas sempre foram bem conservadoras em relação a compatibilidade, e com certeza, é por isso que elas são tão respeitadas e seus produtos atingiram sucesso. Um outro belo exemplo foi a migração de versões do WordPress, eu simplesmente apertei um botão e a ferramenta se atualizou sozinha.

Já essa empresa que faz esse framework que usamos no projeto sempre foi negligente em relação a mudanças de versões. Mesmo em mudanças de versões minors eles conseguem tornar suas ferramentas incompativeis entre versões! Mas enfim, paciência!

Meu objetivo nesse post é conscientizar os programadores a sempre atentarem para esse ponto. Em um momento que a integração entre sistemas, SOA, ganham força a cada dia, é importantíssimo mantermos compatibilidade quando atualizarmos nossos sistemas. Isso inspira confiança para o cliente do seu sistema/framework/API/serviço. É sempre preciso fazer o possivel e o impossível para isso. E no caso que realmente for imprescindível quebrar a compatibilidade, fazer tudo para ajudar o seu cliente e nunca ˜lavar as mãos˜.

Fica aqui meu desabafo!