Нотация_DeeProSoft_1.0Test2

advertisement
ООО «DeeProSoft»
www.deeprosoft.com
НОТАЦИЯ DeeProSoft
(Ревизия от 15 февраля 2011 г.)
© Малых Д.А., Дейнего В.М.,
Коротков А.В. Шайдуров А.Г.
Список изменений
13.01.2010 V 1.0 Test1
15.01.2010 V 1.0 Test2
19.01.2010 V 1.0 Test3
15.02.2011 V 1.0
Раздел 1.
Программные модули
1.1. Именование программных модулей
Все имена программных модулей должны иметь следующий вид:
<Название модуля>.<расширение>
Например, существует программный модуль визуализации графа. Программные модули к нему
относящиеся должны иметь вид:
GraphVis.h
GraphVis.cpp
GraphVis.lib
GraphVis.dll
…
1.2. Предотвращение коллизий включений.
Для предотвращения коллизий включения требуется применять одну из следующих техник.
Техника 1. (Применима для кросс-платформенных приложений).
В начале каждого заголовочного файла ( *.h ) должны иметься строки:
#ifndef _<имя модуля>_H
#define _<имя модуля>_H
Имена проекта и модуля пишутся заглавными буквами. В конце файла должна присутствовать
следующая строка:
#endif // _<имя модуля>_H
Для примера заголовочный файл модуля визуализации графа будет выглядеть следующим образом:
#ifndef _GRAPH_VIS_H
#define _GRAPH_VIS_H
…
<код модуля>
…
#endif // _GRAPH_VIS_H
Техника 2. (Применимая только в Visual Studio и Windows проектах)
В начале каждого заголовочного файла ( *.h ) вставляется:
#pragma once
1.3.1. Именование функций
Все функции начинаются с заглавной буквы. В имени не допускаются символы подчеркивания,
каждое новое слово в имени начинается с заглавной буквы.
Все функции во всех программных модулях, должны именоваться по следующим правилам:
<возвращаемое значение> <имя функции>(<параметры>);
Например, функция генерации случайного числа будет иметь следующий вид:
int GenerateRandomValue();
Указатель на функцию должен именоваться следующим образом:
<возвращаемое значение> (*p<имя функции>)(<параметры>);
Исключение
Если необходимо соблюдать название (прототип функции) для использования функции в других
библиотеках или еще где-либо, то правило можно нарушить.
1.3.2. Именование методов классов
Для public методов класса действует соглашения пункта 1.3.1., для private и protected методов так же
действует правило предписывающее начинать имя метода с символа подчеркивания «_».
private:
<возвращаемое значение> _<имя функции>(<параметры>);
public:
<возвращаемое значение> <имя функции>(<параметры>);
1.3.3. Именование полей структур и перечислений
Поля структуры именуются по тем же правилам что и переменные см. пункт 1.5.
Перечисления именуются заглавными буквами по следующему правилу:
enum E_<имя перечисления>
{
<префикс перечисления>_<имя поля 1> = 0,
<префикс перечисления >_<имя поля 2>,
…
};
Имя перечисления и его полей пишутся заглавными буквами, для разделения слов необходимо
использовать подчеркивание. Префикс перечисления для полей перечисления определяется на
основе первых букв слов имени перечисления.
Например:
enum E_BATCH_MODE
{
BM_AUTO = 0,
BM_DISABLED,
BM_ENABLED_UEP,
BM_ENABLED_UER
};
1.4.1. Текстовые пояснения в программных модулях
В начале каждого программного модуля следует оставлять комментарий следующего вида:
/**
\author
\version
\date
\brief
<имя автора>
<major>.< minor> [доп. обозначения]
<дата последних изменений>
<краткое описание>
[полное описание]
[
Далее опционально дополнительные параметры см. раздел 1.4.4.
\todo
<текст>
…
]
*/
Пример правильного пояснения в заголовочном файле:
/**
\author
\version
\date
\brief
Shestakov Mikhail aka Mike
0.9 Beta
15.02.2008 ©Shestakov Mikhail
Database bridge.
Provides connection between SQLite and common engine database
interfaces.
\bug
\todo
*/
Possible memory leaks.
Make logging for all routines.
1.4.2. Текстовые пояснения классов, интерфейсов и перечислений
Пояснения классов необходимо писать только для тех, которые будут использоваться сторонними
разработчиками, либо являются экспортируемыми из библиотеки. Пояснять надо как сами классы,
так и все их поля.
Внимание: Каждый метод интерфейса, равно как и сам интерфейс, должен иметь описание всегда.
Пояснение класса или интерфейса производится следующим образом:
/**
<краткое описание>
[полное описание]
Далее опционально дополнительные параметры см. раздел 1.4.4.
*/
Пояснение полей производится следующим образом:
/**<краткое описание>
[полное описание]
\param<тип параметра> <имя параметра> <описание>
\return <описание>
[\see <имя функции>]
*/
<метод>
Примечание: <тип параметра> может быть [in], [out] и [in, out].
Примеры:
/**a normal member taking two arguments and returning an integer value.
\param[out]
iValue an integer argument.
\param[in]
cpTxt a constant character
pointer.
\return The test results
\see TestMeToo()
*/
int TestMe(int &iValue, const char *cpTxt);
/**
A constructor.
A more elaborate description of the constructor.
*/
Test();
Перечисления поясняются следующим образом:
/**
<краткое описание>
[полное описание]
*/
enum E_<имя перечисления>
{
<имя поля> = 0,
<имя поля>
/**< <краткое описание> */
/**< <краткое описание> */
};
Например:
/** An enum.
More detailed enum description.
*/
enum E_TEST_ENUM
{
TE_VAL1 = 0,
TE_VAL2,
/**< enum value 1. */
/**< enum value
2. */
TE_VAL3
/**< enum value
3. */
};
Поля классов, если они являются переменными, поясняются следующим образом:
/**
<краткое описание>
[полное описание]
*/
<тип и имя переменной>
или
<тип и имя переменной> /**< <краткое описание> */
Например:
/**
a public variable.
Details.
*/
int iPublic_var;
или
int iPublic_var; /**< a public variable. */
1.4.3. Текстовые пояснения дефайнов, типов и глобальных переменных
Для дефайнов, типов и глобальных переменных действуют следующие правила:
/**
<краткое описание>
[полное описание]
*/
Пример:
/**
A macro that returns the maximum of \a a and \a b.
Details.
\warning Not good style to use it.
*/
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
1.4.4. Дополнительные параметры в текстовых пояснениях
В любых текстовых пояснениях при необходимости допускается использование следующих
дополнительных параметров:
\example <filename>
\include <filename>
\remarks <txt>
\todo <txt>
\bug <txt>
\warning <txt>
\note <txt>
и т.д. на усмотрение программиста.
1.5. Именование переменных
Для всех переменных, которые являются полями классов, параметрами функций или глобальными
переменными действует следующие правило: Именование переменной всегда начинается со
строчной буквы, каждое новое слово начинается с заглавной буквы, использование символа
подчеркивания не допускается.
Переменные, которые передаются в качестве параметров в функцию, являются свободными
глобальными переменными или полями класса public, должны именоваться следующим образом:
<обозначение тип> [идентификатор типа]<имя переменной>
Переменные в private и protected начинаются со знака подчеркивания и именуются следующим
образом:
<обозначение тип> _[идентификатор типа]<имя переменной>
Примеры:
private:
int _maxWidth;
public:
int width;//Не рекомендуется
int iWidth;//Рекомендуется
char *pcTxt;
MyClass *&prTest; //Такое тоже допускается
Локальные переменные внутри функций именуются таким же образом, как переменные
передающиеся в качестве параметров функции, но они всегда именуются только строчными буквами,
слова разделяются при помощи символа подчеркивания «_». После идентификатора типа также
ставится знак подчеркивания.
<обозначение тип> [идентификатор типа]_<имя переменной>
Примечание: Если идентификатор типа отсутствует, то символ подчеркивания не ставится.
Примеры:
int max_width;
uint16 ui16_value_1;
int i_width;
float *pfArray;
Примечание1: Идентификатор типа используется на усмотрение программиста, рекомендуется
использовать для редко встречающихся типов(например uint16 ui16MyValue), настоятельно рекомендуется
для ссылок и всегда для указателей.
Примечание2: Допускается использование счетчиков циклов без идентификатора типа(например, int i, j, k, l,
m, n).
Таблица 1. Идентификаторы типов переменных
Тип
Идентификатор
Тип
Идентификатор
int
i
unsigned
u
long int
short int
i32
i16
(long)
(short)
float
f
double
d
char(если byte)
bt
bool
b
char/wchar
c/wc
class
cl
<тип>*
p
enum
e
struct
st
string
str
&
r
array
a
typedef
t
Примечание: Идентификаторы типов группируются по мере того, как они встречаются в коде, кроме
идентификаторов p и r, они имеют более высокий приоритет и должны ставиться первыми.
Таблица 2. Обозначения типов переменных
Тип
Обозначение
Тип
Обозначение
int
int
short
int16
long
int32
__int64(long long)
int64
char
byte
char
char
wchar_t
wchar
bool
bool
float
float
double
double
Примечание: Для всех типов(кроме bool, float и double) существую unsigned типы начинающиеся с префикса u.
Например: uint16.
1.6. Именование переменных с модификаторами
Правила данного пункта не относятся к константам передающимся в качестве параметров функций.
Таблица 3. Префиксы модификаторов
Тип
Обозначение
const
c_
static
s_
volatile
v_
mutable
m_
Примечание: Префикс модификатора имеет более низкий приоритет чем префикс «_», указывающий что
поле класса является private.
Способ именования переменных с модификатором:
<обозначение тип> <префикс модификатора>[идент. типа]<имя переменной>
Константы, как глобальные переменные всегда именуются либо через ключевое слово const, либо
через определение их в предалах enum. Для enum'ов исползуются свои правила см. пункт 1.3.3.
Глобальные константы всегда именуются большими буквами. Для них префикс модификатора не
используется, равно как префикс определяющий их тип. Никогда глобальные константы не
определять через директиву препроцессора #define.
Примеры:
Глобальная константа:
const float PI 3.141592654f
Локальные константы:
const float c_f_pi 3.141592654f
static const int sc_number 5
Поле класса:
private:
const uint _c_uiMoveSpeed;
Иницализировать константы класса необходимо в списке инициализации класса.
Примечание: Допускается в именовании констант проводить несложные математические вычисления, но
только в том случае, если это будет в Compile Time.
1.7. Именование классов, структур, типов и интерфейсов
Все классы должны именоваться следующим образом:
С<имя класса>
Если же класс реализует абстрактный интерфейс, то его необходимо именовать следующим образом:
I<имя интерфейса>
Структуры должны именоваться следующим образом(это же правило действует для типов
(typedef'ов)):
T<имя структуры>
Первая буква имени класса, интерфейса или типа всегда заглавная.
Например:
interface IEngBaseObj;
class CBitmapFont;
typedef CDelegate0 <void> TDelProc;
1.8. Именование макроопределений
Все макроопределения необходимо именовать заглавными буквами.
Пример:
#define LOG(txt, type) LogEx(string(txt).c_str(),type,__FILE__,__LINE__)
После ветвлений макроса #else или #elif необходимо пояснять какое ветвление закрывает
деректива(см. пример).
Примеры:
#define
")").c_str()
MODULE_VERSION
("Beta1("+string(__DATE__)+
Или
#if defined(_WIN32)
#include <Windows.h>
#define ENGINE_USE_COM
#elif defined(_WIN64) //_WIN32
#error Win64 not implemented yet.
#else //_WIN64
#error Unknown platform.
#endif
Макроопределения должны только сокращать запись вызова функции какого-либо класса, но, не в
коем случае, не быть самостоятельными функциями!
Раздел 2.
Элементы объектно-ориентированного программирования
2.1. Обязательные элементы класса.
1.
2.
Конструктор.
Деструктор.
2.2. Дополнительные требования к классам.
Использование public переменных в полях класса допускается только в крайних случаях, когда
это гарантированно безопасно, во всех остальных необходимо реализовывать методы типа int
GetValue(); и void SetValue(const int value);.
2.4. Требования по объектно-ориентированной оптимизации
Все простые классы, в которых из идей объектно-ориентированного программирование применяется
только перегрузка функций, и отсутствуют наследование и полиморфизм, требуется объявлять как
структуру (struct), и не в коем случае не как класс (class).
Раздел 3.
Концепции оформления кода программ
3.1. Концепция константных переменных
Все переменные, которые передаются в функцию и не изменяются в ее теле должны объявляться
константными:
void GenerateRandomArray(const int *ipArr, const int iLength);
3.2. Концепция константных методов
Если метод класса не меняет значений полей данного класса, то этот метод должен объявляться как
константный.
Пример:
class CSimple
{
public:
int *ipArr;
public:
void Print() const
{
if (ipArr) printf(“%d\n”, *ipArr);
}
};
3.3. Концепция форматирования кода
Для удобочитаемости программного кода следует расставлять отступы в следующих случаях:
1.
Вокруг знаков: «+», «–», «*», «/», «=», «==», «!=», «&», «&&», «|», «||», «^», «<», «>» и
их комбинаций
2.
В тернарном операторе «(<условие>) ? <при истине> : <при ложи>;»
3.
Перед и после символов «(», «)», «[» и «]» пробелы не ставятся.
Функции с длинным объявление следует разбивать на несколько строк следующим образом:
template ...
inline …
спецификатор dll (если необходим)
тип возвращаемый функцией
имя функции, тип и имя первого параметры
типы и имена остальных передаваемых параметров
Пример
template <class T>
inline
__declspec(dllexport)
const DataPool::CLineElement&
DataPool::CopyNodeDP(DataPool::CLineElement* clpDest,
DataPool::CLineElement* clpSource,
DataPool::CLineElement* clpRootD,
DataPool::CLineElement* clpRootS);
3.4. Концепция совпадающих переменных
Если функция класс принимает параметр и инициализирует ими приватные поля класса, то имена
параметров должны совпадать с именами полей класса.
Пример:
void СPlane::Set(const TVector stNormal)
{
_stNormal = stNormal;
}
3.5. Концепция краткости оператора if
Для удобства чтения кода в операторе if более краткую часть следует оформлять в основной ветке.
Более длинная часть кода программы заключается в ветку else. Пример кода
if (f < 4)
f++;
else
{
/// много кода
}
3.6. Сравнения с константой на равенство
При сравнении переменной с константой на равенство требуется писать константу первой, как на
примере ниже:
if (DF_NULL == pPointer)
…
3.7.
Концепция отступов для соблюдения структуры программ
Обязательно соблюдать структуру программ. Отступ – это один Tab. Стандартный Tab – 4 пробела.
Запрещается заменять Tab на 4 пробела. Приведенная размерность нужна для настройки MS Visual
Studio и других IDE.
Раздел 4.
Исключение из кода программ магических чисел и hard-coded
включений
4.1. Исключение магических чисел
Никогда! не писать в коде конструкций типа:
if (fX < 0.000001f) then …
В данном случае 0.000001f признается магическим числом и должно быть исключено. Если у Вас
появляется необходимость использовать здесь какое-то число, подумайте:
1.
Быть может, есть такая определенная константа, если ее нет, то возможно ее стоит
определить.
2.
Быть может, стоит передавать это значение как параметр функции.
3.
Быть может, стоит хранить это значение как член класса и загружать из файла
конфигурации.
4.
Быть может, есть еще какие-нибудь выходы.
Как бы там ни было, но магических чисел в коде быть не должно! К таковым относятся и «магические
строки», которые в идеале должны быть вынесены в файл языкового словаря и подгружаться оттуда
по символьным константам.
4.2.
Hard-coded включения
Под hard-coded включениями понимаются различные элементы логики программы, которые в
данном месте нарушают универсальность программы. Это могут быть
1.
Логика программы, которая по идее должны быть в скриптах.
2.
Более высокоуровневая логика, которая реализуется в вышележащих проектах.
3.
Уже реализованный в виде метода какого либо метода класса код (изобретение
велосипеда).
Hard-coded включений в коде быть не должно. Если они появляются – значит Вы плохо подумали.
Раздел 5.
Обеспечение целостности модулей системы
5.1. Обеспечение внутренной целостности типов
Никогда в модуле системы не должно присутствовать типов, которые не имеют отношения к данной
системе и ее функциям. Простой пример, в библиотеке математики, в определениях классов вектора
не должно присутствовать векторов API DirectX.
Раздел 6.
Использование стандартных библиотек
6.1. STL
6.1.1. Траверс контейнера
Всегда осуществлять траверс контейнера (если нет другой острой нужды, но тогда – как минимум
надо посоветоваться с техническим директором) с использованием итераторов. Или ranged-based for,
за исключением ситуаций, когда индекс необходим не только для перебора.
6.1.2. Использование типов
При работе с stl необходимо пользоваться типами stl, например size_t.
Раздел 7.
Общие советы
7.1. Не изобретайте колесо – пользуйтесь библиотеками.
7.2. Не верьте в чудеса; разберитесь, что делают ваши библиотеки, как они это делают и какова цена
их использования.
7.3. Когда у Вас есть выбор, отдавайте предпочтений стандартной библиотеке.
7.4. Не думайте, что стандартная библиотека идеально подходит для решения всех задач.
7.5. Пользуйтесь string вместо char*.
7.6. При добавлении элементов в контейнер STL пользуйтесь push_back и back_inserter.
РАСШИРЕНИЕ НОТАЦИИ НА
ДРУГИЕ ЯЗЫКИ ПРОГРАММИРОВАНИЯ
Следует отметить тот факт, что перечисленные ниже рекомендации только дополняют основные
положения нотации. Поэтому основные положения нотации действуют и в других языках, если в
расширении не сказано обратное.
Download