Ambientes de Desenvolvimento com Dev Containers e Boas Práticas em Python

Parabéns por chegar ao último submódulo de fundamentos! Você já instalou o WSL, o Docker, o VS Code e aprendeu a usar o Git/GitHub. Agora, vamos unir tudo isso com a ferramenta que transforma seu ambiente de desenvolvimento: os Dev Containers.

Os Dev Containers (Contêineres de Desenvolvimento) automatizam o uso do Docker para criar ambientes de desenvolvimento completos, consistentes e reproduzíveis com apenas um clique. Adeus, “mas na minha máquina funciona”! Com Dev Containers, a máquina de todos é a mesma: um contêiner Docker perfeitamente configurado.

Dev Containers na Prática

Passo 1: Instalar a Extensão Dev Containers

Para começar, você precisa da extensão “Dev Containers” no VS Code. Ela é a ponte entre o seu editor e os contêineres Docker.

  1. Abra o VS Code.
  2. Vá para a aba de Extensões (ícone de blocos no menu lateral, ou Ctrl+Shift+X).
  3. Procure por Dev Containers.
  4. Instale a extensão publicada pela Microsoft.

Passo 2: Criando seu Primeiro Dev Container

Embora você possa usar configurações pré-definidas geradas pelo VS Code, o poder real dos Dev Containers vem da personalização. Normalmente, uma configuração de Dev Container reside em uma pasta .devcontainer na raiz do seu projeto e é composta por dois arquivos principais: Dockerfile e devcontainer.json.

Dockerfile: A Receita do Ambiente

O Dockerfile é um arquivo de texto que contém as instruções para construir a imagem Docker do seu ambiente. É aqui que você define o sistema operacional base, instala dependências do sistema (como curl ou git), e configura usuários.

Veja um exemplo básico:

Dockerfile
# Usa uma imagem linux base Debian 12 (Bookworm) que já inclui Python (3.10) e a ferramenta 'uv' (0.6.17).
FROM ghcr.io/astral-sh/uv:0.6.17-python3.10-bookworm

# Evita que o Python armazene a saída em buffer, facilitando o logging.
ENV PYTHONUNBUFFERED=1

# Argumentos para criar um usuário não-root. Usar um usuário não-root é uma boa prática de segurança.
ARG USERNAME=usuario
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Cria o grupo e o usuário.
RUN groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME

# Define o usuário padrão do contêiner para o usuário não-root que criamos.
USER $USERNAME

# Define o diretório de trabalho dentro do contêiner.
WORKDIR /home/$USERNAME/workspace

devcontainer.json: A Configuração do VS Code

O arquivo devcontainer.json diz ao VS Code como ele deve usar o Dockerfile e como configurar o editor uma vez que esteja conectado ao contêiner.

Veja um exemplo simplificado:

devcontainer.json
{
    "name": "Meu Ambiente de Desenvolvimento",
    // Diz ao VS Code para construir o ambiente a partir de um Dockerfile.
    "build": {
        "dockerfile": "Dockerfile"
    },
    // Define o usuário remoto que o VS Code deve usar ao se conectar.
    // Deve ser o mesmo usuário criado no Dockerfile.
    "remoteUser": "usuario",
    // "Features" adicionam funcionalidades pré-empacotadas ao seu contêiner,
    // como ferramentas comuns de linha de comando ou o histórico do shell.
    "features": {
        "ghcr.io/devcontainers/features/common-utils:2": {},
        "ghcr.io/stuartleeks/dev-container-features/shell-history:0": {},
        "ghcr.io/nils-geistmann/devcontainers-features/zsh:0": {}
    },
}

Com esses dois arquivos dentro da pasta .devcontainer, o VS Code irá notificá-lo para reabrir o projeto dentro do contêiner. Ao aceitar, ele cuidará de todo o processo de build e conexão, entregando um ambiente de desenvolvimento pronto e consistente.


Introdução Prática ao Python

Python é uma das linguagens mais populares para ciência de dados devido à sua sintaxe simples e ao seu ecossistema de bibliotecas poderosas.

Gerenciando Pacotes e Ambientes Virtuais

No Dev Container de exemplo, o Python 3.10 já vem instalado. O próximo passo é gerenciar as dependências do seu projeto. É uma má prática instalar pacotes diretamente no Python “global” do sistema. Para isso, usamos ambientes virtuais.

Um ambiente virtual é uma pasta que contém uma instalação Python isolada, específica para o seu projeto. Isso evita que as dependências do Projeto A entrem em conflito com as do Projeto B.

venv: O Padrão

venv é o módulo padrão do Python para criar ambientes virtuais.

# Criar um ambiente virtual em uma pasta chamada .venv
python3 -m venv .venv

# Ativar o ambiente (Linux/WSL)
source .venv/bin/activate

# Agora, seu terminal mostrará (.venv) no início.
# Qualquer pacote instalado ficará restrito a este ambiente.

Com o ambiente ativo, você pode instalar pacotes com o pip, o instalador de pacotes do Python.

# Instalar a biblioteca pandas
pip install pandas

uv: O Recomendado

UV é uma ferramenta moderna e extremamente rápida que pode substituir pip e venv com uma única interface. É um projeto promissor que vale a pena conhecer.

# Instalar uv de forma global (geralmente uma única vez)
# No devcontainer de exemplo o uv já vem instalado
pip install uv

# Iniciar o uv na pasta atual
uv init
Nota

O uv vai criar os seguintes arquivos:

├── .gitignore
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

Para simplificar seu projeto, você pode deixar apenas o pyproject.toml.

Finalmente, para instalar dependências com o uv é simples:

# Instalar pacotes pandas e numpy com uv
uv add pandas numpy

Tipos de Dados e Variáveis

Você pode declarar variáveis e o Python inferirá o tipo.

# Tipos numéricos
numero_inteiro = 10
numero_decimal = 10.5
soma = numero_inteiro + numero_decimal

# Texto (string)
saudacao = "Olá, Mundo!"

# Booleanos (Verdadeiro ou Falso)
verdadeiro = True
falso = False

# Listas (coleções ordenadas e mutáveis)
minha_lista = [1, "dois", 3.0, True]

# Imprimindo os resultados no console
print("Soma:", soma)
print("Saudação:", saudacao)
print("Primeiro item da lista:", minha_lista[0])

Funções e Instalação de Pacotes

Funções permitem agrupar código para reutilização. A verdadeira força do Python para ciência de dados está em seus pacotes. Como vimos, você usa uv para instalá-los.

# Exemplo de uma função simples
def somar(a, b):
    """Esta função recebe dois números e retorna sua soma."""
    return a + b

resultado = somar(5, 3)
print("Resultado da função somar:", resultado)

# Para usar pacotes externos, você primeiro os instala no terminal do vscode
# (com seu ambiente virtual ativo):
# uv add pandas numpy

# E depois os importa no seu código:
import pandas as pd
import numpy as np

print("\nPacotes importados com sucesso!")

Boas Práticas para Projetos de Ciência de Dados

À medida que seus projetos crescem, passar de um único script para uma estrutura de projeto organizada é fundamental para a manutenção, colaboração e reprodutibilidade.

Estrutura de pastas

Uma estrutura de pastas bem definida torna seu projeto intuitivo. Aqui está uma sugestão robusta:

seu_projeto/
├── .devcontainer/  # Configuração do Dev Container
├── .gitignore
├── data/
│   ├── raw/        # Dados brutos e imutáveis. A fonte da verdade.
│   └── processed/  # Dados limpos, transformados, prontos para análise.
├── notebooks/      # Notebooks Jupyter ou Quarto para exploração e relatórios.
├── scripts/        # Scripts para automação (ex: rodar um pipeline de processamento).
├── src/            # Código fonte principal do projeto
├── .env            # Arquivo para variáveis de ambiente e segredos (NUNCA versionar no Git).
├── pyproject.toml  # Arquivo de configuração do projeto Python
├── uv.lock         # Dependências Python
└── README.md       # Documentação principal do projeto.

Modularização

Evite criar scripts monolíticos de milhares de linhas.

  • Quebre o código em funções: Cada função deve ter uma única responsabilidade.
  • Organize funções em módulos: crie arquivos .py dentro de src/ (ex: src/data_processing.py, src/modeling.py).
  • Crie um arquivo de utilidades: Um src/utils.py é perfeito para funções auxiliares genéricas (ex: carregar configurações, configurar logging) usadas em várias partes do projeto.
  • Use “Services” para abstrair fontes de dados: Se seu projeto se conecta a um banco de dados ou a uma API, crie um módulo específico para isso (ex: src/database_service.py). Isso isola a lógica de conexão do resto do código.

Documentação: O Manual de Instruções

Código bem escrito é parcialmente autoexplicativo, mas a documentação explica o porquê das coisas.

  • Docstrings: Descrevem o que uma função faz, seus parâmetros e o que ela retorna.

    def carregar_dados(caminho_arquivo: str) -> pd.DataFrame:
        """Carrega dados de um arquivo CSV e retorna um DataFrame.
    
        Args:
            caminho_arquivo: O caminho para o arquivo CSV.
    
        Returns:
            Um DataFrame pandas com os dados carregados.
        """
        return pd.read_csv(caminho_arquivo)

Gerenciando Configurações e Segredos com .env

Nunca coloque informações sensíveis (senhas, chaves de API) diretamente no seu código. Use arquivos .env para gerenciá-las.

  1. Crie um arquivo chamado .env na raiz do projeto.
  2. Adicione suas variáveis: DB_PASSWORD="minha-senha-secreta".
  3. Adicione .env ao seu arquivo .gitignore!
  4. Use bibliotecas como python-dotenv para carregar essas variáveis no seu ambiente de execução.

Conclusão do Módulo Zero

Se você chegou até aqui, parabéns! Você completou uma jornada fundamental: partiu de um sistema Windows, mergulhou no Linux com WSL, dominou contêineres com Docker, aprendeu a colaborar com Git e GitHub, e agora sabe como criar ambientes de desenvolvimento profissionais e reproduzíveis com Dev Containers.

Você está mais do que preparado para enfrentar os desafios de qualquer projeto de ciência de dados com as melhores ferramentas e práticas do mercado.