دوال السحابة مقابل الواجهة الخلفية التقليدية: متى يكون النمط اللاخادمي منطقيًا
مقارنة واقعية بين الدوال اللاخادمية والواجهات الخلفية التقليدية - تغطي التكلفة، زمن الاستجابة، تجربة المطور، ومتى يتفوق كل نهج.

كل مشروع جديد أبدأه يفرض نفس القرار: هل أقوم بتشغيل خادم تقليدي أم أكتب دوال سحابية؟ بعد إطلاق أنظمة إنتاج على كلا الجانبين — Firebase Functions لسير العمل المعتمد على الأحداث، AWS Lambda لنقاط نهاية API، وخوادم Express/Fastify لكل ما بينهما — لدي رأي دقيق إلى حد ما حول متى يتفوق كل نهج بالفعل. الإجابة، كما هو متوقع، هي "يعتمد الأمر"، ولكن تفاصيل ما يعتمد عليه تستحق الاستكشاف بالتفصيل.
تعريف النهجين
قبل المقارنة، دعني أحدد بدقة ما أعنيه بكل منهما.
الواجهة الخلفية التقليدية تشير إلى عملية خادم طويلة الأمد — تطبيق Node.js Express، خادم Python FastAPI، خادم Go HTTP — يتم نشره على جهاز افتراضي (VM)، حاوية، أو منصة حوسبة مُدارة. تبدأ العملية، وتبقى قيد التشغيل، وتتعامل مع الطلبات فور وصولها. تشمل أهداف النشر EC2، Cloud Run، ECS، Railway، Fly.io، أو خادم افتراضي خاص (VPS) بسيط.
دوال السحابة (الدوال اللاخادمية) هي معالجات دوال فردية تُنفذ استجابةً للأحداث. تدير المنصة البنية التحتية للحوسبة بالكامل. يعمل رمزك، ويعيد استجابة، وقد يستمر بيئة التنفيذ أو لا تستمر للاستدعاء التالي. يشمل المزودون AWS Lambda، Google Cloud Functions، Firebase Functions، Azure Functions، و Cloudflare Workers.
التمييز لا يتعلق باللغة أو الإطار — بل يتعلق بنموذج التنفيذ. الواجهة الخلفية التقليدية تمتلك دورة حياة عمليتها. دالة السحابة لا تمتلك ذلك.
واقع البدء البارد
البدء البارد هو القيد الأكثر مناقشة في النمط اللاخادمي، والواقع في عام 2026 أكثر دقة مما يوحي به الخطاب.
ماذا يحدث فعليًا أثناء البدء البارد
عندما لا يتم استدعاء دالة سحابية مؤخرًا (أو عندما تتجاوز الاستدعاءات المتزامنة عدد المثيلات الدافئة المتاحة)، يجب على المنصة:
- توفير بيئة تنفيذ جديدة (جهاز افتراضي مصغر microVM أو حاوية)
- تنزيل واستخراج حزمة النشر الخاصة بك
- تهيئة وقت التشغيل (Node.js، Python، إلخ)
- تنفيذ رمز التهيئة الخاص بك (استيراد الوحدات، إعداد SDK، اتصالات قاعدة البيانات)
- تنفيذ معالج الدالة الفعلي
الخطوات 1-3 هي عبء المنصة. الخطوة 4 هي حيث تكون خيارات رمزك مهمة للغاية.
أرقام البدء البارد في الممارسة
فيما يلي أوقات البدء البارد التي قمت بقياسها عبر منصات وتكوينات مختلفة في مشاريع حقيقية:
| المنصة | وقت التشغيل | حجم الحزمة | البدء البارد |
|---|---|---|---|
| AWS Lambda | Node.js 20 | 5 ميجابايت | 250-400 مللي ثانية |
| AWS Lambda | Node.js 20 | 50 ميجابايت | 800-1200 مللي ثانية |
| AWS Lambda | Python 3.12 | 10 ميجابايت | 400-600 مللي ثانية |
| Firebase Functions v2 | Node.js 20 | 15 ميجابايت | 600-1000 مللي ثانية |
| Cloudflare Workers | JavaScript | 1 ميجابايت | 0-5 مللي ثانية |
| Google Cloud Functions v2 | Node.js 20 | 10 ميجابايت | 300-500 مللي ثانية |
تعتبر Cloudflare Workers استثناءً لأنها تستخدم V8 isolates بدلاً من الحاويات، مما يلغي تمامًا عقوبة بدء تشغيل الحاوية. المقايضة هي بيئة تشغيل أكثر تقييدًا.
التخفيف من البدء البارد
هناك العديد من الاستراتيجيات التي تساعد حقًا:
التزامن المخصص (Lambda): يحافظ على N من المثيلات دافئة في جميع الأوقات. يكلف 0.0000041667 دولار لكل جيجابايت-ثانية من السعة المخصصة. لدالة بحجم 256 ميجابايت، هذا حوالي 3.20 دولار/شهر لكل مثيل دافئ. يستحق ذلك لنقاط النهاية الحساسة لزمن الاستجابة.
الحد الأدنى من المثيلات (Cloud Run، Firebase Functions v2): نفس المفهوم، تسمية مختلفة. يفرض Cloud Run رسومًا على المثيلات الخاملة بسعر مخفض.
تقليل حجم الحزمة: هذا له أعلى نسبة تأثير إلى جهد. تقنية Tree-shaking، استبعاد تبعيات التطوير، واستخدام عملاء SDK أخف يقلل بشكل كبير من وقت التهيئة.
// سيء: يستورد حزمة AWS SDK بأكملها (يضيف 40 ميجابايت+ إلى الحزمة)
import AWS from 'aws-sdk';
// جيد: يستورد عميل S3 فقط (يضيف ~3 ميجابايت)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
التهيئة الكسولة: لا تنشئ اتصالات قاعدة البيانات أو تحمل موارد ثقيلة في نطاق الوحدة. قم بتهيئتها عند الاستدعاء الأول وإعادة استخدامها عبر الاستدعاءات الدافئة.
import { Pool } from 'pg';
let pool: Pool | null = null;
function getPool(): Pool {
if (!pool) {
pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 1, // اتصال واحد لكل مثيل Lambda
});
}
return pool;
}
export async function handler(event: APIGatewayEvent) {
const db = getPool();
const result = await db.query('SELECT * FROM users WHERE id = $1', [event.pathParameters?.id]);
return { statusCode: 200, body: JSON.stringify(result.rows[0]) };
}
مقارنة التكلفة على نطاقات مختلفة
التكلفة هي حيث يصبح الحديث مثيرًا للاهتمام، لأن الاقتصاد ينعكس مع تزايد حركة المرور.
حركة مرور منخفضة (1,000 - 50,000 طلب/يوم)
على هذا النطاق، يكون النمط اللاخادمي دائمًا أرخص تقريبًا. تقع العديد من الشركات الناشئة والمشاريع الجانبية هنا.
تكلفة Lambda لـ 30,000 طلب/يوم، بمتوسط مدة 200 مللي ثانية، وذاكرة 256 ميجابايت:
- رسوم الطلبات: 900 ألف طلب/شهر × 0.20 دولار/مليون = 0.18 دولار
- رسوم الحوسبة: 900 ألف × 0.2 ثانية × 0.25 جيجابايت × 0.0000166667 دولار = 0.75 دولار
- الإجمالي: ~1 دولار/شهر
خادم تقليدي مكافئ (t4g.small على AWS):
- عند الطلب: 12.26 دولار/شهر
- مع خطة توفير لمدة عام: ~8 دولار/شهر
عند حركة المرور المنخفضة، أنت تدفع مقابل خادم يعمل دائمًا ويكون خاملًا بنسبة 95%.
حركة مرور متوسطة (100,000 - 1,000,000 طلب/يوم)
هذه هي منطقة التقاطع حيث تصبح المقارنة متقاربة.
تكلفة Lambda لـ 500,000 طلب/يوم، بمتوسط 200 مللي ثانية، وذاكرة 256 ميجابايت:
- رسوم الطلبات: 15 مليون/شهر × 0.20 دولار/مليون = 3.00 دولار
- رسوم الحوسبة: 15 مليون × 0.2 ثانية × 0.25 جيجابايت × 0.0000166667 دولار = 12.50 دولار
- الإجمالي: ~15.50 دولار/شهر
t4g.medium (2 vCPU، 4 جيجابايت RAM):
- عند الطلب: 24.53 دولار/شهر
- مع خطة توفير: ~16 دولار/شهر
التكاليف قابلة للمقارنة، لكن الخادم التقليدي يتعامل مع هذه الحركة بوجود مساحة كبيرة. إذا كانت حركة المرور ثابتة، فإن الخادم أرخص قليلاً. إذا كانت حركة المرور متقطعة (كثيفة في أيام الأسبوع، دفعات تعتمد على الأحداث)، فإن فاتورة Lambda لكل استدعاء تعني أنك لا تدفع مقابل الفترات الهادئة.
حركة مرور عالية (5,000,000+ طلب/يوم)
على هذا النطاق، يكون النمط اللاخادمي دائمًا أكثر تكلفة لأعباء العمل المستمرة.
تكلفة Lambda لـ 5,000,000 طلب/يوم، بمتوسط 200 مللي ثانية، وذاكرة 512 ميجابايت:
- رسوم الطلبات: 150 مليون/شهر × 0.20 دولار/مليون = 30 دولار
- رسوم الحوسبة: 150 مليون × 0.2 ثانية × 0.5 جيجابايت × 0.0000166667 دولار = 250 دولار
- الإجمالي: ~280 دولار/شهر
c6g.large (2 vCPU، 4 جيجابايت RAM) مع مجموعة التوسع التلقائي:
- مثيلان مع خطة توفير: ~60 دولار/شهر
- مع موازن التحميل: ~16 دولار/شهر
- الإجمالي: ~76 دولار/شهر
النهج التقليدي أرخص 3.7 مرة على هذا النطاق، وتتسع الفجوة مع زيادة حركة المرور.
التكاليف الخفية التي يجب أخذها في الاعتبار
فاتورة Lambda ليست الصورة الكاملة. أضف API Gateway (1-3.50 دولار لكل مليون طلب)، CloudWatch Logs (0.50 دولار/جيجابايت مستهلكة)، وتتبع X-Ray إذا كنت تستخدمه. على الجانب التقليدي، أضف تكاليف موازن التحميل، والمراقبة، ووقت العمليات لإدارة المثيلات وعمليات النشر.
اختلافات تجربة المطور
تجربة المطور في النمط اللاخادمي
المزايا:
- لا توجد بنية تحتية لإدارتها (لا ترقيع، لا تكوين توسع)
- نشر كل دالة على حدة يعني نطاق تأثير أصغر
- التطوير المحلي باستخدام المحاكيات (Firebase Emulator Suite، SAM CLI، Serverless Framework offline)
- قابلية المراقبة المدمجة من خلال تسجيل المنصة وتتبعها
نقاط الضعف:
- التطوير المحلي لا يطابق تمامًا سلوك الإنتاج
- تصحيح أخطاء استدعاءات الدوال الموزعة بين الدوال أصعب من تتبع تطبيق متجانس
- قيود حجم النشر (Lambda: 250 ميجابايت غير مضغوطة) تقيد خيارات التبعيات
- تكوين IAM والأذونات مطول ومن السهل أن تخطئ فيه
- البدء البارد يجعل حلقات تكرار التطوير أبطأ عند الاختبار مقابل الدوال المنشورة
تجربة المطور في الواجهة الخلفية التقليدية
المزايا:
- بيئة التطوير المحلية هي بيئة الإنتاج (نفس العملية، نفس الحالة)
- تصحيح الأخطاء مباشر — قم بإرفاق مصحح أخطاء، وضع نقاط توقف، وتتبع الخطوات
- لا توجد قيود على حجم النشر
- أنماط Middleware، خطافات دورة حياة الطلب، ومعالجة الأخطاء الشاملة طبيعية
- دعم WebSocket، العمليات طويلة الأمد، والمهام الخلفية تعمل بدون خدمات إضافية
نقاط الضعف:
- أنت تمتلك دورة حياة البنية التحتية (التحديثات، التوسع، فحوصات الصحة)
- عمليات النشر تتطلب تنسيقًا (تحديثات متدحرجة، فترات سماح لفحص الصحة)
- التوسع يتطلب تكوينًا (مجموعات التوسع التلقائي، تنسيق الحاويات)
- المراقبة والتسجيل يتطلبان إعدادًا صريحًا
الفجوة بين الأطر تتقلص
لقد حسنت الأطر مثل SST (Serverless Stack) و Architect تجربة المطور في النمط اللاخادمي بشكل كبير. يوفر SST على وجه الخصوص وضع تطوير "Live Lambda" حيث يتعامل رمزك الذي يعمل محليًا مع استدعاءات Lambda في الوقت الفعلي، مما يلغي دورة النشر والاختبار بالكامل.
على الجانب التقليدي، قامت منصات مثل Railway، Fly.io، و Render بتبسيط النشر إلى git push. لقد انخفض عبء العمليات لتشغيل واجهة خلفية تقليدية بشكل كبير.
متى يتفوق النمط اللاخادمي
أعباء العمل المعتمدة على الأحداث
إذا كان رمزك يعمل استجابةً للأحداث — تحميل الملفات، تغييرات قاعدة البيانات، رسائل قائمة الانتظار، المهام المجدولة — فإن النمط اللاخادمي هو الأنسب. أنت لا تحتفظ بحلقة استقصاء أو عملية استماع. تقوم المنصة بتشغيل رمزك بالضبط عند الحاجة.
// Firebase Functions: يتم تشغيله عند إنشاء مستند Firestore
import { onDocumentCreated } from 'firebase-functions/v2/firestore';
export const onOrderCreated = onDocumentCreated('orders/{orderId}', async (event) => {
const order = event.data?.data();
if (!order) return;
// إرسال بريد إلكتروني للتأكيد
await sendEmail(order.customerEmail, {
template: 'order-confirmation',
data: { orderId: event.params.orderId, items: order.items },
});
// تحديث المخزون
await updateInventory(order.items);
// إخطار المطعم
await sendPushNotification(order.restaurantId, {
title: 'New Order',
body: `Order #${event.params.orderId} received`,
});
});
حركة مرور متقطعة أو غير متوقعة
أداة داخلية تتلقى 50 طلبًا صباح يوم الاثنين وطلبين في بقية الأسبوع. مستقبل webhook يعالج الأحداث من API لجهة خارجية. مولد تقارير مجدول يعمل لمدة 30 ثانية مرة واحدة في اليوم. هذه الأعباء لها تكلفة شبه صفرية على النمط اللاخادمي وتهدر المال على بنية تحتية تعمل دائمًا.
نقاط نهاية API ذات حركة مرور منخفضة إلى متوسطة
بالنسبة لواجهة برمجة تطبيقات (API) لمنتج الحد الأدنى القابل للتطبيق (MVP) لشركة ناشئة تخدم بضعة آلاف من الطلبات يوميًا، يوفر النمط اللاخادمي واجهة خلفية وظيفية بأقل قدر من الأعباء التشغيلية وتكلفة شبه صفرية. يمكنك التركيز بالكامل على منطق العمل.
معالجة البيانات المتوازية
هل تحتاج إلى معالجة 10,000 صورة، أو تحويل 500 فيديو، أو تشغيل تحليلات على مجموعة بيانات كبيرة؟ قم بالتوزيع على آلاف استدعاءات Lambda المتزامنة، وقم بالمعالجة بالتوازي، وادفع فقط مقابل وقت الحوسبة المستخدم. يتطلب تحقيق نفس التوازي مع الخوادم التقليدية توفير (والدفع مقابل) تلك السعة القصوى.
متى تتفوق الواجهات الخلفية التقليدية
الاتصالات المستمرة
تتطلب اتصالات WebSocket، و Server-Sent Events، وتدفقات gRPC، و long-polling جميعها اتصالًا مستمرًا بين العميل والخادم. دوال Lambda لديها حد تنفيذ يبلغ 15 دقيقة وليست مصممة للاتصالات طويلة الأمد.
يمكنك تجاوز هذا باستخدام API Gateway WebSocket APIs أو AWS IoT Core، ولكن التعقيد والتكلفة غالبًا ما تتجاوز خادم WebSocket بسيط على Cloud Run أو منصة حاويات.
مسارات الطلبات المعقدة
عندما يمر الطلب عبر المصادقة، وتحديد معدل الطلبات، والتحقق من المدخلات، ومنطق العمل، وعمليات قاعدة البيانات، وتحديثات ذاكرة التخزين المؤقت، وإصدار الأحداث، وتنسيق الاستجابة — فإن نمط مسار Middleware الخاص بـ Express/Fastify/Koa يتفوق من الناحية المريحة على نمط المعالج المسطح لدوال السحابة.
// التقليدي: مسار Middleware نظيف
app.use(cors());
app.use(helmet());
app.use(rateLimiter);
app.use(authenticate);
app.use('/api/v1', apiRouter);
app.use(errorHandler);
يتطلب تكرار هذا في Lambda إما إطار عمل مثل Middy (الذي يضيف وزنًا وتعقيدًا) أو تكرار رمز الإعداد عبر الدوال.
العمليات ذات الحالة
إذا كان تطبيقك يحتفظ بحالة في الذاكرة — ذاكرة تخزين مؤقت، مجموعة اتصالات، عداد لتحديد معدل الطلبات، بيانات الجلسة — فإن الخادم التقليدي يتعامل مع هذا بشكل طبيعي. يمكن لدوال Lambda إعادة استخدام الحالة عبر الاستدعاءات الدافئة، ولكن لا يمكنك الاعتماد على ذلك. أي حالة يجب أن تستمر تحتاج إلى خدمة خارجية (Redis، DynamoDB)، مما يضيف زمن استجابة وتكلفة.
متطلبات زمن الاستجابة الضيقة
بالنسبة لواجهات برمجة التطبيقات (APIs) حيث كل مللي ثانية مهمة — المزايدة في الوقت الفعلي، خوادم الألعاب، المعاملات المالية — فإن زمن الاستجابة غير المتوقع الذي يسببه البدء البارد غير مقبول، حتى مع التزامن المخصص. عملية خادم مضبوطة جيدًا مع تجميع الاتصالات وذاكرات التخزين المؤقت الدافئة توفر أوقات استجابة متسقة أقل من 10 مللي ثانية لا يمكن للنمط اللاخادمي ضمانها.
النهج الهجين
في الممارسة العملية، معظم أنظمة الإنتاج التي أبنيها تنتهي بأن تكون هجينة. تعمل واجهة برمجة التطبيقات (API) الأساسية على واجهة خلفية تقليدية (Cloud Run أو منصة حاويات)، بينما تعمل أعباء العمل المساعدة على دوال السحابة.
هندسة معمارية هجينة عملية
العميل
│
├─→ API Gateway / موازن التحميل
│ └─→ Cloud Run (واجهة برمجة التطبيقات الرئيسية)
│ ├─→ PostgreSQL (Cloud SQL)
│ ├─→ Redis (Memorystore)
│ └─→ Pub/Sub (ناقل الأحداث)
│
└─→ Cloud Functions (معالجات الأحداث)
├─→ معالجة الصور (عند الرفع)
├─→ إرسال البريد الإلكتروني (عند إنشاء الطلب)
├─→ تجميع التحليلات (مجدول)
└─→ معالجة Webhook (مشغل HTTP)
تتعامل واجهة برمجة التطبيقات الرئيسية مع حركة مرور الطلب والاستجابة المتزامنة مع اتصالات قاعدة البيانات المستمرة، والتخزين المؤقت في الذاكرة، وزمن الاستجابة المتسق. تتعامل دوال السحابة مع أعباء العمل غير المتزامنة والموجهة بالأحداث حيث لا يهم البدء البارد لأن المستخدم لا ينتظر استجابة.
استراتيجية الترحيل: من التقليدي إلى اللاخادمي
إذا كان لديك واجهة خلفية تقليدية موجودة وترغب في اعتماد النمط اللاخادمي بشكل انتقائي:
- حدد العمليات الموجهة بالأحداث التي تعمل حاليًا كمهام خلفية، أو مهام cron، أو مستهلكي قائمة الانتظار. هذه هي الأسهل للترحيل.
- استخرج نقاط النهاية المستقلة التي لا تشارك الحالة مع نقاط نهاية أخرى. نقاط نهاية فحص الصحة، ومستقبلات webhook، وواجهات برمجة التطبيقات المساعدة هي مرشحات جيدة.
- حافظ على واجهة برمجة التطبيقات الأساسية تقليدية ما لم يكن لديك سبب مقنع لتفكيكها. غالبًا ما يتجاوز العبء التشغيلي لإدارة 50 دالة Lambda عبء إدارة حاوية واحدة.
- استخدم ناقل أحداث (Pub/Sub، EventBridge، SQS) كطبقة تكامل بين واجهة برمجة التطبيقات التقليدية ودوالك اللاخادمية. تنشر واجهة برمجة التطبيقات الأحداث؛ وتشترك الدوال وتتفاعل.
استراتيجية الترحيل: من اللاخادمي إلى التقليدي
الذهاب في الاتجاه الآخر ضروري أحيانًا عندما تتجاوز واجهة برمجة تطبيقات لاخادمية هندستها المعمارية:
- لا تعيد كتابة كل شيء دفعة واحدة. ابدأ بدمج الدوال ذات حركة المرور الأعلى في خادم API واحد.
- احتفظ بالدوال الموجهة بالأحداث كدوال. قم بترحيل معالجات الطلب والاستجابة فقط.
- استخدم نفس مسارات API. وجه API Gateway/موازن التحميل الخاص بك إلى الخادم الجديد للمسارات التي تم ترحيلها واستمر في التوجيه إلى Lambda للبقية.
- قم بترحيل اتصالات قاعدة البيانات أولاً. أكبر مكسب في الأداء هو الانتقال من إعداد الاتصال لكل استدعاء إلى تجميع الاتصالات المستمر.
ملاحظات خاصة بالمنصات
دوال Firebase (الإصدار 2)
تعمل Firebase Functions v2 على Cloud Run تحت الغطاء، مما يمنحها مزايا كبيرة على الإصدار 1: تزامن قابل للتكوين (طلبات متعددة لكل مثيل)، الحد الأدنى من المثيلات، مهلات أطول (تصل إلى 60 دقيقة)، وتخصيصات ذاكرة أكبر. إذا كنت تستخدم دوال Firebase v1، فإن الترقية إلى v2 تستحق جهد الترحيل.
توفر Firebase Emulator Suite أفضل تجربة تطوير محلية في مساحة النمط اللاخادمي. إنها تحاكي Firestore، Auth، Storage، و Functions في بيئة محلية واحدة، مع إعادة التحميل السريع عند تغييرات الرمز.
AWS Lambda
تتمتع Lambda بأعمق نظام بيئي للتكامل — مشغلات من كل خدمة AWS تقريبًا، طبقات للرمز المشترك، و SnapStart لأعباء عمل Java. تلغي ميزة URL الدالة الحاجة إلى API Gateway لحالات الاستخدام البسيطة، مما يوفر 3.50 دولار لكل مليون طلب.
تعد Lambda@Edge و CloudFront Functions قوية لمعالجة الطلب/الاستجابة على مستوى CDN، ولكن تجربة التطوير وتصحيح الأخطاء أسوأ بكثير من Lambda القياسية.
Cloud Run
يطمس Cloud Run الخط الفاصل بين النمط اللاخادمي والتقليدي. إنه يشغل حاويات (أي لغة، أي إطار عمل)، يتوسع إلى الصفر، ويدعم التزامن (طلبات متعددة لكل مثيل). إنه لاخادمي في نموذج الفوترة ولكنه تقليدي في نموذج التنفيذ. للفرق التي تريد اقتصاديات النمط اللاخادمي دون إعادة كتابة رمزها كمعالجات دوال، غالبًا ما يكون Cloud Run هو الإجابة الصحيحة.
اتخاذ القرار
إليك إطار عمل القرار الذي أستخدمه:
- هل عبء العمل موجه بالأحداث وغير متزامن؟ النمط اللاخادمي.
- هل حركة المرور منخفضة وغير متوقعة؟ النمط اللاخادمي.
- هل تحتاج إلى اتصالات مستمرة أو حالة في الذاكرة؟ التقليدي.
- هل زمن الاستجابة المنخفض المتسق حاسم؟ التقليدي.
- هل الفريق صغير ويكره العمليات؟ النمط اللاخادمي (أو Cloud Run).
- هل حركة المرور عالية وثابتة؟ التقليدي (أرخص).
- هل هو مزيج مما سبق؟ هجين.
أسوأ قرار هو التعامل مع هذا كخيار شامل أو لا شيء. استخدم الأداة المناسبة لكل عبء عمل، وقم بتوصيلها من خلال واجهات محددة جيدًا، وستحصل على فوائد كليهما دون الالتزام بالكامل بأي منهما.