Otimização e desempenho

quinta-feira, 29 de outubro de 2009

Como eu já disse anteriormente, sou monitor da disciplina "Computação 2" (Orientação a Objetos com Java) na graduação em Ciência da Computação da UFRJ.

Uma pergunta bastante recorrente ao longo dos períodos tem sido "Como é mais rápido?" geralmente acompanhada de "O que consome mais memória?".

Estas perguntas podem ser facilmente respondidas em Java com System.nanoTime() e System.currentTimeMillis() para a velocidade e ferramentas de profiling para a memória e outras informações. Embora isto responda a pergunta, ataca um sintoma e não a raiz do problema:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." - Donald Knuth

O mal ("evil") a que ele se refere é consequência de algo bem explicado por outro grande autor:

"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult." - C. A. R. Hoare

Quem já percebeu a relação entre estas duas frases, já sabe onde eu vou chegar. A questão é que muitos tendem a se preocupar primariamente com otimização e deixam a legibilidade do código em segundo plano.
Ao fazer isso, o código pode ficar otimizado onde não precisa, prejudicando a legibilidade sem trazer ganho real.

Em via de regra, seu foco deve ser fazer um código legível. O máximo possível. SE vc tiver problema de desempenho (o que você só sabe depois que rodar com a carga esperada de usuários e objetos criados simultaneamente) é que você deve alterar o código de forma a ganhar desempenho prejudicando a legibilidade o mínimo possível, até atingir o desempenho desejado.


“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”-Martin Fowler

Já falei de legibilidade aqui antes: "Você comenta seu código?"

A grande questão é que você não trabalha sozinho. Cedo ou tarde alguém vai por a mão no seu código, assim como você vai mudar algo que alguém fez. E ainda que você esteja começando a desenvolver agora e esteja só fazendo pequenos exercícios, é de cedo que se deve treinar bons hábitos.
É importante que você deixe tudo muito bem claro para o seu colega, assim como ele deve deixar tudo claro para você. É mais um fator que pode contribuir para que você tenha no seu currículo um projeto de sucesso, um reconhecimento no ambiente de trabalho e consequentemente uma boa carreira profissional.
Mesmo que seja um projeto seu, particular, você mesmo pode querer mudá-lo alguns meses depois de começado.
Clareza é fundamental e deve vir em primeiro lugar, principalmente porque quando se escreve código, não se sabe, a priori, o que será suficientemente rápido ou precisará de otimização.

Isto só se descobre quando a funcionalidade foi implementada, para que possa passar por teste de carga (também conhecido como teste de estresse ou de performance).

Testes de carga são aqueles em que o sistema é forçado a executar em condições acima do projetado, para ver como se comporta. Por exemplo, se a sua previsão é para 50 usuários simultâneos, teste com 200, para ver como o sistema reagiria num caso de pico de utilização.

Estes testes são feitos geralmente através de ferramentas automatizadas que simulam execuções por usuários virtuais extremamente leves (para que uma máquina sozinha possa simular muitos). Uma ferramenta para Java free e muito popular é o JMeter e há outras para outras linguagens, inclusive algumas independentes de linguagem, já que basta simular um "agente" (termo que usam para um usuário ou sistema externo).

Estes testes, associados a ferramentas de profiling já mencionadas anteriormente fornecem informações sobre quais são os métodos mais lentos, que consomem mais memória, que executam maior quantidade de vezes, etc.

É só a partir destas informações que se pode detectar onde as otimizações devem ser feitas CASO precisem ser feitas. E mesmo assim, o código deve ser modificado para a otimização que menos prejudica a legibilidade e a portabilidade. Depois de um novo teste é que se decide se foi suficiente ou se mais alguma ação deve ser tomada.

Um ótimo exemplo de otimização sem perda de legibilidade está no Blog C++ do Zimbrão. Este é sobre Java e este sobre C++, lembrando que otimizações que realmente funcionam variam de linguagem para linguagem e de compilador para compilador em uma mesma linguagem. O post de otimizações em C++ é muito elucidativo a este respeito.

Além disso, deve-se lembrar neste momento que há diversos mecanismos para melhorar a performance como clusters de aplicações (felizmente para quem trabalha com JEE, isto vem de graça), configurações de datasource, pool de conexões com banco, cache de banco que não mudam a aplicação em si, caso tenha sido desenvolvida corretamente, isolada de acoplamentos com outros sistemas, como o sistema gerenciador de banco de dados ou o servidor onde será executada.

Vou só lembrar ainda que é importante também seguir as convenções de codificação da sua organização. Mas este é assunto para outro post. ;-)

P.S.: Pra quem gostou dos quotes, aqui tem mais: http://en.wikipedia.org/wiki/Program_optimization#Quotes

Abraço a todos!

Bookmark and Share

Nenhum comentário:

Postar um comentário

 
addthis_config = { data_ga_tracker: pageTracker }