Содержание
Соглашения по исходному коду
Именование файлов
В именах юнитов с исходным кодом приняты следующие префиксы:
- c_ Юниты в которых объявлены только константы
- t_ Юниты в которых объявлены только простые типы (Record, Enum и тд)
- i_ Юниты в которых объявлены только интерфейсы
- fr_ Юниты в которых объявлены фреймы (Наследники TFrame)
- frm_ Юниты в которых объявлены визуальные формы
- u_ Все остальные юниты, не подходящие под предыдущие префиксы
Связи между юнитами
- c_ Юниты могут зависеть только от t_ Юнитов
- t_ Юниты должны зависеть только от других t_ Юнитов
- i_ Юниты могут зависеть от t_ Юнитов и других i_ Юнитов, циклические связи невозможны в принципе, так как раздел реализации пустой.
Все остальные юниты могут зависеть друг от друга, но крайне желательно, что бы в разделе интерфейса были в основном i_ Юниты и t_ Юниты. Циклические ссылки между юнитами теоретически возможны, но их нужно максимально избегать.
Допустимые типы переменных в API плагинов
- Строки - WideString (WSTR). PWideChar - допускается, но не рекомендуются. PAnsiChar допустим только для ASCII-строк. PChar и ANSI-строки запрещены.
- Символьные - AnsiChar и WideChar. Char - запрещено;
- Целые - Integer, Cardinal, Int64, UInt64, NativeInt, NativeUInt, Byte, Word. Запрещено использовать Currency.
- Вещественные - Single и Double. Запрещено использовать Extended, Real, Real48 и Comp.
- Логический - BOOL. Допускается ByteBool, WordBool и LongBool, но не рекомендуется. Boolean - запрещено.
- Статические массивы - array[число..число] of из допустимых типов.
- Записи - (record) из допустимых типов.
- Указатели - на данные допустимого типа; нетипизированные указатели.
- Интерфейсы - (interface), в методах которых используются допустимые типы.
- Запрещено передавать объекты (TObject) и компоненты (TForm, TButton).
Форматирование кода
Длина строки.
Мы предпочитаем делать строки короткими и наглядными. Короткие строки не только более читабельны, но и позволяют задавать операторы в более простой форме (особенно, когда они используются с описательными именами переменных). Методы, состоящие из серий коротких простых операторов, легче для восприятия и модифицирования. Даже диффы в результате точнее показывают, что поменялось между коммитами.
Блоки Uses
Название каждого юнита с новой строки (опять же для упрощения диффов) примерно в таком порядке:
- Системные юниты (SysUtils, Types и тд.)
- Юниты библиотек (GR32, KAZip и тд.)
- Юниты программы:
- Юниты в которых объявлены только константы
- Юниты в которых объявлены только простые типы
- Юниты в которых объявлены только интерфейсы
- Обычные юниты с кодом
- Юниты в которых объявлены фреймы
- Юниты в которых объявлены визуальные формы
Идентификаторы
В именах типов, классов, методов, переменных, параметров и тд. Нужно использовать CamelCase.
Сразу за именем переменной должно стоять двоеточие, потом пробел, потом имя типа.
Пример:
VOperationID: Integer;
Желательно использовать префиксы:
- T Имя класса
- I Имя интерфейса
- V Локальная переменная функции (Без префикса можно использовать простые счетчики: i, j и тд. но желательно не увлекаться)
- F Поле класса
- A Параметр функции
- C Константа
Объявление полей класса только по одному на строку с указанием типа для каждого.
Объявление локальных переменных - в большинстве случаев по одному на строку типа для каждой переменной отдельно (исключение простые счетчики)
Объявление параметров функций и процедур - по возможности указывать тип для каждой переменной отдельно, если параметров больше чем один-два, то каждый параметр должен расположен на отдельной строке.
Пример кода:
function FindItems(
const AVisualConverter: ILocalCoordConverter;
const ALocalPoint: TPoint
): IVectorItemSubset;
constructor Create(
const ARootFolderName: WideString;
const AFolderNameFromRoot: WideString;
const AFileMask: WideString;
const AFilesOnly: Boolean
);
Форматирование кода
Необходимо соблюдать отступы.
Пробелы перед запятой или точкой с запятой недопустимы.
После запятой должен быть пробел.
Операторные скобки begin/end обязательны.
begin располагается на той же строчке, что и операция к которой он относится.
end располагается на новой строчке с тем же отступом, что и команда к которой он относится
Пример кода:
if FDataRecived then begin
VDataRecived := True;
FDataRecived := False;
end else begin
if FLastDataReceiveTick > 0 then begin
if FLastDataReceiveTick > VCurrTick then begin
FLastDataReceiveTick := VCurrTick;
end else begin
VTickDelta := VCurrTick - FLastDataReceiveTick;
if VTickDelta > VNotDataTimeout then begin
FGPSRecorder.AddEmptyPoint;
FGpsTrackRecorder.AddEmptyPoint;
VDataRecived := True;
end;
end;
end;
end;
Закомментированный код зло и должен быть удален до коммита.
Общие идеи
Весь функционал максимально прячется за интерфейсами. Это дает такие преимущества:
- Управление временем жизни объектов при помощи автоматического подсчета ссылок.
- Интерфейсы можно передавать между границами DLL (Например в плагины и из плагинов), а обычные делфовские объекты нельзя. Пока далеко не все классы имеют интерфейсы и это тормозит появление плагинов.
- Имея интерфейс, мы можем делать его реализации совсем не связанными между собой.
В интерфейсах нельзя использовать делфовских классов. То есть, если нам нужно возвратить или получить просто бинарные данные, то нужно использовать не TStream, а интерфейс IBinaryData (Сейчас есть пару исключений самое главное TCustomBitmap32, но это временно). Это же касается делфовских динамических массивов, объявленных как array of По возможности в интерфейсах нужно избегать использования указателей. Использовать их стоит только если это действительно оправдано.
