Na última quinta e sexta-feira aconteceu em São Paulo o RubyConf 2011. O RubyConf é sem sombra de dúvida a melhor conferência nacional sobre programação na atualidade.
As palestras, como sempre, foram acima da média. E esse ano a organização deu um passo além transmitindo online todas as apresentações. Se você não pôde estar presente é possível assistir ao evento inteiro no site da eventials, a empresa encarregada pela transmissão e gravação do evento. Segue o link: http://www.eventials.com/rubyconfbr
Eu também tive a oportunidade de palestrar, junto com meu amigo Luis Gustavo, e dessa vez o assunto foi sobre a nova máquina virtual Ruby compacta que estamos desenvolvendo aqui na Plano Bê. Para assistir a minha palestra, clique aqui. Os slides estão abaixo.
Eu já participei de muitas conferências sobre Ruby e outras linguagens, mas nenhuma se compara a RubyConf. Eu sei que o custo envolvendo a entrada do evento, viagem, alimentação e outros pode ser um pouco pesado, principalmente se você está iniciando na área, mas vale cada centavo.
O RubyConf Brasil 2011 está chegando e o Grok Podcast vai te ajudar a participar do evento sem gastar um centavo. Estamos sorteando até sexta-feira 4 ingressos para o evento.
Para participar é fácil. Basta clicar aqui ou publicar a mensagem abaixo no seu Twitter:
Participe da #RubyConfBR by #Locaweb, saiba mais sobre o evento em http://goo.gl/K5gHh e concorra a 4 ingressos /via #GrokPodcast
Aproveite que está no Twitter e me siga em @carlosbrando. ;)
Esse episódio introduz um formato diferente. Episódios extras, fora da cronologia normal e patrocinados por uma empresa ou grupo. Não queremos em hipótese alguma fazer simples propaganda, pelo contrário somente conteúdo relevante e que agregue conhecimento serão aprovados para esse formato. Porém o patrocinador pode sugerir temas que estejam relacionados ao seu negócio.
Esse primeiro episódio é apenas um piloto. O objetivo principal do Grok Podcast é informar e compartilhar conhecimento e não necessariamente lucrar com isso, porém com o crescimento de nossa audiência nossos gastos tem aumentado muito e esses anunciantes nos ajudam a manter o podcast no ar.
Porém, nós estamos interessados em saber o que você achou desse piloto. Se você é um ouvinte, deixe um comentário dizendo como se sente em relação a esses episódios extras e quais as suas expectativas.
O mesmo vale caso você tenha interesse em anunciar na série regular ou patrocinar um episódio extra. Nesse caso, entre em contato através da nossa página de contato e explicaremos em mais detalhes como isso funciona.
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.
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.
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.
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[];
Encontre o identificador.
123
int *p[];
^
"p é"
Siga pela direita enquanto encontrar um símbolo ou abre parênteses.
123
int *p[];
^^
"p é um array de"
Quando não puder mais mover para a direita (os símbolo acabaram), então siga para a esquerda e encontre:
123
int *p[];
^
"p é um array de ponteiros para"
Continue seguinte pela esquerda e encontre:
1234
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())();
Encontre o identificador.
123
int *(*func())();
^^^^
"func é"
Vá para a direita.
123
int *(*func())();
^^
"func é uma função retornando"
Não dá para ir mais a direita devido ao fecha parênteses, então vá para a esquerda.
123
int *(*func())();
^
"func é uma função retornando um ponteiro para"
Não pode mais ir para a esquerda devido ao abre parênteses, então continue indo pela direita.
123
int *(*func())();
^^
"func é uma função retornando um ponteiro para uma função retornando"
Não dá mais para ir para a direita porque não há mais simbolos, então vá para a esquerda.
123
int *(*func())();
^
"func é uma função retornando um ponteiro para uma função retornando um ponteiro para"
E finalmente, o último símbolo a esquerda.
123
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)"
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:
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.