-
Notifications
You must be signed in to change notification settings - Fork 0
RADProgrammer Style Guide Other Guidance
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.
Case typically does not matter in Pascal, however code should always be written in a case-sensitive matter for readability and consistency purposes
-
Consider
with
to be deprecated and not used -
Consider
goto
as usually worse thanwith
-
Consider the System.DateUtil methods
YearsBetween
,MonthsBetween
,YearSpan
, andMonthSpan
as deprecated and use alternatives -
Do not utilize
inline variables
(first introduced in 10.3 in November 2018) until the tooling catches up. Some examples include:- RSP-32507 Inline variable breaks the Methods drop-down box in Navigation Toolbar
- RSP-33176 Extract method refactoring broken by inline var definition
- RSP-33365 In-block variables break the "Find references"
- RSP-23096 Incorrect debugger values
-
RSP-22089 Code Formatter Fails on Inline Vars
- See note from Marco on RSP-28948: May 14, 2020 The formatter is not related with CodeInsight and LSP and is an area we plan addressing next.
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.
- 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
raise Exception.Create('Invalid TMyExampleEnum value');
end;
- Wrapping very long lines at an nondescript right margin may signify that refactoring is needed
- Using page-up and page-down in a single method may signify that refactoring is needed
- Favor composition over inheritance when building your classes
- 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;
- Utilize the
const
reserved word for read-only parameters to allow the compiler to optimize structured and string parameters.
- 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;
- 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.
- 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.)
- 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.
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
...
- 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.
- 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;
- Do not define property Setter and Getter methods that are direct single line assignments or reads of the corresponding field variable
- Code written for Unit, Integration, Performance, Security, and other testing purposes should generally follow all Style Guide rules
- 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.