Винятки "помилка програмування" - чи звучить мій підхід?


9

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

Як слід по-різному трактувати ці два види винятків? Чи вважаєте ви, що винятки з помилок мають бути чітко задокументовані чи достатньо для документування відповідних передумов? І чи можете ви вилучити документацію винятку передумови чи помилки, якщо це має бути очевидним (наприклад, ObjectDisposedExceptionпри виклику методу на розміщений об'єкт)


Зазвичай я виокремлюю ще одну категорію винятків: винятки з бізнесу. Вони відносяться до умов помилок, яких користувач цікавить деталями. Як правило, ці винятки перевіряються.
белучин

Відповіді:


2

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

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

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

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

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

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


Я розумію необхідність документування, які значення дозволені, але якщо ви бачите функцію performReadCommand(ICommand cmd, int replySizeBytes)- чи очікуєте, що нуль буде прийнятним для cmd або негативним значенням для replySizeBytes? Документація IMO потрібна буде лише в тому випадку, якщо ці значення фактично були дозволені, і ви, ймовірно, повинні вирішити, чи 0 дійсний для replySizeBytes.
Медо42

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

2

Ось мої власні думки. Зауважте, що я не надто впевнений, що це найкращий шлях, і саме тому я створив це питання в першу чергу.

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

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

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

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


1

Розумне правило:

  1. Ловіть будь-який виняток, який ви можете виправити.
  2. Ловіть, коментуйте та повторно скидайте будь-які винятки, які ви не можете виправити, але можете сказати щось корисне.
  3. Не вдавайте жодного винятку, який ви не можете обробити та діагностувати краще, ніж буде оброблена за замовчуванням.

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


0

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


Це суперечить популярній раді - зокрема, Ефективна Java, 2-е видання, пункт 62 - "Документуйте всі винятки, викинуті кожним методом". Насправді, Блох визнає, що неперевірені винятки, як правило, стосуються помилок програмування, але їх також слід ретельно задокументувати, оскільки це "найкращий спосіб" документувати передумови методу. Я не впевнений, чи згоден я. Якщо я задокументую винятки, я зроблю їх частиною контракту на інтерфейс і, можливо, доведеться додати код, щоб вони залишилися тими ж, якщо моя реалізація зміниться.
Медо42

1
Для кожного експерта є зустрічний експерт. Брюс Еккель, автор досить відомого Мислення на Яві , колись був у таборі перевірених винятків і змінив сторони. Існує приємна дискусія між Екклсом та Андерсом Хейлсбергом , творцем C #, який не перевірив винятків.
Росс Паттерсон

0

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


2
Чи вважаєте ви (наприклад) розраховане (або значення помилки) NULL як помилку програмування або помилку контракту ? Я йду з вашою відмінністю, але межа не так чітко вирізана :)
Андрій

Якщо null обчислюється з аргументу, який було передано (наприклад, аргумент null або щось недійсне), це помилка контракту. Якщо нуль обчислюється через шматок неправильного коду, це помилка програмування. Якщо нуль повинен бути обчислений, це не помилка. Я в цьому прикладі не бачу жодної двозначності.
Дж. Ашворт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.