Posts de February, 2009

[Tiago Peczenyj] Ate um simples Hello World pode ser complicado

Friday, February 27th, 2009

Para ilustrar a sintaxe de uma linguagem, é comum o primeiro exemplo ser o hello world, no qual o programa realiza um aceno breve e fugaz (valeu zED9h) para o mundo exterior. Vejamos em C:


#include <stdio.h>
int main (int argc, const char* argv[]){
printf(”hello world!\n”);
return 0;
}

Aparentemente é um codigo simples, vamos olhar a execução

peczenyj@XXX:~$ gcc -Wall hello.c -o hello.exe
peczenyj@XXX:~$ ./hello.exe && echo “ok” || echo “nok”
hello world!
ok

Testar um hello world sob condições normais não é dificil: ele vai escrever uma mensagem fixa na stdout e vai retornar 0 para o bash (que pode ser recuperado via $? ou então encadear && e || como eu fiz no exemplo acima.

Agora vejamos o strace:

peczenyj@XXX:~$ strace ./hello.exe
execve(”./hello.exe”, ["./hello.exe"], [/* 35 vars */]) = 0
brk(0) = 0×804a000
access(”/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f9c000
access(”/etc/ld.so.preload”, R_OK) = -1 ENOENT (No such file or directory)
open(”/etc/ld.so.cache”, O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=81298, …}) = 0
mmap2(NULL, 81298, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f88000
close(3) = 0
access(”/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)
open(”/lib/tls/i686/cmov/libc.so.6″, O_RDONLY) = 3
read(3, “\177ELF\1\1\1\3\3\1\260a\1″…, 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=1339816, …}) = 0
mmap2(NULL, 1349136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e3e000
mmap2(0xb7f82000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0×143) = 0xb7f82000
mmap2(0xb7f85000, 9744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f85000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e3d000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e3d6b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7f82000, 4096, PROT_READ) = 0
munmap(0xb7f88000, 81298) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), …}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f9b000
write(1, “hello world!\n”, 13hello world!
) = 13
exit_group(0) = ?
Process 6344 detached

Vejamos só: uma grande preparação para, no final, mostrar um hello world e sair (com sucesso). Isso mostra que qualquer coisa, mesmo a mais simples, esta envolta em muitas camadas de abstração até ser corretamente executada. Aqui estamos ignorando o sistema de arquivos, sistema operacional, memoria, cpu, etc. Com linguagens interpretadas ou que rodam sob uma JVM a coisa é mais complexa ainda.

[Tiago Motta] Duck typing e os testes de aceitação automáticos

Thursday, February 26th, 2009

Uma discussão frequente em minha equipe é sobre maneiras de garantir que nossos sistemas estejam funcionando adequadamente por meio de testes automáticos. Em nossos ultimos projetos temos conseguido alcançar 100% de cobertura de testes unitários, e nos sistemas legados temos aumentado a cobertura aos poucos.

No entanto, estamos cientes de que nem 100% de cobertura de testes unitários garantem a ausência de bugs. Isso nos remete aos testes de aceitação automáticos, não só por causa do funcionamento das telas e fluxos de navegação, mas também dos possíveis problemas que um refactoring com um pouco menos de atenção pode causar em uma linguagem baseada em duck typing.

Darei um exemplo em ruby para ilustrar um bug que pode ser introduzido sem que seus testes unitários percebam. Digamos que você tenha as seguintes classes:

class Filme < ActiveRecord::Base do  def alugar    self.estoque.remover self  endendclass Estoque < ActiveRecord::Base do  def remover(filme)    # ...  endend

No seu spec que verifica o método alugar da classe Filme você colocaria um mock mais ou menos como mostrado abaixo:

@estoque = mock_model(Estoque)@estoque.should_receive(:remover).with(@filme).once

Um dia você percebe que o nome do método remover não está explicando muito bem o significado, e resolve fazer um refactoring renomeando-o para remover_fita_do_filme.

Você altera os testes da classe Estoque, renomeia o método e logo depois recebe uma ligação de uma empresa de telefonia te oferecendo serviços excepcionais que você nunca precisou. Puto da vida você desliga o telefone, roda os testes e todos passam! Serviço feito!

Perceberam o problema? Sem um teste de aceitação automático ou no mínimo um teste manual, você não perceberia que a classe Filme continua referenciando o método antigo, remover, da classe Estoque. Esse tipo de problema não passaria em uma linguagem que não segue duck typing, pois a etapa de verificação de código da compilação serviria como uma espécie de teste unitário de tipos e nomes.

Um problema mais evidente seria um método que recebe um objeto que precisa ter determinado método, ou seja implementar determinada interface. Veja o exemplo abaixo, que mostra que ao alugar um item, no caso um Filme, adiciona-se todas as tags dele às tags preferenciais do cliente:

class Cliente < ActiveRecord::Base do  def alugar(item)    #...    adiciona_tags_preferenciais item.tags  endendclass Filme < ActiveRecord::Base do  def tags    # ...  endend

Se mudarmos o nome do método tags em Filme e também corrigirmos o uso de dele no método alugar da classe Cliente tudo funcionará bem. Mas, como usamos duck typing não temos como garantir que outros objetos, digamos alugáveis, tenham sido alterados. Se por exemplo esta locadora também alugas livros, teríamos um erro evidente:

class Cliente < ActiveRecord::Base do  def alugar(item)    #...    adiciona_tags_preferenciais item.tags_principais  endendclass Filme < ActiveRecord::Base do  def tags_principais    # ...  endendclass Livro < ActiveRecord::Base do  def tags    # ...  endend

Esse tipo de erro só seria pego num teste manual se lembrássemos de testar o aluguel de livros também. Por isso é tão importante o teste de aceitação automático em uma linguagem com duck typing. Em Java por exemplo, que a interface precisa ser explícita, o erro seria pego no que poderíamos considerar o teste unitário que a compilação executa. As classes Filme e Livro implementariam a interface Alugavel por exemplo:

public interface Alugavel {  List tagsPrincipais();}

Mas é claro que o uso de uma liguagem menos dinâmica não remove a necessidade de testes de aceitação automáticos. O valor desse tipo de testes é independente da linguagem, e sua implementação é importantíssima para garantir fluxos de navegação e integração entre os diversos componentes do sistema.

[Danilo Bardusco] Enterprise Scrum – Recife Summer School

Monday, February 23rd, 2009

Na útima segunda-feira(16/02/09), estive novamente em recife, desta vez fui ao C.E.S.A.R, num excelente evento organizado pelo CESAR.Edu, o RSS, para falar sobre os desafios encontrados ao implementar Scrum em toda uma organização. Os slides podem ser vistos abaixo e o original em PDF vc encontra no slideshare.

No fim do dia Boris Gloger fez uma apresentação que tem tudo a ver com o tema da minha apresentação: Going LARGE by Staying small

Apresentaram também no mesmo dia:

  • Manoel Pimentel
  • Scott Ambler
  • Teresa Maciel e Felipe Furtado
  • Agradecimento especial para a Ana Paula Cavalcanti e Teresa Maciel pelo convite e pela excelente organização do evento.

    Como sempre, feedback sobre a apresentação é muito bem vindo.

    [Tiago Peczenyj] Adicionando Funcionalidades a um Sistema em Produção

    Friday, February 20th, 2009

    Por mais de uma vez eu tive que adicionar certas funcionalidades em sistemas que ja estavam em produção. É uma tarefa arriscada pois o serviço não pode parar por algum erro que vc esta introduzindo, ainda mais se este mesmo sistema estiver funcionando sem problemas nos ultimos meses ou anos.

    Aprendi um truque bem interessante que, pensando bem, é um tanto obvio: ao adicionar uma funcionalidade onde boa parte do codigo ficou inalterada, pode fazer sentido desabilitar esta nova funcionalidade na configuração. Dessa forma se a porção nova de codigo produzir algum problema é possivel - teoricamente - minimizar os problemas desabilitando temporariamente esta feature.

    Nem sempre isto faz sentido, porém não se trata de esconder a sujeita para debaixo do tapete: é de se esperar uma intensa bateria de testes de regressão alem de testes sobre o codigo novo. Conseguimos ter certeza da situação ao olhar os relatorios de cobertura de código, por exemplo. Esta é mais uma tecnica para evitar problemas em algo ja estabelecido.

    Imagine que, no ambiente de produção, a nova feature desenvolve um memory leak, ou a escalabilidade dela não é a esperada? Desabilitar na configuração é menos traumatico do que um rollback na aplicação, mas ainda assim é traumatico. Agora, se vc desabilita e o problema continua isso ja dá pistas de que existe um problema em outro lugar - por exemplo na propria porção de código legado.

    E vc, como adiciona funcionalidade a um sistema em produção?

    [Emerson Macedo] BBB9 e o brother que você não gosta - NO AR !!!

    Friday, February 20th, 2009

    Entrou hoje, exatamente as 08:34 da manhã, o aplicativo oficial do Big Brother Brasil 9 para orkut na plataforma Open Social, desenvolvido pelo time o qual faço parte aqui na globo.com. Esse aplicativo tem por objetivo alfinetar o brother que o usuário não gosta e comentar sobre o assunto.

    Aplicativos Open Social parecem algo como uma brincadeirinha de criança, coisa que qualquer pessoa faz. Mas na verdade, desenvolver esse tipo de aplicação para um programa como o Big Brother Brasil não é tão simples. Aplicações de grande volume geralmente usam arquiteturas recheadas de cache, processamento assíncrono usando fila, criptografia, alguns servidores e um bocado de outras coisas que o torna tão complexo quanto qualquer outro sistema.

    Quero aproveitar também e destacar, que conseguimos desenvolver o produto completo “do zero”, em pouco mais de 1 mês. Isso inclui configuração de todos os servidores (inclusive produção que são várias máquinas), ambiente interno de desenvolvimento, servidor de integração contínua, desenho dos bonecos dos brothers de forma personalizada, vários testes de carga em ambientes que simulam produção e muita comunicação. Estou falando disso, pois usamos metodologias ágeis e acredito fortemente que se não fosse assim, não teria sido possível entregar o aplicativo nesse tempo (e não trabalhamos nenhum fim de semana). No caso específico aqui da globo.com, SCRUM é a metodologia usada, mas poderia ser Extreme Programming ou alguma outra qualquer. Um detalhe também importante é que nosso time tem apenas 10 pessoas, o que contraria um pouco o modelo tradicional que diz que com mais gente o trabalho anda mais rápido.

    Se você gosta de Big Brother Brasil e deseja expressar sua opinião sobre algum brother, entre na seção de aplicativos do orkut e procure por: BBB - Voodoo Brother.

    [Bernardo Heynemann] <frustrated>Am I that stupid?

    Friday, February 20th, 2009

    God am I frustrated. It’s 3 am and I’ve been trying to setup a decent Python environment in Ubuntu since 10 am yesterday! Well, I gotta say that I’m very well impressed with Ubuntu, though. It’s a pretty cool OS with an awesome user experience. My problems…(read more)

    [Tiago Motta] Plugin do rails para copiar erros de um model para outro

    Thursday, February 19th, 2009

    Em um projeto pessoal precisei desenvolver uma maneira de copiar os erros de um model para outro. Como é uma funcionalidade que outrora já havia precisado, aproveitei para criar um plugin e disponibilizá-lo para quem mais tiver esse mesmo problema.

    O plugin está disponível no GitHub pelo endereço http://github.com/timotta/copy_errors_from/tree/master. Para instalar no seu projeto basta rodar a seguinte linha:

    script/plugin install git://github.com/timotta/copy_errors_from.git

    Após instalar todos os seus models terão o método copy_errors_from, que pode ser utilizado como mostrado abaixo:

    > filme = Filme.new :titulo => 'Corra que a polícia vem aí'> ator = Ator.new> filme.atores.push ator> filme.save #return false> filme.errors.entries #return []> ator.errors.entries #return [['nome','Não pode ser vazio']]> filme.copy_errors_from ator> filme.errors.entries #return [['ator_nome','Não pode ser vazio']]> filme.errors.on(:ator_nome) #return 'Não pode ser vazia'

    [Rafael Silva Pereira] QoS Parameters for Video Streaming

    Friday, February 13th, 2009

    When we talk about professional media streaming, there is a lot concern with the quality of service, especially when we have large volumes of requests, or when we delivery contents in high definition. In this scenario, is essential to have a fairly clear idea about what is quality of service, and how we can identify, through objective parameters, if we’re or not at an acceptable level, which ensures a high quality experience for end users.

    In the case of video streaming, quality of service means that the user should watch a certain content, without interruption (rebuffering), and without degradation of video quality caused by the delivery process (loss of frames, problems in the reconstruction of b-frames and p-frames due packet loss).

    Thus, the best known parameter for evaluating the quality of a streaming service is the buffer length, which is the ability to maintain the user’s buffer always at an acceptable level, being greater enough to ensure a continuous experience independent of small variations in bandwidth available, and in the bitrate of the encoded video. Associated with this parameter, we have the average rebuffering rate, which consists of a ratio between the total time used filling the buffer, and the total playing time. This parameter is very interesting to assess the quality of service for live streaming, where users can stay connected for a long time, and, of course, they would like to play the content without interruptions.

    A high quality streaming service should always keep the rate of rebuffering below 0.5%, discarding the initial buffer, at normal bandwidth availability. Moreover, this parameter can be very useful to identify network bottlenecks at content distribution process.

    Another key parameters are the average frame rate and the rate of frame loss. These two parameters give us an overview of the capacity, of the server to stream the video content, and, of the users to receive and decode the stream. In case of server overloading , one of the first alternatives used to maintain a continuous experience is to reduce the frame rate, or basically, drop frames. These parameters usually indicate that either the server is not able to serve the content, or, the clients do not have the minimum conditions to receive and decode the video. These problems are usually associated with intensive CPU usage, due an excess of clients in the server side, or by lack of resources for decoding the video on the client.

    For Flash Media Server specifically, some parameters related with memory usage for input and output buffer, size of buckets, and use of aggregated messages, can influence directly in the video frame rate, but in this case, we can detect the problem even with a small amount of users.

    Finally, we have some parameters, not least importants, to complement the set of basic checkpoints to ensure the quality of streaming video service, including, the time to establish the connection, the rate of reconnection, the sync between audio and video, and psnr between the video decoded by the user and the video that comes out of encoder (since the loss of packets may influence the reconstruction of the frames, especially for temporal video compression). Measuring and evaluating all these parameters we can identify with much more efficiency any problem that might compromise the quality of service, which is essential for professional media streaming business.

    [Rafael Silva Pereira] QoS Parameters for Video Streaming

    Friday, February 13th, 2009

    When we talk about professional media streaming, there is a lot concern with the quality of service, especially when we have large volumes of requests, or when we delivery contents in high definition. In this scenario, is essential to have a fairly clear idea about what is quality of service, and how we can identify, through objective parameters, if we’re or not at an acceptable level, which ensures a high quality experience for end users.

    In the case of video streaming, quality of service means that the user should watch a certain content, without interruption (rebuffering), and without degradation of video quality caused by the delivery process (loss of frames, problems in the reconstruction of b-frames and p-frames due packet loss).

    Thus, the best known parameter for evaluating the quality of a streaming service is the buffer length, which is the ability to maintain the user’s buffer always at an acceptable level, being greater enough to ensure a continuous experience independent of small variations in bandwidth available, and in the bitrate of the encoded video. Associated with this parameter, we have the average rebuffering rate, which consists of a ratio between the total time used filling the buffer, and the total playing time. This parameter is very interesting to assess the quality of service for live streaming, where users can stay connected for a long time, and, of course, they would like to play the content without interruptions.

    A high quality streaming service should always keep the rate of rebuffering below 0.5%, discarding the initial buffer, at normal bandwidth availability. Moreover, this parameter can be very useful to identify network bottlenecks at content distribution process.

    Another key parameters are the average frame rate and the rate of frame loss. These two parameters give us an overview of the capacity, of the server to stream the video content, and, of the users to receive and decode the stream. In case of server overloading , one of the first alternatives used to maintain a continuous experience is to reduce the frame rate, or basically, drop frames. These parameters usually indicate that either the server is not able to serve the content, or, the clients do not have the minimum conditions to receive and decode the video. These problems are usually associated with intensive CPU usage, due an excess of clients in the server side, or by lack of resources for decoding the video on the client.

    For Flash Media Server specifically, some parameters related with memory usage for input and output buffer, size of buckets, and use of aggregated messages, can influence directly in the video frame rate, but in this case, we can detect the problem even with a small amount of users.

    Finally, we have some parameters, not least importants, to complement the set of basic checkpoints to ensure the quality of streaming video service, including, the time to establish the connection, the rate of reconnection, the sync between audio and video, and psnr between the video decoded by the user and the video that comes out of encoder (since the loss of packets may influence the reconstruction of the frames, especially for temporal video compression). Measuring and evaluating all these parameters we can identify with much more efficiency any problem that might compromise the quality of service, which is essential for professional media streaming business.

    [Tiago Peczenyj] How Many HTML Elements Can You Name in 5 Minutes?

    Wednesday, February 11th, 2009

    50

    Created by OnePlusYou