הפעם שגיליתי שבנקים עדיין כותבים קוד כמו ב-1975
מסע אל תוך התופת של קבצי ASCII ברוחב קבוע, קובול, ולמה לאפליקציית הווב המודרנית שלכם צריך לדבר מיינפריים

קיבלתי היום אימייל מוזר. ללקוח יש איזה “תוכנה מקומית” שרצה, שאמורה לקבל מהשרת שלנו את הנתונים הפיננסיים העדכניים ביותר. באימייל כתוב שהאינטגרציה לחשבוניות שלהם שבורה. המערכת לא מצליחה לקרוא את הנתונים שלנו. “הקובץ חייב להיות ASCII עם ריווח קבוע.”
ASCII. ריווח קבוע. אני בוהה במסך. השנה 2026. יש לנו AI שיודע לכתוב שירה ולנהוג ברכב. ואיפשהו, מערכת בנקאית דורשת ממני לפרמט נתונים כאילו הם מנוקבים על כרטיסיות ומוזנים למחשב בגודל חדר.
מה זה בכלל קובץ ברוחב קבוע?
אתם יודעים איך אנשים נורמלים משתמשים ב-CSV? או ב-JSON? פורמטים שבהם מפרידים בין שדות בפסיקים או מבנים נתונים עם סוגריים? שבהם “John Doe” יכול להיות 9 תווים בשורה אחת, ו-”Kovalev Alexander Sergeevich” יכול להיות 28 בשורה הבאה?
קבצים ברוחב קבוע לא עובדים ככה. כל שדה מתחיל במיקום תו מדויק ובעל אורך מדויק. תמיד.
[127 רווחים] 12345000000000000002000000000000050זו לא טעות. קוד הפריט יושב בתווים 128-147, ברוחב 20 תווים, לא יותר ולא פחות. אם קוד הפריט שלכם הוא רק 5 ספרות, אתם מרפדים אותו ב-15 רווחים. אם הוא 21 ספרות? חבל, אתם קוצצים.
המפרט מגיע כשני PDF בעברית. אחד מגדיר את מבנה הכותרת:
- מיקום 1: סוג הקובץ (תו אחד)
- מיקום 19-43: שם הלקוח (25 תווים)
- מיקום 45-69: כתובת (25 תווים)
- מיקום 112-126: סכום כולל (15 תווים)
השני מגדיר את שורות הפריטים:
- מיקום 128-147: קוד פריט (20 תווים)
- מיקום 149-163: כמות (15 תווים)
- מיקום 165-179: מחיר (15 תווים)
שמתם לב למשהו? שדות הכותרת מתחילים במיקום 19. שדות השורה מתחילים במיקום 128. הם לא אמורים לחלוק שורה, ככה הפורמט פשוט עובד. מה שאומר ש-127 תווים של כלום לפני (או אחרי) הנתונים האמיתיים שלכם.
10 20 30 40 50 60 70 80 ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8 0·················Kovalev Alexander Sergeev·רחוב הרצל 5···············תל אביב···
25/25 עמודות · נקצץ:ich
למה שמישהו יעשה ככה?
הייתי חייב לחפש את זה כי פשוט לא האמנתי. הפורמט הזה מגיע ממיינפריימים של IBM משנות ה-60 עד ה-80. בנקים, חברות ביטוח, מערכות ממשלתיות - הם בנו הכל על המכונות האלה. מערכות שרצות קובול, מעבדות נתונים בפורמטים ברוחב קבוע כי:
- מהירות - המחשב יודע שהתו ה-128 הוא תמיד קוד הפריט. אין צורך בפירוק (parsing). קופצים ישר למיקום.
- בטיחות בינארית - אי אפשר להשתמש במפרידים כשהנתונים שלכם עלולים להכיל את אותם מפרידים. מיקומים קבועים מבטלים את הבעיה.
- קובול מצפה לזה - מיליוני שורות של לוגיקה עסקית שנכתבו בקובול, ושכתובן מחדש היה עולה מיליארדים.
כשהנתונים גדולים (ג’יגה/טרה-בייטים), קבצים בפורמט רוחב קבוע יכולים להיות הרבה יותר יעילים.
מכיוון שלכל רשומה ושדה יש גדלים קבועים, אפשר פשוט לקפוץ (seek) לשורה, לדוגמה, ה-n-מיליונית ולקרוא משם כמה רשומות. אפשר גם למפות את כל הקובץ לזיכרון ולקבל גישה אקראית יעילה וקלה יחסית לכל דבר.
הם לעולם לא ישדרגו. למה שיעשו את זה? המערכת עובדת. היא עיבדה טריליוני דולרים בעסקאות. היא יציבה. היא נבדקה. להחליף אותה יהיה פרויקט של מיליארדי דולרים עם סיכון עצום.
אז במקום זה, כל מפתח ווב מודרני שצריך להשתלב עם המערכות האלה חייב לטוס בזמן חזרה ל-1975 וללמוד לדבר מיינפריים.
הקוד שירשתי
$data .= $year . str_pad($order_id, 6, "0", STR_PAD_LEFT) . '|' . $order->get_date_created()->format('d/m/y') . '|' . mb_str_pad($order->get_formatted_billing_full_name(), 25, " ", STR_PAD_LEFT) . '|' . mb_str_pad($order->get_billing_address_1(), 25, " ", STR_PAD_LEFT) // ... נמשך עוד 12 שדותרואים את תווי הפייפ האלה? זו הבעיה. זה יוצר קובץ עם מפרידים:
26240001|19/01/26|יוסי כהן|רחוב הרצל 5|...אבל המיינפריים רוצה:
0יוסי כהן רחוב הרצל 5 תל אביב 1234567...בלי פייפים. בלי מפרידים. רק מיקומים מדויקים. תמיד.
הודעת השגיאה
המערכת שלחה בחזרה קובץ שגיאות. בעברית. מקודד ב-Windows-1255 (עוד שריד מהעבר). אחרי פענוח:
תקלה ASCII במספר שורה בקריאת: 1שדה מספר 64 אינו תקין: 26 |00000000039תרגום: “שדה 64 שבור. שלחתם: 26 |00000000039”
שדה 64 אמור להיות מספר בן 15 ספרות: 000000000000026
אנחנו שלחנו: 26 |00000000039 (אורך שגוי, יש בו תו פייפ, לא מרופד באפסים)
התיקון
להסיר את כל המפרידים. לרפד הכל לאורכים מדויקים. למקם שדות במיקומי תווים מדויקים.
function formatHeaderRecord($order) { return str_pad('0', 1) // מיקום 1: סוג הקובץ . str_repeat(' ', 18) // מיקום 2-18: ריק . mb_str_pad($order->billing_name, 25, ' ') // מיקום 19-43: שם . mb_str_pad($order->billing_address, 25, ' ') // מיקום 45-69: כתובת . mb_str_pad($order->billing_city, 15, ' ') // מיקום 71-85: עיר . str_repeat(' ', 26) // מיקום 86-111: ריק . str_pad(formatNumber($order->total), 15, '0', STR_PAD_LEFT); // מיקום 112-126: סכום כולל}
function formatLineRecord($item) { return str_repeat(' ', 127) // מיקום 1-127: ריק . str_pad($item->sku, 20, ' ') // מיקום 128-147: קוד פריט . str_pad(formatNumber($item->quantity), 15, '0', STR_PAD_LEFT) // מיקום 149-163: כמות . str_pad(formatNumber($item->price), 15, '0', STR_PAD_LEFT); // מיקום 165-179: מחיר}127 רווחים. ואז הנתונים שלכם. כי מתכנת כלשהו ב-1975 החליט ששם צריך להיות קוד הפריט, ומאז אף אחד לא הורשה לשנות את זה.
מה שלמדתי
הקוד שלכם שורד. הפונקציה החרא הזאת שאני כותב היום? מחר אני אשכח ממנה. בעוד שנה אולי יכתבו אותה מחדש ב-rust. אבל אם אכתוב אותה מספיק טוב, יכול להיות שהיא תשרוד אחריי. מתכנת כלשהו בשנת 2077 ייתקל באינטגרציית ה-WooCommerce שלי, יקלל את שמי, ויתהה למה שדה 64 מתחיל במיקום 112.
מתכנת הקובול שכתב את המערכת הבנקאית הזאת ב-1975 כנראה חשב שהוא פשוט פותר את הבעיה של אותו יום. לכתוב מפרט, לעבד כמה חשבוניות, ללכת הביתה. חמישים שנה אחר כך, הקוד שלו מעבד טריליוני דולרים. בנקים התמזגו, נרכשו, פשטו רגל - הקוד המשיך לרוץ. מתכנתים פרשו, מתו - הקוד המשיך לרוץ.
תזכרו את זה בפעם הבאה שמישהו מציע “לבנות את הלגאסי מחדש”. במיוחד היום, כשכל wrapper חדש של GPT גורם לקוד להרגיש זול מתמיד, ושכתוב נראה כמו עבודה של סוף שבוע. זה מפתה. רק תזכרו:
רוב הקוד שורד מסיבה כלשהי.
וכבר שאני מטיף פה, הנה הדבר היחיד ששווה לחלץ מכל הבלגן הזה: זה מה שקוד טוב באמת נראה. לא חכם, לא גמיש, לא מודרני. פשוט ברור, מתועד, וספציפי מספיק כדי שמישהו בשנת 2075 עדיין יוכל להבין מה לעזאזל אמור להיות בשדה 64.
אז כן, אני אכתוב את הפורמטר שלי לרוחב קבוע. ארפד את המחרוזות שלי. אספור מיקומי תווים כמו נזיר שמעתיק כתבי יד. ואשאיר readme קצר (כן, Claude, קצר), כי אולי, רק אולי, אם אכתוב את זה מספיק טוב, איזה מתכנת מסכן בשנת 2077 יודה לי.
עכשיו אם תסלחו לי, יש לי 127 רווחים לרפד.
קישורים שימושיים
אי-התאמת תאריכים באקסל ושגיאות off-by-one, עוד פורמט קבצים ישן שנשך אותי
https://www.easydatatransform.com/help/latest/windows/html/index.html?fixed_width_format.html https://stackoverflow.com/questions/7666780/why-are-fixed-width-file-formats-still-in-use
תגובות
התגובות נשמרות ב-GitHub Discussions (דרך giscus), אז כדי להצטרף לשיחה צריך חשבון GitHub.