Я много слышал о том, чтобы методы были короткими, и я слышал, как многие программисты говорят, что использование тегов #region внутри метода является верным признаком того, что он слишком длинный и должен быть преобразован в несколько методов. Однако мне кажется, что во многих случаях разделение кода с тегами #region внутри метода является лучшим решением для рефакторинга на несколько методов.
Предположим, у нас есть метод, вычисления которого можно разделить на три довольно разных этапа. Кроме того, каждый из этих этапов имеет отношение только к вычислениям для этого метода, и поэтому их извлечение в новые методы не дает нам повторного использования кода. Каковы же преимущества извлечения каждой фазы в свой метод? Насколько я могу судить, все, что мы получаем, это некоторая читаемость и отдельная переменная область действия для каждой фазы (что поможет предотвратить случайное нарушение модификаций определенной фазы другой фазой).
Тем не менее, оба из них могут быть достигнуты без выделения каждой фазы в свой собственный метод. Теги регионов позволяют нам свернуть код в форму, которая так же удобочитаема (с дополнительным преимуществом, что нам больше не нужно покидать свое место в этом файле, если мы решим расширить и исследовать код), и просто заключить каждую фазу в {}
создает свою собственную область для работы.
Преимущество такого подхода состоит в том, что мы не загрязняем область действия уровня класса тремя методами, которые на самом деле имеют отношение только к внутренней работе четвертого метода. Мне кажется, что немедленный рефакторинг длинного метода в серию коротких методов является повторным использованием кода, эквивалентным преждевременной оптимизации; Вы вводите дополнительную сложность для решения проблемы, которая во многих случаях никогда не возникает. Вы всегда можете извлечь один из этапов в его собственный метод позже, если возникнет возможность повторного использования кода.
Мысли?
источник
#region
теги, но и отключаю свертывание кода в Visual Studio. Мне не нравится код, который пытается скрыть от меня.Ответы:
Все, что вам нужно, - это чтобы ваш код был пригоден для использования, а не для повторного использования. Обезьяна может преобразовать пригодный для использования код в повторно используемый код, если есть какие-либо преобразования, которые нужно сделать вообще.
Аргумент «Мне нужно это только здесь», говоря вежливо. Технику, которую вы описываете, часто называют техникой заголовков, и ее обычно осуждают.
Также актуально: мысли Джеффа Этвудса о свертывании кода
источник
Проблема заключается не в регионах в методах, а в том случае, когда есть необходимость (или даже использование) для помещения областей в методы.
После того, как мне пришлось отлаживать множество 200-300 строковых методов, я могу сказать, что никому не хотел бы этого. Если вы пишете и присматриваете за собственным кодом, это нормально - делайте что хотите. Но как только кто-то еще смотрит на это, должно быть сразу ясно, что делает метод.
Нет, этого недостаточно. Разбейте его на регионы, сколько захотите, но я все еще качаю головой, просто думая об этом.
Если вы взломаете методы, вы получите много преимуществ:
///
) и введите описание, параметры, тип возвращаемого значения, а такжеexception
,example
,remarks
узлы подробно эти сценарии. Вот куда это идет, вот для чего оно!{}
, но должен ли я проверять каждый метод, чтобы убедиться, что вы не «обманули»? ЭтоdodgyObject
я использую здесь только потому, что используется в этом регионе, или это откуда-то еще? Если бы я был по своему собственному методу, я бы легко мог увидеть, был ли он передан мне или я сам его создал (или, скорее, вы его создали).TurnThingsUpsideDown
метод не удался - возможно, он проваливается, но плохо получается» - это гораздо лучше, чем «О,DoEverything
метод не удался - это могло быть 50 разных вещей, и мне придется поискать его в течение часа» ,Это все перед любыми проблемами повторного использования или улучшения. Правильно разделенные методы, очевидно, облегчают повторное использование, а также позволяют легко заменить метод, который не выполняется (слишком медленный, слишком глючный, измененная зависимость и т. Д.). Вы когда-нибудь пробовали рефакторинг любого из этих огромных методов? Нет никакого способа узнать, что то, что вы меняете, не повлияет ни на что другое.
Пожалуйста, правильно заключите вашу логику в методы разумного размера. Я знаю, что им легко выйти из-под контроля, и спорить о том, что не стоит перепроектировать один раз в этот момент, является другой проблемой. Но вы должны принять тот факт, что не будет никакого вреда и, по крайней мере, потенциальной выгоды от правильно инкапсулированных, четко написанных и просто разработанных методов.
источник
Если ваш метод достаточно сложен, чтобы его можно было разделить на три отдельные фазы, то это должны быть не только три отдельных метода ... но на самом деле ваш метод должен быть отдельным классом, предназначенным для этих вычислений.
«Но тогда у моего класса будет только один публичный метод!»
Вы правы, и в этом нет ничего плохого. Идея принципа единой ответственности состоит в том, что ваш класс делает одно .
Ваш класс может вызывать каждый из трех методов по очереди и возвращать результат. Одна вещь.
В качестве бонуса, теперь ваш метод является тестируемым, потому что он больше не является приватным методом.
Но не берите в голову один класс; в действительности у вас должно быть четыре : один для каждой части вашего метода, плюс один, который принимает каждую из трех в качестве зависимости и вызывает их в правильном порядке, возвращая результат.
Это делает ваши занятия еще более тестируемыми. Это также позволяет вам легко изменить одну из этих трех частей. Просто напишите новый класс, унаследованный от старого, и переопределите измененное поведение. Или создайте интерфейс для поведения каждого из ваших трех частей; а затем, чтобы заменить один, просто напишите новый класс, реализующий этот интерфейс, и замените его на старый в конфигурации контейнера внедрения зависимостей.
Какая? Вы не используете инъекцию зависимости? Ну, вы, вероятно, еще не видели необходимости, потому что вы не следуете принципу единой ответственности. Как только вы начнете, вы обнаружите, что самый простой способ дать каждому классу свои зависимости - это использовать DI-контейнер.
РЕДАКТИРОВАТЬ :
Хорошо, давайте отложим вопрос рефакторинга. Цель
#region
состоит в том, чтобы скрыть код , который в основном означает код, который не нужно редактировать ни при каких обычных условиях. Сгенерированный код является лучшим примером. Он должен быть скрыт в регионах, потому что обычно вам не нужно его редактировать. Если вам это нужно, то расширение области дает вам небольшое предупреждение в стиле «Здесь будут драконы», чтобы убедиться, что вы знаете, что делаете.Поэтому я бы сказал,
#region
что не следует использовать в середине метода. Если я открою метод, я хочу увидеть код. Использование #region дает мне другой уровень сокрытия, который мне не нужен, и это становится раздражением: я раскрываю метод ... и все еще не вижу никакого кода.Если вы беспокоитесь о том, что люди видят структуру метода (и вы отказываетесь от его рефакторинга), добавьте комментарии баннера, например:
Это поможет кому-то, просматривая код, увидеть отдельные части вашего метода, не имея дело с расширением и свертыванием
#region
тегов.источник
ctrl+n
Я думаю, что пример, который вы приводите в своем аргументе, касается не YAGNI (вам это не понадобится), а больше касается написания надлежащего качественного кода, который легко поддерживать.
На самых ранних курсах по программированию мы узнаем, что если метод имеет длину 700 LOC, он, вероятно, слишком большой и, безусловно, будет огромной болью, чтобы попробовать и отладить.
Во-вторых, если я напишу методы A, B и C, которые используются только в методе D, тогда мне будет проще проводить модульное тестирование AB и C независимо от D, что позволяет проводить более надежные модульные тесты во всех 4 методах.
источник
Это два преимущества. Но, во всяком случае, для меня важна отлаживаемость . Если вам нужно проследить через этот код, гораздо проще перешагнуть через два из трех разделов и перейти только к тому, который вам нужен. Рефакторинг на более мелкие методы позволяет это; теги региона нет.
источник
ctrl-f10
- беги к курсоруМое личное правило: если метод длиннее одного экрана, скажем, 40 строк, он слишком длинный. Если класс длиннее 500 строк, он слишком большой. Я иногда нарушаю эти правила, иногда даже большим числом, но обычно я сожалею об этом в течение года.
Даже метод длиной от 20 до 30 строк в большинстве случаев становится немного длиннее. Поэтому я бы сказал, что использование областей в методе - это, как правило, плохая идея, просто потому, что почти никогда не имеет смысла разбивать область из 20-30 строк на несколько субрегионов.
Разбивка функций, которые являются длинными по этому определению, имеет как минимум два преимущества:
Вы можете указать, что делают эти подфункции, что проясняет ваше нынешнее мышление и упрощает задачу последующих сопровождающих.
Разложение на меньшие функции вынуждает вас передавать только те параметры, которые нужны этим меньшим функциям, поэтому объем данных, которые они требуют и изменяют, предельно ясен. Это предполагает, что вы не получаете доступ и не изменяете состояние объекта в сотне различных конечных функций, что я также не рекомендовал бы.
По моему опыту, эти правила создают код, который легче писать, не совершая типичных ошибок, и его можно понять и изменить позже, не нарушая тонкого поведения. Не имеет значения, является ли человек, который должен понимать / модифицировать код, кем-то другим, или я сам после того, как я спал и забыл все.
Поэтому я бы рассматривал регионы в методах как «запах кода», указывающий на применение неустойчивых методов. Как всегда, могут быть исключения, но они случаются настолько редко, что их почти не стоит обсуждать.
источник
Здесь мы снова ... Есть много других тем на программистов, которые оказались в той же дискуссии.
Вы указываете на некоторые очень интересные аргументы, касающиеся коротких функций. Это не популярное утверждение, но я с вами об этом . После того, как я обсуждал это много раз раньше, у меня складывается впечатление, что дискуссия обычно сводится к тому, сосредоточены ли вы в первую очередь на правильной инкапсуляции или на максимальном уровне разработки, основанной на тестировании. Это два главных претендента на то, что, похоже, превращается в еще одну священную войну, и я боюсь, что мы находимся под слабой стороной.
Тем не мение ...
Решение, на мой взгляд, определенно не охватывает «фазы» в регионах. Сворачивание кода используется, чтобы смести код под ковриком. Оставьте код там, как он есть, это может напомнить вам, что вы можете реорганизовать его позже! Чтобы связать это с аргументом в вашем вопросе: как вы сможете увидеть возможность повторного использования кода, если вы не видите кода? Длинные сегменты кода должны быть именно таким, шипом в глазу, который заставляет вас захотеть его реорганизовать.
В качестве подходящей замены для регионов я предлагаю использовать параграфы кода, поскольку Алекс Пападимулис называет их в комментарии . Возможно, вы уже используете подобный подход. Это просто блоки кода с заголовком комментария, объясняющие, что делает весь блок. У вас есть удобочитаемость функций, но вы можете использовать английские предложения с нормальным интервалом, и вы не потеряете инкапсуляцию.
источник
Хотя я согласен с тем, что обычно лучше реорганизовать код, чем использовать
#region
, это не всегда возможно.Чтобы поддержать это утверждение, позвольте мне привести пример.
Легко перенастроить регионы, чтобы изменить порядок или расширить, когда дополнительные поля добавляются в класс. В любом случае, комментарии необходимы, чтобы быстро увидеть, как должен работать порядок. И больше всего: я не вижу, как рефакторинг поможет читабельности в этом случае.
Тем не менее, эти исключения редки. Обычно это можно сделать рефакторинг, как говорят многие другие ответы.
источник
Я не думаю, что есть единственный ответ, почему некоторые люди или команды решают не использовать,
#region
но если бы мне пришлось перечислить несколько, это были бы главные причины, которые я видел.источник