Эффект внутренней платформы.
Эффект внутренней платформы — создание настолько настраиваемой системы, что она становится плохой копией платформы, на которой работает, например базой данных в базе данных.
Эффект внутренней платформы — это склонность архитекторов программного обеспечения создавать систему настолько настраиваемую, что она становится копией, причём зачастую плохой копией, той платформы разработки, которую они используют. Это, как правило, неэффективно, и такие системы часто считаются примерами антипаттерна.
Примеры
Примеры видны в плагин-ориентированном ПО, таком как некоторые текстовые редакторы и веб-браузеры, в которых разработчики нередко создают плагины, воссоздающие программы, которые обычно работали бы поверх самой операционной системы. Механизм дополнений Firefox использовался для разработки ряда FTP-клиентов и файловых менеджеров, которые фактически воспроизводят некоторые возможности операционной системы, хотя и на более ограниченной платформе.
В мире баз данных разработчиков иногда тянет обойти РСУБД, например храня всё в одной большой таблице с тремя столбцами с названиями «идентификатор сущности», «ключ» и «значение». Хотя эта модель «сущность—атрибут—значение» позволяет разработчику вырваться из структуры, навязанной SQL-базой данных, она лишается всех её преимуществ, поскольку вся работа, которую могла бы эффективно выполнять РСУБД, перекладывается на приложение. Запросы становятся гораздо более запутанными, индексы и оптимизатор запросов больше не могут работать эффективно, а ограничения целостности данных не применяются. Производительность и сопровождаемость могут оказаться крайне плохими.
Аналогичный соблазн существует для XML, где разработчики иногда отдают предпочтение обобщённым именам элементов и используют атрибуты для хранения значимой информации. Например, каждый элемент может называться item и иметь атрибуты type и value. Такая практика требует соединений по нескольким атрибутам, чтобы извлечь смысл. В результате XPath-выражения становятся более запутанными, вычисление менее эффективным, а структурная валидация даёт мало пользы.
Ещё один пример — феномен веб-десктопов, когда целое окружение рабочего стола — часто включающее веб-браузер — работает внутри браузера (который сам, как правило, работает внутри окружения рабочего стола, предоставляемого операционной системой). Рабочий стол внутри рабочего стола может быть на удивление неудобен для пользователя, и поэтому так обычно делают лишь для запуска программ, которые трудно развернуть на пользовательских системах, либо скрывая внешний рабочий стол.
Эффект
Для разработчиков ПО нормально создавать библиотеку собственных функций, относящихся к их конкретному проекту. Эффект внутренней платформы возникает, когда эта библиотека разрастается и начинает включать функции общего назначения, дублирующие функциональность, уже доступную как часть языка программирования или платформы. Поскольку каждая из этих новых функций обычно вызывает ряд исходных функций, они, как правило, медленнее, а при плохой реализации ещё и менее надёжны.
С другой стороны, такие функции часто создаются, чтобы представить более простой (и зачастую более переносимый) уровень абстракции поверх низкоуровневых сервисов, которые либо имеют неудобный интерфейс, слишком сложны, непереносимы или недостаточно переносимы, либо просто плохо подходят для высокоуровневого кода приложения.
Уместное применение
Внутренняя платформа может быть полезна по причинам переносимости и разделения привилегий — иными словами, чтобы одно и то же приложение могло работать на самых разных внешних платформах, не затрагивая ничего за пределами песочницы, управляемой внутренней платформой. Например, Sun Microsystems спроектировала платформу Java, чтобы достичь обеих этих целей.
Пример
Вместо отдельной таблицы для каждой сущности всё складывается в одну универсальную таблицу «сущность — атрибут — значение», и приложению приходится заново реализовывать то, что база данных уже умеет: типы, ограничения и соединения. Даже простой фильтр требует самосоединения и приведения типа, и ничто не мешает клиенту остаться без email или получить отрицательный кредитный лимит.
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE entity (id INTEGER, attr TEXT, value TEXT)")
def save_customer(cid, name, email, credit_limit):
db.executemany(
"INSERT INTO entity VALUES (?, ?, ?)",
[(cid, "name", name), (cid, "email", email), (cid, "credit_limit", str(credit_limit))],
)
def customers_over(limit):
return db.execute(
"SELECT n.id, n.value FROM entity n "
"JOIN entity c ON c.id = n.id AND c.attr = 'credit_limit' "
"WHERE n.attr = 'name' AND CAST(c.value AS REAL) > ?",
(limit,),
).fetchall()
Настоящая схема позволяет СУБД проверять типы и ограничения, использовать индекс и оптимизировать запрос — приложение больше не воспроизводит платформу, на которой работает.
import sqlite3
db = sqlite3.connect(":memory:")
db.execute(
"CREATE TABLE customer ("
" id INTEGER PRIMARY KEY,"
" name TEXT NOT NULL,"
" email TEXT NOT NULL UNIQUE,"
" credit_limit REAL NOT NULL CHECK (credit_limit >= 0))"
)
db.execute("CREATE INDEX customer_credit_limit ON customer (credit_limit)")
def save_customer(cid, name, email, credit_limit):
db.execute("INSERT INTO customer VALUES (?, ?, ?, ?)", (cid, name, email, credit_limit))
def customers_over(limit):
return db.execute("SELECT id, name FROM customer WHERE credit_limit > ?", (limit,)).fetchall()
Адаптировано по статье Википедии “Inner-platform effect” (версия 1319593770), распространяется по лицензии CC BY-SA 4.0; текст переведён и отредактирован, добавлены примеры.