Какие алгоритмы могут анализировать зависимости вызовов для деления библиотеки?

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

Простой пример, в нем четыре функции: альфа, бета, гамма и дельта.

  • бета и гамма оба называют дельтой.
  • 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++ [именно поэтому у меня есть этот ответ], но это большая задача даже для нас. Мы хотели бы получить дополнительную серьезную мотивацию!

Другие вопросы по тегам