Как вы реорганизуете большую грязную кодовую базу? - PullRequest
40 голосов
/ 05 июня 2010

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

Я нарушил все правила, о которых читал за последний год. Есть классы с множественными обязанностями, есть косвенный доступ (я забыл термин - что-то вроде foo.bar.doSomething()), и, как я сказал, это не очень хорошо прокомментировано. Кроме того, это начало игры, так что графика связана с данными, или места, где я пытался отделить графику и данные, я сделал данные public, чтобы графика могла иметь доступ необходимые данные ...

Это огромный беспорядок! С чего мне начать? Как бы вы начали что-то вроде этого?

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


Обновление через два дня: Я рисовал UML-подобные диаграммы своих классов и по пути ловил некоторые из "Низко висящих фруктов". Я даже нашел несколько фрагментов кода, которые послужили началом новых функций, но, пытаясь все уменьшить, я смог удалить эти фрагменты и сделать проект более понятным. Я, вероятно, собираюсь провести рефакторинг как можно больше, прежде чем собирать тестовые наборы (но только те вещи, которые на 100% уверены, что они не повлияют на функциональность, конечно!), Так что мне не придется рефакторинг тестовых наборов, так как изменить функциональность. (Как вы думаете, я делаю это правильно или, по вашему мнению, мне было бы легче смириться с этим и сначала написать тесты?)

Пожалуйста, проголосуйте за лучший ответ, чтобы я мог отметить его справедливо! Не стесняйтесь добавлять свой собственный ответ и к группе, для вас еще есть место! Я дам ему еще один день или около того, а затем, вероятно, отмечу ответ с наибольшим количеством голосов как принятый.

Спасибо всем, кто ответил до сих пор!


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

Для этого я делаю четыре вещи, когда необходимо изменить код:

  1. Определите, для чего предназначался код
  2. Нарисуйте UML и диаграммы действий участвующих классов
  3. Найдите подходящий дизайн
  4. Определение более четких имен для текущих классов и методов

Ответы [ 14 ]

19 голосов
/ 06 июня 2010

Возьмите себе копию Рефакторинга Мартина Фаулера . У него есть несколько полезных советов о том, как решить проблему с рефакторингом. Около 75% книги - это небольшие шаги по рефакторингу в стиле кулинарной книги, которые вы можете сделать. Он также поддерживает автоматические модульные тесты, которые вы можете запускать после каждого шага, чтобы доказать, что ваш код все еще работает.

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

Без каких-либо высокоуровневых спецификаций или дизайна, вы просто рискуете снова потеряться и в конечном итоге получить еще один неразрывный беспорядок.

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

16 голосов
/ 05 июня 2010

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

11 голосов
/ 06 июня 2010

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

Перья рассказывают о Тестах характеристик , которые являются модульными тестами не для подтверждения известного поведения системы, а для изучения и определения существующего (неясного) поведения - в случае, когда вы написали свой собственный устаревший код и исправление его самостоятельно, это может быть не так важно, но если ваш дизайн небрежный, то вполне возможно, что есть части кода, которые работают «по волшебству», и их поведение неясно Даже вам - в этом случае тесты характеристик помогут.

Одной из замечательных частей книги является обсуждение поиска (или создания) швов в вашей кодовой базе - швы - это естественные «линии разлома», если хотите, где вы можете проникнуть в существующую систему начать тестирование, и потянув его к лучшему дизайну. Трудно объяснить, но хорошо стоит прочитать.

Есть краткая статья , в которой Перья раскрывают некоторые концепции из книги, но на самом деле это стоит того, чтобы выследить все это. Это один из моих любимых.

5 голосов
/ 06 июня 2010

Просто дополнительный рефакторинг, который важнее, чем вы думаете: правильно называйте вещи!

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

Кроме того, документируйте свои вещи. Всякий раз, когда ответ на ПОЧЕМУ? неясно передал ответ на КАК? (будучи кодом) вам нужно будет добавить некоторую документацию. Захват проектных решений, вероятно, является наиболее важной задачей, поскольку это очень трудно сделать в коде.

5 голосов
/ 05 июня 2010

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

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

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

Может быть удивительно приятно обновлять программу, чтобы она делала то, что делала раньше, только более "чисто". ;)

Как уже упоминали другие, юнит-тесты - ваш лучший друг! Они помогают вам гарантировать, что ваш рефакторинг работает, и если вы начинаете с нуля, это идеальное время для написания их.

4 голосов
/ 06 июня 2010

Купите IDE с хорошей поддержкой рефакторинга. Я думаю, что IntelliJ - лучший, но у Eclipse он тоже есть.

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

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

Отслеживание покрытия кода на ходу. Вы хотите работать до 70% или лучше. Для классов, которые вы меняете, вам нужно, чтобы они составляли 70% или выше, прежде чем вносить изменения.

Со временем создайте эту систему безопасности, и вы сможете с некоторой уверенностью провести рефакторинг.

4 голосов
/ 05 июня 2010

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

Удаление переменных из общей области, как вы это делаете, является отличным началом, поскольку вы распределяете обязанности. В конечном итоге вы хотите, чтобы каждый класс выражал одну ответственность. Несколько вещей, на которые вы можете посмотреть:

  • Простыми целями для рефакторинга являются код, который дублируется во многих местах и ​​содержит длинные методы.
  • Если вы управляете состоянием приложения через статически инициализированные синглтоны или хуже, глобальное состояние, с которым все разговаривают, рассмотрите возможность его перемещения в управляемую систему инициализации (т. Е. Инфраструктуру внедрения зависимостей, такую ​​как spring или guice) или, по крайней мере, убедитесь, что что инициализация не запутывается с остальной частью кода.
  • Централизуйте и стандартизируйте доступ к внешним ресурсам, особенно если у вас есть такие вещи, как расположение файлов или URL-адреса в жестком коде.
3 голосов
/ 10 июня 2010

Для кода Java мой любимый первый шаг - запустить Findbugs, а затем удалить все мертвые хранилища, неиспользуемые поля, недоступные блоки catch, неиспользуемые частные методы и возможные ошибки.

Затем я запускаю CPD, чтобы найти свидетельства обрезанного и вставленного кода.

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

3 голосов
/ 06 июня 2010

очень медленно: D

Нет, серьезно ... делай это шаг за шагом. Например, рефакторинг чего-либо только в том случае, если он влияет или помогает вам написать текущую ошибку / функцию, над которой вы работаете сейчас, и не делает ничего более этого. А перед рефакторингом убедитесь, что у вас есть darn , что у вас есть какой-то автоматизированный тест, который запускается на каждой сборке, которая фактически проверяет то, что вы пишете / рефакторинг. Даже если у вас нет модульных тестов, никогда не поздно начать добавлять их для всего нового и измененного кода, который пишется. Со временем ваша кодовая база будет улучшаться небольшими приращениями ежедневно или еженедельно, а не хуже - и все это без огромных куч изменений.

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

2 голосов
/ 06 июня 2010

Рефакторинг низко висящих фруктов. Откусывайте легкие биты, и когда вы это сделаете, более жесткие биты станут немного легче. Когда для рефакторинга не осталось битов, все готово.

Рефакторинги, которые вы, вероятно, найдете наиболее полезными: Метод переименования (и даже более тривиальные переименования, такие как Field, Variable и Parameter), Метод извлечения и Извлечение Класс . Для каждого выполняемого рефакторинга напишите необходимые модульные тесты, чтобы сделать рефакторинг безопасным, и запускайте весь набор модульных тестов после каждого рефакторинга. Заманчиво - и, честно говоря, довольно безопасно - полагаться на автоматизированный рефакторинг вашей IDE без тестов - но это хорошая практика, и будет полезно иметь тесты в будущем, когда вы добавите функциональность в свой проект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...