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

Отслеживание служебных классов

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

Я работаю над крупномасштабным проектом Java, который имеет > 1M строк кода. Интерфейсы и структура классов разработаны очень хорошо, и инженеры, пишущие код, очень компетентны. Проблема заключается в том, что в попытке сделать код чище люди пишут классы Утилиты всякий раз, когда им нужно повторно использовать некоторые функции, в результате с течением времени и по мере того, как в проекте растет все больше и больше полезных методов. Однако, когда следующий инженер сталкивается с необходимостью такой же функциональности, он не знает, что кто-то уже реализовал класс (или метод) утилиты где-то в коде и реализует другую копию функций в другом классе. Результатом является много дублирования кода и слишком много полезных классов с перекрывающимися функциональными возможностями.

Существуют ли какие-либо инструменты или какие-либо принципы проектирования, которые мы, как команда, можем реализовать для предотвращения дублирования и низкой видимости классов полезности?

Пример: У инженера A есть 3 места, которые ему необходимо преобразовать XML в String, поэтому он пишет класс утилиты, называемый XMLUtil, и помещает в него статический метод toString(Document). Инженер B имеет несколько мест, где он сериализует документы в различных форматах, включая String, поэтому он пишет класс утилиты, называемый SerializationUtil, и имеет статический метод с именем serialize(Document), который возвращает строку.

Обратите внимание, что это больше, чем просто дублирование кода, так как вполне возможно, что 2 реализации вышеприведенного примера отличаются (например, один использует API-интерфейс трансформатора, а другой использует Xerces2-J), поэтому это можно рассматривать как "передовой практики"...

Обновление: Я предполагаю, что лучше описать текущую среду, в которой мы развиваемся. Мы используем Hudson для CI, Clover для покрытия кода и Checkstyle для статического анализа кода. Мы используем гибкое развитие, включая ежедневные переговоры и (возможно, недостаточные) обзоры кода. Мы определяем все наши классы полезности в .util, который благодаря этому размеру теперь имеет 13 подпакетов и около 60 классов под корневым (.util) классом. Мы также используем сторонние библиотеки, такие как большинство баннеров apache и некоторые банки, которые составляют Guava.

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

4b9b3361

Ответ 1

Ваша проблема очень распространенная. И реальная проблема тоже, потому что нет хорошего решения.

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

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

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

Хороший базовый дизайн Java API является одной из причин успеха Java. Хорошие сторонние библиотеки с открытыми источниками тоже очень много. Даже небольшой хорошо продуманный API позволяет предлагать действительно полезную абстракцию и может значительно уменьшить размер кода. Но вы знаете, что создание фреймворка и публичного API - это совсем не то же самое, что просто кодирование класса утилиты за 2 часа. Это очень дорого. Класс утилиты стоит 2 часа для первоначального кодирования, возможно, 2 дня с отладкой и модульными тестами. Когда вы начинаете делиться общим кодом с большими проектами/командами, вы действительно создаете API. Вы должны обеспечить идеальную документацию, а затем, действительно читаемый и поддерживаемый код. Когда вы выпускаете новую версию этого кода, вы должны оставаться обратно совместимыми. Вы должны продвигать его в масштабе всей компании (или, по крайней мере, в команде). С 2-х дней для вашего небольшого класса полезности вы вырасти до 10 дней, 20 дней или даже 50 дней для полноценного API.

И ваш дизайн API может быть не таким уж большим. Ну, это не значит, что ваши инженеры не яркие - действительно, они есть. Но согласны ли вы позволить им работать 50 дней на небольшом служебном классе, который просто помогает анализировать число в согласованном режиме для пользовательского интерфейса? Готовы ли вы разрешить им перепроектировать все это, когда вы начнете использовать мобильный интерфейс с совершенно разными потребностями? Также вы заметили, как самые яркие инженеры в слове делают API, которые никогда не будут популярны или будут медленно исчезать? Видите ли, в первом веб-проекте, который мы использовали, использовались только внутренние рамки или вообще нет рамки. Затем мы добавили PHP/JSP/ASP. Затем в Java мы добавили Struts. Теперь JSF является стандартом. И мы думаем об использовании Spring Web Flow, Vaadin или Lift...

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

Но основная точка производительности в компании-разработчике программного обеспечения заключается не в получении 10 или даже 50 строк кода при анализе XML. Общий код для этого будет расти до тысячи строк кода в любом случае и воссоздает сложный API, который будет накладываться слоями классами. Когда парень делает класс утилиты для синтаксического анализа XML, это хорошая абстракция. Он дает имя одной дюжине или даже сто строк специализированного кода. Этот код полезен, потому что он специализирован. Общий API позволяет работать с потоками, URL-адресами, строками и т.д. Он имеет factory, поэтому вы можете выбрать реализацию парсера. Класс полезности хорош, потому что он работает только с этим синтаксическим анализатором и со строками. И потому, что вам нужна одна строка кода для ее вызова. Но, конечно, этот код полезности ограничен. Он хорошо работает для этого мобильного приложения или для загрузки конфигурации XML. И вот почему разработчик добавил для него класс утилиты.

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

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

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

Ответ 2

Хорошим решением этой проблемы является добавление дополнительной объектной ориентации. Чтобы использовать ваш пример:

Пример: у инженера A есть 3 места, которые ему необходимо преобразовать XML в String, поэтому он пишет класс утилиты, называемый XMLUtil, и помещает в него статический метод toString (Document)

Решение состоит в том, чтобы прекратить использование примитивных типов или типов, предоставляемых JVM (String, Integer, java.util.Date, java.w3c.Document) и обернуть их в свои собственные классы, специфичные для проекта. Тогда ваш класс XmlDocument может предоставить удобный метод toString и другие методы утилиты. Ваш собственный ProjectFooDate может содержать методы синтаксического анализа и форматирования, которые в противном случае оказались бы в разных классах DateUtils и т.д.

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

Ответ 3

Существует несколько способов гибкости /XP, которые вы можете использовать для решения этой проблемы, например:

  • разговаривать друг с другом (например, во время ежедневной встречи в режиме ожидания)
  • парное программирование/обзор кода

Затем создайте, документируйте и протестируйте один или несколько проектов библиотек утилиты, на которые можно ссылаться. Я рекомендую использовать Maven для управления зависимостями/версиями.

Ответ 4

Вы можете подумать о том, чтобы все классы полезности были помещены в хорошо организованную структуру пакетов, например com.yourcompany.util.. Если люди хотят назвать подпакеты и классы хорошо, то, по крайней мере, если им нужно найти утилиту, они знают, где искать. Я не думаю, что здесь есть какой-то серебряный пуля. Общение важно. Может быть, если разработчик отправит простую электронную почту остальным сотрудникам отдела разработки, когда они напишут новую утилиту, этого будет достаточно, чтобы получить ее на радарах людей. Или общую страницу вики, где люди могут перечислить/документировать их.

Ответ 5

  • Командная связь (кричать "эй кто-то имеет документ toString?" )
  • Сохранять классы утилиты до абсолютного минимума и ограничивать их одним пространством имен
  • Всегда думайте: как я могу сделать это с помощью объекта. В вашем примере я бы расширил класс Document и добавил к ним те методы toString и serialize.

Ответ 6

Эта проблема помогает при объединении функций IDE с "завершением кода" с языками, поддерживающими расширения типов (например, С# и F #). Таким образом, для представления Java была такая возможность, программист мог бы легко изучить все методы расширения класса в среде IDE, например:

Document doc = ...
doc.to //list pops up with toXmlString, toJsonString, all the "to" series extension methods

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

Ответ 7

Его довольно сложно создать инструмент, который распознает "ту же функциональность". (В теории это на самом деле невозможно, и где вы можете это сделать на практике, вам, вероятно, понадобится доказательство теоремы).

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

Наш CloneDR - это инструмент для обнаружения точного и близкого к пропуску клонированного кода на основе использования параметризованных деревьев синтаксиса. Он соответствует разборным версиям кода, поэтому его не путают макет, измененные комментарии, пересмотренные имена переменных или во многих случаях вставляемые или удаленные операторы. Существуют версии для многих языков (С++, COBOL, С#, Java, JavaScript, PHP,...), и вы можете увидеть примеры выполнения операций клонирования при условии ссылка. Обычно он находит дублированный код 10-20%, и если вы отрисуете этот код на библиотечные методы на религиозной основе, ваша база кода может фактически сократиться (что произошло с одной организацией, использующей CloneDR).

Ответ 8

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

  • TeamCity: удивительный простой в использовании продукт, который управляет всем вашим автоматическим построением кода из вашего репозитория и запускает модульные тесты и т.д. < бр /" > Это даже бесплатный продукт для большинства людей.
    Еще лучшая часть: он построил в код дублирования обнаружения по всему вашему коду.
    li >

Больше информации для чтения:

Ответ 9

  • стандартный проект утилиты приложений. постройте банку с ограниченной областью расширяемости и пакетом на основе функциональности.
  • используйте общие утилиты, такие как apache-commons или google collections и предоставляйте абстракцию
  • поддерживать базу знаний и документацию и отслеживать JIRA для ошибок и улучшений.
  • эволюционный рефакторинг
  • findbugs и pmd для поиска дублирования кода или ошибок
  • утилиты для проверки и тестирования утилиты
  • Используйте карму! попросите членов команды внести вклад в базу кода, когда они найдут ее в существующем коде джунглей или потребуют новых.