Posts de ‘Tiago Peczenyj’

[Tiago Peczenyj] 10 coisas que todo o programador deveria saber

Sunday, March 15th, 2009

Listas de x coisas só servem para lembrar de tudo o que ficou de fora, portanto, IMHO, as 10 coisas que todo o programador deveria saber são:

0 - usar o google
1 - fazer um hello world em pelo menos 5 linguagens de programação diferentes (sendo uma funcional e uma script)
2 - instalar o wordpress e tudo o que é necessario para que o mesmo execute.
3 - instalar e configurar o Ubuntu, ou outro *nix, incluindo configuração de rede e impressão
4 - entender o que é CLASSPATH
5 - saber a diferença entre HTTP e FTP, entre TCP e UDP e qual camada OSI eles atuam. bonus: saber como funciona um GET ou POST (é possivel ver usando o live http headers do firefox).
6 - conhecer o comando grep e algumas opções como -c, -v, -A
7 - SQL: entender o que é select,update,insert, delete, commit, rollback
8 - como ler e gerar XML
9 - entender o que é NULL, , **qqcoisa do C e quais os seus usos (principalmente em strings)
10 - a diferença entre licença BSD e GPL veja aqui.

Alem disso é bom seguir alguns blogs, frequentar foruns, listas de discussão e ler muito. Mesmo um texto “chato” como A Catedral e o Bazar traz informações relevantes e outras referencias.

Boa sorte e que começe a flame-war :)

[Tiago Peczenyj] JMock - trabalhando com mock objets em java

Sunday, March 15th, 2009

Lendo sobre testes unitarios, imagine o caso onde o seu teste é complexo: um objeto que chama outro e, então, realiza as suas tarefas. Um bom caso é um DAO que acessa o banco de dados para fazer alguma coisa: se vc pensa em testar esse codigo de forma unitaria teria que subir um banco de testes e, se encontrasse um problema, poderia ser dificil dizer se é problema do DAO ou dos objetos que ele depende (como a conexão com o banco, ou o banco em si).

A solução para estes casos pode ser trabalhar com mocks: objetos “burros” que podem não ter nenhuma função alem de responder ao que vc especificou. A abordagem mais utilizada é vc programar estes objetos para responder a um ou mais metodos com argumentos especificos, assim como as respostas esperadas. No caso do DAO eu posso esperar um determinado SQL e especificar uma determinada resposta, tudo de acordo com o meu cenario de teste.

É claro que Mock Objects em excesso podem atrapalhar, mas é tudo uma questão de bom senso: costumo dizer para quem esta começando a focar os testes nas partes mais importantes do sistema, o core do modelo e regras de negocio e, então, incrementar estas praticas caso veja necessidade. Sem falar que volta e meia surge algo novo.

Para java existe o excelente framework JMock. Logo de cara o site oficial traz um exemplo de como utilizar um mock bem simples (incluindo a integração do mesmo com JUnit 4)

http://www.jmock.org/getting-started.html

Para entender, imagine esta interface

interface Subscriber {
void receive(String message);
}

Imagine que eu tenho um objeto do tipo Publisher que, ao invocar o metodo publish(message), ele envie esta mensagem para um Subscriber (que recebe com o metodo acima). Para testar o publish eu teria que me certificar que o metodo receive deste objeto Subscriber foi invocado com a mensagem especificada, mais ou menos assim:

import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.Expectations;

@RunWith(JMock.class)
class PublisherTest {
Mockery context = new JUnit4Mockery();

@Test
public void oneSubscriberReceivesAMessage() {
// set up
final Subscriber subscriber = context.mock(Subscriber.class);

Publisher publisher = new Publisher(); // objeto que vou testar
publisher.add(subscriber); // tenho que adicionar o mock!

final String message = “message”;

// aqui eu programo o que eu espero do teste
context.checking(new Expectations() {{
oneOf (subscriber).receive(message);
}});

// aqui eu executo!
publisher.publish(message);
}
}

Facil?

[Tiago Peczenyj] XStream - Simplicidade ao lidar com XML em Java

Sunday, March 15th, 2009

Quem nunca passou por isso: ter que gerar e/ou ler arquivos xml e teve que escolher dentre diversas tecnologias e frameworks diferentes. Seja carregar tudo pra memoria ou ler aos poucos, se é um parser push ou pull, etc, é possivel dizer que para cada situação existe uma boa escolha.

Se o seu caso é trabalhar com arquivos cujos elementos podem ser mapeados em objetos java, uma boa escolha é o XStream

XStream xstream = new XStream(new DomDriver());
Person pac = new Person(”Tiago”, “Pac Man”);
String xml = xstream.toXML(pac);

/* Simples. É, para fazer o contrario, basta */

Person newPac = (Person)xstream.fromXML(xml);

Este e outros exemplos podem ser conferidos aqui:
http://xstream.codehaus.org/tutorial.html

É claro que o xml gerado assim, cru, nem sempre serve. Para isso vamos usar algumas linhas a mais para trabalhar com os recursos de alias, annotations e os Converters.


xtream.alias(”pessoa”,Person.class);

Dessa forma, para se livrar do nome.do.pacode.Person e trabalhar com algo mais expressivo como pessoa, basta adicionar este alias antes de converter de/para xml. Para trabalhar com aliasing de atributos (e coleções implicitas) o ponto de partida é este:

http://xstream.codehaus.org/alias-tutorial.html

É possivel trabalhar com annotations no seu modelo de classes, evitando toda essa configuração manual

http://xstream.codehaus.org/annotations-tutorial.html

Para trabalhar com o maximo de flexibilidade do XStream, entretanto, vc precisa trabalhar com Converters - Veja o exemplo da classe Birthday

http://xstream.codehaus.org/converter-tutorial.html

XStream trabalha muito bem com classes imutaveis, pois não recria os objetos usando o construtor e sim de maneira semelhante ao mecanismo de serialização de objetos, fazendo um bypass do construtor. Sem falar que traz um pensamento menos voltado a “tags” e mais OO.

[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 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?

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

Wednesday, February 11th, 2009

50

Created by OnePlusYou

[Tiago Peczenyj] Literate Programs

Monday, February 2nd, 2009

Descobri uma wiki muito interessante sobre algoritmos, programação e linguagens: Literate Programs

Eles estão abertos a contribuições (em inglês) e utilizam um formato bem interessante para descrever os problemas e soluções: infelizmente não é tão completo quando poderia ser por isso precisa da contribuição de pessoas bem intencionadas como nós. Não é um repositorio de códigos e sim artigos elaborados explicando alguns detalhes interessantes.

Um bom exemplo são as 9 versões de 99 Bottles of Beer, porém vc encontra calculo de numeros primos, fibonacci, quicksort, o interessante exponentiation by squaring e muito mais. Vc encontra implementações em muitas linguagens como C, Java, AWK, Erlang entre outras.

Quem procura coisas mais basicas em linguagens mais populares (Java, C#, ActionScript) como “gravar em arquivo”, “ler xml”, etc, pode procurar no java2s.

[Tiago Peczenyj] Fibonacci: alguns algoritmos efetivos em AWK

Friday, January 30th, 2009

Estava apreciando hoje de manhã um post do Felipe Tonello: Analisando Número de Fibonacci e Recursividade. É um bom artigo sobre aquelas coisas que alguns podem ter visto na faculdade e são sempre uteis: matemática, analise de algoritmos e um pouco de mente aberta.

Imediatamente tratei de testar a velocidade dos dois algoritmos propostos usando AWK (que, por ser interpretado, pode revelar melhor as nuances entre as abordagens). Algoritmos recursivos são interessantes, principalmente quando trabalhamos com linguagens funcionais, porém algumas formas tem um custo computacional muito alto e o calculo de Fibonacci é um exemplo perfeito: para cada termo eu preciso calcular os dois termos anteriores e, então, soma-los, e isso cresce geométricamente, consumindo memória e processamento, sem falar que tenho muita repetição de código desnecessária.

A tecnica de programação dinâmica apresentada cria um cache de resultados, dessa forma evito boa parte do trabalho extra, veja o resultado:

Fibonacci(36) pelo algoritmo recursao simples:14930352 usando 48315633 iteracoes

real    0m51.961s
user    0m23.881s
sys     0m0.012s
Fibonacci(36) pelo algoritmo programacao dinamica:14930352 usando 71 iteracoes

real    0m0.002s
user    0m0.000s
sys     0m0.000s

Usando programação dinâmica eu uso muito menos de 1% do processamento necessário pela forma recursiva tradicional. Parece ótimo, não? Depende, pois eu apenas afastei o problema: ao calcular termos de alta ordem eu terei o mesmo problema, afinal o algoritmo é O[n].

Lembrei de um post do Ronaldo Melo Ferraz, Conceitos de Programação: Tail Recursion enquando estava testando os algoritmos em Erlang e encontrei esta implementação. A adaptação para awk é tranquila e o teste mostrou este resultado:

Fibonacci(36) pelo algoritmo programacao dinamica:14930352 usando 71 iteracoes

real    0m0.002s
user    0m0.000s
sys     0m0.000s
Fibonacci(36) pelo algoritmo tail recursion:14930352 usando 38 iteracoes

real    0m0.001s
user    0m0.000s
sys     0m0.004s

Um resultado ainda mais interessante, pois eu consigo obter o valor do termo com um pouco mais da metade das iterações do que usando programação dinâmica (sem onerar a memória com o cache dos resultados).

Esta analise é muito superficial, a ideia é apenas despertar a curiosidade sobre estes tópicos.

O codigo fonte utilizado nesse benchmark:
function Fib_normal(N) {
return (N > 1)? Fib_normal(N-1) + Fib_normal(N-2) : N
}
function Fib_dinamic(N) {
if (!m[N]) m[N] = (N > 1)? Fib_dinamic(N-1) + Fib_dinamic(N-2) : N
return m[N]
}

function Fib(N) { return Fib_tr(N,0,1); }
function Fib_tr(I,R,N){
return (I==0)? R : Fib_tr(I-1,N,R+N)
}