Inhaltsverzeichnis

Code-Konventionen

Verbindliche Coding-Standards für die WvdS FPC RAD Suite.

Namenskonventionen

Typen

Kategorie Präfix Beispiel
Klasse TWvdS* TWvdSBuildConfig, TWvdSProjectManager
Interface IWvdS* IWvdSLogger, IWvdSParser
Record TWvdS* TWvdSBuildResult, TWvdSToolPath
Enum TWvdS* TWvdSProjectType, TWvdSBuildStatus
Exception EWvdS* EWvdSFileNotFound, EWvdSParseError
Callback TWvdS* TWvdSBuildCallback, TWvdSProgressHandler
Externe API-Typen (VSCode, Node.js) behalten ihre originalen Namen.

Unit-Namen

Microsoft-Stil Namespaces mit WvdS-Präfix:

WvdS.{Domain}.{Layer}.pas

Beispiele:
WvdS.Build.Models.pas
WvdS.Build.Service.pas
WvdS.Projects.SettingsDialog.pas
WvdS.VSCode.Commands.pas

Layer-Suffixe

Suffix Inhalt Beispiel
.Models Records, Enums, Typen WvdS.Build.Models
.Service Geschäftslogik WvdS.Build.Service
.Dialog WebView-Dialoge WvdS.Projects.SettingsDialog
.Provider VSCode API Wrapper WvdS.Designer.EditorProvider

Variablen und Parameter

Kategorie Präfix Beispiel
Private Felder F FProjectPath, FConfig
Parameter A APath, AOptions, ACallback
Lokale Variablen Kein Result, I, Config

Resourcestrings

Präfix nach Feature:

Präfix Feature
rsCore* Core Extension
rsBuild* Build Extension
rsProject* Projects Extension
rsDesigner* UI Designer
rsPreview* UI Preview
rsMeta* UI Meta
rsPackaging* Packaging
rsTool* Toolchain

Code-Struktur

Unit-Aufbau

unit WvdS.{Feature}.{Layer};
 
{$mode objfpc}{$H+}
 
interface
 
uses
  // 1. System Units
  SysUtils, Classes,
  // 2. WvdS Common
  WvdS.System, WvdS.Collections,
  // 3. Feature-spezifisch
  WvdS.{Feature}.Models;
 
type
  // Typ-Definitionen
 
function PublicFunction(const AParam: string): Boolean;
procedure PublicProcedure(AValue: Integer);
 
implementation
 
uses
  // Private Uses (nur hier benötigte Units)
  WvdS.VSCode.Strings;
 
// Private Typen und Variablen
type
  TInternalHelper = class
  end;
 
var
  InternalState: TObject;
 
// Implementierungen
 
function PublicFunction(const AParam: string): Boolean;
begin
  // ...
end;
 
procedure PublicProcedure(AValue: Integer);
begin
  // ...
end;
 
initialization
  // Initialisierung
 
finalization
  // Aufräumen
 
end.

Klassen-Aufbau

type
  TWvdSExampleClass = class(TObject)
  private
    FName: string;
    FValue: Integer;
    procedure SetName(const AValue: string);
  protected
    procedure DoInternalWork; virtual;
  public
    constructor Create(const AName: string);
    destructor Destroy; override;
    procedure Execute;
    property Name: string read FName write SetName;
    property Value: Integer read FValue write FValue;
  end;

Dokumentation

PasDoc-Format

(*
  @abstract(Kurze Beschreibung in einem Satz.)
 
  Ausführliche Beschreibung des Zwecks und der Verwendung.
  Kann mehrere Sätze umfassen.
 
  @param(APath Vollständiger Pfad zur Datei)
  @param(AOptions Optionale Konfiguration, kann nil sein)
  @returns(True wenn erfolgreich, False bei Fehler)
 
  @raises(EWvdSFileNotFound wenn Datei nicht existiert)
  @raises(EWvdSAccessDenied wenn keine Leserechte)
 
  Security:
    - CWE-22: Pfad wird gegen Path Traversal validiert
 
  @seealso(RelatedFunction)
  @seealso(TWvdSRelatedClass)
*)
function ProcessFile(const APath: string; AOptions: TOptions): Boolean;

Inline-Kommentare

// Kurzer Kommentar für einzelne Zeile
Result := CalculateValue;
 
// Mehrzeiliger Kommentar für komplexere Logik
// Erklärt den Grund, nicht das Was
if (Value > Threshold) and (Mode = mAdvanced) then
begin
  // Wir müssen hier den erweiterten Algorithmus verwenden,
  // da der einfache bei großen Werten ungenau wird
  Result := AdvancedCalculation(Value);
end;

Konstanten statt Magic Numbers

// VERBOTEN
if Length(Name) > 64 then
if Timeout > 30000 then
 
// KORREKT
const
  MAX_PROJECT_NAME_LENGTH = 64;
  DEFAULT_TIMEOUT_MS = 30000;
 
if Length(Name) > MAX_PROJECT_NAME_LENGTH then
if Timeout > DEFAULT_TIMEOUT_MS then

Terminologie

Konsistente Begriffe verwenden:

Verwende Vermeide
Path Url, Location, Dir (inkonsistent)
Config Settings, Options, Prefs (inkonsistent)
Create Make, Build (für Objekte)
Generate Create (für Ausgabe)
Validate Check, Verify (für Eingaben)
Initialize Setup, Init (inkonsistent)
Execute Run, Process (inkonsistent)

Formatierung

Einrückung

// KORREKT
procedure Example;
begin
  if Condition then
  begin
    DoSomething;
    DoMore;
  end
  else
  begin
    DoAlternative;
  end;
end;
 
// VERBOTEN
procedure Example; begin
  if Condition then begin DoSomething; DoMore; end
  else DoAlternative;
end;

Zeilenlänge

// Bei langen Parameterlisten
function VeryLongFunctionName(
  const AFirstParameter: string;
  const ASecondParameter: Integer;
  AThirdParameter: TOptions
): Boolean;
 
// Bei langen Bedingungen
if (FirstCondition) and
   (SecondCondition) and
   (ThirdCondition) then
begin
  // ...
end;

Verbotene Patterns

Leere Exception-Handler

// VERBOTEN
try
  DoSomething;
except
  // Nichts tun - Fehler verschlucken!
end;
 
// KORREKT
try
  DoSomething;
except
  on E: Exception do
    LogError(rsUnexpectedError, [E.ClassName, E.Message]);
end;

TODO/FIXME im Produktionscode

// VERBOTEN in main-Branch
// TODO: Implement this later
// FIXME: This is broken
 
// ERLAUBT nur in Feature-Branches, muß vor Merge entfernt werden

Hardcodierte Strings

// VERBOTEN
ShowMessage('File not found');
ShowMessage('Datei nicht gefunden');
 
// KORREKT
ShowMessage(rsFileNotFound);  // resourcestring

Globale Variablen in Services

// VERBOTEN
var
  GlobalConfig: TConfig;  // Schwer testbar!
 
// KORREKT - Parameter übergeben
function ProcessWithConfig(const AConfig: TConfig): Boolean;

Testbarkeit

Services müssen ohne VSCode/UI testbar sein:

// VERBOTEN - UI in Service
procedure ValidateAndShowError(const AName: string);
begin
  if not IsValid(AName) then
    ShowMessage('Invalid name');  // UI-Abhängigkeit!
end;
 
// KORREKT - Rückgabewert
function ValidateName(const AName: string; out AError: string): Boolean;
begin
  Result := IsValid(AName);
  if not Result then
    AError := rsInvalidName;
end;

pas2js Kompatibilität (WICHTIG)

pas2js ist NICHT 100% kompatibel mit FPC! Diese Einschränkungen MÜSSEN beachtet werden.

Nicht unterstützte Features

Feature FPC pas2js Workaround
class var Unit-Level Variable verwenden
Inline var Im var-Block deklarieren
Int64 Integer verwenden