Я работаю на довольно большой кодовой базе. Сотни классов, тонны различных файлов, множество функциональных возможностей, более 15 минут требуется для создания новой копии и т. Д.
Большая проблема с такой большой кодовой базой состоит в том, что у нее есть довольно много вспомогательных методов и таких, которые делают то же самое, или есть код, который не использует эти служебные методы, когда это возможно. А также служебные методы не просто все в одном классе (потому что это будет огромный беспорядок).
Я довольно новичок в кодовой базе, но у руководителя группы, который работал над ним годами, похоже, та же проблема. Это приводит к большому количеству кода и рабочего дублирования, и, как таковое, когда что-то ломается, оно обычно разбивается на 4 копии в основном того же кода
Как мы можем обуздать эту модель? Как и в большинстве крупных проектов, не весь код документирован (хотя некоторые и есть), и не весь код ... ну, чистый. Но в целом было бы очень хорошо, если бы мы могли работать над улучшением качества в этом отношении, чтобы в будущем у нас было меньше дублирования кода, и такие вещи, как служебные функции, было легче обнаружить.
Кроме того, служебные функции обычно находятся в каком-то статическом вспомогательном классе, в каком-то нестатическом вспомогательном классе, который работает с одним объектом, или являются статическим методом в классе, с которым он в основном «помогает».
У меня был один эксперимент по добавлению служебных функций в качестве методов расширения (мне не нужны были какие-то внутренние компоненты класса, и это определенно требовалось только в очень специфических сценариях). Это имело эффект предотвращения беспорядка в первичном классе и тому подобном, но на самом деле его уже нельзя обнаружить, если вы уже не знаете об этом
Ответы:
Ответ прост: вы действительно не можете предотвратить дублирование кода. Однако вы можете «исправить это» через сложный непрерывный повторяющийся инкрементный процесс, который сводится к двум шагам:
Шаг 1. Начните писать тесты на унаследованном коде (желательно с использованием инфраструктуры тестирования)
Шаг 2. Перепишите / реорганизуйте код, который дублируется, используя то, что вы узнали из тестов
Вы можете использовать инструменты статического анализа для обнаружения дублированного кода, а для C # существует множество инструментов, которые могут сделать это за вас:
Подобные инструменты помогут вам найти точки в коде, который делает подобные вещи. Продолжайте писать тесты, чтобы определить, что они действительно делают; используйте те же тесты, чтобы сделать дубликат кода более простым в использовании. Этот «рефакторинг» может быть выполнен несколькими способами, и вы можете использовать этот список, чтобы определить правильный:
Кроме того, есть также целая книга на эту тему, написанная Майклом К. Фезерсом, « Эффективная работа с устаревшим кодексом» . В нем подробно рассматриваются различные стратегии, которые вы можете использовать, чтобы изменить код к лучшему. У него есть «алгоритм изменения устаревшего кода», который не за горами двухэтапного процесса, описанного выше:
Книга хорошо читается, если вы имеете дело с разработкой «коричневого поля», то есть с устаревшим кодом, который необходимо изменить.
В этом случае
В случае с OP я могу представить, что непроверяемый код вызван «медовым горшком» для «служебных методов и приемов», которые принимают несколько форм:
Обратите внимание, что в этом нет ничего плохого, но, с другой стороны, их обычно сложно поддерживать и изменять. Методы расширений в .NET являются статическими, но их также относительно легко проверить.
Прежде чем приступить к рефакторингу, поговорите об этом со своей командой. Они должны храниться на той же странице, что и вы, прежде чем что-либо предпринимать. Это потому, что если вы что-то рефакторинуете, то высоки шансы, что вы будете вызывать конфликты слияния. Поэтому, прежде чем что-то переделывать, исследуйте это, попросите команду поработать над этими кодами с осторожностью, пока не закончите.
Поскольку OP является новым для кода, перед тем, как что-либо предпринимать, нужно сделать еще кое-что:
Удачи!
источник
Мы также могли бы попытаться увидеть проблему под другим углом. Вместо того, чтобы думать, что проблема заключается в дублировании кода, мы можем рассмотреть вопрос о том, возникает ли проблема из-за отсутствия политик повторного использования кода.
Недавно я прочитал книгу « Разработка программного обеспечения с повторно используемыми компонентами», и у нее действительно есть ряд очень интересных идей о том, как повысить эффективность повторного использования кода на уровне организации.
Автор этой книги, Йоханнес Саметингер, описывает ряд барьеров для повторного использования кода, некоторые концептуальные, некоторые технические. Например:
По мнению автора, разные уровни повторного использования происходят в зависимости от зрелости организации.
Таким образом, возможно, помимо всех предложений, приведенных в других ответах, вы могли бы поработать над созданием программы повторного использования, задействовать управление, сформировать группу компонентов, отвечающую за идентификацию повторно используемых компонентов, выполнив анализ предметной области, и определить хранилище повторно используемых компонентов, которое другие разработчики могут легко запрашивать и искать готовые решения своих проблем.
источник
Есть 2 возможных решения:
Профилактика - старайтесь иметь как можно более качественную документацию. Сделайте каждую функцию должным образом документированной и легкой для поиска по всей документации. Кроме того, при написании кода, сделайте очевидным, куда должен идти код, чтобы было очевидно, где искать. Ограничение количества «полезного» кода является одним из ключевых моментов этого. Каждый раз, когда я слышу «давай сделаем полезный урок», мои волосы растут, а кровь замерзает, потому что это, очевидно, проблема. Всегда имейте быстрый и простой способ попросить людей знать кодовую базу, когда какая-либо функция уже существует.
Решение. Если предотвращение не удастся, вы сможете быстро и эффективно решить проблемный фрагмент кода. Ваш процесс разработки должен позволять быстро исправлять дублирующийся код. Модульное тестирование идеально подходит для этого, потому что вы можете эффективно изменять код, не опасаясь его взлома. Так что, если вы найдете 2 одинаковых фрагмента кода, то абстрагирование их в функцию или класс должно быть легко с небольшим рефакторингом.
Я лично не думаю, что профилактика возможна. Чем больше вы пытаетесь, тем больше проблем найти уже существующие функции.
источник
Я не думаю, что такого рода проблемы имеют общее решение. Дублированный код не будет создан, если разработчики будут достаточно готовы искать существующий код. Также разработчики могут исправить проблемы на месте, если они хотят.
Если язык C / C ++, дублирование будет легче из-за гибкости компоновки (можно вызывать любые
extern
функции без предварительной информации). Для Java или .NET вам может потребоваться разработать вспомогательные классы и / или служебные компоненты.Я обычно начинаю удаление дублирования существующего кода, только если основные ошибки возникают из-за дублированных частей.
источник
Это типичная проблема более крупного проекта, который обрабатывался многими программистами, которые иногда оказывали содействие под большим давлением со стороны сверстников. Очень очень заманчиво сделать копию класса и адаптировать его к этому конкретному классу. Однако, когда проблема была обнаружена в исходном классе, она также должна быть решена в его потомках, о которых часто забывают.
Для этого есть решение, и оно называется Generics, которое было представлено в Java 6. Это эквивалент C ++, называемый Template. Код, точный класс которого еще не известен в общем классе. Пожалуйста, проверьте Java Generics, и вы найдете тонны и тонны документации для него.
Хороший подход состоит в том, чтобы переписать код, который кажется скопированным / вставленным во многих местах, переписав первый, который вам необходимо исправить, т.е. исправить из-за определенной ошибки. Перепишите его, чтобы использовать Generics, а также написать очень строгий код тестирования.
Убедитесь, что вызывается каждый метод класса Generic. Вы также можете ввести инструменты покрытия кода: общий код должен полностью охватывать код, потому что он будет использоваться в нескольких местах.
Также напишите тестовый код, т. Е. Используя JUnit или аналогичный для первого назначенного класса, который будет использоваться вместе с Общей частью кода.
Начните использовать общий код для второй (чаще всего) копируемой версии, когда весь предыдущий код работает и полностью протестирован. Вы увидите, что есть несколько строк кода, специфичных для этого обозначенного класса. Вы можете вызвать эти строки закодированным в абстрактном защищенном методе, который должен быть реализован производным классом, который использует базовый класс Generic.
Да, это утомительная работа, но с течением времени вам будет все лучше и лучше вырывать похожие классы и заменять их чем-то очень чистым, хорошо написанным и намного более легким в обслуживании.
У меня была похожая ситуация, когда в обобщенном классе в конце концов заменили что-то вроде 6 или 7 других почти идентичных классов, которые были почти полностью идентичны, но были скопированы и вставлены различными программистами в течение определенного периода времени.
И да, я очень за автоматическое тестирование кода. Вначале это будет стоить дороже, но, безусловно, сэкономит вам огромное количество времени. И попробуйте достичь общего покрытия кода, по крайней мере, 80% и 100% для общего кода.
Надеюсь, что это поможет и удачи.
источник
Я на самом деле собираюсь повторить наименее популярное мнение
Gangnus
и предположить, что дублирование кода не всегда вредно и иногда может быть меньшим злом.Если, скажем, вы даете мне возможность использовать:
A) Стабильная (неизменная) и крошечная библиотека изображений, хорошо протестированная , которая дублирует несколько десятков строк тривиального математического кода для векторной математики, таких как точечные произведения, лепры и зажимы, но полностью отделена от всего остального и состоит из доли Второй.
Б) Нестабильная (быстро меняющаяся) библиотека изображений, которая зависит от эпической математической библиотеки, чтобы избежать пары десятков строк кода, упомянутых выше, с математической библиотекой, которая нестабильна и постоянно получает новые обновления и изменения, и поэтому библиотека изображений также должна быть перестроен, если не полностью изменен. На сборку уходит 15 минут.
... тогда, очевидно, большинству людей должно быть понятно, что A, и на самом деле именно из-за незначительного дублирования кода, является предпочтительным. Ключевой акцент, который мне нужно сделать, - это хорошо проверенная часть. Очевидно, нет ничего хуже, чем иметь дублированный код, который вообще не работает, и в этот момент он дублирует ошибки.
Но есть также связь и стабильность, о которых стоит подумать, и некоторое скромное дублирование здесь и там может служить механизмом развязки, который также увеличивает стабильность (неизменный характер) пакета.
Таким образом, мое предложение на самом деле будет сосредоточено больше на тестировании и попытке придумать что-то действительно стабильное (например, неизменное, найти несколько причин для изменения в будущем) и надежное, чьи зависимости от внешних источников, если таковые имеются, очень стабильный, по сравнению с попытками искоренить все формы дублирования в вашей кодовой базе. В большой командной среде последнее, как правило, является непрактичной целью, не говоря уже о том, что это может увеличить сцепление и количество нестабильного кода, имеющегося в вашей кодовой базе.
источник
Не забывайте, что дублирование кода не всегда вредно. Представьте себе: теперь перед вами стоит задача, решаемая в совершенно разных модулях вашего проекта. Просто сейчас это та же задача.
На это может быть три причины:
Некоторые темы вокруг этой задачи одинаковы для обоих модулей. В этом случае дублирование кода является плохим и должно быть ликвидировано. Было бы разумно создать класс или модуль для поддержки этой темы и использовать его методы в обоих модулях.
Задача теоретическая с точки зрения вашего проекта. Например, это из физики или математики и т. Д. Задача существует независимо от вашего проекта. В этом случае дублирование кода является плохим и должно быть также ликвидировано. Я бы создал специальный класс для таких функций. И используйте такую функцию в любом модуле, где вам это нужно.
Но в других случаях совпадение заданий является временным совпадением и не более того. Было бы опасно полагать, что эти задачи останутся такими же во время изменений проекта из-за рефакторинга и даже отладки. В этом случае было бы лучше создать две одинаковые функции / фрагменты кода в разных местах. И будущие изменения в одном из них не коснутся другого.
И этот третий случай случается очень часто. Если вы дублируете «по незнанию», в основном именно по этой причине - это не настоящее дублирование!
Поэтому старайтесь держать его в чистоте, когда это действительно необходимо, и не бойтесь дублирования, если это не обязательно.
источник
code duplication is not always harmful
это один плохой совет.