Categorias
Crônicas

Retrospectiva 2017

Ao final de cada ano, desde 2015, comecei uma pequena tradição inspirada pelo meu amigo e chefe Fernando Freitas Alves. Escrever uma retrospectiva do ano que passou.

Talvez a parte mais importante seja parar para pensar em tudo que aconteceu. Minha grande motivação para escrever em 2015 foi o fato de que aquele ano me ensinou mais do que qualquer outro em toda a minha vida.

Já a retrospectiva de 2016 mostrou que ano passado foi de estabilização no trabalho e na vida pessoal. Apesar de não ter muitos avanços na parte da saúde, uma das metas que continuei tendo em 2017.

Como sempre faço em minha vida, em 2017 experimentei diversas maneiras de me manter em uma rotina mais saudável. Tentei algumas novas atividades físicas, como o Crossfit por exemplo, e infelizmente não consegui dar continuidade como deveria.

Também me arrisquei em técnicas de jejum intermitente para perda de peso e melhora da atividade cerebral… sem sucesso.

Graças a mais um ano de falhas na área da saúde percebi que preciso dar uma importância maior para este tópico na minha escala de metas para 2018. O primeiro passo já foi dado: horário marcado na nutricionista já para janeiro.

Mas tive uma pequena conquista nesse ano. Foi agora, bem no finalzinho, em dezembro mesmo. Foi uma amostra de que posso atingir algo se me esforçar um pouco. Parei de roer unhas! Graças a um aplicativo chamado Coach.me.

Roer unhas era um hábito que estava difícil de largar e por isso resolvi usar como um experimento desse aplicativo. Acredite se quiser, estou sentindo as unhas batendo nas teclas neste exato momento como há anos não sentia. Um pequeno passo, mas uma grande prova de que posso conseguir mudar alguns hábitos em 2018, certo?

Outra pequena conquista desse ano foi o café sem açúcar. Sempre tomei café muito doce, mas com a ideia do jejum intermitente veio a necessidade de tomar café ao natural.

O primeiro dia sempre é estranho. Você faz careta a cada gole, mas no dia seguinte eu já estava sentindo o gosto de diferentes tipos de café que temos disponíveis lá no escritório e decidindo os que realmente são do meu gosto.

No trabalho, que nos ocupa boa parte do tempo dentro de um ano, 2017 se mostrou estável. Continuo trabalhando como desenvolvedor na startup de legal tech Tikal Tech.

Com o lançamento de uma nova linha de produtos na empresa as coisas aconteceram rápido. Este foi o ano do ELI na Tikal Tech.

Graças ao desenvolvimento do ELI ICMS Energia tivemos uma experiência muito produtiva com arquitetura de microsserviços. Além de outras integrações interessantes como o Login Integrado do LegalNote para aplicativos ELI. Um sistema de gestão de acesso de usuários centralizado para diferentes aplicativos em Django.

Antes disso, mais pro início do ano, tive o prazer de participar da comunidade Chatbot Brasil. Até criei alguns chatbots e coloquei algum conteúdo por aqui sobre o assunto. Já na Tikal Tech implementamos o chatbot Corujinho na fanpage do SeuProcesso no Facebook. Foi uma experiência bem interessante.

Com o crescimento da empresa tivemos um aumento considerável no staff. Basta ver a  foto do pessoal na retrospectiva de 2015 e notar como as coisas mudaram! Veja a foto da equipe nesse ano.

Equipe Tikal Tech 2017

Falando em trabalho não posso esquecer das minhas férias. Este foi uma das grandes metas desse ano. Aproveitei  maravilhosos 30 dias de viagens e descanso merecido depois de muitos e muitos anos sem tirar férias.

O ponto alto foi a primeira semana em que eu e minha namorada passamos alguns dias em Paraty. Que lugar maravilhoso para aproveitar natureza, os locais históricos e, é claro, as praias e os passeios de barco. Que delícia!

Financeiramente 2017 também foi um ano muito bom para mim, pelo menos comparados aos últimos dez anos de perrengues e problemas para manter um orçamento estável. Graças à liberação do FGTS inativo consegui quitar algumas dívidas e até mobiliar um pouco minha vazia casa.

Mas o que realmente está fazendo a diferença é o estudo de finanças pessoais. Durante esse ano inteiro investi um bom tempo nesse tópico, seguindo canais de Youtube interessantes como o do Gustavo Cerbasi e o Me Poupe!, os quais indico muito a quem quer começar a sair do buraco.

Graças a isso, posso até começar a pensar em investir algum dinheiro para 2018. Nem que sejam apenas alguns trocados. A meta é montar uma reserva de emergência o quanto antes!

Para terminar, algo legal que voltei a fazer: desenhar.

Desenho desse ano! Yey!

Nesse ano de 2017 eu voltei a desenhar e até alimentei o meu canal que fala sobre criação de histórias em quadrinhos no Youtube. Separei os tópicos que falam sobre isso aqui no meu blog para um novo domínio separando assim os conteúdos.

Criei também um Instagram e voltei a alimentar a minha velha fanpage no Facebook.

Sempre adorei desenhar histórias em quadrinhos e manter um hobby divertido como esse é algo essencial para a qualidade de vida de qualquer um. Me fez um bem danado!

Participei pela primeira vez de um Inktober! Se quiser entender melhor o que é isso, é melhor dar uma lida na publicação que fiz no meu blog de desenho.

Bem, por cima esse foi o meu ano de 2017. Essa retrospecitva vale mais para quem escreve do que para quem lê, porque a parte mais legal é repassar o ano na sua cabeça. Rever o que foi feito e pensar em como melhorar no ano seguinte.

Se você leu até aqui, obrigado! Deixe seu comentário sobre como foi seu ano também!

Um abraço e até 2018!

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
Tecnologia

Calculando a distância entre dois pontos e ordenando os resultados com GeoDjango

Atualmente tenho trabalhado com Django em um projeto de API que aproveita a geolocalização do usuário para ordenar os dados e mostrar os resultados mais próximos.

Para fazer isso é preciso utilizar um conjunto de ferramentas específicas para geolocalização que o Django possui, que são conhecidos como GeoDjango.

Nesse texto não irei cobrir as instalações e configurações específicas do banco de dados. Mas elas podem ser vistas aqui.

[gist id=”fde02ecf744cfeb8e5db” file=”settings.py”]

Começamos adicionando django.contrib.gis no nosso arquivo settings.py e partimos para os nossos models.

[gist id=”fde02ecf744cfeb8e5db” file=”models-1.py”]

Ao invés de importar os models comuns do Django, importamos os models do django.contrib.gis.db. Nesse caso eu criei um abstract model que vai ser utilizado em todos os outros que necessitarem de endereço e localização.

O campo location vem com um tipo especial, o PointField, que irá guardar os dados de geolocalização do endereço.

No model que extende nosso AddressBaseModel utilizamos o GeoManager para substituir o manager dos models comuns do Django.

[gist id=”fde02ecf744cfeb8e5db” file=”models-2.py”]

Agora podemos ordenar o resultado pela distância de um ponto específico.

Na view vamos utilizar o método distance do queryset para “criar” um campo com o mesmo nome e utilizar o order para ordenar por esse novo campo distance.

Para o método distance, precisamos passar uma origem. Origem será o local que o usuário está nesse caso. Para transformar as strings com a latitude e longitude em um ponto de geolocalização, utilizamos a classe Point do django.contrib.gis.geos.

[gist id=”fde02ecf744cfeb8e5db” file=”views.py”]

Para formatar o resultado eu criei um método get_distance no StuffSerializer. O objetivo dele é mostrar a distância em metros ou quilômetros.

[gist id=”fde02ecf744cfeb8e5db” file=”serializers.py”]

O resultado será algo como o exemplo abaixo.

[gist id=”fde02ecf744cfeb8e5db” file=”result.json”]

Este é um exemplo de como podemos utilizar o GeoDjango para calcular a distância e ordenar os resultados através dela, mas existem diversas outras formas de fazer isso também.

Deixe seu comentário ou dúvida abaixo.