Должны ли программисты использовать логические переменные для «документирования» своего кода? - PullRequest
78 голосов
/ 19 марта 2010

Я читаю McConell Code Complete , и он обсуждает использование логических переменных для документирования вашего кода. Например, вместо:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || 
   (elementIndex == lastElementIndex)){
       ...
}

Он предлагает:

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

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

Ответы [ 14 ]

1 голос
/ 19 марта 2010

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

Так что:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || 
   (elementIndex == lastElementIndex)){
   ...
}

После преобразования становится:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) |
   (elementIndex == lastElementIndex)){
   ...
}

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

0 голосов
/ 19 марта 2010

Я редко создаю отдельные переменные. Когда я усложняю тесты, я делаю вложенные IF и добавляю комментарии. Как

boolean processElement=false;
if (elementIndex < 0) // Do we have a valid element?
{
  processElement=true;
}
else if (elementIndex==lastElementIndex) // Is it the one we want?
{
  processElement=true;
}
if (processElement)
...

Допустимый недостаток этой техники заключается в том, что следующий программист, который придет, может изменить логику, но не потрудиться обновить комментарии. Я предполагаю, что это общая проблема, но я много раз видел комментарий, который говорит: «Подтвердите идентификатор клиента», а в следующей строке рассматривается номер детали или что-то подобное, и мне остается задаться вопросом, где клиент Идентификатор приходит.

0 голосов
/ 19 марта 2010

По своему опыту я часто возвращался к некоторым старым сценариям и спрашивал себя: «Что, черт возьми, я тогда думал?». Например:

Math.p = function Math_p(a) {
    var r = 1, b = [], m = Math;
    a = m.js.copy(arguments);
    while (a.length) {
        b = b.concat(a.shift());
    }
    while (b.length) {
        r *= b.shift();
    }
    return r;
};

, который не так интуитивен, как:

/**
 * An extension to the Math object that accepts Arrays or Numbers
 * as an argument and returns the product of all numbers.
 * @param(Array) a A Number or an Array of numbers.
 * @return(Number) Returns the product of all numbers.
 */
Math.product = function Math_product(a) {
    var product = 1, numbers = [];
    a = argumentsToArray(arguments);
    while (a.length) {
        numbers = numbers.concat(a.shift());
    }
    while (numbers.length) {
        product *= numbers.shift();
    }
    return product;
};
0 голосов
/ 19 марта 2010

Я думаю, это зависит от того, какой стиль предпочитаете вы / ваша команда. Рефакторинг «Ввести переменную» может быть полезен, но иногда нет:)

И я должен не согласиться с Кевином в его предыдущем посте. Его пример, я полагаю, применим в том случае, когда вводимая переменная может быть изменена, но введение ее только для одного статического логического значения бесполезно, поскольку у нас есть имя параметра в объявлении метода, так зачем дублировать его в коде?

например:

void DoSomeMethod(boolean needDelete) { ... }

// useful
boolean deleteOnCompletion = true;
if ( someCondition ) {
    deleteOnCompletion = false;
}
DoSomeMethod(deleteOnCompletion);

// useless
boolean shouldNotDelete = false;
DoSomeMethod(shouldNotDelete);
...