Хотя я долгое время задумывал написать развёрнутую заметку о недостатках ROOT, сделать её в полной мере справедливой нельзя без учёта истории этого фреймворка.
Важно в первую очередь определить, что же мы будем называть здесь фреймворком, и почему ROOT — это вот оно. Я настаиваю на номенклатурном использовании устоявшейся кальки (пусть и неблагозвучной) — прямой транслитерации с английского framework, как ставшего наиболее общеупотребимой нормой в среде промышленных программистов. Хотя в ранней отечественной литературе подобную схему организации программного обеспечения когда-то принято было называть каркасом, впоследствии эти термины существенно разошлись, и это необходимо иметь в виду.
Каркас, или framework в том виде в котором его понимали в 80-90-х, это в известном смысле антонимичное понятие библиотеке. Наиболее доходчиво будет понимать каркас как среду в которую "вставляются" заменяемые библиотеки (это соответствует жёсткому размещению непереносимых в памяти программ — ныне забытой особенности организации ранних ЭВМ). Если библиотека определяет, как должна выполняться та или иная операция, каркас должен был определять в каком месте это типично происходит, являясь таким образом набором типичных сценариев использования более элементарных операций, реализованных, понятно, в библиотеках.
Однако по мере развития концепций ООП, упрощения и обкатки теоретических подходов к дизайну ПО, изначально понимаемые под каркасом функциональные черты существенно размылись и редуцировались. И этой исторической эволюции понятия "framework" уделяется на мой взгляд слишком мало внимания на страничке википедии: начинаясь с описания изначального смысла понятия, текст постепенно скатывается к современному пониманию, довольно отличному от изначального. Там же предпринимаются довольно вялые попытки скрыть возникающие противоречия за контекстом использования понятия, но по-моему у читателя должно оставаться парадоксальное впечатление.
Потому что современные фреймворки устроены иначе: наряду с набором типичных сценариев с точками расширения, они реализуют и собственный набор более элементарных функций, которые в оригинальном "каркасе" должны были бы оказаться делегированными библиотекам. Так что само различие, дихотомия между фреймворком и библиотекой стёрлись, и первый просто обычно превосходит вторую, предоставляя, как правило, более широкий набор общих (более высокого уровня) процедур, нежели классическая библиотека, однако по-прежнему в виде API.
Примером таковой гибридизации, по сути классическим фреймворком в современном понимании и является ROOT, "framework for data analysis": это набор библиотек объединённых более-менее связным и совместимым API с пластичными сценариями взаимной интеграции.
Так например, функции нескольких библиотек, включённых в него:
libThread
— библиотека реализующая функциональность POSIX-потоков в виде
класса C++ (POSIX treads изначально реализованы под чистый Си)libFFTW
— обёртка над внешней библиотекой (или самостоятельная реализация)
быстрого преобразования ФурьеlibHistPainter
— собственная реализация отрисовки гистограммlibTree
— библиотека для работы с собственным форматом хранения данных,
типично применяемым для хранения физических событийВ то же время библиотека libGui
довольно жёстко фиксирует использование
собственных библиотек ROOT для реализации графического пользовательского
интерфейса, а libDict
вовсе позволяет сериализовать экземпляр произвольного
класса C++, что соответствует довольно высокоуровневым сценариям. Ну и конечно
libCling
, как и само окружение CLING (ранее CINT) реализует исполнение
интерпретируемых сценариев на собственном диалекте C++.
При этом для ROOT характерны довольно архаичные черты, пришедшие из тех времён,
когда в ООП видели панацею от всех затруднений при проектировании большого ПО:
жёсткое централизованное API (в идеале всякий класс отнаследован от общего для
всех предка — TObject
),
отсутствие встроенных механизмов RPC, слабая гранулярность кода в целом.
Эти черты — результат многолетней истории ROOT, о которой лучше всего почитать в интервью с создателем системы, Rene Brun'ом. Из истории же делается понятно и пренебрежение многими прогрессивными концепциями и практиками разработки ПО на C++: обобщённым программированием (шаблонами), практически полное игнорирование встроенных механизмов RTTI и тотальная склонность к изобретению велосипедов (чего стоит только рукодельный XML-парсер, игнорирующий 80% стандарта XML, зато чувствительный к пробелам и переносам строк).
Я попробую теперь изложить один взгляд на то что же сделало ROOT таким популярным решением в High Energy Physics.
static const
, это едва ли будет для вас проблемой. Но
стоит вам попытаться выделить обработчик событий GUI в отдельный поток, чтобы
управлять машиной состояний в реальном времени из каких-то дополнительных
источников, начинается настоящая головная боль...strcmp()
, несконачемый le bricolage —
от уже упомянутого XML-парсера до авторского видения ущербных регулярных
выражений. Первый похоронил замечательную идею
GDML в зачатке, а вторые
настолько плохи, что почти нигде не используются в самом ROOT! Недоделки и
(un)known issues станут вашими спутниками на весь цикл сопровождения
эксперимента. Лучшим тому подтверждением является многочисленность попыток
"довести до ума" этот фреймворк командами с различной компетенцией —
FairROOT,
PandaROOT,
AliROOT,
счёт идёт на десятки.ROOT — это популярный инструмент, с исторически-обусловленными недостатками, по существу герметизирующими его в нише High Energy Physics. Построенный на изначально прогрессивных для своего времени концепциях, к настоящему моменту он достаточно устарел, чтобы уступить место менее ригидным решениям, из которых, впрочем, пока ни одно не оказалось достаточно состоятельным, чтобы потеснить его на этом нишевом Олимпе.
Каким бы ни был инструмент в общем, то объективное соображение что, с учётом его популярности, попросту нет ничего лучше (то есть, один исследователь-то может, наверное, писать на Python, хранить в Apache Thrift, масштабировать в Kubernettes и визуализировать в D3.js) делает его качество вторичным, оно диктует простые рамки профессиональной этики: мы работаем в команде, мы пишем для команды, нам важен X-check и совместимость.