Baru-baru ini saya menulis sepotong kecil kode yang akan menunjukkan dengan cara yang ramah-manusiawi berapa umur suatu peristiwa. Misalnya, ini dapat mengindikasikan bahwa acara tersebut terjadi "Tiga minggu lalu" atau "Sebulan yang lalu" atau "Kemarin."
Persyaratannya relatif jelas dan ini adalah kasus yang sempurna untuk pengembangan yang digerakkan oleh tes. Saya menulis tes satu per satu, menerapkan kode untuk lulus setiap tes, dan semuanya tampak berfungsi dengan baik. Sampai bug muncul dalam produksi.
Inilah bagian kode yang relevan:
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.
Tes sedang memeriksa kasus dari suatu peristiwa yang terjadi hari ini, kemarin, empat hari yang lalu, dua minggu yang lalu, seminggu yang lalu, dll, dan kode dibangun sesuai.
Apa yang saya lewatkan adalah bahwa suatu peristiwa dapat terjadi sehari sebelum kemarin, sementara menjadi satu hari yang lalu: misalnya suatu peristiwa yang terjadi dua puluh enam jam yang lalu akan menjadi satu hari yang lalu, sementara tidak persis kemarin jika sekarang jam 1 pagi. Lebih tepatnya, itu satu poin sesuatu, tetapi karena delta
bilangan bulat, itu hanya satu. Dalam hal ini, aplikasi menampilkan "One days ago," yang jelas-jelas tidak terduga dan tidak ditangani dalam kode. Itu dapat diperbaiki dengan menambahkan:
if delta == 1:
return "A day ago"
setelah menghitung delta
.
Sementara satu-satunya konsekuensi negatif dari bug adalah saya menghabiskan setengah jam bertanya-tanya bagaimana kasus ini bisa terjadi (dan percaya bahwa itu ada hubungannya dengan zona waktu, meskipun penggunaan seragam UTC dalam kode), keberadaannya mengganggu saya. Ini menunjukkan bahwa:
- Sangat mudah untuk melakukan kesalahan logis bahkan dalam kode sumber yang sederhana.
- Pengembangan yang digerakkan oleh tes tidak membantu.
Yang juga mengkhawatirkan adalah saya tidak bisa melihat bagaimana bug seperti itu bisa dihindari. Selain berpikir lebih banyak sebelum menulis kode, satu-satunya cara yang dapat saya pikirkan adalah menambahkan banyak pernyataan untuk kasus-kasus yang saya yakini tidak akan pernah terjadi (seperti saya percaya bahwa sehari yang lalu adalah kemarin), dan kemudian mengulang setiap detik untuk sepuluh tahun terakhir, memeriksa setiap pelanggaran pernyataan, yang tampaknya terlalu rumit.
Bagaimana saya bisa menghindari membuat bug ini sejak awal?