Недавно я писал небольшой кусочек кода, который по-человечески укажет, сколько лет событию. Например, это может указывать на то, что событие произошло «Три недели назад», «Месяц назад» или «Вчера».
Требования были относительно ясны, и это был идеальный случай для разработки, основанной на тестировании. Я писал тесты один за другим, реализуя код для прохождения каждого теста, и все, казалось, работало идеально. Пока ошибка не появилась в производстве.
Вот соответствующий кусок кода:
now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
return "Today"
yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
return "Yesterday"
delta = (now - event_date).days
if delta < 7:
return _number_to_text(delta) + " days ago"
if delta < 30:
weeks = math.floor(delta / 7)
if weeks == 1:
return "A week ago"
return _number_to_text(weeks) + " weeks ago"
if delta < 365:
... # Handle months and years in similar manner.
Тесты проверяли случай события, происходящего сегодня, вчера, четыре дня назад, две недели назад, неделю назад и т. Д., И код был построен соответствующим образом.
Что я пропустил, так это то, что событие может произойти позавчера, когда оно произошло один день назад: например, событие, которое произошло двадцать шесть часов назад, было бы один день назад, а не совсем вчера, если сейчас 1 час ночи. Точнее, это одно очко что-то, но так как delta
это целое число, оно будет только один. В этом случае приложение отображает «Один день назад», что является неожиданным и необработанным в коде. Это можно исправить, добавив:
if delta == 1:
return "A day ago"
только после вычисления delta
.
Хотя единственным негативным последствием этой ошибки является то, что я потратил полчаса, размышляя о том, как может произойти этот случай (и полагая, что это связано с часовыми поясами, несмотря на равномерное использование UTC в коде), его присутствие беспокоит меня. Это указывает на то, что:
- Совершенно легко совершить логическую ошибку даже в таком простом исходном коде.
- Разработка через тестирование не помогла.
Также беспокоит то, что я не вижу, как можно избежать таких ошибок. Помимо размышлений перед написанием кода, единственный способ, которым я могу придумать, - это добавить множество утверждений для случаев, которые, как я считаю, никогда не произойдут (как я полагал, что день назад обязательно является вчерашним днем), а затем просматривать каждую секунду для последние десять лет проверяют наличие каких-либо нарушений утверждений, что кажется слишком сложным.
Как я мог избежать создания этой ошибки в первую очередь?