По моему опыту, почти всегда более продуктивно функционально декомпозировать (разбивать вещи на более мелкие функции, которые делают одно и делают это хорошо) до попадания в ветви и эквивалентные логические выражения.
не теряя много времени, пытаясь сначала понять все второстепенные аспекты функциональности?
Помимо прочего, акт функциональной декомпозиции приведет к вашему пониманию того, что делает код, что приведет к дальнейшим возможностям декомпозиции. Вы хотите получить функции, которые принимают только несколько аргументов и возвращают no, одно или несколько значений.
И, разложив, вы получите лучшее понимание того, какие части являются алгоритмически важными (это должно быть сделано таким образом, чтобы быть корректными), а какие части являются просто деталями реализации (которые должны быть выполнены, но могут быть выполнены различными способами). разные способы без изменения выхода).
Часто вы обнаружите, что многие из этих глубоко вложенных if
либо не нужны, либо повторяются с избыточностью, либо достаточно похожи, их можно сократить до одной или нескольких функций, если исключить незначительные различия в других отношениях. повторный код.
Другими словами, вы хотите получить представление не о мелочах кода, а об абстрактной вещи, с которой имеет дело код. Многие проблемы сводятся к некоторой структуре данных (список, очередь, дерево, набор) и некоторым операциям с этой структурой. В той степени, в которой вы можете разделить структуры данных и алгоритмы, вы можете получить уровень абстракции, который упрощает вещи. Или вы можете обнаружить, что все, что вам нужно сделать, лучше подходит для других структур или алгоритмов, и тогда вы можете сойти с ума.
Я помню, как много лет назад коллега, который всегда писал курсоры базы данных, делал что угодно, потому что это все, что он знал, как это делать. Установка и разрушение курсора требует некоторого шаблона и цикла с некоторой проверкой ошибок, поэтому его код всегда выглядел поверхностно сложным. Он сделал бы это в сохраненном процессе, что, конечно, добавило больше шаблона.
Теперь, как это и произошло, это было в Sybase T-SQL, в котором есть глобальный для ошибок и глобальный для состояния курсора, которые он проверял дважды, один раз, когда он получил первую строку курсора, затем один раз в цикле, который повторяется по всем другим строкам. И он постоянно путал переменную ошибки (@@error
) с переменной состояния курсора (@@sqlstatus
, которая равна нулю при успехе (получил строку курсора), 1 при ошибке и 2, если в курсоре больше нет строк) , Его код работал по номинальному пути, потому что оба были равны нулю, если он получил строку, и когда он попытался получить строку после последней, он получил ошибку. Поэтому, если вы внимательно посмотрите на его код, вы будете стонать (еще раз!) И исправите это для него.
Но тогда вы посмотрите поближе и увидите, что он делал что-то вроде курсора в наборе всех строк where x = 1
и для каждого параметра строки y = y * 2
, и вы в конечном итоге сказали бы ему: "просто напишите заявление об обновлении!
Ваше исправление его проверки глобальных переменных, в то время как правильное , не решило реальную проблему, заключающуюся в том, что он использовал курсор и сохраненный процесс без уважительной причины, когда он просто мог отправить оператор обновления из кода клиента.
Выяснить это было сложнее, потому что вместо того, чтобы просто смотреть на локальное использование глобалов, вам пришлось искать два места: где был объявлен курсор (declare cursor_foo cursor for select * from table where x = 1 for update;
) и двадцать строк вниз, где происходило обновление (update table set y = y * 2 where current of cursor_foo
). (И все это будет многострочным, очень стандартным способом.)
Выяснить это было также сложнее, потому что вы просто предполагали, что никто не пройдет через все это только для обновления; конечно весь этот шаблон должен был быть, потому что в обновлении происходило что-то особенное, верно? Или потому что предикат where
был динамическим или что-то в этом роде? Итак, вы посмотрите на это, и, будучи скромным программистом, который уважает своих коллег, ваш первый инстинкт был бы: «Что здесь пропущено I , должна быть причина курсор был использован? "
(Несмотря на то, что и я, и его начальник объясняли разницу между @@ error и @@ sqlstatus, он просто так и не понял, тем более, что он почти всегда мог просто сделать update
; он думал с точки зрения процедурного код, и никогда не "получил" базы данных, несмотря на очевидный опыт "программиста базы данных".)
Урок заключается в том, чтобы не зацикливаться на мелочах, пока вы не подтвердите, что в первую очередь нужны мелочи (детали реализации). Разложив свой код в первую очередь, у вас будет больше шансов понять абстракции, с которыми вы имеете дело, и действительно улучшить код.