يا أهلاً وسهلاً فيكم يا جماعة، معكم أخوكم أبو عمر.
قبل كم سنة، كنا شغالين على نظام كبير ومعقد لشركة ناشئة واعدة. الفريق كان صغير، شعلة حماس، والكل “إيد واحدة”. اتخذنا قرارات معمارية كثيرة بسرعة، بعضها غريب شوي، بس كان ماشي حاله والنظام شغال زي الساعة. مرّت الأيام والشهور، وكبر الفريق. بعض الشباب اللي أسسوا المشروع ترقوا أو انتقلوا لشركات ثانية، ودخل دم جديد على الفريق.
في يوم من الأيام، دخل علينا شب جديد اسمه “خالد”، مبرمج شاطر ونشيط، بس بحب يسأل “ليش؟” على كل إشي. وهذا حقه طبعاً. في أول اجتماع لمراجعة الكود، مسك خالد جزئية في النظام وقال بصوت عالي: “يا جماعة، شو القصة؟ ليش مستخدمين Message Queue هان لفصل خدمة الفواتير عن خدمة الطلبات؟ استدعاء API مباشر أسرع وأبسط بكتير! هاد تعقيد على الفاضي”.
ساد صمت رهيب في الغرفة. أنا والشباب القدامى طلعنا في بعض. كلنا متذكرين إنه كان في سبب *وجيه جداً* لهالقرار. متذكرين إنه كان في نقاش طويل، ومتذكرين إنه الحل المباشر سبب لنا مشاكل في البداية. بس شو هي المشاكل بالضبط؟ شو كانت الأرقام؟ مين اللي اقترح الحل البديل؟ الذاكرة خانتنا. دخلنا في جدال استمر ساعة كاملة، كل واحد فينا بحاول “يتذكر” السياق. ضاعت الساعة، وخالد طلع من الاجتماع مش مقتنع، وإحنا طلعنا محبطين لأنه ما قدرنا نوصل الحكمة وراء قرارنا.
هذاك اليوم كان نقطة تحول. أدركنا إنه ذاكرة الفريق هي أضعف أصل نملكه. من هنا، بدأت رحلتنا مع ما يسمى بـ “سجلات القرارات المعمارية” أو Architecture Decision Records (ADRs). خلوني أحكيلكم عنها.
ما هي سجلات القرارات المعمارية (ADRs)؟
ببساطة شديدة، الـ ADR هو عبارة عن ملف نصي قصير، يسجل قراراً معمارياً واحداً مهماً تم اتخاذه في المشروع. الفكرة مش توثيق كل صغيرة وكبيرة، لا. الفكرة هي توثيق القرارات اللي إلها تأثير كبير على النظام، القرارات اللي ممكن يجي مبرمج جديد بعد سنة ويسأل “ليش عملتوا هيك؟”.
فكر فيها زي “محضر اجتماع” موجّه ومختصر لذاكرة مشروعك. بدلاً من توثيق “ماذا” فعلنا (الكود نفسه بوثّق هاد الإشي)، الـ ADR يركز بشكل أساسي على “لماذا” فعلناه. هو الجسر اللي بنعبر فيه فجوة الزمن والذاكرة.
الجميل في الـ ADRs أنها لا تحتاج أدوات معقدة. كل ما تحتاجه هو محرر نصوص واتفاق داخل الفريق على صيغة موحدة. عادة ما تكون ملفات Markdown بسيطة توضع مباشرة في مستودع الكود (Git Repository) الخاص بالمشروع.
تشريح سجل قرار معماري (ADR): ماذا نكتب فيه؟
معظم فرق العمل تستخدم هيكل مشابه، وهو اللي تبنيناه في فريقنا. أي ADR جديد لازم يحتوي على الأقسام التالية. خلونا نأخذ مثال قرارنا باستخدام Message Queue اللي حكيتلكم عنه.
العنوان (Title)
لازم يكون واضح ومختصر ومرقّم. الترقيم بساعد على تتبع القرارات عبر الزمن.
مثال: ADR-007: استخدام RabbitMQ لمعالجة الطلبات غير المتزامنة
التاريخ (Date)
تاريخ اتخاذ القرار.
مثال: 2021-10-25
الحالة (Status)
هاي النقطة مهمة جداً لتتبع دورة حياة القرار. الحالات الشائعة هي:
- مقترح (Proposed): القرار مطروح للنقاش ولم يتم قبوله بعد.
- مقبول (Accepted): تم الاتفاق على القرار وسيتم تنفيذه.
- مرفوض (Rejected): بعد النقاش، تم رفض الاقتراح.
- مهجور (Deprecated): القرار كان مقبولاً في الماضي، لكننا لم نعد ننصح به للخصائص الجديدة.
- مستبدَل (Superseded by ADR-XXX): تم اتخاذ قرار جديد يلغي هذا القرار (مع الإشارة لرقم الـ ADR الجديد).
مثال: مقبول (Accepted)
السياق (Context)
هذا هو قسم “شو القصة؟”. هنا نصف المشكلة اللي بنحاول نحلها، والظروف المحيطة. هذا أهم قسم لخالد (المبرمج الجديد في قصتنا) ولكل من سيأتي بعده.
مثال على السياق:
“أثناء فترات الضغط العالي (مثل عروض الجمعة البيضاء)، لاحظنا أن خدمة الطلبات (Orders Service) تستغرق وقتاً طويلاً للرد لأنها تنتظر تأكيداً من خدمة الفواتير (Invoicing Service). هذا الانتظار كان يؤدي إلى فشل بعض الطلبات (Timeouts) وتجربة مستخدم سيئة. الحل المباشر عبر استدعاء API متزامن (Synchronous) أثبت عدم قدرته على التوسع (Scalability) تحت الضغط.”
القرار (Decision)
هنا نذكر بوضوح وبشكل مباشر ما هو القرار الذي تم اتخاذه.
مثال على القرار:
“قررنا فصل عملية إنشاء الفاتورة عن عملية تأكيد الطلب للمستخدم. سنقوم باستخدام طابور رسائل (Message Queue)، وتحديداً RabbitMQ. خدمة الطلبات ستقوم بنشر رسالة (event) عند إنشاء طلب جديد، وستقوم خدمة الفواتير بالاستماع لهذه الرسائل ومعالجتها بشكل غير متزامن (Asynchronous).”
العواقب (Consequences)
هذا القسم هو قمة النضج الفكري للفريق، لأنه يجبرنا على التفكير في الآثار الإيجابية والسلبية لقرارنا. لا يوجد قرار معماري مثالي، كل قرار هو عبارة عن مقايضة (Trade-off).
مثال على العواقب:
- إيجابيات:
- تحسين سرعة الاستجابة لعملية إنشاء الطلب بشكل كبير.
- زيادة صمود النظام (Resilience)؛ لو كانت خدمة الفواتير متعطلة، لن تفشل عملية الطلب، بل ستتم معالجة الفاتورة لاحقاً عند عودة الخدمة للعمل.
- فصل حقيقي (Decoupling) بين الخدمات، مما يسهل تطويرها وصيانتها بشكل مستقل.
- سلبيات:
- إضافة تعقيد تشغيلي (Operational Complexity) للنظام. الآن نحن بحاجة لمراقبة وصيانة RabbitMQ.
- صعوبة أكبر في تتبع مسار الطلب الكامل (Distributed Tracing) مقارنة بالاستدعاء المباشر.
- مفهوم “الاتساق النهائي” (Eventual Consistency) قد يكون صعب الفهم على المطورين الجدد؛ العميل قد لا يرى فاتورته فوراً.
وهذا قالب Markdown بسيط ممكن تستخدموه كنقطة بداية:
# ADR-XXX: [عنوان القرار]
- **Date**: YYYY-MM-DD
- **Status**: Proposed | Accepted | Rejected | Deprecated | Superseded by ADR-YYY
## Context
[اشرح المشكلة أو القوة الدافعة وراء هذا القرار. صف السياق التقني والتجاري.]
## Decision
[صف القرار الذي تم اتخاذه بوضوح.]
## Consequences
[صف النتائج المترتبة على هذا القرار، الإيجابية والسلبية. كل قرار له مقايضات.]
### Positive consequences
- [أثر إيجابي 1]
- [أثر إيجابي 2]
### Negative consequences
- [أثر سلبي 1]
- [أثر سلبي 2]
كيف أنقذتنا الـ ADRs في الممارسة العملية؟
بعد ما تبنينا هذي المنهجية، تخيلوا معي نفس الموقف مع خالد، ولكن بعد تطبيق الـ ADRs. يسأل خالد نفس السؤال. بدلاً من الصمت والارتباك، أبتسم وأقول له: “سؤال ممتاز يا خالد. افتح مستودع الكود، وروح على مجلد /docs/adr واقرأ الملف رقم 007“.
بعد خمس دقائق، يرجع خالد ويقول: “تمام أبو عمر، فهمت. السياق واضح جداً الآن، والمقايضات منطقية. شكراً للتوضيح”.
انتهى الموضوع! لا جدال، لا إضاعة وقت، لا إحباط. والأهم، خالد لم يشعر بأننا نفرض عليه قرارات “من فوق”، بل فهم التاريخ الهندسي للمشروع وأصبح جزءاً منه. هذه هي قوة توثيق “لماذا”.
نصائح من “الختيار” أبو عمر 👴
على مدار السنين، تعلمنا كم درس عن كيفية تطبيق الـ ADRs بفعالية. اسمحولي أشارككم كم نصيحة عملية:
- ابدأ بسيطاً ولا تنظر للماضي كثيراً: لا تحاول توثيق كل قرار اتخذته في آخر خمس سنوات. هذا مجهد ومحبط. ابدأ مع القرار المهم *التالي* الذي ستتخذه. مع الوقت، ستجد أن لديك مكتبة قيمة من القرارات الموثقة.
- مش كل إشي بده ADR: اختيار مكتبة لترتيب الأيقونات؟ غالباً لا يحتاج ADR. اختيار بين قاعدة بيانات SQL و NoSQL للمشروع بأكمله؟ هذا بالتأكيد يحتاج ADR. القاعدة العامة: إذا كان القرار يصعب أو يكلف عكسه، فهو مرشح جيد لـ ADR.
- خلّي الـ ADRs جنب الكود: أكبر خطأ هو وضع التوثيق في نظام منفصل (مثل Confluence أو Google Docs). التوثيق الذي يعيش بعيداً عن الكود، يموت وحيداً. ضع مجلد
/docs/decisionsأو/docs/adrفي نفس مستودع Git. هكذا، كل من يعمل على الكود يرى التوثيق. - الأتمتة صديقتك: في أدوات بسيطة مثل
adr-tools(موجودة كـ command-line tool) تساعدك على إنشاء ADR جديد بالصيغة الصحيحة وتحديث سجل القرارات. هذا يقلل من المجهود ويشجع الفريق على الالتزام. - استخدم الـ Pull Requests للنقاش: عندما يكون هناك قرار مقترح، لا تتناقشوا فيه عبر الإيميل. أنشئ ADR جديد بحالة “مقترح” (Proposed) وافتحه كـ Pull Request. يمكن للفريق كله أن يعلق ويناقش ويقترح تعديلات في مكان واحد. عند الوصول لاتفاق، يتم دمج الـ PR وتغيير الحالة إلى “مقبول” (Accepted).
الخلاصة: وثّق قرارك اليوم، تشكرك نفسك (وفريقك) غداً 💡
في عالم البرمجيات سريع التغير، الفرق تأتي وتذهب، والمشاريع تعيش لسنوات. ذاكرتنا البشرية ضعيفة، والسياق يضيع مع الزمن. سجلات القرارات المعمارية (ADRs) ليست مجرد “توثيق” ممل، بل هي استثمار صغير جداً في مستقبل مشروعك وصحة فريقك العقلية.
إنها الأداة التي تحول الأسئلة المحبطة مثل “ليش عملتوا هيك؟” إلى لحظات تعلم وتمكين. إنها تحمي قراراتك الصعبة من النسيان، وتضمن أن الحكمة التي اكتسبتها بشق الأنفس لا تضيع مع أول موظف يغادر الفريق.
نصيحتي الأخيرة لكم: ابدأوا اليوم. مع أول قرار معماري قادم، خذوا نصف ساعة إضافية لتوثيقه في ملف ADR. صدقوني، “أبو عمر” المستقبلي في فريقكم، و”خالد” الجديد الذي سينضم إليكم بعد سنتين، سيدعون لكم. بالتوفيق يا جماعة. 🙏