Разумным рассуждением является то, что я считаю, что исключения не лучше, чем «Goto», считают вредными с 1960-х годов, в том смысле, что они создают резкий прыжок с одной точки кода к другому. На самом деле они значительно хуже, чем GoTo
- Они невидимы в исходном коде.
- Они создают слишком много возможных точек выхода для функции.
Как мы имеем дело с неопределенностью в нашем коде?
Если что-то пойдет не так, в нашем коде, нам нужно знать об этом, желательно без разрушения нашей программы. Когда я возвращаюсь в кодовые месяцы спустя или я использую кого-то код ELSES, я хочу, чтобы компилятор поможет мне обрабатывать ошибки изящными.
Вот несколько шаблонов, которые я видел, мой собственный код включен.
Шаблон 1 – Вернитесь или ложь
function doWork() : boolean {
// do some SIDE EFFECT
let result = doWork();
this.some_member_variable = result;
let success = result !== null;
if (success) {
return true;
} else {
return false;
}
}
Побочные эффекты облегчают рассуждать о том, что делает ваш код. Чистые функции, боковые эффекты Бесплатные функции, также проще тестируют. Также, если произошла неудача, вы не можете отправить сообщение для вызывающего абонента.
Узор 2 – Вернуть нулевой Если не удалось
В следующих примерах давайте предположим, что наши вещи базы данных синхронно, чтобы сделать вещи немного проще.
Вместо того, чтобы возвращать true или false, мы могли бы вернуть значение или нулевое значение.
import DB from 'my-synchronous-database';
function getUser(id : UserID) : User | null {
const user = DB.getUserById(id);
if (user) {
return user;
} else {
return null;
}
}
Это немного лучше, теперь, когда у нас нет побочного эффекта. Однако у нас все еще нет сообщения об ошибке, и нам лучше позаботиться о том, чтобы обратиться за возвращением null ценность или наша программа взорвется.
Это устраняет побочный эффект, но теперь создает новую проблему.
Я называю это моим миллиардной долларой ошибкой. Это было изобретение нулевой ссылки в 1965 году. В то время я разработал первый комплексную систему типа для ссылок на объектно-ориентированном языке (ALGOL W). Моя цель состояла в том, чтобы гарантировать, что все употребление ссылок должно быть абсолютно безопасным, при этом проверка выполняется автоматически компилятором. Но я не мог противостоять искушению поставить в нулевую ссылку, просто потому, что это было так легко реализовать. Это привело к неисчислимому ошибкам, уязвимости и сбоям системы, которые, вероятно, вызвали миллиард долларов от боли и ущерба за последние сорок лет.
Узор 3 – бросок исключение
Наш другой выбор – бросить исключение.
import DB from 'my-synchronous-database';
function getUser(id : UserID) : User {
const user = DB.getUserById(id);
if (user) {
return user;
} else {
throw new Error(`Cannot find the user by id ${id}`);
}
}
Теперь у нас есть сообщение об ошибке, но теперь мы ввели другой побочный эффект: исключение. Если вы не поймаете исключение, в большинстве случаев ваша программа потерпела крах.
В JavaScript не может сказать, используя функцию, если она бросит или нет. Java помогает, потому что инструмент предупреждает вас, что вы используете другую функцию. Еще никто не любит видеть nullexceptionpointer в Java Land. Не смешно.
Шаблон 4 – вернуть тип результата
Что если мы хотели оба вернуть сообщение об ошибке, если что-то пойдет не так, а также не вводить побочные эффекты.
Это Результат тип.
Эта вещь запекана в стандартную библиотеку новых языков программирования, таких как ржавчина и вяз. У нас есть std:: Результат в ржавении и Тип результата в эльме. Некоторые новые языки не реализуют исключения и лечить ошибки как данные Как Идти , Ржавчина и Elm Отказ
Поскольку эта статья использует TeampScript, я собираюсь использовать библиотеку нерешительный Но есть другие на выбор. Это также будет работать в простом JavaScript.
Давайте посмотрим на неворотую Результат тип.
От неворота Документы :
type Result= Ok | Err
Хорошо <т, е> : содержит значение успеха типа T
ERR : содержит значение отказа типа Свидетельствовать
И вот это в действии.
import { Result, ok, err } from 'neverthrow';
import DB from 'my-synchronous-database';
type DBError = string; // type alias for error message
function getUser(id : UserID) : Result {
const user = DB.getUserById(id);
if (user) {
return ok(user); // return instance of OK
} else {
return err(`Cannot find the user by id ${id}`); // return instance of Err
}
}
Это улучшение, потому что сейчас есть Нет побочных эффектов и мы можем вернуть сообщение об ошибке Если что-то пойдет не так. Я знаю, что когда я использую эту функцию, я всегда буду получать Результат Отказ
const userID = 1; const userResult : Result= getUser(userID); if (userResult.isOK()) { console.log(userResult.value); } else { console.log(userResult.error); }
Если вы попытаетесь получить USERRESULT.Value. Прежде чем вы проверили ISOK () Компилятор TS не позволит вам. Довольно круто.
JavaScript Tooling.
Цлинт неизменен Это плагин для ЦИЛИНТ, который имеет несколько вариантов для предотвращения бросков исключений. Смотрите этот набор функциональных правил программирования для ЦЛИНТ здесь Отказ Включить Без-бросок и Нет, попробуйте Отказ
И здесь это похожий набор правил для Eslint.
Другие библиотеки и языки
Эти идеи также рассматриваются на других языках. Вот некоторые библиотеки, которые я нашел.
C ++ std:: Дополнительно , Дополнительный , самый безопасный путь, чем просто возвращение null Отказ Необязательно может быть пустым или удерживать значение типа T . Он не содержит сообщение об ошибке. Этот тип также называется Может быть в эльма и в других местах.
Результат C ++ Либлиотека только заголовка, которая реализует ржавчину Результат тип. Этот тип может удерживать значение или ошибку.
Результат Python Еще один визуальный тип результата.
Если вы хотите исследовать больше напечатанного функционального программирования в TeampScript, проверьте очищать , Истинный миф или полнофункциональный FP-TS Отказ
Оригинал: “https://dev.to/pianomanfrazier/exceptions-considered-harmful-3065”