В программировании самое главное - не создавать
write-only код, тогда всё остальное будет проще. Для этого нужно работать по двум направлениям:
уменьшать связность и дробить контекст. Насчёт последнего есть пара мыслей.
Главная цель
дробления - ограничить объём информации, необходимой для понимания действия. Этого можно достичь как вынесением функции, так и простым оформлением блока с помощью комментариев. Есть много школ, но фундаментально все они лежат на прямой между сплошной портянкой и десятислойными ооп-абстракциями. Среди них можно выделить
два самых частых подхода:
/// Вариант А
fn action() {
partial_action_1();
partial_action_2();
partial_action_3();
}
fn partial_action_1() { ... }
fn partial_action_2() { ... }
fn partial_action_3() { ... }
/// Вариант Б
fn action() {
// partial action 1
...
// partial action 2
...
// partial action 3
...
}
Первый вариант можно встретить гораздо чаще (спасибо годам пропаганды clean code и тд), но на мой взгляд он имеет неочевидные
нюансы.
Функция - это
абстракция, а любая абстракция - это
ограничения. Вынесение блока кода в функцию создаёт новые рамки, усложняя доступ к одним данных и упрощая к другим. Далеко не всегда эти ограничения оказываются в тему, ведь их создаём мы, живые люди. Те самые, которые иногда ошибаются. Но когда абстракция уже существует, неудобство ограничений сложнее заметить.
Лень тоже вносит свои коррективы. Если нужно сделать определённую работу, а в коде уже существует функция с подозрительно похожим по смыслу названием, возникает ненулевой шанс, что она будет вызвана без заглядывания вовнутрь. Но названия тоже придумывают люди.
В последнее время я чаще склоняюсь ко
второму варианту дробления, и на мой взгляд у этого есть
преимущества:
1 :: Проще переписывать части и менять группировку, ведь нет ограничений в виде разделения на функции.
2 :: Выше явность контекста. Не нужно бегать вверх-вниз по файлу, чтобы собрать в голове этапы действия. Всё написано последовательно.
3 :: Меньше риск выполнения кода в неправильном месте, ведь никто не сможет вызвать функцию, если её не существует.
Если один и тот же код нужен в нескольких местах - без функции не обойтись. Дублирование создаёт кратно больше проблем. Поэтому фреймворк примерно такой:
1 :: Если функция вызывается один раз -> заинлайнить
2 :: Много раз -> попробовать перестроить код так, чтобы вызвать нужно было только один раз, после заинлайнить