• дата конвертации всегда текущая;• мы используем только 10 валют из 164.
Несложный комбинаторный подсчёт показывает, что даже такой сильно урезанный входной набор характеризуется количеством размещений из 10 по 2, помноженным на 100 миллионов входных значений (1 миллион с шагом 0,01):
102 × 100 000 000 = 10 000 000 000.
То есть для обеспечения полноты тестирования нашего входного набора потребуется 10 миллиардов проверок! Сравните, например, с микросхемой дешифратора, преобразующего входное 4-разрядное двоичное значение в сигнал на одном из 16 выходов. Входных наборов будет всего 16, а таблица истинности состоит из 162 = 256 значений.
На практике программист применит допустимую эвристику и будет тестировать, например, только несколько значений (один миллион, ноль, случайная величина из диапазона) для нескольких типовых конвертаций из 100 возможных, дополнительно проверяя допустимую точность значений на входе. При этом формальный показатель покрытия модульными тестами по-прежнему будет 100 %…
Но это ещё не всё. Микросхема работает с заданной тактовой частотой. Если, например, частота равна 1 МГц, то подав на вход набор значений, вы гарантированно через одну микросекунду получите результат на выходе.
Если же вы подадите набор значений на вход нашего компонента, то время отклика будет неопределённым. Может быть, программа отработает за секунду.
Может быть, зависнет навечно, если не предусмотрен тайм-аут. А если несколько параллельных запросов?
Поэтому вдобавок к модульному тесту необходимо программировать тест производительности (нагрузочный), который тем не менее не гарантируетвремя отклика, а только позволяет определить его ожидаемое значениепри некоторых условиях.
Таким образом, собрав из кучи микросхем устройство, мы уверены, что оно будет работать:
• согласно таблицам истинности;• с заданной тактовой частотой.
Собрав же из компонентов программу, мы можем только:
• приблизительно и с некоторой вероятностью оценивать время отклика на выходе;• в большинстве случаев ограничиться выборочным тестированием, забыв о полноте.
Если вам говорят: «Пришло время собранных из кубиков программ», будьте в курсе ограничений технологии. Очень уж далеки программные компоненты от электронных кубиков.
Безысходное программирование
Любая программа, даже созданная визуально, имеет в своей основе исходный код на каком-либо языке программирования.
Безысходное программирование – это программирование без «исходников». То есть мы пишем свой код, не имея исходных текстов используемой подпрограммы, класса, компонента и т. п.
Когда необходимо обеспечить гарантированную работу приложения, включающего в себя сторонние библиотеки или компоненты, то, не имея доступа к их исходному коду, вы остаётесь один на один с «чёрным ящиком». Даже покрыв их тестами, близкими к параноидальным, вы не сможете понять всю внутреннюю логику работы и предусмотреть адекватную реакцию системы на нестандартные ситуации. Поэтому программирование без исходников в таком сценарии превращается в настоящую безысходность и безнадёгу.
Пока цена ошибки в приложении – потеря нескольких строк введённой пользователем информации, дело может ограничиться долгоживущей записью в базе данных ошибок, закрываемой не её исправлением, а описанием обхода «граблей» [19] . Но ситуация кардинально поменяется, если цена будет исчисляться многими нулями потерь от упущенной сделки в торговой системе, сотнями исков клиентов, получивших неверные счета, или того хуже – аварией на производстве. Ответственность с разработчиков никто не снимал.
В рамках аудита нередко приходилось наблюдать, как правят программный код триггеров и хранимых процедур прямо в базе данных. Ассоциация с этим непотребством у меня тесно связана с утилитой debug, которая в MS DOS позволяла писать машинные команды прямо в память. Или с командой type > program.com для набора машинного кода с консоли в исполняемый файл. Понятное дело, что занимаются такими вещами при разработке программного обеспечения только от безысходности.
Частным, но частым случаем безысходного программирования является софтостроение без использования системы управления исходным кодом ( revision control system), позволяющей архивировать и отслеживать все его изменения.
Эволюция аппаратуры и скорость разработки
В 1980-х годах у японцев существовала программа по созданию ЭВМ 5-го поколения. К сожалению, цель достигнута не была, хотя проявилось множество побочных эффектов вроде всплеска интереса к искусственному интеллекту, популяризации языка Пролог, да и отрицательный опыт – тоже опыт, возможно, не менее ценный.