Привет, Хабр.

Этим постом продолжается цикл публикаций о проекте ОС «Сивелькирия». В первой статье цикла было дано общее описание концепции, во второй объяснялось, зачем это надо и в каком виде продукт сможет увидеть свет, в третьей тезисно описывались архитектурные решения. Поскольку многие комментаторы поднимали вопрос об удобстве разработки под данную ОС, настоящая статья призвана осветить эту тему.

Процесс разработки ПО


Процесс разработки ПО под «Сивелькирией» отличается от такового под другими ОС (Windows, Linux, Android и т. д.), поскольку разработчики во всех случаях готовят общие компоненты, конкретный сценарий использования которых на момент разработки неизвестен. Иными словами, разработка ведётся так, словно во всех случаях разрабатываются библиотеки и никогда — приложения.

Ни один модуль не может взять на себя несвойственные ему функции. Ни один модуль не может жёстко требовать или неявно предполагать, что он будет взаимодействовать именно с тем модулем, который подразумевал разработчик или с которым он был протестирован при разработке. Таким образом, модуль заведомо не имеет зависимости от версии любого другого модуля, что предотвращает возникновение проблемы ада зависимостей. Ещё раз подчеркнём, что в рамках «Сивелькирии» происходит отказ от парадигмы приложений, в том числе — как программ, состоящих из заранее определённого набора модулей.

При этом модуль может определять, через какие интерфейсы он производит взаимодействие с другими модулями. Кроме того, он может требовать и рекомендовать, чтобы для модуля-контрагента проходили конкретные тесты, представленные в центральном репозитории. От модуля не требуется всегда использовать последнюю версию каждого интерфейса — он может использовать любую поддерживаемую версию, а приведением версий занимается операционная система.

В том, что касается языков и сред, «Сивелькирия» предоставляет ту же гибкость, что и другие операционные системы. Модуль может содержать как машинный код, так и байт-код или интерпретируемый код. При этом для разных типов кода используются разные исполнители, сами являющиеся модулями. Их задачей является обеспечение выполнения кода модуля и прохождения вызовов и данных через его границы, а также выполнение необходимого обслуживания (например, уборки мусора). Благодаря такому подходу планируется поддержать большое количество языков (как интерпретируемых, так и компилируемых) и сред. В то же время, ограничения, установленные операционной системой, применяются к модулю независимо от языка и способа загрузки, так как любой исполнитель в конечном итоге взаимодействует с операционной системой через вызовы интерфейсных методов, разрешения для которых контролируются универсальным образом.

Концепцию динамических библиотек в «Сивелькирии» практически полностью заменяет концепция модулей. Модули, распространяемые совместно, могут при необходимости выносить часть кода в общую библиотеку, однако ни один другой модуль, не входящий в данный комплект поставки, не сможет получить к ней доступ. Проблема поиска общей библиотеки также решается тем, что во всех случаях используется именно та библиотека, которая входит в комплект поставки. Любые другие взаимодействия с общим кодом происходят через систему модулей.

Организация взаимодействия разработчиков


Очевидно, что такая структура операционной системы требует особого подхода к организации взаимодействия разработчиков модулей с разработчиками операционной системы: в высшей степени наивно было бы полагать, что разработчики операционной системы смогут за один раз составить набор интерфейсов, покрывающий все будущие способы применения устройств под управлением данной ОС. Напротив, организация всеобщей совместимости требует непрерывного двустороннего сотрудничества между разработчиками ОС, предоставляющей интерфейсы и прототипы, и разработчиками ПО, использующего их.

Каждый интерфейс характеризуется номером версии, состоящим из старшей и младшей частей. С увеличением младшей версии внутри одной старшей версии интерфейс может дополняться новыми сущностями, однако удаление или переделка уже существующих сущностей не допускается. Новые старшие версии выпускаются тогда, когда интерфейс требует глубокой переработки.

Все младшие версии внутри одной старшей версии совместимы между собой. В случае совпадения фактически реализуемого объектом и ожидаемого вызывающим контекстом номеров младших версий такая совместимость очевидна. Если фактически используемый объект реализует более высокую младшую версию интерфейса, чем ожидает вызывающий контекст, то часть данных и функций, предоставляемых интерфейсом, попросту не используется. Если же объект реализует более низкую младшую версию, чем ожидается, то при обращении к фактически не реализованным сущностям вызываются обработчики по умолчанию, работа которых основана на данных и алгоритмах, уже представленных в более ранней версии интерфейса. Так, если более поздняя младшая версия интерфейса «Статья» добавляет к доступным через интерфейс данным поле «Текст рекламы», которое в некоторых изданиях используется, например, на баннерах, открывающих доступ к полному тексту статьи, то для совместимости обработчик по умолчанию может использовать в качестве такого текста первый абзац или первое предложение полного текста. Другой подход состоит в возврате специальных значений (исключений) «Не реализовано» при обращении к недоступным данным, что перекладывает обязанности по обработке подобных ограничений на вызывающий контекст.

Старшие версии интерфейсов могут быть как совместимы между собой, так и нет. Например, в гипотетическом случае перехода от рассмотрения положения точек на экране в декартовых координатах к использованию полярных координат интерфейс «Положение точки 1.0» использует декартовы координаты, тогда как интерфейс «Положение точки 2.0» содержит представление в полярных координатах. Поскольку между двумя этими представлениями существует взаимно однозначное соответствие, операционная система всегда может выполнить пересчёт координат в случаях, когда фактически используемая версия интерфейса отличается от ожидаемой.

К сожалению, подобная маскировка фактического номера версии возможна не всегда. Например, если интерфейс «Мелодия» в версии 1.0 описывает произведение в виде партитуры, а в версии 2.0 — в виде аудиозаписи, то между ними нет взаимно однозначного соответствия: одну и ту же мелодию можно сыграть на разных инструментах, в то время как запись может содержать звуки, которые нельзя выразить на нотном листе. Аналогично, если интерфейс «Заметка» изначально разрабатывался для текстового содержимого, а затем был адаптирован для рукописного ввода, перевести одно в другое будет сложно: заметка, написанная от руки, может содержать рисунки, тогда как в тексте могут присутствовать скрытые символы (например, мягкие переносы). Наконец, карты городов традиционно изображаются в двух измерениях, однако для мегаполисов с многоуровневыми развязками этого всё чаще становится недостаточно; если в будущем будет совершён переход от двумерных карт к трёхмерным, получить из одной другую будет не так-то просто.

Схожие правила применяются при изменении версий прототипов модулей. Поскольку основная задача модуля состоит в реализации интерфейсов данных, мы не будем останавливаться на этом подробнее.

Распространение интерфейсов происходит централизовано через репозиторий, поддерживаемый командой разработчиков операционной системы. Подгрузка новых версий осуществляется при обновлении операционной системы. Существование других репозиториев, распространяющих интерфейсы, не допускается, поскольку оно поставит крест на всеобщей совместимости, являющейся основной целью создания ОС «Сивелькирия». Единственным исключением могут быть внутрикорпоративные репозитории, используемые в случаях, когда сам факт разработки некоторых интерфейсов является коммерческой тайной. Такие интерфейсы, однако, не могут выходить за пределы фирм, использующих их для своей внутренней работы.

Распространение модулей возможно как через репозиторий, поддерживаемый командой разработки операционной системы, так и через репозитории, поддерживаемые третьими сторонами (фирмами, выпускающими коммерческое ПО, сообществами, разрабатывающими ПО с открытым исходным кодом, корпоративными серверами и т. п.). При этом центральный репозиторий, поддерживаемый командой разработки ОС, позиционируется в качестве основного, поскольку предоставляет некоторые ункальные сервисы.

Так, при загрузке новых версий модулей в репозиторий производится их тестирование с использованием пополняемой библиотеки интеграционных и модульных тестов, а также тестов производительности. Информация о прохождении таких тестов становится доступна как разработчикам, так и пользователям. При добавлении новых тестов они применяются также и к более старым версиям модулей, присутствующих в репозитории. Все тесты, предоставляемые центральным репозиторием, доступны всем разработчикам для использования как внутри него, так и на собственной инфраструктуре; единственное исключение состоит в противодействии оптимизации модулей под конкретные тесты в ущерб использованию в общем контексте.

Кроме того, центральный репозиторий собирает информацию обо всех модулях, доступных в других открытых репозиториях, а также по мере возможности выполняет их тестирование, хотя загрузка таких модулей по-прежнему доступна только из разместивших их репозиториев. Это позволяет пользователям иметь всю информацию о доступных модулях в одном месте, а разработчикам ПО — получать дополнительную раскрутку своих собственных репозиториев (магазинов).

Наконец, центральный репозиторий помогает осуществлять арбитраж в спорных случаях (например, при распространении нелицензионного ПО третьими лицами). Создание стороннего репозитория невозможно без регистрации в центральном репозитории (включая внутрикорпоративные репозитории); команда поддержки центрального репозитория имеет полномочия и возможности блокировать нарушителей правил (пиратов, хакеров, разработчиков ПО с закрытой архитектурой) как на уровне отдельных модулей, так и на уровне целых сторонних репозиториев.

Предыдущие статьи цикла доступны здесь: раз, два, три. Полный текст, как и прежде, доступен на сайте проекта.