Docu/ru/BB-Rules.odc

Cоглашения по оформлению программ
ENGLISH
Редакция перевода: Ф.В.Ткачев, 2009-03-20

Содержание

1.СамоеЏважное
2.Оберон
3.ЏЭлементарныеЏтипы
4.Шрифтовыеатрибуты
5.ЏКомментарии
6.ТочкиЏсЏзапятыми
7.Разыменование
8.Регистр
9.Имена
10.Пробелы
11.Пример
12.ЗаголовокОткрытогоисходногоЏкода


Этот текст описывает соглашения относительно правил программирования и форматирования исходного кода, которые использовались при создании системы Блэкбокс (BlackBox Component Framework). По документации существуют аналогичные соглашения.
Некоторые правила программирования важнее остальных. В первом разделе описаны самые важные правила. Остальные разделы содержат правила косметического характера, описывающие, как выглядят программы, опубликованных компанией Oberon microsystems. Если эти правила вам нравятся, смело пользуйтесь ими. Они могут сделать ваши программы более легкими для понимания теми, кто будет использовать их для проектирования, документирования и кодирования в BlackBox. 
1. Самое важное

Наиболее важные соглашения по программированию нацелены на то, чтобы обеспечить развиваемость (evolvability) программ. Это означает, что нужно максимально облегчить внесение надежных изменений в существующие программы, даже если программы были написаны давно или кем-то другим. Развиваемость часто может быть повышена путем увеличения степени локализованности частей программы: если можно четко ограничить тот отрезок программного текста, на который могут повлиять изменения в исправляемой части программы, то легче определить всю цепочку необходимых дальнейших изменений. Всущности, речь здесь о том, чтобы удержать под контролем всю цепную реакцию изменений.
Предусловия (preconditions)  один из наиболее полезных инструментов для обнаружения непредусмотренных последствий цепной реакции изменений. Проверки предусловий позволяют отловить семантические ошибки на максимально ранней стадии, то есть максимально близко к их источникам. Хорошо расставленные проверки (операторы ASSERT) могут радикально сократить время отладки после больших изменений в проекте. 
Везде, где можно, используйте статические средства, чтобы выразить все, что вам известно о структуре программы. В частности, используйте для этой цели систему типов и модули Компонентного Паскаля, чтобы компилятор смог помочь вам выявить несоответствия и, тем самым, стать эффективным инструментом реструктуризации.
 Выполняйте проверки предусловий. Не позволяйте вызывающей программе входить в ваш модуль, если не выполнены предусловия входных точек вашего модуля (процедур, методов). Таким образом вы избежите распространения чужих ошибок в вашем собственном коде.
Используйте следующие номера в соответствии с принятыми в Блэкбоксе правилами:
Свободные	0 .. Џ19	использовать для временных точек останова
Предусловия 	20 .. Џ59	допустимость параметров на входе процедуры
Постусловия	60 .. Џ99	допустимость результатов в конце процедуры
Инварианты	100 .. 120	допустимость промежуточных состояний 
		(выявление локальных ошибок) 
Резерв	121 .. 125	зарезервировано на будущее
Еще не реализовано	126	процедура еще не реализована
Резерв	127	зарезервировано на будущее
 Должно быть как можно меньше глобальных переменных.
Значения глобальных переменных могут изменяться из любого места программы, в любое время. Это затрудняет отслеживание всех возможных взаимодействий (т.наз. побочных эффектов) с такими переменными. Тем самым увеличивается вероятность внесения ошибок при изменении их использования.
 Процедуры-функции, т.е. процедуры, возвращающие результат, не должны менять глобальные переменные или VAR параметры в качесте побочного эффекта. Легче иметь дело с такими функциями, которые являются истинными функциями в математическом смысле, т.е. не имеют побочных эффектов. Но допустимо вместе с возвращением результата функции присваивать значений OUT параметрам.
 Используйте ELSE в CASE или WITH, только если входные данные допускают расширение.
Ветку ELSE в операторе CASE x OF или WITH x DO следует использовать, только если х действительно является расширяемым. Если х не расширяемо, то все возможные варианты должны быть известны статически и могут быть перечислены в списке альтернатив.
2. Оберон
Не используйте в новых программах специальные функции языка Оберон, которые не являются частью Компонентного Паскаля. В частности, это тип LONGREAL и процедура COPY. Старайтесь избегать супервызовов (используйте композицию вместо наследования) и процедурных типов (используйте вместо них объекты и методы).
3. Элементарные типы
По умолчанию используйте типы INTEGER, REAL и CHAR. Типы BYTE, SHORTINT, LONGINT, SHORTREAL и SHORTCHAR следует использовать только тогда, когда для этого есть веские причины. Эти вспомогательные типы введены для обеспечения взаимодействия с другими программами, для упаковки очень больших структур или для вычисления очень больших целых чисел. Это правило, конечно, важнее для экспортируемых интерфейсов, чем для скрытых реализаций.
4. Шрифтовые атрибуты
Программы пишутся как плоский текст, цветом, заданным по умолчанию, со следующими исключениями:
 Комментарии пишутся курсивом:  (* это комментарий *)
 Экспортированные элементы, за исключением полей записи и сигнатур методов в объявлениях записей, пишутся жирным шрифтом: PROCEDURE Do*;
 Ключевые слова, соответствующие нелокальной передаче управления, пишутся жирным шрифтом, например, RETURN, EXIT и HALT
 Текстовые фрагменты, которые тестируются и подвержены изменениям, временно могут быть записаны другим цветом
5. Комментарии
Комментарии, которые являются частью описания интерфейса (в отличие от простого описания реализации), оформляются дополнительными звездочкам, своего рода метками экспорта для комментариев, например, (** охрана для команды xyz **)
6. Точки с запятой
Точки с запятой используются для разделения операторов, а не для их завершения. Это означает, что не должно быть избыточных точек с запятой.
Хорошо
	IF done THEN
		Print(result)
	END
Плохо
	IF done THEN
		Print(result);
	END
7. Разыменование
Оператор разыменования ^ следует убирать отовсюду, где это возможно.
Хорошо
	h.next := p.prev.next
Плохо
	h^.next := p^.prev^.next
8. Регистр
Вообще говоря, каждый идентификатор начинается с маленькой буквы, за исключением следующих случаев:
 Имя модуля всегда начинается с большой буквы
 Имя типа всегда начинается с большой буквы
 Имя процедуры всегда начинается с большой буквы, это верно также для процедурных констант, типов, переменных, параметров и полей записи.
Хорошо
	null = 0X;
	DrawDot = PROCEDURE (x, y: INTEGER);
	PROCEDURE Proc (i, j: INTEGER; Draw: DrawDot);
Плохо
	NULL = 0X;
	PROCEDURE isEmpty (q: Queue): BOOLEAN;
	R = RECORD
		draw: DrawDot
	END;
Не используйте идентификаторы (кроме однобуквенных), состоящих только из заглавных букв. Их следует зарезервировать для языка.
9. Имена
 Для имен обычных процедур берутся глаголы, например, РисоватьТочку (DrawDot)
 Для имен процедур-функций используются существительные или предикаты, например, NewObject(), IsEmpty(q)
 Тип запись объявляйте только при необходимости (FooDesc for each Foo are normally not needed anymore)
 Процедуры с именами на Init обладают тем свойством, что при повторном вызове они либо ничего не делают, либо приводят к аварийной остановке. Напротив, процедуры для многократной (пере)установки состояния начинаются префиксом Set.
Примеры
	PROCEDURE InitDir (dir: Directory);
	PROCEDURE (p: Port) Init (unit, colors: LONGINT);
 Процедуры-охранники имеют те же имена, что и охраняемые команды, но с суффиксом Guard.
Пример
	PROCEDURE PasteChar;
	PROCEDURE PasteCharGuard (VAR par: Dialog.Par);
10. Пробелы
  Новый уровень отступа создается добавлением еще одного символа табуляции
 Между элементами списков <объявлений>, между фактическими параметрами и между операторами вставляется один пробел.
Хорошо
	VAR a, b, c: INTEGER;
	DrawRect(l, t, r, b);
	a := i * 8 + j - m[i, j];
Плохо
	VAR a,b,c: INTEGER;
	DrawRect(l,t,r,b);
	a:=b;
	a := i*8 + j - m[i,j];

 Ставится один пробел между именем процедуры (или ее меткой экспорта) и списком параметров в описании, но не в вызове
Хорошо
	PROCEDURE DrawDot* (x, y: INTEGER);
	DrawDot(3, 5);
Плохо
	PROCEDURE DrawDot*(x, y: INTEGER);
	DrawDot (3, 5);
 Открывающие и закрывающие ключевые слова стоят на одном уровне отступа либо записаны в одной строке
 Секции IMPORT, CONST, TYPE, VAR, PROCEDURE имеют стоят на один отступ глубже по сравнению с уровнем окружения.
 Цикл LOOP никогда не пишется в одной строке
 PROCEDURE X и END X всегда выровнены
 Если вся конструкция не помещается в одной строке, за ключевым словом не ставится описание типа или оператор
 Содержимое операторов IF, WHILE, REPEAT, LOOP, FOR, CASE стоит на один отступ глубже, если оно не помещается в одной строке.
Хорошо
	IF expr THEN S0 ELSE S1 END;
	REPEAT S0 UNTIL expr;
	WHILE expr DO S0 END;
	IF expr THEN
		S0
	ELSE
		S1
	END;
	REPEAT
		S0
	UNTIL expr;
	LOOP
		S0;
		IF expr THEN EXIT END;
		S1
	END;
	i := 0; WHILE i # 15 DO DrawDot(a, i); INC(i) END;
	TYPE View = POINTER TO RECORD (Views.ViewDesc) END;
	IMPORT Views, Containers,
		TextModels, TextViews;
	VAR a, b: INTEGER;
		s: TextMappers.Scanner;
Плохо
	IF expr THEN S0
	ELSE S1 END;
	PROCEDURE P;
	BEGIN ... END P;
	BEGIN i := 0;
		j := a + 2;
		...
	REPEAT i := 0;
		j := a + 2;
		...
11. Пример
MODULE StdExample;

	IMPORT Models, Views, Controllers;

	CONST null = 0X;

	TYPE
		View* = POINTER TO RECORD (Views.View)
			a*, b*: INTEGER
		END;

	VAR view-: View;

	PROCEDURE Calculate* (x, y: INTEGER);
		VAR area: LONGINT;

		PROCEDURE IsOdd (x: INTEGER): BOOLEAN;
		BEGIN
			RETURN ODD(x)
		END IsOdd;

	BEGIN
		area := x * y;
		IF IsOdd(area) THEN area := 1000 END
	END Calculate;

BEGIN
	Calculate(7, 9)
END StdExample.
12. Заголовок Открытого исходного кода
Модули, опубликованные под лицензией BlackBoxComponentBuilderOpenSourceLicense, включают текстовый заголовок, оформленный по следующем образцу:

(**
	project	= "BlackBox"
	organization	= "www.oberon.ch"
	contributors	= "Oberon microsystems"
	version	= "System/Rsrc/About"
	copyright	= "System/Rsrc/About"
	license	= "Docu/BB-License"
	purpose	= ""
	changes	= "
	- YYYYMMDD, nn, ...
	"
	issues	= "
	- ...
	"

**)