Tech Leads deveriam gerenciar pessoas?

Tech Leads deveriam gerenciar pessoas? Alguns líderes técnicos tem um frio na espinha só de pensar nisso. Outros, que já estão fazendo isso no dia-a-dia se lamentam e acreditam que essa é a grande dificuldade do trabalho deles e que deveriam focar só na parte técnica. Porém, na minha opinião, a resposta para essa pergunta é um grande e sonoro SIM.

No entanto, para muitos Tech Leads, essa é uma dor. É como se essa fosse a parte do trabalho que mais cria ansiedade, como aquela palpitação antes de ter um 1-1, ou se perguntando “Por que não pensei em falar isso naquela hora?” E ainda as avaliações de performance ou demissões. Muitos pensam que seria mais fácil quebrar esse papel em dois entre pessoas e tecnologia. Algumas empresas até fazem isso, mas eu não acredito nessa separação.

Por certo, você evoluiu por várias etapas no seu desenvolvimento técnico, conseguiu negociar soluções, simplificar problemas, fazer escolhas difíceis, trade-offs e navegar pela sua carreira para alcançar essa posição de liderança. Você foi forjado nesses desafios e seria um desperdício ignorar isso e se reduzir ao conhecimento técnico de uma linguagem, sistema ou framework. Aproveitar o que você sabe facilitará o caminho daqueles que você lidera e eles vão crescer com chances de se tornarem líderes também.

Porém, só para deixar claro. Sempre que eu usar a palavra líder, eu estarei falando no sentido de um facilitador, de um mentor, de alguém que está ajudando alguém a superar os desafios. Não gosto de pensar em líder como “chefe”. Aliás, não gosto nem dessa palavra.

Imagem do Mentor do He-man. 
Tech Leads deveriam gerenciar pessoas?
Mentor.
Para quem lembra do He-man

Deixa eu me explicar.

Por fim, fiz esse vídeo, no qual explico um pouco sobre o porquê eu acredito tanto que tech Leads deveriam gerenciar pessoas.

Esse assunto começou sendo discutido lá no meu instagram, me sigam: https://www.instagram.com/ffreitasalves/

Efeito Dunning-Kruger e a Síndrome do Impostor

Muito se fala sobre a síndrome do impostor, porém pouco temos visto sobre o outro lado da moeda que é o Efeito Dunning-Kruger.

Quantas pessoas você conhece que sabem tão pouco sobre um assunto mas se acham as maiorais, enquanto outras pessoas com muito conhecimento, sentem-se incapazes? Esses problemas são reais. Um deles podemos evitar com um pouco mais de humildade, no outro, com mais auto-confiança. Veja o vídeo que gravei para o meu instagram:

E esse vídeo tem uma continuação aqui, falando sobre as pessoas que usam a Síndrome do Impostor como bengala.

Contudo, mesmo falando que tem gente que usa isso como bengala, ainda existem muitos casos reais de quem sofre com isso, como nessa história que eu falei aqui.

O óbvio ululante para quem quer crescer na carreira de tecnologia

Tem uma pequena coisa que você precisa entender para ser um profissional de tecnologia melhor. É uma coisa óbvia que a grande maioria se esquece no dia a dia e depois não entende porque está demorando para evoluir como uma liderança técnica. Você precisa entender qual o objetivo da área técnica.

E não é só para liderança, mesmo um desenvolvedor no começo da carreira poderia crescer mais rápido se tivesse isso em mente.

O objetivo da área técnica é dar viabilidade para o negócio. Ponto!

O Poço e quando defecam em nós.. Óbvio. | by Sephiroth Computatrum | Medium

Tem que entender o negócio de verdade. Se interesse pelo problema a ser resolvido, traga alternativas, aprenda a negociar escopo, avalie quando dá pra entregar algo inacabado, mas com alguém operando no back-office, saiba quando poderia ou não comprar uma dívida técnica, enfim, tenha em mente sempre em como o resultado do seu trabalho vai impactar o negócio.

Entender isso faz toda a diferença para crescer mais rápido na carreira e para ser uma liderança técnica eficaz!

Publiquei esse texto ontem 15/Set/20 no meu Linkedin e depois usei os stories do Instagram para falar um pouco sobre casos desse tipo.

Me sigam por lá!

PS: Usei a famosa expressão do Nelson Rodrigues, “Óbvio ululante”, em homenagem a um brasileiro que era espetacular. Esse ano li “A Pátria de Chuteiras” que é uma coletânea de textos futebolísticos do Nelson Rodrigues e de lá podemos ver o quanto esse cara acreditou no brasileiro. Eu também acredito!

Culpa por estar descansando

Você passa o final de semana se culpando por estar descansando? 

Esse é um assunto que surgiu algumas vezes conversando com desenvolvedores na minha mentoria. A história é sempre parecida: Você tem pouco tempo durante a semana e no final de semana quando vai descansar ou se divertir, você pensa que deveria estar trabalhando ou estudando e se sente culpado.

Bart Bored | Capa twitter

Citando Yuval Harari no livro Homo Deus: “No mundo moderno, nós humanos tocamos o negócio. Por isso estamos sob constante pressão dia e noite”.  Essa pressão é normal, pois você sabe que é o grande responsável pelo seu sucesso e seu futuro, seja na carreira, na vida familiar, financeira, etc. Não dá pra terceirizar, é melhor aceitar que é difícil e fazer alguma coisa quanto a isso.


O que fazer? Planeje-se. E antes de inventar a desculpa de que “não adianta planejar minuto a minuto”, dê uma chance para o planejamento. Esse simples ato vai te dar muitos insights sobre o que você deveria ou não estar fazendo.

Pegue papel e caneta e escreva tudo que você gostaria de fazer, quais áreas da sua vida você precisa balancear, quanto tempo você gostaria de se dedicar para cada coisa e se planeje. Se você decidir que não vai usar o final de semana para esses objetivos então simplesmente fique em paz. Você vai ver que o problema não é estar se divertindo, é simplesmente estar com um monte de abas do Chrome em aberto na sua cabeça.

Descanso planejado não tem sentimento de culpa! Você só precisa estar OK com as escolhas que você fez para você. Se você não estiver confortável porque gostaria de estar investindo seu tempo em um negócio próprio, em um curso ou em uma atividade física, se planeje e execute.


Meetup Virtual de Flutter para Pessoas em Quarentena

Meetup virtual de Flutter para pessoas em quarentena

Eu estava querendo organizar um Meetup de Flutter mas com a quarentena até dei uma desanimada… Até descobrir a história de como o Meetup foi criado.

Depois do ataque ao World Trade Center em 2001, Scott Heiferman se reuniu com seus vizinho. Apesar de morar no mesmo prédio há anos, nunca havia falado com eles.

A situação em Nova York era tão delicada que acabou por aproximar as pessoas em suas comunidades locais. O espírito era de cooperação.

Depois desse encontro e de uma vigília na cidade, Scott se viu com questões como:

  • O que une as pessoas?
  • O que leva as pessoas a falarem umas com as outras?
  • O que leva as pessoas a se organizarem em grupos para fazerem coisas boas?

Scott diz que antes não era muito ligado a comunidades, porém estava intrigado e no ano seguinte resolveu criar o Meetup junto a mais cinco pessoas.

O Meetup é uma plataforma online que busca unir pessoas presencialmente. Contudo, desde a quarentena que nos foi imposta pelo COVID-19 eles mudaram o “in-person event policy” e estão incentivando os organizadores a criarem eventos online.

Aproveitei a oportunidade e criei o Meetup Virtual de Flutter para Pessoas em Quarentena

O ser humano é um animal social e espero que estejamos ainda mais unidos depois de passarmos por esta crise.

Deploy de aplicações SSR utilizando o Supervisord

Se você está construindo aplicações que renderizam do lado do servidor, o famoso SSR, utiliznado React (com o next.js) ou Vue.js (com o nuxt.js), você vai precisar de alguma ferramenta para controle do processos quando for fazer o deploy. Eu escolhi fazer o deploy de aplicações SSR utilizando o Supervisord, apesar de ter visto em vários sites o pessoal utilizando PM2 para este tipo de aplicação, acredito que o Supervisord é mais conhecido em um contexto geral, não só de quem é do mundo do node.
Se você já viu meu Guia para Deploy Django e Python 3, você já usou o Supervisor.

A razão número 1 para você ter um aplicativo React ou Vue utilizando SSR é por causa do SEO. O Googlebot não trabalha bem com páginas renderizadas do lado do cliente (CSR, o contrário do SSR) e por conta disso pode nem indexar suas páginas. Então, ter uma aplicação SSR dessas rodando no seu servidor, significa que você vai servir a aplicação utilizando o node pra rodar os javascripts que você criou. E para manter o seu comando node rodando, você não pode simplesmente abrir em um screen e torcer para que continue rodando. Você precisa colocar seu app em uma ferramenta de controle de processos como o Supervisord para inicializar sua aplicação caso o servidor reinicie ou sua própria aplicação dê algum pau.

Instalando o Supervisord:

sudo apt-get install supervisor

Agora, vamos criar um arquivo de configuração para a aplicação SSR:

sudo vi /etc/supervisor/conf.d/my-ssr-app.conf

That’s the content:


[program:myappname]
directory=/home/username/yourproject/
command=npm run start
user=username
autostart=true
autorestart=true

Então, precisamos avisar o supervisord que existe um novo processo para ele controlar


sudo supervisorctl reread
sudo supervisorctl update

E futuramente, quando precisar restartar apenas o seu app, use o nome que você colocou no arquivo de configuração.


sudo supervisorctl restart myappname

E é isso aí. Agora você sabe como fazer deploy de aplicações SSR utilizando o Supervisord.

I Know Kung Fu GIF from The Matrix (Now you know how to deploy ssr applications using supervisord)

Alguns links:

Post original em inglês

https://www.reddit.com/r/reactjs/comments/an16mx/how_does_seo_work_with_react/

https://medium.com/walmartlabs/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8

https://dev.to/stereobooster/server-side-rendering-or-ssr-what-is-it-for-and-when-to-use-it-2cpg

Criando um container Docker para um projeto Django Existente

Neste post, vou mostrar como criar um container Docker para um projeto Django já existente. Como exemplo, resolvi buscar por uma issue aberta no github que estivesse pedindo para ser dockerizada. Criei um PR para a Issue e usei como exemplo aqui.

Por quê você vai querer dockerizar uma aplicação web django que já existe? Bom, existem muitas razões, se você acha que não tem uma, faça pela diversão!

Eu decidi usar o docker em uma das minhas aplicações porque ela estava ficando muito difícil de instalar. Muitos requisitos do sistema, vários bancos de dados, celery, rabbitmq e por aí vai. Sem dockerizar cada vez que uma nova pessoa entra no time é um inferno pra setar tudo porque levava tempo demais.

O mundo ideal é que o programador tenha em seu ambiente de desenvolvimento o mais próximo que puder do ambiente de produção. Se você usa SQLite na sua máquina mas Postgres no servidor pode ser que tenha problemas de dados que são simplesmente truncados localmente mas que vão levantar erros na base de produção. Só para ter ideia de um exemplo.

Se você não sabe o que é o docker, imagine que é um imenso virtualenv que no lugar de ter apenas pacotes python tem o sistema operacional “inteiro”. Isso consegue isolar seu app de tudo que está no seu SO, bancos de dados, workers, etc.

Mão na massa

Ok, falar é fácil, vamos codar um pouco.

Primeiro de tudo, instale o Docker. Fiz isso no Ubuntu e no Mac sem nenhum problema. Já no Windows Home não consegui fazer funcionar.

Para dizer ao docker que sua aplicação é um container você precisa criar um arquivo Dockerfile:



FROM python:3.6
ENV PYTHONUNBUFFERED 1

RUN mkdir /webapps
WORKDIR /webapps

# Installing OS Dependencies
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
libsqlite3-dev

RUN pip install -U pip setuptools

COPY requirements.txt /webapps/
COPY requirements-opt.txt /webapps/

RUN pip install -r /webapps/requirements.txt
RUN pip install -r /webapps/requirements-opt.txt

ADD . /webapps/

# Django service
EXPOSE 8000

Vamos lá, linha a linha:

Docker Images

FROM python:3.6

Aqui estamos usando uma imagem do docker hub. Isto, é um container pré-formatado do docker que permite que você monte sua máquina a partir daquela configuração inicial. Nesse caso, Python 3.6 é um container de um Ubuntu que tem o Python 3.6 instalado nele. Você pode procurar por containers no docker hub.

Environment Variables (Variáveis de ambiente)

Você pode criar todas as variáveis de ambiente que quiser com o ENV.

ENV PYTHONUNBUFFERED 1  # Here we can create all Environment variables for our container

Por exemplo, se você usa variáveis de ambiente para guardar sua secret key do Django é só fazer assim:

ENV DJANGO_SECRET_KEY abcde0s&&$uyc)[email protected]!a95nasd22e-dxt^9k^7!f+$jxkk+$k-

E usar no seu settings, desse jeito:

import os
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']

Run Commands

Docker Run Commands tem um nome meio óbvio. Você pode rodar um comando “dentro” do seu container. Estou colocando dentro entre aspas porque o docker na verdade cria algo como sub containers para que não precise rodar os mesmos comandos novamente no caso de precisar dar um rebuild do container.

RUN mkdir /webapps
WORKDIR /webapps

# Installing OS Dependencies
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
libsqlite3-dev

RUN pip install -U pip setuptools

COPY requirements.txt /webapps/
COPY requirements-opt.txt /webapps/

RUN pip install -r /webapps/requirements.txt
RUN pip install -r /webapps/requirements-opt.txt

ADD . /webapps/

Aqui estamos criando o diretório que guardará os arquivos do projeto: webapps/.

Workdir é uma instrução para mostrar ao docker em qual diretório ele vai rodar os comandos a partir dali.

Depois disso estou instalando as dependências do sistema operacional. Quando estamos usando requirements.txt no projeto, estamos colocando apenas os requisitos do python e não os do SO. Mais um motivo para querer usar o docker para desenvolver. Quanto maior seu projeto, mais requisitos de sistema operacional vão aparecer.

COPY e ADD

Copy e ADD são basicamente a mesma cosia. Ambos copiam um arquivo do seu computador (o Host) dentro do container (o Guest). No meu exemplo, estou apenas copiando o requirements para dentro do docker, para que eu possa dar pip install nos pacotes.

EXPOSE

Expose é para mapear uma porta do Guest (o Container) para o Host (seu computador)

# Django service
EXPOSE 8000

Ok, e agora? Como podemos adicionar mais containers para rodá-los juntos? E se precisarmos colocar um postgresql para rodar em um container também? Não se preocupe, vamos usar o docker-compose.

Docker-Compose

O compose é uma ferramenta para rodar múltiplos containers do docker. Só precisa criar um arquivo yml na pasta do seu projeto com o nome docker-compose.yml:

version: '3.3'

services:
  # Postgres
  db:
    image: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=postgres

  web:
    build: .
    command: ["./run_web.sh"]
    volumes:
      - .:/webapps
    ports:
      - "8000:8000"
    links:
      - db
    depends_on:
      - db

Aqui estou usando uma imagem do Postgres que também peguei no Docker Hub.

Agora vamos mudar o settings.py para poder usar o Postgres do container como banco de dados.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': '5432',
    }
}

Quase lá, deixa eu falar um pouco sobre o arquivo docker-compose.yml,

VOLUMES

Lembra do vagrant?

Era uma vez o Vagrant. Ele era uma forma de rodar um projeto dentro de uma Máquina Virtual que permitia configurar e mapear portas fácilmente, provisionar requisitos do sistema e compartilhar volumes. Seu computador (o Host) podia compartilhar um volume com a máquina virtual (o Guest, ou convidado). No docker, o volume é exatamente a mesma coisa. Quando você escreve um arquivo em um volume que está compartilhado o arquivo também está sendo escrito dentro do container.

volumes:
  - .:/webapps

Nesse o caso, o diretório em que nos encontramos (.) é o que está sendo compartilhado com o container.

LINKS

links:
  - db

Você pode se referir a outro container que pertence ao seu arquivo docker-compose utilizando o nome dele. Como criamos um container com o nome db para o Postgres nós podemos criar um link para ele no nosso container chamado web. Pode ver que no settings.py nós colocamos ‘db‘ como host.

DEPENDS_ON

Para rodar sua aplicação, seu banco de dados precisa estar pronto antes do container web, senão vai dar algum pau!

depends_on:
  - db

Command

Command é o comando padrão que o docker vai rodar logo depois que você subir, ou seja, colocar os containeres para funcionar.

No nosso exemplo, eu criei um run_web.sh que vai rodar as migrações, coletar o static files e iniciar o servidor de desenvolvimento.

#!/usr/bin/env bash

cd django-boards/
python manage.py migrate
python manage.py collectstatic --noinput
python manage.py runserver 0.0.0.0:8000

Alguém pode argumentar que migrar assim automaticamente toda vez que subir o container pode não ser uma boa prática. Eu concordo. Você pode (e deve) rodar o migrate direto na máquina web. Você pode acessar seu container para rodar comandos assim (como no bom e velho vagrant ssh):

docker-compose exec web bash

Se você quiser , você pode rodar o comando sem acessar o container mesmo, apenas mudando o último argumento do comando acima:

docker-compose exec web python manage.py migrate

O mesmo para outros comandos:

docker-compose exec web python manage.py test
docker-compose exec web python manage.py shell

Rodando o Docker

Com nosso Dockerfile, docker-compose.yml e o run_web.sh no lugar, vamos rodar tudo junto:

docker-compose up

Você pode ver esse projeto aqui no meu GitHub.

Escrevi esse texto originalmente em inglês.

**EDITADO**

Antes eu estava usando run no lugar de exec. Mas o Bruno FS me mostrou que o exec é melhor pois está acessando exatamente o container que já está rodando e que o run na verdade está criando um novo container.

References:

4 Melhores Podcasts sobre Tecnologia e Startups

Ouvir Podcasts é uma forma muito eficiente para se manter por dentro do que acontece na sua área.  Ouço vários Podcasts sobre tecnologia e startups, além de outros temas e tenho certeza que eles são importantes para que eu continue atualizado no meu ramo. Estar informado pode ser a diferença entre ser bom e ser ótimo.

Para quem não conhece, podcast é como um programa de rádio com a diferença de que você pode ouvir quando quiser, escolher os episódios e sempre ficará sabendo quando publicarem um programa novo. Podcast não é novidade mas não chegou a virar mainstream no Brasil ainda. Vai crescer muito este ano.

Meu aplicativo para assinar (baixar e ouvir) podcasts é o PocketCasts ele é pago, paga uma vez só e usa todos os dias, mas existem várias outras opções gratuitas aí para quem não quiser desembolsar os R$ 12 reais. Bora pra lista:

Hipsters.tech

logo do podcast hipsters.tech

Apesar do nome péssimo, clichê e modinha é na minha opinião o melhor podcast brasileiro. Tem um episódio por semana e é um programa muito bem formatado. Normalmente os episódios tem menos de uma hora e variam sobre desenvolvimento, design, empreendedorismo, etc.

Esse é um dos episódios que gostei bastante sobre Squads. Você pode dar uma olhada em outros episódios no site deles https://hipsters.tech

Software Engineering Daily

software engineering daily logo

Esse é um podcast gringo (em inglês). Eles soltam um episódio por dia útil, ou seja, é daily mesmo. Mesmo que não dê para ouvir todos os dias é bom ficar por dentro e olhar o que eles já fizeram. Tem entrevistas com gente da área de tecnologia e de startups, normalmente engenheiros e empreendedores de empresas renomadas e criadores das tecnologias que estão sendo discutidas. Você pode ver os episódios aqui

Talk Python to Me

talk python to me podcast logo

Esse podcast é mais específico para pythonistas, mas quem não gosta de python? Tem participações de caras muito fodas da comunidade como Kenneth Reitz, David Beasley e até do Guido Van Rossum.

O site é esse aqui: https://talkpython.fm/ . Meu único problema com esse podcast é que ele tinha a melhor música de abertura de qualquer podcast até o meio do ano passado, depois entrou uma música chata =P

Like a Boss

like a boss podcast logo

Esse é um podcast dos mesmos criadores do Hipsters. O objetivo é “trazer entrevistas com líderes, fundadores de startups e empresas inovadoras” nas próprias palavras deles. Está bem no comecinho, tem apenas 7 episódios.

Gostei bastante dessa entrevista com David Vélez, o fundador do Nubank.

Outros podcasts:

Eu gostava muito do ZOFE (Zone of Front-Enders) , mas infelizmente ele não tem novas publicações já faz tempo. O site está mais desatualizado que o podcast mas ainda assim dá para ouvir conteúdo do passado. Era realizado pelo Daniel Filho, um cara diferenciado que eu sempre via no melhor meetup de front-ends de São Paulo, o FEMUG-SP.

Falando em podcasts antigos, outro que curti bastante mas já não solta coisa nova é o Grok Podcast. Isso que é bom dos podcasts, eles podem ter acabado mas os episódios estão aí para sempre.

Um podcast que eu descobri recentemente foi o Castálio Podcast. Também fala bastante de Python. Por enquanto, só ouvi um episódio e foi sobre serverless. Aliás, dá pra ver o podcast sendo gravado ao vivo no youtube e mandar perguntas para eles.

Mais um podcast gringo que estou esperando ver como vai desenrolar é o Modern CTO. Me parece uma estratégia audaciosa para criar conteúdo para CTOs uma coisa que não se vê todo dia. Estou começando a acompanhar.

Bom, esses foram os meus podcasts favoritos sobre esses temas. Quem tiver outros podcasts que quiser indicar deixe nos comentários.

 

Guia para Deploy Django Python 3

crianças fazendo deploy

Tutorial de Deploy por aí é o que não falta, a maioria em inglês. Esse que estou criando é pra engrossar o caldo de deploys em português. Esse é um Guia Definitivo Rápido, ou não tão rápido, para fazer Deploy Django com Python 3. É um deploy para Kids.

A dificuldade de fazer um deploy reside nos detalhes. No fundo é fácil se você está familiarizado com as partes envolvidas. Você precisa saber fazer uma autenticação ssh, estar acostumado com a linha de comando, conhecer linux, saber configurar o projeto, entender o que é servir arquivos estáticos, gunicorn…. tá, tá… nunca é fácil e muito menos rápido, justamente por isso criaram um monte de ferramentas pra deploy. E hoje com Ansible, Docker e whatever kids are using these days fica fácil fazer o deploy mas muito abstrato entender o funcionamento.

Em alguns anos esse post será obsoleto pra sempre, com serverless e tudo mais acho que pouca gente vai querer saber como fazer um deploy django dessa forma. Mas, mesmo assim, se ajudar uma pessoa já está bom. Será um tutorial Old-Style.

O Servidor

Vou imaginar que você não tem um servidor, não tem uma conta na AWS, nem DigitalOcean, nem Linode, nada… Você pode criar uma conta em um deles, lançar uma máquina com as configurações que quiser (Na AWS é tudo mais complicado pra quem não está acostumado, se for sua primeira vez, prefira outro).

Pra esse tutorial estou falando de Ubuntu 16.04, que é o servidor que você mais vai ver por aí nesse momento nesses serviços. Você pode escolher um Debian qualquer também.

Configuração inicial

Configure o timezone do servidor

sudo locale-gen --no-purge --lang pt_BR
sudo dpkg-reconfigure tzdata

Atualize os pacotes:

sudo apt-get update 
sudo apt-get -y upgrade

Instalando Python 3.6 no lugar do Python 3.5

Agora substitua o Python 3.5 instalado, pelo Python3.6 (O Ubuntu que indiquei, ele vem com Python 3.5.1)

sudo apt-get update
sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt-get install python3.6
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2

Você pode escolher qual versão do Python o SO vai usar ao chamar python3 com:

sudo update-alternatives --config python3

Se você se enrolar, dê uma olhada aqui.

Instale os requisistos do Sistema Operacional

Aqui tem alguns pacotes que eu sempre uso em um deploy.

sudo apt-get install python3-pip nginx supervisor git git-core libpq-dev python-dev 
python-virtualenv

Seu projeto pode ter outros requirements do SO pra instalar.

VirtualEnvWrapper para o Python3

Eu gosto muito do VirtualEnvWrapper, acho simples de começar um virtualenv, e deixa todos os meus virtualenvs no mesmo lugar, mas isso é escolha pessoal, se você não gosta, faça como está acostumado

Você instala o virtualenvwrapper, depois define a pasta dos seus virtualenvs (WORKON_HOME).

Para usar com múltiplos Pythons você vai precisar definir VIRTUALENVWRAPPER_PYTHON. No caso estou usando sempre o padrão que defini para o comando python3. Isso não é um problema porque você pode criar um virtualenv depois apontando qual python aquele virtualenv vai usar.

sudo pip3 install virtualenvwrapper
echo 'export WORKON_HOME=~/Envs' >> ~/.bashrc
echo ‘export VIRTUALENVWRAPPER_PYTHON=`which python3`’ >> ~/.bashrc
echo 'source /usr/local/bin/virtualenvwrapper.sh' >> ~/.bashrc
source ~/.bashrc

Crie seu VirtualEnv apontando qual python aquele virtualenv irá usar

mkvirtualenv nome_venv --python=python3

O VirtualEnvWrapper é muito fácil, para entrar em um Virtualenv que você criou, você pode usar:

workon nome_venv

Para sair do virtualenv:

deactivate

Para excluir um virtualenv:

rmvirtualenv nome_venv

Gere as Chaves SSH para autenticar no GitHub

Você não quer (e nem deveria) escrever a senha pra fazer o git pull do seu projeto no servidor.

Gere as chaves SSH

cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "[email protected]"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa

Veja e copie o conteúdo da sua chave pública (id_rsa.pub)

cat ~/.ssh/id_rsa.pub

Depois entre no seu github, em Settings > SSH and GPG Keys. Clique em New SSH Key, dê um nome pra essa chave, como (“chaves do servidor teste”) e em Key cole o conteúdo da chave pública id_rsa.pub

Faça o clone do seu projeto Django

Copie o link SSH do Github para fazer o clone, no caso estou usando um projeto que encontrei agora pra exemplo

git clone [email protected]:kirpit/django-sample-app.git

Entre na pasta do projeto e instale os requirements do projeto.

Lembre-se de estar no virtual env correto.

cd django-sample-app/
pip install -r requirements.txt

Agora faça as alterações que forem necessárias para o deploy django, como criar um arquivo de settings_local, banco de dados, ou qualquer outra coisa específica do seu projeto.

Depois de tudo certo, você ainda precisa rodar as migrações e gerar os arquivos estáticos (se estiver usando)

python manage.py migrate
python manage.py collectstatic

Configurando o NGINX

Nginx, assim como o Apache, tem um mundo inteiro só deles, nesse momento você precisa conhecer o básico.

Existe um diretório /etc/nginx/sites-available/ onde ficão os arquivos de configuração de sites disponíveis para o nginx servir e existe o diretório /etc/nginx/sites-enabled/ que é a mesmíssima coisa, mas o que estiver aqui o Nginx estará servindo mesmo.

Normalmente você cria o arquivo de configuração no sites-available/ e cria um link simbólico para o sites-enabled/

Nós vamos fazer isso. Primeiramente, vou excluir o site default do nginx

sudo rm /etc/nginx/sites-enabled/default

Agora crie o arquivo de configuração para o seu site. (Se você não está acostumado com o VIM, use troque vi por nano)

sudo vi /etc/nginx/sites-available/meusite

No conteúdo do arquivo, coloque isto, mudando os caminhos necessários:

server {
 listen 80;
 access_log /home/usuario/logs/access.log;
 error_log /home/usuario/logs/error.log;

 server_name nome-site.com.br;

 location / {
 proxy_pass http://127.0.0.1:8000; 

 #As proximas linhas passam o IP real para o gunicorn nao achar que sao acessos locais
 proxy_pass_header Server;
 proxy_set_header X-Forwarded-Host $server_name;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header Host $http_host;


 }

 location /static {

   alias /home/usuario/caminho_projeto/static/;

 }

}

Agora crie o link simbólico para o sites-enabled:

sudo ln -s /etc/nginx/sites-available/meusite /etc/nginx/sites-enabled/meusite

Reinicie o Nginx:

sudo service nginx restart


(Se você configurou tudo direitinho até aqui, ao acessar o site você verá uma página com um erro 502 Bad Gateway do próprio nginx)

Isso acontece porque ainda não tem nada aqui http://127.0.0.1:8000

Vamos colocar o site pra rodar nessa porta pelo gunicorn

Configurando o Gunicorn

Alguém vivo até essa parte? Cansa não, falta pouco.

No seu virtualenv (lembra workon nome_env?) instale o gunicorn

pip install gunicorn

Na pasta do seu projeto crie um arquivo chamado gunicorn_conf com:

bind = "127.0.0.1:8000"
logfile = "/home/usuario/logs/gunicorn.log"
workers = 3

Agora se você rodar o gunicorn, você vai ver seu site rodando:

/home/usuario/Envs/nome_venv/bin/gunicorn projeto.wsgi:application -c gunicorn_conf

Mas o que você pretende fazer? Rodar esse comando dentro de um screen e ir embora? Não dá né! Então, você vai usar o Supervisor pra controlar o funcionamento do gunicorn.

Configurando o Supervisor

Crie o seguinte arquivo de configuração

sudo vi /etc/supervisor/conf.d/gunicorn.conf

Com o seguinte conteúdo:

[program:gunicorn]
command=/home/usuario/Envs/nome_venv/bin/gunicorn projeto.wsgi:application -c /home/usuario/projeto/projeto_django/gunicorn_conf
directory=/home/usuario/projeto/projeto-django
user=usuario
autostart=true
autorestart=true
redirect_stderr=true

Depois é só avisar o supervisor que existe um novo processo que ele precisa controlar da seguinte forma:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart gunicorn

E voilá! Um site rodando você terá!

Conclusão

Existem muito mais coisas envolvidas no processo de um deploy. Você precisa configurar um firewall, provavelmente precisará servir mais pastas estáticas, etc, etc, etc… Mas precisa começar por algum lugar.

Não acredito que fiz um post inteiro sem colocar nenhum gif no meio, então só pra terminar, PRESTE ATENÇÃO em TODOS os caminhos que eu coloquei acima, você vai ter que usar os seus próprios paths corretamente

Oops..

Populando um campo novo não-nulo no Django

Fala pessoal, esse é um post rápido no qual eu vou mostrar como popular uma migração criando um campo novo não-nulo no django

SAY WUUUUT?????

george costanza taking his glasses off

Seguinte, sabe quando você tem seu projeto rodando, banco de dados, models, front, em produção as porra tudo e então aparece um requisito novo e eis que surge um campo obrigatório, que ninguém pensou antes, nem o cliente, nem o product owner, nem ninguém! Essa é a situação!

Acontece que você usa as migrações do django e você quer que poder colocar esses campos usando os migrations, tanto migrando pra frente quanto pra trás, ok?

Chega de conversa, pra esse exemplo resolvi pegar um projeto pronto nas interwebz, acabei optando por um django polls feito em django 1.10 já pronto.

Então lá se vão os passos de sempre, clonar e criar virtualenv…

git clone [email protected]:garmoncheg/django-polls_1.10.git
cd django-polls_1.10/
mkvirtualenv --python=/usr/bin/python3 django-polls 
pip install django==1.10  # Nesse projeto o autor não criou um requirements.txt
python manage.py migrate  # rodando as migrações existentes
python manage.py createsuperuser 
python manage.py runserver

Obs: Esse projeto pronto que pegamos está com uma migração faltando, então se você estiver seguindo esse passo a passo rode um python manage.py makemigrations pra que seja criada a migração 0002 (que é só a mudança de um verbose_name)

Agora você acessa o admin (http://localhost:8000/admin/polls/question/add/) e cria o seu poll :

 

django polls admin
Aí você pode ir lá no app polls e ver sua pergunta, responder etc…
até aí OK, ainda não fizemos nada!

Bom, o ideal é criar mais umas perguntas com datas de publicação diferentes para a brincadeira
ficar boa.

Depois de começar a usar você vai perceber que qualquer enquete fica infinita no seu site, ou seja, todas as vezes que alguém entra no site ele tem a oportunidade de votar, você nunca encerra a votação.

Então nossa alteração no código será a seguinte: De agora em diante, todas as enquetes terão uma data de expiração. No momento do cadastro o usuário poderá colocar a data na qual a votação se encerrará e o usuário será direcionado diretamente para o resultado. Queremos que essa data de expiração seja um campo obrigatório! E para os que já estão funcionando na plataforma vamos determinar arbitrariamente que cada um tenha um mês de validade a partir da data de publicação.

Antigamente, antes de migrações como isso era feito em qualquer sistema? Via SQL você criava um campo que permitisse NULOS, depois você criava uma query que populava esse campo e por fim você alterava a tabela pra tornar aquela coluna obrigatória. Com as migrações é a mesma coisa.

Então vamos criar o campo novo nos models vou chamá-lo de expires_date:

expires_date = models.DateTimeField(‘expires at’, null=True)

E o model inteiro fica assim:

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    expires_date = models.DateTimeField('expires at', null=True)

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'


Agora vamos criar a migração dessa mudança:

python manage.py makemigrations

E ele criará a migração 0003_question_expires_date. O conteúdo é o seguinte:

class Migration(migrations.Migration):

    dependencies = [
        ('polls', '0002_auto_20170429_2220'),
    ]

    operations = [
        migrations.AddField(
            model_name='question',
            name='expires_date',
            field=models.DateTimeField(null=True, verbose_name='expires at'),
        ),
    ]

 

Vamos modificar o código dessa migration, NO PANIC!

Populando o novo campo

Primeiro criamos uma função para popular o banco com as datas de expiração:

def populate_expires_date(apps, schema_editor):
    """
    Popula o campo data de expiração das perguntas já existentes colocando um mẽs de validade para cada.
    """
    from datetime import timedelta

    db_alias = schema_editor.connection.alias
    Question = apps.get_model('polls', 'Question')

    for row in Question.objects.using(db_alias).filter(expires_date__isnull=True):
        row.expires_date = row.pub_date + timedelta(days=30)
        row.save()

Originalmente usei esse código em um projeto que utiliza múltiplos bancos de dados, então precisei usar o db_alias e achei interessante deixá-lo aqui. Quanto ao Question, estou dando um import desse model usando o apps.get_model pois nesse momento que estamos rodando a migração o campo ainda não existe para o projeto, pois a migração não acabou de rodar, então é melhor que importar do model.

Agora, dentro da migração existe uma lista chamada operations. Nessa lista vamos adicionar os comandos para rodar a nossa função e em seguida, vamos adicionar a obrigatoriedade do campo: ficando dessa forma:

operations = [
    migrations.AddField(
        model_name='question',
        name='expires_date',
        field=models.DateTimeField(null=True, verbose_name='expires at'),
    ),
    migrations.RunPython(populate_expires_date, reverse_code=migrations.RunPython.noop),
    migrations.AlterField(
        model_name='question',
        name='expires_date',
        field=models.DateTimeField(verbose_name='expires at'),
    )
]

Você pode ver que utilizamos o migrations.RunPython para rodar nossa função durante a migração. O reverse_code serve quando alguém for dar um unapply da migração, nesse caso não existia o campo, então não faremos nada.

Logo em seguida adicionei a migração que altera o campo e ele deixa de ter null=True. Também poderíamos ter feito isso em outra migração, só retirando essa informação do model (que precisa ser retirada agora de qualquer forma) e ter criado uma nova migração.

O model ficará assim:

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    expires_date = models.DateTimeField('expires at')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

agora você pode rodar o migrate tranquilamente:

python mange.py migrate

Pronto! Pra ver as alterações vou adicionar esse campo no admin, tanto para ser editado como no list_display:

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date', 'expires_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
    list_display = ('question_text', 'pub_date', 'expires_date', 'was_published_recently')
    list_filter = ['pub_date']
    search_fields = ['question_text']

E voilá, todos as Questions que você tinha no polls contam com um expires_date, obrigatório e com 30 dias adicionado por default para as Questions antigas.

É isso aí, agora tem esse campo que queremos! O projeto com as alterações está aqui: https://github.com/ffreitasalves/django-polls_1.10

Se gostou, compartilhe com os amigos e deixe um comentário. Se não gostou também! Abraços!

 

Fontes:

http://stackoverflow.com/questions/28012340/django-1-7-makemigration-non-nullable-field

http://stackoverflow.com/questions/29217706/django-view-sql-query-without-publishinhg-migrations

https://realpython.com/blog/python/data-migrations/

https://docs.djangoproject.com/en/1.10/howto/writing-migrations/#non-atomic-migrations