Должен ли кто-нибудь оставить утверждения в продуктах iOS для производства?

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

Я тестирую свои приложения, НО, учитывая, что я не Кнут (и он записывает проверки на сумму 1 доллар США), и я не могу позволить себе использовать большую команду людей с полной занятостью, некоторые медицинские компании и компании, занимающиеся программным обеспечением космических систем, я полагаю, что во всех приложениях всегда будет много ошибок, которые еще никогда не наблюдались во время тестирования или QA. Предполагая иное, кажется совершенно интеллектуально нечестным. Итак, после тестирования приложения (и, очевидно, удаления всех ошибок, вызвавших ранее обнаруженные сбои ASSERT) и получения приложения для отправки в Apple, что делать со всеми проверками ASSERT в сборке Release/Distribution? Оставить или не работать?

Вот одно обоснование для их оставления: если приложение действует для некоторых пользователей, приложение может оцениваться этими пользователями как 1-Star, и никто не расскажет разработчику о том, почему он достаточно подробно. Но если приложение потерпит неудачу в результате сбоя ASSERT, приложение может по-прежнему получать рейтинг 1-Star, но разработчик может потенциально получить некоторые аварийные дампы, косвенно через iTunes и iTunes Connect, если достаточно пользователей, чтобы понять, что происходит не так. И если приложение будет отклонено Apple из-за нового сбоя ASSERT, это предотвратит появление плохой версии приложения на одном клиентском устройстве.

Ответ 1

Оставьте их именно по указанным вами причинам, но также потому, что в некоторых случаях они действуют как комментарии (особенно, если типы относятся к Objective-C). И не беспокойтесь о производительности, если это не проблема, или вы знаете, что находитесь в критичной для производительности ситуации, и конкретный аргумент будет запускаться сотни или тысячи раз в главном цикле выполнения.

Нельзя удержаться от упоминания этой статьи о утверждениях против NSAssert.

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

Примечание.. Еще один момент заключается в том, что просто удаление утверждений является абсолютно глупым, поскольку ваше приложение будет либо аварийно, либо находиться в несогласованном состоянии, оба из которых хуже, чем сбой, узнайте из журналов сбоев (так что оставьте утверждения). С другой стороны, замена утверждений операторами if может быть хорошей.

Ответ 2

Моя рекомендация: вы должны оставить их включенными по умолчанию. Я говорю: "терпеть неудачу, неудачно рано" - и сохраняйте свои исправления с более высоким приоритетом, чем функции.

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

К сожалению, это не может быть запоздалой мыслью (если, возможно, вы не готовы определить качество и тестирование на неограниченное время). Если вы подумаете об этом, то единственный/традиционный подход также не может быть запоздалой мыслью. С любой моделью лучше всего решить, будут ли утверждения или какие утверждения будут включены в выпуске до написания вашей программы.


Итак, основной общий вид модели с двойным утверждением может выглядеть так:

#include <assert.h>

/*
  MONDebugAssert assertion is active in debug and disabled in release.
  Recommendation: Always define NDEBUG (or not) in your build settings, 
  and nowhere else.
*/
#if defined(NDEBUG)
    #define MONDebugAssert(e) ((void)0)
#else
    #define MONDebugAssert(e) \
        (__builtin_expect(!(e), 0) ? __assert(#e, __FILE__, __LINE__) : (void)0)
#endif

/* MONAssert assertion is active at all times, including release builds. */
#define MONAssert(e) \
       (__builtin_expect(!(e), 0) ? __assert(#e, __FILE__, __LINE__) : (void)0)

где __assert - обработчик утверждения платформы.

Затем используется:

MONDebugAssert(0); // << will fail in debug, and not in release.
MONAssert(0); // << will fail in any case

Конечно, достаточно легко адаптироваться для ваших нужд или создать варианты, в которых self предполагается находиться в области (например, NSAssert).

Ответ 3

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

Хорошее время для утверждения: при продолжении уничтожает пользовательские данные ( "есть уже известный хороший файл сохранения, и я обнаружил поврежденные структуры данных, если я напишу над хорошим файлом с тем, что у меня есть уничтожьте это" ). Очевидно, что "лучший" вариант - не повредить данные в первую очередь. Во-вторых, обнаруживать поврежденные данные во время сохранения и сохранения в новый файл (это может быть загружаемо или, может быть, то, что в нем, достаточно ценно для спасения с помощью героических средств).

Еще одно подходящее время, чтобы утверждать: когда вы знаете, что продолжение продолжается, произойдет сбой (передача NULL ко многим простым функциям C, собирающимся делить на ноль...). Утверждение будет содержать более полезную информацию. Сверху еще лучше не попасть в это состояние. Во-вторых, прервать операцию, а не программу ( "Я не могу напечатать", лучше, чем "Я выбросил ваши несохраненные данные и, кстати, вы не можете распечатать" ).

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

... так что это компромисс. Что еще в вашей программе будет лучше, если вы избавитесь от восстановления ошибок? Будет ли еще лучше компенсировать дополнительные сбои?

Ответ 4

Мои ошибки NSAssert указывают, что что-то пошло не так, и дальнейшее продолжение приведет к поведению undefined и повреждению данных. Я не могу себе представить, почему люди-попугаи отключают их в сборках релизов.

Если вы можете восстановить его, вы должны использовать NSError.