- PVSM.RU - https://www.pvsm.ru -
«Стандарты именование объектов БД» и «правила оформления кода» темы не новые. Так или иначе, к вопросу выработки или заимствования таких стандартов и правил приходят все команды разработчиков. При желании в сети можно найти статьи и презентации по данной теме, а так же примеры и шаблоны различных соглашений. Многие из них безусловно полезны, некоторые — практически идеальны, если бы не одна маленькая оговорка: они написаны разработчиками и для разработчиков.
К сожалению, в моей субъективной реальности разработчики являют собой лишь некую абстракцию. Эдакие фантомы по ту сторону телефонной трубки, от которых меня отделяют тысячи километров и 3 часовых пояса. Прямого доступа в их коллективный
В принципе, пожелания по оформлению и именованию у «прикладника» (администратора приложения/технолога) и разработчика на 90 процентов совпадают. Но существуют все же некоторые отличия в восприятии «читателя» и «писателя», о которых я хотел бы поговорить.
Цель данной статьи: выработать свод правил именования объектов баз данных (мне нравится термин Naming Conventions – NC, по аналогии с Code Conventions) для применения командой разработчиков программных продуктов при проектировании информационных систем на базе СУБД Oracle, удовлетворяющий следующим требованиям:
Почему именно СУБД Oracle? Мне она ближе и родней. А попытки объять необъятное с претензиями на универсальность не по моим зубам и компетенциям. В данном топике я попытался обобщить материалы статей Билла Коулэма (Bill Coulam), Стивена Ферстайна (Steven Feuerstein) и Тома Кайта (Tom Kyte) по данной теме и свой скромный опыт проектирования, разработки и эксплуатации различных информационных систем.
Те, кому лень читать про разные подходы к именованию и продираться через доводы в защиту того или иного подхода, могут просто прокрутить статью до конца, где я привел ссылку на собственный «Oracle NC»-плакат. Там же вы сможете найти другие полезные ссылки по теме топика.
Вы еще здесь? Смогли сдержаться и не начали скроллить? Поздравляю, вам достается специальный бонус: вы можете скачать «Oracle NC»-плакат [2] прямо здесь, не сходя с этого места. Дело в том, что я уже читал свою статью (да-да) и заранее предупреждаю: она громоздка и изобилует малопонятными с первого взгляда врезками-шаблонами. Воспринимать ее будет гораздо проще, имея под рукой все правила и примеры на одном листе.
Казалось бы, идея выработки NC для проекта в сфере IT лежит на поверхности. Соблюдение требований NC при проектировании и разработке, тоже задача не бог весть. Однако ж, мой опыт работы с решениями от ведущих российских разработчиков на рынке биллинговых систем для телекоммуникационных компаний говорит о том, что культура именования объектов и оформления исходного кода на деле крайне низка. В принципе, все решения, которые по долгу службы были мной изучены, можно поделить на четыре группы:
Я не хочу углубляться в анализ причин п.п. 1-3, я просто констатирую факт. Все, что я хочу – помочь сделать шаг к «мечте» п. 4. Итак, начнем.
Начнем с того, о чем следует помнить и чему следовать при разработке под СУБД Oracle:
create table "MyTable" (a number);
Короче, избегайте таких извращений.
В вопросе именования таблиц я почти полностью разделяю точку зрения Билла Коулэма. Разработанный им стандарт исчерпывающ и практически идеален, как для разработчика, так и для «эксплуататора». Я не буду приводить здесь полный перевод, остановлюсь только на основополагающих моментах.
Итак, Коулэм предлагает следующую универсальную форму именования таблицы (фигурные скобки включают обязательные компоненты, а «прямые» скобки – опциональные):
[Модуль_][Группа_]{Наименование}[_Роль]
Под Модулем (в терминах Коулэма — системная группа) понимается наименование подсистемы внутри нашей базы данных. Обычно используется сокращение в 2-4 символа. Например, таблицы модуля «Тарификатор» могут иметь префикс «TAR_», а таблицы Платежного модуля префикс «PAY_». От себя добавлю, что если разработка ведется в «чужой» схеме желательно добавлять дополнительный префикс для разделения своих и чужих объектов. Обычно я добавляю в префикс сокращенное наименование своей организации. Конечно, это удлиняет названия объектов, зато позволяет четко выделить «свои» объекты в дереве проекта. Если вас смущает такой подход, вполне достаточно добавить перед кодом модуля один символ («локальные разработчики» обычно предпочитают Х или ХХ -наследие OEBS ?!).
Группа используется для тех же целей: она позволяет группировать сущности, логически связанные между собой (обычно до 20 объектов в группе). Представляет собой так же сокращение в 2-4 символа. Использование системной и логических групп позволяет не только группировать сущности в дереве объектов, но и существенно упрощает разработку и сопровождение системы в целом. Действительно, исчезает необходимость запоминать наименования конкретных объектов, достаточно помнить аббревиатуры модуля и логической группы, а дальше подсказчик кода поможет легко найти необходимый вам объект.
С Наименованием все понятно. Это и есть фактическое название сущности. Билл Коулэм рекомендует использовать единственное число, но лично мне ближе и привычнее множественное (Стивен Ферстайн, привет!). И Стивен и Билл советуют избегать сокращений в наименованиях сущностей. Исключения — слова длиннее 8 символов.
Не всегда назначение таблицы удается выразить одним словом. В этом случае некоторые отечественные разработчики по привычке пользуются правилом, которое я про себя называю «Правилом товарного чека», когда порядок слов идет от общего к частному, от сущности к свойствам. Т.е. «Бумага туалетная», вместо «Туалетная бумага», «Огурцы маринованные», а «Паста томатная». К сожалению, в англоязычных наименованиях это чаще всего выглядит ужасно. Сравните YELLOW_SUBMARINE и SUBMARINE_YELLOW. В данном случае я не вижу смысла опираться на единый шаблон, а рекомендую использовать тот порядок, который более уместен в конкретном контексте.
Роль – по сути назначение (тип назначения) таблицы в системе. Коулэм выделяет около двух десятков ролей, но на мой вкус некоторые из них избыточны. Приведу только те, которые использую я:
В отдельный класс Коулэм выделяет таблицы, посредством которых реализуется взаимосвязь «многие-ко-многим». Для таких таблиц он предлагает следующий шаблон именования:
[Модуль_]{Имя/Код таблицы 1_Имя/Код таблицы 2}
В большинстве проектов, с которыми я сталкивался, для таких таблиц-ассоциаций разработчики использовали «значащие» имена. Сам я использую шаблон:
[Модуль_][Группа_]{Код таблицы 1_}{Код таблицы 2}
Код таблицы в данном случае представляет собой сокращенное наименование таблицы, которая участвует в связке (2-4 символа). Например, таблица, хранящая связи студентов (STUDENTS), посещающих лекции преподавателей (TEACHERS) в данном стандарте будет называться STUD_TCHR. Да, на первый взгляд выглядит отталкивающе, но со временем понимаешь удобство: с первого взгляда классифицируешь таблицу как «связку» (благодаря использованию кодов/аббревиатур вместо полных имен), сразу видишь, какие сущности связываются.
Начнем с ограничений общей длины наименования – старайтесь уложиться в 15 символов (лучше — меньше). Запас до верхнего ограничения вам понадобится для последующего именования ограничений, индексов и столбцов с внешним ключом.
В своих проектах я использую следующий шаблон:
[Код таблицы_]{Наименование столбца}[_Роль]
Код таблицы представляет собой сокращенное наименование таблицы, которой принадлежит колонка (2-4 символа). Хоть я и обозначил данный префикс опциональным, я его использую почти для всех столбцов. Исключение – «служебные» столбцы, которые хранят значение неких свойств абстрактной записи любой таблицы, а не свойств конкретного объекта (например, UPDATE_DATE, UPDATE_BY и т.п.).
Наименование столбца говорит само за себя. Отдельно хочется сказать только о правиле формирование наименования для внешнего ключа – оно состоит из кода дочерней таблицы плюс полное наименованием родительского первичного ключа.
Роль – опциональный суффикс. Обращаю внимание, что это тип значения столбца, а не код типа данных этого столбца! Чаще всего я использую следующие роли (типы значений):
Многие считают шаблон (а, конкретно, префикс в виде кода таблицы) избыточным. Однако я, имея возможность сравнивать разные подходы, выбрал для себя именно его. Приведу свои доводы:
Коулэм рекомендует именовать ограничения, используя префикс в виде полного имени таблицы, на которую данное ограничение распространяется. Я считаю такое именование необоснованным расточительством, особенно с учетом общего лимита в 30 символов на длину наименования. Поэтому стараюсь, где возможно использовать Код таблицы вместо полного имени. Таким образом, для первичного ключа получаем:
[Модуль_][Группа_]{Код таблицы}{_PK}
Здесь и далее префиксы Модуль и Группа ограничения получают в «наследство» от таблицы, с которой они связаны. Это позволяет избежать нарушений уникальности при формировании имен в больших системах, а так же удобно группировать ограничения по модулям.
Для уникального ключа, построенного на одном столбце:
[Модуль_][Группа_]{Шаблон столбца}{_UK}
Напоминаю, что шаблон столбца у нас включает Код таблицы. Таким образом, для колонки PRM_CODE таблицы UTL_PARAMS_REF уникальный ключ будет называться UTL_PRM_CODE_UK
Для уникального ключа, построенного на нескольких столбцах:
[Модуль_][Группа_]{Код таблицы_}{CОMP_UK}[_#]
COMP – в данном случае обозначает COMPOSITE (признак составного ключа), # (порядковый номер) используется если уникальных составных ключей несколько (если честно, я не могу придумать вменяемый пример для такого случая).
Внешний ключ на базе одного столбца:
[Модуль_][Группа_]{Шаблон столбца}{_FK}
Так как полное наименование столбца внешнего ключа у нас содержит Коды дочерней и родительской таблиц, то для колонки PVL_PRM_ID таблицы UTL_PARAM_VALUES внешний ключ будет называться UTL_PVL_PRM_ID_FK (ссылается на столбец PRM_ID таблицы UTL_PARAMS_REF)
Внешний ключ, построенный на нескольких столбцах:
[Модуль_][Группа_]{Код таблицы_}{COMP_FK}[_#]
Ограничение на уровне столбца:
[Модуль_][Группа_]{Шаблон столбца}{_CK}
Ограничение на уровне таблицы:
[Модуль_][Группа_]{Код таблицы_}{COMP_CK}[_#]
На просторах Интернета я часто встречал горячие обсуждения необходимости именования ограничения типа NOT NULL. Да, согласен, лениво, но если строго придерживаться концепции, то:
[Модуль_][Группа_]{Шаблон столбца}{_NN}
Индексы я обычно делю на три категории:
Индексы на базе ключей (первичного и уникального) именуются так же, как и соответствующие им ограничения:
[Модуль_][Группа_]{Код таблицы}{_PK}
[Модуль_][Группа_]{Шаблон столбца}{_UK}
[Модуль_][Группа_]{Код таблицы_}{CОMP_UK}[_#]
Индексы на базе одного столбца:
[Модуль_][Группа_]{Шаблон столбца}[_Роль]{_IDX}
Под Ролью в данном шаблоне понимается модификатор типа индекса. Коулэм рекомендует использовать следующие модификаторы:
Индексы на основе нескольких столбцов. Коулэм рекомендует следующую форму:
[Модуль_][Группа_]{Код таблицы}{_COMP}[_Роль]{_IDX}[#]
Я считаю шаблон Коулэма частным случаем и всегда стараюсь перечислить все столбцы (если при этом не нарушается ограничение по длине) в наименовании индекса:
[Модуль_][Группа_]{Код таблицы_}{Список столбцов}[_Роль]{_IDX}
Почему я ограничиваюсь модификатором COMP для ограничений, но стараюсь не использовать его для индексов? Все дело в том, что составные ограничения все-таки являются скорее исключением, чем правилом. Их обычно не очень много, да и сообщение с ошибкой об их нарушении встречаются не очень часто. Другое дело – составные индексы. Во-первых, их просто много. Во-вторых, их часто больше одного на таблицу. И, в третьих, разработчик и администратор приложения работает с ними постоянно, проверяя планы запросов.
В данной статье я рассматриваю только триггеры DML, потому что считаю, что все остальные типы относятся больше к зоне ответственности DBA, а не разработчика. Триггеры я именую по следующим правилам:
[Модуль_][Группа_]{Код таблицы}[_Цель/Роль]_{B|A|C (I|U|D)[S]}[_#]
Где аббревиатуры B, А, С (BEFORE, AFTER, COMPOUND), определяют «момент» срабатывания триггера; I, U, D (INSERT, UPDATE, DELETE) – событие срабатывания; S (STATEMENT) — определяют «уровень» срабатывания.
В своих проектах я выделяю две «типизированные» Цели (роли) триггеров:
Правила именования представлений ничем не отличаются от правил именования таблиц. Единственное пожелание — включать в наименование признак, что данный объект является именно представлением. Подходы тут могут быть разные. Я встречал данный признак в виде префикса имени. Например, V_ или даже V$, как у системных представлений Oracle. Лично я использую суффиксы:
Но вам не посоветую. Знак доллара в качестве разделителя – дело привычки. Это «якорь» для моих глаз, который позволяет отличить таблицу от представления. Объективно на данных подход я взглянуть не могу, поэтом ничего не имею против знака «нижнего подчеркивания», как у Ферстайна (суффиксы _V и _MW).
Последовательности я выделяю среди других объектов суффиксом _SEQ и рекомендую именовать по следующему правилу:
[Модуль_][Группа_]{Код таблицы | Полное наименование столбца | Цель}{_SEQ}
Код таблицы (сокращенное наименование таблицы 2-4 символа) используется для последовательностей, служащих для генерации суррогатного первичного ключа таблицы.
Наименование столбца (а у нас оно, напомню, включает код таблицы) используется для генерации значения колонки, не входящей в первичный ключ. На самом деле, это вырожденный случай, который я реально не использую. Если последовательность не используется для генерации значений первичного ключа – в наименовании я стараюсь отразить Цель данной последовательности.
Для примера, последовательность для генерации первичного ключа таблицы INTERNET_LOGINS я назову ILG_SEQ, а последовательность для генерации логина конкретной учетной записи интернет – LOGIN_SEQ.
Синонимы именуются так же, как и объекты, на которые они ссылаются
По типам, у меня нет окончательно сформированного мнения. Я встречал разные подходы к именованию этих объектов, но так и не смог до конца определиться, какой подход мне ближе. Опишу здесь те, которые не вызывают во мне негативных реакций:
[Модуль_][Группа_]{Наименование}[_Признак коллекции]T
Данный шаблон рекомендует Коулэм. Признак коллекции типа обознается символом Т. Таким образом, тип одиночного объекта всегда имеет суффикс _T, тип коллекции — _TT. Например, UTL_PARAMETER_T, UTL_PARAMETER_TT.
[Модуль_][Группа_]{Наименование}[S]_TYP
Здесь S обозначает множественное число, а суффикс TYP квалифицирует объект БД как тип. Например, UTL_PARAMETER_TYP, UTL_PARAMETERS_TYP. Это подход мне нравится менее всего, потому что признак коллекции не выделен и глаз за него не цепляется.
[Модуль_][Группа_]{Наименование}_{OBJ | TAB}
В данной нотации, если наименование объекта БД заканчивается на OBJ или TAB, то объект является типом (TAB – коллекция, OBJ – одиночный объект). Например, UTL_PARAMETER_OBJ, UTL_PARAMETERS_TAB
Правила оформления кода программных модулей я хотел бы выделить отдельную статью. Здесь приведу шаблон, предлагаемый Коулэмом. Для пакетов процедур Билл использует следующее правило:
[Модуль_][Группа_]{Цель/Назначение}[_Функцион. модификатор][_PKG]
В терминах NC Коулэма Функциональный модификатор (для меня понятнее термин Подгруппа) используется при выделении каких-то функций в отдельный пакет при рефакторинге. Скажем так, это дополнительный уровень логической группы. Например, пакет UTIL содержал функции работы с числами и строками. Его разбили на два: UTIL_NUMBER и UTIL_STRING.
При разработке в PL/SQL специалист постоянно оперирует функциями и процедурами других пакетов. Чтобы код не смотрелся громоздким, я стараюсь избегать ненужного удлинения в наименовании пакетов. Поэтому суффикс _PKG использую только в случаях, когда наименование пакета может совпадать с наименованием другого объекта схемы.
Для отдельных процедур и функций Коулэм рекомендует следующий шаблон:
[Действие_]{Цель/Назначение}
Под действием понимается глагол (GET, SET, ASSIGN, RUN), под целью – то, что необходимо сделать. Со своей стороны, я стараюсь вообще не использовать процедуры и функции вне пакетов при разработке. Кроме того, те же функции у меня часто группируются по объектам, с которыми они работают, поэтому я обычно использую шаблон
{Цель}[_Действие]
Таким образом, подсказчик кода отлично группирует процедуры по объектам: PARAM_GET, PARAM_SET, PARAM_CHECK и т.п.
Как и обещал, привожу ссылку на собственный «Oracle NC»-плакат [2].
Я, ни в коем случае, не навязываю никому свои правила и стандарты и не настаиваю на их использовании. Я просто считаю наличие NC и соблюдение его требований в команде хорошим стилем — «вежливостью» разработчика к тому, кто будет работать впоследствии с системой.
Удачи вам в ваших проектах.
P.S. Внимательный читатель безусловно заметил мой маленький обман. Первая цель статьи так и не была достигнута: далеко не все типы объектов СУБД Oracle описаны в статье и присутствуют в NC-плакате. Что же, у вас есть шанс исправить этот недочет. Вы можете скачать «исходник» [3] NC-плаката и отредактировать его под свои цели и задачи.
В статье использованы следующие источник:
Автор: Artem_7
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/news/51435
Ссылки в тексте:
[1] мозг: http://www.braintools.ru
[2] «Oracle NC»-плакат: https://www.dropbox.com/s/duqmjr4i3b962d7/Oracle%20Naming%20Convention.pdf
[3] «исходник»: https://www.dropbox.com/s/6x7ctcmc21t8peo/Oracle%20Naming%20Convention.doc
[4] Naming Convention and Code Standards: http://www.toadworld.com/cfs-file.ashx/__key/communityserver-wikis-components-files/00-00-00-00-03/Naming-Conventions-and-Coding-Standards.pdf
[5] Oracle Naming Standard: https://www.dropbox.com/s/nup7ix17e6nfz4t/Coulam%20-%20Oracle%20Naming%20Standard.pdf
[6] Ask Tom...: http://asktom.oracle.com/
[7] SQL.RU: http://forum.sql.ru/forum
[8] Источник: http://habrahabr.ru/post/207102/
Нажмите здесь для печати.