Какие шаги и меры я могу предпринять, чтобы предотвратить глубокие отступы в моем коде?
Какие шаги и меры я могу предпринять, чтобы предотвратить глубокие отступы в моем коде?
Ответы:
Глубокий отступ обычно не является проблемой, если каждая функция / метод в вашей программе выполняет одно и только одно. Иногда может потребоваться вложить условные выражения на несколько уровней, но я могу честно сказать, что я написал код с глубоким отступом всего несколько раз за 12+ лет написания кода.
Лучшее, что вы можете сделать, это извлечь методы:
int Step1(int state)
{
if (state == 100)
{
return Step2(state);
}
else
{
return Step3(state);
}
}
int Step2(int state)
{
if (state != 100)
{
throw new InvalidStateException(2, state);
}
// ....
}
if
условий. В крайнем случае вы получите исполняемый псевдокод.
else
блоки.
Может быть, вы могли бы рассмотреть пункты охраны ?
вместо того
public void DoSomething(int value){
if (someCondition){
if(someOtherCondition){
if(yetAnotherCondition){
//Finally execute some code
}
}
}
}
Делать
public void DoSomething(int value){
if(!(someCondition && someOtherCondition && yetAnotherCondition)){
return;
//Maybe throw exception if all preconditions must be true
}
//All preconditions are safe execute code
}
Если у вас когда-нибудь будет шанс, я рекомендую вам прочитать «Code Complete» Стива Макконнелла. У него много хороших советов по этим темам.
http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_6
Для получения дополнительной информации о «пунктах охраны» см .: https://sourcemaking.com/refactoring/replace-nested-conditional-with-guard-clauses
Инвертировать ваши if
с.
Вместо того:
if (foo != null)
{
something;
something;
if (x)
{
something;
}
something;
}
else
{
boohoo;
}
Я бы написал:
if (foo == null)
{
boohoo;
return;
}
something;
something;
if (x)
{
something;
}
something;
То же относится и к if
- else
блокам. Если else
короче / меньше вложенных, то верните их.
Проверьте значения параметров в одном месте
Проверьте все параметры на недопустимые значения, как только вы введете свой метод, затем продолжайте, зная, что вы в безопасности. Это делает код более читабельным, но также избавляет вас от необходимости накапливать условные блоки в дальнейшем и распространять эти проверки по всей подпрограмме.
If
s в начале кода, которые останавливают поток выполнения из-за невыполнения некоторых условий, также называются защитными предложениями , как указывал @JasonTuran. И это кажется настолько близким, насколько это возможно, к определенному имени.
Как правило, я видел, что код с глубоким отступом обычно является проблематичным кодом. Если вы столкнулись с этой проблемой, сделайте шаг назад и оцените, выполняет ли ваша функция слишком много вещей.
В то же время, чтобы ответить на ваш вопрос, если есть необходимость в столь глубоких отступах, я бы предложил, чтобы вы позволили этому быть там. По той простой причине, что в таком коде отступ поможет, так как он, вероятно, будет очень длинным фрагментом кода.
Разбейте вложенные компоненты (особенно повторяющиеся) на отдельные функции (это проще, если ваш язык поддерживает замыкания) или замените серию вложенных циклов рекурсией.
Кроме того, сделайте отступ двух пробелов вместо четырех.
Я не рассматриваю глубокие отступы как категорическую проблему, которую нужно удалить (и при этом я не рассматриваю рефакторинг как истинный ответ на все вопросы).
Обычно вместо вложенных ifs я люблю писать логические выражения:
if (foo && bar && baz)
скорее, чем
if foo
if bar
if baz
Я сам в это не верил, но согласно Code Complete это подходящее место для использования break
(если ваша команда на борту). Я полагаю, что это более приемлемо для программистов на C ++, хотя там, где они break
используются в switch
выражениях, чем для программистов на Delphi, где они break
используются только тогда, когда вам не хочется писать while
цикл.
Отступ - это действительно боевая мысль. То, что я научился делать, это сначала разделить метод на части, а затем использовать странный трюк, чтобы пропустить все последующие части, если одна часть не удалась. Вот пример:
Вместо того :
{if (networkCardIsOn() == true)
{if (PingToServer() == true)
{if (AccesLogin(login,pass) == true)
{if (nextCondition == true)
...
}
}
}
Я сейчас пишу:
{vbContinue = true;
if (vbContinue) {
vbContinue = networkCardIsOn();
if (vbContinue == false) {
code to Handle This Error();
}
}
if (vbContinue) {
vbContinue = PingToServer();
if (vbContinue == false) {
code to HandleThisError2();
}
}
if (vbContinue) {
vbContinue = AccesLogin(login,pass);
if (vbContinue == false) {
HandleThisErrorToo();
}
}
...
Поначалу мне это показалось странным, но с тех пор, как я это использую, затраты на обслуживание были поделены пополам, и мой мозг в конце дня остыл.
Фактически, выгода, представленная этой «техникой», состоит в том, что сложность кода действительно разделена, потому что код менее плотен.
При чтении кода вам не нужно ничего вспоминать о прошлых условиях: если вы находитесь в точке X в коде, предыдущие шаги пройдены и успешно выполнены.
Другим преимуществом является то, что «путь и условие выхода» из всех вложенных «если-еще» упрощается.