Book Review: Code Simplicity by Max Kanat-Alexander

Livro Code Simplicity

O Code Simplicity foi uma enorme surpresa para mim. Trata-se de um livro de 2012 com “meras” 84 páginas. Quão bom ele poderia ser? Ele é tão fininho que quase vale mais a pena colar o conteúdo aqui, ao invés de falar sobre ele(!).

Quem é o autor?

Conforme ele conta no livro, o Max estava no time responsável por reorganizar o Bugzilla em uma época em que funcionalidades deixavam de ser adicionadas porque ninguém mais tinha coragem de alterar o código (quem nunca, né?). Hoje ele é o responsável pela produtividade dos desenvolvedores do Youtube.

Por que eu deveria ler?

Programar, em essência, precisa se tornar o ato de transformar complexidade em simplicidade.

Apesar do título, não se trata de um manual com detalhes sobre como escrever código simples, aliás o livro praticamente não contém código. O livro busca definir uma base para se desenvolver software sempre reduzindo a sua complexidade. E o faz de maneira, ao menos pra mim, bastante inusitada. O autor tem a audácia de definir Regras e Leis(!) para o desenvolvimento de software. Coisas que ele identificou durante a sua carreira e até hoje, segundo ele, não encontrou evidências que digam o contrário.

Nas palavras do Max:

Ao ler algumas delas [as ideias/leis] você pode pensar que elas são tão simples que chegam a ser estúpidas. Não é que as pessoas não saibam de muitas dessas ideias – é que elas não sabiam que eram leis. Uma vez que você passar a pensar nessas ideias como a base fundamental para todas as boas decisões sobre desenvolvimento de software, como verdades inabaláveis das quais todas as melhores práticas derivam, será quando você começará a entender o seu real valor.

E continua:

A diferença entre um programador bom e um ruim é a compreensão. Isto é, programadores ruins não entendem o que estão fazendo e bons programadores entendem. Acreditando ou não, é simples assim. Quanto mais você entender o que está fazendo, melhor o fará.

A principal lei do desenvolvimento de software

Para o Max é:

O propósito de um software é ajudar pessoas

E se você parar pra pensar, e como o Max sugere, encarar isso como uma Lei, verá que isso facilita bastante na hora de tomar várias decisões. Seja se for para escolher qual funcionalidade será a próxima a ser adicionada ou se adicionar testes ao seu projeto é uma boa ideia.

A principal lei do design de software

O valor de uma mudança é diretamente proporcional ao valor dela hoje adicionada ao seu valor no futuro, e é inversamente proporcional ao esforço de implementação somado ao esforço de manutenção.

Isso pode ser traduzido para a seguinte fórmula:

Law Of Software Design

Em que,

Vn = Valor Hoje; Vf = Valor Futuro; Ei = Esforço de Implementação; Em = Esforço de Manutenção

Acontece que o Valor Hoje e o Esforço de Implementação são valores fixos. Por outro lado, o Valor Futuro e o Esforço de Manutenção, são valores que te afetarão por muito tempo. Por exemplo, você poderia estimar que vai gastar R$ 1000/mês (Em) e receber R$ 2500/mês (Vf) nos próximos anos por ter implementado essa funcionalidade. A consequência disso é que, no longo prazo, a equação pode ser reduzida para:

Simplified Law Of Software Design

Isso, obviamente, assume que o software será mantido por tempo suficiente, o que geralmente é o caso. O Max também comenta sobre como tendemos a achar que nossos softwares serão mantidos por menos tempo do que acabam sendo no final das contas.

A principal implicação disso é que precisamos lutar para sempre reduzir o custo de manutenção, porque ele é a parte da equação que está sob nosso controle. Enquanto o nosso custo de manutenção estiver perto de zero, o valor obtido não vai tirar o nosso sono (use o bom senso).

Resumindo, no longo prazo:

É mais importante reduzir o custo de manutenção do que reduzir o custo de implementação.

E essa história de Simplicidade. Não é meio relativo?

O Max responde essa pergunta também:

So, how simple do you have to be?

Honestly?

If you really want to succeed?

Stupid, dumb simple.

É claro que ele não pára por aí e aborda assuntos como consistência, legibilidade, como dar nomes, comentários e sobre como, para ser simples, você precisa de um bom design.

Conclusões

Eu apenas comentei rapidamente sobre as duas leis principais que o Max define no livro. Ele trata ainda de outros tópicos interessantes, baseando-se principalmente nas experiências dele no Bugzilla que eu acho de imenso valor. Como o livro é ridiculamente conciso, não vejo como não recomendá-lo. Mas não se engane pela grossura do livro. Com certeza é um dos que vou deixar sempre à vista para poder revisitar de vez em quando.

Também vale muito a pena dar uma olhada no blog do Max, que tem uns posts muito legais.

Além disso, tem uma série em 4 partes no youtube em que ele fala sobre as principais falhas no design de software:

Ah!

E você? Conhece algum livro com menos de 100 páginas que considere ser leitura obrigatória? Eu tenho notado que tem muita gente por aí escrevendo livros muito mais longos do que o necessário, precisamos de mais bons exemplos como o do Max!

Porque eu troquei o Read It Later pelo Evernote

Em um post anterior eu comentei um pouco sobre como o Read It Later me ajudava a reduzir a ansiedade por informação. Uma outra opção que, ultimamente, eu tenho usado mais é o Evernote. Mais precisamente, em substituição ao Read It Later, eu tenho usado o Evernote Web Clipper, que IMO tem algumas vantagens que eu vou mostrar pra vocês agora.

Como funciona

Muito simples. Ao encontrar uma página que te interesse, basta pressionar ` (a crase). O Web Clipper vai te apresentar algumas opções, em um menu à direita, como na imagem:

Evernote Web Clipper

Nesse momento, você escolhe em qual notebook vai adicionar a página. Como eu ainda não li o conteúdo com calma, eu geralmente jogo no notebook Inbox, que eu processo periodicamente à la GTD.

A funcionalidade principal do Web Clipper, nesse momento, é que ele consegue salvar a página como um Simplified Article, ou seja, apenas o conteúdo principal da página, sem distrações. Isso funcionou bem pra 99% das páginas que eu encontrei até agora.

E por que é melhor?

Até aqui nada de diferente do que pode ser feito com o Read It Later. Contudo, na hora de ler o conteúdo é que o Evernote brilha, principalmente, porque ele permite uma leitura mais ativa (dizem por aí que isso ajuda a absorver e fixar melhor as informações).

Permite editar o texto

Ao transformar a página em uma nota, ganhamos a vantagem de poder editar o conteúdo, removendo partes que não nos interessam e também adicionando conteúdo.

Permite anotar as imagens

Além do texto puro, conseguimos também adicionar marcações e textos às imagens:

EvernoteImagemAnnotation

Highlights

Além de poder editar o texto como quiser, há também a opção (mais rápida) de adicionar highlights ao texto. Facilitando encontrar os pontos principais no futuro, quando você revisitar a nota:

Evernote Highlights

Por fim

Além das funcionalidades acima, o Web Clipper facilita a tarefa de manter tudo no Evernote, o que é um pré-requisito para potencializar a sua utilidade.

Com certeza há muito mais funcionalidades que podem te ser úteis tanto no Evernote quanto no Web Clipper, essas são apenas as que me têm sido mais úteis ultimamente. Comentem aí, caso tenha deixado alguma funcionalidade interessante de fora? :)

Apprenticeship Patterns – Guidance for the Aspiring Software Craftsman – Book Review

“Mastery is more than knowing. It’s knowing in a way that lightens your load.”  (Ward Cunningham)

apprenticeship_patterns

O Apprenticeship Patterns foi um livro que estava dando sopa na empresa, eu dei uma folheada e acabei trazendo pra casa, porque gostei bastante. Trata-se de um livro de 2009 cujo principal objetivo é que nos tornemos excelentes desenvolvedores. Para isto ele anos ajuda com lições que vão desde como nos organizar pessoalmente até dicas de posturas a serem tomadas quando estamos trabalhando em equipe.

Todas as lições estão no formato:

Contexto -> Problema -> Solução -> Ações

Por isso o Patterns no título do livro.

Apprenticeship?

De acordo com o vocabulary.com:

Apprenticeship is a kind of job training that involves following and studying a master at the trade on the job instead of in school.

Ou, nas palavras dos autores:

Apprenticeship is a way to learn about being a professional software developer. Specifically, it is a way to learn to be like the most skilled software developers you can find. It involves seeking out good teachers, and taking opportunities to learn by working alongside them. It is the first step on the road toward becoming a different kind of software professional—one who wants to be more than just competent.

Por que eu deveria ler?

Pra mim, a maior contribuição do livro está nas seções de Ações que você pode realizar imediatamente para melhorar ou resolver cada um dos problemas. Isso porque os problemas são comuns e a maioria de nós que já os enfrentou consegue pensar em algumas soluções. Contudo, muitos têm dificuldade em transformar essas soluções em ações concretas ou toma decisões equivocadas, por inexperiência.

O livro aborda problemas e momentos pelos quais fatalmente um craftsman vai passar em sua carreira, como:

  • O Faixa Branca: “Eu conheço relativamente bem a minha primeira linguagem e os meus colegas até me consultam quando têm problemas. Contudo, aprender coisas novas tem se tornado cada dia mais difícil. Sinto que não consigo mais me desenvolver”
  • Mantenha-se nas Trincheiras: “Como resultado da sua dedicação, você construiu a reputação de quem entrega software de maneira efetiva. Na sua empresa trabalho excepcional é recompensado com subidas na hierarquia, logo,  uma promoção para um cargo que irá afastá-lo do desenvolvimento lhe foi oferecida.”

Conclusões

Definitivamente se trata de um livro que vale a pena ter à mão para revisitar de vez em quando. Não me recordo de um padrão que não tenha trazido uma lição valiosa ou uma contribuição à solução que eu já havia elaborado.

Contudo, mais importante ainda, nem sempre temos a auto consciência de que estamos passando por uma situação comum e que ações práticas podem ser tomadas imediatamente. Ler o livro poderá te ajudar a identificar isso.

A boa notícia é que, por enquanto, o livro está disponível gratuitamente no O’Reilly Atlas, então você pode ir lá dar uma folheada e ver se tem alguma lição que pode te ajudar no seu momento atual.

Brincando com Numba pra poder usar Python no Google Code Jam 2014

TL;DR; Fiz uns testes simples simplórios com o numba, com uma abordagem não-científica, na solução de um problema para o code jam’14. Obtive um speed-up de 50x e fiquei faceiro por poder continuar usando Python nos próximos rounds (hahaha, como se eu fosse passar). A proposta não é explicar como o numba funciona, mas apenas como ele me ajudou e, quem sabe, pode te ajudar.

The long story

Semana passada ocorreu o qualification round do code jam 2014 e eu, que gosto muito desse tipo de competição desde a faculdade, despretensiosamente tentei resolver os dois probleminhas mais fáceis e acabei passando de fase.

No qualification round eu usei  Python, mas conforme os rounds vão avançado os problemas vão se complicando e as estatísticas mostram que a proporção de competidores que usam C/C++ e Java vai crescendo, enquanto as outras linguagens vão ficando pra trás, principalmente por performance.

Como eu já estava interessado em dar uma olhada nas alternativas mais modernas (fáceis, 80/20, you know?) de otimizar minhas soluções em Python, e não estou afim de usar Java (awesome language, btw) ou C++ nas minhas horas de lazer, aproveitei o feriadão pra brincar um pouco, nada rigoroso.

O que “pega” é que temos muitas alternativas hoje(!): numpy, cython, pypy, jython, numba, blaze, numexpr, entre outros, sem falar na joblib, sobre a qual eu pretendo escrever um (ou mais) post mais pra frente. A boa notícia é que a maioria dessas alternativas pode se complementar e podemos ter small-wins fáceis só estudando um pouco.

Enfim, comecei a ler artigos aleatórios e acabei concluindo que o numba seria uma boa primeira tentativa, principalmente porque ia doer menos, como vamos ver agora.

Instalando

Very easy, se você não se importa de usar o conda (no OSX não sei se tem pra onde fugir):

$ conda install numba

Otimizando

Como o meu objetivo de curtíssimo prazo era ver se o numba seria uma boa opção pra usar no próximo round, nada melhor do que testá-lo nos problemas do round anterior.

Você não precisa se preocupar muito em entender 100% do código (e eu não me preocupei em deixá-lo 100% legível :D), porque eu vou destacar as partes mais importantes a cada etapa de otimização, mas o código original que eu submeti durante a competição para o problema Cookie Clicker foi o seguinte:

#!/usr/bin/env python
# coding=utf-8

import fileinput

data = (l for l in fileinput.input())
T = int(data.next())

def worth_build_another_farm(rate, C, F, X):
    time_to_reach_X = X / rate
    time_to_build_another_farm = C / rate
    time_to_reach_X_in_the_new_rate = X / (rate + F) 

    return time_to_reach_X > time_to_build_another_farm + time_to_reach_X_in_the_new_rate

for i in xrange(1, T+1):
    C, F, X = [float(f) for f in data.next().split()]

    rate = 2.0 # cookies/sec
    elapsed_time = 0.0

    while worth_build_another_farm(rate, C, F, X):
        elapsed_time += C / rate # time to build another farm
        rate += F 

    # by now I've burned all cookies building new farms
    elapsed_time += X / rate 

    answer = elapsed_time
    print('Case #%d: %.7f' % (i, answer))

Em alto nível, são apenas dois loops: o primeiro for que lê a entrada e o while que chama a função #worth_build_another_farm enquanto fizer sentido para cada entrada, nada de complicado.

Esse código estava resolvendo o Large Input em 0.3s.

Não tem mágica

O jeito mais simples de usar o numba é através do decorator @numba.jit, usado para indicar que a função deve ser compilada just-in-time. Assim, a minha primeira tentativa de otimização foi, logo de cara, colocar um @numba.jit na função #worth_build_another_farm, que resultou em um tempo de execução de 0.4s… Wat?

O que eu posso imaginar é que o tempo de execução do script não era lá dos maiores e, logo, o tempo que o numba levou pra compilar a função (JIT, lembram?) não se pagou.

A primeira vitória

Com isso eu pensei: “será que se eu jogar TODA a lógica do script (fora a leitura do input) para o numba otimizar vai resultar em ganho?”. O primeiro passo foi refatorar o código e colocar toda a lógica em apenas uma função, a #elapsed_time abaixo:

@numba.jit
def elapsed_time(rate, C, F, X):
    def worth_build_another_farm(rate, C, F, X):
        time_to_reach_X = X / rate
        time_to_build_another_farm = C / rate
        time_to_reach_X_in_the_new_rate = X / (rate + F)

        return time_to_reach_X > time_to_build_another_farm + time_to_reach_X_in_the_new_rate

    elapsed_time = 0.0

    while worth_build_another_farm(rate, C, F, X):
        elapsed_time += C / rate # time to build another farm
        rate += F

    # by now I've burned all cookies building new farms
    return elapsed_time + X/rate

start = time.time()

for i in xrange(1, T+1):
    C, F, X = [float(f) for f in data.next().split()]

    rate = 2.0 # cookies/sec

    answer = elapsed_time(rate, C, F, X)

É interessante notar aqui que, apenas com essa modificação (sem usar o numba) o tempo de execução com Python puro já caiu pra 0.23s. Isso ocorre muito provavelmente pela redução do escopo da #worth_build_another_farm, que agora é uma nested function e buscar por ela tornou-se mais rápido do que buscar no escopo global.

Contudo, ao tentar usar o numba dessa vez, obtive um erro:

NotImplementedError: offset=3 opcode=84 opname=MAKE_FUNCTION

E com isso chegamos à nossa 2ª lição: o numba não otimiza nested functions (linha 2).

A segunda vitória

Refatorando o código para remover a nested function e, finalmente, podendo usar a @numba.jit:

@numba.jit
def elapsed_time(rate, C, F, X):
    elapsed_time = 0.0

    worth = True
    while worth:
        time_to_reach_X = X / rate
        time_to_build_another_farm = C / rate
        time_to_reach_X_in_the_new_rate = X / (rate + F)
        worth = time_to_reach_X > time_to_build_another_farm + time_to_reach_X_in_the_new_rate

        if worth:
            elapsed_time += C / rate # time to build another farm
            rate += F

    # by now I've burned all cookies building new farms
    return elapsed_time + (X / rate)

start = time.time()

data = (l for l in fileinput.input())
T = int(data.next())

for i in xrange(1, T+1):
    C, F, X = [float(f) for f in data.next().split()]

    rate = 2.0 # cookies/sec
    answer = elapsed_time(rate, C, F, X)
    #print('Case #%d: %.7f' % (i, answer))

print "Finished in ", time.time()-start, " secs."

Conseguimos uma nova vitória com o novo tempo de execução de 0.06s.

A terceira vitória

Nesse momento eu já tinha um speed-up razoável, de 5x, apenas refatorando o código e adicionando um decorator. Contudo, a @numba.jit ainda estava sendo usada na sua forma mais simples, em que o numba é forçado a fazer inferência dos parâmetros e do retorno da função.

Por sorte, podemos ajudar o numba a nos ajudar. Nós podemos dizer ao numba quais são os tipos dos nosso parâmetros e o tipo do retorno da função. Para esse problema, eu sabia que os parâmetros seriam sempre floats e um int e que o retorno seria sempre um float. Será que definindo a assinatura da função seria possível obter um tempo melhor? Alterando a linha 1 do código anterior para:

@numba.jit('f8(f8,i4,f8,f8)')

obtive a terceira vitória com um novo tempo de execução: 0.006s.

Great, agora temos um speed-up apresentável, de 50x. Por hoje, estou satisfeito :D

Conclusões

É possível obter algumas melhoras rápidas no desempenho do código com o numba. Se a #elapsed_time fosse o principal gargalo no processamento de 1M de linhas de um banco de dados, por exemplo, ao invés de esperar 83.3 horas com a solução inicial, esperaríamos apenas 1.6 horas, tudo por causa de um refactoring e um decorator do numba.

Not bad

Por fim, usar o numba tem suas implicações e, como vimos na primeira tentativa de otimização, ele não pode ser utilizado indiscriminadamente. Caso você decida utilizá-lo, vale a pena começar pelos seguintes textos para que você tenha uma visão melhor dos trade-offs  a que estará sujeito e dos ganhos que pode esperar obter:

Ah, você pode encontrar as versões intermediárias do cookieclicker no meu github.

Book Review: The Phoenix Project

The Phoenix Project

No mês passado eu li o The Phoenix Project, livro que estava na primeira posição do Top 100 Agile Books do Jurgen Appelo, primeiro motivo pelo qual eu achei legal dar uma olhada. O segundo foi porque ele é A Novel About IT, DevOps… e eu ainda não tinha parado pra criar uma imagem bem definida sobre o que é esse tal de DevOps que o povo tanto fala por aí.

Como o próprio subtítulo já diz, se trata de A Novel, ou seja, uma historinha, um romance. Então, não espere um livro técnico cheio de do’s and don’ts.

Pra ser bem sincero, o começo da história é um pouco entediante e eu quase desisti de lê-lo quando estava lá pela centésima página (de um livro de 340 páginas!). Contudo, após o primeiro terço não tão legal, a coisa começa a esquentar. Como não é um livro técnico, não vou entrar em muitos detalhes da trama para não estragar a sua leitura. Contudo, fica a dica para perseverar.

O livro conta a história do Bill, que era chefe de uma pequena divisão e acaba sendo promovido a VP of IT Operations de uma empresa de peças para carros, na qual se tinha a visão de que TI era apenas uma atividade meio. Ao assumir o cargo ele se depara com várias bizarrices no modo como as coisas eram feitas na empresa, que era totalmente disfuncional. Essa empresa tinha o tal do Projeto Phoenix que deveria ser a salvação da lavoura, pois a tiraria de um atraso de anos (porque o Phoenix estava atrasado há anos) em relação aos competidores. O problema é que havia vários problemas que forçavam as equipes a passar a maior parte do tempo apagando incêndios.

O restante do livro conta o processo pelo qual o Bill, auxiliado pelo seu mentor Erik, passa a entender o que é realmente importante para a entrega de software e começa a desfazer os erros do passado utilizando abordagens que integram mais todas as partes envolvidas na produção e entrega de um software (ah, o tal do DevOps).

Bem, em alto nível é isso, não quero estragar a sua leitura. Mas gostei do formato pouco comum para apresentar de forma suave tópicos que são difíceis para algumas pessoas de serem compreendidos quando são apresentados através de regras em um livro mais técnico. É legal que a gente se sente na pele do cara responsável por resolver pepinos que muita gente deve encontrar nas próprias empresas onde trabalham. Principalmente para aqueles que ainda trabalham em empresas  em que devs, testers, OPs e afins trabalham isoladamente, recomendo a leitura do livro. Quem sabe ele sirva de inspiração para futuras mudanças positivas no seu dia-a-dia. Ou então passa pro teu chefe, quem sabe assim ele abre o olho :D

Para o pessoal que já tem acompanhado e tentado aplicar técnicas mais Lean/Ágeis nas suas empresas, acho que o livro não vai agregar tanto, mas ainda vale como uma leitura mais leve, de lazer.

Transformando seu projeto python em um pacote (instalável via pip) em 2 passos

Essa semana eu precisei extrair um (sub)projeto para um pacote que torço para que, brevemente, vá para o PyPi. Surpreendentemente, não doeu tanto e o processo pode ser resumido em dois passos:

1º Passo: Ajustar o Layout do Projeto

O layout que eu usei foi seguindo o modelo abaixo:

awesome_project/
    bin/
    LICENSE.txt
    README.txt
    setup.py
    awesome_project/
        __init__.py
        awesome_module.py
        utils.py
        test/
            __init__.py
            test_awesome_module.py
            test_utils.py

De todos os arquivos acima, provavelmente o que você não tem hoje no seu projeto é o setup.py.

2º Passo: Definir um setup.py

É no setup.py que você vai descrever o teu pacote. Ele deve ter mais ou menos essa cara:

setup(
    name='awesome_project',
    version='0.1.0',
    author='Joãozinho',
    author_email='joaozinho@example.com',
    packages=['awesome_project', 'awesome_project.test'],
    url='http://pypi.python.org/pypi/awesome_project/',
    license='LICENSE.txt',
    description='Esse projeto vai mudar o mundo, for real.',
    long_description=open('README.txt').read(),
    install_requires=[
        "Django >= 1.1.1",
        "caldav == 0.1.4",
    ],
)

E isso é o mínimo do mínimo que você precisa pra gerar um pacote.

Daqui pra frente os teus projetos podem seguir essa estrutura de diretórios, facilitando a sua vida caso você queira transformá-lo em um pacote.

Tá, mas como eu instalo?

Piece of cake. Na raíz do projeto:

$ python setup.py sdist

Isso vai gerar alguns arquivos, o principal deles é o teu pacote, que vai estar no diretório dist.

Pra instalar via pip:

$ pip install dist/awesome_project-0.1.0.tar.gz

Bônus 1: Mas Zé, o meu projeto está no github. Eu tentei usar um README.md e deu erro:

IOError: [Errno 2] No such file or directory: 'README.md'

mas o arquivo está lá(!).

É, por default o distutils não inclui arquivos .md nos pacotes. Você precisa criar um arquivo MANIFEST.in. Nele você pode definir que quer adicionar, por exemplo, todos os *.md ao seu pacote:

include *.md

Generalizar conforme a necessidade.

Bônus 2: Zé, meu projeto tem scripts também. Dá pra instalar junto?

Dá sim. Na estrutura de diretórios lá em cima tem um bin/. Nele você pode adicionar os seus scripts e, então, definir no setup.py os que você quer que sejam instalados. Basta definir o parâmetro scripts da setup():

scripts=['bin/awesome_script', ...]

Pra saber mais

Isso foi o que eu aprendi com o meu projeto. Pra saber mais consulte o The Hitchhiker’s Guide to Packaging.

Praticando o desapego pelas abas (ou Como manter uma dieta de pouca informação)

Finalmente eu tirei um tempo pra fazer um screencast sobre o método que eu uso pra tentar manter o foco no que eu preciso, reduzindo o multitasking e reduzindo a sensação de atraso causada por uma quantidade enorme de abas abertas no navegador. Com isso, fica mais fácil priorizar também as informações que eu vou consumir no pouco tempo livre que eu, assim como todo mundo que trabalha 40h semanais, tem.

É o meu primeiro screencast público, portanto tentem ser tolerantes. Ficou muito mais longo do que eu gostaria, mas foi o segundo “take” e não consegui baixar de 5 minutos. Critiquem nos comentários, assim eu melhoro no próximo.

Ps: Eu gosto de screencasts e os acho mais efetivos, mas é um troço com pouca tolerância a falhas (se você não tiver um editor de vídeos), né? Posts textuais acabam sendo mais tranquilos no final das contas.