Важно: это часть моего бесплатного образовательного эксперимента Python Times: я пробую объяснять программирование через истории. Если художественный формат вам не близок — предупреждаю заранее, дальше будет именно он.
Редакция Python Times, 09:47
Дверь с грохотом распахнулась — Элиф влетела в редакцию как ураган, сумка нараспашку. Из неё торчал дождевик, скомканный шарф и бумажный пакет, от которого сразу запахло корицей и ванилью.
— Вы ВИДЕЛИ это?! — она на ходу выудила из пакета два круассана, один плюхнула на стол прямо перед Тимом, а второй прижала к груди. — NASA угробило Mars Climate Orbiter! Триста двадцать семь миллионов долларов просто СГОРЕЛИ в атмосфере Марса!
Тим, стажёр, который недавно устроился в редакцию, оторвался от блокнота и уставился на круассан.
— Это мне?
— Ну да, я же… там было два, в общем. — Элиф махнула рукой и отвернулась, сбрасывая сумку на пол. — Не важно сейчас! Слышал про зонд-то?
Зен, умное ИИ-устройство на стене, негромко загудел, а его индикатор мигнул жёлтым.
— Доброе утро, Элиф. Опоздание — девятнадцать минут. Третий раз за неделю.
— Да какая разница! — Элиф плюхнулась на стул рядом с Тимом и развернулась к нему. — Тим, ну представь себе: сотни инженеров, годы работы — и всё насмарку!
Тим осторожно отломил кусочек круассана.
— Ну… космос — дело тонкое. Может, метеорит попал? Или датчик отказал?
— Одна строчка, — Элиф придвинулась ближе, накручивая прядь волос на палец. — Понимаешь? ОДНА. Точнее, даже не строчка, а то, что её не было вовсе.
Трейси медленно перевернула страницу в потрёпанном блокноте, не поднимая глаз.
— Сначала факты, — произнесла она. — Триста двадцать семь миллионов — это вся программа Mars Surveyor '98: орбитер, посадочный модуль Mars Polar Lander, два запуска и операции. Сам сгоревший аппарат стоил около ста двадцати пяти миллионов. Впрочем, лендер через два с половиной месяца тоже разбился, так что списывай всю сумму, не ошибёшься.
— Ты умеешь утешить, — фыркнула Элиф.
— И не строчка, а единицы измерения, — продолжила Трейси. — Наземный софт от Lockheed Martin выдавал данные об импульсах двигателей в фунт-сила-секундах. Навигационная команда JPL читала эти же числа как ньютон-секунды. Девять с половиной месяцев полёта — и каждая коррекция траектории чуть-чуть врала.
— Стоп, — Тим нахмурился. — Ну перепутали единицы. Разве это такая проблема?
Элиф всплеснула руками.
— ТАКАЯ?! Да это же трагедия космического масштаба! Буквально! Корабль летел девять месяцев, и в самый последний момент…
— Элиф, — спокойно оборвала Трейси, разворачивая ноутбук. — Факты лучше драмы.
На экране появился код:
# Команда А (наземное ПО, расчёт импульса) impulse = 100 # фунт-секунды... но это нигде не написано # Команда Б (навигация) correction = impulse * k # думает, что это ньютон-секунды!
Тим вгляделся в экран.
— Но ведь сто — это просто число. Что тут может пойти не так?
Зен ответил:
— Один фунт-сила равен 4.45 ньютона. Каждая коррекция траектории врала примерно в четыре с половиной раза.
— Вот видишь! — Элиф ткнула пальцем в воздух. — Это как если ты думаешь, что едешь шестьдесят километров в час, а реально летишь под двести семьдесят!
— Аппарат должен был пройти в двухстах двадцати шести километрах от поверхности, — добавила Трейси без эмоций. — Прошёл в пятидесяти семи. Расследование NASA заключило, что он, вероятнее всего, разрушился в атмосфере — напрямую этого уже никто не видел, связь пропала раньше.
Повисла пауза. Тим постучал ручкой по блокноту.
— Значит, хватило бы одного комментария в коде?
Трейси кивнула и набрала:
impulse = 100 # pound-force-seconds, НЕ newton-seconds!
— Или хотя бы проверки:
if unit != "newton_seconds": impulse = convert_to_newton_seconds(impulse)
— Сто двадцать пять миллионов долларов, — тихо повторил Тим, и в его голосе прозвучало что-то между ужасом и благоговением.
— И потерянный ретранслятор для посадочного модуля, который летел следом, — сухо добавила Трейси. — Так что косвенно — сильно больше.
Дверь снова распахнулась. На пороге возник Флэш с двумя дымящимися стаканами кофе и болтающейся камерой на груди.
— О, вы про марсианский облом? — он поставил стаканы на край стола, а сам уселся рядом, свесив ноги. — Классика! А хотите историю попроще и повеселее?
Не дожидаясь ответа, он подскочил к доске, схватил маркер, начал подбрасывать его и ловить.
— YouTube, декабрь две тысячи четырнадцатого. Gangnam Style.
Поймал маркер и размашисто вывел: 2_147_483_647
— Узнаёте цифру?
Тим покачал головой.
— Максимум для тридцатидвухбитного знакового целого! — Флэш щёлкнул пальцами. — YouTube хранил счётчик просмотров именно так. Инженеры думали — ну два миллиарда, этого ж хватит до скончания веков!
Элиф фыркнула.
— А потом появился PSY с лошадкой.
— Ага! — Флэш дописал:
2_147_483_647 + 1 = ???
Тим почесал переносицу.
— Ну… два миллиарда сто сорок семь миллионов четыреста восемьдесят три тысячи шестьсот сорок восемь?
— В Python — да, — Трейси перелистнула страницу. — Но не в большинстве других языков.
Зен добавил:
— В языках с фиксированными типами переполнение знакового целого превращает число в отрицательное. Максимум плюс один становится -2_147_483_648.
— Погоди, — Тим выпрямился. — То есть если бы видео перевалило за предел, YouTube показывал бы…
— Минус два миллиарда! — Элиф рассмеялась, откидываясь на спинку стула и случайно задев локтем Тима. — Самое популярное видео в мире вдруг стало бы самым непопулярным!
Флэш развернулся к доске и быстро нарисовал карикатуру — человечка с вытаращенными глазами:

Трейси закатила глаза, и в уголке губ мелькнула едва заметная улыбка.
— Только вот минуса на экране никто не увидел. Это, Флэш, любимый миф интернета — «Gangnam Style сломал YouTube». На самом деле инженеры заметили проблему за месяцы и тихо перевели счётчик на шестьдесят четыре бита заранее. А первого декабря просто пошутили об этом в Google+: мол, мы не думали, что видео можно посмотреть больше двух миллиардов раз, пока не встретили PSY. У видео тогда было около двух и полутора десятых миллиарда просмотров.
— То есть никакой паники? — разочарованно протянул Флэш.
— Никакой паники. Зато Книга рекордов Гиннесса выдала PSY титул: первое видео, которому понадобился шестидесятичетырёхбитный счётчик. Верхний предел теперь — девять квинтиллионов. Чтобы столько набрать, каждый человек на планете должен посмотреть видео больше миллиарда раз.
Она развернула ноутбук к Тиму:
views = 2_147_483_647 views = views + 1 print(views) # 2147483648 - в Python работает
— Тогда в чём загвоздка? — спросил Тим. — Если в Python всё нормально?
— Загвоздка, — Трейси набрала новый код, — в том, что Python общается с внешним миром. Базы данных, API, библиотеки на C: там типы жёсткие, фиксированные.
import numpy as np views = np.int32(2_147_483_647) views = views + 1 print(views) # -2147483648 - переполнение!
Тим кивнул, будто что-то улеглось в голове.
— Значит, надо сразу закладывать запас. Использовать типы с большим диапазоном.
— Бинго! — Флэш подбросил маркер и не поймал — тот покатился по полу. — И заметь: YouTube выкрутился красиво именно потому, что заметил проблему ДО того, как она случилась. Если бы ждали минуса на экране — вот тогда была бы паника. Элиф полезла в сумку, вытащила телефон и что-то там полистала.
— Раз уж про большие числа… — она придвинула стул ближе к Тиму, развернула телефон к нему. — Две тысячи тринадцатый, PayPal. Парень по имени Крис Рейнольдс открывает почту с ежемесячной выпиской и видит баланс…
На экране:
$92_233_720_368_547_800
— Девяносто два квадриллиона долларов, — выдохнула Элиф, и глаза её блеснули. — Мировой ВВП тогда был около семидесяти пяти триллионов. У Криса на счету лежало больше тысячи мировых экономик!

Тим уставился на цифры и расхохотался.
— Не может быть. Это же розыгрыш!
— Чистая правда, — подтвердил Зен. — Правда, когда Рейнольдс зашёл в аккаунт онлайн, баланс уже показывал ноль. Ошибка прожила ровно одну выписку. PayPal извинился и предложил пожертвовать деньги на благотворительность по его выбору. Технических деталей компания так и не раскрыла.
— Но есть рабочая гипотеза, — Трейси постучала пальцами по столу. — Подчёркиваю: гипотеза, а не подтверждённый факт. Смотри на число внимательно.
Она записала в блокноте:
Максимум int64: 9_223_372_036_854_775_807 Баланс Криса: 92_233_720_368_547_800
— Улавливаешь паттерн? — она подняла глаза. — Девяносто два, двадцать три, тридцать семь… Это максимум int64, поделённый примерно на сто, с округлением.
Тим сдвинул брови.
— А зачем на сто делить?
— Деньги хранят в центах, — объяснила Трейси, и в её голосе промелькнуло лёгкое раздражение. — Чтобы не мучиться с дробями. Сто долларов в базе — это десять тысяч центов. Максимум int64 в центах — это как раз девяносто два квадриллиона долларов на экране.
— В интернете гуляет версия, что где-то стояло магическое число, — добавила Элиф. — Минус один вместо «счёт не найден».
balance = None # счёт не найден if balance is None: balance = -1 # "магическое" значение вместо данных
— Ну и что? — Тим пожал плечами. — Минус один как минус один.
— И вот тут популярная версия хромает, — Трейси развернула ноутбук. — Минус один, приведённый к БЕЗЗНАКОВОМУ шестидесятичетырёхбитному типу, дал бы два в шестьдесят четвёртой минус один цент. Это сто восемьдесят четыре квадриллиона, а не девяносто два. А у Криса — ровно максимум ЗНАКОВОГО int64. Значит, где-то в системе что-то записало в баланс предельное значение типа. Как именно — знает только PayPal, а PayPal молчит. Поэтому число выдаёт тип данных с головой, механизм — нет.
— Постой-ка, — Тим поднял руку. — А зачем вообще использовать минус один для «нет данных»? Есть же None!
Трейси посмотрела на него и впервые за утро улыбнулась по-настоящему.
— Вот именно.
Набрала:
balance = None # данных нет balance = 0 # данные есть, баланс нулевой
— Чувствуешь? Оба похожи на «пусто». Но смысл разный в корне.
Тим почесал затылок.
— А разве? Если проверить через if…
balance = None if balance: print("Есть деньги") else: print("Нет денег") # выведет это balance = 0 if balance: print("Есть деньги") else: print("Нет денег") # и это тоже!
— Результат одинаковый.
— Ответ один, — Трейси отпила из большого термоса, — а причины разные. None значит «мы не знаем, есть ли деньги». Ноль значит «мы точно знаем: денег ноль».
Элиф встала, подошла к окну. Молча постояла, накручивая прядь волос на палец. За стеклом моросил дождь.
Обернулась. Её голос стал тише и серьёзнее.
— Март две тысячи девятого. Лондон, конференция QCon. На сцену выходит сэр Тони Хоар — живая легенда Computer Science. Изобретатель быстрой сортировки.
Пауза. Элиф посмотрела прямо на Тима.
— И изобретатель null.
Зен процитировал:
Я называю это своей ошибкой на миллиард долларов. Это было изобретение нулевой ссылки в 1965 году. Я проектировал первую всеобъемлющую систему типов для ссылок в ALGOL W и не смог устоять перед искушением добавить null просто потому, что это было так легко реализовать. Это привело к бесчисленным ошибкам, уязвимостям и сбоям систем, которые, вероятно, причинили ущерба на миллиард долларов за последние сорок лет.
Тим замер.
— Он сожалел, что придумал None?
— Он сожалел, — Трейси захлопнула блокнот, — что создал концепцию "отсутствие значения", которую слишком просто перепутать с "пустым значением". Он умер этой весной, в марте. Ему было девяносто два. И половина современных языков — Rust с его Option, Kotlin с nullable-типами — это, по сути, ответ на ту его лекцию.
Элиф медленно вернулась к столу. Остановилась за спиной Тима, и он почувствовал лёгкий запах её духов.
— Тим, — она положила руку ему на плечо, и её пальцы чуть сжались на ткани толстовки. — Вся история программирования — это история доверия.
Смахнула крошку круассана с его плеча.
— Мы пишем код. Код работает с данными. Мы доверяем, что данные говорят правду. Что сто — это действительно сто, а не сто фунт-сила-секунд. Что None означает "нет данных", а не "возьми максимум". Что счётчик не переполнится.
Помолчала. Её рука всё ещё лежала на его плече.
— Но данные контекста не знают. Не знают, что ты имел в виду. Они знают только то, что написано чёрным по белому. — Голос стал тише. — И если написано недостаточно…
Рука скользнула с плеча. Элиф отступила.
— Материалы главному редактору через десять минут, — сказала Трейси, закрывая ноутбук. — Элиф, у тебя же интервью?
Элиф встрепенулась, будто очнулась.
— Да. Крис Рейнольдс. — Она глянула на часы, поморщилась. — Чёрт, такси через пять минут.
Схватила сумку, полезла внутрь и вытащила дождевик.
— Тот самый? С квадриллионами? — Флэш поднял брови. — Он согласился на интервью?
— Эксклюзив, — кивнула Элиф, натягивая дождевик. — Для серии "Дорогие ошибки". Окно всего два часа.
— Ладно, побежали, — Флэш сунул маркер в карман. — Я с тобой, мне фото нужны.
Развернулась и почти выбежала в коридор.
— Эй, погоди же! — голос Флэша удалялся.
Тишина упала на редакцию как одеяло.
— Зен, — позвал Тим тихо, не отрывая взгляда от двери.
— Слушаю.
— Что ещё можно потерять? Кроме денег?
Зен немного подумал и ответил:
— Время, которое не вернуть. Доверие, которое не восстановить. — Долгая пауза. — Людей, которые могли бы вернуться, но не вернулись.
Трейси перевернула страницу блокнота. Голос стал тише, жёстче.
— Therac-25. Аппарат лучевой терапии, восьмидесятые. С восемьдесят пятого по восемьдесят седьмой — шесть случаев радиационной передозировки, некоторые дозы превышали терапевтические в сотни раз. Три смерти связывают с облучением — точную цифру называют по-разному, у части пациентов рак и радиация убивали наперегонки.
— Из-за кода?
— Из-за состояния гонки: если опытный оператор вводил данные быстро и исправлял режим на лету, аппарат стрелял полным пучком без защиты. Во втором баге — переполнение счётчика: команда, отправленная в момент, когда однобайтовый счётчик обнулялся, пропускала проверку. А главное — из-за того, что аппаратные блокировки, которые в старых моделях физически не давали такому случиться, убрали. Понадеялись на софт.
— Люди умерли… из-за доверия?
— Из-за того, — Трейси резко захлопнула блокнот, — что кто-то доверился. Не проверил. Решил, что "и так сойдёт".
За окном дождь усилился, капли всё быстрее колотили по стеклу…
P.S. От автора.
Честно признаюсь: все технические истории в этом уроке — реальные. И раз уж урок про доверие к данным, вот пруфы:
Mars Climate Orbiter действительно погиб 23 сентября 1999 года из-за путаницы фунт-секунд и ньютон-секунд в наземном ПО. Знаменитые $327 млн — это стоимость всей программы, орбитера и посадочного модуля вместе; сам аппарат оценивают примерно в $125 миллионов. Источник: пресс-релиз JPL от 30.09.1999
Gangnam Style действительно упёрся в int32 в декабре 2014-го. Знаменитый пост Google в блоге — это просто легенда. Реальный первоисточник — пост в Google+ от 1 декабря 2014, который умер вместе с Google+. Источник: архив поста Google+
PayPal действительно показал Крису Рейнольдсу $92 квадриллиона — в июльской email-выписке 2013 года. Онлайн-баланс уже был нулевым, а компания предложила пожертвование на выбранную им благотворительность. Гипотеза про int64 и "-1 в беззнаковом типе" — правдоподобная реконструкция сообщества, официально причина не раскрыта. Источник: Fox13seattle
Тони Хоар действительно назвал null своей "ошибкой на миллиард долларов" — на QCon London в марте 2009 (запись опубликована InfoQ в августе). Печальное примечание 2026 года: сэр Тони Хоар ушёл из жизни 5 марта 2026 года. В сцене выше — 2009 год, и тогда "живая легенда" было буквальной правдой. Источник: InfoQ
Therac-25 — это не художественный вымысел. Минимум шесть передозировок в 1985–1987 годах, дозы до 250 раз выше нормы, смерти и тяжёлые увечья. Число погибших в источниках разнится от двух до четырёх. Каноничный разбор — исследование Нэнси Левесон и Кларка Тёрнера (IEEE Computer, 1993). Источники: полный текст статьи Левесон (PDF)
Но.
Элиф, Тим, Трейси, Флэш и Зен — художественные персонажи. Их разговоры, взаимоотношения, личные истории — сторителлинг и инструмент для обучения.
Почему я учу Python через истории персонажей?
Лет пятнадцать назад я открыл очередной учебник по программированию, дошёл до двадцатой страницы и захлопнул. Не потому что было сложно. А потому что стало невыносимо скучно. Переменные a и b. Задачи про яблоки, которые никто в жизни не считает. Код ради кода.
Я задал себе вопрос: а что если каждая техническая концепция появляется не абстрактно, а когда без неё настоящую проблему не решить? Что если каждая строчка кода — ответ на реальный вопрос?
Так родилась редакция Python Times.
Это не "роман с уроками Python". Это курс программирования через призму человеческих историй, потому что наш мозг запоминает не абстракции, а эмоции и контекст.
Вы не будете складывать безымянные числа. Вы узнаете, например, почему Netflix случайно "состарил" подростков до 127 лет и другие странные случаи.
Персонажи меняются от урока к уроку. Влюбляются. Ошибаются. Исчезают и возвращаются.
Курс абсолютно бесплатный. Подходит и новичкам с нуля и опытным разработчикам, которым надоели сухие туториалы.
Если зацепило — Python Times: интерактивный курс-детектив для начинающих
P.P.S. Дойдёте до финала — узнаете, что на самом деле между Тимом и Элиф. Но это уже совсем другая история.