About me

About

2011-09-30

Numeração romana e sed.

A lógica da numeração romana é curiosa porque não se baseia em nenhuma base, embora o 5 e o 10 tenham um papel tipo base.

Outro aspecto interessante da sua lógica é que obedece a um padrão greedy. Como tal podem-se usar expressões regulares para converter de/para romano. Entra o sed.

  • conversão de romano para decimal

    #! /bin/sed -f

    # fr_roman.sed -- from roman (to decimal)
    # Carlos Duarte, 980707

    # usage: echo MCMXCVIII | sed -f fr_roman.sed
    # output: 1998
    #
    # converts roman literals to decimal
    # some input error checking is done, but not all cases are covered
    # (bigger constructions following smallers, for instance)
    #

    # build table, all possible constructs that evaluate to [1-9]0* are here
    1{
    x
    s/$/0/
    s/$/I1/
    s/$/II2/
    s/$/III3/
    s/$/IV4/
    s/$/V5/
    s/$/VI6/
    s/$/VII7/
    s/$/VIII8/
    s/$/IX9/
    s/$/X10/
    s/$/XX20/
    s/$/XXX30/
    s/$/XL40/
    s/$/L50/
    s/$/LX60/
    s/$/LXX70/
    s/$/LXXX80/
    s/$/XC90/
    s/$/C100/
    s/$/CC200/
    s/$/CCC300/
    s/$/CD400/
    s/$/D500/
    s/$/DC600/
    s/$/DCC700/
    s/$/DCCC800/
    s/$/CM900/
    s/$/M1000/
    s/$/MM2000/
    s/$/MMM3000/
    x
    }

    # converts from MMXXII to 2000,20,2, from lookup table
    s/^/\
    /
    G

    ta
    :a
    s/\n\(..*\)\(.*\n.*[0-9]\)\1\([1-9]0*\)/\3,\
    \2\1\3/
    tb

    s/\n/>>> error:/
    s/\n.*//
    #q
    b

    :b
    /\n\n/!ba
    s/\n\n.*$//

    # convert from 2000,20,2, to 2022. this is not trivial!
    #
    # steps:
    # 2000,20,2, -> 2000<20>2, <20> is the work digit
    :d
    s/,/</
    te
    :e
    s/,/>/
    tf

    # exit point here: contains `2022,' so, remove the `,' and go
    s/.$//
    b

    # 2000<20>2, -> 2000,:20<20>2, : is the cursor for changing the 20 in ,:20
    # into 00 (for later, remove these from 2000)
    :f
    s/<\(.*\)>/,:\1&/

    # 2000,:20<20>2, -> 2000,00:<20>2,
    tc
    :c
    s/:[0-9]/0:/
    tc

    # 2000,00:<20>2, -> 2020,2, convert next digit
    s/\(0*\),\1:<//
    s/>/,/
    bd
  • conversão de decimal para romano

    #! /bin/sed -f

    # to_roman.sed -- converts decimal to roman
    # Carlos Duarte, 980707

    # do not perform error checking
    # converts input treated as arabic decimals, to roman literal
    #
    # eg: echo 1998 | sed -f to_roman.sed
    # outputs: MCMXCVIII
    #

    # build table, all possible constructs that evaluate to [1-9]0* are here
    1{
    x
    s/$/1I/
    s/$/2II/
    s/$/3III/
    s/$/4IV/
    s/$/5V/
    s/$/6VI/
    s/$/7VII/
    s/$/8VIII/
    s/$/9IX/
    s/$/10X/
    s/$/20XX/
    s/$/30XXX/
    s/$/40XL/
    s/$/50L/
    s/$/60LX/
    s/$/70LXX/
    s/$/80LXXX/
    s/$/90XC/
    s/$/100C/
    s/$/200CC/
    s/$/300CCC/
    s/$/400CD/
    s/$/500D/
    s/$/600DC/
    s/$/700DCC/
    s/$/800DCCC/
    s/$/900CM/
    s/$/1000M/
    s/$/2000MM/
    s/$/3000MMM/
    x
    }

    s/.*/:&:/
    ta
    :a
    s/:.\([^:]*\):$/&\1:/
    ta

    :c
    s/:\(.\)/\1,/
    tb
    :b
    s/,[0-9]/0,/
    tb
    /,::$/bd
    s/,/;/
    bc

    :d
    s/...$/;/
    s/;00*//g
    s/^/,/

    G
    te
    :e
    s/,\([^;]*\);\(.*\n.*\)\1\([IVXLCDM][IVXLCDM]*\)/\3,\2\1\3/
    te
    s/.\n.*//
  • compilador de romano para expressão numérica do equivalente decimal

    • echo MCXLIII | sed -f from_roman.sed => 1000+100+40+1+1+1
    • echo MCMLXXXI | sed -f from_roman.sed => 1000+900+50+10+10+10+1
    #! /bin/sed -f

    # from_roman.sed -- output bc(1) code that convert roman to decimal
    # Carlos Duarte, 980707

    # usage: echo MCXLIII | sed -f from_roman.sed | bc

    s/$/\
    0M1000CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1/

    s/^/\
    /
    ta
    :a
    s/\n\(..\)\(.*\n.*[0-9]\)\1\([1-9]0*\)/\3+\
    \2\1\3/
    tb
    s/\n\(.\)\(.*\n.*[0-9]\)\1\([1-9]0*\)/\3+\
    \2\1\3/
    tb

    s/\n/0; ">>> error:/
    s/\n.*/"/
    #q
    b

    :b
    /\n\n/!ba
    s/.\n\n.*$//

2011-09-29

Código de ordenação em awk.

  • bubble sort

    function bubble_sort(arr, a, b,     i,done,t) {
    i = a
    done = 1
    for (;;) {
    if (i == b) {
    if (done)
    break
    i = a
    done = 1
    }
    if (arr[i] > arr[i+1]) {
    t = arr[i]
    arr[i] = arr[i+1]
    arr[i+1] = t
    done = 0
    }
    i = i+1
    }
    }


    # main
    { x[++n] = substr($0,1) } ## lexical sort
    #{ x[++n] = $0+0 } ## numerical sort
    END { bubble_sort(x, 1, n); for (i=1; i<=n; i++) print x[i] }
  • heap sort

    ## works only on arrays indexed [1..n]

    function heap_sort(arr, n, i,t) {
    make_heap(arr, n)
    for (i=n; i>1; i--) {
    t = arr[1]
    arr[1] = arr[i]
    arr[i] = t
    sift_down(arr, i-1, 1)
    }
    }

    function make_heap(arr, n, i) {
    for (i=int(n/2); i>=1; i--)
    sift_down(arr, n, i)
    }

    function sift_down(arr, n, i, k,j,t) {
    k = i
    do {
    j = k
    if (2*j <= n && arr[2*j] > arr[k])
    k = 2*j
    if (2*j < n && arr[2*j+1] > arr[k])
    k = 2*j+1
    t = arr[j]
    arr[j] = arr[k]
    arr[k] = t
    } while (j != k);
    }

    # main
    { x[++n] = substr($0,1) } ## lexical sort
    #{ x[++n] = $0+0 } ## numerical sort
    END { heap_sort(x, n); for (i=1; i<=n; i++) print x[i] }
  • insert sort

    # sorts array ARR[A..B]
    function insert_sort(arr, a, b, i,j,t) {
    for (i=a+1; i<=b; i++) {
    if (arr[i] > arr[i-1])
    continue
    t = arr[i]
    j=i-1
    do
    arr[j+1] = arr[j];
    while (--j>0 && t < arr[j]);
    arr[j+1] = t
    }
    }

    # main
    { x[++n] = substr($0,1) } ## lexical sort
    #{ x[++n] = $0+0 } ## numerical sort
    END { insert_sort(x, 1, n); for (i=1; i<=n; i++) print x[i] }
  • merge sort

    function merge_sort(arr, a, b,      k) {
    if (a<b) {
    k = int((a+b)/2)
    merge_sort(arr, a, k)
    merge_sort(arr, k+1, b)
    merge(arr,a,k,b)
    }
    }

    function merge(arr, a, k, b, i,j,p,c) {
    j = i = a
    p = k+1
    while (a <= k && p <= b) {
    if (arr[a] <= arr[p]) {
    c[i++] = arr[a++]
    } else {
    c[i++] = arr[p++]
    }
    }
    while (a <= k) c[i++] = arr[a++]
    while (p <= b) c[i++] = arr[p++]

    while (j<=b) {
    arr[j] = c[j]
    j++
    }
    }

    ## main
    function pr(arr,i,j) { while (i<=j) print arr[i++] }
    { x[++n] = substr($0,1) } ## lexical sort
    #{ x[++n] = $0+0 } ## numerical sort
    END { merge_sort(x, 1, i); pr(x, 1, i); }
  • quick sort

    function quick_sort(arr, a, b,      pivot,i,j,t) {

    if (a >= b)
    return

    if (a+1 == b) {
    if (arr[a] > arr[b]) {
    t = arr[a]
    arr[a] = arr[b]
    arr[b] = t
    }
    return
    }

    pivot = median(arr[a], arr[b], arr[int((a+b)/2)])
    i = a-1;
    j = b+1;
    for (;;) {
    while (arr[++i] < pivot)
    ;
    while (arr[--j] > pivot)
    ;

    if (i>=j)
    break

    t = arr[i]
    arr[i] = arr[j]
    arr[j] = t
    }
    quick_sort(arr, a, i-1)
    quick_sort(arr, i, b)
    }

    function median(a, b, c) {
    if (a<b) {
    if (b<c)
    return c
    if (a<c)
    return c
    return a
    }
    if (a<c)
    return c
    if (b<c)
    return c
    return b
    }

    # main
    { x[++n] = substr($0,1) } ## lexical sort
    #{ x[++n] = $0+0 } ## numerical sort
    END { quick_sort(x, 1, n); for (i=1; i<=n; i++) print x[i] }
  • selection sort

    # sorts array ARR[A..B]
    function selection_sort(arr, a, b, i,j,k,t) {
    for (i=a; i<=b; i++) {
    k=i
    for (j=i+1; j<=b; j++) {
    if (arr[k] > arr[j])
    k = j
    }
    if (k != i) {
    t = arr[i]
    arr[i] = arr[k]
    arr[k] = t
    }
    }
    }

    # main
    { x[++n] = substr($0,1) } ## lexical sort
    #{ x[++n] = $0+0 } ## numerical sort
    END { selection_sort(x, 1, n); for (i=1; i<=n; i++) print x[i] }

E por falar em ordenação...

E por falar em ordenação…

Um z80, lançado originalmente em 1976, ordenava 1000 números em 60s, usando o algoritmo selection sort, programado directamente em código máquina, com o processador dedicado a 100% à operação. Ou seja, aproveitando as potencialidades máximas do sistema.

Alguns anos mais tarde, vejamos o seguinte exercício:

  • CPU: Intel(R) Core(TM)2 Duo CPU T7250 @ 2.00GHz, mas fixado a 800MHz
  • sistema operativo linux 2.6.33.7 32 bits
  • 101 processos mas load average 0.00, i.e. máquina virtualmente sem carga
  • linguagem awk: interpretada, de “alto nível”
  • cenário: ordenação de strings de tamanho arbitrário
  • algoritmos: selection sort, insertion sort, heap sort, bubble sort, merge sort, quick sort

Execução:

dd if=/dev/urandom | tr -c -d A-Za-z0-9_\\n | sed 10000q | \time mawk -f quick_sort.awk | sort -c
  1. dd if=/dev/urandom | tr -c -d A-Za-z0-9_\\n | sed 10000q: produção de 1000 linhas de texto aleatórias;
  2. \time mawk -f quick_sort.awk: ordenação do input e medição do tempo que demorou
  3. sort -c: validação da correcção da ordenação

Algumas medições efectuadas, com os tempos sempre em segundos:

  • selection sort revisitado às 1000 linhas: 0.37;

  • Benchmark de 10k linhas (tempo em segundos):
    • bubble_sort.awk => 100.78
    • selection_sort.awk => 26.70
    • insert_sort.awk => 16.76
    • heap_sort.awk => 1.66
    • quick_sort.awk => 1.41
    • merge_sort.awk => 1.33

Agora algumas contas:

  • se o selection sort é O(n^2), significa que o tempo de execução num ambiente pode ser calculado derivando uma constante c;
  • assim: t=n^2/c; logo c=n^2/t;
  • como já temos n=1000 e t=26.70 no caso do selection sort, fica c=3745318;
  • qual o número de itens necessários para a ordenação demorar 60s? n^2=ct => n=sqrt(ct), sabemos c=3745318 e pretendemos t=60, logo n=14990;
  • testando:
    • dd if=/dev/urandom | tr -c -d A-Za-z0-9_\\n | sed 14990q | \time mawk -f selection_sort.awk |sort -c
    • Resultado: 63.87. Perfeito. :)

Estes resultados mostram uma coisa que por vezes é negligenciada: o hardware tem evoluído bastante mas a dimensão dos dados também. Se os algoritmos que processam os dados não forem eficientes, o novo hardware traz poucos ganhos em escala e pode acontecer a lentidação causada pelo crescimento dos dados ultrapassar os ganhos introduzidos pelo novo hardware.

Neste pequeno exemplo, uma ordenação de 1k números no velhinho spectrum corresponde a uma ordenação de 15k num portátil hoje em dia, em powersave :), mais coisa menos coisa. A comparação não foi 100% rigorosa (assembler vs awk, etc) mas tem o rigor suficiente para o que se demonstra.

2011-09-27

Memórias do zx spectrum... e código máquina!

No fim de semana estive a fazer uma limpeza (leia-se: pôr no lixo) a coisas velhas. Invariavelmente nestas alturas acontecem duas coisas: um ataque de nostalgia… e a redescoberta de algumas preciosidades.

Acabei por encontrar literalmente centenas de páginas de código para o ZX Spectrum que fiz quando era mais novo. A maior parte é código máquina para o z80, o processador que equipava o spectrum. Centenas de páginas em papel mesmo, tudo manuscrito, que era a única forma que eu tinha na altura de fazer código: escrevê-lo em papel.

Curiosidades:

  • fazia o código todo em papel primeiro, em rascunho, e posteriormente passava a limpo, para ficar legível, como se vê nas fotos mais abaixo;

  • normalmente as coisas funcionavam bem à primeira, o que até é lógico, porque escrevendo as coisas no papel presta-se muito mais atenção que fazendo-o directamente no computador;

  • o detalhe dado à documentação! A frente de cada folha servia para listar o código máquina e o verso para o documentar, com casos de uso, notas, fluxogramas e tudo. Fiquei seriamente surpreendido:

    1. primeiro pelos bons hábitos que tinha antes de ser profissional, sem qualquer tipo de formação… e que se perderam quando passei a sê-lo!

    2. pela paciência que tinha!

    3. o meu motto no linkedin nunca esteve tão certo como nesta altura: “Goal: to get a life!”.

Este material data dos anos 1991 ~ 1992…
Rotina de ordenação em assembler.

Tinha desenhado estas pautas para escrever os meus programas. A primeira coluna era o endereço de memória onde o programa iria residir, a segunda era o código máquina em hexadecimal e a terceira era a mnemónica assembler. Tudo feito à mão. Que paciência :-)

Nesta altura ainda não sabia nada de algoritmos nem estruturas de dados, como tal “inventei” um algoritmo qualquer de ordenação que me veio à cabeça. Acho que é o selection sort.

código de ordenação

A correspondente documentação no verso da página. Algumas preciosidades:

  • Ocupa 70 bytes + 2 para dados”.
  • Demora cerca de 60 segundos para ordenar 1000 números”.
  • A seguinte fórmula dá-nos aprx o tempo em segundos da ordenação: n^2/16000” — interessante que sem qualquer conhecimento de algoritmia e notações O(), relacionei claramente o tempo de execução com a ordem assimptótica do algoritmo, O(n^2). Eheh!!

documentação nas costas

Páginas e páginas e páginas de código e documentação manuscritas.

papéis

Validar o NIF em XPath.

Um proof of concept que fiz há uns anos.

Nota: comando xml

#! /bin/sh
f() {
xml sel -t -c '

/foo[string-length(nif)=9 and
string(
(11 -
(substring(nif,1,1)*9+
substring(nif,2,1)*8+
substring(nif,3,1)*7+
substring(nif,4,1)*6+
substring(nif,5,1)*5+
substring(nif,6,1)*4+
substring(nif,7,1)*3+
substring(nif,8,1)*2) mod 11) * number(
(11 -
(substring(nif,1,1)*9+
substring(nif,2,1)*8+
substring(nif,3,1)*7+
substring(nif,4,1)*6+
substring(nif,5,1)*5+
substring(nif,6,1)*4+
substring(nif,7,1)*3+
substring(nif,8,1)*2) mod 11) < 10))
= substring(nif,9,1)]/nif/text()'
}

g() {
read line
echo "$line" | xml sel -t -c '//nif' | tr -d \\n
answer="$(echo "$line" | f)"
if test "$answer" = ""; then
echo " - BAD";
else
echo " - OK";
fi
}

printf '<foo><nif>123456780</nif></foo>\n' | g
printf '<foo><nif>123456781</nif></foo>\n' | g
printf '<foo><nif>123456782</nif></foo>\n' | g
printf '<foo><nif>123456783</nif></foo>\n' | g
printf '<foo><nif>123456784</nif></foo>\n' | g
printf '<foo><nif>123456785</nif></foo>\n' | g
printf '<foo><nif>123456785</nif></foo>\n' | g
printf '<foo><nif>123456786</nif></foo>\n' | g
printf '<foo><nif>123456787</nif></foo>\n' | g
printf '<foo><nif>123456788</nif></foo>\n' | g
printf '<foo><nif>123456789</nif></foo>\n' | g

Resultado:

<nif>123456780</nif> - BAD
<nif>123456781</nif> - BAD
<nif>123456782</nif> - BAD
<nif>123456783</nif> - BAD
<nif>123456784</nif> - BAD
<nif>123456785</nif> - BAD
<nif>123456785</nif> - BAD
<nif>123456786</nif> - BAD
<nif>123456787</nif> - BAD
<nif>123456788</nif> - BAD
<nif>123456789</nif> - OK

2011-09-26

Alguns "python one liners" interessantes.

Algumas construções one liners de python.

  1. remover duplicados numa lista

    >>> list = [1,2,3,3,4,4,5]
    >>> list = filter(lambda x,map={}: not (map.has_key(x) or map.setdefault(x, 0)), list)
    >>> list
    [1, 2, 3, 4, 5]
  2. simular o operador de C “condition ? expr_true : expr_false”

    1. se expr_true e expr_false são expressões avaliadas como boolean, basta a construção: condition or expr_true and expr_false

      >>> x=0
      >>> print x==1 and "1" or x==2 and "2" or x==3 and "3" or "nada"
      nada
    2. genericamente: (expr_false,expr_true)[condition]

      >>> x="foo"
      >>> print (x,None)[x=="NULL"]
      foo
      >>> x="NULL"
      >>> print (x,None)[x=="NULL"]
      None

2011-09-24

Mais linkedin.

Ainda sobre o meu rant acerca da utilizaçao do linkedin, estava a dar uma olhadela em potenciais grupos do meu interesse e, com o meu olho clínico :), reparei na seguinte preciosidade:

  • Gestão de projectos: 3,061 members
  • Portugal-a-Programar: 264 members
  • Portugal Web Development Professionals: 135 members
  • Java Development (Portugal): 107 members

Compare-se a diferença de membros entre o primeiro grupo e os restantes. Depois leia-se o ponto 1 do rant.

Sistemas de controlo de versões visitados.

No início apareceram os sistemas de controlo de versões para ficheiros individuais, casos do RCS e SCCS. Serviam para versionar ficheiros isoladamente, um a um. Introduziram um conjunto de comandos para suportar a gestão de versões que são a base do que se usa actualmente.

Principais comandos do RCS
cicheckin / commit
cocheckout
rcsdiffdiferenças entre revisões
rcsuma espécie de “add”
rloglog

Depois vieram os sistemas de controlo de versões com repositório central, como o CVS e SVN. Estes sistemas já operavam em grupos de ficheiros, permitindo o conceito de projecto. O repositório central estava associado a um sistema de servidor de qualquer tipo o que facilitava o trabalho de equipas nos mesmos projectos. O CVS originalmente usava o RCS como motor de controlo de versões (ficheiros de extensão ,v).

Principais comandos do CVS herdados dos sistemas singulares
cvs commit
cvs checkout
cvs diff
cvs add
cvs log
Alguns comandos criados para suportar o conceito de repositório
cvs updatesincroniza com o repositório
cvs removeremove ficheiros do repositório
cvs tagcria branches e tags

Nos últimos anos multiplicaram-se as implementações de sistemas de controlo de versões distribuídos. Nestes sistemas, cada working directory / working copy é um repositório completo local. Todas as operações dos sistemas de repositório central estão agora disponíveis localmente e adicionaram-se novos comandos (principais: pull, push) para sincronizar repositórios. Como cada cópia local é um repositório, cada commit produz um changeset (eventualmente) diferente por repositório, que passa a ser identificado pelo sua assinatura (SHA1 por exemplo).

Os sistemas deste género com mais hype nos dias que correm são o GIT, da fama do Linus Torvalds, e o Mercurial (HG).

Repositório central:

Sistemas distribuídos:

Comparação entre sistemas de controlo distribuídos com contextualização:

2011-09-23

Documentação ágil.

A arte de bem documentar é difícil e pouco atractiva. Felizmente muita documentação necessária usualmente não requer grande elaboração. Nestes casos torna-se útil agilizar o processo.

Agilizar como? Texto! O “formato texto” é simples, prático e funcional. Todos os sistemas de comunicação populares baseiam-se em interfaces cujo input é feito em texto simples ou em sistemas muito simplificados de formatação. Mail, blogs, foruns online, twitter, são alguns exemplos.

As grandes lacunas do texto simples são a falta de capacidade de estruturação e inclusão de elementos gráficos. No entanto, usando-se algumas convenções e software que as processe, consegue-se adicionar elementos que conferem alguma estrutura ao texto. Estes sistemas permitem estruturar um texto banal apenas com ligeiras anotações não intrusivas e convertê-lo em vários formatos possíveis, como html, docbook, odf openoffice, latex, rtf e pdf. Um outro formato de saída interessante e geralmente suportado é o s5 que permite construir apresentações em html.

Alguns sistemas populares:

Software de processamento:

O output poderá ser o documento final ou um trecho para incluir noutro sistema de documentação.

Com este tipo de abordagem consegue-se escrever documentação de forma rápida e flexível, ou seja, ágil.

7FFP - reuniões.

Contexto: 7 factores que nos frustram a produtividade.

Uma reunião é uma boa “ferramenta” de trabalho: um grupo de pessoas reúne-se para decidir e esclarecer assuntos de forma muito mais célere do que seria feito de outra forma. Infelizmente esta utilidade, a par da facilidade de realização, levou ao seu recurso em exagero, sem preparação adequada, a chamada reunite.

As principais características do fenómeno reunite, segundo a minha experiência, são:

  • reuniões em excesso

    Um exemplo notável foi num projecto de 6 meses, sem praticamente qualquer integração com equipas externas, ter sido convocado para cerca de 55 reuniões!

  • desorganizadas, confusas, promovem divagações e são demoradas

    São raras as reuniões que têm uma agenda pré-definida ou que aos participantes seja distribuída informação relevante de antemão. A reunião típica é ad-hoc: convocam-se as pessoas e logo se vê. Isto origina divagações, conversas em ciclo que estendem para além do razoável a sua duração.

  • pouco esclarecedoras, por vezes inúteis

    Não raramente acontece sair duma reunião demorada sem qualquer resultado prático: os temas entraram em loop, não se chegou a nenhuma conclusão, não foi definida qualquer acção.

Em suma:

  • fazer agenda, distribuí-la aos participantes antecipadamente e segui-la durante a reunião;
  • enviar informação relevante aos participantes antecipadamente;
  • garantir que são produzidos resultados: são tomadas decisões, são distribuídas acções aos participantes.

7FFP - multitasking

Contexto: 7 factores que nos frustram a produtividade.

Apesar de por vezes termos a sensação que conseguimos lidar com vários assuntos em simultâneo, está provado que o ser humano diminui bastante de produtividade quando muda de contexto. Ou seja, as pessoas não lidam bem com o multitasking, mas são comummente pressionadas a fazer demasiadas coisas ao mesmo tempo.

Em suma:

  • priorizar e fazer (bem) uma coisa de cada vez.

2011-09-22

7FFP - mau uso do mail.

Contexto: 7 factores que nos frustram a produtividade.

O correio electrónico foi dos primeiros meios de comunicação a ser implementado em computadores, mesmo antes de existirem redes. As máquinas albergavam vários utilizadores que enviavam mails uns aos outros, no mesmo computador.

Apesar do impacto negativo causado pelo spam e por outras alternativas de comunicação, como as redes sociais, fóruns web, blogs, instant messaging, o mail continua a ser o meio de comunicação primário na internet. Todas as pessoas que conheço têm pelo menos uma conta e consultam-na com regularidade (se prestam a atenção devida aos mails é outra história). O mail tem algumas vantagens enquanto sistema de comunicação: não exige a atenção imediata do destinatário e é um meio rico de transmissão de informação, pode-se enviar desde texto simples a diversos conteúdos multimédia e anexos.

Pessoalmente leio sempre e com atenção os mails que me são intencionalmente direccionados, tal como sempre lhes respondo, sempre que apropriado. Infelizmente não me parece que este comportamento seja generalizado. Do que tenho constatado, as pessoas…

  • não lêem com a devida atenção os mails, especialmente se tiverem muito que ler;
  • recebem demasiados para que lhes possam prestar atenção;
  • algumas não lhe ligam muito;
  • algumas não (os) sabem escrever.

“Ler na diagonal”

Ler na diagonal, à letra, não existe. Tipicamente isto consiste em ler as primeiras palavras e, eventualmente, parte das últimas. A pessoa fica com uma ideia incompleta, por vezes errada, do que se tratava. Ou seja, o mail foi inútil.

Actualmente parece estar a surgir um novo chavão a substituir este li na diagonal que é o vi que enviaste mas não li!

Porque recebemos demasiados mails?

  • porque estamos subscritos em demasiadas coisas: grupos, mailing lists, etc;
  • porque os mails têm demasiada gente em “CC” e acabamos por receber coisas que podíamos dispensar.

Pressão resultante do mau uso do mail

Se a informação transmitida por mail não passa, os destinatários ficam sem conhecimento que deviam ter ou tentam obtê-lo por outros meios (telefone, pessoalmente). Ambos os casos têm consequências directas em perda de produtividade.

Em suma:

  • usar classificadores automáticos sempre que possível;
  • remover subscrições e sistemas de notificações em que até podíamos estar interessados mas não temos tempo e raramente prestamos atenção, de qualquer modo;
  • moderar a quantidade de gente que se adiciona em “CC”;
  • resolver (e responder) imediatamente os mails que podem ser resolvidos imediatamente;
  • prestar atenção ao que se recebe e escrever com atenção o que se envia: poupa muito tempo e trabalho a todas as partes.

7FFP - demasiadas rotinas.

Contexto: 7 factores que nos frustram a produtividade.

É fácil criar rotinas e definir procedimentos, especialmente quando é para os outros fazer. Facilmente cai-se em exagero ou em inutilidades. Ao longo do tempo tenho assistido a casos que enquadram em um ou mais dos seguintes factores: excesso de rotinas, sobre-complexas, inúteis, evitáveis. Este tipo de situações consomem tempo útil de trabalho e desmotivam.

Em suma:

  • automatizar procedimentos manuais;
  • não complicar processos.

7FFP - cansaço.

Contexto: 7 factores que nos frustram a produtividade.

Existem pela net muitas histórias de pequenas calamidades feitas a nível profissional devido ao cansaço. As que envolvem administradores de sistemas ou DBAs são particularmente populares, por razões óbvias.

Com a pressão causada por coisas como prazos irrealistas, cortes de pessoal ou má eficiência de organização, entre outros, as pessoas acabam em alturas críticas por reduzir o tempo de descanso, tornando-se menos produtivas e causando mais erros.

Em suma:

  • dormir mais;
  • ser mais realista.

7FFP - atrasos.

Contexto: 7 factores que nos frustram a produtividade.

O problema dos atrasos é óbvio: enquanto alguém espera por alguém está a perder tempo. Está simplesmente parado, sem produzir, a gastar o seu tempo… à espera.

Infelizmente os atrasos não se resumem apenas a atrasos “sociais”, em que alguém espera por alguém. Também temos atrasos entre equipas, projectos, sistemas, pagamentos… O atraso de pagamentos a fornecedores em Portugal será provavelmente o inimigo número 1 do sector das pequenas e médias empresas.

O irónico dos atrasos é que muitos podiam ser resolvidos a custo zero, bastando “apenas” uma mudança de atitude por parte das pessoas. Assisto a muitos atrasos que não têm qualquer razão de ser: se uma reunião está marcada às 15h, digamos, as pessoas começam a dirigir-se para a sala já às 15h05, sabendo que ainda vão demorar uns 5 minutos a lá chegar, sem que haja qualquer razão para que o não tivessem feito às 14h55 ou até um pouco antes.

Escrevi “apenas” propositadamente entre aspas, porque se há coisas que são fáceis de mudar em teoria mas quase impossíveis na prática, atitudes e mentalidades estão entre elas.

Em suma:

  • levantar da cadeira mais cedo!

7FFP - falsa panaceia das aplicações online

Contexto: 7 factores que nos frustram a produtividade.

De há uns anos para cá surgiram as aplicações web e com elas veio o suposto eldorado dos nossos problemas processuais. Na verdade, se não houver reengenharia de processos, uma aplicação web apenas moderniza a burocracia, não a resolve. Exemplificando com a burocracia estatal, substitui impressos por formulários web e balcões por acessos à internet… facilita, mas não resolve o problema base.

Outro problema consiste nas limitações de integração da solução. Se uma aplicação apenas dispõe de um só interface, web, toda a sua interacção tem que passar por aí. Isso obriga o utilizador a abrir o browser, navegar pela usabilidade da aplicação e realizar operações através das interacções web disponíveis. Para pequenas acções pode ser suficiente, para uso frequente talvez não. Num mundo ideal as aplicações web deveriam ser clientes de uma solução SOA. Nesse cenário qualquer pessoa poderia escolher a melhor interacção, mais automatizada e que lhe desse menos trabalho. Infelizmente raramente isso acontece.

Finalmente outro fenómeno usual é a redundância de informação pedida. A falta de single-sign-on é um dos problemas mais frequentes mas também um dos que mais vai sendo endereçado. Coisas como pedir várias vezes os mesmos dados, especialmente dentro de uma organização, como usernames, nomes, centros de custo, managers, departamentos, etc são também frequentes.

Em suma:

  • simplificar processos primeiro;
  • criar serviços;
  • desenvolver as aplicações baseadas nos serviços;
  • evitar redundância.

Como são feitos estes artigos?

Para colocar posts num blog — até porque a actividade de “blogar” não é propriamente a minha favorita nem o meu conceito de comunicação preferido — coloquei alguns pressupostos:

  1. editar os artigos em texto;
  2. ter facilidade na produção de alguns conteúdos específicos: trechos de código, links, formatações básicas;
  3. automatizar o mais possível as operações, o que inclui não ter que usar um browser para submeter um artigo.

Para fazer face aos pontos 1 e 2, a solução recaiu no formato markdown e no excelente programa pandoc, de John MacFarlane.

markdown é um formato de texto simples que usa anotações básicas para descrever formatações, à semelhança de outros formatos, como o reStructuredText que é usado para produzir toda a documentação do projecto Python, e na senda de uma série clássica de outros formatos de texto, mais ou menos complexos, desde o ROFF ao HTML.

pandoc é um excelente utilitário que aqui é usado para converter markdown no formato final de apresentação HTML.

Finalmente o ponto 3 foi resolvido usando a aplicação googlecl, que fornece um interface linha de comando para o blogger (e outros serviços do google). Perfeito.

Uma makefile orquestra tudo, permitindo integrar facilmente com outros utilitários de texto (mais uma vantagem de se usar texto). Neste caso o sed é usado para extrair a primeira linha do ficheiro para título, a segunda para a lista de etiquetas a associar ao artigo e tratar linhas começadas por “#” como comentários.

Makefile usada:

FILE=$$(ls -tr *.txt|tail -1)
T=/tmp/xgcl.html
PANDOC = pandoc -f markdown -t html --no-wrap
B_ID = --blog='tecnosutra'

all:

post-not:
tags="$$(sed -n 's/^tags: *//p' $(FILE))" && \
title="$$(sed -n '1p' $(FILE))" && \
sed '/^\(#\|tags:\)/d; 1d;' $(FILE) | \
iconv -f latin1 -t utf8 | $(PANDOC) -S -s > $(T) && \
echo google blogger post $(B_ID) --tags="$$tags" --title="$$title" $(T)

post:
tags="$$(sed -n 's/^tags: *//p' $(FILE))" && \
title="$$(sed -n '1p' $(FILE))" && \
sed '/^\(#\|tags:\)/d; 1d;' $(FILE) | \
iconv -f latin1 -t utf8 | $(PANDOC) -S -s > $(T) && \
google blogger post $(B_ID) --tags="$$tags" --title="$$title" $(T)

check:
aspell -d portugues -c $(FILE)

clean:
rm -f *.bak

Ligando as peças:

  1. edito um ficheiro de texto,
  2. make post-not para verificar se está tudo ok,
  3. make post e já está.

Simples.

7 factores que nos frustram a produtividade.

Quem nunca chegou ao fim do dia com a sensação de ter estado sempre ocupado mas não ter feito nada? Isso acontece porque ao longo desses dias aconteceram muitas coisas que nos consumiram tempo sem que daí adviesse produção correspondente.

Ao longo do tempo tenho identificado alguns factores genéricos, comuns à maioria das funções, que contribuem para isso. Segue a lista sem qualquer ordenação relevante, ficando o desenvolvimento de cada um dos pontos para artigos posteriores.

  • reuniões;
  • atrasos;
  • mau uso do mail;
  • cansaço;
  • falsa panaceia das aplicações online;
  • demasiadas rotinas;
  • multitasking.

3 coisas que aprendi no linkedin.

1. toda a gente é chefe, importante e excelente no que faz.

Pode ser apenas consequência do crescente fenómeno “auto-promoção”, pode ser uma questão de superioridade ilusória, mas o que é certo é que a maioria dos perfis no linkedin com que me deparo são CTOs, CEOs, COOs, directores, project manangers, team leaders, entre outros cargos superlativos, sendo simultaneamente especialistas triple-A em tudo o que fizeram até então e mesmo no que não fizeram.

2. rede de contactos totalmente falhada.

O objectivo do sistema de contactos é construir uma rede de pessoas que se conhecem bem: trabalharam juntas, têm um bom nível de confiança mútuo, etc. Por isso é que os segundos e terceiros níveis podem estar-nos expostos, mediante configuração do nosso contacto de primeiro nível: “eu confio em quem confia em quem eu confio”.

Mas em que se tornou a rede de contactos? Numa lista infindável que tanto é composta pelo nosso “braço direito”, como pelo tipo a quem enviámos um email por engano há 5 anos.

Há dias dei uma olhadela na lista de pessoas que são vistas por quem vê o meu perfil:

  • 3 simplesmente não sei quem são;
  • 2 são ex-colegas de quem nada sei há mais de 10 anos;
  • outros 2 são-me pouco relacionados;
  • e finalmente 3 estão mesmo relacionados comigo, sendo os únicos que fazem parte da minha rede de contactos.

3. recomendações recíprocas e avantajadas.

Outro factor curioso é o sistema de recomendações do linkedin ter-se transformado numa espécie de colectânea de eufemismos. Chego a lacrimejar-me todo tão ternurenta é a prosa com que os colegas se mimam.

E em tantos casos de forma recíproca. É que se o A recomenda o B, o B não se fica por menos e recomenda o A. É uma espécie de “cá se faz cá se paga” numa versão positivista do karma.