Composition API مقابل Options API في Vue 3 لمكتبات مكونات كبيرة
Vue 3 Composition API مقابل Options API: كيف يؤثر كل منهما على إعادة الاستخدام، الاختبار، وتأهيل المساهمين لمكتبات مكونات إدارية كبيرة.

لماذا هذا الاختيار مهم في مكتبات مكونات إدارة كبيرة
مكتبة مكونات كبيرة في تطبيق إدارة ليست موقع تسويقي يحتوي على بضعة أزرار. إنها مجموعات بناء عشرات (أو مئات) التي تتكرر عبر الشاشات: جداول بيانات مع ترتيب وإجراءات جماعية، لوحات فلترة، نماذج بقواعد تحقق، أدراج وحوارات، سير تأكيد، وأدوات صغيرة مثل منتقيات التواريخ وحراس الأذونات.
لأن هذه الأنماط تظهر في كل مكان، غالبًا ما يقوم الفرق بنسخ وتعديل الشيفرة للوفاء بالمواعيد. تحصل لوحة على شريط فلترة مخصّص، وأخرى تحصل على شريط مختلف قليلًا، وسرعان ما تملك خمس نسخ "قريبة من نفس الشيء". هنا يتوقف سؤال Composition API مقابل Options API عن كونه تفضيلًا شخصيًا ويبدأ بالتأثير على صحة المكتبة ككل.
ما ينهار أولًا عادةً هو الاتساق. الواجهة لا تزال تعمل، لكن السلوك ينزلق: حوار يغلق بالضغط على Escape في مكان ولا يغلق في مكان آخر؛ نفس حقل النموذج يتحقق عند فقدان التركيز في صفحة وعند الإرسال في أخرى. بعد ذلك تنخفض السرعة لأن كل تغيير يتطلب البحث عبر نسخ شبه مكررة. وأخيرًا يتلاشى الثقة: الناس يتجنبون إعادة الهيكلة لأنهم لا يستطيعون توقع ما الذي سيتأثر.
ثلاثة قرارات عملية تهم في مكتبة مشتركة:
- إعادة استخدام الشيفرة: كيف تعبئ المنطق المشترك بدون تبعيات متشابكة.
- الاختبارات: مدى سهولة التحقق من السلوك بدون اختبارات هشة ومكثفة على الواجهة.
- التأهيل: مدى سرعة قدرة المساهم الجديد على قراءة مكوّن وإجراء تغيير آمن.
مثال بسيط: لو أن لوحة الإدارة لديك تحتوي 20 صفحة قوائم، وطلب المنتج ميزة "المرشحات المحفوظة". إذا كانت منطق الجداول والمرشحات ومزامنة العنوان منتشرًا وغير متناسق، فإما ستسلمها ببطء أو ستسلمها بها أخطاء. نمط الـ API الذي تختاره يشكل ما إذا كان ذلك المنطق يعيش في مكان قابل لإعادة الاستخدام، ومدى وضوح اتصاله بكل شاشة، ومدى سهولة امتداده لشخص جديد.
إذا كنت تبني تطبيقات إدارة Vue 3 (بما في ذلك الفرق التي تستخدم Vue 3 داخل منصات مثل AppMaster لطبقة واجهة الويب)، فإن اتخاذ هذا الاختيار مبكرًا يمكن أن يوفر شهورًا من الصيانة لاحقًا.
كيف تختلف Options و Composition في الشيفرة اليومية
أسرع طريقة لتلمس الفرق هي فتح مكوّن إدارة كبير وطرح السؤال: "أين أغيّر السلوك لهذه الميزة؟" في مكتبة مكونات، يظهر هذا السؤال يوميًا.
مع Options API، تُجمّع الشيفرة حسب النوع: data للحالة، methods للإجراءات، computed للقيم المشتقة، وwatch للتأثيرات الجانبية. هذا الهيكل سهل المسح عندما يكون المكوّن صغيرًا. في مكوّن جدول أو نموذج كبير، كثيرًا ما ينتهي منطق ميزة واحدة (مثل الإجراءات الجماعية أو تحقق الحقل) موزّعًا عبر عدة كتل. يمكنك إبقاؤه مرتبًا، لكنه يتطلب انضباطًا وتسمية متسقة لتجنّب سير عمل "التنقّل عبر الملف".
مع Composition API، تُجمّع الشيفرة عادةً بحسب الميزة. تُعرّف الحالة ذات الصلة، القيم المشتقة، التأثيرات الجانبية، والمساعدين بجانب بعضهم، ويمكنك سحب المنطق المتكرر إلى composables. في مكتبة على نمط الإدارة، يتطابق هذا غالبًا مع طريقة تفكير الناس: "كل شيء عن الفلترة هنا"، "كل شيء عن اختيار الصف هنا". كما يمكن أن يقلل التكرار بين مكونات متشابهة، مثل إعادة استخدام usePagination عبر عدة جداول.
فرق يومي كبير هو كيف تظهر التبعيات.
- قد يبدو Options API أكثر ضمنية: قد تعتمد دالة على
this.userوthis.filtersوthis.loading، ولا تعرف ذلك إلا بقراءة داخل الدالة. - تميل Composition API لأن تكون أكثر صراحة: عندما تغلق دالة على
filtersوloadingترى تلك المتغيرات معرفة بالقرب، ويمكنك تمريرها إلى دوال مساعدة عند الحاجة.
المقايضة هي أن Composition API قد يصبح صاخبًا إذا أُلقيت كل الأشياء في setup() واحد دون بنية.
قاعدة عملية:
- اختر Options API عندما تكون المكونات عرضية في الغالب ومنطقها خفيف.
- اختر Composition API عندما تحتوي المكونات على ميزات متعددة وقواعد مشتركة عبر المكتبة.
- إذا اخترت Composition API، اتفق على تخطيط بسيط يجمع الشيفرة بحسب الميزة (وليس "كل refs أولًا").
- إذا اخترت Options API، فرض التسمية وحافظ على منطق ذي صلة معًا بتعليقات قصيرة وأسماء دوال متسقة.
كِلاهما يمكن أن يعمل. المفتاح هو اختيار أسلوب التنظيم الذي يجعل التغيير التالي واضحًا وليس ذكيًا بشكل مفرط.
إعادة الاستخدام: ما الذي يتوسع بشكل نظيف وما الذي يصبح فوضويًا
في تطبيقات الإدارة، إعادة الاستخدام ليست ترفًا. تكرر نفس السلوك عبر عشرات الشاشات، وعدم الاتساق الصغير يتحول إلى أخطاء وتذاكر دعم.
معظم احتياجات إعادة الاستخدام تقع في عدة صناديق متكررة: الترتيب/الفلترة/الترقيم المطابق للـ backend، تحقق النماذج وتخطيط الأخطاء، فحوصات الأذونات وإغلاق الواجهة، مزامنة الاستعلام (معلمات العنوان، العروض المحفوظة، الفلاتر الافتراضية)، والإجراءات الجماعية مع قواعد اختيار الصفوف.
إعادة الاستخدام في Options API: قوي، لكن يسهل إخفاء التعقيد
مع Options API، يبدأ إعادة الاستخدام غالبًا بالـ mixins، extends، أو الإضافات (plugins).
الـ mixins سريعة، لكنها تتوسع سيئًا لأنها تخفي من أين جاءت دالة أو قيمة محسوبة. يمكن أن تصطدم mixins اثنتان باسم دالة واحد بصمت، والآن تبحث عن سلوك غير مرئي داخل ملف المكوّن.
قد تبدو extends أنظف من mixins، لكنها ما زالت تخلق ألغاز توريث حيث عليك قراءة عدة ملفات لتفهم ما يفعله المكوّن حقًا. تعمل الإضافات جيدًا للهموم على مستوى التطبيق (diretives عالمية، خدمات مشتركة)، لكنها ليست مكانًا رائعًا لقواعد العمل التي تختلف بحسب الشاشة.
اللحظة الفوضوية عادةً تصل عندما يصبح إعادة الاستخدام ضمنيًا. لا يستطيع المساهمون الجدد الإجابة على "من أين تأتي هذه البيانات؟" دون البحث في كل قاعدة الشيفرة.
إعادة الاستخدام في Composition API: composables تظل صريحة
إعادة الاستخدام في Composition API تُبنى عادة حول composables: دوال صغيرة تُعيد refs وقيم محسوبة ومعالجات. المكسب الكبير هو أن إعادة الاستخدام تصبح مرئية بالقرب من أعلى المكوّن، ويمكنك تمرير معطيات بدل الاعتماد على سياق المكوّن المخفي.
على سبيل المثال، يمكن أن يقبل usePagination افتراضات ويصدر التغييرات بشكل متسق، بينما usePermissions يمكن أن يقبل الدور الحالي واسم الميزة. عند هذه النقطة، يصبح الخيار أقل عن الصياغة وأكثر عن ما إذا كانت مكتبتك تفضّل التوصيل الصريح على الوراثة الضمنية.
للحفاظ على إعادة استخدام متوقعة، عامل كل وحدة قابلة لإعادة الاستخدام كواجهة صغيرة: امنحها اسمًا واضحًا، حدد المدخلات والمخرجات، واجعل لها مسؤولية واحدة. إذا بدأ composable بالتعامل مع الترقيح، التخزين المؤقت، الأذونات، والإشعارات، فقم بتقسيمه. من الأسهل استبدال جزء واحد لاحقًا دون كسر كل شيء.
بناء مكونات نماذج وجداول قابلة لإعادة الاستخدام بدون ألم
في تطبيقات الإدارة، تكون النماذج والجداول حيث إما تدفع المكتبة ثمنها أو تتحول إلى متاهة. كلا الأسلوبين يمكن أن يعمل. الاختلاف في كيفية تعبئة السلوك المشترك مثل حالة "قذر"، تخطيط الأخطاء، وسير الإرسال دون جعل كل مكوّن "خاصًا".
بالنسبة لمنطق النماذج المشترك، عادةً ما يدفعك Options API نحو mixins أو مساعدات مشتركة. قد تكون mixins مريحة في البداية، لكن لاحقًا يصبح من الصعب الإجابة على أسئلة بسيطة: "من أين يأتي خطأ هذا الحقل؟" أو "لماذا تم تعطيل الزر إرسال؟"
يجعل Composition API هذا النوع من إعادة الاستخدام أكثر وضوحًا لأنك تنقل المنطق إلى composables (على سبيل المثال، useDirtyState, useFormErrors, useSubmitFlow) وترى بالضبط ما يستدعيه مكوّن النموذج. في مكتبة كبيرة، غالبًا ما تهم هذه الوضوح أكثر من حفظ بضعة أسطر.
طريقة عملية للحفاظ على واجهات مكونات مستقرة هي اعتبار السطح العام عقدة: props، emits، وslots يجب أن تتغير نادرًا، حتى لو أعدت كتابة الداخل. تبدو هذه العقدة نفسها في كلا الأسلوبين، لكن Composition API غالبًا ما يجعل إعادة الهيكلة أكثر أمانًا لأنك تستطيع استبدال composable واحد في كل مرة دون لمس قالب الـ template.
أنماط تبقى عاقلة مع نمو المكتبة:
- ابنِ مكونات أساسية تؤدي وظيفة واحدة جيدًا (BaseInput, BaseSelect, BaseTable)، ثم ركّبها في مكونات ميزة.
- فضّل الـ slots لمرونة التخطيط (منطقة الإجراءات، حالات الفراغ، رندر الخلايا) بدل إضافة props لكل حالة حافة.
- طبيع الأحداث مبكرًا (مثل
update:modelValue,submit,rowClick) حتى لا تعتمد التطبيقات على تفاصيل داخلية. - احتفظ بالتحقق والتنسيق قريبًا من المدخلات، لكن ضع قواعد العمل خارجها (في composables أو مكوّنات الحاوية).
التعمية الزائدة هي الفخ الشائع. مكوّن "نموذج سوبر" يتعامل مع كل نوع حقل، كل قاعدة تحقق، وكل خيار تخطيط غالبًا ما يصبح أصعب استخدامًا من Vue العادي. قاعدة جيدة: إذا احتاج مكوّن أساسي إلى أكثر من عدد قليل من props ليغطي حاجات الفرق كلها، فقد يكون مكونين.
أحيانًا التكرار هو الخيار الصحيح. إذا كانت شاشة واحدة فقط تحتاج رأس جدول غريب بتجميع متعدد الصفوف، انسخ قطعة صغيرة واجعلها محلية. التجريدات الذكية لها ذيل صيانة طويل، خاصة عندما ينضم مساهمون جدد ويحاولون فهم الفرق بين المكونات "العادية" وإطار عمل داخل إطار العمل.
إذا كنت تقرر بين Composition و Options لمكتبة كبيرة من النماذج والجداول، حسّن قابلية قراءة تدفق البيانات أولًا. إعادة الاستخدام جيد، لكن ليس عندما يخفي المسار من فعل المستخدم إلى الحدث المرسل.
تأثير الاختبارات: ما الذي يصبح أسهل للتحقق
في مكتبة مكونات، عادةً تقسم الاختبارات لثلاث فئات: المنطق النقي (التنسيق، التحقق، الفلترة)، العرض (ما يظهر لحالة معينة)، والتفاعلات (نقرات، إدخال، لوحة مفاتيح، الأحداث المرسلة). نمط الـ API الذي تختاره يغير عدد المرات التي تستطيع فيها اختبار الفئة الأولى دون تركيب مكوّن كامل.
تميل اختبارات Options API إلى الظهور كـ "ركّب المكوّن، عدّل حالة النسخة، أكد DOM". هذا يعمل، لكنه قد يشجع اختبارات أكبر لأن المنطق مختلط في methods, computed, watch، و lifecycle hooks. عندما يفشل شيء، تمضي وقتًا في معرفة ما إذا كانت مشكلة توقيت watcher أو تأثير lifecycle أو المنطق نفسه.
يزوّج Composition API الميزان. إذا نقلت المنطق إلى composables، يمكنك اختبار هذا المنطق كوحدات دوال عادية، بمدخلات صغيرة ومخرجات واضحة. هذا يقلل عدد اختبارات "الركوب والنقر" المطلوبة، ويجعل الفشل محليًا أكثر. كما يجعل التبعيات أسهل للتحكم: بدلًا من محاكاة global، تمرر اعتمادًا (مثل دالة fetch، منسق تاريخ، أو فاحص أذونات) إلى composable.
مثال ملموس: AdminTable قابل لإعادة الاستخدام مع ترتيب، ترقيم، وصفوف محددة. مع Composition API، يمكن أن يعيش منطق الاختيار في useRowSelection() ويُختبر دون عرض الجدول إطلاقًا (تبديل، مسح، اختيار الكل، الحفاظ عبر الصفحات). بعدها تحتفظ بمجموعة أصغر من اختبارات المكوّن لتأكيد أن القالب يربط الأزرار، مربعات الاختيار، والأحداث المرسلة بشكل صحيح.
للحفاظ على اختبارات صغيرة ومقروءة (بغض النظر عن الأسلوب):
- ضع قواعد العمل في دوال نقية أو composables، وليس في watchers.
- احتفظ بالتأثيرات الجانبية (fetch، التخزين، المؤقتات) خلف تبعيات قابلة للحقن.
- فضّل بعض اختبارات التكامل المركزة لكل مكوّن، لا اختبار عملاق واحد لكل شيء.
- سمّ الحالات والأحداث باستمرار عبر المكتبة (هذا يقلل إعداد الاختبار).
- تجنّب الاقتران الخفي (مثل اعتماد دالة A على تشغيل watcher B).
إذا كان هدفك قرارًا يحسّن استقرار الاختبارات، اتجه إلى سلوكيات أقل اعتمادًا على lifecycle ووحدات منطق معزولة تستطيع التحقق منها دون DOM.
تأهيل المساهمين الجدد: مدى سرعة الناس ليصبحوا منتجين
في مكتبة مكونات إدارة كبيرة، التأهيل أقل عن تعليم Vue وأكثر عن مساعدة الناس في العثور على الأشياء، اتباع نفس الاتفاقيات، والشعور بالأمان عند إجراء تغييرات. معظم البطء يأتي من ثلاث فجوات: التنقّل (أين المنطق؟)، الاتفاقيات (كيف نفعل هنا؟)، والثقة (كيف أغير هذا دون كسر خمس شاشات؟).
مع Options API، عادةً يبدأ القادمون بالتحرك أسرع في اليوم الأول لأن البنية مألوفة: props، data، computed، methods، watchers. المقايضة أن السلوك الحقيقي غالبًا ما يكون منتشرًا. ميزة واحدة مثل "الفلترة على الخادم" قد تنقسم بين watcher، computed، ودالتين، بالإضافة إلى mixin. يستطيع الناس قراءة كل كتلة، لكنهم يقضون وقتًا في نسج القصة معًا.
مع Composition API، ميزة التأهيل هي أن المنطق ذي الصلة يمكن أن يجلس معًا: الحالة، التأثيرات الجانبية، والمساعدين في مكان واحد. التكلفة هي إلمام الـ composables. يحتاج المساهمون الجدد لفهم أنماط مثل useTableState() وكيف تتدفق القيم التفاعلية عبر عدة composables. بدون حدود واضحة، قد يشعرون وكأنهم يقفزون بين ملفات دون خريطة.
بعض الاتفاقيات تزيل معظم الأسئلة، أيًا كان الأسلوب:
- استخدم هيكلًا متوقعًا:
components/,composables/,types/,tests/. - اختر نمط تسمية والتزم به (مثل:
useX,XTable,XForm). - أضف docblocks قصيرة: ما الذي يفعله المكوّن، props الأساسية، والأحداث الرئيسية.
- عرّف قاعدة "مخرج الطوارئ" واحدة (متى يجوز إضافة composable أو مساعد جديد).
- احتفظ بمكوّن "ذهبي" صغير يُظهر النمط المفضل.
مثال: إذا كان فريقك يولّد لوحة إدارة Vue 3 ثم يخصّصها (مثل تطبيق ويب مبني على AppMaster وموسّع من قبل المطورين)، يتحسّن التأهيل كثيرًا عندما يوجد مكان واحد واضح لتعديل سلوك الجدول (الترتيب، الفلاتر، الترقيم) ومكان واضح لتعديل ربط الواجهة (slots، عارضو الأعمدة، إجراءات الصف).
هذه الوضوح أهم من الـ API الذي تختاره.
خطوة بخطوة: اختيار نمط وتقديمه بأمان
للمكتبة الكبيرة، الطريقة الأكثر أمانًا لحسم السؤال هي البدء بميزة محكمة النطاق ومعاملتها كمشروع تجريبي لا كإعادة كتابة شاملة.
اختر وحدة واحدة ذات سلوك واضح وإعادة استخدام عالية، مثل فلترة الجداول أو تحقق النماذج. قبل أن تلمس الشيفرة، اكتب ما تفعله اليوم: المدخلات (props، معلمات الاستعلام، أفعال المستخدم)، المخرجات (الأحداث، الـ emits، تغييرات العنوان)، والحالات الحافة (حالة الفراغ، إعادة الضبط، أخطاء الخادم).
بعد ذلك حدّد الحدود. قرّر ما الذي يجب أن يبقى داخل المكوّن (العرض، أحداث DOM، تفاصيل الوصول) وما الذي يمكن نقله إلى شيفرة مشتركة (تحليل الفلاتر، debouncing، بناء معلمات API، الحالة الافتراضية). هنا غالبًا ما يخطئ الفرق: إذا نقلت قرارات الواجهة إلى شيفرة مشتركة، تصعّب إعادة الاستخدام.
خطة تطبيق عملية:
- اختر مكوّنًا واحدًا يظهر النمط بوضوح ويُستخدم عبر شاشات متعددة.
- استخرج وحدة مشتركة واحدة (composable أو مساعد عادي) بواجهة صغيرة وصريحة.
- أضف اختبارًا مُركّزًا لتلك الوحدة أولًا، مستندًا إلى سيناريوهات إدارة حقيقية.
- أعد بناء المكوّن المختار من البداية إلى النهاية باستخدام الوحدة الجديدة.
- طبّق نفس النمط على مكوّن آخر لتأكيد أنه يتوسع.
اجعل واجهة الوحدة المشتركة مملة وواضحة. على سبيل المثال، قد يقبل useTableFilters() فلاتر ابتدائية ويُعرّض filters, apply(), reset(), ودالة toRequestParams(). تجنّب السحر الذي يقرأ من حالة عالمية إلا إذا كان ذلك قاعدة ثابتة في تطبيقك.
بعد التجربة، انشر إرشادات داخلية قصيرة مع مثال واحد يمكن للمساهمين نسخه. قاعدة واحدة ملموسة تتغلب على وثيقة طويلة، مثل: "كل منطق فلترة الجدول يعيش في composable؛ المكونات تربط عناصر الواجهة وتنادي apply() فقط."
قبل التوسيع، استخدم تعريفًا بسيطًا للإنجاز:
- الكود الجديد يُقرأ بنفس الطريقة عبر مكوّنين مختلفين.
- الاختبارات تغطي المنطق المشترك دون تركيب الواجهة كاملة.
- يمكن لمساهم جديد تغيير قاعدة فلترة دون لمس ملفات غير ذات صلة.
إذا كان فريقك يبني أيضًا لوحات إدارة عبر أداة بدون كود مثل AppMaster، يمكنك استخدام نفس عقلية المشروع التجريبي هناك: اختر سير عمل واحد (مثل الموافقات)، حدّد السلوكيات، ثم قسّم النمط قبل توسيعه عبر المنتج.
أخطاء شائعة وفخاخ في المكتبات الكبيرة
أكبر المشاكل في مكتبة مكونات كبيرة نادرًا ما تكون متعلقة بالصياغة. إنها ناتجة عن قرارات محلية صغيرة تتراكم وتجعل إعادة الاستخدام، الاختبار، والصيانة أصعب.
أحد الفخاخ الشائعة هو خلط الأنماط عشوائيًا. إذا كان نصف المكتبة يستخدم Options API والنصف الآخر Composition API بلا قاعدة، يصبح كل مكوّن جديد نقاشًا حول الأسلوب. كما ينتهي بك الأمر بحلول مكررة لنفس المشاكل (نماذج، جداول، أذونات) مكتوبة بأشكال مختلفة. إذا سمحت بكلا الأسلوبين، اكتب سياسة واضحة: المكونات الجديدة تستخدم نمطًا واحدًا، القديم يُلمس فقط عند الضرورة، والمنطق المشترك يعيش في مكان متفق عليه.
فخ آخر هو "composable الإله". يبدأ عادةً كمساعد مفيد useAdminPage() أو useTable() ثم يمتص التوجيه، الجلب، التخزين المؤقت، الاختيار، الحوارات، التنبيهات، والأذونات. يصبح صعب الاختبار لأن نداءً واحدًا يطلق آثارًا جانبية متعددة. كما يصبح صعب إعادة الاستخدام لأن كل شاشة تحتاج 30% منه لكنها تدفع تكلفة التعقيد 100%.
الـ watchers مصدر ألم آخر. من السهل إضافتهم عندما يبدو شيء غير متزامن، لكن أخطاء التوقيت تظهر لاحقًا (خصوصًا مع البيانات غير المتزامنة وحقول مدخلة مع تأخير). عندما يشتكي المستخدمون "أحيانًا تُمسح اختياراتي"، قد تضيع ساعات في محاولة إعادة إنتاج الخطأ.
علامات حمراء عادةً تعني أن المكتبة تتجه نحو المشاكل:
- مكوّن يعمل فقط عندما يُستخدم بترتيب محدد من props وevents.
- composable يقرأ ويكتب حالة عالمية دون وضوح.
- عدة watchers تحدث نفس القطعة من الحالة.
- إعادة الهيكلة تستمر بكسر شاشات المستهلكين بطرق صغيرة.
- يتجنب المساهمون لمس "ذلك الملف" لأنه يبدو مخاطرة.
الفخ الأخير هو كسر واجهة المكوّن العامة أثناء إعادة الهيكلة. في تطبيقات الإدارة، تنتشر مكونات مثل الجداول، المرشحات، وحقول النماذج بسرعة. إعادة تسمية prop، تغيير حدث مرسل، أو تعديل سلوك slot قد يكسر عشرات الشاشات بصمت.
نهج أكثر أمانًا هو معاملة واجهات المكونات كعقود: وضع إهمال بدل حذف، الحفاظ على شَجَرات التوافق لفترة، وإضافة اختبارات استخدام بسيطة تُركّب المكوّن بالطريقة التي يستخدمها المستهلكون. إذا كنت تبني واجهات إدارة Vue 3 مُولّدة بأدوات مثل AppMaster، فالأمر أكثر أهمية لأن عقود المكونات المتسقة تسهّل إعادة استخدام الشاشات والمحافظة على التنبؤ بالتغييرات.
فحوصات سريعة قبل الالتزام بنمط
قبل اختيار Composition API أو Options API أو مزيج، قم ببعض الفحوصات السريعة على مكونات حقيقية من مكتبتك. الهدف بسيط: اجعل من السهل العثور على المنطق، أعد استخدامه بأمان، واختبر الأجزاء التي يعتمد عليها المدراء فعليًا.
1) هل يستطيع شخص ما العثور على المنطق بسرعة؟
افتح مكوّنًا نموذجيًا غنيًا بالإدارة (مرشحات + جدول + أذونات + إجراءات جماعية). الآن تخيّل أنك جديد في قاعدة الشيفرة.
إشارة جيدة هي أن يستطيع المساهم الإجابة على "أين منطق الفلاتر؟" أو "ما الذي يقرر إذا كان الزر معطلاً؟" في أقل من دقيقتين. مع Options API، عادةً يعني هذا أن المنطق مُقسم بوضوح عبر computed, methods, وwatchers. مع Composition API، يعني أن setup() منظم إلى كتل صغيرة مسمّاة (أو composables) ويتجنّب دالة واحدة عملاقة.
2) هل تعمل الأدوات المشتركة كدوال، لا كسحر؟
مهما كان النمط، يجب أن تكون الشيفرة المشتركة ذات مداخل ومخارج واضحة وآثار جانبية قليلة. إذا كان مساعد يصل إلى الحالة العالمية، يغيّر كائنات مرّرها، أو يطلق طلبات شبكة بدون وضوح، يصبح إعادة الاستخدام مخاطرة.
فحص سريع:
- هل يمكنك قراءة توقيع composable أو المساعد وتخمين ما يعيده؟
- هل يمكنك استخدامه في مكوّنين دون إعداد خفي؟
- هل يمكنك إعادة ضبط حالته في الاختبارات بدون حيل؟
3) هل اختباراتكم مركزة على سلوكيات الإدارة؟
تفشل تطبيقات الإدارة بطرق متوقعة: تطبيق الفلاتر خاطئ، تسرب الأذونات، تحقق النماذج غير متسق، وحالة الجدول تنهار بعد تعديلات. بدلاً من اختبار تفاصيل التنفيذ الداخلية (watchers مقابل refs)، اكتب اختبارات حول السلوك: "مع الدور X، الإجراء Y مخفي"، "الحفظ يظهر خطأ ويحتفظ بإدخال المستخدم"، "تغيّر الفلتر يحدث تحديث الاستعلام ورسالة الفراغ". هذا يبقي الاختبارات مستقرة حتى لو أعِدت كتابة النمط لاحقًا.
4) هل لديكم معيار لحالة الـ async؟
تكبر المكتبات لتضم تدفقات async صغيرة عديدة: تحميل الخيارات، التحقق من الحقول، جلب صفوف الجدول، إعادة المحاولة عند الفشل. إذا اخترع كل مكوّن شكلًا خاصًا لـ loading/error، يصبح التأهيل وتصحيح الأخطاء بطيئًا.
اختر شكلًا واضحًا واحدًا لحالة async (loading, error, retries, cancellation). Composition API غالبًا ما يشجع على useAsyncX() قابلة لإعادة الاستخدام، بينما يمكن لـ Options API توحيد data() وحزم طرق مشتركة. كلاهما جيد إذا كان متسقًا.
5) هل واجهات مكوناتكم العامة مستقرة وتشرح نفسها؟
عامل المكونات كمنتجات. props، الأحداث المرسلة، والـ slots هي العقدة. إذا تغيرت تلك العقدة كثيرًا، تصبح كل شاشة إدارة هشة.
ابحث عن تعليقات تشرح النية (ليس الآليات): ما معنى props، ما الأحداث المضمونة، وما الذي يعتبر داخليًا. إذا كنت تبني أدوات داخلية مع منصة مثل AppMaster، تساعد هذه العقلية أيضًا: لبنات بناء ثابتة تجعل الشاشات المستقبلية أسرع في الشحن.
سيناريو مثال وخطوات قادمة لفريقك
تخيّل صفحة "المستخدمون" تقوم بإعادة بنائها: شريط فلترة (الحالة، الدور، تاريخ الإنشاء)، جدول مع صفوف قابلة للاختيار، إجراءات جماعية (تعطيل، حذف، تصدير)، والتحكم بحسب الدور (فقط المسؤولون يمكنهم الحذف الجماعي، المديرون يمكنهم تعديل الأدوار).
مع Composition API مقابل Options API، الواجهة قد تبدو نفسها، لكن الشيفرة تميل للترتيب بشكل مختلف.
في Options API، كثيرًا ما ينتهي بك الأمر بمكوّن واحد كبير يحتوي data للفلاتر والاختيار، computed للحالات المشتقة، وmethods للجلب، الإجراءات الجماعية، وفحوصات الأذونات. يظهر إعادة الاستخدام عادةً كـ mixins أو وحدات مساعدة مشتركة. إنه مألوف، لكن قد يصبح المنطق ذي الصلة منتشرًا (الجلب في methods، مزامنة الاستعلام في watchers، الأذونات في computed).
في Composition API، عادةً تقسم الصفحة إلى composables مركزة: واحدة للـ query والفلترة، واحدة لاختيار الصفوف والإجراءات الجماعية، وواحدة للأذونات. يصبح مكوّن الصفحة تجميعًا لهذه الأجزاء، ويظل منطق كل قلق معًا. المقايضة هي أنك تحتاج إلى تسمية ومجلدات واضحة حتى لا يشعر المساهمون أن كل شيء "سحر في setup".
يتجلّى إعادة الاستخدام بطبيعة الحال في مكتبات الإدارة حول الفلاتر المتزامنة مع العنوان، أنماط الجداول على الخادم (ترقيم، ترتيب، اختيار الكل، حراس الإجراءات الجماعية)، فحوصات الأذونات وإغلاق الواجهة، وحالات الفراغ/التحميل المتسقة عبر الصفحات.
خطة خطوات مقترحة لمعظم الفرق:
- اختر نمطًا افتراضيًا للكود الجديد، اسمح بالاستثناءات فقط مع سبب مكتوب.
- حدّد اتفاقيات: أين تعيش composables، كيف تُسمّى، ما الذي يجوز استيراده، وماذا يجب أن تُرجع.
- أضف صفحة مرجعية صغيرة (مثل صفحة Users هذه) كنموذج ذهبي للأنماط والبنية.
- اكتب اختبارات حول الأجزاء القابلة لإعادة الاستخدام أولًا (الفلاتر، الأذونات، الإجراءات الجماعية)، وليس حول التخطيط البصري.
- إذا كانت السرعة أهم من التخصيص العميق لشاشات معينة، فكّر في توليد تلك الشاشات بأداة بدون كود مثل AppMaster، وركّز مكتبتك اليدوية على الأجزاء الفريدة حقًا.
إذا كنتم تبنون بالفعل مع AppMaster، يساعد الحفاظ على نفس النموذج الذهني بين الأجزاء المولّدة والمكتوبة يدويًا: عقود مكونات ثابتة ومنطق مشترك معبأ كوحدات صغيرة وصريحة. بالنسبة للفرق التي تقيم بدون كود للأدوات الداخلية، تُبنى AppMaster (appmaster.io) لتوليد تطبيقات كاملة (backend، ويب، وموبايل) مع السماح لك بتوحيد واجهة Vue 3 حيث يهم.
إذا فعلت شيئًا واحدًا هذا الأسبوع، اجعل صفحة Users نموذجك وطبّقها في مراجعات الشيفرة. مثال واضح واحد يفعل أكثر للاتساق من دليل طويل.
الأسئلة الشائعة
افترض استخدام API التركيب (Composition API) إذا كانت مكتبتكم تحتوي سلوكيات متكررة مثل التصفية، الترقيح، الإجراءات الجماعية، وحواجز الأذونات. يجعل من السهل استخراج المنطق المشترك إلى composables ويبقي التبعيات صريحة. استخدم Options API عندما تكون المكونات عرضية في الغالب ومنطقها خفيف.
يقسم Options API الشيفرة بحسب النوع (data, methods, computed, watch)، لذا من الشائع أن ينتهي الأمر بمنطق ميزة واحدة موزّعًا عبر كتل متعددة. يميل Composition API إلى تجميع الشيفرة بحسب الميزة، بحيث يجتمع كل شيء متعلق بـ"المرشحات" أو "الاختيار" معًا. الخيار الأفضل هو الذي يجعل التغيير التالي سهلاً ويمكن العثور عليه بسرعة.
مع Options API، تبدأ إعادة الاستخدام غالبًا بالـ mixins أو extends، ما قد يخفي مصدر الدوال والقيم المحسوبة ويتسبب في تصادم أسماء. مع Composition API، يتحول هذا عادةً إلى composables بواجهات إدخال/إخراج واضحة، فتكون الأسلاك مرئية في المكوّن. في مكتبة مشتركة، يميل النهج الصريح إلى البقاء سهل الصيانة لفترة أطول.
عامل كل composable كواجهة API صغيرة: مسؤولية واحدة، معطيات واضحة، ومخرجات متوقعة. إذا بدأ composable بمزج الترقيح، التخزين المؤقت، الأذونات، والإشعارات، فقم بتقسيمه. composables الصغيرة أسهل للاختبار، لإعادة الاستخدام، ولمنع الآثار الجانبية غير المتوقعة.
حافظ على عقدة الواجهة العامة ثابتة: يجب أن تتغير الـ props، الـ emits، والـ slots نادرًا. ضع تنسيق الإدخال والتحقق الأساسي بالقرب من مكونات الحقل، لكن اجعل قواعد العمل في composables أو مكوّنات الحاوية. بهذه الطريقة يمكنك إعادة كتابة الداخل دون إجبار كل شاشة على التغيير.
عادةً يجعل Composition API اختبار المنطق أسهل دون تركيب مكوّن كامل، لأنك تختبر composables والدوال النقية مباشرة. Options API قد يدفعك للاختبار عبر تركيب المكوّن حيث تضيف المشغولات والـ lifecycle ضوضاء. بغض النظر عن النمط، فصل قواعد العمل عن ربط واجهة المستخدم هو ما يحافظ على الاختبارات صغيرة ومستقرة.
وحدد شكلًا واحدًا لحالة الـ async مثل loading, error، وطريقة واضحة لإعادة المحاولة أو الإلغاء. لا تقم لكل مكوّن بابتكار قواعد خاصة به، لأن ذلك يجعل تصحيح الأخطاء بطيئًا وغير متناسق. يمكنك تنفيذ المعيار بأي من الـ APIs طالما أنه مستخدم بشكل موحّد عبر المكتبة.
يُسهِل Options API على المبتدئين البدء سريعًا لليوم الأول لأن الهيكل مألوف: props، data، computed، methods، watchers. لكن السلوك الحقيقي غالبًا ما يكون منتشرًا. Composition API يمكن أن يكون أسرع بعد أن يتعلم الناس composables وبنية المجلدات لأن السلوك ذي الصلة مجمّع ومرئي. أكثر ما يحسّن الانضمام هو وجود مكوّن واحد "ذهبي" كمثال وفرض نفس الأنماط في مراجعات الشيفرة.
اختر ميزة محكمة النطاق وتُستخدم كثيرًا (مثل ترشيح الجداول أو مطابقة أخطاء النماذج) وعاملها كمشروع تجريبي. استخرج وحدة مشتركة واحدة بواجهة صغيرة وصريحة، اكتب اختبارًا مركزًا لها، ثم أعد بناء مكوّن واحد بالكامل باستخدامها. بعد أن تعمل في مكوّنين على الأقل، وسّع النمط تدريجيًا.
راقب التكرارات المتقاربة، سلاسل الـ watchers التي تتصارع، والمكوّنات التي تعمل فقط في ترتيب محدد من props وevents. علامات التحذير الأخرى: composable يقرأ ويكتب حالة عالمية بدون وضوح، أو تغييرات متكررة على props وevents وslots التي تكسر الشاشات. إذا تجنب المساهمون لمس ملفات معينة لأنها خطرة، فذلك علامة واضحة على الحاجة لعقود أوضح وإعادة تنظيم المنطق المشترك.


