Какие алгоритмы могут анализировать зависимости вызовов для деления библиотеки?
Предположим, у меня есть библиотека, которая содержит множество взаимозависимых функций, эта библиотека слишком большая, и я хочу разделить ее. Какие существуют алгоритмы для поиска подходящих разделов?
Простой пример, в нем четыре функции: альфа, бета, гамма и дельта.
- бета и гамма оба называют дельтой.
- module1 вызывает альфа и бета.
- module2 вызывает гамму.
- Модуль 3 вызывает альфа, бета и гамма.
Выходные данные алгоритма могут быть:
- LibA содержит (альфа, бета)
- LibB содержит (гамма)
- LibC содержит (дельта)
- module1 зависит от LibA
- module2 зависит от LibB
- module3 зависит от LibA и LibB
- LibA зависит от LibC
- LibB зависит от LibC
то есть он находит самый мелкозернистый раздел Lib* со следующим свойством
Для всех X, если LibX разделен любым методом на LibY и LibZ, то все модули / библиотеки, которые зависят от LibY, также зависят от LibZ и наоборот.
Есть ли стандартное решение для этого?
1 ответ
(Это та же проблема, что и у людей с заголовочными файлами в программах на C и C++.)
Это не просто "вызовы", которые создают зависимости; это любая ссылка на переменную-член, статическую переменную или даже определение константы.
По сути, вам нужно обнаружить все мелкозернистые зависимости (для этого обычно требуется инструмент анализа, подобный компилятору, который читает код и обнаруживает такие зависимости между объявленными элементами языка (объявлениями, полями, методами, классами, пакетами, если вы java-ориентированный и т. д.) и другие языковые элементы, использующие семантику языка, на котором написаны библиотеки (такой анализ, вероятно, консервативен). Это суть дает вам гигантский граф с узлами, являющимися элементами языка, и дуги "использования".
Проблема с упаковкой библиотеки в реферате разбивает этот граф на части, сводя к минимуму дуги зависимости между блоками. Это может дать вам огромное количество маленьких библиотек.
Практическая проблема заключается в объединении нескольких фрагментов, которые не зависят друг от друга, но обычно используются вместе. Например, набор процедур доступа к буферу может не иметь явной зависимости от определения размера буфера по умолчанию, но вы, вероятно, хотите, чтобы одна библиотека содержала оба, а не две библиотеки с одной, содержащей только объявление размера буфера по умолчанию. Это понятие использованного вместе - действительно артефакт проблемной области, и его не видно нигде в коде, за исключением, возможно, некоторого статистического совместного использования.
Трудной частью этой проблемы является обнаружение мелкозернистых семантических зависимостей. Вы можете приблизить это вручную, но если у вас есть какой-то масштаб, у вас не будет аппетита на это. (Люди не реорганизуют заголовочные файлы по той же причине). В значительной степени вам нужны языковые инструменты для анализа, управление большими графами, чтобы предлагать куски, статистический анализ для получения групповой группировки и, вероятно, пользовательский интерфейс, позволяющий эксперту в области редактировать группировку для создания пересмотренных библиотек.
Затем вам нужен инструмент, чтобы вернуться к коду, который использует устаревшие библиотеки, и изменить их для использования пересмотренных библиотек. И рефакторинг библиотеки, и пересмотр базы кода требуют масштабного анализа и изменения кода, что требует автоматизации.
Наш инструментарий реинжиниринга программного обеспечения DMS с его многочисленными языковыми интерфейсами, вероятно, является хорошей основой для осуществления такой реорганизации библиотеки. Мы рассматривали возможность сделать это для C и C++ [именно поэтому у меня есть этот ответ], но это большая задача даже для нас. Мы хотели бы получить дополнительную серьезную мотивацию!