Функции являются основой программирования, без них ваш код превратится в сущий кошмар, им станет невозможно управлять.
С помощью функций вы можете структурировать вашу программу так, что ее будет легко расширять, анализировать и тестировать. Хороший и читаемый код понятен не только его автору, но и другим программистам.
Вне зависимости от языка программирования принцип работы программы всегда одинаковый — машина последовательно (построчно) считывает передаваемые ей инструкции. Чтобы принести ощутимую пользу, она должна выполнить не одну, а целый набор таких инструкций, называемый алгоритмом.
Допустим, есть алгоритм из десяти строк кода, описывающий действия по сортировке слов в алфавитном порядке. Вы использовали его в одном месте своей программы, и все хорошо работает. Если вам понадобится этот алгоритм в другом месте, тогда вы просто скопируете имеющийся код и вставите его туда, где он необходим. Но тут возникнут проблемы.
Такой алгоритм может использоваться в одной программе много раз, например, десять. Следуя логике выше, в вашем коде появится десять повторяющихся фрагментов. Во-первых, такой код будет трудно читать, это создаст путаницу. Во-вторых, если спустя время вы найдете в вашем алгоритме ошибку, ее придется исправлять везде. Это же справедливо, когда вы найдете способ улучшить ваш код сортировки. Одним словом — пытка.
Функция — это именованный фрагмент кода. Чтобы им воспользоваться, достаточно вызвать функцию, обратившись к ней по имени. Вместо десяти строк алгоритма вы пишете всего одно слово — имя вашей функции.
Когда понадобится изменить алгоритм, это делается в одном месте, там, где объявляется функция. В объявлении вы один раз описываете детали ее работы, а вызываете ее сколько угодно раз. Общий код становится выразительным, его легко читать и понимать. Но тут важно присвоить вашей функции подходящее имя, явно обозначающее ее назначение.
Функции можно вызывать не только в общем коде программы, но и в телах других функций. Когда в одной функции вызывается другая, образуется иерархия функций, некая цепочка вызовов, где становятся видны функции основные и вспомогательные. Общий код обретает древовидную структуру, что дает возможность легко им управлять.
К слову, в современном программировании почти всегда используется понятие ООП. Здесь функции называются методами, — это те же функции, только более продвинутые. Чтобы понимать, как работает метод, необходимо понимать, что такое функция, так как она — прародитель метода.
Функции состоят из входных параметров, тела и возвращаемого значения. В языках со строгой типизацией параметры должны иметь заданный тип данных, например, если в объявлении функции указано, что ее параметром является целое число, тогда при ее вызове в параметр помещается только целое число. В языках с динамической типизацией интерпретатор автоматически определяет помещенный в параметр тип, что, кстати, снижает производительность.
В функцию может быть передано много параметров, то есть данных, с которыми она будет производить манипуляции. При использовании функции достаточно знать, что она принимает и что возвращает. Это похоже на принцип черного ящика, где детали обработки скрыты и не так уж важны на этапе кодирования.
В своей работе функция руководствуется кодом, помещенным внутри нее, то есть всем тем, из чего состоит тело функции, а именно — уникальным алгоритмом, который может иметь разную степень сложности или эффективности. Когда вы готовы использовать какую-то функцию, вам достаточно знать, какие данные она вам вернет в ответ на принятые данные. А над внутренней работой самой функции программист уже не думает. Подобные абстракции критически важны в программировании, они дают возможность оперировать более ощутимыми понятиями.
То, что вернет функция, может выступить в качестве параметра для другой функции. И так далее. Иногда требуется, чтобы функция ничего не возвращала. Например, нужно, чтобы она просто распечатала текст на экране. Но такие функции используются редко и никакой сложности для понимания не представляют.
Возвращаясь к началу статьи, возникает вопрос. Если программу можно поместить в один файл, причем не используя никаких функций, то какой именно код нужно выносить в отдельную функцию?
Новички создают функции недостаточно эффективными. Они делают их либо неполноценными, либо слишком универсальными. Что это значит? Для будущих проектов им придется «допиливать» уже имеющиеся функции под новые задачи. Их старые функции были слишком зависимы от проекта, а это противоречит основной идее. Ведь именно повторное использование кода повышает продуктивность программиста.
Когда вы разрабатываете функцию, делайте это с прицелом на ее использование в дальнейшем. Но многие машут рукой — главное, чтобы работало сейчас. Через полгода им снова придется потратить время на доработку и погружение в детали работы собой же написанных функций.
Универсального правила написания функции не существует, однако учтите, она не должна уметь делать все, но то, что она делает, должно быть очень конкретным и полноценным. Исходите из того, что если действия повторяются несколько раз в коде, их нужно выразить в виде отдельной функции.
Часто бывает так, что кусок вашего кода уникален, он нигде больше не повторяется, но его также целесообразно поместить в отдельную функцию, чтобы совокупный код был более понятным. В общем, строгих правил здесь нет и быть не может. Правило в программировании лишь одно — нужно соблюдать золотую середину, балансировать между множеством теорий и убеждений. А это умение приходит с опытом.