В прошлом году я нашел в блоге этот до смешного нечитаемый фрагмент кода C#. Без объяснений, вот код:

for (Dog _dog = _animal as Dog; _dog != null; _dog = null) {
//здесь находится бизнес-логика
}

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

1. Опишите, что произойдет, когда этот цикл for будет выполнен.
2. Что бы вы сделали, если бы столкнулись с таким кодом в приложении?

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

Но остается вопрос: что здесь происходит? Я думаю, что это допустимый сценарий кода, с которым можно проверить собеседника C#, потому что большинство из нас думают о конструкции цикла for только как о полезной для итерации по коллекции. Да, вы можете перебирать коллекцию с помощью цикла for, но в C# для этого есть лучший инструмент: цикл foreach. Что делает цикл for интересным, так это то, что это конструкция «назначить, оценить, переназначить».

(Если вы действительно хотите знать, что здесь происходит, объяснение находится в конце этой части.)

По общему признанию, это выглядит как вопиющая ошибка в вопросе на собеседовании, но суть не в этом. Ожидание не в том, что кто-то объяснит это (что они, вероятно, не смогут сделать, если они уже не прочитали это: http://stackoverflow.com/a/7113387), а в том, чтобы быть немного сбитым с толку сбалансируйте его перед описанием логического потока, что позволит им увидеть, как и почему он работает. После того, как процесс цикла for будет объяснен и опрашиваемый получит его, за столом будет задан вопрос, который на самом деле описывает этот сценарий: Что бы вы сделали, если бы столкнулись с таким кодом? в производственном приложении? Я ищу любой разумный вариант следующего: я бы переписал его следующим образом, чтобы сделать его более понятным для каждого программиста после меня, который должен работать в этой части кодовая база:

Dog _dog = _animal as Dog;
if (_dog != null) {
//здесь идет бизнес-логика
}

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

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

(Если вы еще не прошли курс Кори Хауса по чистому коду — Чистый код, написание кода для людей — вам действительно стоит… Я не могу рекомендовать его достаточно высоко.)

* * * * * * * * * * * * * * *

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

Первоначальное назначение: это происходит только один раз в жизненном цикле цикла for. Мы определяем переменную типа Dog и, используя ключевое слово as, приводим _animal к Dog и присваиваем его переменной _dog. Если ключевое слово as в C# для вас новое, важно знать, что если _animal не может быть приведено к Dog, то возвращается null.

Утверждение оценки: _dog != null. На предыдущем шаге, если _animal может быть приведено к Dog, то это оценивается как true (_dog не будет нулевым), поэтому будет выполняться код в теле цикла for.

Заявление о переназначении: это может быть та часть, которая больше всего вас сбивает с толку. Обычно это утверждение похоже на «i++» (или «i+3», если счет до 3 делает вас счастливее), но здесь работает любое допустимое присваивание, включая «_dog = null». Этот оператор запускается после первого выполнения кода в теле цикла и непосредственно перед повторным запуском оценочного теста (_dog != null).

На простом английском языке: если _animal можно привести к типу Dog, тогда запустите блок кода ровно один раз. Полезно осознавать, что цикл for может использоваться таким образом, но написание такого кода крайне сложно читать… настолько сложно, что даже после того, как он объяснен, вы, вероятно, возвращаетесь к его пошаговому прохождению в своем мозгу. Такой тупой код всегда должен быть переписан во что-то более простое для понимания.

Первоначально опубликовано на http://www.mikece.com 6 августа 2015 г.