Каков правильный баланс между целостностью кода и улучшением кода?

53

Недавно у меня была дискуссия с коллегой по поводу стиля кода. Он утверждал, что использование вами API-интерфейсов и общих шаблонов, которые вы используете, должно быть как можно более похожим с окружающим кодом, если не с базой кода в целом, так же, как если бы вы использовали внешний вид кода (позиционирование фигурных скобок, использование заглавных букв и т. Д.) , Например, если бы я добавлял метод в класс DAO в C #, я бы попытался использовать LINQ там, где это необходимо, чтобы сделать мой код чистым и простым в обслуживании, даже если ни один из других методов в этом классе не использовал его. Тем не менее, мой коллега будет утверждать, что я не должен использовать его в этом случае, потому что это будет противоречить существующему стилю этого класса и, следовательно, будет сложнее понять.

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

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

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

Роберт Джонсон
источник
14
Так как же улучшится качество кода, если все ограничатся «плохим» способом?
Изката
Когда вы пишете LINQ, вы не имеете в виду LINQ to SQL? Если да, то я могу согласиться с твоим другом. Если вы говорите о LINQ, то я не согласен с ним. Все должны быть знакомы с LINQ в эти дни. Это не их выбор. Им платят, чтобы быть знакомыми.
Петр Перак
@Peri Я имел в виду просто базовый LINQ - я думаю, мой пример должен был работать с IEnumerables, а не с DAO.
Роберт Джонсон
2
ICYMI - комикс Дилберта на эту тему: dilbert.com/strips/2013-09-21
Джим Бетанкур,

Ответы:

53

Чтобы дать более общий ответ:

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

  • Насколько выгоден «правильный» путь?

    • Иногда новая и улучшенная передовая практика значительно повышает производительность, устраняет ошибки, намного упрощает программирование и т. Д. В таком случае я бы сильно склонялся к использованию нового метода. С другой стороны , «правильный путь» может быть немного больше, чем синтаксический сахар, или согласованный идиоматический метод выполнения чего-то, что на самом деле не превосходит. В этом случае согласованность кода, вероятно, важнее.
  • Насколько серьезной может быть проблема несоответствия?

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

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

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

samthebrand
источник
7
Очень хороший и взвешенный ответ (+1). По моему опыту, команда может быть более продуктивной, если все согласны с относительно небольшим набором хорошо понятых идиом, чем если бы каждый член команды мог свободно использовать новые и разные идиомы, которые другим членам команды может быть трудно понять. Небольшое замечание в отношении утверждения «переписать существующий код, чтобы он использовал самые последние практики и был последовательным»: «последний» не означает автоматически «лучше». Надо всегда решать от случая к случаю.
Джорджио
1
@ Джорджио, спасибо за отзыв; Я подправил язык финальной точки.
6
Хороший ответ и хороший комментарий от Джорджио. Возможно, стоит учесть, что в этом примере, в зависимости от команды / культуры, возможно скоординированное принятие команды, а не начало в одиночку. Это уменьшает некоторые риски, связанные с техническим обслуживанием (так как все на борту). (т.е. уделять больше внимания реальным навыкам команды в данный момент, а не к коду, который они написали в прошлом.)
Мэтт
+1. Согласованный, тщательный и взвешенный ответ - хорошее рассмотрение различных сценариев. Опять же, хороший комментарий от Джорджио.
Роберт Джонсон
1
Что касается принятия новых идиом, технологий: я бы посчитал начало нового проекта хорошей точкой для введения новых вещей. После этого на протяжении всего проекта стиль кода должен быть максимально согласованным. Недавно мне пришлось выкопать какой-то 5-летний код, и я был очень рад, что смог все же найти свой путь через этот код, потому что вся команда придерживалась общей архитектуры и набора идиом, с которыми мы договорились (не без борьбы! ) в начале проекта.
Джорджио
26

Оставаться последовательным не имеет большого значения с моей точки зрения; постоянное совершенствование является обязательным.

Позиция вашего коллеги действительно препятствует инновациям. Аргумент согласованности приводит вас в ситуацию, когда вы можете использовать, например, LINQ, только если вы перенесете весь код для использования LINQ. И у нас нет времени для этого, не так ли?

Я предпочел бы иметь противоречие, когда некоторый код все еще работает foreachнад ArrayLists, а другие части используют LINQ IEnumerable<T>вместо того, чтобы придерживаться самого старого способа работы до конца времени.

Ваши коллеги обязаны оставаться актуальными и изучать новые способы ведения дел.

Joppe
источник
3
«Ваши коллеги обязаны оставаться актуальными и изучать новые способы ведения дел». Возможность состоит в том, чтобы использовать новые идиомы и библиотеки в новом коде (новые модули) и поддерживать согласованный стиль в унаследованном коде.
Джорджио
8

Согласованность API очень важна как для общедоступных, так и для внутренних API.

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

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

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

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


Что касается новых языковых функций, таких как LINQ (ну, это не совсем новое), единственное, что нужно учитывать, - будет ли достаточно новая версия языка / библиотек использоваться везде, где будет использоваться код? В случае сомнений придерживайтесь функций, которые, как известно, совместимы. Это, конечно, не мешает вам продвигать обновление версии по всей системе, поэтому вы можете начать использовать новые приятные вещи.

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

Хайд
источник
6

Ответ на это прост.

Последовательность имеет первостепенное значение.

но это идет с оговоркой ...

Вы и ваш коллега, вероятно, зациклены на неправильной последовательности

Реализации одноразовые. Они могут быть полностью пересмотрены с различной степенью легкости в зависимости от качества и полноты набора тестов. Беспокоясь о таких вещах, как «Должно ли это быть свойство?», «Разве тонкий код не должен использовать LINQ вместо конструкции более низкого уровня?» имеет сомнительную ценность Его сложно привязать к каким-либо измерениям к значению согласованности на уровне реализации. Гораздо лучше задать вопрос на этом уровне: «Работает ли этот код так, как рекламируется?». TL; Последовательность реализации DR - это то место, где «маленькие умы» надевают хобгоблинов.

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

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

API не являются одноразовыми.

Это все уровень кода API, веб-сервисы, SDK и т. Д. Они должны, ДОЛЖНЫ, быть согласованными. Повышение производительности от такого разнообразия согласованности огромно по ряду причин:

Интеграционные тесты:

Если вы поддерживаете свой API, вы можете создавать наборы интеграционных тестов. Это позволяет разработчикам свободно обмениваться деталями реализации и добиваться немедленной проверки. Хотите поменять вашу совместную работу на LINQ? Проводятся ли интеграционные тесты? Он также обеспечивает проверку при подготовке к производству. Поскольку компьютеры работают быстро, один ноутбук может выполнить работу тысячи тестеров, выполняющих повседневные задачи. Это равносильно значительному увеличению численности персонала вашей организации.

производительность

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

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

Заключение

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

Рэймонд Хеттингер (Raymond Hettinger) в своем выступлении на Pycon 2015 отметил несколько отличных моментов, касающихся использования руководства по стилю PEP8 для команд программистов на python. Он показал, что одержимость стилистической последовательностью фрагмента кода заставила рецензентов пропустить серьезные недостатки логики и дизайна. Его гипотезу можно резюмировать так, как легко найти стилистические несоответствия; определить реальное качество фрагмента кода сложно

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

nsfyn55
источник
4

Не знакомы с LINQ? Если это так, не станет ли мой код более понятным для моих коллег-разработчиков, если я не буду его использовать?

Язык C # все еще развивается. Если бы люди не узнали об изменениях в C # 1, они бы упустили:

  • Дженерики
  • Partials
  • Анонимные методы
  • итераторы
  • Обнуляемые типы
  • Авто-недвижимость
  • Анонимные типы
  • Методы расширения
  • вереск
  • Лямбда
  • Асинхронные методы

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

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

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

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

Сэм
источник
2
Я полностью согласен с тем, что вы говорите, но мой вопрос не столько о новых возможностях языка и ответственности разработчиков за их изучение, сколько о более общем вопросе решения подобных проблем различными способами в относительно небольшой области кода. Я упомянул LINQ, потому что это хороший пример использования другого способа решения проблемы. Мой коллега рад использовать новые языковые функции, но только если они не идут вразрез с кодом, над которым он работает.
Роберт Джонсон
@RobertJohnson Я хотел бы указать вашему коллеге, что удобство сопровождения превосходит согласованность, поэтому даже если что-то «идет вразрез» с существующим кодом, если его удобнее поддерживать, вы должны это сделать. Я сомневаюсь, что использование старого DAO позволит лучше обслуживать Linq.
Энди
3

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

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

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

меритон - забастовка
источник
1

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

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

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

Ozz
источник
Для чего был минус?
Оз
0

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

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

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

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

user606723
источник
-1

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

Муравей
источник
Для чего был понижен?
Муравей
Я не был downvoter, но это не кажется целенаправленным для вопроса. Это командный процесс, который можно применять ко всему, а не к обсуждению проблем стиля кодирования. Кроме того, вы не имеете в виду «изобрел колесо», а не «заново изобрел колесо»?
Я предполагаю, что это семантика, является ли бревно типом колеса или нет, но оно вращается, уменьшает трение, имеет поверхность, которая находится в последовательном контакте с землей и является круглой. Я уверен, что есть лучшие примеры того, что я имею в виду - я оставлю это в качестве упражнения для читателя.
Муравей