Plano de Estudos Rust: Nível Sênior (18+ Meses)

Roadmap para se tornar um desenvolvedor Rust sênior. Unsafe Rust, FFI, otimização de performance, internals do compilador, liderança técnica e contribuição para o ecossistema Rust.

O caminho para o nível sênior em Rust vai muito além de dominar a sintaxe e os padrões da linguagem. Um desenvolvedor sênior entende o “porquê” por trás das decisões de design do Rust, sabe quando e como contornar as garantias de segurança usando unsafe, otimiza performance em níveis profundos e exerce liderança técnica que eleva toda a equipe.

Este plano é para quem já tem pelo menos 18 meses de experiência sólida com Rust, já trabalhou em projetos de produção e quer atingir o nível de excelência que define os profissionais mais valorizados do mercado.

Visão Geral do Roadmap

PeríodoFocoResultado Esperado
Meses 19-22Unsafe Rust, FFI e internalsEntender Rust em nível profundo
Meses 23-26Performance e otimizaçãoExtrair máxima performance do hardware
Meses 27-30Arquitetura e liderançaProjetar e liderar sistemas complexos
Meses 31-36Contribuição core e influênciaImpactar o ecossistema Rust

Meses 19-22: Unsafe Rust, FFI e Internals do Compilador

Unsafe Rust: Poder com Responsabilidade

Unsafe Rust é uma das áreas mais mal compreendidas da linguagem. Um desenvolvedor sênior sabe exatamente quando usar unsafe, como encapsulá-lo corretamente e como manter as garantias de segurança do Rust mesmo quando opera fora do safe subset.

Os 5 superpoderes do unsafe:

  1. Derreferenciar ponteiros brutos (*const T, *mut T)
  2. Chamar funções ou métodos unsafe
  3. Acessar ou modificar variáveis estáticas mutáveis
  4. Implementar traits unsafe
  5. Acessar campos de unions
use std::alloc::{self, Layout};
use std::ptr;

/// Um buffer circular thread-safe implementado com unsafe
/// para máxima performance
pub struct RingBuffer<T> {
    buffer: *mut T,
    capacidade: usize,
    leitura: usize,
    escrita: usize,
    tamanho: usize,
}

impl<T> RingBuffer<T> {
    pub fn new(capacidade: usize) -> Self {
        assert!(capacidade > 0, "Capacidade deve ser maior que zero");
        assert!(
            capacidade.is_power_of_two(),
            "Capacidade deve ser potência de 2 para otimização de módulo"
        );

        let layout = Layout::array::<T>(capacidade).unwrap();
        // SAFETY: layout tem tamanho > 0 (garantido pelo assert acima)
        let buffer = unsafe { alloc::alloc(layout) as *mut T };

        if buffer.is_null() {
            alloc::handle_alloc_error(layout);
        }

        RingBuffer {
            buffer,
            capacidade,
            leitura: 0,
            escrita: 0,
            tamanho: 0,
        }
    }

    pub fn push(&mut self, valor: T) -> Result<(), T> {
        if self.tamanho == self.capacidade {
            return Err(valor);
        }

        // SAFETY: escrita está sempre dentro dos limites do buffer
        // porque usamos máscara de bits (capacidade é potência de 2)
        unsafe {
            let pos = self.escrita & (self.capacidade - 1);
            ptr::write(self.buffer.add(pos), valor);
        }

        self.escrita = self.escrita.wrapping_add(1);
        self.tamanho += 1;
        Ok(())
    }

    pub fn pop(&mut self) -> Option<T> {
        if self.tamanho == 0 {
            return None;
        }

        // SAFETY: leitura está dentro dos limites e aponta para
        // um valor válido inicializado por push()
        let valor = unsafe {
            let pos = self.leitura & (self.capacidade - 1);
            ptr::read(self.buffer.add(pos))
        };

        self.leitura = self.leitura.wrapping_add(1);
        self.tamanho -= 1;
        Some(valor)
    }

    pub fn len(&self) -> usize {
        self.tamanho
    }

    pub fn is_empty(&self) -> bool {
        self.tamanho == 0
    }
}

impl<T> Drop for RingBuffer<T> {
    fn drop(&mut self) {
        // SAFETY: precisamos dropar todos os elementos restantes
        while let Some(_) = self.pop() {}

        let layout = Layout::array::<T>(self.capacidade).unwrap();
        // SAFETY: buffer foi alocado com o mesmo layout em new()
        unsafe {
            alloc::dealloc(self.buffer as *mut u8, layout);
        }
    }
}

// SAFETY: RingBuffer é Send se T é Send, pois possui os dados exclusivamente
unsafe impl<T: Send> Send for RingBuffer<T> {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn operacoes_basicas() {
        let mut rb = RingBuffer::new(4);
        assert!(rb.push(1).is_ok());
        assert!(rb.push(2).is_ok());
        assert!(rb.push(3).is_ok());
        assert!(rb.push(4).is_ok());
        assert!(rb.push(5).is_err()); // cheio

        assert_eq!(rb.pop(), Some(1));
        assert_eq!(rb.pop(), Some(2));

        assert!(rb.push(5).is_ok()); // agora tem espaço
        assert!(rb.push(6).is_ok());
    }

    #[test]
    fn wraparound() {
        let mut rb = RingBuffer::new(4);
        for i in 0..100 {
            rb.push(i).unwrap();
            assert_eq!(rb.pop(), Some(i));
        }
    }
}

Princípios para unsafe seguro:

  1. Minimize a superfície unsafe: encapsule unsafe em funções com interface safe
  2. Documente invariantes: explique em comentários // SAFETY: por que o unsafe é correto
  3. Teste exaustivamente: use Miri para detectar undefined behavior
  4. Prefira abstrações existentes: antes de escrever unsafe, verifique se há uma crate que já resolve
# Rodar testes com Miri para detectar UB
rustup component add miri
cargo +nightly miri test

FFI (Foreign Function Interface)

FFI permite que Rust interaja com código C/C++ e vice-versa. Isto é fundamental para integração com bibliotecas do sistema, drivers e código legado.

// Chamando código C a partir de Rust
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int};

// Declarando funções externas de uma biblioteca C
extern "C" {
    fn strlen(s: *const c_char) -> usize;
    fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int;
    fn getenv(name: *const c_char) -> *const c_char;
}

fn tamanho_cstring(s: &str) -> usize {
    let c_str = CString::new(s).expect("String contém null byte");
    // SAFETY: c_str é uma string C válida terminada em null
    unsafe { strlen(c_str.as_ptr()) }
}

fn ler_variavel_ambiente(nome: &str) -> Option<String> {
    let c_nome = CString::new(nome).ok()?;
    // SAFETY: getenv retorna null ou ponteiro para string válida
    let ptr = unsafe { getenv(c_nome.as_ptr()) };
    if ptr.is_null() {
        None
    } else {
        // SAFETY: ptr não é null e aponta para string C válida
        Some(unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned())
    }
}

// Expondo Rust para ser chamado por C
#[no_mangle]
pub extern "C" fn rust_somar(a: c_int, b: c_int) -> c_int {
    a + b
}

#[no_mangle]
pub extern "C" fn rust_fibonacci(n: c_int) -> c_int {
    match n {
        0 => 0,
        1 => 1,
        _ => {
            let mut a = 0;
            let mut b = 1;
            for _ in 2..=n {
                let temp = b;
                b = a + b;
                a = temp;
            }
            b
        }
    }
}

Usando bindgen para gerar bindings automaticamente:

# Cargo.toml
[build-dependencies]
bindgen = "0.69"
// build.rs
fn main() {
    println!("cargo:rerun-if-changed=wrapper.h");

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Falha ao gerar bindings");

    let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Falha ao escrever bindings");
}

Internals do Compilador e MIR

Entender como o compilador Rust funciona internamente ajuda a escrever código melhor e a contribuir para o projeto.

Fases de compilação do Rust:

Código Fonte (.rs)
    │
    ▼
[Parsing] → AST (Abstract Syntax Tree)
    │
    ▼
[Name Resolution + Macro Expansion] → Expanded AST
    │
    ▼
[HIR Lowering] → HIR (High-level IR)
    │
    ▼
[Type Checking + Trait Resolution] → Typed HIR
    │
    ▼
[MIR Lowering] → MIR (Mid-level IR)
    │
    ▼
[Borrow Checking] → Verified MIR
    │
    ▼
[Optimization] → Optimized MIR
    │
    ▼
[Code Generation] → LLVM IR
    │
    ▼
[LLVM Optimization + Code Gen] → Código de máquina

Explorando MIR:

# Visualizar MIR de uma função
RUSTFLAGS="--emit=mir" cargo build

# Ou usar o Rust Playground com a opção MIR

# Visualizar LLVM IR
RUSTFLAGS="--emit=llvm-ir" cargo build

# Visualizar assembly
RUSTFLAGS="--emit=asm" cargo build
// Exemplo: entendendo como o compilador otimiza
// Esta função é eliminada pelo compilador (zero-cost abstraction)
fn somar_iterador(nums: &[i32]) -> i32 {
    nums.iter().sum()
}

// Gera assembly praticamente idêntico a:
fn somar_loop(nums: &[i32]) -> i32 {
    let mut total = 0;
    for &n in nums {
        total += n;
    }
    total
}

// O MIR mostra que ambas são reduzidas
// à mesma sequência de operações

Ferramentas para explorar internals:

FerramentaUso
cargo-expandVisualizar macros expandidas
cargo-asmVisualizar assembly gerado
cargo-llvm-linesContar linhas de LLVM IR por função
Rust Playground (MIR)Explorar MIR interativamente
Compiler Explorer (godbolt.org)Comparar assembly entre versões

Checklist dos Meses 19-22

  • Escreve unsafe Rust com documentação SAFETY correta
  • Usa Miri para verificar ausência de undefined behavior
  • Implementa FFI bidirecional (Rust←→C)
  • Usa bindgen para gerar bindings automaticamente
  • Entende as fases de compilação e sabe ler MIR
  • Sabe quando unsafe é necessário vs. quando evitá-lo

Meses 23-26: Performance e Otimização

Profiling e Benchmarking

Antes de otimizar, é preciso medir. Otimização prematura é a raiz de muitos problemas.

// Benchmarking com criterion
// Cargo.toml:
// [dev-dependencies]
// criterion = { version = "0.5", features = ["html_reports"] }
// [[bench]]
// name = "meu_benchmark"
// harness = false

use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};

fn busca_linear(dados: &[i32], alvo: i32) -> Option<usize> {
    dados.iter().position(|&x| x == alvo)
}

fn busca_binaria(dados: &[i32], alvo: i32) -> Option<usize> {
    dados.binary_search(&alvo).ok()
}

fn benchmark_busca(c: &mut Criterion) {
    let mut grupo = c.benchmark_group("busca");

    for tamanho in [100, 1_000, 10_000, 100_000].iter() {
        let dados: Vec<i32> = (0..*tamanho).collect();
        let alvo = tamanho / 2;

        grupo.bench_with_input(
            BenchmarkId::new("linear", tamanho),
            tamanho,
            |b, _| b.iter(|| busca_linear(black_box(&dados), black_box(alvo))),
        );

        grupo.bench_with_input(
            BenchmarkId::new("binaria", tamanho),
            tamanho,
            |b, _| b.iter(|| busca_binaria(black_box(&dados), black_box(alvo))),
        );
    }

    grupo.finish();
}

criterion_group!(benches, benchmark_busca);
criterion_main!(benches);

Ferramentas de profiling:

# perf (Linux)
cargo build --release
perf record -g ./target/release/meu_programa
perf report

# Flamegraph
cargo install flamegraph
cargo flamegraph --release

# Valgrind / Cachegrind (análise de cache)
valgrind --tool=cachegrind ./target/release/meu_programa
cg_annotate cachegrind.out.*

# Heaptrack (análise de alocação)
heaptrack ./target/release/meu_programa
heaptrack_gui heaptrack.*.gz

Otimização de Alocações

Alocações de heap são uma das principais fontes de lentidão. Um desenvolvedor sênior sabe minimizá-las.

use std::borrow::Cow;

// Ruim: aloca desnecessariamente
fn processar_nome_ruim(nome: &str) -> String {
    if nome.contains(' ') {
        nome.replace(' ', "_")
    } else {
        nome.to_string() // alocação desnecessária
    }
}

// Bom: usa Cow para evitar alocação quando possível
fn processar_nome_bom(nome: &str) -> Cow<'_, str> {
    if nome.contains(' ') {
        Cow::Owned(nome.replace(' ', "_"))
    } else {
        Cow::Borrowed(nome) // zero alocação
    }
}

// Reutilizando buffers em loops
fn processar_dados_otimizado(dados: &[Vec<u8>]) -> Vec<String> {
    let mut buffer = String::new(); // alocado uma vez
    let mut resultados = Vec::with_capacity(dados.len()); // pré-alocado

    for item in dados {
        buffer.clear(); // reutiliza a memória alocada
        for &byte in item {
            buffer.push(byte as char);
        }
        resultados.push(buffer.clone());
    }

    resultados
}

// Usando SmallVec para vetores pequenos (stack allocation)
// use smallvec::SmallVec;
// let mut nums: SmallVec<[i32; 8]> = SmallVec::new();
// Para 8 ou menos elementos, fica na stack

// Arena allocation para muitas alocações pequenas de mesma lifetime
// use bumpalo::Bump;
// let arena = Bump::new();
// let s = arena.alloc_str("texto na arena");
// Tudo liberado de uma vez quando arena é droppada

SIMD e Otimizações de CPU

// Processamento vetorial com SIMD
// Nota: requer nightly ou std::simd quando estabilizado

// Abordagem portável: confiar no auto-vetorização do LLVM
fn soma_quadrados_autovec(dados: &[f32]) -> f32 {
    dados.iter().map(|x| x * x).sum()
}

// Para o compilador vetorizar eficientemente:
// 1. Use slices contíguos (não linked lists)
// 2. Evite branches dentro de loops
// 3. Use tipos alinhados
// 4. Processe em blocos de tamanho fixo

fn dot_product_otimizado(a: &[f32], b: &[f32]) -> f32 {
    assert_eq!(a.len(), b.len());

    // Processamento em chunks para auto-vetorização
    let mut soma = 0.0f32;
    let chunks = a.len() / 4;

    for i in 0..chunks {
        let offset = i * 4;
        soma += a[offset] * b[offset]
            + a[offset + 1] * b[offset + 1]
            + a[offset + 2] * b[offset + 2]
            + a[offset + 3] * b[offset + 3];
    }

    // Processar elementos restantes
    for i in (chunks * 4)..a.len() {
        soma += a[i] * b[i];
    }

    soma
}

// Dicas de compilação para performance:
// RUSTFLAGS="-C target-cpu=native" cargo build --release
// Isso habilita instruções SIMD específicas da CPU

Otimização de Cache e Layout de Memória

// Ruim: Array of Structs (AoS) - pobre localidade de cache
struct ParticleAoS {
    x: f64,
    y: f64,
    z: f64,
    mass: f64,
    vx: f64,
    vy: f64,
    vz: f64,
    name: String,  // 24 bytes desnecessários para cálculo de posição
}

// Bom: Struct of Arrays (SoA) - excelente localidade de cache
struct ParticlesSoA {
    x: Vec<f64>,
    y: Vec<f64>,
    z: Vec<f64>,
    mass: Vec<f64>,
    vx: Vec<f64>,
    vy: Vec<f64>,
    vz: Vec<f64>,
    names: Vec<String>,
}

impl ParticlesSoA {
    fn atualizar_posicoes(&mut self, dt: f64) {
        // Acessa apenas os dados necessários - cache friendly
        for i in 0..self.x.len() {
            self.x[i] += self.vx[i] * dt;
            self.y[i] += self.vy[i] * dt;
            self.z[i] += self.vz[i] * dt;
        }
    }
}

// Alinhamento de dados para SIMD
#[repr(C, align(64))]  // Alinhado ao tamanho de cache line
struct AlgoritmoBuffer {
    dados: [f64; 8],
}

// Ordenação de campos para minimizar padding
// Ruim: desperdiça bytes com padding
struct PaddinRuim {
    a: u8,      // 1 byte + 7 padding
    b: u64,     // 8 bytes
    c: u8,      // 1 byte + 3 padding
    d: u32,     // 4 bytes
}               // Total: 24 bytes

// Bom: campos ordenados por tamanho decrescente
struct PaddingBom {
    b: u64,     // 8 bytes
    d: u32,     // 4 bytes
    a: u8,      // 1 byte
    c: u8,      // 1 byte + 2 padding
}               // Total: 16 bytes (33% menor!)

Concorrência e Paralelismo de Alta Performance

use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;

// Contadores atômicos lock-free
struct Metricas {
    requisicoes_total: AtomicU64,
    requisicoes_erro: AtomicU64,
    bytes_processados: AtomicU64,
}

impl Metricas {
    fn new() -> Self {
        Metricas {
            requisicoes_total: AtomicU64::new(0),
            requisicoes_erro: AtomicU64::new(0),
            bytes_processados: AtomicU64::new(0),
        }
    }

    fn registrar_requisicao(&self, bytes: u64, sucesso: bool) {
        self.requisicoes_total.fetch_add(1, Ordering::Relaxed);
        self.bytes_processados.fetch_add(bytes, Ordering::Relaxed);
        if !sucesso {
            self.requisicoes_erro.fetch_add(1, Ordering::Relaxed);
        }
    }

    fn snapshot(&self) -> (u64, u64, u64) {
        (
            self.requisicoes_total.load(Ordering::Relaxed),
            self.requisicoes_erro.load(Ordering::Relaxed),
            self.bytes_processados.load(Ordering::Relaxed),
        )
    }
}

// Processamento paralelo com Rayon
// use rayon::prelude::*;
//
// fn processar_paralelo(dados: &mut [f64]) {
//     dados.par_iter_mut().for_each(|x| {
//         *x = (*x * 2.0).sin().abs();
//     });
// }
//
// fn soma_paralela(dados: &[f64]) -> f64 {
//     dados.par_iter().sum()
// }

Checklist dos Meses 23-26

  • Faz profiling com perf, flamegraph e cachegrind
  • Escreve benchmarks com Criterion
  • Minimiza alocações usando Cow, SmallVec, arenas
  • Entende layout de memória e otimização de cache
  • Sabe usar Rayon para paralelismo de dados
  • Usa operações atômicas lock-free quando apropriado
  • Aplica otimizações de compilação (LTO, PGO, target-cpu)

Meses 27-30: Arquitetura e Liderança Técnica

Arquitetura para Grandes Codebases Rust

Princípios de organização:

empresa-plataforma/
├── Cargo.toml                  # workspace root
├── crates/
│   ├── proto/                  # definições de protocolo (protobuf/gRPC)
│   ├── domain/                 # tipos de domínio e regras de negócio
│   ├── storage/                # abstração de persistência
│   │   ├── storage-core/       # traits e interfaces
│   │   ├── storage-postgres/   # implementação PostgreSQL
│   │   └── storage-redis/      # implementação Redis
│   ├── service-auth/           # microsserviço de autenticação
│   ├── service-orders/         # microsserviço de pedidos
│   ├── service-payments/       # microsserviço de pagamentos
│   ├── gateway/                # API gateway
│   └── common/
│       ├── config/             # configuração centralizada
│       ├── telemetry/          # logging, métricas, tracing
│       ├── error/              # tipos de erro compartilhados
│       └── testing/            # utilitários de teste
├── tools/                      # ferramentas de desenvolvimento
│   ├── migrate/                # ferramenta de migração
│   └── seed/                   # dados de teste
└── deploy/                     # configuração de deploy

Estratégias para manter a qualidade:

  1. Feature flags em compile time: use features do Cargo para habilitar/desabilitar funcionalidades
  2. Testes em camadas: unitários rápidos, integração em CI, E2E antes de deploy
  3. Documentação arquitetural: ADRs (Architecture Decision Records) para decisões importantes
  4. Padronização: clippy, rustfmt, e lints customizados para toda a equipe
# .cargo/config.toml compartilhado pelo time
[build]
rustflags = [
    "-D", "warnings",
    "-W", "clippy::pedantic",
    "-W", "clippy::nursery",
    "-A", "clippy::module_name_repetitions",
]

[alias]
ci = "clippy --all-targets --all-features -- -D warnings"

Liderança Técnica e Mentoria

Um sênior não é apenas um programador melhor; é alguém que multiplica a efetividade de toda a equipe.

Habilidades de liderança técnica:

  1. Definir padrões: estabelecer convenções de código, padrões de review e processos
  2. Tomar decisões: avaliar trade-offs e escolher soluções adequadas ao contexto
  3. Comunicar: explicar decisões técnicas para stakeholders não-técnicos
  4. Mentorar: identificar gaps de conhecimento e criar planos de desenvolvimento
  5. Desbloquear: remover impedimentos técnicos para a equipe

Conduzindo code reviews eficazes:

## Checklist de Review para Código Rust

### Correção
- [ ] O código faz o que deveria?
- [ ] Todos os edge cases são tratados?
- [ ] Erros são propagados corretamente?

### Segurança
- [ ] Unsafe está minimizado e documentado com SAFETY?
- [ ] Sem race conditions ou data races?
- [ ] Input validation adequada?

### Performance
- [ ] Alocações desnecessárias?
- [ ] Clones que poderiam ser referências?
- [ ] Algoritmo adequado para o tamanho dos dados?

### Manutenabilidade
- [ ] Código auto-documentado com nomes descritivos?
- [ ] Testes adequados?
- [ ] Documentação atualizada?

Mentoring de desenvolvedores Rust:

Nível do MentoradoFoco da MentoriaAbordagem
InicianteOwnership, borrowing, erros do compiladorPair programming, exercícios guiados
JúniorPadrões idiomáticos, design de códigoCode review detalhado, projetos com coaching
PlenoArquitetura, performance, liderançaDiscussões de design, delegação de decisões

Tomada de Decisão Técnica

Como sênior, você frequentemente precisa decidir entre múltiplas abordagens. Use um framework estruturado:

## ADR-001: Escolha do framework web

### Contexto
Precisamos de um framework web para nosso novo serviço de API.

### Opções Consideradas

| Critério | Axum | Actix-web | Rocket |
|----------|------|-----------|--------|
| Performance | Excelente | Excelente | Boa |
| Ecossistema Tower | Nativo | Parcial | Não |
| Facilidade de teste | Alta | Média | Média |
| Comunidade | Grande e crescente | Grande | Média |
| Compatibilidade Tokio | Nativa | Próprio runtime | Tokio |

### Decisão
Escolhemos Axum pelos seguintes motivos:
1. Integração nativa com o ecossistema Tower
2. Melhor testabilidade através de extractors
3. Alinhamento com a direção do ecossistema async Rust

### Consequências
- Time precisa aprender Tower middleware
- Migramos endpoints existentes de Actix gradualmente

Checklist dos Meses 27-30

  • Projeta arquitetura de workspace multi-crate
  • Estabelece padrões de código e processos para o time
  • Conduz code reviews focados em qualidade e crescimento
  • Toma decisões técnicas documentadas com ADRs
  • Mentora pelo menos 1 desenvolvedor mais junior
  • Sabe quando dizer “não” para complexidade desnecessária

Meses 31-36: Contribuição Core e Influência no Ecossistema

Contribuindo para o Compilador Rust

Contribuir para o compilador ou para a biblioteca padrão é o ápice da expertise em Rust.

Como começar:

  1. Leia o Rustc Dev Guide (rustc-dev-guide.rust-lang.org)
  2. Configure o ambiente: clone e compile o rustc
  3. Comece por issues E-easy no repositório rust-lang/rust
  4. Participe do Zulip (#t-compiler, #t-libs)
# Configurando o ambiente para contribuir com rustc
git clone https://github.com/rust-lang/rust.git
cd rust
cp config.example.toml config.toml

# Edite config.toml para configurar:
# [llvm]
# download-ci-llvm = true  # Baixa LLVM pré-compilado (muito mais rápido)
#
# [rust]
# debug = true
# incremental = true

# Compilar
./x.py build library
./x.py test library/std

Áreas para contribuir:

ÁreaComplexidadeImpacto
Mensagens de erroMédiaAlto
Documentação da stdBaixaAlto
Diagnósticos do compiladorMédiaAlto
Clippy lintsMédiaMédio
Otimizações MIRAltaAlto
Novos featuresMuito altaMuito alto

Escrevendo RFCs e Documentos de Design

RFCs (Request for Comments) são o processo pelo qual mudanças significativas no Rust são propostas e discutidas.

Estrutura de um RFC:

- Feature Name: meu_feature
- Start Date: 2026-02-27
- RFC PR: (preenchido depois)
- Rust Issue: (preenchido depois)

# Resumo
Uma explicação de um parágrafo do feature proposto.

# Motivação
Por que estamos fazendo isso? Quais casos de uso ele suporta?
Qual é o resultado esperado?

# Guia de Referência
Explique o feature como se estivesse ensinando para outro
desenvolvedor Rust. Use exemplos de código.

# Referência Detalhada
Especificação técnica precisa.

# Desvantagens
Por que NÃO deveríamos fazer isso?

# Alternativas
Que outros designs foram considerados e por que não foram escolhidos?

# Questões Não Resolvidas
Pontos que precisam ser esclarecidos durante o processo de RFC.

# Trabalho Futuro
Extensões possíveis que não fazem parte desta proposta.

Construindo e Mantendo Crates

Publicar e manter crates de qualidade é uma forma poderosa de contribuir para o ecossistema.

Checklist para publicar uma crate:

# Cargo.toml completo para publicação
[package]
name = "minha-crate"
version = "0.1.0"
edition = "2021"
rust-version = "1.70"
authors = ["Seu Nome <email@exemplo.com>"]
description = "Descrição concisa da funcionalidade"
documentation = "https://docs.rs/minha-crate"
repository = "https://github.com/usuario/minha-crate"
license = "MIT OR Apache-2.0"
keywords = ["keyword1", "keyword2", "keyword3"]
categories = ["development-tools"]
readme = "README.md"
exclude = ["tests/fixtures/*", ".github/*"]

[badges]
maintenance = { status = "actively-developed" }

Boas práticas de manutenção:

  1. Versionamento semântico rigoroso: breaking changes apenas em major versions
  2. CHANGELOG.md: documente todas as mudanças
  3. CI abrangente: testes em múltiplas versões do Rust, MSRV verificado
  4. Documentação exemplar: exemplos em cada função pública, guia de uso no README
  5. Responda issues e PRs: uma comunidade ativa atrai mais contribuidores
  6. Política de deprecação: avise antes de remover APIs
# GitHub Actions CI para crate
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        rust: [stable, beta, nightly, "1.70"]
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ matrix.rust }}
      - run: cargo test --all-features
      - run: cargo clippy -- -D warnings
      - run: cargo doc --no-deps

Checklist dos Meses 31-36

  • Contribuiu para o compilador Rust ou biblioteca padrão
  • Participou de discussões em RFCs ou Zulip
  • Publicou e mantém pelo menos 1 crate no crates.io
  • Escreveu documentação ou blog posts técnicos sobre Rust
  • Apresentou em conferência ou meetup sobre temas avançados
  • É reconhecido como referência pela comunidade

Recursos para o Nível Sênior

Leitura Essencial

RecursoFoco
RustonomiconUnsafe Rust em profundidade
Rust ReferenceEspecificação da linguagem
Rustc Dev GuideInternals do compilador
The Unstable BookFeatures nightly
Rust Performance BookOtimização
Crust of Rust (Jon Gjengset)Temas avançados em vídeo
“Rust for Rustaceans” (Jon Gjengset)Livro para níveis intermediário/avançado

Conferências e Talks

  • RustConf: conferência oficial anual
  • Rust Nation UK: conferência europeia
  • EuroRust: comunidade europeia
  • RustLab: conferência italiana
  • Talks essenciais: pesquise por talks de Niko Matsakis, Aaron Turon, Without Boats, Mara Bos

Comunidades Avançadas

  • Rust Zulip: discussões sobre o desenvolvimento do Rust
  • IRLO (Internals): fórum de discussão interna
  • r/rust: subreddit com discussões técnicas
  • This Week in Rust: newsletter semanal
  • Rust Blog: anúncios oficiais

Checklist Final: Critérios de Senioridade

Profundidade Técnica

  • Unsafe Rust com encapsulamento seguro e documentação SAFETY
  • FFI bidirecional com C/C++
  • Otimização de performance baseada em profiling
  • Entendimento de internals do compilador (MIR, monomorphization, etc.)
  • Macro procedurais para geração de código
  • Concorrência lock-free e algoritmos paralelos

Liderança e Impacto

  • Projeta arquitetura de sistemas complexos
  • Toma decisões técnicas que consideram o contexto do negócio
  • Mentora outros desenvolvedores efetivamente
  • Contribui para o ecossistema Rust (crates, compilador, documentação)
  • É reconhecido como referência técnica dentro e fora da empresa

Comunicação

  • Escreve documentação técnica clara e acessível
  • Apresenta temas complexos de forma compreensível
  • Conduz discussions de design que levam a decisões produtivas
  • Participa ativamente de code reviews com foco no crescimento

Considerações Finais

O nível sênior não é um destino; é um patamar de responsabilidade e influência que se mantém através de aprendizado contínuo. A tecnologia evolui, o Rust evolui, e os desafios que enfrentamos evoluem junto.

O que diferencia um verdadeiro sênior é a combinação de profundidade técnica com habilidade de multiplicar o impacto da equipe. Não basta escrever código excelente; é preciso ajudar outros a escrever código excelente também.

O ecossistema Rust ainda é jovem comparado a linguagens como C++ ou Java. Isso significa que há oportunidades enormes para quem quer deixar sua marca. Seja contribuindo para o compilador, publicando crates essenciais, mentorando a próxima geração de Rustaceans, ou construindo sistemas que demonstram o potencial da linguagem.

A jornada é longa, mas vale cada passo. O Rust não é apenas uma linguagem de programação; é uma comunidade de pessoas que acreditam que podemos fazer software melhor, mais seguro e mais confiável. Ao atingir o nível sênior, você passa a ser parte ativa dessa missão.

Continue construindo. Continue ensinando. Continue evoluindo.