Чи є змінні помилки антидіаграмою чи хорошим дизайном?


44

Щоб обробити кілька можливих помилок, які не повинні зупиняти виконання, у мене є errorзмінна, яку клієнти можуть перевіряти та використовувати для викидання винятків. Це анти-шаблон? Чи є кращий спосіб впоратися з цим? Для прикладу цього в дії ви можете побачити API mysqli PHP . Припустимо, що з проблемами видимості (доступними, публічними та приватними сферами - це змінна в класі чи глобальній?) Правильно обробляються.


6
Це для чого try/ catchіснує. Крім того, ви можете поставити ваш try/ catchнабагато далі стек у більш підходяще місце для обробки (що дозволяє розширити проблеми).
jpmc26

Що потрібно пам’ятати: якщо ви будете використовувати обробку на основі винятків і отримуєте виняток, ви не хочете показувати користувачеві занадто багато інформації. Використовуйте оброблювач помилок на зразок Elmah або Raygun.io, щоб перехопити його та показати користувачеві загальне повідомлення про помилку. НІКОЛИ не показуйте користувачеві сліду стека або конкретного повідомлення про помилку, оскільки вони розкривають інформацію про внутрішню роботу програми, якою можна зловживати.
Nzall

4
@Nate Ваша порада застосовується лише для критично важливих для безпеки програм, коли користувач не має повного довіри. Неясні повідомлення про помилки самі по собі є анти-зразком. Таким чином, це надсилання повідомлень про помилки по мережі без виразної згоди користувача.
пієдар

3
@piedar Я створив окреме запитання, де про це можна говорити вільніше: programmers.stackexchange.com/questions/245255/…
Nzall,

26
Загальний принцип в дизайні API, який приносить вам досить далеко, - це завжди дивитися, що робить PHP, а потім робити точно протилежне.
Філіп

Відповіді:


65

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

Якщо у вас є вибір, ви можете використати винятки.

Повідомлення

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

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

У випадку повідомлень про виключення я надаю якомога більше контексту, таких як:

Політику імені "foo" не вдалося отримати для користувальницької "бар", на яку посилалось у профілі користувача.

Порівняйте це із зворотним кодом -85. Якому б ви віддали перевагу?

Стеки викликів

Винятки зазвичай також мають детальні стеки викликів, які допомагають швидше та швидше налагоджувати код, і за потреби вони можуть реєструватися кодом виклику. Це дозволяє розробникам чітко визначити проблему в точній лінії, і, таким чином, є дуже потужним. Ще раз порівняйте це з файлом журналу із значеннями, що повертаються (наприклад, -85, 101, 0 тощо), який би ви хотіли?

Невдалий швидко упереджений підхід

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

Обгортка та розгортання винятків

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

Простота коду

Це трохи важче пояснити, але я дізнався за допомогою цього кодування як із поверненими значеннями, так і з винятками. Код, написаний за допомогою зворотних значень, зазвичай здійснював дзвінок, а потім проводив ряд перевірок того, що було значенням повернення. У деяких випадках він би викликав інший метод, і тепер буде проведена інша серія перевірок на значення, що повертаються з цього методу. За винятком, обробка винятків набагато простіша у більшості, якщо не у всіх випадках. У вас є блок "try / catch / нарешті", час виконання якого намагається виконати код, нарешті, блокує для очищення. Навіть вкладені блоки try / catch / нарешті порівняно простіше простежити та підтримувати, ніж вкладені if / else та пов'язані з ними значення повернення з декількох методів.

Висновок

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

Однак, якби це був C ++, визначити його було б складніше, тому що велика база коду вже існує з кодами повернення, і велика кількість розробників налаштована на повернення значень на відміну від винятків (наприклад, Windows насичена HRESULTs) . Крім того, у багатьох додатках це може бути проблемою продуктивності (або, принаймні, сприймається).


5
Windows повертає значення HRESULT з функцій C ++, щоб підтримувати сумісність з C у своїх публічних API (і тому, що ви починаєте потрапляти у світ шкоди, намагаючись маршалити винятки через межі). Не слід сліпо слідувати моделі операційної системи, якщо ви пишете заявку.
Коді Грей,

2
Єдине, що я хотів би додати до цього, - це згадка про нещільне з'єднання. Винятки дозволяють вирішити безліч несподіваних ситуацій у найбільш підходящому місці. Наприклад, у веб-додатку ви хочете повернути 500 за будь-який виняток, до якого не був підготовлений код, а не збити веб-додаток. Тож вам потрібен якийсь вилов у верхній частині коду (або у вашому рамках). Аналогічна ситуація є і в настільних графічних інтерфейсах. Але ви також можете розміщувати менш загальні обробники в різних місцях коду, щоб обробляти різні ситуації відмов таким чином, щоб відповідати поточному процесу, який намагається здійснити.
jpmc26

2
@TrentonMaki Якщо ви говорите про помилки конструкторів C ++, найкраща відповідь тут: parashift.com/c++-faq-lite/ctors-can-throw.html . Коротше кажучи, киньте виняток, але не забудьте спочатку очистити потенційні витоки. Я не знаю жодної іншої мови, де просто кинути з конструктора просто погано. Більшість користувачів API, які я думаю, вважають за краще виловлювати винятки, а не перевіряти коди помилок.
Псалом Огр33,

3
"Такі розширені сценарії непросто реалізувати із поверненими значеннями." Впевнені, що зможете! Все, що вам потрібно зробити, це створити ErrorStateReturnVariableсуперклас, і однією з його властивостей є InnerErrorState(що є екземпляром ErrorStateReturnVariable), який реалізуючи підкласи можна встановити, щоб показати ланцюжок помилок ... о, зачекайте. : p
Брайан Ш

5
Тільки тому, що мова підтримує винятки, не робить їх панацеєю. Винятки запроваджують приховані шляхи виконання, і, отже, їх ефекти слід правильно контролювати; спроба / улов легко додати, але отримати право на відновлення важко , ...
Матьє М.

21

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

Звичайно, якщо у вас є помилка типу, яку можна краще класифікувати як "попередження" (= ваша бібліотека може доставити дійсний результат, і абонент може ігнорувати попередження, якщо він вважає, що це не важливо), то індикатор стану у формі змінної може мати сенс навіть у мовах за винятком. Але будьте обережні. Абоненти бібліотеки, як правило, ігнорують подібні застереження, навіть якщо вони не повинні. Тож подумайте двічі, перш ніж вводити таку конструкцію у свою ступінь.


1
Дякую за пояснення! Ваша відповідь + Омер Ікбал відповів на моє запитання.
Mikayla Maki

Інший спосіб обробляти "попередження" - це скинути виняток за замовчуванням і мати якийсь необов'язковий прапор, щоб зупинити викид виключення.
Cyanfish

1
@Cyanfish: так, але треба бути обережним, щоб не передумувати такі речі, особливо під час створення бібліотек. Краще забезпечити один простий і робочий механізм попередження, ніж 2, 3 і більше.
Док Браун

Виняток слід кидати лише тоді, коли стався збій, невідомий або невідправний сценарій - виняткові обставини . Слід очікувати впливу на ефективність при створенні винятків
Gusdor

@Gusdor: абсолютно, тому типове "попередження" повинно IMHO не кидати виняток за замовчуванням. Але це також трохи залежить від рівня абстракції. Іноді служба чи бібліотека просто не можуть вирішити, чи слід незвичну подію трактувати як виняток з точки зору абонентів. Особисто я в таких ситуаціях я віддаю перевагу lib просто встановити попереджувальний індикатор (не виняток), нехай абонент перевірить цей прапор і кине виняток, якщо вважає його доцільним. Це те, що я мав на увазі, коли писав вище, «краще забезпечити один механізм попередження в бібліотеці».
Док Браун

20

Існує кілька способів подати сигнал про помилку:

  • змінна помилка для перевірки: C , Go , ...
  • виняток: Java , C # , ...
  • обробник "умови": Lisp (тільки?), ...
  • поліморфне повернення: Haskell , ML , Rust , ...

Проблема змінної помилки полягає в тому, що її легко забути перевірити.

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

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

Поліморфні повернення ( Either a bв Haskell) - це моє улюблене рішення поки що:

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

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


1
Хороша відповідь! Я сподівався, що я можу отримати список способів обробляти помилки.
Mikayla Maki

Arrghhhh! Скільки разів я бачив це "Проблема змінної помилки в тому, що її легко забути перевірити". Проблема з винятками полягає в тому, що її легко забути зловити. Тоді ваша програма вийде з ладу. Ваш начальник не хоче платити, щоб виправити це, але ваші клієнти перестають користуватися вашим додатком, оскільки вони розчаровані від збоїв. Все через те, що не вплинуло б на виконання програми, якби коди помилок були повернені та проігноровані. Єдиний раз, коли я бачив, як люди ігнорують коди помилок, коли це не так важливо. Код вище в ланцюзі знає, що щось пішло не так.
Данк

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

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

12

Я думаю, це жахливо. Наразі я переробляю програму Java, яка використовує зворотні значення замість виключень. Хоча ви, можливо, зовсім не працюєте з Java, я думаю, що це все-таки стосується.

Ви отримуєте такий код:

String result = x.doActionA();
if (result != null) {
  throw new Exception(result);
}
result = x.doActionB();
if (result != null) {
  throw new Exception(result);
}

Або це:

if (!x.doActionA()) {
  throw new Exception(x.getError());
}
if (!x.doActionB()) {
  throw new Exception(x.getError());
}

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

x.doActionA();
x.doActionB();

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

Поточний (жахливий) код:

private String doActionA() {
  try {
    someOperationThatCanGoWrong1();
    someOperationThatCanGoWrong2();
    someOperationThatCanGoWrong3();
    return null;
  } catch(Exception e) {
    return "Something went wrong!";
  }
}

Нове та вдосконалене:

private void doActionA() throws Exception {
  someOperationThatCanGoWrong1();
  someOperationThatCanGoWrong2();
  someOperationThatCanGoWrong3();
}

Слідочок сліду зберігається і повідомлення доступне за винятком, а не марним "Щось пішло не так!".

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


1
Однак, є одна ситуація, коли ваші "нові та вдосконалені" втрачають контекст, коли виняток відбувається спочатку. Наприклад, у "поточній (жахливій) версії" doActionA (), застереження може мати доступ до змінних екземплярів та іншої інформації з об'єкта, що додає, для надання більш корисного повідомлення.
ПоінформованоAA

1
Це правда, але наразі цього не відбувається. І ви завжди можете зловити виняток у doActionA та обгорнути його в інший виняток із повідомленням про стан. Тоді у вас залишиться слід стека та корисне повідомлення. throw new Exception("Something went wrong with " + instanceVar, ex);
mrjink

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

2
Отже, попросіть абонента включити його, коли він обробляє виняток. Це ж стосується і початкового питання. Зараз ви нічого не можете зробити, що не можете зробити з винятками, і це призводить до більш чистого коду. Я віддаю перевагу виняткам над поверненими булевими або повідомленнями про помилки.
mrjink

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

5

"Щоб вирішити кілька можливих помилок, які не повинні зупиняти виконання",

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

Два шаблони, якими я користувався:

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

  • Передайте об'єкт обробника помилок / попередження (або встановіть його як змінну члена). І кожна помилка викликає функцію члена обробника. Таким чином, абонент може вирішити, що робити з такими непостійними помилками.

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

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

class MyFunClass {
  public interface ErrorHandler {
     void onError(Exception e);
     void onWarning(Exception e);
  }

  ErrorHandler eh;

  public void canFail(int i) {
     if(i==0) {
        if(eh!=null) eh.onWarning(new Exception("canFail shouldn't be called with i=0"));
     }
     if(i==1) {
        if(eh!=null) eh.onError(new Exception("canFail called with i=1 is fatal");
        throw new RuntimeException("canFail called with i=2");
     }
     if(i==2) {
        if(eh!=null) eh.onError(new Exception("canFail called with i=2 is an error, but not fatal"));
     }
  }
}

3
+1 за те, що помітив, що користувач хоче попередження, а не помилку. Можливо, варто згадати warningsпакет Python , який дає ще один зразок цієї проблеми.
James_pic

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

Може бути корисним згадати, що об'єкт зворотного виклику помилки, що передається, може винести виняток, коли трапляються певні помилки чи попередження - справді це може бути поведінка за замовчуванням - але це може бути також корисним засобом, за допомогою якого він може запитати функція виклику щось робити. Наприклад, метод "помилки розбору помилок" може дати абоненту значення, яке, як вважають, повернув аналіз.
supercat

5

Часто немає нічого поганого у використанні цього чи іншого шаблону, якщо ви використовуєте шаблон, який використовують усі інші. У розробці Objective-C значно кращим шаблоном є передача покажчика, де метод, який викликається, може депонувати об'єкт NSError. Винятки зарезервовані для помилок програмування та призводять до збоїв (якщо у вас немає програм Java або .NET, які пишуть свій перший додаток для iPhone). І це працює досить добре.


4

На питання вже відповіли, але я не можу собі допомогти.

Ви не можете реально очікувати, що виняток надасть рішення для всіх випадків використання. Молот кого?

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

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

Тож урок тут такий: Винятки мають свої місця, як і коди помилок. Вибирайте мудро.


Я думаю, це швидше передбачає поганий дизайн. Метод, який бере аргументи, повинен мати можливість мати справу з тими чи ні - нічого середнього. У вашому прикладі має бути Validator(інтерфейс), який вводиться у відповідний метод (або об'єкт за ним). Залежно від введеного Validatorметоду буде діяти з неправильними паролями - чи ні. Оточуючий код може потім спробувати a, WeakValidatorякщо користувач запитав його після, наприклад, a WeakPasswordExceptionбуло кинуто початково спробуваним StrongValidator.
jhr

Ах, але я не сказав, що це не може бути інтерфейсом чи валідатором. Я навіть не згадував JSR303. І якщо ви уважно прочитали, я переконався, що не кажете слабкий пароль, швидше, щоб він був не дуже сильним. Слабкий пароль може стати причиною зупинки потоку і попросити користувача більш міцного пароля.
Олександр Сантос

А що б ви зробили із середньо-сильним, але не дуже-дуже слабким паролем? Ви перервете потік і покажете користувачеві повідомлення, яке вказує, що введений пароль не дуже сильний. Тож мати MiddlyStrongValidatorчи щось. І якщо це насправді не перервало ваш потік, ви Validatorповинні бути зателефоновані заздалегідь, тобто перед тим, як продовжувати потік, поки користувач ще вводить свій пароль (або подібний). Але тоді перевірка в першу чергу не була частиною розглянутих методів. :) Напевно, справа смаку все-таки ...
jhr

@jhr У написаних валідаторами я, як правило, створюю AggregateException(або подібний ValidationException) і вкладаю конкретні винятки для кожної проблеми перевірки в InnerExceptions. Наприклад, це може бути BadPasswordException: "Пароль користувача менше мінімальної довжини 6" або MandatoryFieldMissingException: "Ім'я користувача повинно бути вказано" тощо. Це не еквівалентно кодам помилок. Усі ці повідомлення можуть відображатися користувачеві таким чином, щоб він зрозумів, і якщо NullReferenceExceptionзамість нього було кинуто, ми отримали помилку.
Омер Ікбал

4

Існують випадки використання, коли коди помилок є кращими за винятки.

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

Інші відповіді висвітлювали, чому виключення слід віддавати перевагу кодам помилок взагалі.


Якщо попередження потрібно зареєструвати або щось таке, так і буде. Але якщо помилка "потребує звітування", під якою я припускаю, що ви маєте на увазі звітність перед користувачем, немає ніякого способу гарантувати, що оточуючий код прочитає ваш код повернення та фактично повідомить про нього.
jhr

Ні, я маю на увазі повідомити про це абоненту. Відповідальність за абонент визначає, чи повинен користувач знати про помилку чи ні, як і у випадку винятку.
Джек Едлі

1
@jhr: Коли коли-небудь гарантують що-небудь? У договорі для класу може бути визначено, що клієнти мають певні обов'язки; якщо клієнти дотримуються договору, вони будуть робити те, що вимагає контракт. Якщо цього не відбудеться, будь-які наслідки будуть виною коду клієнта. Якщо хтось хоче захиститись від випадкових помилок клієнта і має контроль над типом, повернутим методом серіалізації, він може містити прапор "непризнаного можливого пошкодження" і не дозволяти клієнтам читати дані з нього, не викликаючи AcknowledgePossibleCorruptionметод. .
supercat

1
... але наявність класу об'єктів для зберігання інформації про проблеми може бути кориснішим, ніж викидання винятків або повернення коду помилки пропуску. Додаток повинен використовувати цю інформацію відповідним чином (наприклад, завантажуючи файл "Foo", повідомляйте користувача про те, що дані можуть бути не достовірними, і запропонуйте користувачеві вибрати нове ім'я при збереженні).
supercat

1
Існує одна гарантія, якщо використовуються винятки: якщо ви їх не спіймаєте, вони піднімаються вище - в гіршому випадку - до інтерфейсу користувача. Такої гарантії немає, якщо ви використовуєте зворотні коди, які ніхто не читає. Звичайно, дотримуйтесь API, якщо ви хочете його використовувати. Я згоден! Але, на жаль, є місце для помилок ...
jhr

2

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

Коли виконання коду не повинно бути перервано (наприклад, дія на введенні користувача, яка може містити кілька помилок, наприклад, програма для компіляції або форма для обробки), я вважаю, що збирання помилок у змінних помилок на зразок has_errorsі error_messagesсправді набагато більш елегантний дизайн, ніж кидання виняток при першій помилці. Це дозволяє знаходити всі помилки у введенні користувача, не змушуючи користувача повторно подавати заявку.


Цікаво взяти на себе питання. Я думаю, що проблема з моїм питанням і моїм розумінням - нечітка термінологія. Те, що ви описуєте, не є винятковим, але це помилка. Як ми повинні це назвати?
Mikayla Maki

1

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

У Perl 6 це робиться через fail, який у випадку, якщо no fatal;діапазон withing повертає спеціальний об'єкт виключення виключення Failure.

У Perl 5 ви можете використовувати Contextual :: Return, з яким ви можете це зробити return FAIL.


-1

Якщо є щось дуже конкретне, я думаю, що змінна помилка для перевірки є поганою ідеєю. Здається, мета полягає в економії часу, витраченого на перевірку (ви можете просто повернути значення змінної)

Але тоді, якщо ви щось зміните, вам доведеться все-таки перерахувати це значення. Я не можу сказати більше про зупинку та викидання винятків.

EDIT: Я не розумів, що це питання парадигми програмного забезпечення замість конкретного випадку.

Дозвольте мені уточнити свої моменти у конкретному моєму випадку, в якому моя відповідь мала б сенс

  1. У мене є колекція об'єктів сутності
  2. У мене є веб-сервіси процедурного стилю, які працюють з цими об'єктами сутності

Існує два види помилок:

  1. Помилки під час обробки трапляються на рівні обслуговування
  2. Помилки, оскільки в об'єктах сутності є невідповідності

У сервісному шарі немає іншого вибору, крім використання об'єкта Result в якості обгортки, що є еквівалентністю змінної помилки. Моделювання винятку через службовий виклик за протоколом, як-от http, можливо, але це, безумовно, не дуже добре. Я не кажу про подібні помилки і не вважаю, що це така помилка, яку задають у цьому питанні.

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

  • використовуючи змінну перевірки
  • киньте виняток негайно, коли поле встановлено неправильно із сеттера

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

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


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