Нещодавно я писав невеликий фрагмент коду, який по-людськи вказував би, наскільки давна подія. Наприклад, це може означати, що подія сталася "Три тижні тому" або "Місяць тому" або "Вчора".
Вимоги були відносно чіткими, і це був ідеальний випадок для тестових розробок. Я писав тести по черзі, впроваджуючи код, щоб пройти кожен тест, і все начебто працювало чудово. Поки у виробництві не з’явився клоп.
Ось відповідний фрагмент коду:
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 у коді), його присутність мене непокоїть. Це вказує, що:
- Зробити логічну помилку дуже просто навіть у такому простому вихідному коді.
- Тестова розробка не допомогла.
Також хвилює те, що я не бачу, як можна було б уникнути таких помилок. Окрім того, щоб подумати більше перед тим, як писати код, єдиний спосіб, який я можу придумати, - це додати багато тверджень для тих випадків, які, на мою думку, ніколи не відбудуться (як я вважав, що день тому обов'язково вчора), а потім переглядати кожну секунду протягом останні десять років, перевіряючи наявність будь-яких порушень тверджень, які здаються занадто складними.
Як я міг у першу чергу уникнути створення цієї помилки?