O Melhor da Internet…

… pelo menos na minha opinião 🙂

Desde criança fui uma pessoa curiosa. Na época eu era chamado de “nerd” ou de “CDF” (pra ser nerd hoje basta gostar de Star Wars).

Procurar informações para satisfazer essa curiosidade nos anos 80 significava garimpar informações como um mineiro procura por ouro. A gente usava bancas de revistas, bibliotecas, sebos, livrarias, televisão, rádios, etc. E boa parte disso só estava disponível para quem podia pagar.

Mesmo sendo trabalhoso era bem divertido e gratificante buscar informações desse jeito. A gente ia atrás das informações e não o contrário.

Online: information overload

A primeira vez que consegui uma informação no mundo digital foi via BBS. Fiquei superfeliz por encontrar a lista de interrupções do Ralf Brown. Uma BBS tem toda informação que cabia em alguns CDROMs no computador do dono da BBS e isso já era muito mais do que um ser humano curioso podia lidar.

Quando tive contato com a Internet, com os buscadores (Cadê?, Yahoo!, …) e, posteriormente, com os feeds a coisa saiu do controle. Hoje eu tenho na minha lista de leitura uma quantidade de conteúdo suficiente para consumir durante toda minha vida. E a coisa não para de crescer.

Hoje eu assino vários feeds, sigo várias pessoas importantes, assino muitas newsletters e uma boa fila de livros para ler… o volume de informações que chega é absurdo e, por causa disso, precisei criar algumas regrinhas para melhorar a gestão disso tudo.

Gestão de consumo de informação

Uso três técnicas para me ajudar nessa tarefa: filtragem humana, fila de leitura, deduplicação e priorização por pares.

Filtragem humana

A quantidade de informação para ser consumida cresceu de modo tão intenso que precisei criar mecanismos para filtrar só aquilo que fosse relevante. E é aí que o bicho pega. Se antigamente era difícil garimpar informação na escassez o mesmo se mostrou muito mais difícil na abundância.

Alguns sistemas digitais até te ajudam nessa tarefa (ex. buscadores) mas nada supera os sistemas de “computação humana” (Human Computation).

Quando o Google Reader existia e tinha a funcionalidade de compartilhar artigos entre os seus usuários comecei a implementar um tipo de “filtragem humana”. Descadastrei de vários feeds que meus amigos acompanhavam e passei a ler apenas o que eles compartilhavam. Exemplo: eu assinava o feed do XKCD junto com outros colegas e eles viviam compartilhando as melhores tirinhas. Descadastrando o feed e seguindo esses colegas eu teria disponível só às melhores tirinhas e controlaria o aumento da minha fila de leitura.

Hoje eu faço isso com o Twitter. Dou follow em amigos que seguem sites importantes e sigo alguns sites importantes para compartilhar o conteúdo com eles. O interessante é que ninguém planejou isso. Foi algo criado organicamente.

Outra forma de filtragem humana é a “editorial”. Alguém muito bem informado ou comunidades se reunem para determinar a relevância das informações.

Os sites que melhor trabalham isso em comunidades são os agregadores (ex. Hacker News, Reddit, …) e sites de QA (ex. StackOverflow, Quora, …). Já as pessoas que fazem esse trabalho de forma individualizada, geralmente, usam blogs ou newsletters.

Fila de leitura

Não dá pra parar para ler todas as coisas interessantes que aparecem no momento que elas aparecem. Digo mais: não dá nem para avaliar se essas coisas são importantes ou não. Então eu faço o básico: mando o link direto para minha fila de leitura.

Uso o Instapaper como ferramenta para gerenciar essa fila mas também tem o Pocket. Acho que o Pocket é tecnicamente melhor mas o importador deles é uma porcaria e como o Instapaper me atende satisfatoriamente continuo com eles.

Tenho Instapaper no celular e usava a funcionalidade de exportar para Kindle (parei porque o kindle também já está entupido de coisas pra ler).

A tática para manter a lista de leitura em um tamanho administrável é: algumas vezes por semana tenho como objetivo ler mais artigos do que adicionei desde a última pausa para leitura.

Nem sempre é possível cumprir essa meta e o resultado é que tenho aproximadamente 400 artigos para ler.

Deduplicação

Se percebo que uma fonte de informação está só duplicando informações que já chegaram até mim por outras vias eu reavalio esse canal. Se o nível de duplicação que ele acrescenta é grande eu simplesmente desligo esse canal.

Priorização por pares

Eu priorizo a leitura do conteúdo pelo número de pares (pessoas) que recomendaram o mesmo material. Exemplo: três amigos cuja opinião literária eu respeito muito indicaram o mesmo livro (ebook). Isso e o fato de que Ridley Scott está fazendo um filme com a história desse livro obviamente fizeram eu comprá-lo e começar a ler.

O Melhor da Internet

Com esse método acabo esbarrando em coisas muito interessantes que acabo compartilhando no meu Twitter. Mas para facilitar a vida das pessoas resolvi criar uma newsletter: O Melhor da Internet.

Agora você pode me usar como filtro humano 😀

Quinzenalmente farei um resumo contendo links e uma breve descrição dos melhores artigos e sites que vi desde que comecei a usar a internet. Vou priorizar material recente mas posso incluir coisas antigas que sejam relevantes. Esse resumo será enviado para o email dos assinantes que se cadastrarem no formulário abaixo.

Os tópicos principais serão:

  • Programação – Python, Django, Web, TDD, …
  • Empreendedorismo – side-project, bootstrap, lifestyle business, passive-income-de-verdade, …
  • Carreira – produtividade, boas práticas profissionais, …
  • “Off-topic” – DIY/eletrônica, retrocomputação, jogos, tirinhas, …

[mc4wp_form]

O plano é publicar a primeira edição sai no dia 21 de julho de 2014.

Foto: lecates

A Web e o problema das senhas “clear text”

Nos últimos dias o serviço Trapster avisou que 10 milhões de senhas dos seus usuários poderiam estar comprometidas. No ano passado a rede de sites de notícia Gawker passou pelo mesmo problema por um problema parecido.

E se formos voltar no tempo vamos descobrir que todo ano temos pelo menos 2 ocorrências similares em sites grandes. E isso vem acontecendo ano após ano desde que a Internet se tornou acessível entre “civis”.

Se todos os usuários usassem senhas diferentes para cada um dos serviços que usa na internet o estrago causado por esse tipo de situação seria bastante limitado. Mas não é isso o que acontece e, quando senhas “vazam” na internet o estrago pode ser gigantesco.

Problema antigo. Solução conhecida.

Em 1994 fui fazer estágio na Telesp no interior de São Paulo. Lá eu tive meu primeiro contato “sério” com um Unix. Era um SCO Unix que rodava num 386SX com 7 terminais seriais.

Enquanto eu estava aprendendo a usar o Unix eu vi que tinha um arquivo chamado /etc/passwd e, pelo nome, imaginei que lá eu encontraria as senhas de usuários do sistema.

Naquela época eu era “metido a hacker” e fiquei entusiasmado com a idéia de descobrir a senha de todo mundo que usava aquele servidor. Fiquei mais animado ainda quando vi que as permissões do arquivo permitiam que qualquer usuário examinasse seu conteúdo.

Quando abri o arquivo veio a decepção… no lugar onde deveriam ficar as senhas estava um “x”. Mas não me dei por vencido. Após estudar as manpages (que viam impressas em manuais imensos!) fiquei sabendo que as senhas não estavam lá. Elas estavam no arquivo /etc/shadow.

Com o ânimo renovado fui atrás desse arquivo. Mas dessa vez as coisas estavam um pouquinho mais difíceis… só o usuário root conseguiria ver esse arquivo.

Chegou a hora, então, de uma pitada de engenharia social… não vou contar como fiz porque foi muito fácil mas consegui a senha de root do sistema… hora de ver a senha dos outros usuários da Telesp e implantar uma mega-revolução na telefonia brasileira!… erm… menos…

Quando abri o arquivo tomei uma ducha de água fria definitiva. No lugar onde as senhas deveriam estar eu só um amontoado de caracteres que não se pareciam com senhas. Até poderiam ser as senhas dos usuários mas parecia muito improvável (e de fato não eram).

Descobri depois que o que estava armazenado ali era o resultado de uma espécie de “criptografia”. Ou seja, em 1992 os sistemas Unix já não armazenavam as senhas em texto puro. É bem provável que eles já não fizessem isso a muito mais tempo.

Estamos em 2011. Se depois de 19 anos eu armazenasse as senhas dos meus usuários em “texto puro” eu deveria ser chamado de irresponsável e incopetente. Se um invasor tivesse acesso à essas senhas eu deveria ser tratado como criminoso. No mínimo.

A solução

A única solução correta e infalível para armazenar senhas de forma segura é: não armazená-las.

Aí você deve estar perguntando: se eu não armazenar a senha do usuário como eu consigo verificar a senha dele durante sua autenticação?

Uma resposta “básica” seria: armazene o hash da senha.

Segundo o HowStuffWorks brasileiro:

“Hash é resultado da ação de algoritmos que fazem o mapeamento de uma seqüência de bits de tamanho arbitrário para uma seqüência de bits de tamanho fixo menor de forma que seja muito difícil encontrar duas mensagens produzindo o mesmo resultado hash (resistência à colisão ), e que o processo reverso também não seja realizável (dado um hash, não é possível recuperar a mensagem que o gerou).”

Existem vários algorítmos para cálculos de hash. Cada um deles possui um determinado tipo de aplicação. As funções de hash mais “famosas” são aquelas cuja aplicação está no campo da criptografia: MD2, MD4, MD5, SHA1, SHA256, …

Vou demonstrar o que acontece com o MD5:

$ echo "123mudar" | md5sum
642d8860fc6fe3126803ebdbe9974abd
$ echo "123mudar" | md5sum
642d8860fc6fe3126803ebdbe9974abd
$ echo "123mudor" | md5sum
fe294bbc902c287efb7acb20c8fdb67a

Note que sempre obtemos o mesmo resultado quando a senha é a mesma mas quando mudamos 1 único caracter o resultado do cálculo de hash muda completamente.

Tendo isso em mente podemos pensar em armazenar no nosso banco de dados apenas o hash da senha do usuário. Quando for preciso verificar a senha informada pelo usuário aplicamos a função de hash à ela e comparamos com aquela que está armazenada no banco de dados.

Perfeito não é? Problema resolvido, não? Não! Ainda falta uma pitada de “sal” nessa receita…

Salt – mais uma dificuldade para o invasor

Vamos supor que um invasor tenha acesso ao banco de dados da aplicação e ao hash das senhas…

Com esses hashes o usuário pode disparar um ataque baseado em dicionários ou até mesmo procurar pelos hashes no Google! Veja o que acontece com uma senha “fraca”:

$ echo "senha" | md5sum
6fd720fb42d209f576ca23d5e437a7bb

Agora procure por “6fd720fb42d209f576ca23d5e437a7bb” no Google e veja o resultado 😀

Para resolvermos esse problema devemos usar um “salt” para gerar o hash da senha.

Salt é uma sequência aleatória de bits que são concatenados à senha do usuário antes de gerar o hash (quanto maior essa sequência mais difícil será o trabalho do invasor).

Por ser uma sequência aleatória precisamos armazená-la junto com o resultado do hash para ser possível verificar a senha depois. Vamos à um exemplo “pythonico”

$ python
>>> import random
>>> import hashlib
>>> senha = "senha"
>>> salt = ''.join(chr(random.randint(65, 122)) for x in range(5))
>>> salt # Esse é o Salt!
'vGBAA'
>>> salt_senha = salt + senha
>>> salt_senha # salt + senha
'vGBAAsenha'
>>> hash = hashlib.md5(salt_senha).hexdigest()
>>> hash # Esse é o hash do salt+senha
'3607507cfa3f31b0cf10e83af947df97'
>>> armazenar = salt + "$" + hash
>>> armazenar
'vGBAA$3607507cfa3f31b0cf10e83af947df97'

Tente procurar pelo hash “3607507cfa3f31b0cf10e83af947df97” no Google agora… ou submeter esse hash à um ataque de dicionário… Você verá que aumentamos um pouco a dificuldade para descobrir a senha do usuário.

Esse é o procedimento usado por grande parte dos frameworks web que implementam alguma forma de armazenamento de senha (ex. django.contrib.auth) (ver atualizações 2 e 3). Ele é bastante seguro e podemos considerar isso satisfatório. Mas as coisas estão mudando…

A nuvem “do mal”

Com o advento da “computação na nuvem” chegamos à situação onde podemos comprar “poder de processamento” tal como compramos energia elétrica.

Antigamente se a gente tivesse um salt+hash em mãos era quase impossível (ou economicamente inviável) conseguir poder de processamento suficiente para submetê-los à um ataque de força bruta.

Mas as coisas mudaram e com 1 cartão de crédito e uma quantidade “viável” de dinheiro é possível contratar dezenas de “nós” de processamento na Amazon ECS, por exemplo, e colocá-los para “atacar” o nosso salt+hash.

Esse tipo de prática provavelmente já está sendo usada por alguns invasores pelo mundo e aparentemente não existe uma solução definitiva para esse tipo de situação.

O que existe são medidas que você pode adotar para dificultar um pouco mais a vida dos vilões 😀

Uma delas é substituir o algoritmo de hash (MD5/SHA1) por outro algorítmo mais apropriado para o nosso uso.

O problema em usar os algorítmos MD5 e SHA1 para calcular os hashes de nossas senhas é que eles são muito eficientes e rápidos. As principais aplicações desses algorítmos exigem que eles sejam rápidos (ex. assinatura digital de um arquivo gigantesco).

Como eles são muito rápidos é possível disparar um ataque de força bruta e testar muitos hashes em um curto espaço de tempo. Como as plataformas na “nuvem” cobram por tempo de uso podemos quebrar uma senha à um custo relativamente baixo (ou viável economicamente).

Se trocarmos esses algorítmos por um que seja muito mais lento obrigamos o invasor a gastar mais poder de processamento (e consequentemente mais dinheiro) para descobrir nossa senha.

Um dos métodos mais indicados, hoje, é o bcrypt (blowfish). Existe implementações desse algorítmo para diversas linguagens:

E como eu sei se um site armazena minhas senhas em texto puro?

Não é possível saber com 100% de certeza se um site ou serviço armazena as suas senhas em “texto puro”, portanto, o melhor mesmo é criar o hábito de usar senhas diferentes em cada um dos serviços (só tente não anotá-las em papéis! :D).

Mas apesar de não ser possível ter certeza se o serviço em questão é desenvolvido por um irresponsável é possível buscar indícios dessa irresponsabilidade:

  • Receber um e-mail de confirmação de cadastro onde sua senha está presente – Se ele está te mandando um e-mail com sua senha é grande a possibilidade dela ser armazenada da mesma forma.
  • Use a opção “esqueci minha senha” dos sites para testar – se você usar essa opção e o site te mandar um e-mail (ou mostrar na tela) a sua senha é porque eles tem a sua senha “original” armazenada em algum lugar. O correto é receber um link para *resetar* sua senha.

Implicações no “mercado”

Nós que trabalhamos com web e somos entusiastas da idéia “da nuvem” devemos condenar a prática de armazenar dados sensíveis do usuário de forma tão irresponsável. Cada notícia que surge dando conta de vazamentos dessas informações prejudica todos os serviços. Para um leigo é a segurança “da internet” que é falha.

Se você é um empresário ou desenvolvedor sério e responsável deve cuidar da segurança dos dados dos seus usuários com todo o cuidado e, sempre que ver outra empresa trabalhando de outra maneira você tem a obrigação de condená-la pois ela também está, indiretamente, prejudicando o seu negócio.

Atualização:

O meu amigo Guilherme Manika postou um link para um artigo onde a equipe do Gawker relata o problema ocorrido com as senhas de seus usuários.

Pelo que entendi eles armazenavam o hash das senhas usando a função crypt(3) e um salt com apenas 12 bits que, como disse, é muito pouco para os padrões de ataque atuais.

Então, em 2008, eles modificaram o sistema para usar o bcrypt() também. Mas, aí a ‘burrada’ deles: eles continuaram gerando o hash com crypt(3) e armazenando no mesmo lugar que os hashes bcrypt() pra manter compatibilidade retroativa!

Segundo um e-mail que circulou numa lista de segurança, 748.081 usuários tinham as senhas armazenadas com crypt() e 195.178 tinham as senhas armazenadas com crypt() e bcrypt(). Total: 943.259 usuários afetados. Quase um milhão de pessoas.

Atualização 2:

O framework Django, ao contrário do que disse, não usa bcrypt() para gerar o hash das senhas armazenadas. No lugar disso ele usa os algoritmos PBKDF2 + SHA256 conforme recomendações do NIST (pdf). Eles também usam outras técnicas complementares para tornar o sistema mais seguro como um comparador de strings em tempo constante.

Atualização 3:

O artigo faz muitas referências à bcrypt() que era o algoritmo recomendado pela maioria dos especialistas na época em que esse artigo foi escrito. Acontece que nesse mundo da tecnologia as coisas vão evoluindo e melhorias vão sendo sugeridas. Apesar disso o uso de bcrypt() é “bom o suficiente” e, por isso, manterei o texto original.

Caso você queira seguir as recomendações mais recentes o melhor é usar PBKDF2+SHA256 (+ algoritmos de comparação de strings em tempo constante) conforme indicado na Atualização 2 acima.

Se você se interessa pelo assunto, quiser se aperfeiçoar e consegue se virar bem com o inglês eu recomendo o curso (gratuito) de Criptografia de Stanford no Coursera.

Tutorial Linux – Parte 1

Tutorial Linux

Esse tutorial é dividido em várias partes e elas podem ser vistas na página Tutorial Linux.

Capítulo 1.UNIX

O UNIX tem uma história interessante que estaremos contando agora. É uma história de mais de 25 anos que foi iniciada nos laboratórios Bell da AT&T, nos EUA, como um passatempo de um dos jovens pesquisadores que trabalhavam lá então. Hoje o UNIX roda nos mais importantes servidores do mundo e faz parte do alicerce da estrutura sobre a qual a Internet funciona.

Nos idos de 1970 o M.I.T., a General Electric e o Bell Labs iniciaram o desenvolvimento do sistema operacional MULTICS (MULTiplexed Information and Computing Service) que trazia diversas inovações, como um sistema de arquivos hierárquico e controle de permissões por arquivo. Entretanto esse trabalho foi se mostrando um grande ‘elefante branco’ e isso fez com que o Bell Labs se retirasse do projeto obrigando um dos pesquisadores envolvidos no projeto, Ken Thompson, a procurar algo mais ‘útil’ para fazer.

Ele resolveu então iniciar o desenvolvimento de uma versão menos ambiciosa do MULTICS em linguagem assembly para um PDP-7 que estava esquecido num canto do laboratório. Quando Brian Kernighan viu o projeto em andamento resolveu batizá-lo de UNICS (UNIplexed Information and Computing Service) como uma brincadeira com o MULTICS. O nome foi posteriormente adaptado para UNIX.

O projeto começou a ficar tão bom que ganhou a participação de outro cientista, Dennis Ritchie. Nessa época eles portaram o UNIX para versões mais modernas dos PDPs. Como ele era todo desenvolvido em linguagem assembly era necessário reescrever grandes quantidades de código para cada versão nova do trabalho. Foi então que Brian Kernighan e Dennis Ritchie resolveram criar uma nova linguagem de programação baseada em B e BCPL que foi denominada C para que pudessem desenvolver o UNIX nela.

Nessa época a AT&T enfrentava um ação de monopólio na justiça que a impediu de vender software. Isso fez com que ela distribuisse livremente os códigos para as universidades americanas formando assim um ambiente de desenvolvimento de software semelhante ao que vemos hoje com o Linux. Nas universidades americanas, o UNIX ganhou muitos dos recursos que o tornaram popular, como uma pilha de rede TCP/IP e memória virtual paginada.

Essa divisão do desenvolvimento entre a AT&T e as universidades americanas gerou uma das grandes cisões do mundo UNIX. Cada sistema UNIX tem pequenas diferenças, mas eles estão agrupados em duas famílias maiores. São elas a família do System V , formada por sistemas derivados do código da AT&T, e a família BSD, formada pelos sistemas derivados do UNIX da Universidade da Califórnia em Berkeley (BSD significa Berkeley Software Distribution). Como exemplo de sistema que seguiu o estilo System V temos o HP-UX, e como exemplo de um sistema BSD temos o SunOS. Essa grande divisão foi quase fechada com o tempo, na medida em que os sistemas acabaram adquirindo os recursos uns dos outros, mas até hoje essa diferença se manifesta em coisas tão simples quanto os parâmetros que um comando aceita.

De qualquer forma, o norte do desenvolvimento do UNIX é a filosofia KISS (Keep It Simple, Stupid!). Se você for desenvolver uma ferramenta para editar textos, ela deve editar textos; deixe a função de planilha pra algum outro aplicativo. No UNIX, cada programa realiza uma tarefa, e realiza essa tarefa bem. Há maneiras bem simples de realizar a integração de diversos aplicativos pequenos e eficientes para realizar as operações que o usuário precisa. Há mais de 25 anos, com a filosofia KISS, sistemas UNIX têm servido bem a função de prover uma plataforma sólida e eficiente para os mais diversos problemas computacionais.

1.1. Estrutura

O UNIX é um sistema operacional multiusuário, multitarefa desde o seu projeto. Ele é organizado em camadas de abstração de hardware como ilustrado na figura abaixo:

Camadas dos Sistemas Unix

Camadas de um sistema Unix

O tema desse livro é o desenvolvimento em shell script, entretando é interessante analisar essa divisão para sabermos exatamente onde estaremos trabalhando.

1.1.1. Kernel

Um dos princípios básicos de um sistema operacional moderno é o de criar uma camada de abstração do hardware, possibilitando que ao desenvolvedor de aplicações não se preocupar com o funcionamento específico de cada um dos modelos de hardware disponíveis no mercado. A aplicação irá solicitar um recurso do sistema operacional e ele é quem irá instruir o hardware corretamente através dos drivers de dispositivos.

O kernel é o núcleo dos sistemas operacionais UNIX. Ele que é reponsável por gerenciar a memória, gerenciar os processos que estão rodando, acessar os discos, passar informações para os drivers de dispositivos, entre outras coisas. A quantidade de tarefas que o kernel de um sistema executa pode variar de sistema operacional para sistema operacional.

1.1.2. Nível de usuário

Nesse nível é onde os aplicativos do sistema rodam. Nessa camada não é permitido fazer acesso direto ao hardware e nenhuma operação sem a permissão do kernel. É nessa camada que é executado o interpretador de comandos do sistema operacional UNIX, o shell.

1.1.3. Shell

O shell é o interpretador de comandos que recebe instruções do usuário e as executa. É a primeira coisa que o usuário vê quando entra no sistema. Além disso, o shell é uma linguagem de programação completa, permitindo que o usuário automatize tarefas da mesma forma que as executaria na linha de comando.

1.2. Conceitos

Vamos agora conhecer as características que são típicas de um sistema UNIX.

1.2.1. Processos

Todas as aplicações que rodam sob um sistema UNIX terão um ou mais processos. Sempre que executamos um programa na linha de comando, o shell irá enviar uma solicitação para que o kernel do sistema execute esse programa e dê a ele uma identificação de processo (PID – Process IDentification). Esse programa automaticamente irá se transformar num processo ‘filho’ do shell que o executou.

Como o UNIX é um sistema multitarefa, ele permite que vários programas sejam executados ao mesmo tempo na máquina, utilizando uma técnica de scheduling para ‘dividir’ o tempo que a CPU vai utilizar para executar cada um dos programas carregados em memória. Os UNIX possuem mecanismos que permitem que você dê mais prioridade a determinados processos fazendo com que o scheduling dedique uma fatia maior de tempo para essa aplicação. O comando que controla esse recurso é o nice. Para listar os processos rodando no sistema, seus PID s e outras informações adicionais, rode ps -ef.

1.2.2. Usuários e Grupos

O UNIX é um sistema multiusuário. Para gerenciar essa característica do sistema foi criado um mecanismo de contas de login. Cada usuário normalmente possui uma conta para usar o sistema. Quando uma conta de usuário é criada, o sistema atribui um número de identificação a esse usuário (o UID). Além disso, os sistemas UNIX possuem uma conta denominada root que é usada para administração do ambiente. O UID do root é reservado e especial, sempre igual a zero.

Essas contas também são organizadas em grupos. Cada grupo recebe um número que o identifica (o GID). Podem existir grupos vazios, que não possuem nenhum usuário, e grupos com diversos usuários. Cada usuário deve pertencer a um grupo principal e pode participar de outros grupos secundários.

Os usuários dos sistemas UNIX normalmente estão cadastrados no arquivo /etc/passwd. A estrutura desse arquivo é a mostrada abaixo:

$ cat /etc/passwd
root:*:0:0:Administrator:/:/usr/bin/ksh
fulano:*:101:101:Fulano de Tal, RH, 555-1234:/home/fulano:/usr/bin/ksh
$ _

Os campos são separados por ’:’ e organizados da seguinte maneira:

  1. Login – nome da conta do usuário. Deve possuir no máximo 8 caracteres e não deve conter símbolos.
  2. Senha – Senha criptografada do usuário. Em sistemas mais modernos a senha é armazenada criptografada em um arquivo legível apenas pelo administrador do sistema.
  3. UID – Identificação do usuário. Note que o UID do usuário root é 0.
  4. GID – Identificação do grupo principal do usuário.
  5. Descrição – Dados do usuário.
  6. Home – Diretório que será o $HOME do usuário.
  7. Shell – Qual será o shell que o usuário irá usar. Não é necessário que seja um shell, se for especificado outro programa aqui, este será executado logo que o usuário efetuar o login e retornará à tela de solicitação de login imediatamente após o término da aplicação.

Os grupos do sistema estão relacionados no arquivo /etc/group. Esse arquivo tem o seguinte aspecto:

$ cat /etc/group
users::100:fulano, cicrano, beltrano
$ _

O arquivo acima diz que os usuários ’cicrano‘, ’fulano‘ e ’beltrano‘ pertencem ao grupo ’users‘ cujo GID é 100. Note que esses usuário tem o grupo ’users’ como grupo secundário, e não primário. O grupo primário de cada um dos usuários é especificado no arquivo /etc/passwd.

1.2.3. Diretórios, Arquivos e dispositivos

O sistema de arquivos do UNIX possui diretórios, arquivos e dispositivos. Cada um deles possui atributos especiais que informam quais as permissões de acesso ao arquivo, quais os usuários que são donos desses arquivos, tamanho, data de criação e nome do arquivo. Você pode visualizar essas informações com o comando ls -l que terá uma saída como abaixo:

$ ls -l
total 0
-rw-rw-rw-  1  nobody  nobody       0  Dec 5  12:27  arquivo
brw-r--r--  1  root    root    0,   0  Dec 5  12:28  device
drwxrwxrwx  2  nobody  nobody      35  Dec 5  12:27  diretorio
-rwxrwxr-x  1  nobody  nobody       0  Dec 5  12:29  script.sh
$ _

Como você pode observar o comando ls -l mostra o conteúdo do diretório e os atributos dos arquivos organizados em colunas. Na primeira coluna podemos ver o mapa de bits com as permissões dos arquivos. A primeira letra desse mapa de bits indica qual o tipo do arquivo, os outros caracteres são agrupados de três em três indicando as permissões conforme a tabela abaixo:

Tipo Dono Grupo Todos
- - - - - - - - - -
d r w x - - - - - -
- r w - r - - r - -
l r w x r w x r w x

Tabela 1.1: Mapa de bits de permissão.

O dono do arquivo e o grupo ao qual ele pertence estão nas colunas 3 e 4 respectivamente. Cada uma das letras acima informa um determinado tipo de permissão conforme mostra a tabela abaixo:

Permissão Octal Significado
0 - - - Nenhuma operação permitida.
1 - - x Permitido apenas execução.
2 - w - Permitido apenas gravação.
3 - w x Permitido gravação e execução.
4 r - - Permitido apenas leitura.
5 r - x Permitido leitura e execução.
6 r w - Permitido leitura e gravação.
7 r w x Permitido leitura, gravação e execução.

Tabela 1.2: Permissões.

Existem outras permissões interessantes cujas implementações variam de UNIX para UNIX, a tabela abaixo mostra algumas delas. Elas serão explicadas com mais detalhes com os comandos chmod e chown.

Atributo Descrição
s SUID/SGID bit.
t Sticky bit.

Tabela 1.3: Outras permissões.

Além das permissões existe o caractere que informa qual o tipo do arquivo. A tabela abaixo mostra cada uma delas:

Atributo Tipo
- Arquivo normal.
d Diretório.
l Link simbólico.
c Dispositivo de caracter.
b Dispositivo de bloco.
p Filas (named pipes).

Tabela 1.4: Tipos de arquivos.

Além de arquivos e diretórios, que são as estruturas mais básicas de um sistema de arquivos existem outros tipos especiais de arquivos aos quais vamos dar uma atenção especial:

Links

Os links simbólicos, ou soft links, são utilizados para apontar para arquivos localizados em outros subdiretórios. Se o link é removido acidentalmente, o arquivo para o qual ele apontava permanece intacto. Se o arquivo original é removido, o link simbólico irá continuar apontando para o mesmo lugar e será inválidado (muito conhecido como link quebrado).

Além dos soft links existem também os hard links que são arquivos normais que possuem o mesmo ponto de entrada dos arquivos originais. Os arquivos com hard links são identificados pelo número da segunda coluna do comando ls -l (contador de referência) que será diferente de 1.

$ ls -l
total 1
-rw-rw-r--  3  osvaldo  osvaldo   0  Dec 5  15:39  arquivo_original
-rw-rw-r--  3  osvaldo  osvaldo   0  Dec 5  15:39  hardlink_1
-rw-rw-r--  3  osvaldo  osvaldo   0  Dec 5  15:39  hardlink_2
lrwxrwxrwx  1  osvaldo  osvaldo  16  Dec 5  15:39  softlink_1 -> arquivo_original
$ rm hardlink_2
$ ls -l
total 1
-rw-rw-r--  2  osvaldo  osvaldo   0  Dec 5  15:39  arquivo_original
-rw-rw-r--  2  osvaldo  osvaldo   0  Dec 5  15:39  hardlink_1
lrwxrwxrwx  1  osvaldo  osvaldo  16  Dec 5  15:39  softlink_1 -> arquivo_original

Notem que o contador de referência mostra quantos hard links apontam para o mesmo arquivo. Agora vamos remover o arquivo_original.

$ rm arquivo_original
$ ls -l
total 1
-rw-rw-r--  1  osvaldo  osvaldo   0  Dec 5  15:39  hardlink_1
lrwxrwxrwx  1  osvaldo  osvaldo  16  Dec 5  15:39  softlink_1 -> arquivo_original
$ _

Vejam que o hard link continua existindo e com o mesmo conteúdo do arquivo_original, entretanto o soft link continua apontando para o arquivo que foi removido, caracterizando um link quebrado.

Dispositivos

Os arquivos do tipo dispositivo são utilizados para fazer a comunicação com os drivers dos dispositivos físicos da máquina. Quando gravamos ou lemos informações desses arquivos estamos, na verdade, enviando e recebendo informações do driver do dispositivo associado a esse arquivo.

Normalmente, todos os dispositivos ficam no diretório /dev e só são usados diretamente pelo usuário root. Alguns dispositivos, porém, são usados rotineiramente por todos os usuários. O /dev/null, por exemplo, é um dispositivo de caracteres que simplesmente descarta qualquer coisa que seja enviada pra ele. Esse dispositivo é usado para, por exemplo, eliminar saída indesejada de algum comando.

Filas

As filas (conhecidas como named pipes) são arquivos que podem ser abertos para operações de escrita por um processo e para leitura por um ou vários processos. Tudo o que for escrito nesses arquivos pelo processo que o abriu para escrita estará disponível para leitura pelos outros processos.

As filas, como o nome em inglês diz, são funcionalmente equivalentes aos pipes, mas têm uma manifestação no sistema de arquivos que pode ser usada em outros programas (por isso, pipes nomeados).

1.2.4. Sinais

Sinais são uma forma simples de comunicação entre processos, com algumas convenções pré-estabelecidas.

Um sistema UNIX normalmente executa muitos processos ao mesmo tempo. Porém, essa execução não acontece sem interrupções; há eventos no sistema que influenciam o funcionamento deles, e deve haver uma forma de notificar esses processos. Por exemplo, quando o sistema vai ser desligado para manutenção, deve existir uma forma de avisar os processos que eles devem escrever qualquer informação que estejam manipulando para o disco, arrumar seu ambiente e parar de rodar para que a máquina possa ser desligada. É para esse tipo de tarefa que os sinais são usados.

Os sinais mais comuns são o HUP, o TERM, o INT e o KILL. O HUP é enviado para processos para indicar que o usuário que o estava executando saiu do sistema. Normalmente, o procedimento padrão nesse caso é gravar dados no disco e sair, mas a ação depende do que o programa achar apropriado. Se for um processo que deve continuar rodando, esse sinal será ignorado, ou alguma outra ação apropriada será performada. O TERM é um pedido de interrupção do processo, e a forma padrão de agir é o programa se desligar graciosamente. O INT é como o TERM, mas é enviado quando o usuário aperta CTRL+C para interromper a execução do processo. O KILL é uma ordem para matar o processo. Ao contrário do TERM, que é um pedido, o KILL elimina imediatamente o processo, não dando tempo sequer parar que ele grave informações essenciais em disco ou para qualquer outra tarefa.

Quase todos os sinais podem ser interceptados pelo processo, exceto os sinais KILL e o sinal STOP, que são essenciais para garantir a estabilidade do sistema em caso de mau uso por algum usuário. Alguns sinais são normalmente enviados pelo kernel, e não pelo usuário, como o FPE em caso de exceção de ponto flutuante (caso o processo execute uma divisão por zero ou outra operação matemática ilegal), o SEGV (em caso de falha de segmentação – o programa tentou ler uma área de memória que não pertence a ele). Outros sinais são enviados por processos de monitoramento. Por exemplo, o processo que monitora a quantidade de energia do no-break da máquina pode enviar o sinal PWR para todos os processos ao detectar que uma falta de energia está prestes a ocorrer. Há, ainda, dois sinais cujo funcionamento não é especificado nem por convenção: USR1 e USR2, que realizam funções não determinadas e que variam de programa para programa.

Uma lista completa dos sinais disponíveis pode ser encontrado na man page signal(5) (acessível com o comando man 5 signal). Lembre-se que, por motivos óbvios de segurança, os usuários só podem enviar sinais para seus próprios processos. Apenas o usuário root pode enviar sinais para processos de todos os usuários.

1.2.5. Pipes

Pipes são uma forma mais elaborada de comunicação entre processos. Cada processo, ao ser rodado, ganha automaticamente três file descriptors. Eles são stdin, stdout e stderr. Pipes fazem a ligação entre descritores de arquivo de diferentes programas.

Por exemplo, é possível especificar que a saída de um programa vai ser a entrada de outro. Essa operação é muito comum. O seguinte comando vai ler o arquivo dados e enviar seu conteúdo para o o comando grep:

$ cat dados | grep texto

Com o auxílio do shell, foi criado um pipe que une a saída do comando cat (stdout) com a entrada do comando grep (stdin). O descritor stderr é usado para mensagens de erro. Normalmente, a saída de erro vai para o terminal, assim como a saída padrão. Quando chegarmos no capítulo sobre shell, porém, vamos aprender como usar redireção para enviar os dados dessas duas saídas para lugares diferentes.

1.2.6. Códigos de erros

Todo processo, ao ser terminado, retorna um código de erro numérico entre 0 e 255. O código 0 indica, por convenção, execução com sucesso, e qualquer coisa diferente disso indica algum erro ou alguma situação não normal. O código de retorno dos comandos é descrito na seção Return Codes de suas respectivas man pages (que podem se acessadas com o comando man comando), e varia de acordo com a função dos programas. O código de retorno 1, por exemplo, normalmente indica uso incorreto do programa. O código 2 pode indicar que algum arquivo está faltando, etc. Também é razoavelmente comum o uso do código 255 para indicar situações catastróficas de erro.

Alguns sistemas mais antigos têm programas que retornam a quantidade de erros ocorridos. Isso é uma convenção antiga que não deve mais ser usada – o correto é retornar um valor fixo de erro e enviar dados sobre quais erros ocorreram para stderr. Essa convenção foi abolida porque, caso o programa tenha mais de 255 erros, o código poderá voltar para os valores iniciais. Um programa com 256 erros retornaria 0, o padrão de execução com sucesso.

1.2.7. Parâmetros

É comum, quando executamos determinados programas, que tenhamos que passar parâmetros para eles. Por convenção, os parâmetros no UNIX são precedidos do caractere ‘-‘. Programas GNU (que seguem as regras da Free Software Foundation) suportam também uma forma de passagem de parâmetros mais extensos, que são precedidos por ’–‘ como na mensagem apresentada abaixo:

-v, --verbose - Exibe informações detalhadas.
-x, --exchange - Troca os parâmetros.
-h, --help - Exibe esta tela de ajuda.

Existe também uma forma de forçar o UNIX a não mais interpretar os parâmetros desse tipo, para isso basta inserir o ’–‘ sem nenhuma opção a mais. Essa opção é útil quando temos que informar um nome de arquivo começado com ’-‘ como parâmetro de um comando:

$ ls -- -arquivo-
-arquivo-
$ _

Outra coisa importante que devemos explicar aqui é a utilização de globs para a passagem de nomes de arquivos como parâmetros. Na tabela abaixo você poderá ver os globs mais comuns:

Glob Descrição
? Qualquer caracter.
* Quaisquer caracteres.
[] Qualquer caractere da lista.
[!] Qualquer caractere exceto o da lista.
{} Qualquer ocorrência da lista (separada por vírgula).

Tabela 1.5: Globs.

Esses globs podem ser utilizados da seguinte maneira:

$ ls
abbb abcde bbbb cbbb hipermercado mercado supermercado
$ ls [bc]bbb
bbbb cbbb
$ ls {hiper,super,}mercado
hipermercado mercado supermercado
$ ls a???
abbb
$ ls a*
abbb abcde
$ ls [!a]*
bbbb cbbb hipermercado mercado supermercado
$ _

Uma coisa que precisa ser explicada é que o shell é que fica com a responsabilidade de ’traduzir‘ os globs e passá-los como parâmetro para aplicação. Deixando a aplicação livre do trabalho de interpretar os globs e substituí-los pelos nomes dos arquivos.

1.3. Comentários finais

Nesse capítulo aprendemos um pouco sobre a história dos sistemas UNIX, seus fundamentos e sua filosofia, com uma breve introdução ao uso da linha de comando. Esse conhecimento é fundamental para usar efetivamente o sistema. Coisas que podem parecer estranhas, como decorar os números octais equivalentes às permissões, facilitam o trabalho do usuário de sistema UNIX, e esse tipo de conhecimento pode ser assimilado facilmente com a prática e a disciplina de uso do sistema.

Continua…

E os programadores, onde erram?

O @marionogueira provocou e eu vou responder.

Carreira de programador

Mas antes vou explicar porque eu compartilho da visão de que o trabalho de desenvolvedor guarda semelhanças com o trabalho de um artista (importante dar destaque à palavra “semelhança” para não pensar que as coisas são iguais).

Como programador você pega uma especificação abstrata que se parece com uma ‘inspiração’ e começa a trabalhar nela até obter algo ‘bruto’, aí você vai lapidando (iterando) sobre esse trabalho, simplificando, e aproximando o software daquela inspiração (especificação).

Nesse processo o programador vai deixando seu “estilo” no código. Na escolha de algorítmos, de estruturas de dados, nos textos de comentários e até mesmo no “Coding Style”. Essas características são tão notáveis que depois de um tempo é possível identificar o autor do código mesmo quando ele não está ‘assinado’.

Uma diferença importante entre o trabalho de artistas e de programadores é que raramente vemos o trabalho em equipe (times) no universo das artes e o mesmo é quase uma regra no mundo do software.

Mas daqui para frente eu vou falar sobre um tipo específico de artistas: aqueles que trabalham sob encomenda pintando retratos de reis e nobres para garantir o seu sustento. E para ilustrar o meu raciocínio vou usar uma das obras de arte mais conhecidas no mundo: a Monalisa.

A Monalisa (La Gioconda) foi uma obra encomendada por Francesco del Giocondo a Leonardo Da Vinci. Existe muitas versões, mitos e mistérios que cercam essa obra mas vamos nos ater à “história oficial”.

Francesco passou uma especificação para Da Vinci (ele queria um retrato de sua esposa Lisa Gherardini) e provavelmente especificou prazo e preço. Ou talvez tenham feito um contrato de escopo aberto? Não sei, não estudei essa história muito a fundo.

Leonardo Da Vinci, então, fez os primeiros esboços e foi apresentando esses esboços ao contratante. Talvez não tenha feito isso porque o contratante confiava plenamente na capacidade de entrega dele. Mas não teria sido vergonha se tivesse que apresentar os esboços no meio da execução do projeto.

O resultado final foi um trabalho encomendado, executado no prazo combinado, à um custo determinado e que, mesmo assim, era uma obra de arte.

Curiosamente o escritório da Triveos é vizinho de uma escola de pintura. Todo dia passo em frente à sala de aula e vejo o trabalho dos alunos. É fácil perceber que não tem nenhum Leonardo Da Vinci ali (por enquanto). Falta-lhes experiência. Prática. Com o tempo e empenho eles se transformarão em bons artistas. Talvez gênios.

O mesmo acontece com os programadores. Só com a prática, a experiência, e com o domínio da técnica um programador se tornará um ‘artista’ de verdade.

Mas voltando à questão levantada pelo @marionogueira…

O ‘mundo’ está errado no gerenciamento dos programadores quando eles mudam escopo, prazo e custo dos projetos a todo o instante e ainda exigem uma obra de arte como resultado do trabalho. Ou quando não permitem que o ‘artista’ trabalhe ao seu modo.

A Monalisa seria uma obra de arte se, durante o seu desenvolvimento, o contratante desse palpites sobre as cores e cenários deveriam ser usados na obra?

Mas os programadores também erram!

Erram quando aceitam o desafio de desenvolver uma obra de arte sem ter o domínio adequado da técnica, a prática e a experiência necessária para transformar aquela especificação em arte.

Em projetos ideais onde o escopo é claro, o prazo é razoável e custo está sob controle os programadores falham quando não compreendem que, mesmo tendo sido encomendada, a ‘obra de arte’ é dele também. Sem essa compreensão eles deixam de se comprometer com sua execução.

Mesmo tendo sido encomendada, Da Vinci não fez a Monalisa ‘nas coxas’. Ele fez o máximo possível para entregar uma obra de arte única. Isso fica claro em projetos open-source onde a obra e o nome do artista fica público.

Um artista não precisa de foco e disciplina para se inspirar. Aliás, isso pode até atrapalhar. Mas para executar a obra é necessário muito foco e muita disciplina. Principalmente se a obra foi encomendada e tem custos e prazos pré-estabelecidos.

O programador falha quando ele não tem foco e disciplina no seu trabalho. Twitter, MSN, GTalk, IRC e outros sugadores de foco, hoje, ficam mais tempo em funcionamento do que a IDEs, editor de textos e outras ferramentas de desenvolvimento. Eu sei. Eu vivo isso.

Fora isso eles podem errar em outras questões que envolvem relacionamento interpessoal, trabalho em equipe, ética, etc. Mas nessas questões todos podem errar.

Como garantir um emprego de desenvolvedor

Foto: Robert Lowe

Post rápido e ligeiro com uma lista de atributos que certamente vão garantir a sua vaga como desenvolvedor em qualquer empresa que valha a pena trabalhar.

Cada atributo tem um dos graus de importância abaixo (do mais importante para o menos importante):

  1. Vital – característica mais do que essencial para vagas de desenvolvedor ou para qualquer outro tipo de posição.
  2. Essencial – característica imprescindível para um desenvolvedor.
  3. Importante – característica importante mas não imprescindível. Pode-se contratar um desenvolvedor que não tenha essa característica desde que haja um compromisso do mesmo em desenvolvê-la.
  4. “Plus” – não faz muita diferença mas pode ser uma característica que pode desempatar (a favor de quem a tem) numa disputa entre dois ou mais candidatos.
  5. Desnecessária – não faz diferença alguma.
  6. Condenável – característica que pode depor contra a sua candidatura.

O que está escrito aqui é a minha visão sobre o assunto. Algumas empresas contratantes podem divergir no grau de importância de cada atributo. Outras, por questões legais, podem exigir determinada característica listada como:

  • Comunicação (vital) – comunicação escrita e verbal, capacidade de argumentação e de expressar idéias e conceitos.
  • Prazer em programar (vital) – você programa nas horas vagas? Não? Então desista. Corra atrás de trabalhar com aquilo que você faz nas horas vagas. Todos ficarão gratos.
  • Prazer por aprender coisas novas (vital) – Veja… eu disse “prazer por” e não “interesse em”.
  • Inglês para leitura (vital) – não dá mais tempo de esperar por traduções de documentação.
  • Programação (essencial) – tem que saber teoria e prática. Conhecer algoritmos, estruturas de dados, conceitos de OO, paradigmas de programação, teoria da computação, matemática, …
  • Familizarização rápida com ferramentas (essencial) – você é capaz de corrigir um bug numa aplicação escrita numa linguagem que você não conhece em quanto tempo? Consegue produzir código numa linguagem nova em menos de uma semana?
  • Inglês para escrita (essencial) – grande parte dos softwares, bibliotecas e sistemas que usamos hoje são desenvolvidos por estrangeiros. Freqüentemente precisamos trocar um e-mail com esses desenvolvedores.
  • Conhecer bem ao menos uma linguagem (essencial) – essa linguagem varia de acordo com o que você deseja desenvolver, mas ela tem que ser uma espécie de ‘segundo idioma’ seu. No meu caso essa linguagem é Python, mas poderia ser outra.
  • Inglês conversação (importante) – grande parte dos lugares bacanas pra se trabalhar, hoje, são estrangeiros, tem filiais fora do país ou estão contratando estrangeiros pros seus times. Poder conversar com eles é importante.
  • Ter familiaridade com ‘linguagens chave’ (importante) – algumas linguagens de programação estão presentes em tantos lugares que não é mais possível desconhecê-las: assembly de pelo menos 1 plataforma, C, Shell Script, linguagem funcional (fico devendo essa :D), linguagem OO (Java, Smalltalk, Python, Ruby, …).
  • Participação em projetos FLOSS (importante) – universo perfeito para exercitar, experimentar, participar, desenvolver, aperfeiçoar, … todas as características listadas aqui. Alguns lugares onde trabalhei sequer pedia curriculums para contratar um desenvolvedor e usavam só a participação dos mesmos em projetos FLOSS
  • Formação acadêmica (plus) – desde que seja numa boa faculdade (USP, Unesp, UNICAMP, UF*, UTF*, PUC*, …) podem indicar que os alunos aprenderam alguns fundamentos importantes de programação. O convívio social dos alunos para estudo, execução de projetos e trabalhos também acrescenta.
  • Certificações (desnecessária) – empresas que pedem ou avaliam certificações não podem ser empresas onde valha a pena trabalhar. Empresas que usam certificações são aquelas que são incapazes de avaliar corretamente os candidatos e ‘terceirizam’ essa tarefa para as entidades certificadoras. Uma empresa incapaz de avaliar um candidato não pode ser capaz de lhe dar boas condições de trabalho.
  • “Corporacionismo” (condenável) – profissionais que falam “frases que agregam valor e aumentam a sinergia do time junior de colaboradores” ou que acham fundamental a existência de uma regulamentação no mercado de trabalho de TI geralmente são aqueles que não querem ou não conseguem se destacar como desenvolvedor por conta própria e precisa de uma ‘mãozinha’ do governo pra isso.

Esse artigo descreve algumas características que um desenvolvedor deve ter para conseguir um emprego. Mas se o desenvolvedor quiser empreender e montar o seu próprio negócio, ele precisa das mesmas características? Sim, mas com graus de importância diferentes. Além desses atributos são necessários alguns outros que tentarei abordar em outro artigo.

Gostou desse artigo?

Assine a minha newsletter quinzenal e receba artigos sobre Programação, Python, Django, carreira e empreendedorismo.

[mc4wp_form]

Home, End, Page Up and Page Down configuration for Mac (Snow Leopard)

Terminal.app

Enter “Terminal->Preferences->Settings->Keyboard“, and change the following options (press <ESC> to get \033 in text below):

Vi Mode

Home: \033[H
End: \033[F  
PageUp: \033[5~  
PageDown: \033[6~

Emacs Mode

Home: \033[1~
End: \033[4~
PageUp: \033[5~
PageDown: \033[6~

Bash/Readline

Edit your ~/.inputrc and add the following lines:

Common settings

# Be 8 bit clean.
set input-meta on
set output-meta on
set convert-meta off

# allow the use of the Delete/Insert keys
"e[3~": delete-char
"e[2~": quoted-insert

# mappings for "page up" and "page down"
# to step to the beginning/end 
# of the history
"e[5~": beginning-of-history
"e[6~": end-of-history

Vim mode settings

# Vi mode
set editing-mode vi
set keymap vi

# allow the use of the Home/End keys
"e[H": beginning-of-line
"e[F": end-of-line

Emacs mode settings

# allow the use of the Home/End keys
"e[1~": beginning-of-line
"e[4~": end-of-line

Vim

Edit the file ~/.vimrc and add the following options:

Terminal configured with Vi mode

map <Esc>[H <Home>
imap <Esc>[H <Home>
map <Esc>[F <End>
imap <Esc>[F <End>
map <Esc>[5~ <PageUp>
imap <Esc>[5~ <PageUp>
map <Esc>[6~ <PageDown>
imap <Esc>[6~ <PageDown>

Terminal configured with Emacs mode

map <Esc>[1~ <Home>
imap <Esc>[1~ <Home>
map <Esc>[4~ <End>
imap <Esc>[4~ <End>
map <Esc>[5~ <PageUp>
imap <Esc>[5~ <PageUp>
map <Esc>[6~ <PageDown>
imap <Esc>[6~ <PageDown>

Cocoa Keybindings

Put the following lines in ~/Library/KeyBindings/DefaultKeyBinding.dict:

{
    /* home */
    "UF729" = "moveToBeginningOfLine:";
    "$UF729" = "moveToBeginningOfLineAndModifySelection:";

    /* end */
    "UF72B"  = "moveToEndOfLine:";
    "$UF72B" = "moveToEndOfLineAndModifySelection:";

    /* page up */
    "UF72C"  = "pageUp:";
    "$UF72C" = "pageUpAndModifySelection:";

    /* page down */
    "UF72D"  = "pageDown:";
    "$UF72D" = "pageDownAndModifySelection:";
}

Firefox

Install the following Firefox extension.

Textmate

I strongly recommend to Textmate users to disable the “Smooth Scrolling” option in System Preferences->Appearance->Use smooth scrolling. This option cause a strange behaviour with Page Up/Down on Textmate.

References

Update: Added suggestion to disable “Smooth Scrolling” for Textmate users.

É mais fácil pedir desculpas do que permissão

Diferente do que escrevi no post Dicas para um bom programa em Python, onde eu dou dicas de como proceder para ter um programa Python melhor, desta vez vou falar sobre um estilo que prefiro. Não quero dizer que estou certo ou errado, apenas que prefiro assim.

It’s easier to ask forgiveness than it is to get permission — Grace Hopper

Recentemente, dentro do tempo que me sobrava, comecei a desenvolver uma biblioteca pra fazer requisições HTTP para uma API REST. Essa biblioteca seria usada para criar testes automatizados do projeto que iremos começar a desenvolver aqui na empresa.

Essa biblioteca faria basicamente o mesmo que a httplib e httplib2 do Python mas com algumas conveniências: (de)serialização de JSON/XML, conteúdo calculado no momento da request (ex. assinatura da requisição), e uma classe “TestCase-like” com funções que auxiliassem no desenvolvimento de testes.

Eu tinha só algumas idéias do que essa biblioteca faria e quase nada de código quando vi o lançamento do Bolacha, desenvolvido pelo Gabriel Falcão, no Planeta Globo.com. Guardei o link pra conferir depois pois poderia ser útil para o que eu queria fazer.

Ontem eu tive um tempo para analisar e vi que ele não só seria útil como já fazia a parte mais essencial do que eu precisava (requisições GET/POST/PUT/DELETE/…).

Como o projeto esta hospedado no github.com tratei logo de fazer um fork para criar as outras funcionalidades que eu precisava. Código legal, código simples, código bem feito, mas… quando encontrei os primeiros…

def request(self, url, method, body=None, headers=None):
  if not isinstance(url, basestring):
    raise TypeError, 'Bolacha.request, parameter url must be ' 
              'a string. Got %s' % repr(url)
 
  if not isinstance(method, basestring):
    raise TypeError, 'Bolacha.request, parameter method must be ' 
              'a string. Got %s' % repr(method)
 
  if method not in HTTP_METHODS:
    raise TypeError, 'Bolacha.request, parameter method must be ' 
              'a valid HTTP method. Got %s. %s' % (method,
                                                    RFC_LOCATION)
    # ...continua

… notei que o estilo do Gabriel divergia do meu. Nada errado com isso. Tanto que, mesmo assim, continuarei a usar e melhorar o Bolacha mantendo (dentro do possível) o mesmo estilo original do autor para que ele possa aceitar minhas contribuições.

O que não gosto desse estilo é que, com ele, sempre estamos pedindo permissão, ou seja, verificando de antemão alguma informação no lugar de usá-la imediatamente e, só em caso de erro, considerá-las inválida. Nesse caso estamos adicionando um overhead desnecessário (muito pequeno neste exemplo) até mesmo para casos de uso correto do método.

Outro problema que temos nesse estilo reside no fato de que estamos usando o mecanismo de herança da linguagem como um sistema de criação de interface para o objeto. Se eu quiser passar um objeto que se comporta exatamente como uma string mas que não seja uma classe derivada de basestring() para o método .request() acima eu não vou poder.

Eu removeria todas as verificações de isinstance() e deixaria o código assim:

def request(self, url, method, body=None, headers=None):
  if method not in HTTP_METHODS:
    raise TypeError, 'Bolacha.request, parameter method must be ' 
          'a valid HTTP method. Got %s. %s' % (method,
                                                    RFC_LOCATION)
    # ... continua

Mais adiante nesse código vemos o uso de uma função chamada is_file() que é implementada da seguinte forma:

def is_file(obj):
  return hasattr(obj, 'read') and callable(obj.read)

Mais uma vez, nada de errado. Mas também não é muito o meu estilo. No meu estilo essa função sequer existiria porque, mais adiante, quando fosse necessário usar obj que, no código em questão, pode ser uma string ou um file object, eu faria algo assim:

try:
  lines.extend(encode_file(obj))
except AttributeError:
  lines.extend([ '...' ])

Mais uma vez eu quero deixar claro que é só uma questão de diferença de estilo e que eu usei o código do Bolacha somente para ilustrar essa diferença. Dentro do estilo do Gabriel o código está perfeito (tá, não existe código perfeito, mas o dele tá muito bom).

Como leitura complementar sobre essas diferenças eu recomendo o artigo isinstance() considered harmful, Duck Typing, Permission and Forgiveness e PEP-3119 – Introducing Abstract Base Classes (funcionalidade de suporte ao estilo usado no Bolacha).

Por último, ao meu estilo, gostaria de pedir desculpas ao Gabriel Falcão por ter usado o código do Bolacha para ilustrar esse artigo sem permissão. 🙂

Dicas para um bom programa em Python

Foto: Olivier H

Oi pessoal, desta vez eu vou pular as ‘desculpas’ por ter demorado tanto para postar aqui no blog e vamos direto ao assunto.

Recentemente eu tenho trabalhado bastante com Python (dã!) desenvolvendo projetos de diversos tipos e resolvi escrever aqui sobre algumas coisas que pratico enquanto desenvolvo.

Esse artigo é uma espécie resumo com boas práticas de programação Python que utilizo no meu dia-a-dia.

Código mais robusto

Deu certo ou errado?

O que você faz quando acontece algo errado na execução do seu método? O que você responde à requisição que lhe foi feita?

Eu tenho visto em muito código por aí os desenvolvedores retornando valores sentinela (None, null, 0, -1, etc.) para avisar que algo incorreto aconteceu na execução do método.

def f(arg):
   if not arg:
      return None
   return [ "resultado", "de", "um", "processamento"  ]

Algumas linguagens de programação não possuem estruturas de tratamento de exceção e, neste caso, o uso de sentinelas é válido. Mas quando a linguagem de programação te disponibiliza essa funcionalidade é bom usá-la.

def f(arg):
   if not arg:
      raise ValueError("Argumento Invalido")
   return [ "resultado", "de", "um", "processamento"  ]

Deixem as exceções fluirem.

Isso mesmo. A menos que você saiba exatamente o que você deve fazer quando uma exceção aparece deixe-a exceção “subir”. Pode ser que “lá em cima” alguém saiba cuidar dela adequadamente.

Quando não fazemos isso estamos ocultando informação importante para os usuários do nosso código (sejam eles usuários, outros desenvolvedores ou nós mesmos).

def f():
   try:
      return conecta()
   except ExcecaoQueDeveriaSerErro:
      return None

Quando eu implemento esse tipo de método/função eu faço assim (na verdade eu não implementaria f() e chamaria conecta()):

def f():
   return conecta()

O que seu método/função retorna?

Código que eu encontrei recentemente:

def get_fulanos():
   q = Q("select * from patuleia where alcunha like 'fulano%'")
   ret = [ str(fulano['nome']) for fulano in q ]
   if len(ret) == 1:
      return ret[0]
   return ret

Perceberam o que está errado? O seu método retorna uma lista de Fulanos ou retorna Fulano?

Isso está conceitualmente errado e pode fazer você perder horas preciosas do seu dia tentando achar um bug causado por esse tipo de código.

Aconteceu comigo. Note que str() implementa uma interface de sequence da mesma forma que list(). Então o erro passa silenciosamente no caso abaixo:

old_fulanos = [ "Ze Ruela", "Ze Mane" ]
old_fulanos.extend(get_fulanos())
print old_fulanos

Rodando esse código você vai obter ['Ze Ruela', 'Ze Mane', 'q', 'u', 'a', 'c', 'k'] sendo que, em mais de 90% dos casos, o que você gostaria de ter seria: ['Ze Ruela', 'Ze Mane', 'quack'].

“Nada” é diferente de “alguma coisa”.

Essa dica é só uma complementação da primeira e da segunda dica.

Quando o seu método/função retorna uma collection (seqüência, conjunto, hash, etc) vazia você deve retorná-la vazia e não um valor sentinela (como None). Isso facilita a vida de quem vai usar o seu método/função:

def vazio():
   return []
 
for elemento in vazio():
   pass #... faz algo se o conjunto contiver dados ...

Se você retorna um valor sentinela:

def vazio():
   return None
 
elementos = vazio()
if elementos:
   for elemento in elementos:
      pass # ...

Notou que tivemos que criar uma variável com o resultado da operação (para não precisar chamá-la duas vezes) e tratar a sentinela com um “if“? Se eu esqueço de tratar a sentinela meu programa vai quebrar.

Lembre-se sempre que uma collection vazia tem valor booleano “False“.

Todo ‘elif‘ tem um irmão ‘else‘.

Sempre que você precisar usar uma construção if/elif coloque uma cláusula ‘else‘.

Além de usar a cláusula ‘else‘ eu geralmente faço com que ela gere uma exceção. Desta forma eu sou obrigado a trabalhar todas as possibilidades nos ‘if/elif‘ evitando ocultar uma situação que pode ser inválida.

class InvalidCommand(Exception):
   pass
 
def minihelp(comando):
   if comando == "print":
      return u"""Imprime dados na tela.
                 Deixará de ser comando no Python 3.0"""
   elif comando == "assert":
      return u"""Certifica se uma condição é
               verdadeira e gera uma excessão em caso contrário"""
   elif comando == "...":
      pass # ...
   else:
      raise InvalidCommand(u"Comando %s inválido." % (comando,))

Eu gosto dessa prática mas isso não significa que você deva seguí-la sempre. Existem situações onde ter um “valor default” é necessário e nestes casos o uso do else sem levantar exceção se faz necessário.

if comando == "if":
   print "Vai usar elif?"
elif comando == "elif":
   print "Muito bem. Agora falta o else"
else:
   print "Pronto. Agora está bom."

“Pythonismos”

Use mais atributos públicos do que atributos protegidos (“_“).

Programadores acostumados com Java utilizam muito as cláusulas ‘private‘ e ‘protected‘ para encapsular os atributos de um objeto para logo depois implementarem os getters e setters para acessar esses atributos.

Essa prática é aconselhada em Java porque em algum momento do futuro você, talvez, precise validar esses dados ou retornar valores calculados. Nestes casos os programadores apenas implementam essa lógica nos métodos que acessam o atributo privado.

Mas em Python isso não é necessário. Em Python você pode transformar seu atributo público em uma “property” que não muda a forma de se acessar o atributo e permite o acrescimo de lógica ao acesso do mesmo.

Evite usar “__“.

Por convenção, em Python, todo método ou atributo iniciado com um “_” é considerado privado (equivalente ao protected em Java) e não deve ser acessado de fora da classe mesmo sendo possível fazê-lo.

Dito isso parece meio óbvio que não precisamos usar “__” para dificultar ainda mais o acesso à esse atributo/método. Além disso o uso do “__” traz alguns incoveninentes para quem quer derivar a sua classe e acessar este método/atributo já que o Python o renomeia acrescentando o nome da classe ao seu nome (__attr vira _Classe__attr).

Não sobrescreva builtins.

Python disponibiliza várias funções e classes builtins que facilitam muito o uso da linguagem e economizam digitação. Mas esses builtins tem nomes muito “comuns” e frequentemente a gente usa os nomes dos builtins como nomes de identificadores. Eu mesmo vivo (vivia) fazendo isso.

O problema é que em certos momentos alguns problemas podem acontecer quando você tenta chamar um buitin que já não é mais um builtin. Na maioria das vezes o problema “explode” logo e você rapidamente conserta mas em alguns casos você pode perder muitas horas tentando achá-lo.

Algumas pessoas usam um “_” no fim do nome do identificador (ex. “id” vira “id_”) mas eu acho isso um pouco feio então uso só quando não encontro uma alternativa melhor.

Vou colocar aqui uma tabela de equivalências que eu costumo usar para substituir o nome dos builtins mais comumente sobrescritos:

  • id – ident, key
  • type – kind, format
  • object – obj
  • list – plural (lista de element vira elements)
  • file – fd, file_handler
  • dict – dic, hashmap
  • str – text, msg

Análise estática economiza seu tempo.

Eu uso o pylint, mas conheço algumas pessoas que preferem o pyflakes ou o PyChecker.

A dica é essa: usar um programinha de análise estática como esses pode diminuir consideravelmente aqueles errinhos chatos de sintaxe, ou de digitação. Pode limpar os ‘import’ desnecessários do seu software, etc, etc.

É lógico que esse tipo de ferramenta não substitui uma boa política de testes mas é um bom complemento para ela.

Challenge yourself

Máximo de 3 níveis de indentação. (ou 4 se estiver dentro de uma classe)

Ao se esforçar para que seu código não fique muito aninhado você está trabalhando melhor a implementação dos seus métodos e funções. Nem sempre é possível (ou aconselhável) restringir tanto o nível de identação do seu código mas muitas vezes isso melhora a sua implementação.

Máximo de 2 indireções.

Recebeu um objeto como parâmetro? Chame apenas métodos dele e evite ao máximo chamar métodos do retorno desses objetos:

def f(obj):
    obj.metodo() # legal!
    obj.metodo().outro_metodo() # ruim!

Quando você chama um método pra um objeto retornado por outro método você está aumentando o acoplamento entre as classes envolvidas impedindo que uma delas seja substituída (ou reimplementada) ‘impunemente’.

Essa regrinha é uma das regrinhas da Lei de Demeter.

Máximo de 0 ‘if/elif/else‘s.

Polimorfismo é isso. No mundo OO ideal, perfeito e utópico praticamente não precisaríamos do comando “if” e usaríamos somente polimorfismo. Mas… como não conseguimos isso tão facilmente* devemos, ao menos, usar o “if” com moderação.

Conclusão

Esta é uma lista incompleta de dicas para programadores Python. Se futuramente eu lembrar ou aprender algo novo eu volto aqui para falar sobre o assunto.

Alguns desenvolvedores podem não concordar com as dicas. Neste caso eles podem enriquecer ainda mais esse texto argumentando sobre o as suas restrições no espaço para comentários.

Se você tiver alguma dica para compartilhar com a gente coloque nos comentários. Se ela for boa mesmo eu coloco ela no corpo principal do blog.

* eu mesmo só consegui fazer uma aplicação OO funcional sem usar um único if. Era uma implementação do joguinho de adivinhação de animais (aquele que pergunta “Vive na água? (s/n)”) em Smalltalk.

Update: pequena correção sugerida pelo Francisco nos comentários: s/Classe/_Classe/.

Quer mais?

Você pode encontrar várias dicas para desenvolvimento Python (e Django) nos artigos reunidos em minha newsletter quinzenal “O Melhor da Internet”. Você vai receber links com o melhor conteúdo relacionado a Python, Django, Carreira, Negócios e Empreendedorismo.

Para assinar basta preencher o formulário abaixo.

[mc4wp_form]

Desempregado ou despreparado?

Foto: Roswitha Siedelberg

Nessa semana a empresa onde trabalho me pediu uma ajuda para conseguir contratar um programador Python com uma certa urgência. Como eu sou o moderador da lista Python Brasil optei por enviar um e-mail ligeiramente diferente para a lista de discussão avisando da oportunidade. O e-mail terminava assim:

Requisitos:
 - Desenvolver pra Linux (necessário)
 - Desenvolver em Python (necessário)
 - Saber inglês (necessário)
 - Se divertir programando (necessário)
 - Desenvolver em C/C++ (plus)
 - Desenvolver Gtk+/GNOME (combo plus)
 - Ter estudado ciências ou engenharia da computação (mega-combo plus)
 - Conhecer bem plataforma ARM (qual é o teu telefone?)

A partir daí eu fui recebendo e-mails e mais e-mails com curriculums de candidatos à vaga e pude ver que os erros básicos que já vi em outras oportunidades continuam sendo cometidos.

Pessoal, as coisas que eu vou dizer aqui são sérias e a forma com que vou dizê-las pode ser um tanto contundente. Mas entendam que é para o bem de quem pretende conseguir um trabalho interessante. Algumas pessoas irão se reconhecer no que eu vou dizer abaixo mas para elas eu quero dizer que não é nada pessoal são apenas conselhos de alguém que trabalhou em bons lugares.

Não lamente, corra atrás

Uma quantidade considerável dos e-mails que recebi dessa vez (e de outras vezes) são de lamentação. Algo do tipo “Pôxa, que pena que eu não programo em Python muito bem :(“.

Vamos ser inteligentes. A oferta diz: “Desenvolver em Python (necessário)”. Que parte de “necessário” não foi possível entender do texto? A gente quer um candidato à vaga não uma pessoa precisando de afago.

No lugar de se lamentar por “não saber Python” você deveria é correr atrás de aprender. Nunca gastei um único tostão pra aprender Python, logo, não ter grana não serve como desculpa. Quando aprendi Python trabalhava em dois empregos e ainda tentava fazer uma faculdade. Isso também elimina a falta de tempo como desculpa.

Mesmo que você tenha uma boa desculpa pra não ter aprendido Python você vai ter que pensar sobre o que você realmente quer da sua vida: a vaga ou alimentar sua desculpa.

Se você não tem um bom projeto em Python para trabalhar fique sabendo que tem milhares de projetos de SL esperando pela sua ajuda. Escolha um que te faça feliz e toca o barco.

O salário será aquele que você irá merecer

Um outro tanto de e-mails que recebi tinham a pergunta: “Qual é o salário?” e na oferta estava escrito: “Salário acima da média local”.

Não se pergunta o salário sem você ter sido sequer entrevistado. O salário é a última coisa que se fala com o candidato. Se tá dizendo que é acima da média local significa que é um salário mais alto do que o que você conseguiria por aqui, entende ou quer que eu desenhe?

Sei que isso é utópico e que as “coisas práticas” são importantes, mas você já pensou que a empresa está te contratando para ajudá-la e não para ter mais um valor saindo mensalmente do seu caixa? Já pensou que você será remunerado na mesma proporção da sua contribuição à empresa?

Se você contribui pouco para a empresa X você vai ganhar pouco. Se a empresa Y diz que paga acima da média local significa que você vai ganhar mais que a empresa X mesmo fazendo pouco.

Quando eu tenho vontade de trabalhar numa empresa eu penso na quantidade de coisas legais que eu posso fazer nessa empresa e não em quanto eu vou ganhar. Só no final do processo é que me interesso pela remuneração.

Ofereça-se apenas para vagas que você consegue trabalhar

Esse é o pior tipo. É a famosa metralhadora giratória de curriculums. Parece que o cara tem um filtro no cliente de e-mail que pega e-mails com as palavras “vaga” ou “emprego” e já dá um reply automático com seu curriculum. Quando eu era o dono da empresa e ia contratar eu não só descartava esses curriculums como ainda marcava o nome do indivíduo na lista de “nunca contratar”.

A vaga é para “desenvolvedor” e não para “administrador de redes”! Se você não consegue ler e interpretar um texto com uma oferta de emprego é bem provável que você também não consiga realizar a tarefa para a qual você seria contratado.

Se você quer “mudar de ares” comece a estudar sobre “desenvolvimento” e mande esse tipo de informação no seu curriculum e não que você sabe instalar “postfix”, “manutenção de hardware” ou coisas do tipo.

Se você não sabe se consegue, imagine o contratante

Se você me manda um e-mail dizendo “Eu programo em Python mas não sei se dou conta de fazer o que vocês fazem” eu (no caso a empresa contratante) devo pensar o que?

Se nem você sabe se dá conta imagina eu 🙂 Mesmo que eu te conheça pessoalmente e a gente tenha conversado sobre o trabalho é você quem tem que bater no peito e bradar: “Eu consigo!”.

Então economize o seu tempo e o meu. Se você não tem certeza da sua capacidade não envie e-mail nenhum. Se você sabe que consegue mande direto o seu curriculum e se candidate à vaga.

Analise a vaga em profundidade

Antes de mandar o seu belo curriculum pra uma vaga procure saber mais sobre a empresa. Personalize o seu curriculum de forma a deixá-lo mais atraente para a tal vaga. Seja inteligente e perspicaz ao enviá-la (mas por favor polpe-se ao trabalho de inventar moda).

Eu tenho umas 4 versões do meu curriculum (e uma versão em inglês para cada uma das 4) e sempre pego ele e edito antes de enviá-lo.

Vamos à uma breve análise dos erros que vi:

  • Página 33 de 150: Não rola, né? 🙂 Se não dá pra resumir as coisas que você fez simplesmente elimine alguns dos empregos que você teve e não acrescentam nada ao seu CV. Por exemplo: eu trabalhei 3 anos em uma agência de publicidade como “publicitário” (ênfase nas aspas). Não preciso colocar isso pra uma vaga de desenvolvedor.
  • Olha a foto! Buuu!: Na mensagem tá pedindo “boa aparência”? Se não tá pedindo significa que tua aparência não importa, certo? Se tua aparência não importa a foto não serve pra nada. Pior: e se você for feio? Num eventual “empate” para a vaga a sua feiura pode te eliminar, mesmo em situações onde ela não seria importante.
  • Mexe com Linux? Pega o .doc: Erro primário esse. Se a vaga fosse pra trabalhar na Microsoft você mandaria seu curriculum no formato .odt? Porque você manda um .doc para trabalhar numa empresa que mexe com Linux? Ok, o OpenOffice “abre” esse tipo de arquivo mas o arquivo .doc mostra habilidade em que tipo de ambiente de trabalho? Na dúvida mande um .pdf, um .txt ou, como eu faço, um .html.

Eu também uso esse conselho para dizer aos candidatos: inverta o papel de quem escolhe quem. Invista no seu aprimoramento muito mais do que o exigido pelo “mercado” e apresente-se numa situação onde a empresa quer contratá-lo.

Eu já vi donos e gerentes de empresa fazendo leilão para levar um candidato. Se você é bom o suficiente para estar nessa situação você concordará comigo que é muito mais confortável.

Mas seja honesto ao ser “leiloado”. Não blefe. Eu já vi ótimos programadores que se queimaram em ambas as empresas porque descobriram o blefe. Acabou sem nenhum emprego e com a imagem arranhada em um mercado onde todo mundo se conhece.

Você trabalha no emprego perfeito, me aconselhe profissionalmente

Pessoal, eu não sou o Max Gehringer. O máximo que eu posso dar de dica é para o tipo de trabalho que eu faço. As dicas do Max são legais para casos mais genéricos mas também não precisa levá-lo à sério demais porque senão você acaba virando mais um daqueles candidatos “robôs” cheio de respostas prontas e pré-fabricadas.

Como teve mais de uma pessoa que me perguntou sobre “investir no aprendizado de Python” eu vou falar um pouco sobre esse caso específico:

Invista o seu tempo em algo que te deixa feliz. Se você gosta de programar em Python invista em Python. Se gosta de programar mas não importa a linguagem programe em várias delas.

Se você não gosta de programar? Vai fazer o que você gosta de fazer. Sai fora dessa área. Evite perder o seu tempo e o de outras pessoas que gostam de trabalhar com isso.

E tem outra coisa: usar o trabalho nessa área como meio para ganhar dinheiro para no futuro atuar em outra área menos rentável. Isso é péssimo. Atue na área “menos rentável” e faça-a se tornar rentável.

Pega o meu curriculum praquela vaga do mês passado

Um certo dia eu ofereci uma vaga em uma empresa onde trabalhava que precisava ser preenchida com urgência e recebemos curriculums para essa vaga por mais de 3 meses.

Se você vê que a oferta foi feita à mais de uma semana desiste.

Se tiver uma gota de esperança de que a vaga não foi preenchida ou tem “inside informations” de que a vaga não foi preenchida tudo bem. Mas se não for esse o caso fica a lição pra você ficar mais atento.

Gostou desse artigo?

Assine a minha newsletter quinzenal e receba artigos sobre Programação, Python, Django, carreira e empreendedorismo.

[mc4wp_form]

Como aprender inglês sozinho (self-taught)

Eu adoro aprender coisas novas, mas eu gosto de ter o controle sobre o meu aprendizado. Não tenho preguiça de ler nem de ouvir os ensinamentos, mas gosto de poder escolher quando, como e quais deles ouvir.

Como quase todo mundo eu também tenho preferência em aprender as coisas que eu gosto mais e não gosto de “perder tempo” aprendendo coisas que eu não gosto. Eu coloquei “perder tempo” entre aspas porque acredito que “perder tempo” e “aprender” são dois conceitos que dificilmente andam junto (ou ao menos não deveriam andar junto).

Pois bem, eu disse tudo isso porque eu não gosto de aprender idiomas. Não importa qual seja. Odiei aprender português enquanto estava na escola e não me esforcei em nada para aprender inglês nas escolas por onde passei (maioria de escolas públicas). Deixei muitos professores revoltados com o fato de que eu não prestava atenção à nenhuma aula e ainda assim conseguia boas notas. Mal sabiam eles que eu estudava a matéria que cairia nas provas. Só que do meu jeito e quando eu queria.

Já comecei uns 10 cursos de inglês e até aprendi um pouco neles mas depois do segundo ou terceiro mês eu já estava desanimado e desestimulado a continuar. Isso acontece porque eu estou tendo que aprender algo que eu não gosto nas horas que os cursos determinavam e do jeito que eles queriam. Desse jeito não rola.

Mas e aí? Eu preciso saber inglês no meu trabalho. E muito. Como eu faço pra aprender inglês? Decidi fazer um auto-aprendizado de inglês. E a minha professora seria a a vida offline e online.

Mas eu não sabia nem por onde começar até que descobri o “poder dos blogs“, dos podcastings e até mesmo dos antigos métodos que usam música e filmes. Coletei alguns deles que listo abaixo e adquiri 3 livros essenciais para o aprendizado do idioma.

BBC-Logo

TV

Assista o noticiário da BBC. Os apresentadores britânicos tem uma dicção melhor e falam mais devagar. É bem melhor para iniciantes do que a CNN 🙂

Internet / Aplicativos

A Internet e os smartphones disponibilizam diversas ferramentas de apoio aos estudantes de vários idiomas. Fiz uma pequena seleção dos que mais gosto. Se você tiver outras sugestões envie através dos comentários.

Duolingo

duolingoEsse aplicativo precisava ter sido inventado antes. Ele é fantástico. Transforma o estudo de inglês em um tipo de partida de “casual game” onde você vai passando de fase, ganhando prêmios (virtuais) conforme aprende um idioma.

Estudei inglês com ele mas existem outros idiomas. E o melhor: totalmente gratuito (não tem nem que comprar créditos de nada).

Esse projeto foi criado por um ex-funcionário do Google que usa o imenso contingente de pessoas que jogam o Duolingo para alimentar com dados sistemas computacionais que fazem traduções de documentos.

English Experts

Fornece um fórum com muitos usuários que podem te ajudar com diversos problemas. Funciona em um modelo de perguntas e respostas que vai premiando os participantes mais ativos.

Tecla SAP

Com um enfoque mais divertido e com histórias engraçadas de pessoas que se deram mal por não saberem inglês é outra boa dica para quem está aprendendo inglês.

Infelizmente os feeds não funcionam muito bem e não são completos.

English as a Second Language Podcast

O mais bem produzido dos podcasts que avaliei é gratuito (exceto se você quiser adquirir o material auxiliar) e tem conversas usadas no dia-a-dia das pessoas seguido de explicações sobre o diálogo.

Livros

Os livros que apresento aqui são ferramentas de apoio e consulta nos seus estudos. Nenhum deles ensina inglês mas todos darão suporte aos seus esforços de aprender.

Oxford Dictionary of Englishoxford-dict

Um dicionário Inglês/Inglês é essencial. Eu sei que é algo caro mas, acredite, eu já comprei um “Michaelis” e considero o dinheiro gasto com ele perdido. A diferença da qualidade do dicionário Oxford e a sua utilidade justificam o gasto extra.

Pense também que esse dicionário lhe servirá por toda a vida e que com essas dicas que estou dando você já está economizando bastante dinheiro.

Oxford Phrasal Verbs

Eu ainda não tenho esse e por essa razão tenho que ficar emprestando o de um companheiro de trabalho. O número de variantes de phrasal verbs é tão grande que merece um dicionário exclusivo para tratar deles. Phrasal Verbs são aquelas expressões compostas de verbo+advérbio ou verbo+preposição tipo: “break down”, “blow up”, “check in”, etc.

Inglês + Fácil Gramática

Essa é uma gramática de consulta rápida. Serve para tirar dúvidas esporádicas sobre gramática. A aquisição deste livro é opcional. É um dos que menos uso apesar de já ter me ajudado algumas vezes.

Longman Dicionário Escolar Inglês/Português-Português/Inglês

Esse dicionário não é muito completo mas o “conjunto da obra” torna-o excelente para aqueles que estão aprendendo inglês agora.

O dicionário português/inglês é extremamente útil para enriquecer nosso vocabulário, os verbetes são fartamente ilustrados, o CD-ROM é prático, os ‘boxes’ explicativos para expressões e gírias são fantásticos e o preço é excelente.

Não deve ser o único dicionário em sua casa, mas é um bom começo. Aqui em casa meu filho usa o tempo todo.

Hábitos Saudáveis

Além do material indicado acima eu pratico alguns hábitos saudáveis para aperfeiçoar meus conhecimentos em inglês.

Filmes

Gosto muito de cinema e tenho o hábito de ver o mesmo filme várias vezes (se o filme for bom, é claro). Quando precisei aprender inglês passei a rever os filmes com a legenda em inglês.

O áudio e a legenda não são iguais mas as palavras principais estão lá. Como eu já conheço a história (assisti com legenda em português antes) o cérebro passa a assimilar o som das palavras (reforçado pela legenda). Se o filme for realmente bom eu ainda tento assistir mais uma vez sem nenhuma legenda.

Músicas

Escute muito à músicas em inglês e, quando se sentir confortável, cante (mesmo no “embromation”) essas músicas.

Depois procure a letra da música na internet (Google: nome-da-música lyrics) e tente cantar lendo a letra. É impressionante a quantidade de coisas que a gente achava que estava certo e não estavam.

Traduzir a música pode ser interessante e buscar o significado dela melhor ainda.

Outros

  • No seu computador: instale tudo em inglês.
  • Participe de grupos de bate-papo em inglês na internet ou em sua cidade. Em cidades maiores é fácil encontrar um grupo desses.

Pratique

Não tenha medo ou vergonha de se expressar em inglês mesmo que você ainda não esteja fluente. Lembre-se que o teu interlocutor não deve saber nada de português também 😀 O máximo que pode acontecer é você ser corrigido e aprender um pouco mais (só um babaca te zoaria por falar errado).

Mais do que ter esse material terei que ter uma grande disciplina para dedicar tempo necessário para estudar.

Atualização: esse artigo foi praticamente reescrito no dia 2/7/2014.

Gostou desse artigo?

Assine a minha newsletter quinzenal e receba artigos sobre Programação, Python, Django, carreira e empreendedorismo.

[mc4wp_form]