Pular para o conteúdo principal

Módulos & Imports

Cada linguagem tem sua própria forma de organizar código em módulos e importar funcionalidades. Veja como diferentes linguagens lidam com a organização de código.

Importando Módulos​

// ES Modules (modern)
import { readFile } from 'fs';
import express from 'express';
import * as path from 'path';
import { useState as useS } from 'react'; // alias

// Default import
import MyComponent from './MyComponent';

// Dynamic import
const module = await import('./module.js');

// CommonJS (Node.js legacy)
const fs = require('fs');
const { join } = require('path');

Exportando / Criando Módulos​

// ES Module exports
// Named exports
export function greet(name) { return "Hello " + name; }
export const PI = 3.14;
export class User { }

// Default export
export default class App { }

// Re-export
export { greet } from './utils.js';
export * from './helpers.js';

// CommonJS exports
module.exports = { greet, PI };
module.exports.greet = greet;

// package.json
// { "type": "module" } // Enable ES modules

Principais Conclusões​

  • Sistemas de módulos variam de simples a rigorosos -- C usa #include (inclusão textual de headers), JavaScript e Python permitem sintaxe flexível de import/from, enquanto Java 9+ (module-info.java) e Rust (Cargo.toml + declarações mod) exigem manifestos explícitos de módulos. A abordagem mais rigorosa previne acoplamento acidental e torna as dependências rastreáveis em tempo de build. Escolha C/JavaScript/Python se quiser iteração rápida e cerimônia mínima; escolha Java/Rust se precisar de encapsulamento forte e builds reproduzíveis.

  • Visibilidade é controlada de formas diferentes -- Go usa convenção de nomenclatura: type User é exportado, type user não é. Rust e Swift usam palavras-chave: pub fn vs fn, public class vs internal class. Java e C# oferecem controle granular com public, private, protected e escopos de pacote/internal. A abordagem por nomenclatura (Go) mantém o código mínimo mas pode surpreender iniciantes; modificadores explícitos (Java, C#) tornam a intenção clara. Prefira modificadores explícitos ao construir bibliotecas grandes; a convenção do Go funciona bem para bases de código menores e coesas.

  • O mapeamento arquivo-módulo difere -- Python mapeia pacotes para diretórios via __init__.py (ex.: mypackage/models.py → from mypackage.models import User). Rust mapeia mod models para models.rs ou models/mod.rs. Go vincula pacotes a diretórios: package models em models/user.go. C e C++ não têm mapeamento embutido—você inclui manualmente #include "path/to/header.h". Diretório-como-módulo (Python, Go) reduz boilerplate; mod explícito (Rust) dá mais controle sobre o que é exposto. Para projetos novos, prefira mapeamento baseado em diretório; para bases de código C/C++ legadas, caminhos de header são a norma.

  • Imports condicionais e dinâmicos variam -- JavaScript suporta import('./module.js') dinâmico para code-splitting e carregamento lazy. Python usa try: import ujson except ImportError: import json para dependências opcionais. Swift usa #if canImport(UIKit) para código específico de plataforma (iOS vs macOS). Esses padrões importam ao direcionar múltiplas plataformas ou quando dependências são opcionais. Use imports dinâmicos quando os bundles precisam ficar pequenos; use imports condicionais quando precisar de implementações específicas por plataforma.

  • Re-exports permitem APIs mais limpas -- O pub use crate::models::User do Rust re-exporta de um submódulo. O export { greet } from './utils.js' e export * from './helpers.js' do JavaScript permitem agregar exports. O __all__ = ['User', 'helper'] do Python controla o que from package import * expõe. Re-exports permitem reestruturar internos sem quebrar consumidores. Use-os ao construir uma superfície de API pública—ex.: uma biblioteca que expõe alguns tipos-chave de módulos aninhados—para que consumidores importem de um só lugar em vez de caminhos profundos.