Стиль

Оглавление

Предупреждение

Описание несамодостаточно, и не содержит всех ссылок на материалы, необходимые для понимания. Некоторые знания и опыт необходимы.

Нумерация версий

Номер версии состоит из мажора и минора, резделенных точкой. Мажор - это целое число в десятичном представлении. Минор - это строка десятичных цифр определенной длинны.

При сравнении номеров версий сначала сравниваются мажоры, больше тот номер версии, у которой больше мажор. Если мажоры совпадают, тогда сравниваются миноры. Они могут сравниваться как десятичные числа (ведущие нули не существенны) и как строки (самые существенные символы слева, конец строки меньше любого символа). У одной программы не должно быть таких номеров версий, что бы от способа сравнения миноров зависел результат сравнения. Таким образом, наличие номеров версий у одной программы 1.2 и 1.11 запрещено, но 2.2, 1.1 и 1.11 разрешено.

Версии с мажором 0 и минором из только символов 0 являются временными, не являются изданиями (релизами) и предназначены только для выбора направления разработки. Остальные версии должны удовлетворять условиям совместимости.

При издании очередной версии надо либо увеличить минор, либо увеличить мажор и минор выбрать произвольным.

Желательно минор увеличивать путем увеличения на единицу представленного в нем числа без увеличения длинны минора, или при необходимости увеличения его длинны увеличивать его приписыванием справа нужной длинны строки из нулей.

Желательно мажор увеличивать на единицу, в качестве минора назначать строку нужной длинны из нулей.

При выборе длинны строки минора нужно оценить количество изданий с текущим мажором и сделать длинну строки минора минимально достаточной длинны для нумерации нужного количества изданий с этим мажором.

Если в интерфейсе разработки описана разделяемая библиотека, то номер ее версии должен быть равен мажору релиза.

Совместимость версий

Любая разработка может быть использована, для использования предназначены интерфейсы, они должны быть описаны. На изменение реализации описанного интерфейса специальных ограничений (кроме здравого смысла :-) не накладывается.

Несоответствие реализации описанию является ошибкой и обычно реализация должна быть исправлена. Если описание не было реализовано ни в одной версии, то можно исправить описание.

При издании очередной версии с сохранением мажора описание может остаться прежним или расширено так, что бы описание от предыдущей версии было справедливо (кроме возможного снятия ограничений и т.п.) для всех последующих описаний с тем же мажором.

Если в каком то контексте работает версия с некоторым мажором, и не работает версия с тем же мажором и бОльшим минором, то это ошибка. Может, ошибка использования недокументированных особенностей версии с меньшим минором, а может, нарушение совместимости у версии с бОльшим минором, и в этом случае такая ошибка должна быть исправлена в последующих изданиях.

К сожалению, я не могу требовать, что бы описание было строго задокументировано, иногда оно может быть в полном объеме только в голове у разработчика :-(, но к полному документированию надо стремиться.

Некоторые, но не все практические аспекты вышеописанных требований к версиям с одинаковыми мажорами:

При настоятельной необходимости не соблюдать вышеописанную совместимость версий при очередном издании меняется мажор версии. При изменении мажора необходимо тщательно подойти к выбору изменений, надо внести все изменения, ожидавшие смены мажора, но при этом вводить изменения так, что бы изменения продуктов, использующих измененные интерфейсы, было по возможности простым и бездумным, по возможности изменения в текстах должны быть минимальными, и желательна автоматизация контроля за правильностью этих изменений (например, сообщения при трансляции).

При изменении мажора разделяемые быблиотеки меняют название файла, потому библиотека с новым мажором может существовать в системе одновременно с библиотекой со старым мажором, и программы, использующие старую библиотеку, могут продолжать ею пользоваться, независимо от несовместимостей старых программ с новой библиотекой.

Коммиты

Результаты работы надо регулярно сбрасывать в репозиторий. Желательно, что бы каждая закомиченная версия была работоспособной, и очень желательно, что бы не были поломаны свойства от предыдущих версий.

Не надо стремиться запихнуть в один коммит как можно больше, желательно каждым коммитом добавлять только одно свойство или если много мелких исправлений, то diffы должны прозрачно рассыпаться по разным изменениям. Особенно надо избегать совмещения в одном коммите изменения форматирования с изменениями, меняющими поведение программы, поскольку в этом случае очень тяжело выделить значимые изменения из массы несущественных.

Издание версии

В commitе, непосредственно предшествующем изданию, первой строкой в сомментарии должна быть строка вида:
Версия X.XX
или
Version X.XX
, где X.XX - номер версии. Дистрибутив издания (релиза) должен содержать файлы в состоянии после commitа (в частности, все $Id$ должны быть проставлены, где они предусмотрены), название его должно быть вида имя_программы-X.XX.suffix, где suffix определяет(ся) способ архивирования дистрибутива.

Как правило, на каждую программу должен быть порт для FreeBSD, и издание должно сопровождаться апгрейдом порта.

Оформление текстов

Желательно в начале файлов дистрибутива иметь комментарии с копирайтом (копилефтом) и лицензией. Если нет специальной конструкции для CVS Id, то и его держать в том же комментарии. Не использовать табуляцию для форматирования, если можно сделать это пробелами. Рассчитывать на ширину страницы 80, 103 или 132 символа. Я, например, почти все форматирую под ширину 103 символа (этого хватает почти на все в C при величине отступа в 4 пробела) и изредка использую 80. В любом случае больше 132 использовать стоит только в особо специальных случаях.

Исходники на C

В .c файлах CVS Id и копирайт содержатся в специальной конструкции (см пример). В .h файлах CVS Id и копирайт содержатся в комментарии. Отступы по 4 пробела на уровень. При большом размере уровня можно отмечать уровень дополнительными символами точки с запятой в начале строки с пробелами, как в строках с комментарием #02.

Описатели снаружи процедур начинаются с первой позиции строки. В инициализаторах массивов запятая выносится вперед, как в примере. Идентификатор процедуры в определении процедуры начинается с первой позиции строки, тип процедуры записывается с первой позиции строки, непосредственно предшествующей идентификатору определяемой процедуры. Левая скобка при определении и при вызове процедуры должна примыкать непосредственно к идентификатору процедуры без пробела. Таким образом легко найти определение нужной процедуры при помощи команды grep и относительно несложно нафильтровать вызовы.

Оператор return записывается как вызов процедуры. Прочие синтаксические операторы со скобками, как while (...)... и подобные записываются с пробелом между идентификатором оператора и открывающей скобкой, оператор if (...)... записывается с двумя пробелами до открывающей скобки, если оператор начинается с позиции в строке, соответствуюшей уровню вложенности, как в примере в стрке с комментарием #01, но не в строке с комментарием #03.

Открывающая фигурная скобка отделяется от того, что ей в строке предшествует, пробелом, и если после закрывающей фигурной скобки есть еще текст, кроме закрывающих фигурных скобок, то между закрывающей скобкой и текстом ставится пробел, как в примере #03.

Несколько одинаковых закрывающих скобок можно разместить на одной строке при условии соблюдения уровней отступа (но понятно, что скобни на соответствующем отступе как правило не будут соответствовать открывающей скобке на том же отступе, см пример в скроке с комментарием #00.

При создании библиотек нужно идентификаторы, описанные на самом внешнем уровне доступа, но к которым не должно быть доступа из программ, использующих эту библиотеку, описывать как static, что бы не отравлять лишними идентификаторами программы.

Унарные операторы записываются со своим операндом без пробела, бинарные операторы отделяются с обеих сторон от своих операндов пробелом, за исключением самых приоритентых операторов - вызов функции (нет пробела перед открывающей круглой скобкой), индексирование (нет пробела перед открывающей квадратной скобкой), выделение элемента структуры (напрямую и по ссылке) (нет пробелов вокруг точки и операции ->).

Не ставятся пробелы после открывающей и перед закрывающей круглой, квадратной или фигурной скобкой кроме тех случаев, когда выражение в скобках занимает несколько строк (пример начинается в строке с комментарием #04.

Операторы, занимающие больше одной строки, должны быть записаны с использованием фигурных скобок, даже если синтаксически допустимо не использовать фигурные скобки при записи такого оператора.

/*-
 * Копирайт (копилефт) и лицензия
 */

#ifndef lint
static const char copyright[] = "\
@(#)Копирайт\n";
static const char rcsid[] = "$Id$";
#endif /* not lint */

struct {
    int a;
    char *b;
} ee[] =
{{1, " 1"}
,{2, " 2"}
,{0, NULL}
};

char n[] =
{ "00", "01", "02", "03",  "04", "05", "06", "07",  "08", "09", "0A", "0B",  "0C", "0D", "0E", "0F"
, "10", "11", "12", "13",  "14", "15", "16", "17",  "18", "19", "1A", "1B",  "1C", "1D", "1E", "1F"
};

static void
короткая_программа(int c) {
    int i, e;
    for (e = i = 0; i < c; i++) {
        e += i;
}   }                         /* #00 */

int
main(int argc, char *argv) {
    тип переменные;
    Еще_тип другие, переменные;
    .....
    struct какаято структура;

    /* пустая строка после длинного списка переменных */
    if  (...) {                          /* #01 */
        if  (...) {
    ;       if  (...) {                  /* #02 Пример отметки большого уровня      */
    ;           операторы;               /* #02 И еще такая отметка в начале строки */
                операторы;
        }   }
    } else if (...) {                    /* #03 */
        операторы;
    }
    for ( длинное инициирующее выражение /* #04 */
        ;   длинное и
         && еще более длинное условие
        ; условие прекращения
        ) {
        операторы;
    }
    exit(0);
}

Исходники на SQL

В SQL нет фиксированного отступа. При небходимости записи большего количества элементов, чем помещаетмся в строку, отступ выравнивается по первому элементу. См. первые 2 оператора SELECT в примере. Операторы отделяются один от другого строкой, в начале которой стоит точка с запятой. Синтаксичесчкие элементы одного оператора при необходимости записи в отдельной строке записываются с отступом в один пробел относительно начала своего оператора, но такие ключевые слова, как UNION, считаются более приоритетными и записываются левее своего SELECTа, см 3й и 4й операторы примера.

Выражения внутри BEGIN и END смещаются на одну позицию вправо.

SELECT идентификатор, другой, третий FROM чего, либо
;
SELECT идентификатор
     , другой
     , третий
     , (длинное выражение)
 FROM чего, либо
;
UPDATE table SET a = ...
               , b = ...
 FROM (SELECT ...
      UNION
       SELECT ...
      )e
;
 SELECT ...
  FROM          t1
   NATURAL JOIN t2
UNION
 SELECT ...
  FROM ...
;
BEGIN
;
 INSERT INTO ...
  SELECT ...
   FROM ...
;
END
;
CREATE FUNCTION o_string(name, bool) RETURNS text
 AS 'SELECT v FROM c
      WHERE o = $1
        AND (a = $2 OR (a IS NULL AND $2 IS NULL))
    '
 LANGUAGE SQL STABLE
;


А.А.Бабайлов (C)2005