sexta-feira, 2 de setembro de 2011

Epidemia

Eu vasculho os logs do meu sistema e encontro ocorrências sempre em grupos de duas ou três. De quando em vez, são quatro ou cinco. Minha primeira conclusão é que as pessoas estão premindo os botões duas vezes, mas os intervalos de tempo são relativativamente grandes entre os registros repetidos (trinta segundos ou dois minutos).

Pode ser uma epidemia de transtorno obsessivo-compulsivo. Aparentemente, o transtorno está relacionado a um QI mais alto e, curiosamente, nosso país tem uma incidência alta. Infelizmente, os argentinos têm mais ainda. Talvez seja sobre esse tipo de coisa que Gödel quebrava a cabeça: ter muito TOC é bom ou ruim? Definitivamente, não consigo decidir.

Além disso, não há nada para fazer. Se meus usuários estivessem abusando do duplo-clique (já vi quem fizesse um quádruplo clique), eu poderia desabilitar o botão depois do primeiro clique. Talvez eu possa adicionar um contador à página: você já fez isso 9 vezes. Mas não quero que fiquem, ademais, paranoicos.

Por enquanto, vou lavar as mãos.

quinta-feira, 25 de agosto de 2011

Métodos frágeis

Uma das práticas mais desastrosas que eu já vi é a de nomear artefatos com os códigos dos casos de uso. A motivação é boa (relacionar os casos de uso ao código que os implementa), mas, como geralmente acontece quando os primeiros princípios são levados adiante por muito tempo antes de se dar uma espiadinha na realidade, o resultado é terrível.

Por exemplo, há quem dê aos JSPs de um projeto Java nomes como "UC123.jsp". Já vi até classes com esse tipo de nome.

Em primeiro lugar, poucos artefatos relacionam-se a apenas um caso de uso. O que o programador vai fazer para resolver isso? Não podemos chamar um JSP de "UC123,127,201.jsp". Em segundo lugar, fica muito difícil ler e encontrar o código que queremos em projetos grandes.

Em terceiro lugar (e este é o motivo mais importante), essas tentativas de burocratizar o código alienam todos os programadores que amam seu trabalho e que preocupam-se com a qualidade do que escrevem. Código bom tem qualidades estéticas para quem sabe apreciá-lo e esse tipo de nome obscurece qualquer tentativa de prover elegância a uma arquitetura.

quarta-feira, 17 de agosto de 2011

Ramais rebeldes

Descobrir o ramal de uma pessoa é muito fácil. A intranet os tem todos. Mas algumas pessoas mais antigas (mesmo que de espírito) gostam do velho hábito de usar a telefonista. Como elas não existem mais, alguém vai cumprir o papel, mesmo que involuntariamente!

Então, em nome da paz no ambiente de trabalho, uma técnica pavloviana e pacífica deve ser usada para treinar os preguiçosos chamadores.

A técnica é simples e consiste em, inicialmente, fazer o chamador pensar que a chamada será redirecionada para o alvo pretendido. O treinador deve dizer que "vou passar a ligação para o ramal XYZ", mas deve colocar ênfase e repetir o número com "se a ligação cair, o ramal é XYZ". Então, aperta-se o botão para transferir e coloca-se o telefone no gancho, para que a ligação caia.

Se o chamador insistir, basta repetir a operação. É garantido o resultado em, no máximo, três chamadas (exceto para alguns casos extremos, geralmente restritos a peixes dourados).

sexta-feira, 12 de agosto de 2011

Força superior

O usuário aproximou-se com um ar otimista e afirmou que "precisamos disponibilizar este software na intranet". A prática me levou a temer esses arroubos dos usuários. Fiz uma cara amigável e perguntei se o programa era para desktop ou para web.

Era desktop, claro. Mas isso é ruim? O diretor autorizou a publicação do sistema na intranet. Já está tudo aprovado.

Ah bom! Se o diretor aprovou a publicação na intranet, então não temos nada a temer. Vou retornar o workflow com um pedido de esclarecimentos.


segunda-feira, 25 de julho de 2011

Jangada de pasto

Numa bela manhã, um vivente levantou-se ao inusitado som do mar. Sim, porque ele havia ido dormir com a certeza inabalável de que, assim como o havia sido por toda sua vida, acordaria com o silêncio do campo. Achou que seria brincadeira do piá e pôs-se de pé já de mau humor. Esquentou água, preparou a cuia e foi olhar o sol nascer sobre o Alegrete.


Os butiás saltaram um a um dos bolsos do gaudério! Ao abrir a porta, avistou a praia de Mostardas e o Rio Grande a afastar-se. Desta vez, o piá fora longe demais!


Algumas semanas depois, mesmo sob os protestos do prefeito e das ligações constantes ao Palácio do Piratini e ao Palácio da Alvorada, o Alegrete continuava à deriva. Embretado entre a França e a Inglaterra, todos acharam que nunca mais veriam o céu celeste sobre o campo.


Mas, como o leitor já deve ter percebido, essa história não está limitada pela realidade física. Nos dias que se seguiram, o Alegrete  despertou-se nos lugares menos esperados.


Os pobres paisanos tiveram que suportar frio, calor, secura e umidade. Ou seja, um dia normal no Rio Grande do Sul.


O código dessa brincadeira é simples, como se pode ver abaixo. Entretanto, as coordenadas ocupam muito espaço. Então, se alguém quiser replicar o experimento com seu próprio município, basta pedi-las!

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
  html { height: 100% }
  body { height: 100%; margin: 0px; padding: 0px }
  div { float: left }
</style>
<script type="text/javascript"
    src="http://maps.google.com/maps/api/js?sensor=true">
</script>
<script type="text/javascript">
  var coordenadas=[...];

  function getCoords() {
    var coords=new Array();
    var bounds = new google.maps.LatLngBounds();
    for(var i=0; i<coordenadas.length; i+=2) {
      var c=new google.maps.LatLng(-coordenadas[i+1],-coordenadas[i]);
      coords.push(c);
      bounds.extend(c);
    }
    coords.bounds=bounds;
    coords.center=bounds.getCenter();
    return coords;
  }
  
  var lat=-29.7640;
  var lng=-55.8861;
      
  function init() {
    var map = new google.maps.Map(document.getElementById("map"),  { 
      zoom: 6, 
      center: new google.maps.LatLng(lat, lng),
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    
    var alegrete = new google.maps.Polygon({paths: getCoords(), 
      strokeColor: '#000000', strokeWeight: 1, strokeOpacity: 1, 
      fillColor: '#00AA00', fillOpacity: 0.4,  clickable: false });
    alegrete.setMap(map);
    
    google.maps.event.addListener(map, 'center_changed', function() {
      var point=map.getCenter();
      alegrete.setMap(null);
      var path=alegrete.getPath();
      path.forEach(function(p,i) {
        path.setAt(i, new google.maps.LatLng(p.lat()-(lat-point.lat()), 
                                             p.lng()-(lng-point.lng())));
      });
      lat=point.lat();
      lng=point.lng();
      alegrete.setPath(path);
      alegrete.setMap(map);
    });
  }

</script>
</head>
<body onload="init()">
  <div id="map" style="width:400px; height:400px"></div>
</body>
</html>
A navegação é a original do Google Maps. A cada mudança de centro do mapa (indicada pelo evento center_changed), o código corrige as coordenadas do Alegrete. Pode-se notar claramente que a forma distorce-se nas aproximações aos polos; é defeito da projeção.

quinta-feira, 7 de julho de 2011

Segundas intenções

Um amigo, passeando por Portugal, achou-se perdido e resolveu pedir ajuda a um paisano. Com a obtusidade típica dos brasileiros, disse "Eu queria ir a Braga". Luso-descendentes, como eu, logo compreendem o erro do pobre tupiniquim e não têm muita dificuldade para imaginar a resposta: "Pois vá".

Essa forma direta de dialogar dos portugueses gera uma infinitude de piadas no Brasil, muitas das quais são baseadas em fatos. Creio que seja uma injustiça e que engraçados sejamos nós, os brasileiros. Nossa forma indireta de perguntar e responder gera muitas confusões. Já que as pessoas perguntam por segunda intenção, os interrogados passam a interpretar os questionamentos e daí só podem surgir dificuldades.

Há pouco tempo, pedi a um pintor que pintasse uma parede em azul até 123cm e em azul celeste dali até o teto. A ordem não podia ser mais clara. No entanto, ele deu-se ao trabalho de interpretar a minha ordem, já que sabia que eu queria colocar uma faixa ornamentada com bichinhos para meu filho. Ele colocou a faixa com a base em 123cm, quando a metade dela deveria estar nessa altura. Se o pintor fosse português, tenho certeza que minha ordem, mais que clara, não seria (mal) interpretada.

Noutro incidente recente, atendi uma ligação para uma colega. A pessoa que chamou disse "Fulano, a Beltrana...". Fiquei suspenso por uns segundos esperando um verbo. A Beltrana morreu? A Beltrana esqueceu de vir para a reunião? A Beltrana está? A Beltrana pediu para avisar que vai chegar tarde? A Beltrana pediu alguma coisa? Enquanto o analisador sintático esperava pelo complemento, o subsistema de previsão de intenções lançou um aviso: essa criatura provavelmente quer falar com a Beltrana. Encaminhei a ligação e torci pelo melhor.

Imagino o horror se os programadores brasileiros levassem essa filosofia para seu código. Por exemplo, um método para indicar se há fundos necessários para efetuar uma retirada poderia ser escrito da seguinte forma:


public Status podeRetirar(double valor) throws FundosInsuficientesException {
  if(saldo-valor<0) {
    throw new FundosInsuficientesException();
  }
  return getStatus();
}

Ou seja, o método, se houver fundos, retorna o status da conta (encerrada ou bloqueada, por exemplo), mas se não houver fundos, lança uma exceção para indicá-lo. Não dá para complicar mais uma coisa tão simples.

Outro defeito grave da comunicação tupiniquim é a falta de cortesia básica. É comum caminhar pela rua e ser surpreendido com um "Que horas são?" ou "Onde fica a rua da Ladeira?". Faltam "Bom dia", "Por favor" e "Com licença", cujos propósitos, antes de mais nada, são os de permitir ao cidadão mudar de contexto e preparar-se para iniciar um diálogo.

Se o TCP/IP tivesse sido projetado por um brasileiro, não haveria o handshake (SYN, SYN-ACK, ACK), mas surgiria a necessidade de uma mensagem HEIN, para quando o servidor não estiver preparado para iniciar uma conexão.

Os mal-entendidos cotidianos devem custar um bocado ao Brasil, então é de se espantar que os personagens principais das piadas ainda sejam o Manoel e o Joaquim.

sexta-feira, 1 de julho de 2011

Coundown Sort II

O Countdown Sort foi otimizado! Infelizmente, a melhoria custou um if adicional. Mesmo assim, como o algoritmo agora está quatro vezes mais rápido, acho que valeu a pena.

O algoritmo original percorria todo o array subtraindo 1 de cada elemento e anexando os que chegavam a 0 a um array ordenado. Evidentemente, não é preciso percorrer os elementos que já chegaram a 0, então resolvi tirá-los da jogada.


  public static short[] countdownSort(short in[]) {
    short[] order=new short[in.length];
    int index=0;
    short delta=0;
    int last=in.length-1;
    do {
      for(int i=last; i>=0; i--) {
        if(in[i]-delta==0) {
          order[index]=in[i];
          index++;
          if(i<last) {
            in[i]=in[last];
          }
          last--;
        }
      }
      delta++;
    } while(last>=0);
    return order;
  }

Agora, sempre que encontrar um 0, o algoritmo o troca pelo último elemento do array original e diminui em uma posição a abrangência da busca. Se justamente o último elemento é que chegou a 0, então basta subtrair 1 do índice que aponta para o fim do array (representado no código pela variável last).

Isso significa que o array original será destruído, mas, como o método retorna uma versão ordenada dos números, o problema não é grave.

Paira ainda no ar a dúvida sobre se algo realmente útil pode advir deste algoritmo.