Começo a aprender Rust

Começo a aprender Rust

Neste final de semana comecei a estudar a linguagem de programação Rust. E para registrar o meu estudo, pretendo escrever alguns textos aqui, começando pelo motivo de ter escolhido esta linguagem, mas depois comentar o que estou achando e dificuldades que estou encontrando.

O principal motivo para eu escolher esta linguagem está ligando as principais linguagens que utilizo, sendo que existia um caso onde elas não atendiam. Para entender a necessidade vou listá-las.

De forma geral utilizo shell script (bash para ser mais específico) quando tenho que fazer automações, ou se já existe algum programa pronto, simplificar o seu uso. Sendo seu maior exemplo o Commit Rules, que permite executar comandos para validar o commit, onde leio o arquivo de configuração, executo alguns comandos e manipulo a saída e exit status dos mesmos.

Quando preciso desenvolver algo mais elaborado, opto pelo Python, que por ser uma linguagem bem geral e de rápido desenvolvimento, facilita bastante o meu trabalho, sendo desde programas em linha de comando, até aplicações web. Vou deixar aqui de exemplo o Deduplicated, que foi desenvolvido como uma biblioteca, tendo tanto uma interface por linha de comando, quanto web.

Porém Python não é uma linguagem que tem foco em performance, especialmente na versão 3. Este foi um dos principais motivos de algumas pessoas da comunidade Python ficarem de olho no Go, o que talvez seria o meu caminho, se tivesse tido necessidade de performance. Também cheguei a pesquisar sobre o Genie, porém por ser recente e a pouca documentação, fizeram eu a deixá-la de lado, até por nem ela, nem Vala terem tido um grande sucesso.

Tenho algum conhecimento de C, porém é mais teórico que prático, não tendo tanta confiança para escrever um software seguro nesta linguagem. Também já tentei estudar mais sobre algumas ferramentas, como Make e Autoconf, porém não encontrei bons materiais para o meu estudo.

Neste ponto encontrei Rust, que pode ser visto como uma alternativa ao C, porém verifica o acesso seguro a memória em tempo de compilação, aumentando minha confiança em escrever um software seguro. Ele também um tem gerenciador de pacotes, que pelos meus testes funcionou muito bem e sem espalhar vários arquivos pelo sistema inteiro, podendo ser excluídos ao apagar um único diretório.

Rust tem outras qualidades, porém esses dois pontos suprem minhas “dificuldades” do C. Se encaixando como uma opção de linguagem quando preciso de desempenho (tenho controle semelhante ao C, e sem garbage collector como outras linguagens), porém ainda é uma linguagem nova com recursos bem interessantes em suas expressões (comandos).

No próximo texto comentarei mais sobre materiais e primeiras impressões.

Remover arquivos duplicados

Há algum tempo, escrevi sobre o método que utilizo para fazer backup do meu hd externo. Porém quando comecei a utilizá-lo, tinha pouco mais de 500 GB de arquivos e muitos backups antigos, diretórios que quando iria formatava o computador, simplesmente olhava que faltava fazer backup de um diretório apenas, copiava-o inteiro, recuperar os arquivos mais importantes ou utilizados, enquanto os demais ficavam perdidos e ocupando espaço, mesmo já vindo de outro backup.

A questão é que eu tinha, pelo menos, uns seis backups, envolvendo formatação e cópias de pendrivers. Muitos desses arquivos estavam repetidos, significando que eu poderia deixar apenas uma cópia, apagando as demais e mesmo assim ter todos os meus arquivos.

O primeiro método que pensei foi gerar hash de todos os arquivos, e depois compará-los para encontrar duplicados, porém gerar hash de 500 GB é extremamente demorado e muitos desses arquivos não sobrem alterações, então não seria necessário recalcular toda execução. Olhando no sistema de arquivos, temos a informação de última alteração no arquivo, então bastava gerar um cache com informações de arquivo, hash e data da última alteração, toda vez que o for executado, poderia comparar primeiro a data de alteração e calcular o hash apenas se necessário.

Com o script pronto, a primeira execução foi demorada, uma vez que teria que calcular o hash dos 500 GB, levando algumas horas, encontrando 5 GB de arquivos que poderiam ser apagados sem que eu perdesse qualquer informação. Uma próxima execução foi muito mais rápida, não levando mais de dois minutos, desde que com modificações em arquivos pequenos.

Consegui logo apagar uns 2 ou 3 GB, porém a lista de arquivos duplicados, apesar de auxiliar no processo, não era algo muito prática, uma vez que teria que buscar o arquivo manualmente para apagá-lo. Com arquivos grandes o processo ia rápido, e liberava mais espaço, porém em arquivos de texto puro não dava um rendimento satisfatório. Como sou programador web, logo montei uma página para listar esses arquivos, com um checkbox para selecionar os arquivos que desejava apagar, deixando o processo todo muito mais prático. Hoje tenho menos de 5 MB de pequenos arquivos duplicados, que comparados aos 5 GB representa menos de 0,1%.

Reorganizei todo o código, aproveitando para montar uma interface web mais completa, e publiquei o código no github sobre licença MIT (https://github.com/eduardoklosowski/deduplicated), então quem quiser dar uma olhada, utilizar, ou até contribuir com o desenvolvimento do mesmo fique à vontade.

Uma explicação rápida para quem deseja utilizá-lo. Por ser escrito em Python, recomendo a instalação via pip com o comando pip install git+https://github.com/eduardoklosowski/deduplicated.git ou pip install git+https://github.com/eduardoklosowski/deduplicated.git#egg=deduplicated[web] caso deseje instalar as dependências da interface web. Com isto você terá o comando deduplicated, bastando utilizar os parâmetros update para atualizar o cache dos arquivos, duplicated para listar os arquivos duplicados ou check para atualizar o cache e exibir os arquivos duplicados, seguido de um ou mais diretórios que deseja verificar, exemplo deduplicated check /home/eduardo. Caso tenha instalado a interface web, basta executar o comando deduplicated-web e abrir o endereço http://127.0.0.1:5050/.

Também existe uma opção para verificar se um arquivo está no cache com o comando indir, exemplo deduplicated indir meuarquivo.txt /home/eduardo. A vantagem é que você não precisa ter os arquivos para fazer essa verificação, eu verificava se os arquivos do meu notebook estavam no hd externo desta forma, sem precisar estar com ele ligado.

Recentemente tive um problema com o meu hd externo, essa história está no hack ‘n’ cast (quando for publicado disponibilizo o link aqui). Como eu tinha o cache do meu hd externo, pude compará-lo com o meu backup, descobrindo o que não estava atualizado e se eu tinha perdido algo. Esse procedimento se resumiu a executar as funções de atualização do cache na manualmente para adaptar certas partes e listar determinados valores. Caso alguém deseje posso até montar o script como uma função extra.

Eu fiquei extremamente feliz ao conseguir economizar o espaço do meu hd externo, o que já valeu o programa. Quando tive problemas no hd externo, percebi que ter as coisas organizadas e automatizadas, podendo consultar alguns logs, torna tudo mais fácil e tranquilo, bastando efetuar o RMA e depois executar um rsync para resolver todo o problema, obviamente teve a parte de formatação e criptografia também.

Microframework contra “Baterias Incluídas”

Python é uma linguagem de programação que tem a fama existir mais frameworks web que palavras reservadas, isso se reflete em uma diversidade de opções para os mais diversos gostos. Talvez isso seja um reflexo da diversidade de pessoas que utilizam o Python para as mais diversas finalidades.

Quando iniciei no desenvolvimento web, comecei com PHP, da forma mais simples possível, montando cada página em arquivos separados com alguns includes para não repetir muito o código. Quando migrei para Python, o primeiro impacto foi ter que utilizar algum framework e não seguir a forma de cada página num arquivo, até poderia manter os arquivos utilizando CGI, mas não teria desempenho, ou escrever o WSGI diretamente, mas acabaria criando outro framework para facilitar o processo.

Comecei a aprender o Django, achei legal, porém foi complicado por ser muito diferente do que eu estava acostumado e passava mais tempo consultando a documentação que programando efetivamente. Com a filosofia de “baterias incluídas”, o Django tem incorporado bibliotecas para as funcionalidades mais comuns de uma página ou aplicação web pode precisar, como formulário, acesso a banco de dados relacionais, paginação, internacionalização…

Outra opção que temos é utilizar um microframework, que auxilie apenas no WSGI e utilizar outras bibliotecas para montar a base da aplicação, como no caso do Flask. Ele vem por padrão com outras bibliotecas, como o Jinja 2 para auxiliar a escrever o html das páginas e caso precise de banco de dados ou formulários, basta instalar alguma biblioteca como o SQLAlchemy e o WTForms.

A primeira coisa que pode ser notada ao comparar esses dois modelos é a complexidade, com certeza um microframework é mais simples e fácil de aprender, uma vez que você está focado apenas em como interagir com o servidor ou protocolo HTTP, não tem que se preocupar com banco de dados por exemplo.

O primeiro ponto contra o microframework é a necessidade do programador conheçer ou procurar outras bibliotecas para partes específicas da aplicação, como persistência de dados. Muitas vezes isso pode levar ao desenvolvimento de algo que já está pronto e disponível por desconhecimento. Porém o programador não fica restrito ao que o framework suporta, podendo adotar qualquer tipo de biblioteca, diferente do Django que por exemplo não suporta oficialmente nenhum banco NoSQL, é possível utilizá-los, porém você não conseguirá integrá-los nativamente com os models e forms. Além de que utilizar algum framework específico pode aproveitar melhor as funcionalidades de um banco de dados, em vez de funções genéricas suportada por todos.

Por outro lado, uma vantagem de você ter um framework que define as bibliotecas é a possibilidade de integração das mesmas, como no caso do Django, com um model escrito, é extremamente fácil criar um form baseado no mesmo, com validação, ou fazer a migração do esquema da tabela no banco sem precisar escrever tudo na mão ou duplicar o código e lógicas. Também não é necessário sair procurando bibliotecas na internet, e você terá tudo em apenas uma documentação, que na hora de buscar ajuda evita respostas do tipo com a biblioteca tal funciona ou ter que conhecer mais de uma biblioteca que fazem a mesma tarefa para decidir qual das duas utilizar.

Microframeworks e “baterias incluídas” são abordagens opostas, cada uma pode se sair melhor que a outra de acordo com o caso. Se você tiver que desenvolver um sistema que necessite de bibliotecas que o Django oferece e se encaixe na forma dele de resolver os problemas, com certeza é uma ótima opção, uma vez que você terá as bibliotecas integradas e tudo pronto para utilizar. Caso o sistema seja mais simples, não necessitando de todas as bibliotecas oferecidas pelo Django, ou tenha necessidades mais específicas, o Flask começa a ganhar vantagens, uma vez que o fato de ser reduzido pode deixá-lo mais leve ou até ter uma configuração inicial mais rápida.

Com certeza tem o conhecimento das duas abordagens é importante na hora da decisão do framework, nada pior que durante o desenvolvimento o framework ficar atrapalhando, por ele não ter foco para um determinado fim, ou ser tornar burocrático demais para coisas simples. Para quem estiver conhecendo um framework como o Django e acha que algumas coisas seriam mais práticas fazer na mão, tente visualizar todo o processo, que em algum ponto será facilitado por ser desta forma ou mais prático, porém vai necessitar de algum tempo para acostumar.

MX Reverse e escolhas de frameworks

Se alguém deu uma olhada recentemente no meu GitHub, pode ter visto um repositório chamado mxreverse, que é um site que desenvolvi para validar o DNS reverso de servidores de e-mail. Apesar do código ser simples, tomei algumas decisões que gostaria de compartilhar.

Primeiramente a linguagem escolhida foi Python principalmente por ser a qual tenho mais domínio e facilidade, também achei uma biblioteca para fazer as pesquisas do DNS, possibilitando o desenvolvimento. Inicialmente pensei em criar uma função para fazer a validação com algumas funções auxiliares, que depois de alguns testes e tempo de desenvolvimento estava pronta.

Agora até aqui foi algo bem normal do qualquer projeto. Porém como disponibilizar esta função? Como utilizei uma biblioteca externa, além do meu código seria necessário também instalá-la para executar local, ou poderia disponibilizar um webservice, que possibilitaria reutilizá-lo com linguagens também. Como o código é Python, a forma mais simples, e provavelmente a mais recomendada é usar a especificação do WSGI, sendo uma única página, com apenas um parâmetro (o domínio a ser verificado), retornando um JSON, não tive necessidade de utilizar outros frameworks. Apesar de conhecer e gostar de Django e Bottle, o projeto não teria vantagens ao utilizar qualquer um dos dois, além de possibilitar fazer algo mais otimizado e simples sem um framework no caminho.

Com a API definida e funcional, era necessário um cliente que consuma a API e mostre as informações, caso contrário perderia a praticidade que gostaria, exigindo que cada um desenvolvesse seu código. Com as atuais aplicações em JavaScript no navegador, interessei me pela ideia de fazer uma página estática, utilizar AJAX para comunicar com a API e JavaScript para mostrar a resposta. Um framework JavaScript que tinha vontade de testar a algum tempo e aproveitei para fazê-lo neste projeto é o AngularJS. A principal ideia é atualizar um template HTML a partir de variáveis do JavaScript, ou seja, bastava ler o JSON e guardá-lo numa variável que o resultado seria mostrado na página.

O mais importante deste projeto é que mesmo que você conheça e goste de algum framework, ele pode não ser o melhor para a aplicação que está sendo desenvolvida. Abandonei a montagem do HTML em Python, passando para o JavaScript, deixei o código no servidor muito mais simples e aproveitei para conhecer outra forma de desenvolver aplicações, que poderei reutilizar em outros projetos onde ela se adapte melhor.

Resumo saia de sua zona de conforto, conhecer outros frameworks, por mais que superficialmente, pode ajudar na hora de montar uma aplicação, escolhendo uma arquitetura mais adequada.