Imports & Dependencies

code specs/code/imports.kmd

Padrão cross-language pra organização de imports/use/require: ordem canônica (stdlib → third-party → local), grouping por origem com linha em branco, aliasing convention (canônicos `np`, `pd`, `tf`), wildcard imports proibidos por default, ciclos proibidos, re-export patterns (prelude/index/lib.rs), side-effect imports documentados via comentário.

When this spec applies

Primary triggers

All triggers

Specification body

Spec — Imports & Dependencies

Facet Code do Koder Design.

Estende code/languages/koda-style.kmd (que cobre só Koda) pra todas as linguagens da Stack.

R1 — Ordem canônica

Em toda linguagem, imports seguem a ordem:

  1. Stdlib (built-in da linguagem)
  2. Third-party (managed dependencies)
  3. Local (mesmo monorepo / mesmo módulo)

Separar grupos com uma linha em branco.

// ✅ Go
import (
    "context"
    "fmt"
    "io"

    "github.com/spf13/cobra"
    "go.uber.org/zap"

    "koder.dev/services/foundation/id"
    "koder.dev/services/foundation/jet"

    "./internal/handler"
)
# ✅ Python
import json
import os
import re
from typing import Optional

import requests
from pydantic import BaseModel

from koder.identity import Client
from koder.kompass import Workspace

from .helpers import format_email
from .models import User
// ✅ Rust
use std::collections::HashMap;
use std::fs;

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

use crate::config::Config;
use crate::handler::Handler;
// ✅ Dart
import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'package:koder_kit/koder_kit.dart';

import 'src/screens/home.dart';
// ✅ TypeScript
import { readFile } from 'node:fs/promises';
import path from 'node:path';

import express from 'express';
import { z } from 'zod';

import { KoderClient } from '@koder/sdk';

import { Handler } from './handler.js';
import { config } from './config.js';

R2 — Sub-grouping (Koder libs primeiro)

Dentro do grupo "third-party", separar Koder libs próprias das de terceiros — Koder primeiro:

# ✅ Sub-group Koder libs
import requests
from pydantic import BaseModel

from koder.identity import Client       # Koder libs primeiro
from koder.kompass import Workspace

(Refletindo o princípio policies/reuse-first.kmd — Koder libs são preferred sobre alternatives quando ambos servem.)

R3 — Ordem alfabética dentro do grupo

Imports alfabéticos dentro de cada grupo. Ferramentas como isort (Python), goimports (Go), dart format fazem isso automaticamente — configurar pra rodar no save.

R4 — Aliasing convention

Quando usar alias

  • Conflito de nomes entre módulos (from datetime import time as std_time vs from .util import time)
  • Aliases canônicos da comunidade (lista fechada — não inventar):
    • Python: import numpy as np, import pandas as pd, import tensorflow as tf, import matplotlib.pyplot as plt
    • JS/TS: imports default já fazem o aliasing (import React from 'react')
    • Rust: use foo::Long as Short quando o nome se repete muito
  • Path muito longo que prejudica leitura (use foo::bar::baz::Quux as Quux)

Quando NÃO usar alias

  • Por preferência pessoal sem motivo técnico
  • Pra "encurtar" sem ganho real (import os.path as p ❌)
  • Mascarando que é a mesma biblioteca (faz code review pior)

R5 — Wildcard imports — proibidos por default

# ❌ Polui namespace, quebra static analysis
from os import *
from .module import *
// ❌
use foo::*;
// ❌
import 'package:foo/foo.dart' show *;  // (não tem essa sintaxe; ilustração)

Exceção controlada: re-exports via prelude / index.ts / lib.rs de uma library que deliberadamente expõe um conjunto curado.

// ✅ Re-export deliberado em lib.rs
pub mod handler;
pub mod config;
pub use handler::Handler;
pub use config::Config;

// ✅ Consumer pode importar tudo dum pacote prelude
use koder::prelude::*;  // explicitamente curado pelo módulo upstream

R6 — Cyclic dependencies — proibidos

Módulo A não pode importar B se B importa A direto ou transitivamente.

Quebrar via:

  1. Extract common — mover o que ambos precisam pra terceiro módulo
  2. Inverter dependência — A define interface, B implementa, C compõe (Dependency Inversion Principle)
  3. Late-binding — passar callback/closure em vez de import direto

CI gate (per linguagem):

  • Go: gocyclo + goimports detectam
  • Python: pylint cycle detection
  • Rust: compiler já bloqueia naturalmente
  • Dart: dart analyze
  • JS/TS: madge --circular

R7 — Re-export patterns (per linguagem)

Linguagem Arquivo Padrão
Python __init__.py from .module import PublicAPI
Rust lib.rs / mod.rs pub use crate::module::PublicAPI;
TS index.ts export { PublicAPI } from './module.js';
Dart <package>.dart (entry) export 'src/module.dart' show PublicAPI;
Go (não tem; flat namespace) n/a — package é a unit de export

Princípio: re-export curado expõe API pública estável; user externo importa do entry point, não dos arquivos internos.

// ✅ Curado — public surface explícita
export 'src/sign_in_button.dart' show KoderSignInButton;
export 'src/user_badge.dart' show KoderUserBadge;
// src/internal_helper.dart não exportado — interno

R8 — Side-effect imports

Quando import existe apenas pelo side effect (não usa o nome importado), documentar com comentário:

// ✅
import (
    _ "github.com/lib/pq"  // register postgres driver with database/sql
)
// ✅
import 'normalize.css';  // CSS reset; no JS exports consumed
import './polyfills.js'; // patch globals before app boots

Linter falha se import sem uso e sem comentário.

R9 — Conditional imports

Casos onde import depende de plataforma ou flag:

Linguagem Padrão
Python if sys.platform == 'darwin': import macos_module
Dart import 'foo_io.dart' if (dart.library.html) 'foo_html.dart'
Rust #[cfg(target_os = "linux")] use linux_specific;
Go Build tags em arquivo separado (foo_linux.go)

Documentar com comentário quando não-óbvio.

Anti-patterns

AP-I1 — Import everything from a module

# ❌
from numpy import *

# ✅
import numpy as np
result = np.array([1, 2, 3])

AP-I2 — Imports embaralhados

# ❌ Sem ordem nem grouping
from .helpers import foo
import os
from koder.id import Client
import json

Ferramenta auto-formata; não é decisão do dev.

AP-I3 — Import dentro de função (sem motivo)

# ❌ Sem motivo
def handler():
    import json
    ...

# ✅ Top-of-file
import json

def handler():
    ...

Exceção: lazy import pra evitar circular ou heavy-weight (com comment).

AP-I4 — Re-export sem curadoria

// ❌ Re-exporta tudo, incluindo internals
pub use crate::*;

// ✅ Curado
pub use crate::handler::{Handler, HandlerError};
pub use crate::config::Config;

Audit deterministic

imports-audit.sh:

  1. Imports não em ordem canônica → warning (auto-fix possível)
  2. Wildcard import sem comment justificando → error
  3. Cyclic dependency detected → error (per linguagem tool)
  4. Side-effect import sem comment → warning
  5. Import dentro de função sem comment → warning
  • code/project-layout.kmd — paths refletem layout
  • code/naming.kmd — package/module naming
  • code/languages/koda-style.kmd — Koda specific
  • policies/reuse-first.kmd — Koder libs preferred

References