Tag: programação

Aprendendo programação com 5 GIFs animados

Este post é uma cópia descarada de parte de uma publicação do site Penjee, cujo foco é aprendizagem de programação.

Reproduzir material não é algo que costumo fazer, mas como já lecionei para várias turmas de iniciantes em programação, reconheço que este é um conteúdo que merece ser repassado.

No começo, todos lutamos um pouco com a lógica de um programa, isto é, como a sequência de comandos que digitamos realmente funciona na prática.

Atenção! As imagens a seguir podem mudar a sua vida e abrir um novo mundo de possibilidades. O conteúdo é forte! 😀

Leia mais

Linguagens de Programação de alto e baixo nível, quais as diferenças?

Há alguns dias surgiu uma pergunta muito interessante no Stack Overflow em Português sobre o que faz uma linguagem ser considerada de alto ou baixo nível.

Abaixo estão algumas de minhas reflexões sobre o tema.

Uma imagem vale mais do que mil palavras

baixo-alto-nível

Abstração computacional

Pensando numa abordagem para diferenciar linguagens de alto e baixo nível do ponto de vista de quem está programando, o nível da linguagem é proporcional ao quanto você gasta pensando em resolver o seu problema (alto nível) ou em resolver problemas relacionados aos cálculos computacionais (baixo nível).

Por exemplo, considere os “comandos” a seguir:

  1. Mova o texto “ABC” para a posição de memória 123, copie todos os caracteres para o fluxo aberto que aponta para a posição 456 do disco.
  2. Gravar o texto “ABC” no arquivo “doc.txt”
  3. Atualize o nome do cliente com o valor “João”

O item #1 é certamente o que possui mais baixo nível. Em relação a ele, o item #2 é de mais alto nível.

Porém, temos o item #3, que é de mais alto nível que todos. Em relação a ele, o item #2 é de mais baixo nível.

Quantidade de camadas de abstração

Desde que os computadores surgiram há um esforço para tornar a sua programação mais fácil. Isso foi feito criando-se novas linguagens e compiladores mais avançados, assim como através de macros, métodos ou objetos que abstraem e automatizam certas tarefas.

Porém, cada vez que adicionamos uma dessas “facilidades”, aumentamos a quantidade de camadas de abstração ou indireção em relação à computação binária.

Por exemplo:

  1. Assembly é uma linguagem que se mapeia praticamente direto para código de máquina, mas ainda assim o programa é escrito em texto antes de ser convertido em binário. Em geral, cada comando assembly consiste em uma instrução ao processador.
  2. C é uma linguagem de mais alto nível, onde cada comando é traduzido pelo compilador geralmente em várias instruções Assembly (ainda que em memória) antes de realmente gerar código binário.
  3. Java e .NET são linguagens ainda de mais alto nível porque cada comando gera uma ou mais instruções de máquinas virtuais, que não é o mesmo que linguagem de máquina. Cada instrução dessas máquinas virtuais precisa ser traduzida, em tempo de execução, para um conjunto de instruções de máquina correspondente à arquitetura da CPU onde o programa está rodando.
  4. No PHP, enquanto linguagem interpretada, cada comando é processado por código previamente compilado em C, geralmente levando à execução de vários trechos de código equivalentes a várias funções C que são mapeadas para inúmeras instruções de máquina.

Vale notar que, em geral, a quantidade de níveis de abstração é proporcional ao quanto o programador fica “longe” do hardware, mas nem sempre isso é diretamente proporcional.

Suba o nível

Independente da linguagem, programadores devem programar em alto nível sempre que possível.

Mesmo que sua plataforma de desenvolvimento permita conversar diretamente com o hardware, a fim de manter a sanidade, um bom programador irá abstrair toda essa complexidade em rotinas de mais alto nível conforme as capacidades da linguagem (funções, método, objetos, módulos, etc.).

Imagine o seguinte código:

notaFiscal = ler_arquivo_nota_fiscal(caminho);
validar_nota_fiscal(notaFiscal);
salvar_nova_fiscal(notaFiscal);

Exceto pelo estilo de codificação, seja Java ou JavaScript, C ou C#, ShellScript ou PHP, qualquer um pode entender o que o código acima faz e implementar os detalhes nas respectivas rotinas.

No fim das contas, não é porque alguém programa em C que necessariamente precisa estar sempre codificando em baixo nível.

Considerações

Não é possível afirmar absolutamente que uma data linguagem é de alto ou baixo nível.

O que poderíamos dizer é que todas as linguagens de programação são de mais alto nível em relação ao código binário (desde que seja humanamente possível ler o código, obviamente).

Além disso, poderíamos ainda afirmar que uma linguagem X é de mais alto ou mais baixo nível em relação à alguma outra linguagem Y considerando o aspecto Z.

Por fim, dentro de uma mesma linguagem, é possível programar em diferentes níveis de abstração. Bons programadores irão subir o nível sempre que possível tanto para aumentar a produtividade quanto para uma melhor qualidade do código.

Depuração Avançada de JavaScript

js-logo-badge-512

Ainda me lembro do tempo em usava alerts para encontrar erros em JavaScript. :/

Hoje todo navegador tem sua ferramenta de ajuda ao desenvolvedor. Basta pressionar F12 (pelo menos no Chrome, Firefox e Internet Explorer para Windows) em qualquer página e você já pode “hackear” o HTML, CSS e JavaScript, monitorar o tempo de carregamento total ou de cada artefato pertencente ao site, depurar JavaScript linha a linha e muito mais.

Infelizmente, muitos desenvolvedores ainda estão limitados às técnicas arcaicas de depuração JavaScript que consistem praticamente em tentativa e erro, por exemplo inspecionando valores com a função alert. Alguns avançaram um pouco e usam o console.log.

Veremos a seguir algumas técnicas um tanto menos triviais para obter uma experiências mais agrádavel ao desenvolver e testar páginas web.

Depurando Javascript

No Chrome, navegador desenvolvido pelo Google e meu predileto, você pode facilmente depurar a execução de código JavaScript.

Para isso, basta acessar a aba Source da Ferramenta do Desenvolvedor. Ali é possível abrir qualquer asset como CSS e JavaScript, editá-los, salvá-los e ver o resultado da edição sem recarregar a página.

Nos fontes JavaScript você pode definir breakpoints como em qualquer IDE de desenvolvimento. Quando aquele trecho for executado, a execução será interrompida. Então você pode inspecionar variáveis e avançar a execução linha por linha.

01-breakpoint

Porém, embora a depuração com breakpoints seja uma tremenda mão-na-roda, ela nem sempre é suficiente.

Depuração Avançada

O Chrome disponibiliza através do console uma API de linha de comando que possibilita meios mais avançados para depuração. Vejamos algumas funcionalidades interessantes nos tópicos a seguir.

Monitorando eventos

Breakpoints funcionam bem, pelo menos até precisarmos depurar um caso mais complexo envolvendo eventos de teclado e mouse.

Imagine o cenário onde você está trabalhando em uma tela que outros desenvolvedores enfeitaram com vários scripts que usam eventos como mouse move, mouse up, mouse down, key up, key down, etc. Agora sobrou para você corrigir um bug em algum dos vários eventos.

Breakpoints podem não ser adequados para analisar o comportamento dos scriots, pois interromper a sua execução no meio de um evento acaba alterando o resultado final da execução, afinal outros eventos deixarão de ocorrer ou não acontecerão na sua sequência natural. Colocar logs em todos os eventos não é muito produtivo nem viável em alguns casos.

Para facilitar esta tarefa, a API do Chrome tem a função monitorEvents, que permite ao desenvolvedor listar os eventos que ocorrem em um objeto.

Um exemplo para capturar eventos do mouse na página é:

monitorEvents(document.body, 'mouse');

Após a execução deste comando, qualquer ação do mouse na página vai gerar um log no console.

02-console-monitor-events

Para desativar o monitoramento, execute o método unmonitorEvents com os mesmos argumentos de antes. Exemplo:

unmonitorEvents(document.body, 'mouse');

Listando manipuladores de eventos (listeners) associados a um objeto

Depurar uma página complexa é uma tarefa árdua. Em algumas situações, é quase impossível saber quais eventos estão associados a quais objetos. Uma função interessante da API de comandos do Chrome permite descobrir exatamente isso: getEventListeners.

O exemplo a seguir mostra os listeners associados ao documento:

getEventListeners(document);

03-listeners

Monitorando chamadas a funções

Outro caso onde breakpoints não resolvem é quando funções são executadas várias vezes em sequência. Neste caso, podemos monitorar cada chamada realizada a determinadas funções, inclusive quais argumentos foram passados, através da função monitor da API do Chrome. Basta passar o nome de uma função por parâmetro:

monitor(minhaFuncao);

Isso vai gerar um log para cada execução.

04-monitor

Para deixar de monitorar as chamadas, use a função unmonitor:

unmonitor(minhaFuncao);

Analisando o desempenho da aplicação

Você pode testar o desempenho da execução dos scripts através da aba Profile da ferramenta do desenvolvedor.

Entretanto, para testes mais específicos é interessante poder iniciar e parar a análise de consumo de CPU programaticamente. Isso pode ser feito através das funções profile e profileEnd.

Dessa forma, você pode analisar as execuções inclusive de forma intercalada:

profile("A");
profile("B");
profileEnd("B");
profileEnd("A");

05-profiles

Outros navegadores

Vale lembrar também que várias dessas funcionalidades de depuração não estão limitadas ao Google Chrome. Praticamente todos os navegadores modernos possuem uma API e um console onde você pode manipular a página.

O plugin Firebug tem uma API bem completa para depuração. Mesmo sem plugin, o Firefox disponibiliza uma API nativa. O mesmo vale para o Safari da Apple. Até o Internet Explorer tem vários métodos em sua API.

Já a API do Opera não parece contar com muitos comandos avançados, mas possui diversas utilidades.

Conclusões

Quem trabalha com front-end ou qualquer outra camada de um sistema web pode acabar, cedo ou tarde, tendo que consertar algum JavaScript.

Portanto, é sempre bom acompanhar a evolução das ferramentas de depuração de páginas web. Aprender as funcionalidades um pouco mais avançados certamente irá lhe economizar tempo e desgaste desnecessários.

Bons programadores escrevem código complexo?

Você já viu algum desenvolvedor se gabar de ter criado código difícil de ler? Talvez você já tenha se sentido o máximo ao fazer algo assim:

void Run( const std::string& v, int tgt, int start ) { for( ; tgt >= 2 * start + 1; ++start ) Run( v + ' ' + boost::lexical_cast( start ), tgt - start, start + 1 ); std::cout << v << ' ' << tgt << std::endl;} int main() { Run( std::string(), 10, 1 ); getchar();}

(Extraído de http://www.cplusplus.com/forum/lounge/13042/)

Código complexo é código ruim

spaghetti-code Bons programadores sabem que a complexidade é sua inimiga. Quando trabalhamos com software de verdade temos de lutar contra ela. A complexidade esconde erros, dificulta a leitura do código e inviabiliza a manutenção. Se nada disso lhe diz muita coisa, pense que o impacto vai diretamente para o seu bolso, principalmente para consultores e freelancers.

Você já precisou dar manutenção em código escrito por você mesmo há muito tempo e teve dificuldades em entender, além de ficar pasmo por ter escrito algo tão hediondo? Será que o cuidado ao produzir código no passado poderia ter lhe poupado de dificuldades e perda de tempo no presente? É claro que sim! E grande esperança há para você se for capaz, hoje, de fazer melhor que antes!

Código complexo é código ruim. Sua manutenção exigirá refatoração abrangente. Você já olhou um programa tão confuso que, antes de modificá-lo, preferia reescrevê-lo completamente?

“Ah, mas pra isso existem os comentários”, você pode argumentar. Não se precipite! Muitos irão lhe contradizer. Processos como o XP enfatizam a necessidade do código ser claro e auto-explicativo. Comentários são por vezes nossos inimigos. Eles podem nos enganar ao declarar algo que o código efetivamente não faz. Em excesso, poluem visualmente o código e tornam nossos fontes mais extensos.

Seja simples

Uma das abordagens para fugir da complexidade é o princípio conhecido como KISS: “Keep It Simple, Stupid!“. Em português poderia ser: “faça isto simples, seu estúpido!”

Resumirei alguns passos deste “programa de reabilitação para programadores”:

  • Seja humilde, não pense em si mesmo como um gênio.
  • Divida suas tarefas em sub-tarefas: não leve mais do que algumas horas para trabalhar em um código.
  • Aprenda muito bem sobre coesão, acoplamento e responsabilidades de classes e métodos.
  • Resolva o problema primeiro, codifique a solução em seguida.
  • Não tenha medo de descartar código.

Um engenheiro de software experiente deve saber usar as ferramentas à disposição para produzir o resultado desejado com o mínimo de complexidade e esforço. Por outro lado, programadores são apaixonados por “reinventar a roda”. Nos meus primeiros anos, pensava comigo: “para que aprender o framework X  se posso escrever o meu?!”. Já reescrevi muitos frameworks. Serviu-me de alguma coisa? Claro! Principalmente em ver minhas limitações e a importância do trabalho alheio!

Exemplo de simplicidade

Pense no cara da direita como você na faculdade e no da esquerda já com alguns anos de experiência.

Conclusão

Quem se importa se o programa leva alguns milissegundos a menos para executar ou se o código é mais “bonito”? O ego do programador?

Um profissional de TI maduro deve se esforçar para aperfeiçoar suas habilidades de comunicação. Isto independe de sua área de atuação, pois todos os artefatos do processo de desenvolvimento, incluindo o código, devem ter qualidade suficiente para cumprir o seu papel e transmitir a informação o mais efetivamente possível.

Além disso, é melhor guardarmos nossas habilidades artísticas para um concurso como o International Obfuscated C Code Contest:

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

Creative Commons O blog State of the Art de Luiz Ricardo é licenciado sob uma Licença Creative Commons. Copie, compartihe e modifique, apenas cite a fonte.