Мой стиль написания кода для вложенных вызовов функций состоит в следующем:
var result_h1 = H1(b1);
var result_h2 = H2(b2);
var result_g1 = G1(result_h1, result_h2);
var result_g2 = G2(c1);
var a = F(result_g1, result_g2);
Я недавно менял в отдел, где следующий стиль кодирования-это очень в использовании:
var a = F(G1(H1(b1), H2(b2)), G2(c1));
Результат моего способа кодирования является то, что в случае функция сбой в Visual Studio можно открыть соответствующий дамп и указать строку, где возникает проблема (я'м, особенно беспокоят нарушения прав доступа).
Я боюсь, что в случае аварии из-за той же проблемы запрограммированы в первом случае, я выиграл'т быть в состоянии знать, какие функции имеет причиной аварии.
С другой стороны, чем больше обработки вы поставите на линию, тем больше у вас логика получается на одной странице, что повышает читабельность.
Мой страх правильно или я что-то пропустил, и в целом, что является предпочтительным в коммерческой среде? Читабельности и ремонтопригодности?
Я не'т знаю, если это'с актуальным, но мы работаем в C++ (без STL) / в C#.
Если вы были вынуждены развернуть один лайнер, как
a = F(G1(H1(b1), H2(b2)), G2(c1));
Я бы'т виню тебя. Что's не только трудно читать, она's жесткий, чтобы отладить.
Почему?
Если вы расширить его с промежуточными результатами, которые вы получаете
var result_h1 = H1(b1);
var result_h2 = H2(b2);
var result_g1 = G1(result_h1, result_h2);
var result_g2 = G2(c1);
var a = F(result_g1, result_g2);
и это's по-прежнему трудно читать. Почему? Он решает сразу две проблемы и вводит четвертый:
Если вы расширить его с именами, добавить новый, хороший, смысловой нагрузки, даже лучше! Хорошее имя помогает мне понять.
var temperature = H1(b1);
var humidity = H2(b2);
var precipitation = G1(temperature, humidity);
var dewPoint = G2(c1);
var forecast = F(precipitation, dewPoint);
Теперь, по крайней мере, это рассказывает историю. Он исправляет проблемы и явно лучше, чем все остальное предложенное здесь, но это требует, чтобы вы придумали названия.
Если вы делаете это с бессмысленными названиями вроде result_this " и " result_that
потому что вы просто можете'т думаю, что хороших имен, то я'd в самом деле, чтобы вы избавили нас ничего не значащим названием беспорядок и развернуть его через какой-то пробел:
int a =
F(
G1(
H1(b1),
H2(b2)
),
G2(c1)
)
;
Это's просто, как читается, если не больше, чем с бессмысленными именами результатом (не то, что эти имена функций, что большой).
Когда вы можете'т думаю, что хороших имен, что's, Как хорошо, как он получает.
По какой-то причине отладчики люблю новые линии так что вы должны найти, что отладка это'т трудно:
Если это's не достаточно, представьте себе, `Г2 () называлась в более чем одном месте, а потом случилось это:
в
Exception in thread "main" java.lang.NullPointerException
at composition.Example.G2(Example.java:34)
at composition.Example.main(Example.java:18)
Я думаю, что это'С приятно, что после каждого Г2()
вызов будет на нем'ы собственную линию, этот стиль берет вас прямо на оскорбительный вызов в Main.
Поэтому, пожалуйста, Дон'т использовать проблемы 1 и 2 в качестве предлога, чтобы сунуть нам с проблемой 4. Используйте хорошие имена, когда вы можете думать о них. Избегайте бессмысленных названий, когда вы можете'т.
Легкость гонок на орбите'ы comment правильно указывает, что эти функции являются искусственными и мертвыми бедные сами имена. Так вот'ы пример применения этого стиля к какой-то код из дикой природы:
var user = db.t_ST_User.Where(_user => string.Compare(domain,
_user.domainName.Trim(), StringComparison.OrdinalIgnoreCase) == 0)
.Where(_user => string.Compare(samAccountName, _user.samAccountName.Trim(),
StringComparison.OrdinalIgnoreCase) == 0).Where(_user => _user.deleted == false)
.FirstOrDefault();
Я ненавижу, глядя на этот поток шума, даже когда перенос слова Это'т нужна. Здесь's, как она выглядит под этот стиль:
var user = db
.t_ST_User
.Where(
_user => string.Compare(
domain,
_user.domainName.Trim(),
StringComparison.OrdinalIgnoreCase
) == 0
)
.Where(
_user => string.Compare(
samAccountName,
_user.samAccountName.Trim(),
StringComparison.OrdinalIgnoreCase
) == 0
)
.Where(_user => _user.deleted == false)
.FirstOrDefault()
;
Как видите, я'вэ нашел этот стиль хорошо работает с функциональным кодом, что's перенос в объектно-ориентированном пространстве. Если вы можете придумать хорошие фамилии для этого в промежуточном стиле, то больше мощности для вас. До тех пор я'м через это. Но в любом случае, пожалуйста, найти какой-то способ, чтобы избежать бессмысленных имен результат. Они делают моим глазам больно.
с другой стороны, чем больше обработки вы поставите на линию, тем больше у вас логика получается на одной странице, что повышает читабельность.
Я совершенно не согласен с этим. Просто глядя на ваши два примера кода называет это как-то неправильно:
var a = F(G1(H1(b1), H2(b2)), G2(c1));
слышно читать. на "читаемость" не имею в виду плотность информации; это означает "легко читать, понимать и поддерживать и".
Иногда, код простой и его имеет смысл использовать одну строку. Другие времена, это просто делает это тяжелее, чтобы читать, без какой-либо очевидной выгоды сверх зубрежки больше на одну линию.
Однако, я'd также вызвать вас на своем, утверждая, что "легко диагностировать сбои", которая означает, что код легко поддерживать. Код, который не'аварии t гораздо легче поддерживать. на "легкий для поддержания" это достигается в первую очередь через код было легко читать и понимать, резервного копирования с хорошим набором автоматических тестов.
Так что если вы поворачиваете одно выражение в многострочном один со многими переменными только потому, что код часто падает и вам нужно больше отладочной информации, то прекратите делать это и сделать код более надежным и вместо. Вы должны предпочитают писать код, который не'т необходимость отладки кода, что'ы легко для отладки.
Ваш первый пример, в одном-назначение-форма, не читается, потому что выбранные имена не будут иметь никакого смысла. Это может быть артефакт, стараясь не разглашать внутреннюю информацию с вашей стороны, настоящий код может быть в порядке в этом отношении, мы не можем сказать. В любом случае, это'ы многословно из-за крайне низкой информационно-плотность, которая обычно не поддается легкого понимания.
Ваш второй пример сжимается до абсурдной степени. Если функции были полезны имена, которые могут отлично и хорошо читаемым, потому что это'т слишком много, но как-это Это'ы путаете в другом направлении.
После введения осмысленные имена, вы можете посмотреть, является ли одной из форм, кажется естественным, или если там's в золотой середине, чтобы стрелять для.
Теперь, когда у вас читабельный код, Большинство ошибок будет очевиден, а остальные, по крайней мере, труднее скрываться от вас.
Как всегда, когда дело доходит до читабельности, провал в крайности. Вы можете взять какие добрые советы по программированию, превратить ее в религиозную правило, и используют его, чтобы произвести совершенно нечитаемый код. (Если вы Don'т верить мне, проверьте эти два IOCCC победителей borsanyi и Горен и взглянем на то, как по-разному они используют функции, чтобы сделать код совершенно нечитаемым. Подсказка: Borsanyi использует ровно одну функцию, Горен многое, многое другое...)
В вашем случае, две крайности 1) с помощью одного выражения лица, и 2) вступление все в большой, немногословные, и сложные высказывания. Либо подход до крайности делает код нечитаемым.
Ваша задача, как программиста, это баланс. Для каждого оператора вы пишите, это ваш задача ответить на вопрос: "это это утверждение легко понять, и это сделать моя функция чтения?&и"
Суть в том, что нет ни одного измеримого сложности заявлением о том, что может решать, что хорошо, чтобы быть включенными в единый заявление. Взять к примеру строки:
double d = sqrt(square(x1 - x0) + square(y1 - y0));
Это довольно сложная инструкция, но любой программист стоит их соли должны быть в состоянии сразу понять, что это делает. Это достаточно известные картины. Как таковая, она является гораздо более читабельным, чем эквивалент
double dx = x1 - x0;
double dy = y1 - y0;
double dxSquare = square(dx);
double dySquare = square(dy);
double dSquare = dxSquare + dySquare;
double d = sqrt(dSquare);
который нарушает хорошо известный шаблон в бессмысленный ряд простых действий. Однако, заявление от вашего вопроса
var a = F(G1(H1(b1), H2(b2)), G2(c1));
похоже, слишком сложно для меня, даже если это'одной операции меньше, чем расчет расстояния. Конечно, что'ы прямое следствие мне не зная ничего о Ф()
, Г1()
, Г2()
, Н1()
, или Н2()
. Я мог бы решить по-другому, если бы я знал больше о них. Но, что'ы как раз и проблема: рекомендуемая сложность изложения сильно зависит от контекста, и об операциях участвует. И вы, как программист, должны взглянуть в этом контексте, и принять решение, что включать в одно заявление. Если вы заботитесь о читабельности, вы не можете переложить эту ответственность на какие-то помехи правило.
@Доминик, я думаю, что в вашем вопросе'ы анализ, вы'снова делаешь ошибку, что "читаемость" и "ремонтопригодность" - а это две разные вещи.
Это возможно, чтобы иметь код, который можно поддерживать, но нечитабельны? И наоборот, если код очень читабельный, почему он стал unmaintainable на счет чтения? Я'ве никогда не слышал о любой программист, который играл эти факторы друг против друга, приходится выбирать одно или другое!
С точки зрения принятия решения, следует ли использовать промежуточные переменные вложенных вызовов функций, в случае 3-х переменных учитывая, звонки на 5 отдельных функций, и некоторые вызовы вложенных 3 глубокие, я бы, как правило, к использованию, по крайней мере, некоторые промежуточные переменные, чтобы разорвать этот вниз, как это сделали вы.
Но я, конечно, не идут так далеко, чтобы сказать, вызовы функций не должны быть вложенными на всех. Это's вопрос суда в обстоятельствах.
Я хочу сказать, что следующие моменты выносить на суд:
Если вызываемой функции представляют собой стандартные математические операции, они'вновь больше может быть, чем вложенные функции, которые представляют какую-то непонятную логику домена, чьи результаты непредсказуемы и не могут быть оценены в уме читателя.
Функция с одним параметром более способные участвовать в гнездо (как внутренней или внешней) функции, чем функция с несколькими параметрами. Смешение функций различных арность на разных уровнях вложенности склонен оставить код, смотря, как свиньи'ы ухо.
Гнездо функции, которые программисты привыкли встречи выразили определенным образом - возможно, потому, что он представляет собой стандартный математический метод или уравнение, которое имеет стандартную реализацию - может быть более трудно прочитать и проверить, если она разбита на промежуточные переменные.
Небольшое гнездо вызовов функций, которые выполняет простые функции и уже понятно читать, а затем измельчали и чрезмерно распыляется, может быть труднее читать, чем тот, который не разбивается на всех.
Оба являются субоптимальными. Рассмотреть Замечания.
// Calculating torque according to Newton/Dominique, 4th ed. pg 235
var a = F(G1(H1(b1), H2(b2)), G2(c1));
Или конкретные функции, а не общего характера:
var a = Torque_NewtonDominique(b1,b2,c1);
При принятии решения, что приводит к буквам, имейте в виду, стоимость (копия против отсчета, L-значение против R-значение), читаемость и риск, индивидуально для каждого оператора.
Например, там's никакой добавленной стоимости от движущихся простой блок преобразования типа на их собственные линии, потому что это легко читать и очень вряд ли удастся:
var radians = ExtractAngle(c1.Normalize())
var a = Torque(b1.ToNewton(),b2.ToMeters(),radians);
Что касается вашего беспокойства по анализу аварийных дампов, проверки входных данных, как правило, гораздо более важный - собственно авария вполне может произойти внутри этих функций, а не линию, называя их, и даже если нет, вы не'т, как правило, необходимо, чтобы ему конкретно объяснили, где что взорвали. Это's путь более важно знать, где все пошло наперекосяк, чем она есть, чтобы знать, где они, наконец, взорвали, что проверка ввода ловит.
На мой взгляд, самодокументированный код лучше, так как ремонтопригодность и читаемость, вне зависимости от языка.
Заявление приведенный выше плотной, но "нагляден и":
double d = sqrt(square(x1 - x0) + square(y1 - y0));
Когда разбивается на этапы (проще для тестирования, конечно) теряет все связи, как указано выше:
double dx = x1 - x0;
double dy = y1 - y0;
double dxSquare = square(dx);
double dySquare = square(dy);
double dSquare = dxSquare + dySquare;
double d = sqrt(dSquare);
И очевидно, используя имена переменных и функций, что государство их целью явно является бесценным.
Даже "если что" блоки могут быть хорошими или плохими в самодокументируемыми. Это плохо, потому что вы не можете легко заставить первые 2 условия, чтобы проверить третий ... все не связаны:
if (Bill is the boss) && (i == 3) && (the carnival is next weekend)
Это делает более "коллективные" в смысле и легче создать условия испытания:
if (iRowCount == 2) || (iRowCount == 50) || (iRowCount > 100)
И это утверждение является лишь случайную строку символов, с самодокументируемыми точки зрения:
var a = F(G1(H1(b1), H2(b2)), G2(c1));
Глядя на вышеуказанное заявление, ремонтопригодность-прежнему является серьезной проблемой, если функции H1 и H2 как переделать же на "Система переменных состояния" и вместо того, чтобы быть объединены в один фильм "Ч" и функция, потому что кто-то в итоге будет изменять Н1 даже не думая, есть Н2 функция посмотреть и может сломать Н2.
Я считаю, что хороший дизайн кода является очень сложным, потому что снова нет жестких правил, которые могут быть систематически обнаружены и принудительно.
Читаемость основной части ремонтопригодности. Сомневаешься во мне? Выбор большой проект на языке, который вы не'т знаю (чтобы они предлагались как язык программирования, а язык программистов), и посмотрите, как вы'd дальше о рефакторинге это...
Я бы поставил читаемости, а где-то между 80 и 90 ремонтопригодности. Остальные 10-20% - это как поддается это рефакторинг.
Что сказал, Вы эффективно проходить в 2 переменных к конечному функции (f). Эти 2 переменные создаются при помощи 3-х переменных. Вы'd были лучше передает В1, В2 и С1 в F, если F уже существует, то создать что ли состав для F и возвращает результат. В этот момент он's просто вопрос предоставления Д доброе имя, и он выиграл'т имеет значения, какой стиль вы используете.
На обзоры нет, вы говорите, что больше логики на страницы читабельность СПИДа. Это неверно, метрика это'т страницы, это способ, и чем меньше логики метода содержится в более читабельный он.
Читаемые означает, что программист может держать логику (ввод, вывод и алгоритм) в их голове. Чем больше он делает, тем меньше программист может понять. Читайте на цикломатическую сложность.
Независимо от того, если вы находитесь в C# или C++, пока вы не в отладочном построении, возможным решением является оклеивание функции
var a = F(G1(H1(b1), H2(b2)), G2(c1));
Вы можете написать выражение короткая, и все же вам указал где проблема, просто глядя на трассировку стека.
returnType F( params)
{
returnType RealF( params);
}
Конечно, если вы называете ту же функцию несколько раз в той же строке, вы не можете знать, какие функции, однако вы все еще можете определить его:
Это не серебряная пуля, но это не так уж плохо на полпути.
Не говоря уже о том, что накрутка группы функций могут быть даже более выгодными для читабельности кода:
type CallingGBecauseFTheorem( T b1, C b2)
{
return G1( H1( b1), H2( b2));
}
var a = F( CallingGBecauseFTheorem( b1,b2), G2( c1));