Привет, хабр! Решил поделиться с миром своим проектом, который делался в свободное время и был мне полезен на моей текущей работе. Ссылка на гитхаб https://github.com/simplepersonru/SimpleOntoDoc
Проект - генератор статического сайта документации для онтологической модели данных
Онтологическая модель данных — это способ формального описания предметной области, в основе которого лежат три главные вещи:
1. Классы (типы объектов, «сущности»).
2. Атрибуты (свойства этих классов).
3. Связи (отношения между классами).
Далее буду называть ее просто онтология
AI дисклеймер - при написании статьи активно использовалась нейросеть головного мозга, будьте осторожны
Мотивация
Я затачивал инструмент под внутренние (в компании) онтологические модели + CIM (IEC61970). Не вдаваясь в глубокие подробности, CIM IEC61970 это стандарт общей информационной модели, который описывает компоненты энергосистемы (трансформаторы, линии, выключатели, ...) в виде онтологии. Но на выходе получилось довольно таки общеприменимо (на мой взгляд).
Коллеги пользовались ontology.tno.nl, потому что чем-то надо пользоваться, не в rdf/xml файле ведь искать все эти перепитии, связи и свойства. Я тоже иногда пользовался. Но во первых он ссылается на онтологию международной версии этого стандарта, а в российской ГОСТ-овской версии есть существенные изменения: чего-то нет от международной версии, много всего своего специфичного. Поэтому хотелось иметь именно документацию актуальную для нас, но ничего подобного в публичном доступе не было, поэтому нужно делать свое
Как это выглядит
Рассмотрим на примере онтологии из примера в репозитории, которая опубликована в виде статик сайта документации. По совместительству, это онтология CGMES 3.0.0 (CIM) от ENTSO-E, т.е. ближе к международному варианту https://test-ontology.simpleperson.ru/
Нас встречает главная страница. "Примеры классов" и "Примеры свойств" снизу можно сказать заполняют эфир, на главной странице особо нечего показывать. Плиточки Classes, Enums, Primitives, Data Types, Compounds имеют общий шаблон с табом в хедере Entities, только плиточка сразу применяет свой фильтр (своего типа), а в Entities вперемешку. Плиточка Properties аналогична табу сверху Properties. Также в хедере работает регистронезависимый поиск по именам и описаниям.
Главная страница

Рассмотрим таб Entities, с шаблоном, аналогичным вышеупомянутым плиточкам. Здесь просто таблица всех сущностей с поиском, который будет сразу сокращать количество вариантов в таблице. Каждая строка кликабельна и ведет к отдельной странице соответствующего класса.
Таб Entities

Рассмотрим страницу отдельного класса на примере PowerSystemResource. Сверху видим описание, а далее диаграмму.
Для каждого класса делается диаграмма, в которой видно всю иерархию наследования плюс связи рассматриваемого класса (но не связи родителей, иначе была бы каша). Каждый узел кликабелен и ведет на страницу соответствующего класса. Навигацию можно осуществлять мышкой и колесом мыши, для этого используется js библиотека panzoom.
Далее таблица свойств, где перечислены все свойства рассматриваемого класса. В колонке ID свойства кликабельны и ведут к отдельной странице соответствующего свойства. Справа небольшой блок сводки о классе и навигации относительно него
Ниже таблицы свойств расположена таблица ссылок. В этой таблице видно, для каких свойств каких классов, рассматриваемый класс является типом данных. Особенно широко эта таблица заполнена для примитивных классов (Integer, Boolean, ...), например видно что в схеме 137 свойств типа Boolean
Ниже таблицы ссылок - таблица дочерних классов. В этой таблице видно все классы, для которых рассматриваемый является базовым классом.
Страница PowerSystemResource

Рассмотрим таблицу отдельного свойства на примере PowerSystemResource.Controls
Здесь немного информации - описание, блок информации о свойстве и немного навигации справа.
Страница PowerSystemResource.Controls

Итого можно шустро перемещаться по "графу" онтологии, много кликабельных связей, есть диаграммы и поиск.
Как можно применить
Приблуда может быть полезна, если существует некая доменная область, сущности которой связаны между собой, имеют свои свойства, наследование, агрегацию, композицию... и прочие вещи, присущие UML диаграммам / набору классов. Тогда описав эту доменную область в нужном текстовом формате (чтобы SimpleOntoDoc понял), можно получить красивую документацию с множеством ссылок между сущностями, поиском, таблицами связей и т.д, все что было описано в главе Как это выглядит
Например, представим себе некий сервис, который содержит в себе 50 доменных классов, у которых свои свойства, кто-то является родителем для другого, третий наследуется от четвертого и т.д. Я уточню, что это не просто 50 каких-то произвольных class из кода, это бизнес-сущности, доменные сущности. Это (по хорошему) общий язык между разработчиками сервиса и аналитиками + постановщиками (ТЗ-писатели).
Как обычно такое описывается? Наверное есть корпоративная wiki, в которой есть ТЗ на этот сервис, наверное там есть глава с терминами, глава с тем какие свойства в окошках ГУИ мы увидим для конкретных сущностей и так далее. Ну и конечно же описание бизнес логики, как эти сущности между собой взаимодействуют при выполнении различных функций системы.
Вместо этого я предлагаю завести в git репозитории сервиса, или отдельном (про спецификации), файл типо такого (на самом деле форматов может быть больше, об этом в главе Что можно улучшить), соответственно его изменения будет удобнее отслеживать. И на CI, по его изменению, будет собственно развертываться статик сайт документации сервиса, где будет описана собственно вся эта онтология в удобном формате сайта-документации.
При этом ТЗ понятное дело никуда не девается, но там можно сосредоточиться на описании логики, а онтология отдельно.
Потенциально можно и что-нибудь кодогенить на базе этого файла, если мы предполагаем что в нем точка истины по части сущностей сервиса, экспортный формат + парсер к нему, сами классы в нужном языке программирования воссоздать и тд, но это уже тема другой статьи
Стек
C# / .Net 9 Для пет проектов, я почти всегда выбираю C#, личное предпочтение, удобство инфраструктуры и так просто сложилось годами. Для данной задачи можно было бы выбрать почти любую популярную технологию
PlantUml Для рендера UML диаграмм классов (и их связей), которыми я приправляю каждую страничку конкретного класса, использую plantUml. Во время выполнения скрипта публикации результирующего сайта (готовый контейнер на базе nginx), я поднимаю plantuml-server и затем в самом приложении шлю запросы на его сетевой адрес для обработки рендера диаграмм.
RazorLight Щас вот смотрю и честно говоря не знаю так ли он мне нужен :D. Изначально я слышал, что есть некий Razor шаблонизатор в стандартной поставке от microsoft и я понимал что это примерно как jinja в python или inja в C++, но я никогда этим не пользовался, поэтому в своей основе попросил примеры у ИИ-шки и дальше их руками развивал, оставляя работоспособными, а нейронка взяла и заиспользовала библиотеку RazorLight. Вот так и появляются лишние зависимости...
Bootstrap 5 Для фронтенд части соответственно. Я на этом птичьем языке разговаривать стараюсь поменьше - меня тошнит от написания и частых взглядов на 4-7 вложенных друг в друга div для отрисовки какой-нибудь карточки, поэтому эту часть я тоже делал с ИИ-шкой, не сильно включая мозг.
Аналоги
Существуют и меня в какой-то степени не устраивают.
ontology.tno.nl
Как готовые примеры статических сайтов документаций конкретных онтологий.
главный минус - я не смог у них найти в общем доступе сам инструмент, которым они сделаны, т.е. получить аналогичные для своих онтологий непонятно как
субьективно не понравился дизайн всего
Widoco
Пример их документации онтологии.
Мне не понравилось что все делается на одной странице. Для больших онтологий (например 400 классов) это не очень удобно
Есть некоторая лишняя информация и нет некоторой нужной мне
субьективно не понравился дизайн всего Пример их документации онтологии.
Ontospy
Пример их документации онтологии.
На самом деле с некоторым допилом под себя именно этот вариант я бы и взял xD. Но сильно глубоко смотреть аналоги я начал только сейчас, когда начал писать статью, учитесь на моих ошибках, не зная броду не суйся в воду. Но не жалею потраченного времени (3-4 плотных вечера), т.к. мое решение мне тоже нравится (в основном - визуально)
Без доработок в любом случае бы не обошлось, потому что я искал не чисто owl или rdf или еще некий SHACL, а что-то попроще, что хорошо ложилось бы на классы из языков программирования, т.к. хочется описывать онтологию и придерживаться ее при разработке продукта. А вышеуказанные форматы допускают очень много вольностей в описании сущностей, будто бы больше чем может себе позволить язык программирования C++, либо возможны сложности с интерпретацией этого.
Что можно улучшить
Перевод некоторых строковых литералов из каркаса сайта на другие языки и выбор опции языка при генерации
Список классов отображать не списком, а деревом, в котором видно наследование (как например в Ontospy)
Больше входных форматов
Когда я начинал, я думал что получится взять за основу какой-нибудь rdf/XML формат, только его парсить, и наверное любая предметная область будет им описываться, потому что им описывается CIM (например CGMES от ENTSO-E). Но в реальности все не так, где-то owl, где-то xmi (один из вариантов экспортного xml формата из ПО Enterprise Architect для построения онтологий), где-то вообще не описано в виде подобного формата и существует просто pdf документ (например ГОСТ) с обычной структурой текстового документа: Главы, абзацы, предложения, ... Т.е. извлекать оттуда информацию по некой предопределенной схеме, как в случае конкретных форматов, упомянутых выше, сложнееПоэтому для использования проекта SimpleOntoDoc необходимо либо руками описать json файл со всей необходимой информацией (как например тут), либо написать на питоне функцию преобразования из интересующего вас формата в набор классов из model.py (используя API этих классов), а затем экспортировать в 1 json файл (используя метод export у класса Schema) и подать на вход генератору статик сайта SimpleOntoDoc. Со временем в проекте может прирастать количество таких обработчиков для различных входных форматов.
Больше возможностей по ограничении свойств. min max для чисел, min max длина для строк, ограничительный RE паттерн для строк и т.п.
Больше возможностей по разметке классов и атрибутов какой-то заранее неизвестной мета-информацией, которая может быть специфична только конкретному экземпляру онтологии. Соответственно иметь и способ в обобщенном виде показывать эту информацию в документации, не теряя лаконичности
Пока писал статью, подумал что было бы неплохо на любой странице конкретного класса или свойства иметь # разделение внутри страницы на разделы, чтобы на них удобнее было ссылаться
Внимание!
Спасибо за внимание
