Противоинтуитивный подход к созданию надежного программного обеспечения

Ваш беспилотный автомобиль обнаруживает неисправные датчики в процессе запуска. Что бы вы предпочли, чтобы случилось потом?

  1. Машина едет со сломанными датчиками, посмотрим, как далеко она уедет.
  2. Автомобиль отказывается двигаться и сообщает о сломанных датчиках.

Если вы не являетесь бесстрашным адреналиновым наркоманом, я думаю, вы выбрали второй вариант. Мы могли бы назвать этот вариант безотказным. Ничего страшного не происходит, потому что машина в кратчайшие сроки прекращает нормальную работу.

Подобную концепцию можно применить при разработке программного обеспечения, о чем и идет речь в данной статье. В этой статье описывается принцип отказоустойчивости, его преимущества, способы его применения и мой личный опыт.

Похоже на ужасную идею

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

  • Запасные варианты
  • Попытки в более позднее время
  • Изящная деградация

Программы, использующие эти методы, будут продолжать работать после возникновения ошибки, но в дальнейшем рискуют неожиданно выйти из строя. Они приводят к медленным или тихим сбоям¹.

Тихо потерпеть неудачу - все равно что зарыться головой в песок. Это не решает основную проблему, а только делает вид, что проблемы нет. - Владимир Хориков

Не прячьте голову в песок, вместо этого работайте как можно быстрее! Программное обеспечение, работающее с быстрым отказом, дает сбой при первой же возможности и настолько заметным, насколько это возможно². Это звучит ужасно, но это не так.

Безаварийный беспилотный автомобиль

Предположим, наша беспилотная машина из введения пытается двигаться сама, несмотря на сломанные датчики. Он без проблем выезжает со стоянки, но как только мы выезжаем на открытую дорогу, случается катастрофа. Сломанные камеры приводят к аварии автомобиля. Машина - полная потеря, и нам повезло, что никто не пострадал.

Учитывая текущее состояние автомобиля, определение причины аварии - трудоемкий процесс. Неисправные датчики специалисты обнаруживают только после долгого и дорогостоящего расследования.

Безотказные автомобили не допускают подобных аварий. Датчики не отремонтируют сами себя, но устранить неполадки легко, потому что автомобиль покажет вам проблему.

Возможно, это надуманный пример. Однако аналогичная концепция применима к отказоустойчивому программному обеспечению. Медленное программное обеспечение также может неожиданно дать сбой, потому что незначительные проблемы остаются незамеченными, что делает отладку сложным и дорогостоящим процессом.

Преимущества быстрой неудачи

Ошибки и сбои быстрее обнаруживаются в отказоустойчивом программном обеспечении, что упрощает их воспроизведение и исправление³. Это делает разработку программного обеспечения намного более приятной.

Я ненавижу ошибки, которые появляются только после нескольких часов успешной работы, при необычных обстоятельствах или чьи трассировки стека ведут в тупик. - Джим Шор

Экономия затрат

Меньше ошибок и сбоев попадает в производственную среду, потому что они обнаруживаются раньше¹. Согласно IBM, раннее обнаружение ошибок приводит к огромной экономии средств, поскольку стоимость исправления ошибки может быть до пяти раз выше, как только она попадет в производственную среду⁴.

Защита от повреждения данных

Принцип отказоустойчивости предотвращает переход программного обеспечения в недопустимое состояние, поэтому становится невозможным сохранять недопустимые состояния в базе данных⁵. Это огромное преимущество, так как повреждение данных может быть трудно исправить.

Нет серебряной пули

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

Хотя быстрый отказ имеет много преимуществ, использование принципов замедления при отказе, таких как постепенная деградация, также имеет свое время и место.

Принцип на практике

Мы видели, как быстро потерпеть неудачу - это не ужасная идея, так как же нам ее применить?

Хотя принцип отказоустойчивости не зависит от языка, я разработчик Java, поэтому в этом разделе используются примеры кода Java.

Утверждения

Мы не должны проигрывать, пока что-то не пойдет не так. Чтобы определить, что что-то пойдет не так, мы используем утверждения.

Утверждения - это фундаментальные строительные блоки отказоустойчивых приложений. Утверждения - это простые фрагменты кода для проверки условий; если проверка не удалась, они вызывают исключение.

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

Хорошие библиотеки утверждений позволяют передавать сообщение об ошибке, которое будет отображаться как часть исключения. Это сообщение играет жизненно важную роль, поскольку позволяет сообщить, что не так, что упрощает устранение проблемы.

Размещение тактического утверждения

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

Разместите свои утверждения так, чтобы программное обеспечение отказывалось раньше - близко к исходной проблеме - чтобы облегчить поиск проблемы. - Джим Шор

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

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

Нет необходимости самоуничтожаться

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

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

Личный опыт

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

Одна служба, над которой я работал, получает информацию о сотрудниках через брокера сообщений. Эта служба преобразует информацию о сотрудниках в Employee объекты и сохраняет эти объекты в базе данных.

Мы используем безотказные утверждения во время создания экземпляров Employee объектов. Если утверждение терпит неудачу, ничего не сохраняется. Мы пишем сообщение в очередь ошибок, указав исходную информацию о сотруднике и причину его перемещения в очередь ошибок. Система оповещения отправляет уведомление, если в очереди ошибок есть сообщения.

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

Заключение

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

Если эта статья вдохновила вас на применение принципа отказоустойчивости в своей кодовой базе, вы можете сразу начать использовать его. Положительные эффекты будут заметны, даже если вы примените принцип к одному файлу.

Спасибо за чтение. Я надеюсь, что это было полезно. Не стесняйтесь оставлять ответ, если у вас есть вопросы или отзывы.

использованная литература

[1] Шор, Дж., 2014. Fail Fast. [онлайн] Martinfowler.com. Доступно по адресу: https://www.martinfowler.com/ieeeSoftware/failFast.pdf

[2] Берт Ф, 2010. Что означает выражение Ранний отказ и когда вы хотите это сделать?. [онлайн] Stackoverflow.com. Доступно по адресу: https://stackoverflow.com/questions/2807241/what-does-the-expression-fail-early-mean-and-when-would-you-want-to-do-so

[3] Хаонг, Д., 2018. Принцип отказоустойчивости в разработке программного обеспечения. [онлайн] Dzone.com. Доступно по адресу: https://dzone.com/articles/fail-fast-principle-in-software-development

[4] Сони М., год неизвестен. Предотвращение дефектов: снижение затрат и повышение качества. [онлайн] Isixsigma.com. Доступно по адресу: https://www.isixsigma.com/industries/software-it/defect-prevention-reeding-costs-and-enhancing-quality/

[5] Хориков В., 2015. Принцип Fail Fast. [онлайн] enterprisecraftsmanship.com. Доступно по адресу: https://enterprisecraftsmanship.com/posts/fail-fast-principle/