segunda-feira, 7 de outubro de 2013

Por que eu não pretendo ter outro Android

Desde que os smartphones se tornaram populares, sempre tive um Android, Motorola Milestone 1, Motorola Atrix 4G LTE e mais recentemente um Samsung Galaxy S3 Mini. E sempre teve algo que me incomodou neles, mas até ter o Galaxy S3 Mini eu não sabia exatamente o que era, ou preferia pensar que o problema era eu.

O problema começou com o meu primeiro Android, meu querido Motorola Milestone 1, que eu adorava seu teclado QUERTY que facilitava muito a vida na hora de digitar. Porém, em um determinado ponto de sua vida, pouco antes que a garantia vencesse mas não antes o suficiente pra dar tempo de enviar pra manutenção, que o GPS simplesmente não se localizava mais. Até ai tudo bem, eu não costumava andar de carro o suficiente pra justificar a ausencia do GPS. Mas, poxa, de que adianta comprar um carro que tem estepe se quando você precisa dele ele está furado?

Em seguida, peguei um Atrix usado com a minha cunhada que veio diretamente do EUA. Passado pouco tempo e novamente o GPS parou de funcionar. Pensei que o problema fosse comigo, como se eu tivesse uma espécie de Toque de Midas reverso, em que tudo que eu coloco a mão, trava, tipo aquele garoto de Nova York. Só que não.
Vendi o celular pra minha irmã, que não dirige e consequentemente não precisa do GPS, e passados mais alguns poucos meses o chip de memória SD parou de funcionar. Mas não o chip, e sim o conector! Ou seja, não importa qual Kingston ou SanDisk você coloque no celular, ele simplesmente não vai funcionar.

Quando vendi meu Atrix para minha irmã, foi porque eu tinha pego um iPhone 3GS como forma de pagamento de uma dívida que uma empresa onde trabalhei (junto com um notebook e um monitor de 17" que não dava metade da dívida, mas isso é outra história). Fiquei um ano com o iPhone e posso dizer que estava bem satisfeito, mas ele começou a dar problema com a bateria, desligando quando atingia 50~60%. Fui ganancioso e resolvi voltar para o Android.

A escolha do Galaxy S3 Mini como meu próximo Android foi bem simples, segui duas regras básicas:
Primeira e mais importante: Não pode ser Motorola. Um possível problema que eu percebi é que os dois Androids que eu tive eram Motorola, um ponto em comum em problemas em comum. Resolvi não confiar mais na Motorola, mesmo após ter sido adquirida pelo Google.
Regra #2: Pegar um celular que já esteja consolidado e de uma marca reconhecidamente boa. Ouvi muitos elogios do Galaxy S2, do S3 e do Galaxy Note, todos da Samsung, que já era uma marca que me atraia. Resolvi então pegar o Galaxy S3 Mini, ele não era dos mais caros, a tela não era gigante (me incomoda não alcançar a tela inteira com uma mão), e a especificação técnica era melhor que o iPhone 3GS.

Sempre fui adepto do movimento software livre, posso não ser um dos maiores contribuidores das história (e nem um dos menores), mas nunca usei Windows que não fosse pra jogos, sendo que até isso está com os dias contados graças ao SteamOS. E o fato dos aplicativos para Android serem escritos em Java sempre foi um incentivo a mais, já que eu acho a sintaxe do Objective-C feia (e o XCode mais ainda).

Comprado o S3 Mini, vi que o Christiano Anderson tinha feito um post relatando problemas que ele teve com o Galaxy S3. Preocupado, instalei tal do eMMC Check pra ver se meu celular estava fadado à desgraça, o que para minha surpresa não estava. Ele passou no teste e meu chip não era um dos intocáveis.

Novamente, menos de um ano depois, o celular começou a apresentar problemas. Felizmente, dessa vez, não é o GPS que parou de funcionar, mas sim a tela. Comecei a perceber que depois de usar alguma coisa que demande processamento intensivo, como Waze ou jogos, a tela ficava com uma mancha roxa quadrada na tela, que lembrava bastante o tamanho e formato de um chip de processamento. No começo a mancha era visível apenas no plano de fundo do Chrome (quando você não tem nenhuma aba aberta), ou nos menus contextuais que possuem uma cor semelhante. Mas ao longo do tempo essa mancha foi ficando cada vez mais visível em qualquer outra cor que esteja na tela, não sendo visível apenas caso tenha movimento na tela ou várias cores que o distraiam. Tudo isso me leva a concluir que o problema é no super aquecimento de um processador que fica praticamente colado na traseira do display. Veja uma foto de quando o problema começou:

Ainda não consegue ver? Compare com a mesma foto com contraste estourado:

E hoje estou com esse abacaxi na mão. Já abri um chamado na Samsumg e eles pediram pra enviar o celular pra analise, e possivelmente correção do problema. Mas antes de enviar, vou trocar a bateria do iPhone 3GS, afinal, não da pra ficar sem nenhum celular, ainda mais com a esposa grávida, mas sei que dificilmente vou confiar no celular quando ele voltar. Sei que vai ser apenas uma questão de tempo até que a garantia expire e novos problemas comecem a pipocar, e no final, vou voltar pro iPhone 3GS até surgir alguma promoção que venda o 4 ou 4S por menos de mil reais.

Você: "AAaahh, mas você não teve problema com o Android então, e sim com o aparelho!! Para de falar mal do meu Android querido!!". Sim, eu sei que o problema não é com o Android, mas com a Motorola e a Samsung, mas esse é um problema que a Apple prefere não se arriscar ao abrir o iOS pra outras montadoras. A fragmentação do Android é um problema sério, mesmo que você não aceite. Pois cada um dos 3 Androids que eu tive tinham interfaces de navegação muito diferentes entre si, e não se trata apenas de versões diferentes de Android. Até hoje, eu não peguei nas mãos dois dispositivos Androids que tivessem a mesma usabilidade. Então, mesmo que você mantenha o núcleo do sistema de forma rígida, as partes que você abre pra que qualquer um possa mexer vão ficar sujeitas a queda de qualidade e quem percebe isso é o usuário final, que não sabe que Android é uma marca do Google, que nada tem a ver com a HTC que fez o seu celular.

terça-feira, 13 de agosto de 2013

Configurando a impressora Bematech MP-4200 TH no Linux (Ubuntu)

Esses dias precisei configurar uma impressora termica no linux e devo dizer que foi um belississimo de um parto.

A configuração da impressora termica MP-4200 TH acaba sendo mais simples do que se parece, mas se você for depender de documentação existente na internet ou do suporte técnico da Bematech, vai ficar na mão (como eu fiquei).

Sem mais delongas, a configuração foi feita em um Ubuntu 12.10 e acredito ser compatível com versões 12.04 até 13.04, se você testar em outra versão ou distribuição me avisa que eu atualizo aqui.

Após a instalação do driver e toda configuração padrão da impressora seja pela interface web do cups ou pelo gerenciador de impressoras do Ubuntu, a impressora já estará praticamente pronta pra funcionar, o problema todo só ocorre por causa de um modulo que é carregado automaticamente e por falta de permissão no dispositivo da impressora.

Para corrigir esse problema, você pode dar um `chmod` manualmente no dispositivo da impressora e corrigir o erro temporariamente (até desconectar a impressora ou reiniciar o computador).

Para tornar a correção permanente, é preciso editar dois arquivos, primeiro, o arquivo `/etc/udev/69-bema.rules`, esse arquivo é criado automaticamente pela instalação do driver, porém, ele esta errado/desatualizado, por isso, troque todo o conteudo do arquivo por:

#MP4000TH
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0b1b", ATTR{idProduct}=="0001", MODE="0777"
#MP4200TH
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0b1b", ATTR{idProduct}=="0003", MODE="0777"

Em seguida, edite o arquivo `/etc/modprobe.d/blacklist.conf` e adicione a seguinte linha:

cdc_acm

Agora é só `reboot` e já era!

terça-feira, 4 de dezembro de 2012

Django: Managers e Querysets

Uma das coisas que eu mais uso nos models do Django são os Managers, aquelas classes que adicionam funções aos `.objects.sua_funcao_aqui` (ou até mesmo, criar outro "objects").

O único problema, era que essa função estava restrita à chamadas via `.objects`, ou seja, enquanto é lindo fazer:

Post.objects.da_semana()

Não era possível fazer:

Comment.objects.da_semana().aprovados()

Não era. (Mentira, sempre foi, eu é quem não sabia fazer)

A solução surgiu em um post no DjangoSnippets.org. E era muito mais simples do que eu esperava.

Da mesma forma que criamos novos Managers para Models, podemos criar Querysets para Managers. Simples assim:

# -*- coding: utf-8 -*-
from django.db import models
from django.db.models.query import QuerySet

class BlogQueryset(QuerySet):
    u'''Aqui nós definimos as funções que retornarão o que 
    queremos

    Você pode retornar qualquer coisa da função, mas tenha 
    em mente que se você não retornar um QuerySet, não será
    possível continuar o encadeamento de filter/order_by/etc
    '''
    def da_semana(self):
        return self.filter(created_at__gt=...)
    def aprovados(self):
        return self.filter(published=True)


class BlogManager(models.Manager):
    u'''Aqui nós precisamos repetir as funções, mas apenas 
    suas definições.
    
    O corpo da função é apenas a chamada para a função no 
    QuerySet, é exatamente assim que as funções filter, 
    exclude, order_by, etc, são feitas no Manager padrão 
    do Django
    
https://github.com/django/django/blob/master/django/db/models/manager.py
    '''
    def da_semana(self):
        return self.get_query_set().da_semana()
    def aprovados(self):
        return self.get_query_set().aprovados()
    def get_query_set(self):
        '''É aqui onde a mágica acontece, pra que toda essa 
        história funcione, você precisa que seja retornada 
        uma instancia do QuerySet que nós criamos'''
        return BlogQuerySet(self.model, using=self._db)
        # Particularmente eu acho que seria mais interessante 
        # usar self.queryset_class, assim não seria preciso 
        # ficar reescrevendo essa função desnecessariamente.
        # Vou tentar alterar no branch de desenvolvimento e 
        # se passar em todos os testes eu faço um pull request

class Post(models.Model):
    # Aqui vem seus campos como geralmente faria
    # ... 
    published = models.BooleanField(db_index=True)
    created_at = models.DateTimeField(db_index=True, auto_now_add=True)
    objects = BlogManager()

Com isso você já pode encadear suas chamadas aos seus filtros :)

pony powered

quinta-feira, 7 de junho de 2012

Snippet: Gerar string aleatória em Python

A cada 2 meses eu preciso, por algum motivo, gerar uma string aleatória, e a cada 2 meses eu abro um terminal do python, importo random, string e fico brincando por alguns minutos até chegar a uma solução que me deixe feliz (ou até cansar de brincar mesmo).

Mas dessa vez resolvi achar alguma solução que me parecesse suficientemente aleatória e que eu não precisasse abrir o terminal de novo e achar mais uma solução, pesquisando nas internets, achei um tópico no stackoverflow que me pareceu interessante pois ele usava a função os.urandom que de acordo com a documentação é aleatória o suficiente para uso criptográfico.

Com base no que eu vi no stackoverflow, fiz a seguinte solução:

import os
import string

def generate_random_string(length, stringset=string.ascii_letters+string.digits+string.punctuation):
    '''
    Returns a string with `length` characters chosen from `stringset`
    >>> len(generate_random_string(20) == 20 
    '''
    return ''.join([stringset[i%len(stringset)] \
        for i in [ord(x) for x in os.urandom(length)]])

quarta-feira, 6 de junho de 2012

Pare de usar a função `.exclude` do Django!

Atenção: Se você é DBA, pare de ler por aqui, esse post vai te magoar!

Ta bom, não esse tipo de DBA, mas mesmo assim...

Pra você que pode não saber o que é, a função queryset.exclude serve para você remover objetos da queryset que não lhe interessam, por exemplo, se você tem uma lista de noticias agrupadas por categoria, você pode usar o exclude para remover as noticias de uma determinada categoria. Mas isso tem um custo.

Quando você usa a função exclude, a query gerada pelo Django passa a usar uma condição negativa em algum ponto, seja usando um NOT, seja usando um <>, e isso tem um problema sério: o indice do banco de dados pode não ser usado corretamente, especialmente se você pega um código como o que eu já peguei assim: Model.objects.exclude(id__in=[1,2,3,...,20]).

Existem situações legitimas em que usar o exclude é aceitável (ao menos eu acho que deve existir, senão essa função nem existiria), mas no meu caso, onde uma das tabelas em que era feito o JOIN tinha mais de 1 milhão de registros, isso tava levando mais de 3 segundos pra executar uma query. UMA QUERY, ainda tinha o site todo pra carregar e ele já estava me ferrando ali.

O que fazer então?

No meu caso, existia uma variável que era uma lista de ID's dos objetos que eu não queria e fiz o que poderia ser impensável pra você DBA teimoso:

# Quero 5 objetos do banco de dados
limit = 5 

# Esses são os IDs dos objetos que eu não quero
excluded = [1,2,3,4,5,6] 

queryset = Model.objects.filter(foo=bar).order_by('-data')

objetos = []

# Pegamos uma quantidade de objetos que garanta 
# que eu va conseguir exatamente `limit` objetos
for objeto in queryset[:limit+len(excluded)]: 
    if objeto.id not in excluded:
        objetos.append(objeto)
    if len(objetos) >= limit:
        break

E pronto, tenho uma lista com apenas os objetos que eu quero exibir.

Existem (varias) situações em que essa solução não serve, por exemplo se você precisa usar o Paginator, mas ainda assim se é o caso que você precisa apenas de uma quantidade pequena de objetos, pode ser mais vantajoso adotar uma solução como essa.

Depois que fiz essa alteração no código, o carregamento inteiro da página caiu pra 0,7 segundos de execução de query, ainda tem muito o que melhorar porque o código ta f0d@, mas já é alguma coisa :)

PS: Esses tempos de execução de SQL eu peguei pelo django debug toolbar.

segunda-feira, 12 de março de 2012

quinta-feira, 8 de março de 2012

Melhorando a escrita dos testes em Django

Esses dias eu estava discutindo com o Avelino que é um saco escrever testes porque em toda maldita classe de testes eu preciso recriar os objetos, tipo assim:

class TesteDaMorte(TestCase):
    def setUp(self):
        # Aqui vem um bilhao de linhas pra criar
        # algumas instancias de objetos.
        # E nenhuma dessas linhas testa alguma 
        # coisa de fato

Eu argumentei que isso é um porre, e se repete várias vezes (código repetido nunca é bom), ai um belo dia o model recebe um novo campo e pronto, la vai você retardadamente reescrever todos os testes pra adicionar o novo campo na criação do objeto e não pra escrever os testes em cima dele. Eu acho esse esforço um desperdicio, mas ao mesmo tempo, sei que testes são extremamente importantes.

Aah, a documentação, nada como ler a documentação...

Bom, como meu índice de preguiça costuma ser representado em gráficos com o texto "MAX" no topo do eixo Y, eu decidi que não ia mais ficar escrevendo essa caralhada de código desnecessário em testes e saí em busca de alternativas.

Eu já tinha pensado em alguma hipoteses como heranças ou chamar setUp's de outros testes, mas não me agradou muito essas opções pelo que o Avelino vivia falando: "ah, mas os testes precisam ser independentes" (ou algo assim, não lembro exatamente o termo, mas era algo assim), e de fato, eu concordo, os testes precisam rodar sozinhos e serem capazes de se testarem a si mesmos isoladamente.

Depois pensei em outras alternativas que provavelmente ainda não existem implementadas, como definir dependencias de testes. Ou seja, não adianta você testar B, se A não passar. Mas como eu disse, não encontrei nenhuma documentação falando se isso existe, então ignorei logo (não tenho experiencia com testes o suficiente pra poder escrever uma solução desse porte).

Cansado de pensar em soluções, resolvi fazer o óbvio: fui procurar a solução na internet. Naturalmente a solução veio direto do site do Django na página de testes: Fixtures!

Quando definindo uma classe de testes, adicione um atributo na classe chamado "fixtures" e indicando quais fixtures você gostaria de importar antes de iniciar os testes. Assim:

class TesteDaMorte(TestCase):
    fixtures = ['tests/usuarios.json']
    def setUp(self):
        # Voce vai poder apagar essa funcao em 90% 
        # dos seus testes e ir direto ao que interessa

Dessa forma, antes de iniciar os testes (e antes mesmo de chamar a função setUp), o Django vai importar as fixtures do arquivo usuarios.json e vai criar os dados pra você.

Pra criar o arquivo de fixtures, você pode iniciar um novo syncdb em um banco de dados temporário, em sqlite mesmo se for o caso, inserir os dados la pelo admin (ou pelo shell) e executar o commando dumpdata do Django, mais ou menos assim:

python manage.py --indent=2 dumpdata auth.User profile.Profile > myapp/fixtures/tests/usuarios.json

Isso vai gerar o arquivo usuarios.json (desde que o diretório exista, claro) com os dados de User e Profile (supondo que seja assim que você o chamou). A ordem em que você adiciona eles no comando é relevante, é importante que as classes sejam especificadas por ordem de parentesco, ou seja, as classes pai aparecem antes das classes filhas (sendo pai=classe que tem o ID e filho=classe que tem a ForeignKey).

Com isso você pode focar em escrever o que importa de verdade: testes.

quarta-feira, 28 de dezembro de 2011

Acelerando os testes no Django

Finalmente achei algo pra escrever sobre programação. Não vai ser um post longo mas é relativamente útil.


Rápido como o Flash!

Em um projeto que estou trabalhando atualmente, rodamos testes pra garantir que tudo roda como deveria (exceto quando você escreve o teste errado, mas ai é outros quinhentos), e tinhamos o problema de que o teste levava 3 minutos e 35 segundos pra rodar


Aham, sei, 0.2 segundos pra rodar o teste ¬¬

Como da pra imaginar, mais de 90% do tempo era gasto criando tabelas, importando fixtures e criando índices (nessa ordem).

O problema de ter testes demorando tanto pra executar é que você fica de saco cheio de ter que esperar o teste rodar pra saber se tudo funcionou certinho e continuar programando, especialmente porque em essência o TDD deve ser escrito antes do código: Você escreve o teste, naturalmente ele não passa, e você escreve a "correção" para o teste.

Ter que fazer isso com uma lag de 3 minutos entre os comandos é um saco ainda mais se o Google Reader já estiver zerado. Então eu dei um jeito de fazer o teste rodar mais rápido.

Edite o seu arquivo settings.py e adicione o seguinte:

if 'na_memoria' in os.environ:
    print '**********************************'
    print 'Vish, rodando as parada na memoria'
    print '**********************************'
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': None
        }
    }

Quando for rodar seus testes execute assim:

$ na_memoria=1 python manage.py test

Isso fará com que todo o banco de dados de teste seja criado na memória, dando uma acelerada bem grande nos testes. Aqui o tempo de execução caiu de 3 minutos pra 11 segundos (10 segundos importando fixture).

Claro que essa solução funciona apenas se seu código for independente de banco de dados (nada -ou quase nada- de SQL na mão).

sábado, 5 de novembro de 2011

Tunel SSH

É assim que o pessoal costuma abrir tuneis SSH no Japão

Mais um post de infra no meu blog de programação, mas tudo bem, que programador nunca precisou de um tunel ssh pra salvar sua vida?

Tunel SSH nada mais é do que abrir uma porta localmente que responda em um serviço remotamente. Isso quer dizer que você pode conectar em seu banco de dados favorito (PostgreSQL, claro) remotamente sem ter que abrir a porta 5432 do seu servidor aos quatro ventos e sair restringindo o acesso via iptables/ufw/ipfw (até você lembrar que seu IP é dinamico e você não ter paciencia pra reconfigura-lo a cada 3 dias).

Pra abrir um tunel SSH é ridiculamente simples, assim como consta no manual, basta executar:

ssh -L 5433:localhost:5432 user@servi.dor

Com isso, o SSH irá se conectar ao servi.dor e abrir a porta 5433 localmente e encaminhar todas as conexões TCP recebidas diretamente para a porta 5432 do localhost.

Isso mesmo, você não está ficando louco (e nem eu), o ssh vai abrir encaminhar o pacotes para a porta 5432 do localhost. O detalhe aqui fica por conta do contexto, "localhost" no caso é a maquina onde você se conectou, e não a sua, ou seja, nesse caso localhost == servi.dor, é um pouco dificil de visualizar num primeiro momento mas se torna natural depois de um tempo.

Só pra deixar claro: o tunel pode se conectar a qualquer serviço remoto localmente (!!). Pode ser o PostgreSQL, MySQL, Apache, MongoDB, RabbitMQ, até mesmo ao próprio SSH, mas você não vai querer uma implosão no seu computador né?

Básicamente é isso, eu tinha pensado em escrever só o comando e deixar o resto pra você se virar e ententer, então acho que já escrevi de mais

Espero que um dia eu consiga escrever sobre programação, queria tanto falar sobre Celery, MongoDB+Django, e outras coisas....