Skip to content

תכנון לאריכות ימי תוכנה עם SQLite ו־WASM: מגבלות וייצוא

מאמר זה בוחן שימור תוכנה באמצעות יישומים מבוססי דפדפן.

בטון רומי משמש כאן מטפורה לאריכות ימים, לא דיווח מאומת על ממצא ארכאולוגי חדש. בתוכנה אין מנגנון מקביל שמתקן אוטומטית API מיושנים או נתונים שאבדו.

שירותים חיצוניים, תלויות ופלטפורמות עשויים להשתנות לאורך זמן. יעד שימור מועיל הוא לצמצם תלויות ולשמור נתונים, קוד מקור, הוראות בנייה וכלים תואמים — לא להבטיח מאה שנות פעולה ללא תחזוקה.

נבחן תכנון קטן של יומן SQLite/WASM, לרבות הפער בין עבודה בזיכרון לאחסון עמיד. הדוגמה להמחשה ולא הורצה; זו אינה מערכת למאה שנה או מערכת המתקנת את עצמה.

האנטומיה של דעיכת תוכנה

לפני הבנייה צריך להבין מדוע תוכנה מודרנית מתיישנת. בטון מתדרדר בשל בליה כימית, מאמץ פיזי ותערובות יסוד לקויות. תוכנה מתדרדרת בגלל:

  • ריקבון API: ממשקי SaaS חיצוניים משתנים, מוציאים נקודות קצה משימוש או מפסיקים לפעול.
  • התיישנות סביבת הריצה: סביבות שפה כמו Node.js,‏ Python ו־Ruby מתקדמות ושוברות תאימות לאחור.
  • שינויי פלטפורמה: מערכות הפעלה, מעבדים ו־API של המארח מתפתחים. סט הוראות נייד מסייע רק אם הייבואים התואמים ושירותי היישום הסובבים עדיין זמינים.
  • תלות בשירות: יישום התלוי בשרת דורש המשך תפעול או נתיב הגירה. יכולת מקומית עשויה לצמצם את התלות, אך עדיין נדרשים גיבויים וסביבות ריצה מתוחזקות.

שאפו למספר קטן של תלויות, לדרישות ביצוע מתועדות ולנתונים הניתנים לייצוא בפורמט מתועד. SQLite ו־WebAssembly עשויים לעזור, אך אף אחד מהם אינו הופך כל מארח לתואם או כל קובץ לקריא בכל מקום.

המחסנית: SQLite ו־WASM, עם מגבלות מפורשות

למה דווקא שניהם? נבחן את הכישורים שלהם:

1. SQLite: פורמט אחסון מתועד

מפתחי SQLite מצהירים על כוונה לתמוך בו עד 2050 ומבהירים שאין זו הבטחה מוחלטת. פורמט הקובץ המתועד וחוצה הפלטפורמות מסייע לשימור; כתיבת קורא תקין אינה בהכרח משימה לסוף שבוע, ומסדים פעילים עשויים לדרוש גם קובצי יומן או WAL.

2. WebAssembly: הוראות ניידות, ממשקים תלויי מארח

WebAssembly מגדיר הוראות ניידות ומנגנון ייבוא. מודול עדיין דורש תמיכה בתכונות ובממשקי המארח שלו; DOM ותלויות JavaScript של דפדפן אינם קיימים אוטומטית בסביבת ריצה עצמאית. אין הבטחת תאימות למכשירים עתידיים.

תכנון היומן העמיד

יומן מקומי־תחילה זה שומר מסד קטן בזיכרון ומציע ייצוא מפורש לקובץ SQLite. רשומות שלא יוצאו אובדות ברענון או בקריסה. קובץ שיוצא הוא תמונת מצב, לא אחסון בלתי משתנה; שמרו עותקים ואמתו שחזור בכלי SQLite תואמים. לא ממומשים כאן ממשק ייבוא או שמירה אוטומטית.

כך נראית הארכיטקטורה ברמה המושגית:

ממשק HTML ו־JavaScript בדפדפן
↕ API רשמי של SQLite ב־JS/WASM
מסד SQLite בזיכרון — נדיף
↓ ייצוא מפורש בידי המשתמש
תמונת SQLite שהורדה לקובץ
נדרשים גיבוי ואימות שחזור בנפרד

מימוש שלב אחר שלב

היעדר CGO אינו מעיד על תאימות לדפדפן: רשימת הפלטפורמות שנבדקה עבור modernc.org/sqlite אינה כוללת js/wasm. לכן הדוגמה המתוקנת משתמשת בהפצת JS/WASM הרשמית של SQLite. זהו תחליף לנתיב הבנייה הלא־מבוסס של דרייבר Go במקור, לא טענה שהקוד התקמפל.

שלב 1: ליבת הדפדפן — app.js

לאחר אתחול SQLite, קוד JavaScript לימודי זה יוצר טבלה, קושר פרמטרי קלט, מציג רשומות כטקסט ומייצא תמונת מצב. השתמשו בנתוני הדגמה לא רגישים; הקובץ המיוצא אינו מוצפן. הקוד לא הורץ ולא נבדק חזותית.

// app.js — illustrative, unexecuted; uses matching local sqlite3.js/.wasm.
const output = document.getElementById("output");
const entry = document.getElementById("entry");
const save = document.getElementById("save");
const exportButton = document.getElementById("export");
let db;
function report(error) { output.textContent = String(error); }
sqlite3InitModule().then(sqlite3 => {
  db = new sqlite3.oo1.DB(":memory:", "c");
  db.exec(`CREATE TABLE journal (
    id INTEGER PRIMARY KEY,
    timestamp TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
    entry TEXT NOT NULL
  )`);
  function refresh() {
    const rows = [];
    db.exec({ sql: "SELECT id,timestamp,entry FROM journal ORDER BY id DESC LIMIT 100",
      rowMode: "object", resultRows: rows });
    output.textContent = rows.map(row =>
      `[${row.timestamp}] (#${row.id}): ${row.entry}`).join("\n") || "No entries";
  }
  save.addEventListener("click", () => {
    try {
      const text = entry.value.trim();
      if (!text || text.length > 2000) throw new Error("Use 1–2000 characters");
      if (db.selectValue("SELECT count(*) FROM journal") >= 1000) {
        throw new Error("Demo limit reached; export your database");
      }
      db.exec({ sql: "INSERT INTO journal(entry) VALUES (?)", bind: [text] });
      entry.value = "";
      refresh();
    } catch (error) { report(error); }
  });
  exportButton.addEventListener("click", () => {
    try {
      const bytes = sqlite3.capi.sqlite3_js_db_export(db);
      const url = URL.createObjectURL(new Blob([bytes],
        { type: "application/vnd.sqlite3" }));
      const link = document.createElement("a");
      link.href = url;
      link.download = "journal-snapshot.sqlite3";
      document.body.append(link);
      link.click();
      link.remove();
      setTimeout(() => URL.revokeObjectURL(url), 60000);
      output.textContent = "Download requested. Verify the saved file and keep a backup.";
    } catch (error) { report(error); }
  });
  save.disabled = exportButton.disabled = false;
  refresh();
}).catch(report);

שלב 2: אריזת קובצי SQLite/WASM תואמים

השתמשו במהדורת SQLite WASM מקובעת ומאומתת, ושמרו את קובצי JavaScript ו־WASM התואמים, המקור והרישיונות. זהו מבנה קבצים מושגי, לא הורדה, התקנה או בנייה שבוצעה:

# Illustrative package layout, not an executed build
# index.html
# app.js
# sqlite3.js   (from the chosen SQLite WASM release)
# sqlite3.wasm (from the same release)

הגישה המקורית של main.wasm דרשה גם wasm_exec.js תואם של Go ותלויות נתמכות. הדוגמה המתוקנת דורשת במקום זאת קובצי SQLite JS/WASM תואמים ו־API מתאימים של הדפדפן. קובץ WASM לבדו אינו היישום כולו.

שלב 3: ממשק קטן — index.html

ה־HTML משתמש בבקרים מובנים, באזהרה גלויה על נדיפות ובכפתורים מושבתים עד להשלמת האתחול. הגישו את החבילה ממקור מקומי מבוקר או מ־HTTPS, עם סוגי MIME נכונים ל־JavaScript ול־WASM; בדקו דפדפני יעד ונגישות במקום להבטיח תצוגה מושלמת בעתיד.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>SQLite WASM Journal Demo</title>
  <script src="sqlite3.js" defer></script>
  <script src="app.js" defer></script>
</head>
<body>
  <h1>SQLite WASM Journal Demo</h1>
  <p>Memory only: reload or crash loses unexported entries.
     Export a snapshot and verify the saved file. Do not enter sensitive data.</p>
  <label for="entry">New entry (up to 2000 characters)</label>
  <textarea id="entry" maxlength="2000"></textarea>
  <button id="save" disabled>Add in memory</button>
  <button id="export" disabled>Download SQLite snapshot</button>
  <h2>Records and status</h2>
  <pre id="output" role="status">Loading SQLite...</pre>
</body>
</html>

יתרונות העמידות ומגבלותיהם

כל תלות חיצונית מוסיפה חובת תחזוקה, אך מהדורה או שינוי מחיר במעלה השרשרת אינם שוברים אוטומטית יישום בעל גרסאות מקובעות. השוו אירוח, עדכונים, שיתוף ושחזור במקום לייחס כשל בלתי נמנע לספקים מסוימים.

שלוש שאלות תכנון נשארות גם לאחר בחירת SQLite ו־WASM:

1. אינרציה מבנית — לא־מקוון תחילה

לאחר שהקבצים הדרושים זמינים, פעולות מסד הנתונים יכולות להישאר מקומיות. טעינה ראשונית, ייבוא מודולים ומקור האירוח עדיין חשובים; קטעי הקוד אינם מממשים הפעלה לא־מקוונת. שמרו את קובצי Go המקוריים index.html,‏ wasm_exec.js ו־main.wasm רק כשמשתמשים בבניית Go שאומתה בנפרד; לדוגמה המתוקנת יש מבנה קובצי SQLite שהוצג לעיל.

2. שחזור אינו שמירה אוטומטית

מסד בזיכרון נעלם כשהחיבור או התהליך מסתיימים. יומני חזרה לאחור ו־WAL באחסון עמיד אינם משמרים את הזיכרון שלא נשמר בדוגמה. שחזור קריסה של SQLite תלוי בהבטחות האחסון ומערכת הקבצים; הוא אינו מתקן שחיתות שרירותית. OPFS הוא אפשרות שמירה נפרדת, עם מכסות, מגבלות דפדפן ודרישות גיבוי.

3. ניידות קיצונית

מארח עתידי עשוי לחייב שינוי בממשק, בייבואים או בשילוב האחסון גם אם הוא מסוגל להריץ main.wasm. שמרו מקור, גרסאות כלי בנייה, סכימה וייצואים לדוגמה, ובדקו מעת לעת שחזור והגירה.

סיכום: תכנון לעשורים

הגישה מתאימה לחלק מהכלים המקומיים הקטנים, לא לכל עומס. שיתוף, עדכוני אבטחה וארכיונים חיוניים דורשים תכנון ואימות משלהם. שאלו כיצד ניתן לשחזר את היישום והנתונים כשהשירות או סביבת הריצה הנוכחיים אינם זמינים.

SQLite ו־WASM יכולים לצמצם חלק ממכשולי הניידות והפריסה. אריכות ימים עדיין דורשת תלויות מתוחזקות, ייצואים מאומתים, גיבויים ותכנון הגירה; היומן הוא נקודת מוצא לימודית, לא הבטחת שימור.

מה דעתכם? האם התנסיתם בקימפול מסדי נתונים ישירות לצד הלקוח? כיצד אתם מתכננים יישומים שישרדו את העשור הבא של שינויי הטכנולוגיה? כתבו בתגובות!

עד הפעם הבאה, המשיכו לתכנת בחוכמה.

סוף המאמר.

מקורות ראשוניים

Post a Comment

Previous Post Next Post