Статьи

Имя должно выражать намерение

На этот раз я начну с примера кода. Взгляните на это:

1
2
3
if (code.isComplexOrUnreadable()) {
    refactor(code);
}

Можете ли вы сказать мне, что не так с этим кодом? Нет?

Позвольте мне задать вам еще один вопрос. Как вы думаете, как выглядит реализация метода isComplexOrUnreadable ()?

Я предполагаю, что многие из вас представят что-то похожее на это:

1
2
3
boolean isComplexOrUnreadable() {
    return complex || unreadable;
}

Я прав?

Хорошо, позвольте мне еще раз спросить вас: можете ли вы сказать мне, что не так с этим кодом?

Первое касается дублирования информации, которое теперь должно быть для вас очевидным. Вторая вещь связана с отсутствием информации. Как это возможно, спросите вы? Позволь мне объяснить.

Не повторяй себя

Мы повторяем информацию о том, как метод был реализован. Это определенно то, чего мы должны избегать.

Ты помнишь
СУХОЙ принцип? Мы не будем повторять код, потому что если мы сделаем это, нам придется помнить об обновлении двух или более мест в случае каких-либо изменений.

Что произойдет, если через некоторое время мы решим изменить реализацию тела метода?

1
2
3
boolean isComplexOrUnreadable() {
    return (complex || unreadable) && tests.exist();
}

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

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

1
2
3
boolean isComplexOrUnreadableWithTests() {
    return (complex || unreadable) && tests.exist();
}

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

1
return complex || unreadable && tests.exist();

Как видите, даже «правильное» имя может вводить в заблуждение в ситуации, когда имя отражает реализацию.

Недостающий Почему!

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

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

Какое изменение будет хорошей причиной для изменения этого метода:

1
2
3
boolean isComplexOrUnreadable() {
    return complex || unreadable;
}

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

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

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

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

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

Проблема может стать еще больше, если есть много способов получить ответ, потому что мы можем выбрать другую реализацию.

Что мы делаем в таком случае? Мы дублируем логику. И что является более проблемным событием, эти виды дублирования могут быть чрезвычайно трудно найти из-за разных имен методов / классов и потенциально разных реализаций.

Почему вам нужно

Как вы можете видеть, имя, которое описывает, КАК, а не ПОЧЕМУ, может быть огромной проблемой и может привести к другим проблемам, которые ухудшают качество вашего кода. Это не то, что мы, как профессионалы, хотели бы сделать.

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

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

И, наконец, вот как может выглядеть код, если его имя будет выражать намерение:

1
2
3
if (code.canBeImproved()) {
    refactor(code);
}
Ссылка: Название должно выражать намерение нашего партнера по JCG Себастьяна Малаки в блоге « Давайте поговорим о Java» .