Categorias
Tecnologia

Como fazer tunelamento de localhost de forma segura

Veja como expor seu servidor local para a internet e para que serve isso

O tunelamento do localhost é uma maneira de ter um “link externo” que aponte para alguma aplicação que você esteja rodando localmente. Dessa forma podemos “expor” nosso servidor local de forma segura.

Mas por que eu iria querer isso? Podemos usar essa solução para diversas situações, principalmente no desenvolvimento web. Vou mostrar alguns exemplos de uso nessa publicação.

Para os exemplos a seguir eu estou usando o ngrok, um software que facilita muito isso e ainda mantém essa exposição totalmente segura.

Mostrar um desenvolvimento em andamento para o cliente

Digamos que você esteja desenvolvendo um site ou um sistema web para um cliente e quer mostrar o que você desenvolveu até o momento. O mais comum seria fazer o deploy do trabalho em andamento em um servidor web e disponibilizar o link para seu cliente.

Mas existe uma outra opção, podemos deixar o site rodando localmente e tunelar com o ngrok.

Você pode iniciar um servidor local com o SimpleHTTPServer do Python, por exemplo, e rodar o ngrok na linha de comando, como no exemplo abaixo.

$ python -m SimpleHTTPServer 8000
Serving HTTP on 0.0.0.0 port 8000 ...

Em outra aba do terminal você inicia o tunelamento.

./ngrok http 8000

Agora ele irá exibir o endereço que ficará disponível para seu cliente pela internet. Será algo como http://36096fff.ngrok.io.

Ao rodar, o ngrok vai aparecer assim no seu terminal…

Estamos iniciando um servidor HTTP local na porta 8000. Perceba que o comando de tunelamento recebeu os parâmetros http e 8000, indicando que é um servidor http e que está usando a porta 8000.

Testar um chatbot durante o desenvolvimento

Durante o desenvolvimento de um chatbot para o Facebook Messenger, por exemplo, não é possível testar sem um “endereço web”. É preciso que seja registrada uma URL nas configurações do seu chatbot do Messenger para que ele receba os eventos de mensagem.

Para entender melhor sobre isso, veja este artigo.

Para que você não precise fazer deploy de cada pequena alteração em um servidor web para testar no seu chatbot, crie um tunelamento, como no exemplo anterior, e registre o endereço gerado na seção webhook nas configurações do chatbot no Messenger.

Obs: Nem todos os aplicativos de mensagem se utilizam de webhooks para receber os eventos. No caso do Telegram, como neste link, não é necessário utilizar o tunelamento.

Testar endpoints de webhooks

Eu falei em webhooks no item anterior. Pra quem não sabe o que é, segue uma tradução livre de uma parte do artigo da Wikipedia:

Webhooks são “retornos de chamada HTTP definidos pelo usuário”. Normalmente eles são ativados por algum evento, como o push de código para um repositório ou um novo comentário postado em um blog. Quando ele acontece, o site origem faz uma requisição HTTP para a URI configurada para o webhook, enviando os dados do evento.

Existem diversos serviços que utilizam esse formato para enviar dados de eventos. Um bom exemplo é o Sendgrid ou o Mandrill, que usam webhooks para enviar os eventos de email (lido, marcado como spam, link clicado, etc.) para um sistema de terceiros que esteja usando sua API.

Outro bom exemplo são integrações com gateways de pagamento, como Iugu, PagSeguro ou PayPal, onde, mesmo durante o desenvolvimento, você precisa de um “endereço web aberto” para receber os eventos relacionados aos pagamentos, alterando o status de uma compra, por exemplo.

Para isso, abra um tunelamento com o ngrok e registre o novo endereço gerado por ele com o seu endpoint para receber os eventos webhook do serviço que você está utilizando.

Painel do ngrok

Uma funcionalidade interessante do ngrok é o seu painel, ou interface web.

Screenshot da interface web

Com ela você vê todas as requisições que foram feitas ao seu endereço web aberto. Com isso você pode verificar os dados que estão vindo com as requisições e ainda dar um “replay” na mesma, para testar novamente.

Para acessar, veja o endereço listado no terminal do ngrok como Web Interface e abra no seu navegador. Vai ser algo como http://127.0.0.1:4040.

Concluindo

Esses são alguns casos de uso para o tunelamento de localhost. Alguns deles eu já utilizei, como o teste de webhooks e a demonstração de desenvolvimento em andamento para cliente. Mas eu descobri mesmo que isso era possível ao ler um tutorial de criação de chatbot para o Facebook Messenger, então resolvi dar esse exemplo também.

Publicado originalmente no Medium.
Categorias
Tecnologia

Como criar um chatbot para Telegram

Essa publicação é baseada na minha primeira experiência criando um chatbot para o Telegram usando Python. O código fonte dessa experiência pode ser encontrado no meu Github.

The Botfather

O Telegram facilita muito a criação de bots para seu sistema. Além de uma documentação muito boa e uma API muito simples de usar, ele possui o BotFather, um bot que ajuda qualquer um a criar seu próprio bot.

Segundo a documentação do Telegram:

BotFather is the one bot to rule them all. It will help you create new bots and change settings for existing ones.

Então vamos lá. Para começar é preciso acessar o @BotFather e fazer o registro do seu novo chatbot.

Para qualquer criação ou configuração de bot é preciso acessá-lo. E como vamos criar um novo bot, acessamos o link @BotFather.

Lá você terá acesso a diversos comandos, dentre eles o /start, que irá apresentar a lista desses comandos e o /newbot, que serve para a criação de um novo bot.

Quando executarmos o /newbot ele pede algumas configurações, como o nome e o username que serão utilizados pelo bot. Nada complicado.

Seu bot será como um usuário comum do Telegram, com um “nome para exibição” e um “nome de usuário” (username) para controle.

Assim que forem preenchidos os dados necessários ele irá gerar um token para ser utilizado no seu script. Esse token é único e serve como uma “senha” para seu bot, portanto deve ser mantido em sigilo.

Para saber mais sobre o @BotFather, acesse a documentação do Telegram que fala sobre bots para desenvolvedores.

Armazenando e acessando o token

Agora que já temos o token do nosso bot, devemos guardá-lo em uma variável de ambiente para que possamos acessá-lo posteriormente no nosso script Python.

Na linha de comando, execute o seguinte:

$ export BOT_API_TOKEN="<aqui vai o token gerado pelo botfather>"

Agora você poderá recuperá-lo facilmente em seu script Python com apenas duas linhas de código.

import os
token = os.environ['BOT_API_TOKEN']

Obs: Esta é apenas uma sugestão de como armazenar essa informação. Você pode guardar seu token da maneira que achar melhor.

Implementando os comandos

Um pacote que facilita muito a vida de quem está desenvolvendo um bot para o Telegram é o pyTelegramBotAPI. Com ele basta adicionar decorators nas suas funções e elas passarão a atender aos comandos recebidos.

Podemos usar o seguinte comando para instalar o pacote via pip:

$ pip install pyTelegramBotAPI

Agora chegou a hora de implementar os comandos que controlarão o bot.

Vou abordar somente um tipo de decorator e de resposta a caráter de exemplo. Através da documentação do pyTelegramBotAPI você consegue facilmente implementar diversas outras formas de input e output para o seu bot.

Começamos o script em Python fazendo nossos imports e iniciando o telebot com o token do Telegram gerado pelo @BotFather, como no exemplo de código abaixo.

import os
import telebot
  
bot = telebot.TeleBot(os.environ['BOT_API_TOKEN'])

Agora é só começar a implementar os comandos. No exemplo abaixo eu estou implementando uma mensagem de boas vindas para os comandos /start e /help.

@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
    bot.reply_to(message, u"Olá, bem-vindo ao bot!")

No final do script adicionamos o método bot.polling() para inicializar o nosso novíssimo bot.

bot.polling()

Basta executar o script em linha de comando e o seu bot está pronto para começar a ser testado.

$ python bot.py

Para executar o teste, basta acessar seu Telegram e seguir o usuário com o username que você deu para seu bot lá no começo do processo, com o @BotFather.

E voilá!

Simples, não é? Veja como nosso script em Python ficou bem pequeno.

import os
import telebot
  
bot = telebot.TeleBot(os.environ['BOT_API_TOKEN'])
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
    bot.reply_to(message, u"Olá, bem-vindo ao bot!")
bot.polling()

Publicado originalmente no Medium.

Categorias
Tecnologia

Como aprender novas tecnologias

Na área de desenvolvimento de software sempre somos bombardeados por notícias de novas tecnologias que estão dominando o mercado. E que, para ficar na “crista da onda” (e ser bem pago), é preciso trabalhar com essa ou aquela nova tecnologia.

Essa é a hora que o desespero bate e você pensa:

“Tenho que aprender esse novo framework senão vou ficar para trás!”

Tenho certeza que isso já aconteceu com muitos programadores por aí.

Aí é só aprender que ficará tudo bem, certo? Mas não é tão simples assim.

Para aprender uma coisa pra valer não basta seguir aquele tutorial maneiro do blog do especialista. Envolve muito mais do que isso.

Aprendendo Python

Em 2012 eu fiz minhas primeiras tentativas de aprender Python e Django, porque eu achava que o PHP não me daria futuro. Leia-se grana.

Em 2012 eu achava que Python me deixaria assim… Doce ilusão.

Objetivo bobo para aprender algo, na verdade. Em 2010 eu tinha tentado a mesma coisa com Java… Não rolou.

Eu fiz uns projetos pessoais como um portfólio e um controle financeiro seguindo alguns tutoriais e a documentação do Django, mas somente a caráter de teste. Não cheguei nem a arranhar a superfície do que o Python ou o Django poderiam me proporcionar como soluções.

Não existia um problema real ao qual eu precisava do Python para resolver.

Eu continuava conseguindo trabalhos somente com PHP, por causa da minha experiência profissional. Com isso acabei não aprendendo nada relacionado a Python na época.

Como não gostar de Python, não é?

Depois de um bom tempo, eu continuava com PHP nas empresas em que trabalhava, mas não queria desistir do Python porque tinha gostado de programar na linguagem.

Aí o objetivo era outro. Aprender porque eu gostava. Mas como?

Foi então que resolvi fazer alguns projetos freelance com o Flask, outro framework em Python. A partir daí comecei a entender e a dominar um pouco mais essa linguagem.

Foi uma tática muito mais inteligente.

Depois de um tempo fazendo esses freelances, acabei conseguindo um emprego para desenvolvedor em Python e hoje trabalho diariamente com ele.

Não-aprendendo AngularJS

Outra experiência parecida foi com o desenvolvimento de frontend.

Durante um período em que fiquei desempregado, comecei a procurar vagas e percebi que existia muita procura por desenvolvedor frontend. Como sempre tive conhecimento sólido com HTML/CSS e JavaScript (e jQuery), pensei que poderia conseguir alguma coisa.

O problema é que a maioria das vagas exigia conhecimentos em AngularJS ou outro framework JavaScript. Me candidatei para várias delas e apesar de chegar à fase final de quase todas, não consegui ser contratado.

Eu tenho certeza que, mesmo tendo bom domínio de HTML/CSS/Javascript, não fui contratado porque não tinha familiaridade com nenhum dos (na época novos) frameworks de frontend.

Durante esse tempo eu fiz alguns tutoriais de AngularJS para tentar melhorar essa deficiência e até para fazer testes para algumas das vagas de emprego. Mas confesso que tudo me parecia meio confuso… No final não aprendi nada. Nem sequer entendi a base do framework.

Acabei por desistir na época.

Um tempo depois, precisei utilizar AngularJS em um projeto. Foi um tempo pesquisando para acabar entendendo e aprendendo. Hoje tenho um projeto em produção usando essa tecnologia.

Graças a necessidade.

Aprendendo com a necessidade

A verdade é que cada um tem seu jeito de fixar conhecimento. Não estou aqui para impor regras a algo tão subjetivo como a forma de aprendizagem de cada um.

Quero compartilhar a minha forma de aprender: E ela chama-se necessidade.

Eu só consigo aprender algo para valer se realmente usá-lo em algum projeto. Um projeto real.

Pode ser pessoal ou comercial, mas que seja algo que eu queira ou precise mesmo fazer.

Para que eu consiga entender e fixar é preciso existir a necessidade de resolver um problema com aquela tecnologia.

Foi assim com o Python, quando comecei a focar em projetos freelance com a linguagem, passei a aprendê-la de verdade.

Resumindo: se não existir um problema real para resolver, dificilmente se chega tão fundo a ponto de conhecer as verdadeiras funcionalidades e qualidades de certa tecnologia.

Quer aprender uma nova tecnologia?

Procure a tecnologia que dê a solução para um problema que você tenha que resolver, ela será a melhor e a mais fácil para você aprender.

Fica a dica.

Publicado originalmente no Medium.

Categorias
Tecnologia

Como usar múltiplos databases no Django

Utilizando o Database Router de uma forma genérica

Existem diversos motivos para utilizar mais de um banco de dados no seu projeto de software. Um deles pode ser as réplicas, por exemplo. Neste caso o aplicativo escreve as informações em um banco de dados, mas lê de outro.

Um diagrama mostrando o banco primário e suas réplicas de leitura

A vantagem de usar uma réplica é que a escrita em banco é mais custosa do que a leitura. Então, se uma consulta for feita durante um processo de inserção de dados, dependendo da quantidade de dados que está sendo escrito no database, ela pode acabar ficando muito mais lenta, causando um problema de timeout ou até tirando seu sistema do ar.

Esse é apenas um dos exemplos que é abordado na própria documentação oficial do Django. Como mostra este link.

Obviamente, esse não é o único motivo para se ter mais de um database no sistema, podem existir inúmeros, incluindo o que me fez pesquisar sobre isso. Vou falar mais sobre o meu caso específico no final desta publicação.

Definindo os databases

O primeiro passo para utilizar mais de um database no Django é definir seus bancos de dados nas configurações do arquivo settings.py.

DATABASES = {
    'default': {},
    'primary': {
        'NAME': 'primary',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'spam',
    },
    'replica1': {
        'NAME': 'replica1',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'eggs',
    },
    'replica2': {
        'NAME': 'replica2',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'bacon',
    },
}

Com esse código, retirado da documentação do Django, estamos definindo um banco de dados principal MySQL e mais duas réplicas.

A partir de agora você pode alternar o banco manualmente chamando o using() do QuerySet. Ele recebe apenas um argumento, o nome do banco de dados.

>>> # Isso irá rodar a consulta no banco 'default'.
>>> Author.objects.all()
>>> # Isso também.
>>> Author.objects.using('default').all()
>>> # Já esse irá rodar a consulta no banco 'other'.
>>> Author.objects.using('other').all()

Acredito que esse approach não deve agradar muito o desenvolvedor. Ter que definir manualmente qual o banco a ser utilizado em cada query, não é lá muito prático, certo?

Pra evitar isso temos o Database Router, o roteador de banco de dados nativo do Django.

Criando um Database Router

O roteador de banco de dados simplesmente define qual banco é usado para cada tipo de operação.

No exemplo abaixo, também retirado da documentação do Django, mostro como rotear entre os bancos. Nesse caso, vamos ler das réplicas e escrever no primário.

import random
class PrimaryReplicaRouter(object):
    def db_for_read(self, model, **hints):
        """
        Consultas vão aleatoriamente para uma das réplicas.
        """
        return random.choice(['replica1', 'replica2'])
    def db_for_write(self, model, **hints):
        """
        Escritas sempre são feitas no banco primário.
        """
        return 'primary'
    def allow_relation(self, obj1, obj2, **hints):
        """
        Relações entre objetos são permitidas se ambos estiverem no 
        pool primary/replica.
        """
        db_list = ('primary', 'replica1', 'replica2')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

Note que o roteador de banco de dados disponibiliza quatro métodos. São eles:

  • db_for_write()
  • db_for_read()
  • allow_relation()
  • allow_migrate()

Na leitura escolhemos aleatoriamente uma das duas réplicas e na escrita escolhemos o banco primário. Perceba que simplesmente retornamos o nome do banco, que definimos nas configurações de database no settings.py.

Para que o router seja aplicado, precisamos adicionar a constante DATABASE_ROUTERS no arquivo settings.py, como mostro abaixo.

DATABASE_ROUTERS = ['caminho.para.o.PrimaryReplicaRouter']

Este é um exemplo simplificado do que pode ser feito com os database routers. Apenas resumi a documentação do Django sobre o assunto até agora.

Partimos para algo diferente, então.

Uma solução mais genérica

Procurando sobre o assunto na internet, cheguei até esta postagem de 2011 que mostra uma solução mais genérica para o database router e ainda com possibilidade de utilizar para mais de um app do Django.

from django.conf import settings
class DatabaseAppsRouter(object):
    """
    A router to control all database operations on models for different databases.
    In case an app is not set in settings.DATABASE_APPS_MAPPING, the router will fallback to the `default` database.
    Settings example:
    DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
    """
    def db_for_read(self, model, **hints):
        """"Point all read operations to the specific database."""
        if settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label):
            return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
        return None
    def db_for_write(self, model, **hints):
        """Point all write operations to the specific database."""
        if settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label):
            return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
        return None
    def allow_relation(self, obj1, obj2, **hints):
        """Allow any relation between apps that use the same database."""
        db_obj1 = settings.DATABASE_APPS_MAPPING.get(obj1._meta.app_label)
        db_obj2 = settings.DATABASE_APPS_MAPPING.get(obj2._meta.app_label)
        if db_obj1 and db_obj2:
            if db_obj1 == db_obj2:
                return True
            else:
                return False
        return None
    def allow_syncdb(self, db, model):
        """Make sure that apps only appear in the related database."""
        if db in settings.DATABASE_APPS_MAPPING.values():
            return settings.DATABASE_APPS_MAPPING.get(model._meta.app_label) == db
        elif settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label):
            return False
        return None

Agora basta mapear os apps com os databases no seu settings.py:

# Fonte: http://stackoverflow.com/a/18548287
DATABASE_ROUTERS = ['caminho.para.o.DatabaseAppsRouter']
DATABASE_APPS_MAPPING = {'nome_do_app': 'nome_do_db',
                         'nome_do_outro_app': 'nome_do_outro_db'}

No Meta do meu model eu defino o app_label, como no exemplo abaixo.

class Author(models.Model):
    name = models.CharFiels(max_length=120)
    class Meta:
        app_label = 'nome_do_app'

No meu caso de uso dessa solução, eu precisava que apenas um model lesse de um banco da dados diferente dos outros. Então, somente nele, eu adicionei o app_label mapeado com o banco de dados diferente.

Todos os outros models, que não possuem essa configuração, usam o banco default automaticamente, apenas o model com o app_label definido passa a usar o outro database.

Essa solução simplificou muito minha vida, pois agora eu posso continuar fazendo as consultas normalmente, porque o database router vai rotear tudo de maneira automática. Não preciso mais me preocupar com qual banco ele está buscando a informação em cada model.

Concluindo

Bem, é isso que tenho para mostrar. Sei que a abordagem é simplificada, mas foi a primeira vez que trabalhei nesse problema e quis dividir o que aprendi por aqui.

Espero que tenha ficado tranquilo de entender sobre o roteamento de banco de dados no Django. Caso eu não tenho sido claro em algum detalhe, entre em contanto.

Publicado originalmente no Medium.

Categorias
Crônicas Tecnologia

Ser um Programador Ninja…

…ou Programador Rockstar ou Mago da Programação…


Este texto foi originalmente publicado no Medium. Leia a versão original clicando aqui e recomende se você gostar.


Alguns bons anos atrás, costumava ser cool ver uma vaga de emprego com a expressão “programador ninja” ou algo do gênero. Mostrava que a empresa era maneira, joinha e que tinha aquele ambiente de trabalho diferentão.

“Buscamos um programador ninja”

Hoje, a coisa é um pouco diferente. Quando vejo uma vaga que busca um programador ninja ou um mago da programação, eu já desconfio.

O problema não é a expressão em si, que hoje em dia é brega e não pinta mais a empresa como “diferentona”. O problema é que ela costuma vir com uma lista absurda de exigências…

O cidadão tem que comprovar anos de experiência em diversas linguagens de programação, tem que gostar de programar em seu horário livre (?!) e, às vezes, é um diferencial, se não obrigação, que o camarada tenha projetos paralelos.

Ou seja, o cara não tem que ser um programador… Ele tem que programar de tudo e o tempo todo. Se tiver vida pessoal, não serve para mago da programação.

O ninja-mago-rockstar da programação

Por algum motivo essas empresas acreditam que é preciso ser apaixonado pela programação para ser um bom profissional. E para demonstrar isso tem que ter aqueles projetos paralelos e, quem sabe, uns commits no seu Github nas madrugadas de sábado.

O que não percebem é que quem programa por prazer não necessariamente vai gostar de trabalhar no seu projeto de gestor administrativo ou de vendas. Hobbies que viram trabalho nem sempre são tão prazerosos. E isso não é tudo…


Nesta semana eu li um texto aqui no Medium chamado Programming Doesn’t Require Talent or Even Passion (Programar Não Exige Talento ou Mesmo Paixão). Eu recomendo a leitura para qualquer um que trabalhe na área.

Nele o autor fala que nunca antes uma habilidade foi tão mitificada como a programação.

“Você não precisa apenas ter talento, você também precisa ser apaixonado para se qualificar como um bom programador.”

É exatamente o que pedem nessas vagas de programador Rockstar dos dias de hoje.


Exemplo de uma vaga postada na lista Python BrasilNo texto citado, o autor ainda traz uma série de grandes nomes da área, como os criadores dos frameworks Rails e Django e da linguagem PHP, por exemplo, que demonstram claramente não serem grandes amantes da programação e muito menos gênios da magia do desenvolvimento de software.

“Na verdade eu odeio programar, mas eu amo resolver problemas.” Tradução da citação de Rasmus Lerdorf, criador do PHP.

Eu trabalho nessa área há cerca de treze anos e não tenho receio em dizer que os melhores profissionais que encontrei não eram grandes magos dos códigos. O que realmente importa nessa área é a entrega. É conseguir resolver os problemas apresentados de forma objetiva e simples e, quase sempre, em um curtíssimo espaço de tempo.

Um bom profissional da programação não precisa ser um gênio, um monstro, um ninja, um hacker… ele precisa saber resolver problemas e ter a capacidade e humildade de aprender o que precisar para atingir esse objetivo.

Além disso, esse mito atrapalha todo mundo que está envolvido ou quer se envolver na área.

“O mito do ‘programador gênio’ é extremamente perigoso. Por um lado, ele deixa o limiar de entrada muito alto, assustando um monte de aspirantes a programador. Por outro lado, também assombra os que já são programadores, porque isso significa que se você não é um mago na programação, você é ruim… …Programação é só um monte de habilidades que podem ser aprendidas e não exigem muito talento, e não é vergonha nenhuma ser um programador mediano.” Tradução livre de parte da citação de Jacob Kaplan-Moss, criador do Django.

Eu consegui aprender a programar, e nem sequer gostava disso…

“Depois de muito tempo percebi que eu tinha ficado melhor em programar e continuava sempre ocupando vagas em empresas nessa área, entretanto, sempre querendo sair para ‘trabalhar com o que gosto’.”

Esse é um trecho de um texto que escrevi em 2014 falando sobre a minha relação conturbada com a programação. Eu passei anos procurando trabalhar em outra área, porque realmente não gostava de programar.

O que mudou isso em mim foi conhecer o Python. Passei a curtir a simplicidade e objetividade de escrever códigos com essa linguagem. Hoje eu gosto do que faço. De vez em quando eu até programo por diversão no meu horário livre.

Eu não consigo me enxergar como um bom programador, mas sei que consigo atender as expectativas de quem me contrata. Resolvo os problemas e faço as minhas entregas. E isso me deixa orgulhoso do meu trabalho.

Não somos ninjas, gênios ou magos, somos profissionais da área de desenvolvimento de software. É isso que temos que ser das 9h as 18h, ou em qualquer que seja seu horário de trabalho, o que fazemos fora disso diz respeito somente a nós mesmos.

Quer ter projetos paralelos? Ama programar? Ótimo.

Mas se você gosta de nadar, andar de bicicleta, jogar futebol, passear com seu cachorro, ficar com sua família ou dormir por horas e horas no seu tempo livre, você continua sendo um programador.

Não é isso que vai definir sua qualidade como profissional.

Pode ser também…

Categorias
Tecnologia

Lendo RSS Feed somente com Javascript (jQuery)

Eu construi uma página estática em HTML, CSS e JS para ser uma espécie de portfólio e cartão pessoal para mim e queria colocar uma seção com os artigos deste blog nela. A melhor maneira de acessar esses artigos sem muito esforço é usando o RSS Feed do blog.

Mas a página é “estática”, então eu poderia usar no máximo o Javascript para ler o Feed do blog. Uma opção seria acessá-lo via Ajax e processar os dados em seguida, mas se o Feed for de outra origem (domínio diferente, que não era o meu caso, mas pode ser o seu) ia acabar esbarrando em um erro de segurança (CORS Error) e não funcionaria.

Então encontrei uma solução (no link de referência no final do artigo), usar uma API do Google que lê um Feed e retorna um JSON com as informações dele.

Segue abaixo uma versão do código que estou utilizando na página, totalmente comentado.

[gist id=”98d6f630b9b89b229deaa19acb38e2bd”]

Os items que temos disponíveis para acesso, como mostra a imagem abaixo, são o autor, categorias e tags, o conteúdo inteiro em HTML, um pequeno snippet do conteúdo em texto puro, a URL do artigo, a data de publicação e o título. Eu senti falta do retorno das mídias, como fotos, por exemplo, mas se for necessário a opção seria pegá-las do próprio HTML que retorna em “content“.

É isso aí, qualquer dúvida ou sugestão deixe nos comentários abaixo. Para ver esse código em funcionamento acesse o site.

Referência: http://pt.stackoverflow.com/a/65758

Categorias
Tecnologia

Usando BeautifulSoup para pegar jogos, resultados e previsões do Brasileirão 2016

O pessoal no escritório está se divertindo muito com o Cartola FC. Graças a Liga que criamos por lá, todos estamos envolvidos em escalar nossos times e para isso eu gosto de ver as probabilidades de resultado dos jogos. Descobri a pouco que o Bing faz uma previsão quando você busca por dois times que irão se enfrentar. Então resolvi automatizar essa busca para me divertir e experimentar o BeautifulSoup4  (BS) para fazer crawler.

A ideia de um crawler é pegar um HTML de um site e procurar informações dentro dele. O BeautfulSoup4 é quem faz o parse deste HTML e nos permite executar métodos que fazem essa busca por informações no mesmo.

Comecei fazendo um app de um arquivo só com o Flask apenas para executar os crawlers facilmente e exibir as informações e dentro dele criei dois métodos que executam crawlers. O primeiro atualiza a tabela de jogos com os resultados (e na primeira execução popula o banco com os jogos) e o segundo executa a busca no Bing e me retorna a previsão de resultado de cada jogo.

Então o primeiro passo é buscar esse HTML no site onde você tem a informação. No caso das informações dos jogos eu fui buscar no site tabeladobrasileirao.net.

Começo utilizando o requests do Python para retornar o HTML dos jogos e seus resultados (no caso dos que já aconteceram).

import requests
r = requests.get('http://www.tabeladobrasileirao.net/')

Depois é a vez do BeautifulSoup4 entrar em ação. Passo o resultado para o BS (com o encode) e ele “parseia” o HTML.

from bs4 import BeautifulSoup
soup = BeautifulSoup(r.text.encode('utf-8'), 'html.parser')

E aí começo a procurar. Depois de analisar o HTML do site, descubro onde as informações estão e uso o método find do BS para pegar as informações.

table = soup.find('table', id="jogos")
for row in table.findAll("tr")[1:]:
    cells = row.findAll("td")
    if len(cells) == 12:
        game = {}
        game['round'] = int(cells[0].find(text=True))

        date_string = cells[1].find(text=True)
        date_string = '{}/{}'.format(date_string, '2016')
        game['date'] = datetime.datetime.strptime(date_string, "%d/%m/%Y").date()

        game['home_team'] = cells[4].find(text=True)

        home_team_result = cells[5].find(text=True)
        if home_team_result:
            game['home_team_result'] = int(cells[5].find(text=True))
        else:
            game['home_team_result'] = None

        away_team_result = cells[7].find(text=True)
        if away_team_result:
            game['away_team_result'] = int(cells[7].find(text=True))
        else:
            game['away_team_result'] = None
            
        game['away_team'] = cells[8].find(text=True)

Neste código estou buscando a tabela com id igual a “jogos” e iterando sobre suas células, a partir das linhas da tabela. Como já identifiquei onde estão os dados, comecei a guardá-los em um dicionário (tratando datas, tipos e resultados nulos) que usarei para salvar no banco de dados posteriormente. Por exemplo, cada jogo está em uma linha e a data dele está na segunda coluna, então uso cells[1].find(text=true) para pegar somente o texto da célula.

Omiti a parte de salvar no banco de dados, mas o código todo está disponível no meu Github.

Com todos os jogos salvos é a vez de procurar pela previsão de resultados no Bing.

Mais uma vez começo com o requests e dou um parse no resultado com o BS. Leve em consideração que a variável “game” no código abaixo retorna a string com o jogo em questão, por exemplo, “Internacional x Grêmio” ou “Corinthians x Flamengo”.

r = requests.get(u'http://www.bing.com/search?q={}'.format(game))

soup = BeautifulSoup(r.text.encode('utf-8'), 'html.parser')
div = soup.find('div',{'id':'tab_4'}).findNext('span',{'class':'b_demoteText'}).find_next_sibling(text=True)

predicts_string = div

Nesse caso foi muito mais difícil achar o local exato no código fonte do resultado da busca do Bing do que foi no caso do tabeladobrasileirao.net. Mas com um pouco de pesquisa e muita tentativa e erro eu acabei chegando no texto de previsão do Bing usando soup.find(‘div’,{‘id’:’tab_4′}).findNext(‘span’,{‘class’:’b_demoteText’}).find_next_sibling(text=True), mais uma vez com text=true para retornar somente o texto do objeto que vem no formato “Chapecoense 14% – Empate 29% – Corinthians 57%”, por exemplo.

Com os templates do Flask eu criei um pequeno site que executa e exibe o resultado desses crawlers. Ficou assim:

Essa foi minha primeira experiência com BeautifulSoup4 e crawlers. Qualquer dúvida ou sugestão, deixe um comentário abaixo. E para ver o código fonte desse pequeno app acesse meu Github.

Categorias
Tecnologia

Usando Grunt para compilar SCSS (Sass)

O Grunt é um gerenciador de tarefas JavaScript. O conheci pela primeira vez quando utilizei o Yeoman para desenvolver um projeto em AngularJS (leia mais).

O Sass é uma linguagem de extensão de CSS, que se auto-intitula “CSS com superpoderes”.

Precisei começar um novo projeto de frontend montando apenas os HTMLs, JavaScripts e CSSs das páginas. Então resolvi conhecer melhor o Grunt e o Sass.

Percebi que dominar essas ferramentas gera dezenas de possibilidades novas para o desenvolvimento frontend. Claro que ainda não dominei, mas vou escrever um pouco sobre o que já aprendi.

Obs: Para todos os comandos abaixo estou utilizando a linha de comando (console) do Linux.

Para instalar o Sass é necessário o package manager do Ruby, o RubyGems.

sudo su -c "gem install sass"

Para instalar o grunt-cli é necessário o package manager do Node.js, o npm. Aproveito para já instalar os pacotes que vou utilizar: grunt-contrib-sass e grunt-contrib-watch.

npm install grunt grunt-contrib-sass grunt-contrib-watch

Estou usando o Bootstrap nesse projeto, então é necessário instalar o bootstrap-sass pelo npm.

npm install boostrap-saas

Minha estrutura de diretórios será a seguinte:

  • project/
    • node_modules/
    • public/
      • css/
      • img/
      • js/
      • index.html
    • sass/
      • style.scss
    • Gruntfile.js
    • package.json

No arquivo Gruntfile.js configuramos todas as tarefas que o Grunt vai executar. No caso desta publicação faremos a preprocessamento do SCSS para CSS.

Todas as tarefas do Grunt são executadas na linha de comando (console) precedidas por “grunt”, como por exemplo “grunt watch” ou “grunt build”.

[gist id=”f1c4801d3fd6f07a76ac28ec4ef3d4d6″]

Primeiro configurei o Sass para compilar para o ambiente de desenvolvimento, nesse caso o CSS não ficará comprimido, para que eu possa vê-lo em ação. No caso da configuração para ambiente de produção ele será comprimido.

Então configuro a tarefa do grunt-watch, ela acionará a tarefa “sass:dev“, que configuramos no passo anterior, a cada mudança que eu fizer aos arquivos *.scss. Isso serve para que eu não precise rodar um comando grunt manualmente a cada alteração no SCSS, o que seria contraproducente.

Obs: Para que isso aconteça é preciso deixar o comando “grunt watch” rodando na linha de comando (console).

No final do arquivo registro as tarefas com o registerTask. No caso apenas “grunt build“, que será usado para gerar o CSS final comprimido para produção, pois a tarefa que gera os arquivos não-comprimidos para ambiente de desenvolvimento já será chamada pelo grunt-watch e não precisa ser registrada novamente.

Estas tarefas registradas ao final do arquivo servem para agregar várias tarefas a um único comando. Assim quando você precisar rodar tudo de uma vez para gerar a versão de produção, você rodorá apenas “grunt build” e todas as tarefas da lista serão executadas. No nosso caso temos apenas o Sass por enquanto, mas futuramente podemos ter diversas tarefas a serem executadas para gerar os arquivos de prod.

Vou falar mais sobre Grunt e Sass no futuro. Se tiver alguma sugestão ou dúvida sobre o conteúdo desta publicação, dexe um comentário abaixo.

Categorias
Crônicas Tecnologia

Lançamento do Diligeiro

Em novembro de 2015 recebi uma ligação de uma empresa na qual eu já havia feito entrevistas e testes meses antes. Nesta ligação marcamos uma reunião e na próxima semana lá estava eu ouvindo pela primeira vez sobre o Diligeiro.

O Diligeiro é um aplicativo para smartphone que serve para conectar advogados correspondentes com escritórios de advocacia ou advogados que precisam do serviço de diligência.

O meu desafio era criar o backend desse aplicativo, uma API. O seu grande diferencial é a geolocalização, mostrar aos correspondentes quais diligências estão mais próximas dele. Ou seja, seria minha primeira experiência desenvolvendo uma API e também a primeira experiência com Geolocalização. Estudei, experimentei e hoje posso dizer que aprendi muito.

Enquanto ainda desenvolvia todas essas coisas novas para mim, fui escalado para fazer também o frontend web do mesmo produto. Mais uma série de aprendizados, desenvolver um frontend web totalmente baseado em requisições de API. Mais estudos, experiências e aprendizados.

Nas últimas semanas o aplicativo para Android e a versão Web do Diligeiro foram lançados em formato Alpha e em seguida em formato Beta, para que os usuários pudessem começar a utilizá-lo e passarem seus feedbacks.

Nesta semana o aplicativo Android e o WebApp foram abertos ao público.

Foram seis meses de muito trabalho, muitos aprendizados e também muita diversão, graças à equipe incrível da TIA Tikal.

O trabalho continua, as melhorias e novas ideias para funcionalidades não param nunca, mas a fase inicial de desenvolvimento acabou. Agora é hora de deixar que os usuários decidam se todo o esforço valeu a pena. O aplicativo iOS continua em desenvolvimento.

Me sinto orgulhoso pelo resultado dessa primeira fase e agradecido a todos os envolvidos. A equipe do Diligeiro e a equipe do LegalNote, o produto irmão do Diligeiro que já está no mercado a mais tempo.

Categorias
Tecnologia

Escondendo partes de um endereço de email com Python

Nessa semana o projeto em que trabalho precisou de uma forma para exibir emails de usuários durante o processo de cadastro, apenas para relembrar qual endereço o mesmo havia cadastrado na sua conta.

Exibir o email completo seria uma falha de privacidade/segurança muito grande, pois o cadastro é um processo público. Para evitar isso, a equipe decidiu mostrar apenas uma parte do endereço, para que o usuário identificasse caso seja o dono da conta, mas caso não seja não teria como saber qual é o endereço completo.

Para atingir isso, criei dois pequenos métodos: um que substitui partes de uma string por asteriscos e outro que divide o email em username e domínio, para então executar o método anterior em cada parte. O resultado é que o email  testedeemail@teste.com se transforma em te********il@tes**.com.

Para deixar o método de substituição da string mais flexível, eu adicionei dois parâmetros (begin_letter_amount, end_letter_amount) que controlam quantas letras serão exibidas no começo e no final da string.

O código segue abaixo.

[gist id=”bcf64b5b57c5fc5d23a77aebcd6c0f4d”]