|
|||||||||
Инфраструктура тиражного проекта | |||||||||
Автор: Абдрахимов Рустам Маратович
ВведениеМного раз я наблюдал мучительный процесс, когда изначально заказной проект, сделанный под нужны индивидуального заказчика, превращался в тиражируемое решение, которое с кровью адаптировалось сначала под второго, потом под третьего заказчика: И только ближе к десятому внедрению система начинала обрастать универсальной инфраструктурой, позволяющей разработчикам при внедрении заниматься исключительно адаптацией автоматизации бизнес-процессов. Потом затевался новый проект, но инфраструктуру из предыдущего невозможно было перенести в новый, так как выдрать её из готового проекта можно было только с «мясом». На этот процесс нет ни времени, ни средств и потому всё начинало повторяться по кругу. Такое печальное положение дел породило желание создать «шаблон» тиражного проекта, в котором есть все общие модули, которые присутствуют в любом проекте, причём реализованные наиболее полно и гибко. Даже если, при наполнении этого шаблона логикой работы предприятия с конкретным видом деятельности, не понадобятся все возможности инфраструктурных элементов, их наличие совершенно не помешает и даже может способствовать незапланированному, но полезному развитию проекта в определённых направлениях. Всё вышеперечисленное начинает порождать желание иметь инфраструктуру в чистом виде, легко дуплицируемую и готовую к наполнению специфическим содержанием. Таким образом, инфраструктура является как бы общей частью всех проектов, то, что независимо от направленности приложения практически не меняется. Такое свойство имеет следствие: инфраструктура должны быть максимально полной, чтобы удовлетворить требованиям любого, даже самого экзотического бизнес-проекта. В данной статье вы не найдёте примеров конкретной реализации инфраструктуры, но здесь будут упомянуты все свойства, параметры и особенности, которые надо учесть при реализации инфраструктурных элементов. Будем исходить из того, что квалификации вашей команды достаточно, чтобы самостоятельно воплотить в жизнь идею инфраструктуры на все случаи жизни. В начале статьи будут описаны элементы инфраструктуры, которые присутствуют в каждом проекте, а ближе к концу - не обязательные, специфические части инфраструктуры. НавигацияУдобный и быстрый способ добраться до нужных действий - это желательное качество любой информационно-управляющей системы. Для тиражного проекта в отношении навигации добавляется требование адаптивности под бизнес конкретного предприятия. Бывает, что навигация имеет сетевую структуру, когда в одно и то же место можно попасть разными способами, но этот случай мы рассматривать не будем, так как тогда сложно соблюсти требование адаптивности. В тиражном проекте более всего подходит иерархическая навигация, когда каждая смысловая точка системы имеет чётко определённое место в системе навигации. Особо подчеркну, что такой подход не исключает вызов одной и той же формы из разных мест. Но об этом ниже. Самый наглядный пример реализации навигации - иерархическое меню. Как оно реализовано в интерфейсе - не имеет значение. У меню могут быть выделены первые несколько уровней (первый уровень - горизонтальные пункты, второй - вертикальные, третий и последующий - всплывающие), а может быть всё меню реализовано однотипно, например раскрывающейся структурой в выделенной области интерфейса. Главное, что в конечном (листовом) пункте меню производится вызов конкретного функционала. На этом навигация не заканчивается. Очевидно, что и далее возможен диалог с пользователем, результатом которого может быть навигация посредством вызова функционала. Функционал - есть некоторая сущность, инкапсулирующая в себе программный код и информацию о вызываемых модулях в контексте некоторых параметров. Понятно, что один и тот же модуль может вызываться из разного функционала, но, как правило, значения параметров этого модуля в разных случаях - разные. Теперь вернёмся к пунктам меню. Их наличие или отсутствие может быть не только результатом воздействия разграничения доступа (об этом ниже), но и обусловлено объективными факторами, присущими конкретной инсталляции. К примеру, одно предприятие использует мультивалютность, а другое - нет. Значит, первому нужно вызывать функциональность, связанную исключительно с мультивалютностью, а другому - это вредно. Одни заказчики используют почти все технологии своей отрасли, а другие являются монотехнологичными. Подобных примеров набирается в крупной системе настолько много, что отсутствие механизма сокрытия пунктов, веток целых разделов меню может привести к тому, что пользователи будут теряться в многотысячных и им совершенно бесполезных пунктах меню. Отсюда вывод - должен быть лёгкий и простой механизм динамического сокрытия пунктов и веток меню (то есть, доступность по условиям). Но и это ещё не всё. Очень неплохо было бы иметь механизм, позволяющий порождать несколько пунктов меню по образцу. Простой пример. Мы даём пользователям создавать технологические сценарии на подобии Work Flow. Каждая точка входа в тот или иной сценарий должна присутствовать в некотором месте иерархического меню. Желательно, что бы очередная точка входа автоматически появлялась в описанном месте сразу после того, как она объявляется доступной для использования. Ниже описывается один из возможных способов реализации вышеобозначенных требований по навигации. Создаём сущность, каждый экземпляр которой описывает прототип пунктов меню и может порождать 0, 1 или более реальных пунктов. Сущность тоже иерархическая. Основная изюминка такого описания - наличие в свойствах прототипа SQL-запроса, который выполняется в момент генерации пунктов меню. Прототип порождает столько пунктов меню, сколько строк в настоящий момент возвращает SQL-запрос. Каждый столбец SQL-запроса должен иметь алиас. При генерации пункта меню возникает столько контекстных параметров, сколько полей в текущей полученной строке запроса. Код параметра совпадает с алиасами столбцов. Замечу, что при генерации родительского пункта меню, тоже порождались контекстные параметры. Запрос во вложенном прототипе может и, как правило, должен использовать значения родительских контекстных параметров. Если параметры не переопределяются текущим запросом, то они будут транслироваться ниже по иерархии. Таким образом, SQL-запрос при генерации пунктов меню может использовать контекстные параметры всех своих родителей с любого уровня. Итак, пункт меню порождается строкой SQL-запроса прототипа, но этого недостаточно для материализации пункта меню. Ему нужно имя, номер по порядку, признак доступности (видимости и активности) и, в конце концов, код вызываемого функционала. Возможно, вам потребуется ввести ещё несколько сервисных признаков. Надо обеспечить, чтобы значения перечисленных параметров могли содержать не только константы, но и ссылки на любые контекстные параметры вверх по иерархии, начиная с текущего уровня. Необязательное, но иногда очень полезное свойство, когда даже неотображаемый (согласно соответствующему свойству) пункт меню всё же может порождать потомков. В этом случае все его потомки появляются на том же уровне, где должен был быть невидимый родитель. К примеру, на предприятиях, использующих несколько источников котировок валют, должен быть уровень в иерархии меню, выбирающий пункты-источники, внутри которых могут вызываться функционалы для работы в контексте выбранного источника (курсы валют, история, настройки). Если же предприятие всегда использует только один источник котировки, то совершенно лишним будет отображать пункт с названием этого источника и заставлять пользователя всё время раскрывать этот пункт для того, чтобы добраться до функционала работы с источником котировки валют. ПараметрыЧасто в тиражных проектах значения параметров - это единственное, что различается в том или ином внедрении. Таким образом, параметры придают индивидуальность экземпляру тиражной системы. Однако, очень многие ошибочно понимают под параметрами только глобальные установки, сужая их применимость до настроек тиражируемого софта под конкретного заказчика. На самом деле параметры могут быть очень многообразными, и мы часто используем их различное воплощение, не подозревая, что всё это можно объединить в рамках одной концепции. Для начала проведём классификацию видов параметров. а).По месту применения:
б).По способу сохранения:
в).По способу изменения:
г).По способу задания начального значения:
Теперь объединим вышеперечисленные свойства в одну сущность. У нас получится средство описания параметра для любого применения. Как же должна быть устроена эта сущность? Для начала заведём справочник параметров. Это способ описания Реальных параметров. Виртуальные параметры не имеют своего описания и порождаются в момент установки им значения. В справочнике указывается некоторое значение (для статического) или способ вычисления значения (для динамического) параметра. Для локальных параметров это будет значение по умолчанию, для глобальных параметров это, собственно, и есть их значение. Там же, в справочнике, есть указание на вариативность параметра. Может ли быть своё значение для разных пользователей и/или компьютеров и/или конфигураций, а может по ещё каким другим размерностям, или это глобальный параметр с общим для всех значением. Далее, надо иметь таблицу индивидуальных значений параметра, куда человеком (при помощи пользовательского интерфейса) или автоматизированным процессом (некоторой функцией) будут помещаться значения локальных параметров. Ну и, наконец, нужно определить виртуальную структуру, где будут храниться значения виртуальных параметров и вычисленные значения реальных параметров. Эта структура индивидуальна для каждого сеанса системы и заполняется в процессе её функционирования. Такая структура, по сути, является персональным окружением, контекстом, рабочей областью сеанса системы, может сохраняться и восстанавливаться, а также передаваться последовательно выполняющимся или ветвящимся её частям. Изменение значения в виртуальной структуре может производиться только программно, процессом или в результате вычисления динамического параметра, а также перевычисления значения динамического параметра, если изменились значения параметров, от которого оно зависит. А теперь несколько примеров параметров с указанием их места в нашей классификации:
СообщенияПрежде, чем перейти непосредственно к сообщениям, затронем тему многоязычности, тем более что к сообщениям это имеет непосредственное отношение. Если вы, хотя бы и в минимальной вероятности, планируете поставлять свой тиражный продукт в не русскоязычные страны и регионы, то на многоязыковую поддержку надо заложиться с самого начала, то есть на уровне инфраструктуры проекта, а именно:
Теперь перейдём непосредственно к сообщениям. Сообщения целесообразно выделить в отдельную сущность. Какую пользу это может принести:
Вызывать сообщения надо всегда через одну функцию, правка которой позволит изменить принципы отображения сообщений сразу во всей системе. Соответственно везде в бизнес-логике приложения, там, где надо породить сообщение (к примеру, ошибку), надо использовать эту функцию с указанием кода и, возможно, параметров сообщения. Имейте в виду, что параметры сообщения должны быть инвариантны к текущему языку. По сути - это могут быть только коды или числа. Как они попадут в текст сообщения - зависит от механизма их имплантации: от банальных шаблонов в текстах на разных языках, до использования условного микроязыка. Понятно, что если вы используете многоязычность, то пояснения к сообщениям должны быть языкозависимыми. Они уже не содержат параметров, могут быть довольно объёмными и содержать инструкции с вариантами действия при получении соответствующего сообщения. Эти тексты нужны будут тем, кто получил данное сообщение впервые и не знает, как на него реагировать. Возможность кастомизации и открытость для правки текстов сообщений связаны. К примеру, пользователь вашей системы захочет указать в тексте сообщения внутренний телефон, по которому нужно обращаться при получении данной ошибки. Напоследок дам совет: для каждого места вызова сообщения создавайте уникальное сообщение, даже если сообщение с нужным текстом уже существует. Сейчас двум разным ситуациям подходит один текст, а потом выяснится, что всё же есть разница и тексты должны немного различаться, но будет поздно что либо изменить при эксплуатации Системы. Разграничение доступаОчевидно, что в промышленных системах, немыслимо обойтись без введения ограничений на доступ к той или иной информации или тем или иным изменениям различным пользователям или группам пользователей. В противном случае убытки, понесённые предприятием из-за несанкционированного доступа и действий (умышленных и неумышленных) порой могут превысить доходы от эксплуатации Системы. Главное здесь - не переусердствовать. Неграмотная организация управлением доступом может привести к тому, что целый отдел администраторов только тем и будет заниматься, что давать и отбирать права у огромной армии пользователей. В связи с этим рекомендуется придерживаться следующих принципов:
Вот пример системы разграничения доступа, удовлетворяющей этим принципам: 1.Вводится понятие Типов объектов разграничения доступа. Это, к примеру, элементы интерфейса, пункты меню, отчёты, функционал и т.п. 2.Каждый Тип объектов права имеет набор возможных Видов прав, в отношении которых будут даваться разрешения или запреты Объектам данного типа. Это Просмотр, Изменение/Добавление/Удаление, Выполнение, Администрирование. Возможно, что для некоторых Типов объектов права понадобятся специфические Виды права, такое, к примеру, как Возможность просмотра списка объектов. Рекомендуется указывать значение права по умолчанию для данного Типа объекта. 3.Объекты того или иного типа могут иметь иерархическую структуру. Самый очевидный пример - пункты иерархического меню. Другой, менее очевидный пример - иерархия элементов интерфейса: Формы - блоки - элементы (столбцы, поля и кнопки). В этом случае права, назначенные родительскому элементу, должны распространяться на подчинённые ему элементы (если им явно не назначены другие права). 4.Пользователи объединяются в группы по интересам и ролям. Один пользователь может входить в несколько групп (например, «Ввод платежей», «Маркетинг», «Администратор отчётов», «Начальник смены»). 5.При манипулировании правами администраторы имею дело с записями, называемыми «Явными правами». Они обозначают, какой группе пользователей даётся или отбирается некоторое право на какой-то объект (или какие-то объекты) некоторого типа. Иными словами, в записи присутствуют:
6.В результате манипулирования явными правами образуются виртуальные сущности - Эффективные (вычисленные) права. Это те права, которые действуют для конкретного пользователя в отношении конкретного объекта. Алгоритм вычисления эффективного права такой:
Самая распространённая ошибка администратора при использовании данной системы разграничения доступа - попытка не мытьём, так катанием раздавать права отдельным пользователям, создавая для них персональные группы. Действовать надо по другому: Допустим, есть некоторые пользователи, которые такие же, как другие в группе, но должны иметь некоторое особое право (или его отсутствие). Создайте 3 группы. Одну для выделенных пользователей, другую для всех остальных и третью - общую для всех. Одинаковые права перенесите в общую группу, особые права назначьте группе выделенных пользователей, а группе остальных пользователей дайте права, которых не должно быть у выделенной группы. Журналирование и АудитЖурналирование событий и последующий аудит этих данных преследуют следующие цели:
Об аудите в тиражном проекте надо позаботиться заранее, чтобы в процессе разработки уже только пользоваться функциями, позволяющими фиксировать события и не заниматься построением системы аудита на ходу. Прежде всего, надо продумать структуру, сохраняющую данные аудита. Предлагается разделить фиксирование факта события и хранение данных, сопутствующие событию. Такая структура позволит хранить события разных типов. Сущность, содержащая факты событий должна иметь только общие для всех типов событий параметры - тип события, время события (желательно, как можно более точное), рабочая станция или адрес, места возникновения события и, наконец, пользователь или процесс, породивший событие. Целесообразно сущность с фактами событий сделать иерархической, так как сами события по своей природе часто зависимы друг от друга. К примеру, изменения данных в таблицах происходят в рамках выполнения некоторого функционала, а функционалы, в свою очередь, невозможны вне сессии, начало и конец которой должны быть зафиксированы. Данные же, сопутствующие событию, могут быть настолько разнообразными и часто пополняемыми, что имеет смысл создать справочник свойств событий и размещать значения свойств как детали сущности Событие. Данные аудита должны попадать в место хранения через одну функцию. Это очень облегчит процесс модификации структуры данных аудитных таблиц и принципов сохранения информации. При разработке системы журналировани и аудита следует помнить о следующем:
ИнтерфейсПринципам построения универсального интерфейса посвящена отдельная статья в этом же журнале, так в данной статье мы не будем подробно на этом останавливаться. On-Line документацияOn-Line документация, которую обычно называют Help, представляет собой контекстно-зависимый текст, разъясняющий пользователю назначение доступных ему элементов интерфейса. В обычной документации на программный продукт должны быть описаны все возможные интерфейсные элементы, возможные значения и их сочетания, все варианты и контекст использования, а также теоретически возможные действия. В отличие от этого, в контекстной документации нужно описывать только то, что пользователь видит в настоящий момент и то, что он может сейчас сделать. С одной стороны, это, вроде, облегчает задачу и автору текста и пользователю, так как автору надо меньше писать, а пользователя не загружают ненужной в данной ситуации информацией. Но это только кажется! Во-первых, всё равно придётся описать все интерфейсные элементы - если они есть, то когда-нибудь они будут доступны и, значит, потребуется их документирование. Во-вторых, необходим интеллектуальный механизм отбора полезной в текущем контексте информации из всего возможного набора. Предлагается для контекстной помощи применить метод инкапсуляции, когда информация об интерфейсном элементе или группе элементов является неотъемлемой частью элемента или группы. Конечный же текст справки будет синтезироваться в момент её вызова и состоять только из текстов, принадлежащих доступным в текущий момент интерфейсным элементам. Какие преимущества даёт этот подход:
А теперь несколько советов по организации контекстно-ориентированной документации:
Коротко об остальномВ этом разделе кратко описываются инфраструктурные элементы, которые могут присутствовать не в каждом проекте. Их упоминание - всего лишь повод задуматься об их организации для лёгкого использования во всех частях информационно-управляющей системы. Обработка событий Возможно, ваш проект должен иметь функциональность, порождающуюся и работающую в асинхронном режиме. Предусмотрите общий механизм обработки событий, выбирающий их из очереди событий, готовых к обработке. Возможно, что обработчиков может быть несколько. Тогда надо подумать об их асинхронном взаимодействии. Помещение новых событий в очередь, отслеживание их состояния, выборка очередного события для обработки, перемещение события в архив - всё это должно производиться через одну и ту же функцию, что обеспечит безболезненную даже кардинальную реорганизацию принципов хранения и выборки событий. Работа с архивами В крупных проектах, как правило, есть, что хранить долго и в большом объёме. Позаботьтесь о том, чтобы редко используемые данные могли отчуждаться от системы, но в то же время легко и быстро могли становиться снова доступными для использования. Желательно, чтобы отчуждение происходило автоматически, а попытки обратиться к отключённым данным не приходило к нештатным ситуациям, а порождало сообщение о необходимости подключить ту или иную часть архива к программе. Отчёты Разработайте общий механизм вызова отчётов. Желательно вызывать отчёты через посреднические группы, которые, в свою очередь, будут вызывать выбираемый пользователем отчёт из этой группы. Это позволит реализовать механизм лёгкого внедрения новых отчётов, разрабатываемых не только авторами Системы, но и теми, кто его эксплуатирует на местах. Не забудьте о параметрах отчётов. Принцип их организации очень похож на описанный выше механизм работы параметров системы. Прогнозирование критических ситуаций Известно, что любую нештатную ситуацию лучше предотвратить, чем потом устранять. Как правило, к сбою приводит вполне диагностируемая цепочка событий или тенденция. Если сразу выявить такую цепочку или тенденцию не удаётся, то после одного-двух сбоев уже однозначно можно. Создайте механизм, где можно, формализовав тенденции, определить критерий бесповоротности возникновения сбоя без вмешательства оператора. В таком случае система должна автоматически всеми доступными средствами оповестить об этом заинтересованный круг лиц. Периодические процессы Название говорит само за себя - это действия, выполняющиеся по расписанию или с определённой периодичностью: закрытие бухгалтерского периода, удаление устаревших данных, сбор и подготовка аналитической информации: В СУБД Oracle есть удобный механизм шедулинга, покрывающий собой всё разнообразие вариантов задание периодичности. Остаётся только создать удобный и наглядный интерфейс для создания и контроля расписания работы указываемых процедур. Справочники Справочными данными считается любая информация, хранящаяся в таблицах, где первичный ключ является текстовой строкой и задаётся человеком - оператором. Очень многие справочники по структуре похожи друг на друга и, потому, могут иметь единый способ отображения и изменения. Возможно даже создание единого виртуального реестра справочников. К примеру, можно сделать View, которое будет выбирать все таблицы, у которых имеются столбцы - CODE (первичный ключ), NAME (уникальный ключ) и NOTES (необязательное поле). Есть ещё вариант - все простейшие справочные данные держать в одной таблице, в которой есть код справочника, код элемента справочника, наименование элемента, значение, пояснение. Управление справочника в этом представлении проще, однако, такой способ затрудняет ссылки на элементы справочников средствами СУБД (внешним ключом). Адреса В проектах, где хранение адресной информации в разнообразном виде и для разного предназначения является важной частью всей системы, имеет смысл разработать стройную и полную систему адресов и адресных элементов. Она должна состоять из: Пополняемого справочника адресных элементов, типы которых конфигурируются в иерархию прямого (квартира - дом - улица - населённый пункт :) и группового (квартиры на этаже, этажи в подъезде, дома в районе, дома в участках обслуживания, дома в отделении связи :) подчинения. Пополняемого справочника свойств элементов разных типов (тип населённого пункта, тип улицы, корпус дома, код домофона в подъезде :). Ну и, наконец, сами адреса, имеющие в деталях или ссылки на конкретные адресные элементы из справочника или их текстовые аналоги (если допускается ввод элементов того или иного типа не из справочника). Автонумерация В больших проектах почти наверняка есть потребность автоматически присваивать номера документам. Эти номера почти всегда имеют строго определённый формат и формализуемые правила образования очередного номера. Ведите справочник типов автонумерации (для использования в различных типах документов). В справочнике типов указывайте шаблон, состоящий из постоянных текстовых элементов, ссылок на значения параметров и ссылок на именованные последовательности номеров. Для каждой последовательности номеров сохраняется под её именем последний использованный номер. Имена последовательностей тоже могут иметь ссылки на параметры и потому синтезироваться на ходу. При обращении к ещё не существующей последовательности она создаётся, и её номер устанавливается в 1. Пример шаблона для номера договора: ФЛ-{YYMM}/NUM4(CONTR{YYMM}). Результат: ФЛ-0812/0348. Начальная настройка Очень часто в тиражном проекте предметом автоматизации является не только деятельность предприятия, но и процесс внедрения системы на конкретном предприятии. Если разработать очень продвинутый и разветвлённый визард, который контролирует пользователя на каждом своём шагу, то процесс внедрения можно полностью или частично переложить на администратора предприятия, где происходит установка экземпляра тиражной системы. Фактически, это будет разновидность Workflow. Понятно, что движок для визарда должен опираться на формализованное представление этого Workflow. Желательно, чтобы визард начальной настройки был повторновходимым, определял точку последнего его использования и позволял откатиться на любое количество шагов. ЗаключениеЯ, конечно же, не призываю всем командам разработчиков, трудящихся над серьёзными проектами, бросить всё и начать реализовывать универсальный базис для будущих разработок. Было бы уже не плохо, если вы критически посмотрите на то, что у вас уже есть и обнаружите очень полезные свойства инфраструктурных элементов вашего проекта, реализация которых сильно поможет вашей системе упроститься, ускориться или получить конкурентные преимущества. Искренне желаю удачи! |
|||||||||
© ФОРС – Центр разработки. Все права защищены |