Рефакторинг: Выделите Метод, Когда Это Имеет Смысл

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

Получил ли я эти знания от «Идеальный код» , либо из «Чистый код» - трудно запомнить.

В целом это не особо важно.

Мы все знаем, что нам следует разделить бизнес-логику на хорошо названные функции.

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

Я лично знаю «программиста», написавшего этот код. Помню, как впервые столкнулся с этой функцией.

Нетрудно предсказать, что моей первой реакцией было: «Какого черта!!! Кто родил эту хрень??Э» Да, представьте себе, этот «программист» до сих пор торчит здесь, в офисе, где я сейчас работаю над текущими проектами.

Я не хочу вдаваться в эту историю, но хочу упомянуть, что эта функция длиной в 5 тысяч строк была ядром программы длиной около 150 тысяч строк.

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

В итоге было принято решение переписать приложение с нуля.

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

Другая крайность — отключить мозг и начать везде распределять классы с однострочными функциями внутри.

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

Сначала нужно проанализировать проблему.

Прежде чем углубляться в этот вопрос, я хотел бы отметить, что, вообще говоря, некоторое время назад между дядей Бобом и Кристиной Горман произошла небольшая стычка на эту тему.

дядя Боб представил технику, которую он назвал «Извлекай до упаду».

, что вкратце означает — извлекать функции до тех пор, пока есть что извлекать.

Кристин Горман чувствовал, что эта техника исключает использование мозга .

Кроме того, был Сообщение Джона Сонмеза о рефакторинге одной функции из .

NET BCL (хотя изначальной целью статьи было показать, что большинство комментариев — зло).

Давайте посмотрим на пример рефакторинга Джона.

В качестве примера он взял следующий метод:

  
   

internal static void SplitDirectoryFile( string path, out string directory, out string file) { directory = null; file = null; // assumes a validated full path if (path != null) { int length = path.Length; int rootLength = GetRootLength(path); // ignore a trailing slash if (length > rootLength && EndsInDirectorySeparator(path)) length--; // find the pivot index between end of string and root for (int pivot = length - 1; pivot >= rootLength; pivot--) { if (IsDirectorySeparator(path[pivot])) { directory = path.Substring(0, pivot); file = path.Substring(pivot + 1, length - pivot - 1); return; } } // no pivot, return just the trimmed directory directory = path.Substring(0, length); } return; }

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

Вот что он получил:

public class DirectoryFileSplitter { private readonly string validatedFullPath; private int length; private int rootLength; private bool pivotFound; public string Directory { get; set; } public string File { get; set; } public DirectoryFileSplitter(string validatedFullPath) { this.validatedFullPath = validatedFullPath; length = validatedFullPath.Length; rootLength = GetRootLength(validatedFullPath); } public void Split() { if (validatedFullPath != null) { IgnoreTrailingSlash(); FindPivotIndexBetweenEndOfStringAndRoot(); if(!pivotFound) TrimDirectory(); } } private void TrimDirectory() { Directory = validatedFullPath.Substring(0, length); } private void FindPivotIndexBetweenEndOfStringAndRoot() { for (int pivot = length - 1; pivot >= rootLength; pivot--) { if (IsDirectorySeparator(validatedFullPath[pivot])) { Directory = validatedFullPath.Substring(0, pivot); File = validatedFullPath.Substring(pivot + 1, length - pivot - 1); pivotFound = true; } } } private void IgnoreTrailingSlash() { if (length > rootLength && EndsInDirectorySeparator(validatedFullPath)) length--; } }

Вау, да? Не так-то просто решить, действительно ли рефакторинг помог сделать код более читабельным.

Ощущение такое, что на самом деле читать стало сложнее.

Раньше была сравнительно небольшая функция с полезными комментариями, которая теперь превратилась в класс с четырьмя функциями внутри без комментариев.

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

Нисколько.

Я не такой кровожадный.

Между этими двумя примерами кода есть несколько различий.

Давайте посмотрим на эти различия:

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

    Напротив, первоначальную версию можно легко просмотреть.

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

  3. Третье отличие, которое я вижу, — это стоимость поддержки.

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

    В общем, ответ на вопрос, какой вариант дороже поддерживать, кроется в требованиях.

    Эти требования определяют, важно ли в конкретной ситуации следовать SRP (принципу единой ответственности) или нет. Если эту функцию можно написать один раз и забыть навеки, то нет смысла тратить время на ее рефакторинг.

    Напротив, если ожидается рост функциональности, то у вас есть все основания провести рефакторинг функции в отдельный класс.

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

Вы сразу броситесь извлекать класс с четырьмя функциями внутри? Мой совет: не делайте этого без какой-либо причины, даже если ваша кодовая база имеет 100% тестовое покрытие.

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

Так что нет ничего плохого в методе «извлекать до упаду».

По моему мнению, вам просто нужно иметь в виду некоторые соображения.

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

Надо сначала подумать, проанализировать, сделать вывод и только потом действовать.

Теги: #рефакторинг #программирование #.

NET #дизайн и рефакторинг

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.