Избегать или использовать конструкции C #, которые нарушают редактирование и продолжение? - PullRequest
20 голосов
/ 05 октября 2010

Я разрабатываю и поддерживаю большое (500k + LOC) приложение WinForms, написанное на C # 2.0.Он многопользовательский и в настоящее время развернут на 15 машинах.Разработка системы продолжается (может рассматриваться как вечная бета-версия), и очень мало сделано для защиты пользователей от потенциальных новых ошибок, которые могут появиться в еженедельной сборке.

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

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

  • Анонимные методы и встроенные делегаты (если полностью невозможно переписать)
  • Универсальные методы (кроме стабильного, неизменного кода утилиты)
  • Ориентация проектов на «Любой ЦП» (т.е. никогда не выполняется в 64-битном режиме)
  • Инициализация полей в точке объявления (инициализация перемещается в конструктор)
  • Запись блоков перечислителя, использующих yield (кроме кода служебной программы)

Теперь я полностью осознаю, что новые языковые функции в C # 3 и 4 в значительной степени несовместимы с функциями редактирования и продолжения (лямбда-выражения, LINQ и т. д.),Это одна из причин, по которой я сопротивлялся переходу проекта на более новую версию Framework.

Мой вопрос заключается в том, является ли хорошей практикой избегать использования этих более сложных конструкций в пользу кода, которыйочень легко отлаживать?Есть ли законность в таком развитии или это расточительно?Кроме того, важно, что любая из этих конструкций (лямбда-выражения, анонимные методы и т. Д.) Влечет за собой накладные расходы производительности / памяти, которых может избежать хорошо написанный, совместимый с редактированием и продолжением код?... или внутренняя работа компилятора C # заставляет такие сложные конструкции работать быстрее, чем написанный вручную "расширенный" код?

Ответы [ 10 ]

21 голосов
/ 05 октября 2010

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

Таким образом, вы затрачиваете усилия один раз, а каждый второй раз «бесплатно» ...

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

Как упоминает @Dave Swersky в комментариях, книга Мчаэля Перса, Эффективная работа с устаревшим кодом - хороший ресурс (он унаследован через 5 минут после того, как вы его написали, верно?)

Так что да, я думаю, что это ошибка - избегать новых контрактов C # в пользуредактировать и продолжить;НО я также думаю, что ошибочно использовать новые конструкции только ради этого, и особенно если они ведут к усложнению понимания кода.

6 голосов
/ 06 июня 2012

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

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

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

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

Ваш подход не должен быть черно-белым.

4 голосов
/ 05 октября 2010

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

Я бы сказал, что каждый раз, когда вы заставляете себя писать код:

  1. Менее выразительный
  2. 1010 * Более длинные *
  3. Повторяется (от избегания универсальных методов)
  4. Непереносимый (никогда не отлаживать и тестировать 64-битные ??!?!?)

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

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

4 голосов
/ 05 октября 2010

Хотелось бы немного пояснить эти вещи

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

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

все можно попробовать и проверить в режиме реального времени, не останавливая процесс.

Это утверждение вводит в заблуждение.С помощью Edit и Continue можно проверить, что изменение устраняет очень специфическую проблему.Гораздо сложнее проверить, правильно ли внесено изменение, и не устраняет ли оно множество других проблем.А именно потому, что edit и continue не изменяют двоичные файлы на диске и, следовательно, не допускают такие элементы, как модульное тестирование.

В целом, хотя да, я думаю, что было бы ошибкой избегать новых конструкций C # в пользу разрешения редактирования и продолжения.«Редактировать и продолжить» - отличная функция (она мне очень понравилась, когда я впервые столкнулся с ней в C ++).Но его ценность, поскольку вспомогательный производственный сервер не компенсирует производительную выгоду от новых функций C #, IMHO.

2 голосов
/ 05 октября 2010

Хотя в вашем подходе нет ничего плохого по сути, он ограничивает степень выраженности, понятную IDE.Ваш код становится отражением его возможностей, а не языка, и, следовательно, ваша общая ценность в мире разработки уменьшается, потому что вы сдерживаете себя от изучения других методов повышения производительности.Отказ от LINQ в пользу «Edit-and-Continue» лично мне кажется огромной альтернативной ценой, но парадокс заключается в том, что вам нужно получить некоторый опыт, прежде чем вы сможете почувствовать это.Как уже упоминалось в других ответах, модульное тестирование вашего кода устраняет необходимость для постоянного запуска всего приложения и, таким образом, решает вашу дилемму другим способом.Если вы не можете щелкнуть правой кнопкой мыши в своей IDE и протестировать только те 3 строки кода, которые вас интересуют, вы уже слишком много работаете во время разработки.

1 голос
/ 05 октября 2010

Я также работал над очень большими постоянными бета-проектами.

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

Я использовал универсальные методы и классы для повторного использования и надежности.

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

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

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

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

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

1 голос
/ 05 октября 2010

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

http://www.codinghorror.com/blog/2006/02/revisiting-edit-and-continue.html

Относительно конкретного вопроса: не избегайте этих конструкций и не полагайтесь на своенавыки отладки - старайтесь вообще избегать ошибок (в развернутом программном обеспечении).Вместо этого напишите юнит-тесты.

0 голосов
/ 05 октября 2010

Похоже, у вас возникла проблема:

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

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

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

Разделение ни одного кода пользовательского интерфейса на другие классы, которые можно протестировать с помощью модульных тестов, позволит вам использовать все конструкции C # в этих классах.Тогда вы можете просто ограничить использование конструкций в самом коде пользовательского интерфейса.

Когда я начал писать множество модульных тестов, мое использование «edit-and-continue» прекратилось, я с трудом использовал его отдельноиз кода пользовательского интерфейса.

0 голосов
/ 05 октября 2010

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

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

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

0 голосов
/ 05 октября 2010

Вы можете попробовать Test Driven Development . Я нашел очень полезным вообще избегать использования отладчика. Вы начинаете с нового теста (например, модульного теста), а затем запускаете только этот модульный тест, чтобы проверить свою разработку - вам не нужно, чтобы все приложение работало постоянно. А это значит, что вам не нужно редактировать и продолжать!

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

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