Это плохая идея перечислить каждый аргумент функции / метода в новой строке и почему?

22

Я работаю с кем-то, кто при каждом вызове функции помещает аргументы в новую строку, например

aFunction(
    byte1,
    short1,
    int1, 
    int2,
    int3,
    int4,
    int5
) ;

Я нахожу это очень раздражающим, поскольку это означает, что код не очень компактен, поэтому мне приходится сканировать больше и больше, чтобы на самом деле понять смысл логики. Мне интересно узнать, действительно ли это плохая практика, и если да, то как я могу убедить их не делать этого?

Дэниэл Болл
источник
25
+1, я не знаю достаточно, чтобы ответить на ваш вопрос, но я тоже ненавижу это. Если у вас есть столько аргументов в функции, то ваша функция, вероятно, делает слишком много.
maple_shaft
28
Более конкретно, почему мы все еще должны видеть предпочтения друг друга по этому поводу? почему наши IDE не могут просто автоматически представлять их в любом стиле, который мы хотим?
Алекс Фейнман
5
Майк, мне нравится, когда код занимает минимум экрана. Но это компромисс. Я поставил {на отдельной строке, потому что это облегчает сопоставление с закрытием} и правильно понимаю область действия блока. Стоит компромисс с потерей линейки экранной недвижимости.
Брайан Шрот
2
@ Алекс: Ты совершенно прав. Я думаю, что правильно было бы иметь язык, на котором дерево разбора кода хранится на диске и отображается в соответствии с предпочтениями пользователя.
Нил Дж
1
@maple_shaft Я презираю подобные заявления. Не потому, что в этом нет никакой правды, а потому, что слишком много людей следуют таким советам, не оставляя места для нюансов.
Стейн

Ответы:

38

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

Очевидно, что лучший способ повысить читабельность - это ограничить количество аргументов.

Мартин Викман
источник
24
Слишком много людей сокращают аргументы, сбрасывая их в массив. Я бы предпочел увидеть безобразный беспорядок, чем более чистый код со скрытой сложностью.
Satanicpuppy
18
Массивы - не лучший способ. Там может быть структура, скрывающаяся в аргументах, или, возможно, функция делает слишком много и должна быть разделена.
Майкл К
4
Я обнаружил, что использование нескольких строк помогает сделать код читабельным, если параметры IF являются длинным выражением или несколько слишком много. В противном случае это просто раздражает.
PedroC88
3
Помещение их в объект передачи данных просто решает проблему. Если все аргументы являются обязательными, то все они должны быть обязательными аргументами конструктора DTO, что означает, что у вас все еще есть столько аргументов.
Скотт Уитлок
21

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

Например:

do_complex_op(
      0, //Starting state, always 0, ask Joe why
      X, //X-coord of thingy
      y, //Y-coord of thingy
      73, //in this case, we don't want to use Z but want constant 
      dlogMessageTitle, //message for dialogue title
      dlogMessageText, //message for dialogue contents, don't care about this.
      SomethingIP, //IP of something-or-other server, can be NULL, won't crash.
      someObject.childObject.getValue(key1).HVAL, //very long path to HVAL
      someObject.childObject.getValue(key1).LVAL, //very long path to LVAL
      this.parentWindow.owner.mainTextBox.text.value.trim, //get the trimmed text, untrimmed text causes weird output
      pvrMainSettingForLongBlahs.getObjectByPath(somePath),
      pvrMainSettingForLongBlahs.K_TCA_UPPER_LIMIT,
      pvrMainSettingForLongBlahs.K_ENDPOINT_COMPLIANCE_LEVEL,
 );

С языками, которые допускают именованные параметры, это более распространено, если вы используете имена параметров (пример на PL / SQL):

PKG_SOME_TEST_CODE.FN_DO_SOMETHING( in_text => 'test text',
                                    in_id => v_id,
                                    in_ref_id => v_ref_id,
                                    out_array_for_storage => v_bArray); 

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

setColour (
    r,
    g,
    b
 );

Мне гораздо легче читать как

 setColour(r,g,b);

Для @ammoQ:

rc=a(b,c(d,e(f)))

rc=a(
     b,
     c(
       d,
       e(
         f
        )
      )
    )
FrustratedWithFormsDesigner
источник
11
Первый пример - неправильный ответ на реальную проблему. Почему бы не использовать явные переменные anmes в первую очередь?
Deadalnix
@deadalnix: Хорошая мысль, немного почистил.
FrustratedWithFormsDesigner
1
Правда. Однако это не всегда проблема с именами переменных. Это больше связано с длинными именами переменных, аргументов со значениями по умолчанию, и т.д.
inspectorG4dget
4
Я бы сказал, что лучшим решением проблемы является рефакторинг do_complex_op (), поэтому он принимает структуру в качестве параметра. Тогда вы можете сделать do_complex_op(new paramStruct { StartingState = 0, XCoord = xcoord }), тогда это становится самодокументированным и намного легче читать
KallDrexx
1
@KallDrexx: Я согласен, но иногда изменение кода не вариант, например, когда это функция в чужой библиотеке. Конечно, я мог бы сделать обертку, но мне все равно придется вызывать их исходную функцию в какой-то момент.
FrustratedWithFormsDesigner
10

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

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

user281377
источник
Хм ... с таким подходом, как мы могли бы представить новую лучшую практику (или, грамматически правильно: лучшую практику )?
Треб
2
Треб: Конечно, просто покажи, что лучшая практика на самом деле лучше , а не просто другая .
user281377 30.06.11
4
Но «труднее читать» само по себе субъективно и является вопросом мнения. Для меня один аргумент в строке проще анализировать визуально, чем два, три или четыре аргумента в строке. И я всегда разбиваю вызов на несколько строк, если он выходит за пределы отметки в 100 символов в редакторе.
Тоби
2
Мех. «Труднее читать» можно измерить объективно. Такого не бывает. Спорить об этом веселее.
JasonTrue
1
это может быть измерено объективно, но не независимо от человека, делающего чтение.
JK.
9

Ну, вот немного приманки. Меня никогда не обвиняли в популярных вещах. Понятно, что если вещи помещаются в одну строку, то хорошо, поместите их в одну строку.

Но меня больше всего беспокоит не то, является ли код «уродливым» или «красивым». Моя главная забота - насколько легко понять и вносить изменения без ошибок.

Если аргументы длинные и их много, почему бы не поставить их в отдельные строки? На мой взгляд, это облегчает понимание того, что они из себя представляют, и их легче менять в случае необходимости. Это также дает мне возможность прикрепить комментарий к каждому аргументу, если я хочу.

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

Итак (мальчик, я за это заплачу) я напишу это так:

nameOfFunction(firstArgument
    , secondArgument // optional comment
       ...
    , lastArgument   // optional comment
    );

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

(И для тех, кто говорит, что я должен передать структуру вместо этого, все, что делает, это смещает проблему, потому что вам нужно множество строк кода для заполнения структуры, не говоря уже о дополнительном коде, чтобы объявить и выделить его.)

Майк Данлавей
источник
1
Я лично считаю, что это отличный ответ, потому что вы очень хорошо объяснили свои рассуждения. Хорошая работа, Майк.
Джордан,
8

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

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

Джаррод Крапива
источник
5

Это облегчает:

  • Изменить порядок аргументов.
  • Закомментируйте или отключите аргументы.
  • Смотрите точно, какой аргумент изменился, когда вы просматриваете diff в вашей системе контроля версий
  • Избегайте повторного отступа и переноса слов при добавлении, удалении аргумента или изменении имени функции. (Даже если ваш редактор автоматически делает отступ, вы по-прежнему создаете множество бесполезных изменений, которые затрудняют отслеживание изменений в вашей системе контроля версий.)
Грэм Борланд
источник
4

Я бы сказал, что вызовы функций должны быть все в одной строке, если они значительно не превышают стандартную ширину кода (часто 80 символов, часто причина аргументов :-).

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

Люк Грэм
источник
Эта штука из 80 персонажей должна исчезнуть, технически обоснованных причин больше нет. Сейчас мы живем в эпоху мониторов 19xx X 16xx и настраиваемых шрифтов И размеров шрифтов.
Anon
4
@anon: веские причины для этого? Как вы думаете, почему текст печатается в колонках, а книги уже, чем могли бы быть? Потому что человеческий глаз теряет след при чтении через очень длинные строки.
Zan Lynx
4
@anon: Также мне нравится использовать мой широкоформатный экран, чтобы два или три файла открывались в горизонтальном разделении, которое возвращает 80-100 символов в строке.
Zan Lynx
4
@anon: Технически нет, практически: черт возьми, ДА. Zan Lynx совершенно прав, плюс есть и другие причины: объединение, различие, использование утилит командной строки ... О, удачи, сосредоточившись на шрифте 8p, когда вы станете старше: o)
MaR
3

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

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

Это противоречит стандартам кодирования компании?

Если нет, то начните обсуждение стандартов и того, что люди хотели бы видеть измененными. Убедитесь, что вы назвали это одной из вещей, которую вы хотели бы изменить.

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

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

ChrisF
источник
2

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

Это также легче читать, чем:

int f(int, int, int,
      char, double, int
      X const&, Y)
{}

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

Важной частью является то, что ваш код может быть напечатан или отображен на стандартных дисплеях 80col, и все еще будет разборчивым.

Эдвард Стрендж
источник
2

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

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

Что для моего прочтения ... это именно то, что вы просите в этом вопросе: нелепый, неискренний аргумент, оправдывающий ваши личные предпочтения.

Дэн Олсон
источник
0

Честно говоря, это зависит от человека. Я бы сказал, что для сложных функций, как показано в FrustratedWithForms, сначала пример, затем да; иначе большое НЕТ. Опять же, именно поэтому я предпочитаю применять функциональность IDE кода произвольно.

Темная Звезда1
источник
0

«Мне интересно знать, действительно ли это плохая практика ...»

Да, это плохая практика, за исключением случаев, когда список переменных ненормально длинный. Но в этом случае проблема, скорее всего, связана с дизайном функции. Почему бы не передать объект, который инкапсулирует многие параметры?

"... и если да, то как я могу убедить их не делать этого?"

Свяжите их и продолжайте щекотать, пока они не согласятся остановить это дерьмо.

ybakos
источник
«Почему бы не передать объект, который инкапсулирует многие параметры?» Хорошо, теперь вы перенесли проблему в этот новый объект. Ему все еще нужно такое же количество параметров (например, через конструктор), поэтому у вас все еще остается та же проблема.
Стейн
-2

Почему вы тратите циклы на такие тривиальные проблемы? Просто запустите вашу верную IDE, откройте файл и переформатируйте. Вуаля! Это будет в любой форме, которую вы хотите.

Теперь давайте перейдем к действительно важному вопросу - vi или emacs, LOL.

SnoopDougieDoug
источник
А потом, когда вы пришли, чтобы проверить это в source-control?
фунтовые
-2

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

foo(arg1, arg2, arg3, arg4, arg5)

противы

foo(
    arg1=arg1,
    arg2=arg2,
    arg3=arg3,
    arg4=arg4,
    arg5=arg5,
    arg6=arg6,
    arg7=arg7
)
user271413
источник
3
это , кажется, не предлагает ничего существенного по точкам сделанных и разъяснено в предыдущих 14 ответов
комар