Подтвердить что ты не робот

Советы по рефакторингу библиотеки 20K строк

Я уже наградил 100 очков за ответ на марио, но могу начать вторую 100-очную награду, если увижу новые хорошие ответы. Вот почему я держу вопрос открытым и не буду выбирать окончательный ответ, несмотря на то, что он наградил мафиотом.

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

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

Итак, помимо чтения кода и попытки его понять, существуют ли общие (или не столь распространенные) советы при реорганизации такой библиотеки? Что вы посоветуете сделать мою жизнь немного легче?

Спасибо всем за ваши комментарии.

4b9b3361

Ответ 1

Применяется несколько общих принципов:

  • Разделите и победите. Разделите файл на более мелкие, логические библиотеки и группировки функций. Вы узнаете больше о библиотеке таким образом и упростите ее понимание и тестирование постепенно.

  • Удалите дублирование. Ищите повторяющиеся функции и концепции и заменяйте их стандартными библиотечными функциями или централизованными функциями в библиотеке.

  • Добавить последовательность. Выделите параметры и имена.

  • Добавьте модульные тесты. Это самая важная часть рефакторинга библиотеки. Используйте jUnit (или аналогичный) и добавьте тесты, которые вы можете использовать для проверки правильности функций и отсутствия изменений.

  • Добавить документы. Запишите свое понимание последовательной, улучшенной библиотеки, когда вы пишете свои тесты.

Ответ 2

Если код плохо написан, вполне вероятно, что он имеет много клонирования. Таким образом, поиск и избавление от клонов может сделать его намного более удобным, а также уменьшить его размер.

Вы можете найти множество детекторов клонов, специально предназначенных для PHP:

занимает наименьший по величине способ (IMHO с моим сильным личным интересом к CloneDR) с точки зрения качественно различной способности обнаруживать интересные клоны.

Если код плохо написан, многие из них могут быть мертвы. Было бы полезно выяснить, какая часть выполняется на практике, а какая нет. Инструмент для тестирования может дать вам хорошее представление об ответе на этот вопрос, даже в отсутствие тестов (вы просто выполняете свою программу вручную). То, что говорит инструмент тестирования, говорит, очевидно, не мертво. То, что не выполняется... может стоить дальнейшего расследования, чтобы увидеть, можете ли вы его удалить. Инструмент тестового покрытия также полезен, чтобы рассказать вам, сколько кода выполняется вашими модульными тестами, как это предлагает другой ответ. Наконец, инструмент для тестирования может помочь вам найти, где есть некоторые функциональные возможности: использовать функции извне, и любой код, о котором говорит тестовый инструмент покрытия, вероятно, имеет значение.

Наш Инструмент для проверки PHP-теста может собирать данные тестового покрытия.

Ответ 3

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

Я на самом деле делаю это иногда для одного из моих приложений, которое строго подключено и позволяет простой cat */*.php > monolithic.php, который облегчает распространение и обработку. Поэтому спросите, может ли это быть там.

Если вы действительно хотите его перестроить, используйте проверенную временем структуру инкрементного расширения. Разделите класс library на mutliple файлы, разделив исходный класс. Разделите каждые ~ 2000 строк и назовите первую часть library0.php:

 class library0 {
     var $var1,$var2,$var3,$var4;
     function method1();
     function method2();
     function method3();
     function method4();
     function method5();

Следующая часть просто идет оттуда и содержит следующие несколько методов:

 class library1 extends library0 {
     function method6();
     function method7();
     function method8();
     ...

Сделайте так, пока вы их не разделите. Вызовите последний файл по его реальному имени library.php, и class library extends library52 { должен это сделать. Это настолько смехотворно упрощенное, регулярное выражение script должно быть в состоянии сделать это.

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

(Я не пробовал этот подход с таким огромным проектом, но произвольно раскалывал что-то на три части, а затем перетасовывал его для чувствительности. Это один раз.)

Ответ 4

  • Я предполагаю, что вы планируете разбить библиотеку на тематически соответствующие классы. Определенно рассмотрите возможность использования автозагрузки. Это лучшая вещь, поскольку нарезанный хлеб, и делает взаимозависимости удобными в обращении.

  • Документируйте код, используя комментарии, совместимые с phpDoc, с самого начала.

Ответ 5

Хорошая книга, которая отвечает на ваш вопрос множеством примеров и подробностей: Эффективная работа с устаревшим кодом Майкла Перса.

Ответ 6

Вызов бокового подхода

Если вы знаете, что использование библиотеки ограничено определенным классом, модулем или проектом, может быть проще подойти к проблеме с вызывающей стороны. Затем вы можете выполнить следующее, чтобы очистить код и реорганизовать его. Точка приближения с вызывающей стороны связана с тем, что в библиотеке очень мало вызовов. Чем меньше вызовов (потенциально) меньше кода, который фактически используется в lib.

Записывать тесты со стороны вызова

Напишите тест, который имитирует вызовы, которые выполняются против библиотеки.

Похоронить мертвый код

Если будет много мертвого кода, это будет огромная победа. Проследите фактические вызовы в библиотеку и удалите все остальное. Запустите тест и проверьте.

Рефактор Whats Left

Поскольку у вас есть тесты, гораздо проще реорганизовать (или даже заменить) код в библиотеке. Затем вы можете применить стандартные правила рефакторинга, т.е. (дедупликация, упрощение, консолидация и т.д.).

Ответ 7

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

Существует также много полезных инструментов, которые помогут вам в рефакторингах (и вообще) на http://phpqatools.org. Используйте их, чтобы проанализировать свой код, чтобы найти такие вещи, как мертвый или дублированный код, высокую циклическую сложность, часто исполняемый код и так далее. Это не только даст вам лучший обзор вашего кода, но также расскажет вам, какие части вашего кода являются критическими (и лучше не тронуты в начале) и которые могут быть кандидатами на рефакторинг.

Что бы вы ни делали, пишите Unit-Tests. Вы должны убедиться, что вы не нарушаете код при рефакторинге. Если библиотека еще не тестировалась, добавьте тест, прежде чем изменять какой-либо код. Если вы обнаружите, что не можете написать тест для части кода, который вы хотите изменить, проверьте, позволяет ли сделать меньшее рефакторинг в каком-либо другом месте, чтобы вы сделали это легче. Если нет, не пытайтесь рефакторинг, пока не сможете.

Ответ 8

  • Напишите тесты для библиотеки, такие как что все строки кода (т.е. 100% охват).
  • Использование   TDD. Начните с высшего   модулем уровня и ре-фактором (сверху до   Нижний подход).
  • Запустите тесты, упомянутые на шаге 1. и проверьте с помощью результатов шага 2.

Я понимаю, что 100% охват (как указано в шаге 1) не обязательно означает, что все функции были покрыты, по крайней мере, мы убеждаемся, что независимо от того, какая o/p текущей системы будет такой же, как и o/p новой системы.

Ответ 9

Прежде всего, рассмотрите возможность использования другой IDE - Eclipse, как известно, ужасно с точки зрения производительности. Комодо быстрее. Точно так же PhpStorm.

Что касается упрощения рефакторинга, я бы сначала попытался определить изображение высокого уровня - какие функции существуют? Есть классы? Можете ли вы поместить эти классы в отдельные файлы только для начала?

Ответ 11

Если у вас есть проблема с головной болью при ручном размещении функций в разных файлах, чем может быть ниже стратегии, может помочь.

получить файл вашей библиотеки в переменной php

$code = file_get_contents('path/yo/your/library.php');

исключить теги

 $code = str_replace('<?php' ,'' ,$code);
  $code = str_replace('?>' ,'' ,$code);

отделить все функции

$code_array = explode('function',$code);

теперь тело всех функций и их имена находятся в массиве создавать отдельные файлы для каждой из функций в папке "функции"

foreach($code_array as $function)
{
   $funcTemp = explode('(',$function); // getting function name
   $function_name  = trim($funcTemp[0]);

  $function_text = '<?php function '.$function;
   file_put_contents('functions/'.$function_name.'.php',$function_text)

}

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

Вы также можете использовать функцию __call() для использования тех же форматов

function __call($name,$params)
{
  include_once('functions/'.$name.'.php');
  $name($params); // this may be wrong ...
}

Надеюсь, это поможет:)

Ответ 12

Обычно общее правило заключается в удалении повторяющегося кода. Также убедитесь, что у вас есть полезная документация. Если вы используете Java, Javadoc очень полезен, но подходящий эквивалент доступен для других языков.