S3.Blog

19 Марта 2024
A A A   RSS-лента
"Я знаю, что ничего не знаю, но многие не знают и этого". Сократ [?].

Стандарты программирования

Дата последнего изменения: 9 Мая 2009
Метки статьи: Документация, HTML, MySQL, Perl

В данном документе описаны стандарты программирования (Perl, SQL, HTML) Предлагаемый список советов и требований, разумеется, не является исчерпывающим.

 

Помимо данного документа рекомендуется к прочтению следующая литература:

Оглавление

  1. Оформление кода
  2. Переменные и константы
  3. Функции
  4. Модули
  5. Регулярные выражения
  6. Безопасность и надёжность кода
  7. Лаконичность кода
  8. XP
  9. Общие замечания
  10. SQL, базы данных
  11. Шаблоны Template Toolkit
  12. HTML-код
  13. Система управления версиями

1. Оформление кода

1.1. Лесенка в 4 или 8 пробелов
Обязательна "лесенка" с отступом в 4 пробела (half-tab) или 8 пробелов (tab). При этом запрещается в редакторе изменять размер отображаемой табуляции, например выставлять отображение табуляции в 4 символа. Код, созданный Вами при таких настройках, будет некорректно отображаться в других редакторах с другими настройками.

1.2. Пробелы после запятых
После запятых и точек с запятой (если, конечно, они не расположены в конце строки) ставятся пробелы. Перед запятой и точкой с запятой пробелы не ставятся:
@a = (1, 2, 3);
for (my $i = 0; $i < $count; $i++) {  };

1.3. Пробелы вокруг знаков операций
Любые операторы / знаки операций (перечисленных в perlop, например "=", "==", "=>", "<", ">", "&&", "||" и т.п.) обязательно отделяются пробелами с обоих сторон

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

$a = $b * $c + $d * $e;
$a = $b * $c  +  $d * $e;

1.4. Пробелы после ключевых слов
После любых ключевых слов языка perl, а также имён функций / методов, обязательно следует пробел. Исключение составляет случай, когда за именем функции/метода следует открывающая круглая скобка, за которой следует пробел.
Примеры:
@foo = grep !/^#/, @bar;
@foo = grep( !/^#/, @bar )

1.5. Пробелы вокруг сложных индексных выражений
В случае, если Вы обращаетесь к элементу массива или хэша по индексу и индексное выражение достаточно сложное, отделяйте его пробелами для улучшения удобочитаемости. Если выражение простое — пробелы не обязательны.
$a[1];
$a[ 1 + 2 + 2 + 4 * function( $a{ $b->{c} } ) ];

1.6. Пробелы после знака комментария
После символа начала комментария («#») перед текстом самого комментария ставится пробел.
Исключение составляют fancy comments, гед допускается сливать начальнуй символ решётки с последующими символами:
############# MY COMMENT ###############
#************** INIT *******************


1.7. «Опять пробелы???»
Для того, чтобы понять, насколько хорошо отформатирован Ваш исходный текст: достаточно ли отступов, пробелов и пустых строк — попробуйте отключить подсветку синтаксиса в Вашем редакторе. Если после отключения подсветки код по-прежнему легко читаем (просмотр и анализ текста производится легко, любые конструкции легко выделяются визуально) — значит код действительно удобочитаем.

Не стоит полагаться на подсветку синтаксиса как на "костыль", скрывающий недостатки форматирования.

1.8. Выравнивайте комментарии точно так же, как и код
Левый край комментариев выравнивается точно так же, как и основной код, т.е. используется принцип "лесенки".
# тили-тили
# трали-вали
if ($cond) {
	# это дело мне по силе
	# откажусь теперь едва ли
}
else {
	# это мы не проходили
	# это нам не задавали
}
Ставить символы «решётки» вначале строки, если левая граница кода находится правее, не допускается.
# тили-тили
# трали-вали
if ($cond) {
# ТАК ДЕЛАТЬ НЕЛЬЗЯ!!!
}

1.9. Максимальная длина строк. Разбиение длинных строк.
Строки желательно не оставлять слишком длинными; условное ограничение — 80-100-120 символов в строке. При необходимости строка разбивается на несколько.
Примеры допустимого разбивания конструкций:
very_long_statement
	if condition;
if (
	very_long_condition_1
	&& very_long_condition_2
) {
	statement;
}

if (
	..
  &&
	...
  ||
	...
) {
	...
}

1.10. Открывающая фигурная скобка на той же строке, что и ключевое слово
Старайтесь придерживаться компактного (K&R) стиля оформления циклов и блоков ветвления: открывающая фигурная скобка находится на той же строке, что и ключевое слово "for", "if", "else", "while" и т.п.
Закрывающая фигурная скобка блока, состоящего из нескольких строк, должна находиться на одной вертикали с ключевым словом начинающим конструкцию.
Примеры:
if ($condition) {
	statement1;
}
else {
	statement2;
}
for (my $i = 0; $i < $count; $i++) {
	statement;
}

1.11. Пробел перед открывающей фигурной скобкой
Перед открывающей фигурной скобкой в блочных конструкциях всегда ставится пробел:
for (@array) {
	statement;
}

1.12. Допускается компактное оформление блоков из одного оператора
Однострочные блоки, состоящие из единственного оператора, могут быть помещены в одну строку вместе с открывающими и закрывающими скобками:
foreach (@array) { $_ *= 2; }
Возможно, лучше в подобных случаях использовать постфиксную форму записи:
$_ *= 2 foreach (@array);

1.13. Ставьте точку с запятой после каждого оператора
В Perl символ «;» является всего лишь разделителем (а не терминатором) операторов. В результате синтаксис позволяет НЕ ставить точку с запятой после последнего оператора блока. Однако, ставьте точку с запятой всё равно, даже если у вас всего лишь один оператор в блоке.

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

push @a, $a
print @a # Ошибка! Пропущена ";"

1.14. Ставьте запятую после каждого значения в многострочном списке
Следуя этому правилу, Вы сможете избежать лишних ошибок при добавлении элементов в конец списка. Также Вам будет проще перегруппировывать элементы списков, не заботясь о расстановке запятых.
my @dwarves = (
	'Happy',
	'Sleepy',
	'Dopey',
	'Sneezy',
	'Grumpy',
	'Bashful',
	'Doc',
);

1.15. Избегайте лишней пунктуации
Избегайте лишнией пунктуации. В особенности, лишних скобок при вызове функций, или при выделении условий.

Например, опускайте круглые скобки для задания аргументов встроенных функций и функций, имеющих прототип:

@foo = grep !/^#/, @bar;
или при написании условия в операторе if с постфиксной записью, а также в тринарных операторах:
print "Ok" if $ok1 && $ok2;

$message = $success ? "OK" : "NOT OK";

Только не забывайте о приоритетах операций.

Словом, стоит опустить лишние скобки там, где их отсутствие не идёт в разрез с удобочитаемостью.

1.16. Разбивайте код на абзацы, при необходимости снабжённые комментариями
Код внутри функций должен быть разделён на смысловые блоки, выполняющие определённую узкую задачу. Смысловые блоки отделяются друг от друга пустыми строками. Для дальнейшего улучшения сопровождабельности кода, добавляйте вначале каждого абзаца однострочный комментарий, объясняющий, что делает эта последовательность операторов.
sub addarray_internal {
	my ($var_name, $needs_quotemeta) = @_;

	# Запомнить оригинал...
	$raw .= $var_name;

	# Добавить экранирование спецсимволов, если необходимо...
	my $quotemeta = $needs_quotemeta ?  q{map {quotemeta $_} } : $EMPTY_STR;

	# Перевести элементы переменной в строку, соединяя их с помощью "|"...
	my $perl5pat = qq{(??{join q{|}, $quotemeta \@{$var_name}})};

	# Добавить отладочный код, если необходимо...
	my $type = $quotemeta ? 'literal' : 'pattern';
	debug_now("Adding $var_name (as $type)");
	add_debug_mesg("Trying $var_name (as $type)");
	return $perl5pat;
}

1.17. Выравнивайте сходные элементы кода по вертикали.
Выравнивайте сходные элементы по вертикали, особенно если они достаточно короткие чтоб поместиться в одну строку:
my %wm_conts_map = (
	first_name  => 'iname',
	last_name   => 'fname',
	email	   => 'email',
);

$IDX = $ST_MTIME;
$IDX = $ST_ATIME	if $opt_u;
$IDX = $ST_CTIME	if $opt_c;
$IDX = $ST_SIZE		if $opt_s;

mkdir $tmpdir, 0700 or die "can't mkdir $tmpdir: $!";
chdir($tmpdir)	     or die "can't chdir $tmpdir: $!";
mkdir 'tmp',   0777 or die "can't mkdir $tmpdir/tmp: $!";

2. Переменные и константы

2.1. Не отделяйте имена переменных и функций от следующей за ними открывающей скобки
Важно ставить открывающую скобку слитно с именем функции или переменной. В противном случае можно визуально спутать функцию с ключевым словом, а начало выражения для элемента массива или хэша со скаляром.
# ХОРОШО
next CANDIDATE if open_region($i);

$candidates[$i] = $incumbent{ $candidates[$i]{region} };
# ПЛОХО!
next CANDIDATE if open_region ($i);

$candidates[$i] = $incumbent { $candidates[$i]{region} };

2.2. Осмысленные названия идентификаторов
Выбирайте осмысленные названия для идентификаторов (переменных, констант, функций). Исключение составляют итераторы циклов, где допускаются короткие идентификаторы: $i, $n и т.п. При этом не допускается калька с русского языка ("$polzovatel", "$sajt" и т.п.). Если вы не можете вспомнить, что это имя значит — у вас проблемы.

2.3. Строчные буквы для названий переменных и функций
Названия всех переменных и функций должны состоять только из строчных букв, цифр и знаков подчёркивания: "get_domain_name" и т.п.

Хотя короткие идентификаторы типа $gotit возможно и неплохи, используйте знак подчеркивания для разделения слов. В общем случае $var_names_like_this прочесть легче чем $VarNamesLikeThis.

2.4. Заглавные буквы для констант
Константы именуются только с использованием заглавных букв:
use constant DEBUG => 0;

2.5. Именуйте массивы во множественном числе, а скаляры в единственном
Массивы рекомендуется называть во множественном числе, например @users, @objects, а скаляры — в единственном: $user, $object. Что касается хешей, то некоторые авторы рекомендуют также именовать их в единственном числе (%param), т.к. для хэшей гораздо более распространено обращение к единственному их элементу ($param{user_id}), в то время как массивы чаще обрабатываются целиком (см. пп. 5.3, 5.4).

3. Функции

3.1. Одна функция выполняет одну задачу
Если функция выполняет несколько разных, слабо связанных друг с другом задач, подумайте о том, чтобы разбить эту функцию на несколько.

3.2. Имена функций являются глаголами
Наименования функций по-возможности должны представлять из себя глагол, например get_domain_name, или chash_my_program.

3.3. Имена private-функций начинаются с подчёркивания
Если в модуле присутствуют функции, предназначенные только для внутреннего использования, которые никогда не будут вызваны за пределами модуля (за исключением случая автоматического тестирования), имеет смысл предварять названия этих private-функций знаком подчёркивания.

3.4. Отступы и комментарии для функций
Функции отделены друг от друга минимум одной пустой строкой. Для каждой функции необходимо краткое однострочное описание того, что она делает:
# Получить имя домена по его id
sub get_domain_name {
	...
}

3.5. Приём входных параметров функций
Параметры принимаются с использованием конструкции:
my ($param1, $param2) = @_;

В случае переменного количества параметров, если количество и смысл последующих параметров может варьироваться в зависимости от значения предыдущих параметров, допускается принимать эти первые по счёту параметры с помощью shift:
my $action = shift;
my ($name, $value) = @_ if $action eq 'new';
my ($reason) = @_ if $action eq 'destroy';

В случае очень коротких функций, там где производительность важнее удобочитаемости, для доступа к параметрам можно использовать $_[0], $_[1] и т.п.

3.6. Документирование входных параметров функций
Если аргументы функции нетривиальны (их назначение и набор допустимых значений не очевидны из их названия и контекста), после описания функции добавляется строка пояснения по аргументам. Если какой-либо аргумент может принимать конечное дискретное множество значений — это множество также перечисляется в комментариях. Если используются именованные параметры — все возможные параметры также перечисляются в комментариях, обязательные параметры обозначаются звёздочкой:
# %param: action*, domain_name*, comment
# action: new, renew, delete

3.7. Не более 3-х позиционных параметров у функций
Функция может принимать не более 2-х, максимум 3-х ПОЗИЦИОННЫХ аргументов. При большем количестве аргументов либо проводится рефакторинг с целью уменьшения количества входных параметров, либо используются именованные параметры:
my %param = @_;
Именованные параметры обязательно документируются (см. п. 2.6)

3.8. Проверка аргументов
В случае использования именованных параметров, если есть как обязательные, так и необязательные параметры, необходимо проверять наличие обязательных параметров. В случае их отсутствия — вызывать исключение с помощью Carp::confess (для получения stack backtrace) или Carp::croak. В случае использования позиционных параметров проверка наличия и корректности переданных аргументов также приветствуется.

3.9. Документирование выходных параметров функций
Если выходные параметры функции не очевидны / нетривиальны, особенно это касается возврата сложных структур данных, желательно их документировать (после описания входных параметров).

3.10. Возврат скаляра или списка, в зависимости от wantarray
Если функция возвращает список значений, но из возвращаемого списка часто может использовать только первое значение, желательно выдавать только первое значение или весь список в зависимости от контекста:
return wantarray ? (user_id, username) : user_id;

4. Модули

4.1. Наименование моделей в стиле MyModuleName
Модули .pm (и, соответственно, файлы модулей) следует называть в стиле MyModuleName, т.е. слова склеиваются между собой, каждое слово записывается с заглавной буквы. В то время как исполняемые файлы ("скрипты"), следует именовать маленькими буквами, с применением знака подчёркивания, и использовать суффикс .pl: clear_cache.pl.

4.2. Комментарий вначале модуля
Вначале модуля желателен комментарий, описывающий назначение модуля.

4.3. После последней строки модуля обязателен перенос
Последняя строка кода модуля обязательно заканчивается переносом строки.

4.4. use strict; use warnings;
Обязательное включение всех предупреждений и максимальное ужесточение автоматического контроля:
use strict;
use warnings;

4.5. Динамическая подгрузка тяжёлых опциональных модулей
Если требуется использовать "тяжёлую" библиотеку или модуль (скажем, отъедающую 5 Мб памяти и более), при этом, необходимость в этой библиотеке возникает лишь изредка, при определённых условиях — лучше загружать такой модуль динамически, когда в нём возникает необходимость:
if ($condition) {
	unless ($INC{'Compress/Zlib.pm'}) {
		require Compress::Zlib;
		import Compress::Zlib ();
	}
}

4.6. Не стоит злоупотреблять экспортированием функций
Не стоит экспортировать функции направо и налево без серьёзной необходимости. Во-первых, в этом случае засоряется namespace модулей, а во-вторых голое название функции без квалификатора может ввести в заблуждение: не очевидно, в каком модуле функция определена — это увеличивает время на понимание чужого (да и своего) кода и время на отладку.

Используйте либо название функции с полным квалификатором:

MyModule::mysub()

либо используйте ОО-интерфейс в Ваших модулях:
my $obj = new MyObject;
$obj->method();

4.7. Don't use Exporter
Старайтесь не использовать модуль Exporter: во-первых, он слишком тяжёл, во-вторых, злоупотребление экспортированием функций — признак дурного тона (см. п. 3.6). Если уж Вы используете этот модуль, лучше делать это так:
use Exporter 'import'; # gives you Exporter's import() method directly

нежели использовать Exporter в виде базового класса:
use base qw(Exporter);

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

5. Регулярные выражения

5.1. Используйте флаг "x" для сложных регулярных выражений
Если вы используете действительно сложное регулярное выражение, используйте модификатор "x" и разделите текст пробелами, чтоб он не выглядел как нагромождение мусора.
5.2. Используйте удобные ограничители для регулярных выражений
Не используйте наклонную черту в качестве ограничителя когда ваше выражение содержит прямые или обратные наклонные черты:
# Используем удобный ограничитель
$s =~ s|/|::|;
# Это куда нагляднее, чем /\//::/;

6. Безопасность и надёжность кода

6.1. Осторожное использование вызовов внешних команд
Прямое использование внешних вызовов команд (через "system" или "``") допускается только в особых случаях, при этом, если командная строка формируется внутри кода, необходимо быть абсолютно уверенным, что в командную строку не могут попасть входные переменные и параметры HTTP-запроса (см. п. 4.2).

6.2. Всегда проверяйте коды возврата системных вызовов.
Всегда проверяйте коды возврата системных вызовов. Если ошибка фатальна — вызывайте исключение с помощью die, Carp::confess или Carp::croak, передавая соответствующее сообщение об ошибке. Хорошее сообщение об ошибке должно включать: в каком месте программы возникла проблема, какой системный вызов был произведен, с какими аргументами, и (ОЧЕНЬ ВАЖНО) должно содержать стандартное системное описание ошибки.
Пример:
open my $fh, "> $filename" or die "Can't open $filename for writing: $!";
print   $fh '....';

Безопасность кода при работе с БД

6.3. Недопущение возможностей для SQL-inject:
Подстановка данных в SQL-запросы ТОЛЬКО через placeholders ("?").

6.4. Минимизация изменений тела запроса
В особых случаях (если необходимо подставить имя поля или название таблицы) допускается подстановка переменных напрямую в тело запроса, при этом должны быть соблюдены два условия:
  • если подставялется имя таблицы или поля, то оно обязательно заключается в кавычки: `fieldname`,
  • Вы должны быть АБСОЛЮТНО уверены в том, что значения переменных НЕ извлекается напрямую из входных параметров/переменных HTTP-запроса, а генерируется внутри кода и могут принимать только конечное дискретное множество значений.
Пример:
SELECT `$fieldname` FROM `$table`

7. Лаконичность кода

7.1. Сокращённая форма записи, основанная на ||
Приветствуется использование сокращённой формы записи, основанной на применении логического оператора "или". Например:
$a = $b || $c

лучше, чем
$a = $b ? $b : $c

и тем более лучше, чем
if ($b) {
	$a = $b;
}
else {
	$a = $c;
}

Также
$a ||= $b

лучше, чем
$a = $b unless $a;

7.2. Сокращённая форма записи, основанная на &&
Приветствуется использование сокращённой формы записи, основанной на применении логического оператора "и". Данная конструкция полезна также для условного выполнения кода. В следующем примере метод method будет вызван только тогда, когда объект $obj проинициализирован.
$result = $obj && $obj->method;


А здесь выполняется функция do_something при выполнении условий $condition1 и $condition2:
$condition1 && $condition2 and do_something();

7.3. Используйте and и or вместо условных конструкций if
В ряде случаях (когда при каком либо условии нужно выполнить всего один оператор) удобнее выполнять условный код с помощью and или or, чем громоздить блоки if:
mkdir $tmpdir, 0700 or die "can't mkdir $tmpdir: $!";

$username = get_user_name() and print "Username: $username\n";

7.4. Минимизация использования циклов for и обращений к элементам по индексу
Старайтесь избегать использование классического цикла for с целочисленным индексом, везде, где это возможно. В целом, старайтесь минимизировать обращение к элементам массивов по индексам. При обработке элементов списка отдавайте предпочтение циклам foreach, а также функциям, обрабатывающим сразу весь список сразу, таким как grep, map, sort, join, split и т.д.:
@foo = grep !/^#/, @bar;

@foo = map { $_ * 10 } @bar;

$_ *= 10 for @bar;

Как правило требуется обработка всех элементов массива сразу, а в этом случае удобнее использовать циклы foreach или функции, обрабатывающие массив целиком (см. п 5.4.). В случае использования foreach, grep, map элементы массива при каждой итерации предстают в виде переменной "$_" (или, для циклов foreach, любой другой переменной, какой Вы укажете), с которой работать куда удобнее, чем каждый раз обращаться к элементам массива по индексу.

7.5. Использование лаконичных вариантов функций DBI
Вместо последовательности DBI вызовов prepare / execute для изменения данных предпочтительнее использовать единственный вызов do.
Вместо последовательности DBI вызовов prepare / execute / fetch_* для выборки данных предпочтительнее использовать единственный вызов selectrow_* / selectall_* / selectcol_*.

8. XP

8.1. Тесты для всех функций / методов
Для каждой новой функции или метода должен быть написан автоматический тест. Лучше — несколько тестов, для проверки реакции на некорректные входные данные. Если Вы вносите серьёзные изменения в функцию и для неё не написаны тесты — создайте их.

Если какие-то чужие тесты у Вас не проходят, то это повод либо поправить исходный код (свой или чужой — не важно), либо тесты, если они не актуальны.

При создании тестов необходимо придерживаться следующих правил:

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

    Исключение составляют записи в логах — логи откатывать не нужно.

  2. Любые действия, производимые в процессе тестирования, меняющие состояние каких либо систем не должны покидать границ Вашей локальной машины. Т.е. запуск тестов у Вас не должен приводить к каким-либо изменениям во «внешнем мире» (логгирование Ваших операций чтения внешними системами — не в счёт). Например, исходящие письма, вместо отправки их реальным пользователям на реальные адреса в Интернете, должны отправляться на какой-либо тестовый ящик на локальной машине.

    Исключение из этого правила составляют модификации, вносимые в специальные ТЕСТОВЫЕ внешние системы (через различные тестовые эккаунты). В тестовых эккаунтах допустимы любые действия, если они не приведут к невозможности дальнейшего использования этого эккаунта для тестирования.

8.2. Рефакторинг
Если код Вам перестаёт нравится: функция слишком сложная и длинная (более 100 строк), слишком много входных и выходных параметров, неудачное название функции и т.п. — делайте рефакторинг. После проведения рефакторинга обязательно запускайте автоматические тесты. Если для функции, над которой Вы работали, тесты не предусмотрены -- создайте их.

9. Общие замечания

9.1. Don't Reinvent Wheel — Не переизобретайте колесо
Не переизобретайте колесо — если подобное колесо уже существует, просто адаптируйте его для своих нужд. Вероятно, для решения данной проблемы уже существует стандартный модуль в дистрибутиве Perl, или модуль из CPAN, или модуль, разработанный другими людьми внутри организации.

9.2. Do not Repeat Youself — не повторяй самого себя
Подумайте о повторном использовании кода. Зачем тратить впустую усилия мысли на одноразовые программы, если в будущем вам может потребоваться что-то подобное снова? Подумайте над обобщением вашего кода. Подумайте над написанием модуля или класса. Позаботьтесь о том, чтоб ваш код выполнялся без предупреждений с "use strict" и "use warnings" (или -w). Подумайте, не предложить ли Ваш код другим.

9.3. KISS — Keep It Simple, Stupid
Всегда и везде стОит придерживаться максимально простых решений, как в области архитектуры, так и в области непосредственно кодирования.

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

9.4. Не живите с разбитыми окнами
Не оставляйте «разбитые окна» (неудачные конструкции, неверные решения или некачественный текст программы) без внимания. Как только Вы их обнаружите — чините сразу. Часто безошибочные, функциональные системы быстро портились, как только окна начали разбиваться. Не давайте энтропии победить себя.

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

Спросите, Зачем?

  1. Система и основной репозиторий «не захламляются» тем самым модулями общего назначения. В результате в основной системе легче ориентироваться
  2. Подготовка модулей к выкладке в общий доступ неизбежно повышает их качество (как минимум надо создавать документацию и тесты, «выпрямлять» код)
  3. Получаем все преимущества OpenSource (другие люди присылают багрепорты и патчи, способствуя улучшению модулей)
  4. Мы должны не только брать, но и отдавать что-то OpenSource-сообществу, возвращая тем самым свой долг
  5. Приятно раскручивать своё имя в CPAN ;)

10. SQL, базы данных

10.1. Форматирование SQL-запросов
Запросы длиной более 50 символов (примерно) рекомендуется разбивать на несколько строк, подгоняя текст по горизонтали. Например так:
SELECT fields
  FROM tables t
 WHERE conditions
   AND more conditions
 GROUP BY fields
 ORDER BY fields
 LIMIT limits
или так:
SELECT
	fields
FROM
	tables t
WHERE
	conditions
AND
	more conditions
GROUP BY
	fields
ORDER BY
	fields
LIMIT
	limits

10.2. Ключевые слова — заглавными буквами
Все ключевые слова SQL записываются заглавными буквами, все наименование таблиц, полей, пользовательских функций — строчными.

10.3. Названия полей и таблиц — строчными буквами
При именовании таблиц и полей не допускается использование заглавных букв. Допускаются только строчные латинские буквы, цифры и знак подчёркивания. Пример: "name_of_the_table".

10.4. Названия таблиц — во множественном числе
Таблицы следует именовать по-английски, во множественном числе. Например: "domains", "users".

10.5. Первичный ключ с именем "id" *
В каждой таблице (за исключением таблиц, где необходимы составные ключи, например таблиц для обеспечения связей многие-ко-многим) обязательно должно быть поле с именем "id" и типом INT, для которого должен быть создан первичный ключ:
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY
Поле для первичного ключа может быть названо по другому и иметь другой тип, но это обязательно обсуждается с другими членами команды и выносится соответствующее обоснование.

10.6. Ссылочные поля — с именем " _id" *
Все поля, использующиеся для связи с другими таблицами по их первичному ключу, именуются как " _id", где " " — имя таблицы в единственном числе. Примеры наименований: domain_id, user_id.

11. Шаблоны Template Toolkit

11.1. Экранирование поставляемых данных во избежание XSS-атак
При подстановке в шаблон данных, передаваемых пользователем (например, переданных ранее через форму на сайте), эти данные обязательно экранируются с помощью фильтра html:
[% company_name | html %].
Во избежание атак XSS.

11.2. Пробелы
К оформлению кода внутри шаблонов применяются те же самые требования, что и к оформлению кода на Perl. В частности это касается расстановки пробелов (пробелы вокруг операторов, пробелы после запятых, вокруг сложных индексных выражений и т.п.) Например,
[% news = [ { date => '31.12.2007', title => 'Happy new Year' } ] %]
[% FOREACH n = news %]

11.3. Лесенка
При использовании логических / блочных конструкций TT данные, внутри блока сдвигаются вправо для улучшения удобочитаемости:
[% IF ru %]
  русский текст
[% ELSE %]
  english text
[% END %]


11.4. Проверки на непустоту списков
В случае необходимости отображения списка или таблицы, где строки передаются в виде массива, должна быть проверка на непустоту этого массива и соответствующая адекватная реакция. Например, вместо вывода пустой таблицы или списка лучше вывести пояснительный текст: "Заказы пока отсутствуют" или "Новостей на сегодня нет".

11.5. Шаблон должен интерпретироваться без ошибок, даже если отсутствуют необходимые данные
Шаблон должен интерпретироваться без ошибок даже в случае, если требуемые шаблоном переменные не передаются шаблонизатору. Это означает, что в шаблонах должна быть предусмотрена адекватная защита, на случае, если данные не передаются.

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

12. HTML-код

12.1. HTML-код должен соответствовать спецификации XHTML
HTML-код по-возможности должен соответствовать спецификации XHTML 1.1, а это означает, что:
  • Все элементы должны быть закрыты. Теги, которые не имеют закрывающего тега (например, или
    ) должны иметь на конце / (например,
    ).
  • Булевы атрибуты записываются в развёрнутой форме. Например, следует писать или
  • Все значения атрибутов обязательно должны быть заключены в двойные кавычки.
  • Имена тегов и атрибутов должны быть записаны строчными буквами (например, вместо ).
  • HTML гораздо строже относится к ошибкам в коде; Символы "<", ">" и "&" должны быть записаны как <, > и & соответственно.

12.2. Тире всегда записывается как —
Тире всегда записывается как —. Использование дефиса вместо тире не допускается. Более подробно тема раскрыта в параграфе Арт. Лебедева «Тире, минус и дефис, или Черты русской типографики».

12.3. Кавычки-«ёлочки» вместо "английских двойных".
В HTML-документах, создаваемых для русскоянычной аудитории, желательно использовать кавычки-«ёлочки» (символы « и »). В документах, создаваемых для внутреннего использования (внутренняя документация, технические задания, должностные инструкции и т.п.) допускается использование "английских двойных" кавычек.

12.4. Не использовать спецсимволы, записанные в национальной кодировке
Не использовать знаки номера, копирайта, спец-кавычек и т.п., записанные в виде символов в национальной кодировке, скажем cp1251. Далеко не во всех редакторах и операционных системах Ваши символы будут корректно отображаться. Для вставки подобных знаков используются html-entities:

Краткий справочник:

&copy; © знак охраны авторского права (copyright)
&reg; ® знак зарегистрированных прав
&trade; символ зарегистрированного товарного знака
&laquo; « левая кавычка (левая ёлочка)
&raquo; » правая кавычка (правая ёлочка)
&mdash; тире
&ndash; короткое тире для обозначения интервалов
&minus; минус
&plusmn; ± плюс/минус
&deg; ° знак градуса
&lt; < знак «меньше»
&gt; > знак «больше»
&le; знак «меньше или равно»
&ge; знак «больше или равно»
&amp; & амперсанд
&nbsp;   «несжимаемый» пробел
&sup1; ¹ 1 в верхнем индексе
&sup2; ² 2 в верхнем индексе
&sup3; ³ 3 в верхнем индексе
&#8470; знак номера
&cent; ¢ знак цента
&pound; £ знак фунта
&yen; ¥ знак йены
&euro; знак евро
&sect; § знак параграфа
&middot; · точка (знак умножения)
&frac14; ¼ одна четверть
&frac12; ½ одна вторая
&frac34; ¾ три четверти
&bull; буллет
&hellip; многоточие
&lsquo; &rsquo; ‘ ’ одинарные лапки
&bdquo; открывающая лапка
&ldquo; закрывающая лапка
&rdquo; закрывающая английская лапка
&#9650; стрелки
&#9651; -- " --
&#9652; -- " --
&#9653; -- " --
&#9654; -- " --
&#9655; -- " --
&#9656; -- " --
&#9657; -- " --
&#9658; -- " --
&#9659; -- " --
&#9660; -- " --
&#9661; -- " --
&#9662; -- " --
&#9663; -- " --
&#9664; -- " --
&#9665; -- " --
&#9666; -- " --
&#9667; -- " --
&#9668; -- " --
&#9669; -- " --

12.5. Для каждого чекбокса должен быть label
Для каждого элемента должен быть предусмотрен элемент , для того, чтобы чекбокс срабатывал также по клику по метке:


12.6. Грамотно используйте табличную форму представления инфрмации
Вначале немного терминологии, касающейся таблиц. Содержимое таблицы организуется в колонки (графы). Таблица состоит из следующих основных элементов: нумерационного и тематического заголовков (номер таблицы и её название), головки (заголовочная часть таблицы), хвоста (вся остальная часть таблицы без головки), боковика (первая слева графа таблицы) и прографки (хвостовая часть таблицы без боковика).

Заполняя таблицу текстовыми или цифровыми данными полезно следовать правилам:

  • Выносить данные общие для каждого элемента графы в её заголовок, а общие для каждого элемента строки в заголовок боковика.
  • По возможности употреблять числа не более чем из четырёх значащих цифр. Для этого более многозначные числа следует округлять. Общий множитель следует вынести в заголовок. То же самое нужно сделать и с единицами измерения.
  • Всегда перед знаком, отделяющим целую часть числа от дробной, должна быть цифра. То есть правильно писать «0.1», но не «.1».
  • Проставлять вместо отсутствующих данных многоточие «...», «Нет свед.». Если данных в принципе быть не может, то лучше отметить это с помощью тире «—».

Взято отсюда.

13. Система управления версиями

13.1. Одна фича — один коммит
Лучше не объединять несколько разных фич (или несколько разных багфиксов) в одном коммите. Сделал что-то одно — протестировал — закоммитил.

Не нужно бояться, что изменений для одного коммита «слишком мало». Коммит может содержать исправление и 1-й буквы, в этом нет ничего страшного.

Если патчи достаточно малы — проще делать откат и ревизию изменений. То есть производимые Вами изменения легче будет анализировать.

Если Вы «заработались» и у Вас накопилось несколько логически не связыннах изменений, их можно закоммитить выборочно:

svn commit  

13.2. Все скрипты должны иметь установленный exec-флаг
Все скрипты должны иметь установленое свойство svn:exec. Если добавлять скрипты в репозитарий, когда они уже имеют установленные права на исполнение — свойство это выставляется автоматически. Иначе свойство надо выставлять «руками»:
svn propedit   

13.3. Чаше заливать свои изменения и получать апдейты

Чем быстрее вы выкладываете изменения (svn commit), тем быстрее их можем протестировать / проконтролировать, найти ошибки, ускоряется обратная связь и, как следствие, разработка вцелом.

Чем чаще вы получаете изменения (svn update), тем меньше вероятность нарваться на конфликт и тем согласованнее будут работа над кодом.

14. Почитать код

14.1. Class::Data::Accessor
Вся красота и стройность Perl'а обнаруживается в этих строках:
Class::Data::Accessor

14.2. package qxp;
А вся красота, стройность и непонятность Perl'а обнаруживается вот в этих строках:
Support Nightmare

Не пишите так, если хотите что бы проект поддерживался другими программистами!


Буду раз услышать любые замечания и дополнения по данному документу.
Пишите на адрес: despair {at} cpan {dot} org.

© Walery Studennikov



Похожие материалы:




 
  Имя *:   Решите пример *: =
 
Полужирный Курсив Подчеркнутый Перечеркнутый
 
Вставить изображение Сделать цитатой Вставить ссылку Вставить код

Вставить смайл
 
 

 



© S3.Blog: Если критикуешь, не предлагая решения проблемы, то ты становишься частью этой проблемы.