Это - плохая практика, чтобы иметь длинный метод инициализации?

Многие люди спорили о функциональном размере. Они говорят, что функции в целом должны быть довольно короткими. Мнения варьируются от чего-то как 15 строк к "об одном экране", который сегодня является, вероятно, приблизительно 40-80 строками.
Кроме того, функции должны всегда выполнять одну задачу только.

Однако существует один вид функции, которая часто перестала работать в обоих критериях в моем коде: функции Инициализации.

Например, в аудиоприложении, аудио аппаратные средства/API должны быть настроены, аудиоданные должны быть преобразованы в подходящий формат, и объектное состояние имеет к правильно инициализированному. Это ясно три различных задачи, и в зависимости от API это может легко охватить больше чем 50 строк.

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

8
задан Community 23 May 2017 в 12:03
поделиться

9 ответов

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

void _init_hardware() { }
void _convert_format() { }
void _setup_state() { }

void initialize_audio() {
    _init_hardware();
    _convert_format();
    _setup_state();
}

Написание кратких функций - это столько же об устранении ошибок и изменений, сколько о сохранении читабельности. Если вы знаете, что ошибка в _convert_format () , вы можете отследить ~ 40 строк, ответственных за ошибку, намного быстрее. То же самое применимо, если вы фиксируете изменения, которые касаются только одной функции.

И наконец, я довольно часто использую assert () , поэтому могу «часто терпеть неудачу и терпеть неудачу рано», а начало функции - лучшее место для пары проверок работоспособности утверждает. Укорочение функции позволяет более тщательно протестировать функцию с учетом ее более узкого набора обязанностей. Очень сложно провести модульное тестирование 400-строчной функции, которая выполняет 10 разных действий.

12
ответ дан 5 December 2019 в 06:09
поделиться

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

2
ответ дан 5 December 2019 в 06:09
поделиться

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

Альтернативой этому является использование инфраструктуры внедрения зависимостей (например, Spring, Castle Windsor, Guice и т. Д.). У этого есть определенные плюсы и минусы ... хотя работа над одним большим методом может быть довольно болезненной, вы, по крайней мере, имеете хорошее представление о том, где все инициализировано, и вам не нужно беспокоиться о том, какая «магия» может происходить . Опять же, инициализацию нельзя изменить после развертывания (как, например, с файлом XML для Spring).

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

1
ответ дан 5 December 2019 в 06:09
поделиться

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

В зависимости от структуры кода, возможно, стоит подумать о том, чтобы абстрагироваться от ваших больших функций инициализации. Я все еще согласен с точкой зрения Мигара, хотя разбиение функций на _init_X (), _init_Y () и т. Д. - хороший способ. Даже если вы не собираетесь повторно использовать комментарии в этом коде, в своем следующем проекте, когда вы спросите себя: «Как я инициализировал этот X-компонент?», Будет намного проще вернуться и выбрать его. функции меньшего размера _init_X () , чем если бы вы выбирали ее из более крупной функции, особенно если X-инициализация разбросана по ней.

1
ответ дан 5 December 2019 в 06:09
поделиться

Если разбиение на более мелкие части делает код лучше структурированным и/или более читаемым - делайте это независимо от того, что делает функция. Дело не в количестве строк, а в качестве кода.

5
ответ дан 5 December 2019 в 06:09
поделиться

Во-первых, вместо функции инициализации следует использовать фабрику. То есть вместо initialize_audio () у вас есть new AudioObjectFactory (вы можете придумать здесь лучшее имя). При этом сохраняется разделение проблем.

Однако будьте осторожны и не абстрагируйтесь слишком рано. Очевидно, у вас уже есть две проблемы: 1) инициализация звука и 2) использование этого звука.Например, до тех пор, пока вы не абстрагируете аудиоустройство, которое нужно инициализировать, или до тех пор, пока данное устройство не может быть настроено во время инициализации, ваш заводской метод ( audioObjectFactory.Create () или что-то еще) действительно должен быть сохранен в только один большой метод. Ранняя абстракция служит только для запутывания дизайна.

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

1
ответ дан 5 December 2019 в 06:09
поделиться

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

1
ответ дан 5 December 2019 в 06:09
поделиться

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

SetupAudioHardware();
ConvertAudioData();
SetupState();

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

3
ответ дан 5 December 2019 в 06:09
поделиться

Длина функции - это, как вы отметили, очень субъективный вопрос. Тем не менее, стандартной лучшей практикой является изоляция кода, который часто повторяется и/или может функционировать как отдельная сущность. Например, если ваша функция инициализации загружает библиотечные файлы или объекты, которые будут использоваться определенной библиотекой, этот блок кода должен быть модульным.

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

Надеюсь, это поможет,
Карлос Нуньес

1
ответ дан 5 December 2019 в 06:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: