Carlos Brando

Nome do Jogo

Contratos onde todos ganham

Lidar com computadores não é fácil, por outro lado lidar com pessoas costuma ser ainda mais complicado. A muito tempo eu já me convenci que o relacionamento entre clientes e programadores sempre serão problemáticos.

A forma mais simples de tentar diminuir a tensão entre os lados envolvidos são os contratos.

Um bom contrato deve deixar claro quais são os direitos e responsabilidades de cada um dos envolvidos. Também não deve deixar dúvidas sobre qual será a repercussão no caso de uma das partes não cumprir com o acordo.

Um tipo básico de contrato é o que define um preço fixo para o projeto. Esse tipo de contrato é a melhor opção para o cliente e a pior para o programador. Uma mudança no escopo ou um pequeno atraso e tudo vai para a conta do desenvolvedor, deixando todo o risco nas mãos do profissional. Normalmente esse é o tipo de contrato que mais dá problema, já que o programador costuma se sentir lesado por alterações no escopo do projeto e o cliente não se sente na obrigação de pagar mais por isso.

Por outro lado um contrato de tempo e recurso, onde o cliente paga pelo tempo de cada profissional alocado no projeto é o melhor contrato para o programador, mas é o pior para o cliente. Nesse caso, atrasos e alterações no escopo caem sempre na conta do cliente, mesmo quando a culpa não é dele.

Para beneficiar ambos os lados, talvez o mais interessante seja unir esses dois tipos de contratos em um contrato híbrido, onde o cliente e o programador definem um valor fixo menor e uma taxa por horas de trabalho.

Funciona mais ou menos assim: se você estimar que serão necessárias aproximadamente duas semanas (80 horas) para finalizar o projeto e normalmente você cobra R$ 100,00 por hora, então o custo estimado para o projeto seria de R$ 8.000. Nesse tipo de contrato você definiria então com o cliente um pagamento fixo no valor de R$ 4.000 e mais uma taxa de R$ 50,00 reais por hora trabalhada no projeto.

Se o projeto terminar dentro do prazo, o cliente terá pago exatamente o valor estimado para o projeto e todos ganham.

Se o projeto terminar antes da data, o cliente terá pago menos e você terá ganho mais. Digamos que o projeto seja finalizado com 60 horas trabalhadas. Então o cliente pagará R$ 7.000 pelo serviço, que é menos do que o esperado. E você receberá R$ 1.000 a mais do que você receberia pelas 60 horas trabalhadas. Mais uma vez, todos ganham.

Por outro lado, se algo acontecer e o projeto atrasar, então o cliente estará pagando adicionalmente metade da sua hora, dividindo assim igualmente o risco entre o cliente e o programador.

Não importa se você usa uma metodologia ágil ou um modelo mais tradicional, contratos são essenciais em qualquer negocio e não será diferente em desenvolvimento de software. O importante é que você nunca feche um negócio sem assinar um antes.

Como convencer sua equipe a usar um sistema de controle de versão

Desenvolver software sem um sistema de controle de versão (ou SCM do inglês source code management) pode parecer irreal para muitos dos leitores desse blog, mas é importante esclarecer que muitas empresas e profissionais ainda não entendem o valor desse tipo de ferramenta.

Nota para o leitor: Se você não sabe o que é um SCM, recomendo ouvir a série sobre o assunto que gravamos recentemente para o Grok Podcast.

A situação fica ainda mais dramática quando um programador “iniciante”, porém esclarecido, trabalha em uma empresa que ainda armazena o código-fonte de seus projetos em um diretório no servidor ou somente no computador do desenvolvedor. Nesse caso, como convencer seus colegas de trabalho e principalmente o seu chefe que eles precisam adotar uma ferramenta para controlar o código?

A palavra-chave aqui é evangelização. Comece implementando o seu próprio SCM particular. Existem dezenas de opções open-source que podem ser instaladas localmente em sua máquina ou em um servidor da empresa que você tenha acesso. Essa iniciativa fará com que ao menos o seu código tenha uma certa medida de segurança, o que lhe trará um pouco de tranquilidade.

Com o tempo você, diferente de seus colegas, passará a ter a resposta para perguntas como: “Exatamente que alteração foi realizada no módulo XYZ?” e “Quem foi o responsável pela alteração que quebrou o software?”. É questão de tempo até que seu chefe e colegas se convençam das vantagens em adotar um sistema para gerenciar o código da sua empresa.

Ainda outra opção é fazer com que sua equipe ouça o Grok Podcast.

Blogando como um hacker

Depois que me acostumei a somente falar e a escrever em sentenças de 140 caracteres, blogar tem se tornado cada vez mais raro. Mas esse blog ainda é a menina dos meus olhos e de forma alguma ficará abandonado.

Embora editar o audio do podcast dê um certo trabalho, falar é muito fácil. Da mesma forma, enviar uma mensagem pelo Twitter também já se tornou algo natural. Mas escrever um texto para o Nome do Jogo ainda exigia um certo ritual que não me agradava muito, que basicamente envolvia acessar a interface do Wordpress, escrever o post, editar os trechos de código no TextMate e exportar para HTML, editar as imagens, etc..

Acostumado com ferramentas ricas e ao mesmo tempo simplistas, eu já estava decidido a mudar a engine desse blog e abandonar o Wordpress. Porém durante muito tempo não consegui encontrar uma ferramenta que justificasse o esforço da migração.

Recentemente eu adquiri uma cópia do excelente aplicativo iA Writer que é um editor de textos muito simples, que não possui nenhuma configuração e permite escrever usando a sintaxe do Markdown. É engraçado, mas me livrar da preocupação com a formatação do texto reativou o meu prazer em escrever.

Outra ferramenta importante nessa equação é o Octopress, uma engine baseada no Jekyll para a publicação de blogs. A simplicidade do Octopress me permitiu migrar todo o conteúdo do Nome do Jogo (quase mil artigos) rapidamente. O maior trabalho que tive na migração foi ajustar alguns textos, mas como tudo é baseado em arquivos: Regex to the rescue!

O que você está vendo agora é o novo blog Nome do Jogo, totalmente baseado no Octopress e com o tema padrão da ferramenta. Acredito que isso vai tornar muito mais fácil publicar meus artigos e certamente vai aumentar a freqüência de publicação.

A Regra Direita-Esquerda do C

Atualmente estou envolvido em um projeto envolvendo módulos específicos em Ruby, Erlang e C. Ruby e Erlang são mais tranquilos, mas C tem a desagradável característica de deixar alguns códigos “meio” complicados de entender.

Porém, um colega da Plano Bê me enviou um artigo que me ajudou muito e quero compartilhá-lo com vocês. O artigo original parece ter sido escrito por Rick Ord da Universidade da California, em San Diego. Segue a tradução:

A Regra Direita-Esquerda do C

A regra direta-esquerda é muito útil para decifrar declarações na linguagem C e também pode ser de grande ajuda ao escrever código. A regra é bem simples, toda vez que encontrar os seguintes símbolos no código, leia:

*   como "um ponteiro para"      - sempre do lado esquerdo
[]  como "um array de"           - sempre do lado direito
()  como "uma função retornando" - sempre do lado direito

Passo 1

Encontre o identificador. Esse é o seu ponto de partida. Então, diga para si mesmo “o identificador é”. É nesse ponto que iniciamos a declaração.

Passo 2

Comece pelos símbolos a direita do identificador. Digamos que você encontrou um (), então você sabe que essa declaração é uma função. Então você deve dizer “o identificador é uma função retornando”. Caso você tenha encontrado um [], então você deve dizer “o identificador é um array de”. Continue avançando pela direita enquanto houver símbolos OU até encontrar um fecha parênteses ). (continue seguindo caso você encontre um abre parênteses, falaremos sobre isso mais abaixo.)

Passo 3

Quando terminarem os símbolos a direita do identificador, então comece a procurar por símbolos a sua esquerda. Se você encontrar algo diferente dos símbolos mencionados acima (digamos, algo como int), simplesmente repita o seu nome. Caso contrário, traduza o símbolo para o português usando a tabela. Continue seguindo pela esquerda enquanto houver símbolos OU até encontrar um abre parênteses (.

Então, repita os passos 2 e 3 até terminar toda a sua declaração. Veja abaixo alguns exemplos:

1
int *p[];
  1. Encontre o identificador.
1
2
3
int *p[];
     ^
"p é"
  1. Siga pela direita enquanto encontrar um símbolo ou abre parênteses.
1
2
3
int *p[];
      ^^
"p é um array de"
  1. Quando não puder mais mover para a direita (os símbolo acabaram), então siga para a esquerda e encontre:
1
2
3
int *p[];
    ^
"p é um array de ponteiros para"
  1. Continue seguinte pela esquerda e encontre:
1
2
3
4
int *p[];
^^^
"p é um array de ponteiros para int". 
(ou "p é um array onde cada elemento é um ponteiro para um inteiro")

Outro exemplo:

1
int *(*func())();
  1. Encontre o identificador.
1
2
3
int *(*func())();
       ^^^^
"func é"
  1. Vá para a direita.
1
2
3
int *(*func())();
           ^^
"func é uma função retornando"
  1. Não dá para ir mais a direita devido ao fecha parênteses, então vá para a esquerda.
1
2
3
int *(*func())();
      ^
"func é uma função retornando um ponteiro para"
  1. Não pode mais ir para a esquerda devido ao abre parênteses, então continue indo pela direita.
1
2
3
int *(*func())();
              ^^
"func é uma função retornando um ponteiro para uma função retornando"
  1. Não dá mais para ir para a direita porque não há mais simbolos, então vá para a esquerda.
1
2
3
int *(*func())();
    ^
"func é uma função retornando um ponteiro para uma função retornando um ponteiro para"
  1. E finalmente, o último símbolo a esquerda.
1
2
3
int *(*func())();
^^^
"func é uma função retornando um ponteiro para uma função retornando um ponteiro para um inteiro".

Como você pode ver, essa regra pode ser muito útil. Ela também é ótima para manter a sua sanidade enquanto estiver criando declarações, além de ajudá-lo a identificar onde colocar o próximo símbolo ou parênteses.

Algumas declarações podem parecer ainda mais complicadas quando definem o tamanho de um array ou informam uma lista de argumentos. Por exemplo, se você ver algo como [3], deve ler “um array (de tamanho 3) de…”. Mas se você ver algo como (char *,int), então deve ler “uma função esperando (char , int) e retornando…”*. Veja mais um exemplo:

1
int (*(*fun_one)(char *,double))[9][20];

Eu não vou seguir cada passo para decifrar essa declaração. Mas o resultado será: “fun_one é um ponteiro para uma função esperando (char , double) e retornando um ponteiro para um array (tamanho 9) de um array (tamanho 20) de inteiros”*.

Fica mais fácil se você remover o tamanho dos arrays e as listas de argumentos:

1
int (*(*fun_one)())[][];

Uma boa opção é decifrar dessa maneira e só depois adicionar o tamanho dos arrays e a lista de argumentos.

Algumas considerações finais

É totalmente possível criar declarações ilegais usando essa regra, então algum conhecimento do que é aceitável e do que não é em C é necessário. Por exemplo, se você tiver algo assim:

1
int *((*fun_one)())[][];

A declaração acima seria traduzida para “fun_one é um ponteiro para uma função retornando um array de arrays de ponteiros para inteiros”.

Uma vez que uma função não pode retornar um array, mas somente um ponteiro para um array, essa declaração é ilegal.

Combinações ilegais incluem:

[]() - não pode haver um array de funções
()() - não pode haver uma função que retorna uma função
()[] - não pode haver uma função que retorna um array

Em todos os casos acima, você provavelmente precisaria de um conjunto de parênteses para colocar um símbolo * a esquerda entre cada () e [] para tornar uma declaração válida.

Segue abaixo alguns exemplos válidos e inválidos para exercitar o que aprendemos:

int i;           "i um inteiro"
int *p;          "p é um ponteiro para um inteiro"
int a[];         "a é um array de inteiros"
int f();         "f é uma função retornando um inteiro"
int **pp;        "pp é um ponteiro para um ponteiro para um inteiro"
int (*pa)[];     "pa é um ponteiro para um array de inteiros"
int (*pf)();     "pf é um ponteiro para uma função retornando um inteiro"
int *ap[];       "ap é um array de ponteiros para inteiros"
int aa[][];      "aa é um array de arrays de inteiros"
int af[]();      "af é um array de funções retornando um inteiro (ILEGAL)"
int *fp();       "fp é uma função retornando um ponteiro para um inteiro"
int fa()[];      "fa é uma função retornando um array de inteiros (ILEGAL)"
int ff()();      "ff é uma função retornando uma função retornando um inteiro (ILEGAL)"
int ***ppp;      "ppp é um ponteiro para um ponteiro para um ponteiro para um inteiro"
int (**ppa)[];   "ppa é um ponteiro para um ponteiro para um array de inteiros"
int (**ppf)();   "ppf é um ponteiro para um ponteiro para uma função retornando um inteiro"
int *(*pap)[];   "pap é um ponteiro para um array de ponteiros para inteiros"
int (*paa)[][];  "paa é um ponteiro para um array de arrays de inteiros"
int (*paf)[]();  "paf é um ponteiro para um array de funções retornando um inteiro (ILEGAL)"
int *(*pfp)();   "pfp é um ponteiro para uma função retornando um ponteiro para um inteiro"
int (*pfa)()[];  "pfa é um ponteiro para uma função retornando um array de inteiros (ILEGAL)"
int (*pff)()();  "pff é um ponteiro para uma função retornando uma função retornando um inteiro (ILEGAL)"
int **app[];     "app é um array de ponteiros para ponteiros para um inteiro"
int (*apa[])[];  "apa é um array de ponteiros para um array de inteiros"
int (*apf[])();  "apf é um array de ponteiros para funções retornando um inteiro"
int *aap[][];    "aap é um array de arrays de ponteiros para inteiros"
int aaa[][][];   "aaa é um array de arrays de arrays de inteiros"
int aaf[][]();   "aaf é um array de arrays de funções retornando um inteiro (ILEGAL)"
int *afp[]();    "afp é um array de funções retornando um ponteiro para um inteiro (ILEGAL)"
int afa[]()[];   "afa é um array de funções retornando um array de inteiros (ILEGAL)"
int aff[]()();   "aff é um array de funções retornando funções retornando um inteiro (ILEGAL)"
int **fpp();     "fpp é uma função retornando um ponteiro para um ponteiro para um inteiro"
int (*fpa())[];  "fpa é uma função retornando um ponteiro para um array de inteiros"
int (*fpf())();  "fpf é uma função retornando um ponteiro para uma função retornando um inteiro"
int *fap()[];    "fap é uma função retornando um array de ponteiros para inteiros (ILEGAL)"
int faa()[][];   "faa é uma função retornando um array de arrays de inteiros (ILEGAL)"
int faf()[]();   "faf é uma função retornando um array de funções retornando inteiros (ILEGAL)"
int *ffp()();    "ffp é uma função retornando uma função retornando um ponteiro para um inteiro (ILEGAL)"

Colorific

Já faz algum tempo que desenvolvi uma gem para imprimir o resultado dos meus testes de uma forma mais intuitiva, menos poluída e mais… colorida! Não sei bem porque, mas não divulguei muito essa gem na época. De qualquer forma, ai está:

Para instalar é fácil, basta adicionar o seguinte código no seu arquivo Gemfile:

1
gem 'colorific', :group => :test

Se desejar contribuir com algo, essa biblioteca tem 78 linhas de código apenas. E todo o código encontra-se no GitHub: https://github.com/carlosbrando/colorific/blob/master/lib/colorific.rb

Quatro anos de Nome do Jogo

Hoje completam quatro anos desde que comecei a escrever esse blog. No total são 812 artigos e 4.305 comentários. Sempre mantive um ritmo muito bom de publicação, porém com o crescimento do Twitter (@carlosbrando) como ferramenta de comunicação o tempo entre um artigo e outro diminuiu muito, eu tenho de confessar.

Escrever e manter um blog por tanto tempo não é fácil, principalmente se você tem a intenção de publicar conteúdo de qualidade. Mas as recompensas valem muito a pena, nesses quatro anos esse blog gerou dois livros, muitos vídeos, um podcast semanal sobre Ruby on Rails e agora o Grok Podcast. Sem contar todas as outras oportunidades que apareceram graças a essa iniciativa.

Obrigado pela audiência!

Grok Podcast 16 - O livro Rework

Depois de um bom período de férias, estamos de volta com o Grok Podcast! E para começar o ano com tudo decidimos gravar uma série inteira sobre o controverso livro Rework de Jason Fried e David Heinemeier Hansson (o criador do framework Ruby on Rails).

Serão ao todo três episódios comentando os pontos-chave de cada um dos capítulos do livro. Se você já leu o livro será como bater um papo sobre a leitura e se você ainda não teve a oportunidade de ler, será como um bom resumo para atiçar a sua curiosidade.

Espero que gostem e continuem acompanhando o Grok Podcast nessa segunda temporada!

Você pode adicionar o podcast ao seu iTunes clicando aqui ou atráves do nosso RSS.

Como funcionam os métodos puts e print no Ruby

Se você já experimentou Ruby com certeza já conheceu os famosos métodos puts, print e outros semelhantes a esses. Talvez você tenha notado que esses métodos, diferente de como aprendemos, podem ser executados sem que seja necessário informar um objeto.

Se você vem de outra linguagem de programação talvez tenha logo especulado que eles sejam palavras reservadas do Ruby. Mas isso não é verdade. Ambos são métodos comuns, como qualquer outro. Veja por si mesmo:

1
2
Object.send :puts, "um texto qualquer"
# => um texto qualquer

Como você pode ver no exemplo acima, esses métodos foram inteligentemente incluidos na classe Object, e como no Ruby tudo é um objeto…

1
puts send(:class) # => Object

O módulo Kernel

Embora esses métodos sejam disponibilizados por meio de Object, eles estão implementados em um módulo chamado Kernel, que é então incluido na classe.

O interessante é que você pode tirar proveito desse mecanismo. Se você adicionar um método ao módulo Kernel ele funcionará exatamente como os métodos citados acima. Veja:

1
2
3
4
5
6
7
module Kernel
    def print_line
        puts '-' * 20
    end
end

print_line # => --------------------