Skip to content
mobius1qwe edited this page Oct 24, 2026 · 5 revisions

Padrão de Código

Home > Guia de contribuição do PascalRAL > Padrão de Código

  • Todas as units precisam ser concisas e referenciar um escopo, não existe necessidade de ter uma unit pra cada classe.

  • Os uses são organizados por grupo de escopo, seguindo as condições:

    • Diretivas de compilação: caso a unit dependa de outra baseada em uma condição específica, essas diretivas sempre vêm primeiro na seção uses. Caso a diretiva seja usada, precisa importar a PascalRAL.inc que contém o mapeamento das diretivas mais comuns. Caso a diretiva que você precisa não esteja inclusa lá, defina lá para usar na classe, garantindo que não seja uma redundância de outra diretiva existente.
    • Units nativas da IDE: dependências presentes em todas as IDEs, tais como Classes, SysUtils, System...
    • Units da dependência: units necessárias da dependência. Ex: ZQuery, ZComponent...
    • Units do projeto: units presentes nos fontes do projeto RAL. Ex: RALTools, RALTypes...
  • Tudo é documentado: unit, classe, record, enum, tipo de evento, constante, rotina e cada membro de classe, privados inclusive. A documentação é em Inglês americano enUS, veja Documentação no código.

  • As seções internas das classes são organizadas em:

      1. Private
      1. Protected
      1. Public
      1. Published

    Não informar a seção caso não precise dela

  • Dentro de cada seção, os atributos e métodos são classificados em ordem alfabética seguindo a ordem:

      1. Atributos internos: variáveis ou constantes
      1. Método constructor
      1. Método destructor
      1. Métodos: procedure ou function, a palavra reservada não influencia na ordem alfabética
      1. Eventos: métodos que começam com “On”
      1. Atributos publicados, property

    Diretiva de compilação ({$IFDEF}, {$ENDIF}...) não se move: a ordem vale dentro de cada trecho entre duas diretivas, e nenhum membro entra ou sai de um {$IFDEF}. Enumerados, sets, constantes inicializadas e records não são reordenados.

  • A Identação padrão é a mesma definida pela IDE Delphi ou Lazarus com as seguintes alterações:

    • Margem direita 90
    • Diretivas seguem identação
  • As units devem ser salvas seguindo o padrão de nomenclatura do projeto: RAL + escopo da unit, por exemplo: RALClient. Dentro da pasta relativa ao escopo de projeto, como base, utils, database…

  • Os escopos de projeto atuais são:

    • Base = pasta que contém as units referentes ao funcionamento mínimo do pacote e são obrigatórias na compilação para o pacote-base funcionar.
    • Utils = pasta que contém funções diversas, mapeadores e demais métodos que são utilizados por várias outras units.
    • Database = pasta que contém todas as units referentes ao tráfego de informações DBWare.
  • Caso o código seja para um pacote diferente, precisa ficar contido no escopo de projeto relacionado a ele, por exemplo um motor de dados possui os arquivos de projeto .dpk dentro de \pkg\<IDE> e as units ficam em \src\engine\<motor>. Basta seguir esse modelo ou entrar em contato seja abrindo uma issue de dúvida, ou uma discussão no GitHub, ou acessando o grupo de suporte do componente.

  • Na 2.0 🚧 as regras de pasta e de pacote são estas (a troca de cada nome está em Migrar para a 2.0):

    • Uma pasta pertence a um pacote só. src\core, common, compress, crypto e plugins são do PascalRAL; src\design é do PascalRALDsgn; cada pacote opcional tem a sua (src\plugins\auth, src\storage, src\modules\web, src\engine\indy...). A exceção é src\others, que guarda só os submódulos (ZSTD, pascal_brotli, kxBSON) e nenhuma unit do RAL.
    • As units de design ficam numa subpasta design do recurso (src\database\design, src\modules\soap\design). Não é enfeite: o lazbuild -B compila de novo, dentro do pacote de design, toda unit de runtime que achar na mesma pasta.
    • Nomes de pacote: PascalRAL e PascalRALDsgn (os obrigatórios, na raiz de pkg\<IDE>); motores <Motor>RAL (IndyRAL), de propósito, para lembrar que é preciso um motor; o resto RAL<Categoria><Item>Package e RAL<Categoria><Item>Dsgn (RALPluginAuthPackage, RALDBFireDACPackage + RALDBFireDACDsgn). No Lazarus, os mesmos nomes em minúsculas.
    • Nenhuma unit termina em Package, Dsgn ou RAL, para um pacote nunca ter o nome de uma unit. A unit que registra componentes é RAL<item>Reg (a do núcleo é RALRegister).
    • Runtime e design separados: os ...Dsgn são {$DESIGNONLY} (DesignTime no Lazarus); um pacote que só registra componentes é de runtime e design e exige o PascalRAL, nunca o PascalRALDsgn.
    • O PascalRAL.inc entra por caminho relativo ({$I ..\core\PascalRAL.inc}, na profundidade da unit), sem include path.
/// Unit that represents the code that complies with documentation for contributors.
unit RALExample;

{$I PascalRAL.inc} // necessary since there's a conditional directive below

interface

uses
  {$IFDEF RALWindows} Windows, {$ENDIF}
  Classes, SysUtils;

type
  /// Example that follows the documentation as a guideline for contributors.
  TMyExample = class
  private
    FSomething: sometype;
  public
    constructor Create;
    destructor Destroy; override;
    /// Returns something.
    function GetSomething: sometype;
    { Defines something. A description that does not fit in one line
      goes in braces. }
    procedure SetSomething(AParam: sometype);
    /// Event to be called during something.
    procedure OnSomething(AParam: sometype);

    /// Something the example keeps.
    property Something: sometype read GetSomething write SetSomething;
  end;

implementation
[...]

end.

Documentação no código

A descrição é o que aparece no autocomplete e no hint do Delphi e do Lazarus, e é dela que o pasdoc gera a documentação da API. Por isso ela é curta.

  • Uma linha (cabe em 90 colunas com a indentação): /// Texto.
  • Mais de uma linha: chaves. O texto começa depois de { , as linhas seguintes ficam alinhadas com ele e o } fecha na última linha. Duas ou três linhas no máximo.
  • O comentário fica colado na declaração, sem linha em branco no meio.
  • Inglês americano, tempo presente. A primeira frase é o resumo e fecha com ponto.
  • Diz o que a coisa é ou faz e o que quem usa precisa saber: unidade e valor padrão ("milliseconds; 0 = no limit"), o que nil ou vazio significa, quando levanta exceção, em que thread um evento roda, restrição de plataforma ou de motor.
  • Não diz: histórico ("used to", "antes era", datas), referência a plano ou etapa, números de medição, alternativa descartada, comparação com outro motor. O git guarda a história.
  • Explicação longa vai para a wiki: o "porquê" de uma decisão e as armadilhas de cada motor ficam nas páginas de internos, não no código.
  • Cada membro tem a sua descrição; comentário de grupo sobre vários campos não vale.
  • Ficam sem descrição só: Create/Destroy sem parâmetro que precise de explicação, override que não muda o contrato do ancestral, e o campo, o getter e o setter de uma propriedade documentada.
  • Enumerados, sets e constantes inicializadas ganham a descrição antes da declaração, que não muda de forma.
  • Diretiva de compilação não é comentário: {$IFDEF} é código.
  • Sem crase e sem lista "- item" dentro do comentário (o pasdoc mostra literal). Identificador escrito puro (TRALServer.SSL) vira link sozinho. Um @ literal é @@, porque @ abre as tags do pasdoc (@code(...), @param, @raises, @deprecated...).
  • Dentro de { } nunca entra } nem {, e o texto nunca começa com $ (viraria diretiva).
  • Comentário dentro de método (// ou { }) só quando o código não se explica: um invariante, uma ordem obrigatória, uma referência de protocolo. Uma ou duas linhas, no presente. Código comentado não fica.
  { Accepted server certificates (SHA-256), one per line: "fp" for any host,
    "host=fp" or "host:port=fp" for one server. }
  property Pins: TStrings read GetPins write SetPins;
  /// Refuses to send anything over plain http, whatever the URL says.
  property Required: boolean read FRequired write FRequired default False;

Mensagem de commit

O CHANGELOG.md é gerado sozinho a partir das mensagens de commit, então o assunto do commit é a nota de versão que o usuário vai ler. Escreva em inglês, dizendo o que muda para quem usa.

A seção do changelog é escolhida pela primeira palavra-chave encontrada no assunto e no corpo, nesta ordem:

Ordem Palavras (em qualquer lugar da mensagem) Seção
1 security, vulnerability, cve, exploit Security
2 breaking change, breaking:, break: Breaking Changes
3 deprecat, obsolete, phase out Deprecated
4 remove, delete, drop, eliminate Removed
5 add, new, create, implement, feat Added
6 fix, resolve, correct, patch, bug, issue Fixed
7 chore, chr (fora das notas)
— nenhuma Changed

Duas pegadinhas:

  • remove vem antes de add: um commit de recurso novo cujo corpo diz "removes the old check" cai em Removed. Escolha a seção e evite no texto as palavras das seções anteriores.
  • As palavras são em inglês: "Adicionado..." não tem add e cai em Changed.

Commits com [skip ci] ou docs: update changelog ficam de fora.

Exemplos:

Add PBKDF2 key derivation for the AES body cipher
Fix the fpHTTP client writing requests into closed connections
Breaking change: CORS lets no origin in by default

Clone this wiki locally