Skip to content

RADProgrammer Style Guide Other Guidance

Darian Miller edited this page Dec 22, 2024 · 22 revisions

Always Use The Code Formatter

Ensure your new code has passed through the Automatic CodeFormatter with the RADProgrammer custom profile active before committing the code to the main developer branch.

Assume Case Sensitivity

Case typically does not matter in Pascal, however code should always be written in a case-sensitive matter for readability and consistency purposes

Assume These Items Are Deprecated

Auto-generated Code Can Be Left As Is

Code that is automatically generated by the IDE does not need to be manually reformatted to match these style guidelines (such as renaming parameter names and manually re-ordering of class methods automatically added to the interface section.) Auto-generated code is expected to be formatted in a particular fashion and can be left as-is.

Case Statements

  • Be intentional on the use of the else clause. Typically, the else clause should be used in the event that the selected expression was not expected. This is easily demonstrated by using an enumerated type in a case statement as in the example below
  TMyExampleEnum = (Enum1, Enum2, Enum3);
  ...

  // This is a common implementation for handling the three options currently available
  // This code does not age well when a new TMyExampleEnum value is added at some point in the future:

  case vMyValue of
    Enum1: DoOne();
    Enum2: DoTwo();
    else
      DoThree();
  end;


  // This code is defensive and will alert on a new value:

  case vMyValue of
    Enum1: DoOne();
    Enum2: DoTwo();
    Enum3: DoThree();
    else
      Assert(False, 'Invalid TMyExampleEnum value');
  end;

Code Smell - Very Long Lines

  • Wrapping very long lines at an nondescript right margin may signify that refactoring is needed

Code Smell - Very Long Methods

  • Using page-up and page-down in a single method may signify that refactoring is needed

Composition Over Inheritance

  • Favor composition over inheritance when building your classes

Compound Statements

  • Each line should contain at most one statement
  // This is technically valid code
  Statement1;  Statement2;

  // Better:
  Statement1;
  Statement2;
  • Always end a statement with a semicolon.
  // this is valid code, but you should always include the final semicolon in a code block
  begin
    Statement1;
    Statement2
  end;

  // Better:
  begin
    Statement1;
    Statement2;
  end;

Const Parameters

  • Utilize the const reserved word for read-only parameters to allow the compiler to optimize structured and string parameters.

Exit Usage

  • Outside of Guard Clauses, use Exit sparingly
  • Guard Clauses can be used to reduce nesting
  // Without guard clause
  function Combine(SomeThing:String; SomeOther:String):String;
  begin

    if (SomeThing <> '') then
    begin
      if (SomeOther <> '') then
      begin
        //combine
        ...
      end
      else
      begin
        Result := SomeThing;
      end
    else
    begin
      Result := SomeOther;
    end;

  end;

  // Guard clauses can reduce complexity
  function Combine(SomeThing:String; SomeOther:String):String;
  begin

    if SomeThing = '' then Exit(SomeOther);
    if SomeOther = '' then Exit(SomeThing);

    //combine
    ...
  end;

Field Access

  • Do not access fields directly in code, rather read and write field values utilizing their Property references with the possible exception of inside the parent class constructor.

Magic Number and Strings Avoided

  • Hard coded numbers (other than 0 and 1) and strings should be defined as named constants or resource strings. (Passwords, cryptographic keys or other credentials should never be embedded in code.)

Organizing Uses Clause

  • The items within a uses clause are usually grouped by scope such as listing RTL (System, Platform) units first, and then System Library (Data, Soap, Xml...), Framework (VCL/FMX), Third Party libraries and components, units shared across projects, and project-specific units listed last.

Parameterless Method Calls

If a method has no parameters, it is preferred to utilize a parenthesis as in the following example:

  if i > 1 then
  begin
    CallSomeMethod();  //parenthesis not required, but recommended
  end
  ...

Minimize Unit Dependencies

  • Unless types are referenced in the unit's Interface section, always add units to the uses clause in the Implementation section which helps to improve project build times and minimize circular dependencies.

Positive Code

  • In general, write code to check for the positive case rather than negative
  // Negative
  if not Good then
  begin
    DoBad;
  end
  else
  begin
    DoGood;
  end;

  // Positive
  if Good then
  begin
    DoGood;
  end
  else
  begin
    DoBad;
  end;

Test Code Is Production Code

  • Code written for Unit, Integration, Performance, Security, and other testing purposes should generally follow all Style Guide rules

Version Control Notes

  • When modifying code that also needs to be refactored, first refactor the code and execute the tests to validate the changes made, commit those refactoring changes and only then proceed to modify the code logic. Refactoring-only changes should be separate commits. (Note: this same rule applies to reformatting a unit.)