# سلسلة دفتر الأستاذ، الجزء الأول: نموذج القيد المزدوج

> تبدأ معظم الأنظمة المالية بالطريقة نفسها. أنت تبني محفظة، ولدى المستخدم $100، فيرسل $30 إلى صديق، فتكتب balance = balance - 30 في صف و balance = balance + 30 في الصف الآخر.

بقلم Shodipo Ayomide، نُشرت في 30 يونيو 2026. نسخة الويب: https://blog.shodipoayomide.com/ar/ledger-series-part-i-the-double-entry-model

![سلسلة دفتر الأستاذ، الجزء الأول: نموذج القيد المزدوج](https://blog.shodipoayomide.com/banners/ledger-series-part-i-the-double-entry-model.png)

تبدأ معظم الأنظمة المالية بالطريقة نفسها. أنت تبني محفظة، ولدى المستخدم *\$100*، فيرسل *\$30* إلى صديق، فتكتب `balance = balance - 30` في صف و `balance = balance + 30` في الصف الآخر. يصبح الرصيد مجرد رقم تحتفظ به في المحفظة وتحدّثه في كل مرة، مثل المجموع المسجّل على بطاقة هدايا. وهذا يعمل، فتدفعه إلى بيئة الإنتاج بهذه الطريقة.

ثم تكبر الشركة، وصار لديك الآن بطاقات خصم وبطاقات ائتمان، وقنوات للعملات المشفرة، ومدفوعات بالعملات الورقية، ورسوم، ومبالغ مستردة، وعدد من مزودي الدفع، ومزود للمحافظ. توزّع النظام المالي على خدمات وجداول تملكها فرق مختلفة. وفي أحد الأرباع، يخبرك قسم المالية أن *$40,000* غير محسوبة، ولا يمكن العثور عليها.

المال ليس مفقودًا من الناحية التقنية. إنه في حسابك المصرفي، وكل سنت فيه محسوب. ما فُقد هو الإسناد أو التوثيق، أي السجل الذي يبيّن *لمن يعود هذا المال*. عمود `balance` في قاعدة بياناتك يحمل رقمًا لكنه لا يحمل القصة الكاملة وراءه، لذا عندما يختلف الرقم مع الواقع، لا توجد طريقة لإعادة تتبّع كيف وصل إلى ما هو عليه. كل مهندس عمل على أي نظام مالي مهم لديه نسخة ما من قصة الرعب هذه، اسأل!

الحل ليس مجرد عمود `balance` مدروس أكثر. إنه نموذج تستخدمه البنوك والأنظمة المالية التقليدية منذ سنوات، وما زال كل دفتر أستاذ جادّ يعمل عليه حتى اليوم: القيد المزدوج.

## لماذا يفشل الرقم الواحد

تخزين المال كرقم قابل للتعديل، أي كقيد واحد، يفشل لثلاثة أسباب رئيسية، وهي تميل إلى الظهور في الساعة 2:45 فجرًا.

ولا يمكنك التتبع لفهم ما حدث لأنه لا يوجد تاريخ واضح. `balance = 70` لا يقول شيئًا عن الحركات التي أنتجته، إنه مجرد رقم. وعندما يكون خاطئًا، لا يوجد شيء تراجعه لتعود عبره إلى الأصل.

لا يوجد طرف ثانٍ. طرح `$30` من محفظة لا يسجّل إلى أين ذهب مبلغ *$30*. مصدر المال ووجهته موجودان فقط في أي سطر من شيفرة التطبيق صادف أنه نُفِّذ، وليس في بيانات النظام الأساسية.

والأكثر من ذلك، لا توجد أي حماية من حالات التسابق التي ستحدث أو قد تحدث. يقرأ طلبان `balance = 100` في الوقت نفسه، فيطرح كل منهما *30*، ويكتب كل منهما *70*. تحرّك المال مرتين، ومع ذلك سيبدو العمود صحيحًا.

## المبادئ الأساسية الثلاثة

يستبدل دفتر الأستاذ القائم على القيد المزدوج ذلك الرقم القابل للتعديل بسجلّ للحركة يُضاف إليه فقط، مبني من ثلاثة كائنات.

1. الحساب (Account): وهو ببساطة وعاء مستقل من القيمة. محفظة المستخدم، والنقد لدى الشركة، والرسوم التي جمعتها، كل واحد منها حساب.

2. القيد (Entry): وهو الآن قيد مدين أو دائن واحد على حساب واحد. يجب حتمًا أن يُكتب القيد مرة واحدة دائمًا، وألا يُغيَّر أو يُحذف أبدًا. كل قيد هو سجل دائم لقيمة تدخل إلى حساب واحد أو تخرج منه *«غير قابل للتعديل»*.

3. المعاملة (Transaction): وهي مجموعة من القيود تتحرك كوحدة واحدة، إما كلها أو لا شيء. وهذا هو الكائن الذي يربط نظامك بأكمله معًا.

لا تكتب القيود مباشرة. أنت تكتب معاملة، والمعاملة تحمل قيودها. والكتابة نفسها تجري داخل معاملة قاعدة بيانات واحدة، فإما أن تتم كلها أو لا يتم شيء، `tx, _ := db.Begin(); tx.Exec(...); tx.Commit()`. على سبيل المثال، تحويل *$30* من *Alfred* إلى *Tobi* هو معاملة واحدة تحمل قيدين، أحدهما يأخذ من *Alfred* والآخر يعطي *Tobi*، فإما أن يُثبَّتا معًا أو لا يُثبَّت أيٌّ منهما. ولا ينبغي أن توجد أبدًا حالة صالحة يكون فيها *Alfred* قد خُصم منه دون أن يُضاف المبلغ إلى *Tobi*. هذا التجميع الذرّي هو الضمان.

## المدين والدائن

والآن، هذا هو الجزء التالي الذي يربك عددًا لا بأس به من الناس. القيد المدين ليس طرحًا، والقيد الدائن ليس إضافة. إنهما ببساطة الاتجاهان الوحيدان اللذان يمكن أن تحدث بهما الحركة أو تأخذهما، وما إذا كان اتجاه معين *يزيد ↑* الحساب أو *ينقصه ↓* يعود إلى نوع الحساب الذي تستقر عليه الحركة. وللتوضيح يمكنك أن تعيد قراءة قسم «المبادئ الأساسية الثلاثة» ببساطة

كل حساب ينتمي إلى نوع من بين حفنة من الأنواع الممكنة كما تحدثنا أعلاه، والنوع هو ما يحدد رصيده الطبيعي، أي الطرف الذي يجعل الرصيد يرتفع. لذا فأنت لا تتعامل إلا مع نوعين. أولًا، الحسابات ذات الطبيعة المدينة، أي الأصول والمصروفات. القيد المدين هو ما يزيدها، والقيد الدائن هو ما ينقصها. ثم الحسابات ذات الطبيعة الدائنة، أي الالتزامات وحقوق الملكية والإيرادات. القيد الدائن هو ما يزيدها، والقيد المدين هو ما ينقصها.

يتضح الفرق في اللحظة التي تطبّقه فيها على مثال المحفظة. مبلغ *$100* الذي يحتفظ به المستخدم لديك ليس مالك، إنه مال تدين به له، لذا فهو في دفاترك التزام، طبيعته دائنة. أما الدولارات الفعلية التي تحتفظ بها نيابة عنه فهي أصل، وطبيعته مدينة.

والآن يصبح للإيداع معنى. على سبيل المثال، يودع مستخدم *100 USDC*، فيصبح أمران صحيحين في آن واحد: أنت تحتفظ الآن بمقدار *100 USDC* إضافية، أي أن أصلًا يزداد، وهذا قيد مدين، وأنت مدين للمستخدم بمقدار *100 USDC* إضافية، أي أن التزامًا يزداد، وهذا قيد دائن. حدثت حركة واحدة، بقيدين، وهما متوازنان.

![إيداع 100usdc بقيدين](https://i.ibb.co/BHc5VCQW/Screenshot-2026-06-30-at-11-44-10-AM.png)

المدين والدائن ليسا نقيضين في حالة شدّ. إنهما منظوران لمبلغ *$100* نفسه بالضبط، سُجّلا في الوقت نفسه، في معاملة واحدة.

ومن خلال تشبيه فيزيائي، هناك طريقة أخرى للنظر إلى الأمر كله وفهمه، وهي قانون نيوتن الثالث للحركة الشهير *«لكل فعل رد فعل مساوٍ له في المقدار ومعاكس له في الاتجاه»*

في أي معاملة، يجب أن يتساوى مجموع القيود المدينة مع مجموع القيود الدائنة. في كل مرة، ودون أي استثناء. Σ القيود المدينة − Σ القيود الدائنة = 0

لا تظهر القوة وحدها أبدًا، بل تأتي دائمًا مع توأمها المساوي لها والمعاكس. والقيمة في سيناريو دفتر الأستاذ هذا تعمل بالطريقة نفسها تمامًا. فهي لا تستقر أبدًا على حساب واحد دون قيد مساوٍ ومعاكس على حساب آخر، وهذان القيدان يُبقيان الدفاتر متوازنة.

مبلغ *100 USDC* الذي تقيّده مدينًا في حساب الحفظ لديك، ومبلغ 100 USDC الذي تقيّده دائنًا لصالح المستخدم، متساويان في المقدار لكنهما ليسا الشيء نفسه، فأحدهما أصل تحتفظ به الآن، والآخر التزام تدين به الآن. لذا لا شيء يتحرك هنا، بل ينمو الطرفان في الوقت نفسه، فيظهر إلى الوجود أصل جديد والتزام جديد مساوٍ له معًا، وهذا بالضبط سبب بقاء الدفاتر متوازنة.

## القاعدة الصارمة

في كل معاملة، يجب أن يساوي مجموع القيود المدينة مجموع القيود الدائنة. ولا يُسمح لمعاملة غير متوازنة بأن توجد في أي مكان.

هذه القاعدة هي ما يحوّل «عدم خسارة المال أبدًا» من مجرد أمنية إلى خاصية أساسية في النظام الذي تعمل عليه. لا يمكن للقيمة أن تغادر حسابًا دون أن تصل إلى حساب آخر، لأن المعاملة لن تتوازن بخلاف ذلك. ولا ينبغي أن ينحرف ما في عهدتك عمّا تدين به لمستخدميك، لأن كل حركة تسجّل الطرفين في آن واحد. وعندما يكون هناك خطأ ما، لا يسلّمك دفتر الأستاذ رصيدًا خاطئًا بصمت، بل يرفض عملية الكتابة رفضًا قاطعًا.

عمليًا، جوهر دفتر الأستاذ هو هذا الفحص الوحيد. في هذه الحالة تُخزَّن المبالغ كأعداد صحيحة غير سالبة بالوحدات الصغرى (السنتات، أو wei)، ويُحمَل الاتجاه في حقل `side` بدلًا من الإشارة:

```typescript
type Entry = { accountId: string; side: "DR" | "CR"; amountMinor: bigint; assetId: string };

function assertBalanced(entries: Entry[]) {
  if (entries.length === 0) throw new Error("empty txn");

  const net = new Map<string, bigint>();

  for (const e of entries) {
    if (e.amountMinor <= 0n) throw new Error(`bad amount: ${e.accountId} ${e.amountMinor}`);
    const delta = e.side === "DR" ? e.amountMinor : -e.amountMinor;
    net.set(e.assetId, (net.get(e.assetId) ?? 0n) + delta);
  }

  for (const [asset, balance] of net) {
    if (balance !== 0n) throw new Error(`unbalanced: ${asset} off by ${balance}`);
  }
}
```

هناك أمران في هذه الشيفرة أهم مما يبدوان. يُفحص التوازن *لكل أصل على حدة*، لذا فإن المعاملة التي تمس الدولارات و bitcoin يجب أن تتوازن في كل منهما بشكل مستقل، ولا يمكن لعملة أن تسوّي عملة أخرى بصمت أبدًا. والمبالغ من نوع `bigint` وليست أعدادًا عشرية بفاصلة عائمة، لأن الفاصلة العائمة والمال قصة رعب منفصلة ليوم آخر.

وهناك أمر آخر يجدر ملاحظته: لا يوجد في أي مكان من هذا المقطع أي تعامل مع عمود `balance`. الشيفرة تتحقق فقط من أن القيود متوازنة، ولا تكتب رصيدًا في أي مكان أبدًا. وهذا هو المكان الصحيح للبدء، فالرصيد ليس أبدًا حقيقة تضبطها مباشرة. أنت لا تكتب `balance = 500`. بل تجمع القيود، `debits - credits`، وتقرأ النتيجة وفقًا للطرف الطبيعي للحساب. القيود هي الحقيقة. والرصيد مجرد سؤال تطرحه عليها.

والآن إليك أمر آخر قد يُفهم خطأ. كون الأرصدة معرّفة بقيودها لا يعني أن تعيد جمعها في كل قراءة. إن فعلت ذلك، فأنت ببساطة تجمع تاريخ الحساب بأكمله في كل مرة، وهذا `O(n)`، و `n` لا يتوقف عن النمو. والحساب الذي تمسه كل معاملة، كخزينتك وما شابه، سينتهي به الأمر إلى أن يكون الأبطأ في القراءة. لذا لا تعيد الجمع. خزّن الرصيد، وحدّثه لحظة وصول كل قيد، وأبقه متزامنًا مع السجل. يبقى السجل مصدر الحقيقة. والرقم المخزّن في الحقيقة مجرد ذاكرة تخزين مؤقت يجب أن تتفق معه. مشتقّ في معناه، مخزّن في الممارسة، الاثنان معًا، لا أحدهما دون الآخر.

الفكرة نفسها في صورة واحدة، معاملة تتفرع إلى قيدين متوازنين يستقران على حسابين:

![قيدان، حسابان](https://i.ibb.co/xKQv3d4S/Screenshot-2026-06-30-at-2-04-51-PM.png)

## لماذا هذا هو الأساس

يطلب منك نظام القيد الواحد أن تثق برقم. أما نظام القيد المزدوج فيرفض أن يقف الرقم وحده، فالرصيد ليس شيئًا تؤكده أنت، بل شيء تفرض القيود صحته. وهو يعمل أيضًا بالطريقة نفسها التي يجعل بها الفهرس الفريد التكرار مستحيلًا بدلًا من أن يكون مجرد شيء لا ينبغي فعله، فمجموعة قواعد التوازن تجعل خسارة المال عملية كتابة لن تُثبَّت، بدلًا من فرق تكتشفه بعد سنوات أو أشهر، وترخيصك موضع مساءلة في جلسة استماع أمام لجنة. وهذا هو السبب في أن كل نظام مالي تقريبًا مبني بهذه الطريقة.

وهذا الجزء الأول ليس سوى الهيكل العظمي أيضًا. على دفتر الأستاذ الحقيقي أن يتعامل مع أموال لم تُسوَّ بعد، كإيداع عملة مشفرة ينتظر تأكيدات الكتل، أو سحب قد يفشل ويحتاج إلى عكسه للمستخدم الذي بدأه. في الجزء الثاني، سنتعمق في هذا النموذج على حركات حقيقية، ونشاهد رصيدًا واحدًا يصبح ثلاثة.
