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

Избегайте или охватывайте конструкции С#, которые нарушают редактирование и продолжение?

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

Требуется немного прояснить эти вещи

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

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

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

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

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

Ответ 4

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

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

  • Меньше выразительных
  • Более длинные
  • Повторяется (исключая общие методы)
  • Не переносится (никогда не отлаживать и не тестировать 64-битные?!?!?)

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

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

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

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

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

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

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

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

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

Там я многое сделаю, чтобы было легче найти ошибки, но не так, чтобы облегчить ошибки.

Ответ 8

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

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

Ответ 9

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

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

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

Ответ 10

Проблема, с которой вы, похоже, сталкиваетесь:

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

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

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

Отделив код UI от других классов, которые могут быть протестированы с помощью модульных тестов, вы сможете использовать все С# -структуры в этих классах. Затем вы можете просто ограничить используемые в коде пользовательского интерфейса конструктивные элементы.

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