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íodo | Foco | Resultado Esperado |
|---|---|---|
| Meses 19-22 | Unsafe Rust, FFI e internals | Entender Rust em nível profundo |
| Meses 23-26 | Performance e otimização | Extrair máxima performance do hardware |
| Meses 27-30 | Arquitetura e liderança | Projetar e liderar sistemas complexos |
| Meses 31-36 | Contribuição core e influência | Impactar 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:
- Derreferenciar ponteiros brutos (
*const T,*mut T) - Chamar funções ou métodos unsafe
- Acessar ou modificar variáveis estáticas mutáveis
- Implementar traits unsafe
- 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:
- Minimize a superfície unsafe: encapsule unsafe em funções com interface safe
- Documente invariantes: explique em comentários
// SAFETY:por que o unsafe é correto - Teste exaustivamente: use Miri para detectar undefined behavior
- 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:
| Ferramenta | Uso |
|---|---|
cargo-expand | Visualizar macros expandidas |
cargo-asm | Visualizar assembly gerado |
cargo-llvm-lines | Contar 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:
- Feature flags em compile time: use features do Cargo para habilitar/desabilitar funcionalidades
- Testes em camadas: unitários rápidos, integração em CI, E2E antes de deploy
- Documentação arquitetural: ADRs (Architecture Decision Records) para decisões importantes
- 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:
- Definir padrões: estabelecer convenções de código, padrões de review e processos
- Tomar decisões: avaliar trade-offs e escolher soluções adequadas ao contexto
- Comunicar: explicar decisões técnicas para stakeholders não-técnicos
- Mentorar: identificar gaps de conhecimento e criar planos de desenvolvimento
- 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 Mentorado | Foco da Mentoria | Abordagem |
|---|---|---|
| Iniciante | Ownership, borrowing, erros do compilador | Pair programming, exercícios guiados |
| Júnior | Padrões idiomáticos, design de código | Code review detalhado, projetos com coaching |
| Pleno | Arquitetura, performance, liderança | Discussõ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:
- Leia o Rustc Dev Guide (rustc-dev-guide.rust-lang.org)
- Configure o ambiente: clone e compile o rustc
- Comece por issues E-easy no repositório rust-lang/rust
- 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:
| Área | Complexidade | Impacto |
|---|---|---|
| Mensagens de erro | Média | Alto |
| Documentação da std | Baixa | Alto |
| Diagnósticos do compilador | Média | Alto |
| Clippy lints | Média | Médio |
| Otimizações MIR | Alta | Alto |
| Novos features | Muito alta | Muito 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:
- Versionamento semântico rigoroso: breaking changes apenas em major versions
- CHANGELOG.md: documente todas as mudanças
- CI abrangente: testes em múltiplas versões do Rust, MSRV verificado
- Documentação exemplar: exemplos em cada função pública, guia de uso no README
- Responda issues e PRs: uma comunidade ativa atrai mais contribuidores
- 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
| Recurso | Foco |
|---|---|
| Rustonomicon | Unsafe Rust em profundidade |
| Rust Reference | Especificação da linguagem |
| Rustc Dev Guide | Internals do compilador |
| The Unstable Book | Features nightly |
| Rust Performance Book | Otimizaçã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.