Почему некоторые функции чрезвычайно долго? (идеи необходимы для научного исследования!) [закрытый]

Во время проекта я заметил, что слишком много повторюсь с необязательными параметрами и настройками, поэтому я создал класс, который обрабатывает проверку типов и присваивает значение по умолчанию, что приводит к аккуратному и читабельному коду. Посмотрите пример и дайте мне знать, если это работает для вас.

var myCar           = new Car('VW', {gearbox:'automatic', options:['radio', 'airbags 2x']});
var myOtherCar      = new Car('Toyota');

function Car(brand, settings) {
    this.brand      = brand;

    // readable and adjustable code
    settings        = DefaultValue.object(settings, {});
    this.wheels     = DefaultValue.number(settings.wheels, 4);
    this.hasBreaks  = DefaultValue.bool(settings.hasBreaks, true);
    this.gearbox    = DefaultValue.string(settings.gearbox, 'manual');
    this.options    = DefaultValue.array(settings.options, []);

    // instead of doing this the hard way
    settings        = settings || {};
    this.wheels     = (!isNaN(settings.wheels)) ? settings.wheels : 4;
    this.hasBreaks  = (typeof settings.hasBreaks !== 'undefined') ? (settings.hasBreaks === true) : true;
    this.gearbox    = (typeof settings.gearbox === 'string') ? settings.gearbox : 'manual';
    this.options    = (typeof settings.options !== 'undefined' && Array.isArray(settings.options)) ? settings.options : [];
}

Используя этот класс:

(function(ns) {

    var DefaultValue = {

        object: function(input, defaultValue) {
            if (typeof defaultValue !== 'object') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? input : defaultValue;
        },

        bool: function(input, defaultValue) {
            if (typeof defaultValue !== 'boolean') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (input === true) : defaultValue;
        },

        number: function(input, defaultValue) {
            if (isNaN(defaultValue)) throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined' && !isNaN(input)) ? parseFloat(input) : defaultValue;
        },

        // wrap the input in an array if it is not undefined and not an array, for your convenience
        array: function(input, defaultValue) {
            if (typeof defaultValue === 'undefined') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (Array.isArray(input) ? input : [input]) : defaultValue;
        },

        string: function(input, defaultValue) {
            if (typeof defaultValue !== 'string') throw new Error('invalid defaultValue type');
            return (typeof input === 'string') ? input : defaultValue;
        },

    };

    ns.DefaultValue = DefaultValue;

}(this));
8
задан Community 23 May 2017 в 02:13
поделиться

15 ответов

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

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

18
ответ дан 3 November 2019 в 12:08
поделиться

Несколько идей, еще не упомянутых явно:

  • повторяющиеся задачи, например, функция считывает таблицу базы данных с 190 столбцами и должна выводить их в виде плоского файла (при условии, что столбцы должны быть обрабатываются индивидуально, поэтому простой цикл по всем столбцам не подходит). Конечно, вы можете создать 19 функций, каждая из которых будет выводить 10 столбцов, но это не сделает программу лучше.
  • сложные, подробные API, такие как Oracle OCI . Когда, казалось бы, простые действия требуют большого количества кода, трудно разбить его на небольшие функции, которые имеют какой-либо смысл.
0
ответ дан 3 November 2019 в 12:08
поделиться

Код синтаксического анализа XML часто содержит множество операций обработки escape-символов в одной функции настройки.

0
ответ дан 3 November 2019 в 12:08
поделиться

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

Я часто занимаюсь разработкой «вырезать и вставить» ...

Итак, для статьи, один аспект, на который следует обратить внимание, - это плохой план / цикл обслуживания и т. Д.

0
ответ дан 3 November 2019 в 12:08
поделиться

Из документации :

С другой стороны, точность time () и sleep () лучше, чем их эквиваленты в Unix: время выражается в виде чисел с плавающей запятой, time () возвращает наиболее точное время доступно (с использованием Unix gettimeofday где доступно), а sleep () будет принять время с ненулевой дробью (Unix select используется для реализации это, если доступно).

И более конкретно wrt sleep () :

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

Рассмотрим цикл:

for...
   func1

внутри цикла все эти нажатия и прыжки могут быть фактором.

Это было в значительной степени решено с помощью представления из Встроенные функции на C99 и неофициально до этого, но некоторый код, написанный ранее или создаваемый с учетом совместимости, мог быть длинным по этой причине.

Также Inline имеет его потоки, некоторые из них описаны в ссылке на встроенные функции .

Изменить:

В качестве примера того, как вызов функции может замедлить выполнение программы:

4         static void
5 do_printf()
6 {
7         printf("hi");
8 }
9         int
10 main()
11 {
12         int i=0;
13         for(i=0;i<1000;++i)
14                 do_printf();
15 }

Это приводит к (GCC 4.2 .4):

 .
 . 
 jmp    .L4
 .L5:
call    do_printf
addl    $1, -8(%ebp)
 .L4:
cmpl    $999, -8(%ebp)
jle .L5

 .
 .
do_printf:
pushl   %ebp
movl    %esp, %ebp
subl    $8, %esp
movl    $.LC0, (%esp)
call    printf
leave
ret

против:

         int
 main()
 {
         int i=0;
         for(i=0;i<1000;++i)
                 printf("hi");
 }

или против:

 4         static inline void __attribute__((always_inline)) //This is GCC specific!
 5 do_printf()
 6 {
 7         printf("hi");
 8 }

Оба производят (GCC 4.2.4):

jmp .L2
.L3:
movl    $.LC0, (%esp)
call    printf
addl    $1, -8(%ebp)
.L2:
cmpl    $999, -8(%ebp)
jle .L3

Что быстрее.

1
ответ дан 3 November 2019 в 12:08
поделиться

Чаще всего я вижу / пишу длинные операторы переключения или операторы полусопереключения if / else для типов, которые нельзя использовать в операторах переключения этого языка (уже упоминалось несколько раз). Сгенерированный код - интересный случай, но здесь я сосредоточен на коде, написанном человеком. Глядя на мой текущий проект, единственная действительно длинная функция, не включенная выше (296 LOC / 650 LOT), - это некоторый Cowboy Code, который я использую в качестве ранней оценки вывода генератора кода, который я планирую использовать в будущем. Я определенно проведу его рефакторинг, что удалит его из этого списка.

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

1
ответ дан 3 November 2019 в 12:08
поделиться

Очень длинные функции, с которыми я сталкиваюсь, написаны не на C, поэтому вы Придется решить, относится ли это к вашему исследованию или нет. Я имею в виду некоторые функции PowerBuilder длиной в несколько сотен строк по следующим причинам:

  • Они были написаны более 10 лет назад людьми, которые в то время не имели в виду стандарты кодирования. .
  • Среда разработки немного усложняет создание функций. Вряд ли хорошее оправдание, но это одна из тех мелочей, которые иногда мешают вам работать должным образом, и я думаю, кому-то просто лень.
  • Функции со временем развивались, добавляя и код, и сложность.
  • Функции содержат огромные циклы, каждая итерация может обрабатывать разные типы данных по-разному. Используя десятки (!) Локальных переменных, некоторых переменных-членов и некоторых глобальных переменных, они стали чрезвычайно сложными.
  • Поскольку они такие старые и уродливые, никто не осмеливается преобразовывать их в более мелкие части. Когда в них обрабатывается так много частных случаев, что их разбиение на части приводит к проблемам.

Это еще одно место, где очевидные плохие методы программирования встречаются с реальностью. В то время как любой первокурсник CS мог бы сказать, что эти звери плохие, никто не станет тратить деньги на то, чтобы они выглядели красивее (учитывая, что, по крайней мере, на данный момент, они все еще работают).

1
ответ дан 3 November 2019 в 12:08
поделиться

Один момент, который, как мне кажется, имеет значение, заключается в том, что разные языки и инструменты имеют разную лексическую область видимости, связанную с функциями.

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

Спорный вопрос: в JavaScript я обычно создаю функции только с целью повторного использования кода. Если фрагмент выполняется только в одном месте, я считаю обременительным перемещаться по файлу (файлам) после спагетти ссылок на функции. Я думаю, что закрытие облегчает и, следовательно, усиливает более длительные [родительские] функции. Поскольку JS - это интерпретируемый язык, а фактический код пересылается по сети, он ' Хорошо, если длина кода будет небольшой - создание соответствующих объявлений и ссылок не помогает (это можно рассматривать как преждевременную оптимизацию). Функция должна быть довольно длинной в JS, прежде чем я решу нарезать ее с явной целью «держать функции короткими».

Опять же в JS, иногда весь «класс» технически является функцией со многими вложенными подфункциями но есть инструменты, которые помогут с этим справиться.

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

1
ответ дан 3 November 2019 в 12:08
поделиться

Сгенерированный код может генерировать очень-очень длинные функции.

2
ответ дан 3 November 2019 в 12:08
поделиться

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

Недавние примеры ...

Анализ и проверка конфигурационного файла с простой структурой имя = значение в массив, конвертирующий каждое значение, как я его нахожу, это один массивный оператор переключения, один случай для каждой опции конфигурации. Почему? Я мог бы разбить на множество вызовов тривиальных функций 5/6 строк. Это добавило бы к моему классу около 20 частных членов. Ни один из них больше нигде не используется. Разделение его на более мелкие части просто не добавляло достаточно ценности, чтобы того стоить, так было с момента создания прототипа. Если мне нужен другой вариант, добавьте еще один случай.

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

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

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

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

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

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

2
ответ дан 3 November 2019 в 12:08
поделиться

Прочтите главу McConnell's Code Complete о подпрограммах, в ней есть рекомендации и указатели того, когда следует разбивать вещи на функции. Если у вас есть алгоритм, в котором эти правила не применяются, это может быть хорошей причиной для использования длинной функции.

3
ответ дан 3 November 2019 в 12:08
поделиться

Функции со временем могут стать длиннее, особенно если они модифицируются многими группами разработчиков.

Показательный пример: я недавно (~ год или 2 назад) реорганизовал некоторый устаревший код обработки изображений с 2001 года или около того, это содержало несколько функций на несколько тысяч строк. Не несколько файлов с несколькими тысячами строк - несколько функций с несколькими тысячами строк.

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

4
ответ дан 3 November 2019 в 12:08
поделиться

Все, что сгенерировано из других источников, т. Е. Конечный автомат из генератора синтаксического анализатора или аналогичного. Если он не предназначен для употребления в пищу, проблемы эстетики или ремонтопригодности не имеют значения.

11
ответ дан 3 November 2019 в 12:08
поделиться

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

1
ответ дан 3 November 2019 в 12:08
поделиться

Много значений в операторе переключения?

14
ответ дан 3 November 2019 в 12:08
поделиться
Другие вопросы по тегам:

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