Що визначає надійний код?


42

Мій професор продовжує посилатися на цей приклад Java, коли він говорить про "надійний" код:

if (var == true) {
    ...
} else if (var == false) {
    ...
} else {
    ...
}

Він стверджує, що "надійний код" означає, що ваша програма враховує всі можливості, і що немає помилки - всі ситуації обробляються кодом і призводять до дійсного стану, отже, і "інше".

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

"Не маючи такого поняття як помилка" також здається смішним; навіть програми Google показують помилки безпосередньо користувачеві, замість того, щоб їх мовчки ковтати або якось вважати їх дійсним станом. І це добре - мені подобається знати, коли щось піде не так. І, як видається, заява сказати, що програма ніколи не матиме жодних помилок.

То яке власне визначення поняття "надійний код"?



4
Це дотримується лише не набраної мови. У сильно набраній мові змінна типу булева (не якесь ціле число, що представляє булева), може бути лише істинним або хибним, третього варіанту немає ...
Marjan Venema

23
запитайте його, як би ви протестували тест на 3-й випадок, оскільки надійний код, безумовно, потребує тестування, і якщо вам не вдасться протестувати 3-й випадок, ви не зможете знайти жодних помилок, які можуть там ховатися.
gbjbaanb

2
@Marjan - мовою, що не дуже набрана, ви, швидше за все, просто напишіть: if (var) {} else {}
kevin cline

2
Я не знаю жодної мови, де і x, і x могли бути правдивими. Зауважте, що я не пропонував "if (x == true) ..."; Я гидую такими порівняннями.
кевін клайн

Відповіді:


33

який сенс перевіряти третій стан, коли третій стан логічно неможливий?

Як щодо того, Boolean?що дозволяє створити NULLстан, який не є ні правдою, ні хибністю. Тепер що робити програмне забезпечення? Деяке програмне забезпечення повинно бути високостійким, як кардіостимулятори. Хтось бачив, щоб хтось додав стовпчик до бази даних, яка була Booleanі ініціалізувала поточні дані NULLспочатку? Я знаю, я це бачив.

Ось декілька посилань, які обговорюють, що означає бути надійним щодо програмного забезпечення:

Якщо ви думаєте, що тут є одне загальновизнане визначення поняття "надійний", удачі. Можуть бути такі синоніми, як захист від бомби або ідіот. Програміст Duct Tape був би прикладом того, хто зазвичай пише надійний код хоча б в моєму розумінні термінів.


13
Якби це було нульовим булевим і Java, і c # кидало б так, що нуль слід перевірити спочатку.
Есбен Сков Педерсен

Здається, не існує універсальної згоди щодо визначення того, що таке кішка чи собака.
Тулен Кордова

11

Заради мого обговорення Bool може мати 2 стани, істинне чи помилкове. Все інше - це невідповідність специфікації мови програмування. Якщо ланцюг ваших інструментів не відповідає його характеристикам, ви шлангуєте незалежно від того, чим займаєтесь. Якщо розробник створив тип Bool, який мав більше двох станів, це останнє, що він коли-небудь зробив у моїй кодовій базі.

Варіант А.

if (var == true) {
    ...
} else if (var == false) {
    ...
} else {
    ...
}

Варіант В

if (var == true) {
    ...
} else {
    ...
}

Я стверджую, що варіант B більш надійний .....

Будь-який твіт може сказати вам вирішити несподівані помилки. Як правило, їх легко виявити, як тільки ви їх думаєте. Приклад, який подав ваш професор, - це не те, що могло статися, тому це дуже поганий приклад.

A неможливо протестувати без скручених тестових джгутів. Якщо ви не можете створити його, як ви збираєтеся його протестувати? Якщо ви не перевірили код, як ви знаєте, що він працює? Якщо ви не знаєте, що це працює, то ви не пишете надійного програмного забезпечення. Я думаю, що вони все ще називають це Catch22 (Чудовий фільм, дивіться його колись).

Варіант B тривіальний для тестування.

Наступна проблема, задайте професору це запитання: "Що ви хочете, щоб я це зробив, якщо булевий неправдивий і неправдивий?" Це повинно призвести до дуже цікавої дискусії .....

У більшості випадків базовий дамп є доцільним, в гіршому випадку це дратує користувача або коштує великих грошей. Що робити, якщо, скажімо, модуль є системою обчислення реєстру в режимі реального часу Space shuttle? Будь-яка відповідь, незалежно від того, наскільки неточна, не може бути гіршою за переривання вагітності, що знищить користувачів. Що робити, якщо ви знаєте, що відповідь може бути неправильною, перейдіть на 50/50 або перервіть і перейдіть на 100% провал. Якби я був членом екіпажу, я брав би 50/50.

Варіант А вбиває мене Варіант В дає навіть рівний шанс на виживання.

Але зачекайте - це симуляція перенавчання космічного човника - що тоді? Аборт, щоб ти знав про це. Звучить, як гарна ідея? - НЕ - тому що вам потрібно перевірити код, який ви плануєте відправити.

Варіант A кращий для моделювання, але його неможливо розгорнути. Безкорисний варіант B - це розгорнутий код, тому моделювання працює так само, як і живі системи.

Скажімо, це було поважною проблемою. Кращим рішенням було б ізолювати обробку помилок від логіки програми.

if (var != true || var != false) {
    errorReport("Hell just froze over, var must be true or false")
}
......
if (var == true){
 .... 
} else {
 .... 
}

Попереднє читання - Therac-25 рентгенівська машина, відмова ракети Ariane 5 та інші (у посилань багато розірваних посилань, але достатньо інформації, що Google допоможе)


1
"..неочікувані помилки. Зазвичай їх можна виявити по-справжньому легко", коли ви думаєте про них ", - але коли ви думаєте про них, вони вже не є несподіваними.
gbjbaanb

7
Виникає питання , чи замість цього if (var != true || var != false) {повинен бути ваш код &&.

1
Я легко можу придумати бул, який не є ні правдою, ні хибністю, але все-таки несподівано. Якщо ви говорите, що bool не може бути чим іншим, якщо я перевіряю, чи є буква символом цифри, а потім перетворюю її на ціле число, я можу легко придумати це ціле значення менше 0 або більше 9, але все одно несподіваний.
gnasher729

1
Null Booleans підтримуються на Java та C # та мають реальну програму. Розглянемо базу даних, що містить список людей. Через деякий час ви вирішите, що вам потрібно гендерне поле (isMale). Null означає "ніколи не просили, не знаю"; true означає чоловічий, а false - жіночий. (Гаразд, транс-гендер пропущено для простоти ...).
ківірон

@kiwiron: Кращим рішенням не буде використання типу перерахування: "Чоловік", "Жінка", "Не запитував". Перерахування краще - може бути розширене, коли виникає потреба (на думку, наприклад, "Асексуал, Гермафродита," Відмовляйся відповідати ".
mattnz

9

Насправді ваш код не більш надійний, але МЕНШЕ надійний. Остаточний else- просто мертвий код, який ви не можете перевірити.

У критичних програмних засобах, таких як космічні апарати, мертвий код і, як правило, неперевірений код заборонено: Якщо космічний промінь створює розлад однієї події, що, в свою чергу, активує ваш мертвий код, все можливе. Якщо SEU активує частину надійного коду, поведінка (несподівана) залишається під контролем.


Я не розумію, що це в космічних апаратах, заборонений код заборонений? тобто ви не можете написати останнє ще? так як ви не можете його перевірити, ви не можете помістити його? але тоді, що це означає: "Якщо SEU активує частину надійного коду, поведінка (несподівана) залишається під контролем".
пошарпаний

5
Так, у критичному просторі тест програмного забезпечення повинен охоплювати 100% і, як наслідок, недоступний код (він же мертвий код) заборонений
mouviciel

7

Я думаю, що професор може заплутати "помилку" та "помилку". Надійний код, безумовно, повинен мати мало / відсутні помилки. Міцний код може, і у ворожій обстановці, повинен мати хороше управління помилками (будь то виняток обробки або жорсткі тести повернення статусу).

Я згоден, що приклад коду професора - дурний, але не такий нерозумний, як мій.

// Assign 3 to x
var x = 3;
x = 3;   // again, just for sure
while (x < 3 or x > 3) { x = 3; }  // being robust
if (x != 3) { ... }  // this got to be an error!

1
Останнє, якщо, безумовно, спрацьовує, воно не вимагатиме дійсно великих зусиль. Будь-який досвідчений програміст C побачив, що значення раптово змінюються. Звичайно, логічно, в контрольованому однопотоковому середовищі цього ніколи не повинно відбуватися. У реальному житті код всередині if з часом станеться. Якщо нічого корисного ви не можете зробити всередині цього, якщо, тоді не кодуйте це! (У мене був кумедний досвід під час певної розробки програмного забезпечення, де я створив виняток із проклятими словами, якщо трапилося щось неможливе ... здогадайтесь, що сталося?).
Алекс

2
Справжня історія:boolean x = something(); if (x) { x = True // make sure it's really true, ... }
Андрес Ф.

6

Не існує узгодженого визначення надійного коду , оскільки для багатьох речей в програмуванні це більш-менш суб'єктивно ...

Приклад, який дає ваш професор, залежить від мови:

  • У Haskell, третій варіант Booleanможе бути або, Trueабо Falseнемає
  • У C ++ boolможе бути true, falseабо (на жаль) походить із якогось сумнівного складу, що ставить його у невідомий випадок ... Це не повинно статися, але може статися внаслідок попередньої помилки.

Однак те, що радить ваш професор, затьмарює код, вводячи сторонні логіки для випадків, що не відбуватимуться в середині основної програми, тож я вкажу вам на захистне програмування .

У випадку університету ви навіть можете його доповнити, прийнявши стратегію проектування за контрактом:

  • Встановіть інваріанти для класів (наприклад, sizeкількість елементів у dataсписку)
  • Встановіть попередні умови та умови для кожної функції (наприклад, ця функція може використовуватися лише з aменшою кількістю 10)
  • Перевірте кожного з них у точках входу та виходу кожної із своїх функцій

Приклад:

class List:
  def __init__(self, items):
    self.__size = len(items)
    self.__data = items

  def __invariant(self):
    assert self.__size == len(self.__data)

  def size(self):
    self.__invariant()

    return self.__size

  def at(self, index):
    """index should be in [0,size)"""
    self.__invariant()
    assert index >= 0 and index < self.__size

    return self.__data[index]

  def pushback(self, item):
    """the subsequent list is one item longer
       the item can be retrieved by self.at(self.size()-1)"""
    self.__invariant()

    self.__data.append(item)
    self.__size += 1

    self.__invariant()
    assert self.at(self.size()-1) == item

Але професор спеціально сказав, що це Java, і конкретно НЕ сказав, що це за тип вар. Якщо воно булеве, воно може бути істинним, хибним або нульовим. Якщо щось інше, воно може бути нерівним як істинним, так і неоднаковим для помилковим. Так, перекриття між міцними, захисними та параноїчними.
Енді Кенфілд

2
У C, C ++ і Objective-C, bool може мати невизначене значення, як і будь-який інший тип, але будь-яке призначення встановить його як true або false і нічого іншого. Наприклад: bool b = 0; b ++; b ++; встановить b в істинне.
gnasher729

2

Підхід вашого професора повністю помилковий.

Функція, або лише трохи коду, повинна мати специфікацію, яка говорить про те, що вона робить, яка повинна охоплювати всі можливі дані. І код повинен бути написаний так, щоб його поведінка гарантувала відповідність специфікації. У прикладі я б написав специфікацію досить просто, як це:

Spec: If var is false then the function does "this", otherwise it does "that". 

Потім ви пишете функцію:

if (var == false) dothis; else dothat; 

і код відповідає специфікації. Тож ваш професор каже: Що робити, якщо var == 42? Подивіться на специфікацію: в ній сказано, що функція повинна виконувати "те". Подивіться на код: Функція робить "те". Функція відповідає специфікації.

Там, де код вашого професора робить речі абсолютно непідступними, це той факт, що при його підході, коли var не є ні правдою, ні помилкою, він виконує код, який ніколи раніше не називався, і який є абсолютно неперевіреним, з абсолютно непередбачуваними результатами.


1

Я згоден з твердженням @ gnasher729: Підхід вашого професора повністю помилковий.

Міцний означає, що він стійкий до поломки / відмови, тому що він робить мало припущень і роз'єднується: це самодостатній, самовизначальний і портативний. Це також включає адаптивність до мінливих вимог. Одним словом, ваш код довговічний .

Зазвичай це перекладається на короткі функції, які отримують свої дані за параметрами, переданими абонентом, та використання публічних інтерфейсів для споживачів - абстрактні методи, обгортки, непрямість, інтерфейси стилю COM тощо - а не функції, що містять конкретний код реалізації.


0

Надійний код - це просто код, який добре поправляє збої. Ні більше, ні менше.

Збоїв існує багато типів: неправильний код, неповний код, несподівані значення, несподівані стани, винятки, виснаження ресурсів, .... Надійний код добре справляється з цим.


0

Я б вважав код, який ви подали, як приклад оборонного програмування (принаймні, як я використовую цей термін). Частина оборонного програмування полягає у виборі, який мінімізує припущення щодо поведінки решти системи. Наприклад, що з них краще:

for (int i = 0; i != sequence.length(); ++i) {
    // do something with sequence[i]
}

Або:

for (int i = 0; i < sequence.length(); ++i) {
    // do something with sequence[i]
}

(У випадку, якщо у вас виникли проблеми з переглядом різниці, перевірте тест циклу: перший використовує !=, другий використовує <).

Тепер, за більшості обставин, дві петлі будуть вести себе абсолютно однаково. Однак перший (порівняно з !=) робить припущення, яке iбуде збільшуватися лише один раз за ітерацію. Якщо воно пропускає значення, sequence.length()то цикл може продовжуватися за межами послідовності та викликати помилку.

Ви можете, таким чином, зробити аргумент, що друга реалізація є більш надійною: вона не залежить від припущень про те, чи змінюється тіло циклу i(зауважте: насправді він все ще робить припущення, яке iніколи не є негативним).

Щоб дати певну мотивацію, чому ви, можливо, не хочете робити таке припущення, уявіть, що цикл сканує рядок, роблячи деяку обробку тексту. Ви пишете цикл і все добре. Тепер ваші вимоги змінюються, і ви вирішите, що вам потрібно підтримувати символи втечі в текстовому рядку, тому ви змінюєте тіло циклу таким чином, що якщо він виявить символ втечі (скажімо, зворотній косий рисок), він збільшується, iщоб пропустити символу відразу після втечі. Тепер у першому циклі є помилка, оскільки якщо останній символ тексту є зворотною косою рисою, тіло циклу збільшуватиметься, iа цикл продовжуватиметься після кінця послідовності.


-1

Я особисто описую код як "надійний", у якого є цей важливий атрибут:

  1. Якщо моя мама сидить перед цим і працює з нею, вона не може зламати систему

Тепер під перервою я маю на увазі або переведення системи в нестабільний стан, або спричинення вилучення з НЕЗАДАЧОГО . Знаєте, іноді для простого поняття можна скласти складне визначення та пояснення. Але я вважаю за краще прості визначення. Користувачі досить добре знаходять надійні програми. Якщо користувач вашої програми надсилає вам багато запитів про помилки, про втрати стану, про неінтуїтивні робочі процеси тощо, то з вашим програмуванням щось не так.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.