Kiamat Pengkodean: Ketika UTF-8 Bukan UTF-8
Bencana data terburuk yang pernah saya saksikan terjadi di sebuah jaringan ritel multinasional pada tahun 2017. Mereka mengkonsolidasikan data pelanggan dari 47 database regional di 12 negara ke dalam satu gudang data. Cukup sederhana, bukan? Ekspor ke CSV, impor ke gudang, jalankan beberapa logika penghapusan duplikat, dan selesai. Kecuali CSV dari divisi Prancis terus merusak nama. "François" menjadi "François". "Chloé" menjadi "Chloé". Divisi Jerman memiliki masalah serupa dengan umlaut. Data divisi Jepang sepenuhnya tidak terbaca—hanya baris tanda tanya dan karakter pengganti. Penyebab utamanya? Setiap tim regional mengekspor CSV mereka menggunakan pengkodean yang berbeda. Prancis menggunakan ISO-8859-1 (Latin-1). Jerman menggunakan Windows-1252. Jepang menggunakan Shift-JIS. Tim UK dan AS menggunakan UTF-8, tetapi beberapa menggunakan UTF-8 dengan BOM (Byte Order Mark) dan yang lain tanpa. Satu tim di Spanyol entah bagaimana mengekspor data mereka dalam UTF-16LE. Proyek konsolidasi, yang awalnya direncanakan selama tiga bulan, memakan waktu sebelas bulan. Kami harus membangun jalur deteksi pengkodean khusus yang akan: 1. Mencoba mendeteksi pengkodean menggunakan beberapa pustaka (chardet, charset-normalizer, dan heuristik khusus) 2. Memvalidasi deteksi dengan memeriksa pola karakter umum di setiap bahasa 3. Mengonversi semuanya ke UTF-8 tanpa BOM 4. Mencatat setiap konversi dengan skor kepercayaan untuk tinjauan manual Bahkan dengan jalur ini, kami memiliki tingkat kesalahan 3% yang memerlukan koreksi manual. Itu 3% dari 47 juta catatan pelanggan—1,4 juta nama yang memerlukan tinjauan manusia. Pelajarannya? Jangan pernah mempercayai pengkodean CSV. Selamanya. Bahkan jika seseorang memberi tahu Anda "itulah pasti UTF-8," verifikasi itu. Saya pernah melihat file yang mengklaim menjadi UTF-8 dalam metadata mereka tetapi sebenarnya adalah Windows-1252 dengan karakter ASCII tinggi. Saya pernah melihat file UTF-8 dengan random potongan ISO-8859-1 di mana seseorang menyalin dan menempel dari sistem lama. Saya bahkan pernah melihat file yang beralih pengkodean di tengah jalan karena skrip ekspor macet dan dimulai ulang dengan pengaturan lokal yang berbeda. Sekarang, setiap CSV yang melewati meja saya dijalankan melalui skrip validasi pengkodean sebelum saya bahkan melihat data. Ini telah menghemat waktu saya yang tak terhitung dan mencegah setidaknya selusin insiden besar.Whitespace yang Tidak Ada (Kecuali Ada)
Pada tahun 2018, saya diundang untuk memperbaiki sistem rekonsiliasi keuangan yang telah gagal selama enam bulan. Perusahaan tersebut adalah pemroses pembayaran yang menangani miliaran dolar dalam transaksi. Proses rekonsiliasi mereka membandingkan catatan transaksi dari database mereka dengan laporan CSV dari mitra perbankan. Sistem tersebut melaporkan ribuan ketidakcocokan setiap hari—transaksi yang muncul dalam laporan bank tetapi tidak ada di database mereka, atau sebaliknya. Tim keuangan secara manual menyelaraskan ketidakcocokan ini, bekerja 60 jam seminggu untuk tetap mengikuti. Mereka akan memeriksa setiap transaksi yang ditandai dan menemukan bahwa itu sebenarnya ada di kedua sistem. ID transaksi cocok sempurna. Tetapi sistem otomatis terus menandai mereka sebagai ketidakcocokan. Saya menghabiskan dua hari menganalisis kode, kueri basis data, dan logika penguraian CSV. Semuanya terlihat benar. Lalu saya melakukan sesuatu yang seharusnya sudah jelas sejak awal: saya membuka CSV dalam editor hex. Di sana ada. Setiap ID transaksi dalam file CSV bank memiliki spasi di akhir. Tidak terlihat di Excel. Tidak terlihat di sebagian besar editor teks. Tetapi di sana, di dump hex: `54 52 41 4E 53 31 32 33 34 35 20` bukan `54 52 41 4E 53 31 32 33 34 35`. Karakter `20` terakhir itu adalah karakter spasi. Database menyimpan ID transaksi tanpa spasi di akhir. Logika perbandingan melakukan pencocokan string yang tepat. "TRANS12345" ≠ "TRANS12345 ". Ribuan ketidakcocokan palsu, ratusan jam terbuang, semua karena satu karakter spasi di akhir. Tapi inilah yang membuatnya lebih buruk: spasi di akhir tidak konsisten. Beberapa ID transaksi memilikinya, beberapa tidak. Beberapa memiliki spasi di akhir, beberapa memiliki spasi di depan, dan beberapa memiliki keduanya. Beberapa memiliki tab alih-alih spasi. Satu file yang sangat diingat memiliki campuran spasi, tab, dan spasi yang tidak terputus (U+00A0). Perbaikannya sederhana—trim semua whitespace selama impor. Tetapi pelajarannya sangat mendalam: whitespace dalam CSV tidak pernah kebetulan, selalu bermasalah, dan sering tidak terlihat. Saya sekarang memiliki aturan: setiap field string harus di-trim saat diimpor, tanpa pengecualian. Saya tidak peduli jika logika bisnis mengatakan field tersebut harus mempertahankan whitespace. Saya tidak peduli jika seseorang bersikeras datanya bersih. Trim semuanya. Saya juga telah belajar untuk waspada terhadap karakter tak terlihat lainnya: spasi lebar nol (U+200B), non-joiners lebar nol (U+200C), joiners lebar nol (U+200D), dan tanda urutan byte yang ditakuti (U+FEFF) yang kadang muncul di tengah file. Karakter-karakter ini adalah hantu dalam mesin, tak terlihat oleh manusia tetapi sangat nyata bagi komputer.Format Tanggal yang Menghancurkan Perdagangan Internasional
Izinkan saya menceritakan tentang saat saya menemui format tanggal yang begitu terkutuk, begitu rusak secara fundamental, sehingga masih menghantui mimpi saya. Ini terjadi di sebuah perusahaan logistik yang mengoordinasikan pengiriman antara produsen di Asia dan pengecer di Amerika Utara dan Eropa. Sistem bekerja seperti ini: produsen akan mengunggah file CSV dengan detail pengiriman, termasuk tanggal pengambilan, tanggal pengiriman yang diperkirakan, dan tanggal pabean. Sistem akan mem-parsing tanggal-tanggal ini, menghitung waktu transit, dan mengoordinasikan dengan perusahaan pengiriman dan broker pabean. Semuanya berfungsi baik selama bertahun-tahun. Namun, pada bulan Maret 2016, sistem mulai menjadwalkan pengiriman untuk tanggal di masa lalu. Kontainer yang seharusnya diambil pada 15 Maret 2016, dijadwalkan untuk 15 Maret 1916. Dokumen pabean diajukan untuk tanggal sebelum penemuan pengiriman kontainer. Penyebab utamanya? Format tanggal otomatis Excel yang dikombinasikan dengan perbedaan format tanggal regional dan kesalahpahaman yang sangat spektakuler tentang cara kerja tanggal. Inilah yang terjadi: 1. Seorang produsen di China akan memasukkan tanggal seperti "3/15/2016" (15 Maret 2016 dalam format MM/DD/YYYY) 2. Excel akan menginterpretasikan ini sebagai tanggal dan menyimpannya secara internal sebagai nomor urut (42444 untuk 15 Maret 2016) 3. Ketika diekspor ke CSV, Excel akan memformatnya sesuai dengan lokal sistem 4. Lokal sistem China menggunakan format YYYY-MM-DD, jadi diekspor sebagai "2016-03-15" 5. Sistem impor kami, yang dikonfigurasi untuk format MM/DD/YYYY, akan mem-parsing "2016-03-15" sebagai "2016/03/15" (bulan ke-2016, hari ke-3, tahun ke-15) 6. Karena bulan 2016 tidak valid, parser akan kembali mencoba menginterpretasikannya sebagai "20/16/03/15" 7. Melalui serangkaian upaya parsing yang semakin putus asa, akhirnya akan menetap pada "03/15/1916" Tapi tunggu, semakin buruk. Beberapa produsen menggunakan format DD/MM/YYYY. Beberapa menggunakan YYYY-MM-DD. Beberapa menggunakan MM/DD/YY (tahun dua digit). Dan satu produsen di Taiwan menggunakan kalender Minguo, di mana tahun 105 sesuai dengan 2016 M (1912 + 105). Kami akhirnya memiliki tanggal yang menjangkau dari 1916 hingga 2116, dengan kluster yang sangat padat di sekitar tahun 1970 (epoch Unix) karena beberapa sistem mengekspor tanggal sebagai cap waktu Unix dan parser kami menginterpretasikannya sebagai format YYYYMMDD. Solusinya memerlukan: - Mengimplementasikan parser tanggal multi-strategi yang akan mencoba mendeteksi formatnya - Menambahkan aturan validasi (menolak tanggal sebelum 2000 atau setelah 2050) - Mengharuskan produsen menggunakan format ISO 8601 (YYYY-MM-DD) secara eksklusif - Membangun antarmuka web untuk unggahan CSV yang akan menampilkan tanggal yang diparsing sebelum diimpor - Membuat rangkaian pengujian komprehensif dengan tanggal dalam setiap format yang dapat ditemui Bahkan dengan semua langkah perlindungan ini, kami masih kadang-kadang mendapatkan kesalahan pemrosesan tanggal. Bulan lalu, saya menemui sebuah CSV di mana seseorang telah memasukkan "2/29/2023" (29 Februari 2023—tanggal yang tidak ada karena 2023 bukan tahun kabisat). Excel dengan senang hati menerimanya, menyimpannya sebagai nomor urut 45000, dan mengekspornya sebagai "2023-02-29". Sistem kami mengimpornya, memvalidasi bahwa itu dalam format yang benar, dan menjadwalkan pengiriman untuk tanggal yang tidak ada."Masalah dengan tanggal adalah bahwa semua orang berpikir mereka memahaminya, tetapi tidak ada yang benar-benar melakukannya. Tanggal adalah konstruksi budaya, bukan yang matematis. Mereka memiliki zona waktu, waktu penyesuaian siang hari, tahun kabisat, detik kabisat, dan reformasi kalender. Mereka memiliki format yang berbeda di negara yang berbeda, titik awal yang berbeda di era yang berbeda, dan makna yang berbeda dalam konteks yang berbeda. Dan file CSV, dengan ketidakadaan metadata mereka, memberi Anda tidak ada cara untuk mengetahui interpretasi mana yang benar."Kutipan ini dari seorang kolega dengan sempurna menangkap masalah tanggal. CSV tidak memiliki tipe data. Mereka tidak memiliki skema. Mereka hanya teks. Ketika Anda melihat "01/02/03" dalam sebuah CSV, apakah itu 2 Januari 2003? 1 Februari 2003? 2 Maret 2001? 3 Februari 2001? Tidak ada cara untuk mengetahuinya tanpa konteks, dan konteks adalah apa yang tidak disediakan oleh CSV.
Angka yang Bukan Angka
Berikut adalah tabel masalah data numerik yang paling umum yang pernah saya temui, bersama dengan frekuensi dan dampak tipikalnya:| Jenis Masalah | Frekuensi | Dampak Tipikal | Contoh |
|---|---|---|---|
| Pemisah ribuan | Sangat Tinggi (60%) | Kegagalan impor, kesalahan tipe | "1,234.56" terurai sebagai string |
| Simbol mata uang | Tinggi (45%) | Kegagalan impor, kesalahan perhitungan | "$1,234.56" atau "€1.234,56" |
| Perbedaan pemisah desimal | Tinggi (40%) | Kesalahan perhitungan yang bencana | "1.234,56" (Eropa) vs "1,234.56" (AS) |
| Notasi ilmiah | Sedang (25%) | Kehilangan presisi, salah interpretasi | "1.23E+05" atau "1.23456789E-10" |
| Angka nol di depan | Sedang (30%) | Kehilangan data, kerusakan ID | "00123" menjadi "123" |
| Tanda persen | Sedang (20%) | Kesalahan perhitungan 100x | "15%" disimpan sebagai 15 bukannya 0.15 |
| Format angka negatif | Rendah (15%) | Kehilangan tanda, perhitungan yang salah | "(123 |