About me

About

2014-07-13

Pythonices, classes ou funções.

Eu uso algumas regras simples para decidir entre usar classes ou funções, em python:

  • se existe necessidade de manter estado: classes;
  • caso contrário: funções;
  • para agrupar informação relacionada, tuples ou namedtuples.

2014-07-02

Configurações.

Algumas configurações pouco comuns mas muito úteis.

  1. Num ambiente X ter teclas e rato rápidos… mas não demais.

    xset m 1
    xset r rate 220 80

    A segunda faz-me bastante falta, e é um efeito que não se consegue obter em Windows (excepto eventualmente se se usarem truques não triviais).

  2. Cores para ecrãs de texto: letras verdes em fundo preto.

    Costumava usar um simples green/black (testar=> xterm -fg green -bg black), mas os novos ecrãs de LED IPS têm um contraste muito maior, o que torna o “green” muito mais brilhante do que estava habituado.

    Após alguma pesquisa, o chamado “kelly green” (fonte: wikipedia) provou ser o melhor verde para este tipo de painéis de alto contraste.

    xterm -fg #4CBB17 -bg black
  3. Fontes mono-espaçadas para terminais e desenvolvimento: DejaVu Sans Mono Book.

    Atenção à semelhança entre alguns caracteres. Ver se os seguintes são suficientemente diferentes para serem facilmente distinguidos:

    i1lI O0

    Em particular gosto que o zero tenha algo no meio (risco, ponto) e que o “l” pequeno faça uma curvinha pelo menos em baixo.

    A fonte “DejaVu Sans Mono Book” tem representações suficientemente diferentes. Outras boas alternativas:

    • Liberation Mono
    • Inconsolata

    Bom exemplo: bom exemplo

    Mau exemplo: mau exemplo

2014-06-29

Pythonices, throttling.

Problema: precisamos de executar uma acção sujeita a limites temporais, não mais que n execuções por segundo são permitidas. Chamemos a isto throttle.

Como boa prática a função de throttle deve estar separada da acção f a executar. Uma abordagem funcional é perfeita: f = throttle(count, timeframe, f), tal que a função retornada por throttle() tenha o mesmo inteface que f.

Isto é precisamente o que fazem os decoradores em python.

Eis a minha implementação desta funcionalidade.

import datetime

def throttle(count, timeframe):  # timeframe in seconds
    def work(fn):
        # state is lasttimemarker, remaining count
        state = [datetime.datetime.now(), count]

        def __work(*args, **kwargs):
            elapsed = datetime.datetime.now() - state[0]
            ntimeframes = int(elapsed.total_seconds() // timeframe)
            if ntimeframes > 0: ## just an optimization
                state[1] += count * ntimeframes
                state[0] += datetime.timedelta(seconds=timeframe) * ntimeframes
            if state[1] <= 0:
                wait_time = timeframe - elapsed.total_seconds() % timeframe
                time.sleep(wait_time)
                return __work(*args, **kwargs)
            state[1] -= 1
            rv = fn(*args, **kwargs)
            return rv
        return __work
    return work

####

import time

# exec 3 times on each 5 seconds timeframe
@throttle(3, 5)
def printtime():
    print time.ctime(time.time())
    
for i in range(10): printtime()
Sat Jun 28 17:16:08 2014
Sat Jun 28 17:16:08 2014
Sat Jun 28 17:16:08 2014
Sat Jun 28 17:16:13 2014
Sat Jun 28 17:16:13 2014
Sat Jun 28 17:16:13 2014
Sat Jun 28 17:16:18 2014
Sat Jun 28 17:16:18 2014
Sat Jun 28 17:16:18 2014
Sat Jun 28 17:16:23 2014

2014-06-28

Pythonices, enumerate.

Uma idiossincrasia comum em python é iterar com ciclos for.

xs = "a b c d".split()
for x in xs:
    print x
a
b
c
d

Mas por vezes é necessário ter um contador associado. A solução mais imediata é manter um contador à parte e incrementá-lo dentro do loop. Por vezes é necessário trocar o for por um while.

Felizmente existe uma construção nativa que permite associar uma contagem a qualquer iterador: enumerate.

xs = "a b c d".split()
for i,x in enumerate(xs):
    print i,x
0 a
1 b
2 c
3 d

O enumerate é a aplicação de uma técnica comum em linguagens funcionais: transformar uma lista de valores (escalares) numa lista de tuples, juntando a informação adicional no outro membro do tuple.

Repare-se que o enumerate corresponde à aplicação de duas funções do módulo itertools.

import itertools
xs = "a b c d".split()
for i,x in itertools.izip(itertools.count(), xs):
    print i,x
0 a
1 b
2 c
3 d

2013-10-15

Pythonices, simplificar objectos de dados.

Um objecto de dados só tem estado, não tem comportamento. Ou traduzindo para python: são instâncias de classes sem métodos, apenas com variáveis.

Formas de definir classes de dados.

Auto iniciar locais a partir dos argumentos

É a solução clássica e mais explícita:

class P:
    def __init__(self, sln, dll=None, aspnet=None): 
        self.sln = sln
        self.dll = dll
        self.aspnet = aspnet

Solução dinâmica

Compacta, python voodoo.

class P:
    def __init__(self, sln, dll=None, aspnet=None): self.__dict__.update(locals())

Ou para ser-se pedante

Falta remover o self do próprio dicionário.

class P:
    def __init__(self, sln, dll=None, aspnet=None): self.__dict__.update(locals()); del self.self

E agora uma coisa completamente diferente: namedtuple

Continuando no exemplo acima, mas desta vez sem defaults.

from collections import namedtuple
P = namedtuple("P", "sln dll aspnet".split())

p = P("xpto.sln", "xpto.dll", None)
print p

# recuperando a solucao classica
class Pc:
    def __init__(self, sln, dll=None, aspnet=None): 
        self.sln = sln
        self.dll = dll
        self.aspnet = aspnet

    def __str__(self): return str([self.sln, self.dll, self.aspnet])

p = Pc("xpto.sln", "xpto.dll", None)
print p

Tem como resultado:

P(sln='xpto.sln', dll='xpto.dll', aspnet=None)
['xpto.sln', 'xpto.dll', None]

Resumindo:

  • o namedtuple fornece uma forma simples e legível de definir objectos de dados simples;
  • as formas compactas são úteis para prototipagem.

2013-10-08

Ubíquo Word.

O Word não só matou a documentação técnica como tomou o mundo da documentação de assalto. Desde a composição de documentos de notas com 3 ou 4 linhas, a livros com centenas de páginas, o seu uso é universal. Como as pessoas se habituaram ao Word, exigem receber documentos de Word. A situação chega a ser tão caricata como os seguintes casos reais:
  • Cerca do ano 2000 enviei o meu CV em PDF a uma conhecida empresa. Responderam-me a dizer que não o conseguiam abrir – na altura o acrobat reader não estava muito disseminado – e que eu enviasse logo a versão “Word”. Algo impossível tendo em conta que eu não tinha usado sequer o Word para o produzir1.
  • Há uns anos enviei um artigo a um colega meu para revisão. Ele respondeu, algo frustrado, que tinha tido muito trabalho a editar o meu artigo porque eu não estava a usar um formato standard, e recomendou-me que da próxima vez o fizesse, que enviasse um doc de Word. O formato que lhe tinha enviado era HTML.
  • Num sítio onde trabalhei havia um processo manual para fazer backups. Eu estava lá contratado para fazer administração de sistemas, mas aproveitei algum tempo livre para desenhar e desenvolver um software que automatizava o sistema de backups. O cliente ficou satisfeito com esse sistema novo mas alertou que não havia documentação. Compilei num README.txt toda a informação técnica sobre esse sistema. Como estava construído, como se instalava no master e nos slaves, como se corria… no dia seguinte mostrei o ficheiro de texto ao cliente. Instantaneamente vira-se para mim e diz: “Isto não é nada” (mesmo assim). Perguntei porquê, o que esperava ter encontrado que não estivesse no documento. Olhou-me de forma estranha, hesitou um pouco e disse que aquilo não era um documento. Apenas. Na realidade ele esperava a mesma informação só que num ficheiro Word. Um ficheiro de texto, apesar de conter o mesmo conteúdo, não era considerado “um documento”.
  • Por fim, ainda me recordo de algumas coisas me terem caído ao chão – e não vou detalhar se em sentido alegórico ou não – quando vi este requisito por parte de uma empresa pública: “O adjudicatário entregará à entidade adjudicante (…) a seguinte documentação em suporte digital (.pdf e .doc/.ppt/.rtf) e em papel: (…)”.

  1. tinha usado groff.

2013-10-07

15 anos de desenvolvimento de software.

Ao longo de 15 anos na área do desenvolvimento de software, sobretudo no mundo das telcos, eis o cenário que pinto sobre o estado de arte nacional.

  1. Não se faz 100% desenvolvimento: ao longo do tempo acabam por se fazer coisas tão díspares como administração de sistemas, coaching, entrevistas, gestão de projectos, burocracia e, sobretudo, pré-venda. Varia com cada um, mas há sempre desvios. Razões para isto?
    • não existe mercado em Portugal para manter uma função exclusiva de desenvolvimento;
    • o desenvolvimento feito em Portugal tipicamente é básico, logo pode ser feito por juniores, logo…
    • não há carreira técnica;
    • não há investimento em inovação, quanto mais em pesquisa;
    • a inovação existente resulta da utilização ou colocação em prática de novos softwares ou práticas vindas de fora, e.g. inovação por compra de novos produtos ou upgrade de versões.
  2. A estratégia de TI empresarial está sujeita aos fornecedores tecnológicos.

  3. O desenvolvimento nacional é pouco ambicioso e simples: a maior parte dos projectos desenvolvidos de raiz são uma implementação básica – ainda que por vezes massiva e/ou complicada – de um modelo source-process-dump. E.g. boa parte das aplicações web.

  4. As necessidades de software mais exigente, do ponto de vista de complexidade, são normalmente supridas por soluções 3rd party.

  5. Os projectos atrasam-se ou correm mal raramente por questões técnicas – já que são simples q.b. – mas por:
    • requisitos mal especificados inicialmente e alterados de forma inconsistente – continuando mal especificados – ao longo do projecto;
    • problemas de integração com outros sistemas;
    • indisponibilidade de ambientes e dados.
  6. A tecnologia escolhida tem pouco impacto no projecto e é irrelevante para a organização: mesmo que outras linguagens e plataformas melhorassem 10x a produtividade no desenvolvimento e deploy, esse tempo seria diluído nas ineficiências gerais do projecto.

  7. A falta de qualidade do código é suprida via testes, ou seja, prática de code-and-fix.

  8. Os programadores juniores apresentam lacunas, que são impeditivas de realizar software bem construído embora suficientes para realizar os nossos projectos básicos (ainda que sem uma boa construção), em:
    • estruturação;
    • abstracção;
    • automatização;
    • scripting e prototipagem.

    As práticas de código mais comuns baseiam-se em excesso de programação imperativa mal estruturada com abuso de copy paste. Há evidência baseada em estudos que estes factores não melhoram com a experiência.