Прочитал статью «Искусство написания простых и коротких функций» https://habrahabr.ru/post/310590/
Эта тема постоянно мусолится, и постоянно у меня в голове возникает один и тот же вопрос.
Очевидно, что нужно разбивать сложные функции на части. Но у меня часто возникает проблема из-за того, что внутренние функции почти наверняка не будут где-либо повторно использованы. Довольно часто получается специфическая функция со специфическим набором параметров и специфическим результатом. И как её тогда называть? Использовать имя родительской функции в качестве префикса?
Более того, если мы выносим код в отдельную функцию, то появляется вопрос проверки входящих параметров, который наверняка выполнялся в родительской функции. В родительской функции мы точно знали, что параметры верные, а тут получается мы или ничего не проверяем, что плохо для самостоятельности новоиспеченной функции, или в очередной раз проверяем то, что уже проверяли раньше, что негативно сказывается на быстродействии. В основном я программирую на php и там у меня с этим совсем беда, так как в языке нет локальных функций. Их наличие могло исправить ситуацию за счет того, что внутренние функции имеют локальную область видимости, а значит не должны иметь уникальные понятные имена, плюс не могут быть вызваны из вне, а значит нет смысла по несколько раз проверять параметры.
Метод split и метод join Python
Что я делаю не так? Бывают ли случаи, когда на самом деле лучше не разбивать? Или наличие подобных случаев однозначно говорит о плохой архитектуре?
- Вопрос задан более трёх лет назад
- 1558 просмотров
Комментировать
Решения вопроса 0
Ответы на вопрос 4
Архитектура измеряется не длиной функций, а их назначением. Функция, выполняющая ровно одну задачу, обычно и не будет длинной.
Подойдите к вопросу со стороны тестирования. Вас устроит тест этой функции как единого черного ящика? Или у нее есть конкретные части, которые выполняют полноценные подзадачи, под которые хорошо бы иметь отдельный тест на случай, если в функции будут изменения? Если нет и у вас просто однородная простыня — разбивать незачем. Если есть — почему нет?
Ну, а если вас смущает накопление никому больше не нужных функций — вспомните, что в РНР есть ООП и все это может быть собрано в класс, а нигде больше не используемые функции — сделаны приватными.
Ответ написан более трёх лет назад
Комментировать
Нравится 5 Комментировать
Откройте для себя namespace.
Никогда не делайте префиксы функций, а то будет вот такое говно `syn_whitelabel_form_whitelabel_partner_node_form_alter()` (это реальный код).
Освойте ООП в конце концов. Собирайте свои функции внутри одного функционального домена в один класс.
Если функция внутренняя объявляйте ее приватной и вызывайте через `self::`.
Прекрати писать код в ОДНОМ файле Python | ТОП 5 Ошибок и создание правильной архитектуры
По поводу проверки параметров — PHP позволяет объявлять типы параметров, например array или классы. Во многих случаев этих вещей достаточно.
Разбивать большие функции на мелкие нужно тогда, когда действие повторяется хотя бы один раз или может быть использовано другой частью проекта.
Типичный пример — валидаторы, они могут быть использованы повсеместно.
Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
У тебя неправильный подход. Ты сначала делаешь какую-то большую функцию, а потом хочешь её разбивать. Так вот эта большая функция твоя — это полное фуфло. Вот в чём дело. Потому что ты её уже неправильно сделал.
У тебя не должно быть так, что сначала появляется функция, а потом ты думаешь, что ею можно сделать. Должно быть наоборот. Сначала должна появляться задача, которую нужно сделать, а вот уже под эту задачу должна появляться функция, которая её выполняет. И таких функций может быть много, и все они могут быть разными.
Например, ты хочешь вывести строку «hello» в C.
#include int main(void)
Вот это уже готовые функции, их уже когда-то написали. И они решают твою задачу. Причём они для этого изначально вообще не предназначались. Многие из них не используются для таких задач, но они могут быть использованы.
Они просто что-то делают с тем, что в них подают. А что в них подают и предназначались ли они для этого изначально — это неважно.
А вот та же задача, но перечисленные функции использовать запрещено. Что делать?
Можно написать функцию вместо них.
#include void f1(void) < putchar(‘h’); putchar(‘e’); putchar(‘l’); putchar(‘l’); putchar(‘o’); putchar(‘n’); >void f2(char c) < putchar(c); putchar(‘e’); putchar(‘l’); putchar(‘l’); putchar(‘o’); putchar(‘n’); >void f3(char c) < int i; putchar(‘h’); putchar(‘e’); for (i = 0; i < 2; i++) putchar(c); putchar(‘o’); putchar(‘n’); >int main(void)
Вот это уже ближе к делу. Задача поставлена и решена с помощью нескольких разных функций. То, что эти функции нигде больше не могут использоваться, — это неважно, это другой вопрос. Главное, что задача решена правильно и точно, как и ставилась.
А вот теперь давай подумаем, как так получилось, что функция printf(), написанная десятки лет назад, решила нашу задачу и тысячи других задач, а свои функции f1(), f2() и f3() могут решить только нашу задачу, но кроме неё не могут решить и десятка других задач?
В чём разница между printf() и f1()? В том, что в printf() строка «hello» передаётся через параметр (то есть выводимый текст параметризован), тогда как в f1() строки вообще нет, она образуется из символов, которые даже не параметризованы. А что у нас с f2(), ведь там есть параметр? А в f2() выводимый текст параметризован недостаточно, так же как и в f3().
В чём же секрет параметризации? В том, что данные должны быть параметризованы максимально и иметь как можно меньше всяких зависимостей. Для этого их стремятся сделать настолько простыми, насколько это возможно, потому что никогда не угадаешь, какие конструкции будут действовать через десятки лет, а какие выкинут на помойку и забудут, как страшный сон.
Вот таким образом и пишется функция: ты должен ставить задачу и решать её вызовом какой-то функции. А если функции не существует, то ты всё равно должен её вызывать, но потом дописывать её содержимое. И вот дописывая функцию, внутри неё ты делаешь то же самое — ставишь задачу и решаешь её вызовом какой-то функции.
В примере выше ты решаешь задачу вывода строки «hello» функцией f1(), а внутри функции f1() ты решаешь задачу вывода символа на экран функцией putchar(). (Благо putchar() готова уже и хорошо параметризована. Но если не готова, то ты так же её вызываешь, а потом дописываешь её внутренность, в которой всё повторяется — задача и вызов.)
Источник: qna.habr.com
Процедурное программирование
Существование процедурных языков было актуальным на ранних этапах развития программирования. Каждый оператор такого языка это указание компьютеру выполнить какое-либо действие (например принять данные от пользователя, произвести с ними определенные действия и вывести результат этих действий на экран).
Программы, написанные на процедурных языках, представляют собой последовательности инструкций.
Для небольших программ не требуется дополнительной внутренней организации (часто называемой термином парадигма). Программист создает перечень инструкций, а компьютер выполняет действия, соответствующие этим инструкциям.
Деление на функции
Когда размер программы велик, список команд становится слишком громоздким. Очень небольшое число программистов способно удерживать в голове более 500 строк программного кода, если этот код не разделен на более мелкие логические части. Функция является средством, облегчающим восприятие при чтении текста программы (термин функция употребляется в языках С и C++; в других языках программирования это же понятие называют подпрограммой или процедурой). Программа, построенная на основе процедурного метода, разделена на функции, каждая из которых в идеальном случае выполняет некоторую законченную последовательность действий и имеет явно выраженные связи с другими функциями программы.
Можно развить идею разбиения программы на функции, объединив несколько функций в модуль (зачастую модуль представляет собой отдельный файл). При этом сохраняется процедурный принцип: программа делится на несколько компонентов, каждый из которых представляет собой набор инструкций.
Деление программы на функции и модули является основой структурного программирования. Структурное программирование представляет собой нечто не вполне определенное, однако в течение нескольких десятков лет, пока не была разработана концепция объектно-ориентированного программирования, оно оставалось важным способом организации программ.
Недостатки структурного программирования
В непрекращающемся процессе роста и усложнения программ стали постепенно выявляться недостатки структурного подхода к программированию. Возможно, вам приходилось слышать «страшные истории» о том, как происходит работа над программным проектом, или даже самим участвовать в создании такого проекта: задача оказывается сложнее, чем казалось, сроки сдачи проекта переносятся. Все новые и новые программисты привлекаются для работы, что резко увеличивает расходы. Окончание работы вновь переносится, и в результате проект терпит крах.
Проанализировав причины столь печальной судьбы многих проектов, можно прийти к выводу о недостаточной мощи структурного программирования: как бы эффективно ни применялся структурный подход, он не позволяет в достаточной степени упростить большие сложные программы
Существуют два недостатка процедурно-ориентированных языков. Первый недостаток в неограниченности доступа функций к глобальным данным. Вторая состоит в том, что разделение данных и функций, являющееся основой структурного подхода, плохо отображает картину мира.
Можно рассмотреть недостатки на примере программы складского учета. В такой программе записи в книге являются глобальными данными.
Источник: studfile.net
Разделить программу Gtkmm на функции (часть 1)
Я знаю, что это будет очень простой вопрос, но на самом деле это не что-то очевидное из-за использования указателей, областей и специальных типов переменных GTK и других. Я действительно не смог найти ответ. Мне нужно разделить связанную с GUI часть программы Gtkmm на функции, но что-то кажется неправильным. Чтобы было ясно, вот пример.
В CODE1.cpp есть код WORKING, и его нужно разделить на нечто похожее на CODE2.cpp (еще не работающее). Первый — это окно, содержащее только метку, второе — одно и то же, но метка создается внутри функции. Где ошибка? Чего не хватает? Любой совет или помощь будут оценены. Указанные коды: CODE1.cpp:
#include
int main (int argc, char *argv[])
Glib::RefPtr app = Gtk::Application::create(argc, argv, «Ejemplo»);
Gtk::Window ventana;
Gtk::Label labela;
labela.set_text(«perrito»);
ventana.add (labela);
ventana.show_all ();
return app->run(ventana);
>
#include
Gtk::Label etiqueta (string x)
Gtk::Label labela;
labela.set_text(x);
return ( labela );
>
int main (int argc, char *argv[])
Glib::RefPtr app = Gtk::Application::create(argc, argv, «Ejemplo»);
Gtk::Window ventana;
etiqueta(«perrito»);
ventana.add (labela);
ventana.show_all ();
return app->run(ventana);
>
спросил(а) 2020-03-27T19:51:25+03:00 3 года, 3 месяца назад
Источник: progi.pro