Table of Contents
كيفية تحقيق التوازن في المرونة والبساطة في التصميم المضاعف للشركة
(ج) كثيراً ما يبدو أن برامجيات التصميم التي تتقيد بـ مبادئ SOLID تبدو وكأنها تمشي على نطاق ضيق، ومن جانب آخر، تحتاج إلى مرونة - القدرة على التكيف مع المتطلبات المتغيرة، وتوسيع الملامح، ومتغيرات العناصر دون كسر النظام.
المبادئ الأساسية: مصفوفة سريعة
(SOLID) هو مختصر لخمسة مبادئ تصميمية استحدثها روبرت س. مارتن (العمدة بوب) لمساعدة المطورين على إنشاء برامج حاسوبية قابلة للاستمرار وموسعة الوجهة للجسم، فهماً لمقصدهم حاسم قبل محاولة تحقيق التوازن بينهما.
مبدأ المسؤولية الوحيدة - سبب واحد للتغيير
وينبغي أن يكون لكل فئة وظيفة واحدة فقط، وعندما تتولى الصف مسؤوليات متعددة، يمكن أن تؤثر التغييرات في أحد المتطلبات تأثيراً غير مقصود على وظيفة أخرى، تزداد هشاشة، وبالطبع، يشجع النظام التوحيدي عن طريق الحد من نطاق كل وحدة، مما يسهل فهمها واختبارها، غير أنه يمكن أن يؤدي إلى انتشار فصول صغيرة تضيف تعقيداً عرضياً (مثلاً، طبقة تسمى [FLT:].
- مشروع المبدأ المفتوح/المغلق - مفتوح للتمديد، مغلق للتحديث
يجب أن تكون قادراً على إضافة سلوك جديد بدون تغيير الرمز الموجود، هذا يتم عادة من خلال الوصلات البينية، الصفوف المجردة، التعددية، البوليمورفيا،
Liskov Substitution Principle (LSP) — Subtypes must Behave like their Base Types
ويجب الاستعاضة عن الفئات المحرومة بطبقات قاعدية دون تغيير في صحة البرنامج، وكثيرا ما تكون الانتهاكات مطروحة على أنها شروط محرجة أو كشوفات، ويبسط الالتزام بنظام الأفضليات المعمم مدونة العملاء لأن المستهلكين يمكنهم الاعتماد على عقود الأساس دون معرفة أنواع محددة.
مبدأ الفصل بين الأوجه - وجه صغير ومركّز
ينبغي ألا يُجبر العملاء على الاعتماد على الأساليب التي لا يستخدمونها، ويتوافق نظام المعلومات الإدارية المتكامل مع البساطة: فالوصلات البينية الصغيرة أسهل لتنفيذها والسبب فيها، ولكن إذا تقاسمت الوصلات البينية بشكل عدواني جداً، ينتهي بك المطاف مع عشرات من الوصلات البينية ذات الخوذة الواحدة التي تعقّد الأسلاك وتخفض من إمكانية القراءة.
مبدأ الإعالة - يعتمد على الخلاصات وليس على الإستنتاجات
وينبغي ألا تعتمد الوحدات الرفيعة المستوى على وحدات متدنية المستوى؛ وينبغي أن تعتمد على الخلاصات؛ فالبرنامج الدولي للحساب الالكتروني أساسي للمرونة - ويتيح تبادل التنفيذ )مثل التحول من قاعدة بيانات محلية إلى نظام الحد الأدنى من التغييرات( مع إدخال تغييرات طفيفة على الحد الأدنى، غير أن الإفراط في استخدام الخلاصات لكل تبعية )حتى الحالات المستقرة مثل ]FLT:1]( يضيف مراسما دون فائدة.
ولكل مبدأ توتر طبيعي مع الآخرين - خاصة النزاع بين المرونة التي يقودها برنامج المقارنات الدولية والدافع إلى البساطة - الفن هو معرفة متى يطبق كل منهما ومتى يحافظ على الأمور مباشرة.
"سبيكتور" بين المرونة والبساطة
ويساعد على تصور المبادلات على أنها طيف:
- Reigid simplicity]: المدونة سهلة الفهم ولكنها صعبة التغيير.
- Over-abstracted flexibility]: المدونة قابلة للنفاذ إلى حد كبير ولكنها مستحيلة أن تتبع دون الخائن، مثال: نظام به ستة مستويات من الاختراق والمصانع وأنماط الزوار لما يمكن أن يكون مشروطا بسيطا.
- Balanced adaptability]: المدونة واضحة في غرضها، ولكنها بنيت حتى الآن لاستيعاب التغييرات المنظورة دون مراسم.
البقعة الحلوة تعتمد على نطاقك وحجم الفريق ومعدل التغيير، قد يتحول النموذج الأولي السريع إلى البساطة؛ يحتاج الإطار الأوسط لتجهيز المدفوعات إلى مزيد من المرونة، والاستراتيجيات الواردة أدناه تساعدك على إيجاد تلك البقعة الحلوة.
الاستراتيجية 1: إعطاء الأولوية للتنوع
وينبغي أن يكون الموقف الافتراضي صالحاً للبساطة، وأن تستخدم الخلاصات فقط عندما تقدم فوائد واضحة ومباشرة ، وإذا لم تستطع أن توضّح لماذا يلزم اليوم تداخل أو صف أساس مجرد (ليس في المستقبل المتصور)، فلا تضيفه، وهذا تطبيق مباشر لمبدأ " YAGNI " ([F]
النظر في هذا المثال من نظام إدارة المستعملين:
// Over-abstracted
interface UserNotifier {
void send(User user, String message);
}
class EmailNotifier implements UserNotifier { ... }
class SmsNotifier implements UserNotifier { ... }
class UserController {
private UserNotifier notifier;
public UserController(UserNotifier notifier) { ... }
}
// Simple version – just send email (start here)
class UserController {
private EmailService email;
public void registerUser(...) {
// ...
email.send(user, "Welcome!");
}
}
فقط مستخرجة عندما يكون لديك حقا قناة إخطار ثانية.
الاستراتيجية 2: الحفاظ على الوجوه الصغيرة والمقصودة
(أ) إن التفريق بين الأوجه كثيراً ما يساء تفسيره على أنه " يُستخدم كل طريقة من طرق الوصل بينية واحدة " ().
(أ) إذا لم يسمي أحد الفئات التي تستخدم واجهة بينية أحد أساليبها، فلا ينبغي أن تكون هذه الطريقة على تلك الوصلة، وهذا يؤدي بطبيعة الحال إلى عقود مركّزة وبسيطة.
الاستراتيجية 3: تطبيق نظام YAGNI بلا هوادة
إنّ (يانغ إن) هو أفضل دفاع لك ضدّ الإفراط في الهندسة، لكنّه ليس عذراً لتجاهل كلّ المتطلبات المستقبلية.
- Foreseeable changes]: Changes the business has explicitly discussed or that are common in your industry (e.g., multi-tenancy, localized output). Build in ]just enough] flexibility-usually by following SOLID with small interfaces and dependency injection.
- Speculative changes]: " ربما نحتاج يوماً ما إلى تطبيق نظام تقييم الأداء الإقليمي لهذه الأداة الداخلية " . لا تصمم له حتى يتم تأكيد الشرط.
A help heuristic: if added an abstraction makes the existing code easier to understand right now, it’s probably worth doing. If it only adds flexibility for a future scenario, let it.
الاستراتيجية 4: عدم التفاوض بشأن إعادة التصنيع بصورة منتظمة
والتوازن بين المرونة والبساطة ليس قراراً لمرة واحدة، فعندما يتطور نظام ما، يصبح الحل البسيط مرهقاً أو ملتوياً. [العاملة] هو كيفية الحفاظ على التوازن مع مرور الوقت.] إنشاء كوادر من الطرق الصغيرة والمستمرة، ومتغيرات إعادة الاسم، وتفكيك الصفوف الكبيرة، وتشديد التفاعلات.
تقنيات إعادة التصنيع المشتركة التي تعيد البساطة دون التضحية بالمرونة:
- Extract Interface ] — only when you have multiple implementations or need test doubles.
- Replace Conditional with Polymorphism - use if you have a clear hierarchy; otherwise, a simple shift may be fine.
- Remove dead Code] -حذف بارامترات غير مستخدمة، وطرق، وطبقات كاملة، وهذا يبقي قاعدة البيانات مائلة.
- Inline Method] — if a method is only called once and adds no clarity, put its logical in the caller.
دمج المفاعلات في سير العمل اليومي: في كل مرة تلمس فيها قطعة من الرموز لإضافة سمة، وتنظف المنطقة المحيطة بها، وتترك قاعدة الكشافة - وتترك الرمز أنظف مما وجدته - يمتثل مباشرة هنا.
الاستراتيجية 5: حقن الإعالة
(د) حقن الإعالة هو أسلوب قوي لتحقيق الـ دي بي أي و OCP.() وبحقن المعالين (مثلاً، عن طريق البارامترات البنائية بدلاً من الترميز بنقطة جديدة)، تجعل المكونات قابلة للاستبدال والاختبار، غير أن الـ دي يمكن أيضاً أن تكون مبالغة في تقديرها، مما يُسمى أحياناً " حمى الحقن " [FLT].
المبادئ التوجيهية للأرصدة:
- Inject only external concerns]: databases, HTTP clients, file systems, services from other modules.
- لا تحقن فئات المرافق ] التي لا يوجد لديها سلوك خارجي (مثل ).
- Use a DI container] (e.g., Spring, Dagger, Guice) to manage wiring, but keep module boundaries clean. Avoid an explosion of small formation classes.
الاستراتيجية 6: التكوين المفضّل على الميراث
فالإرث يخلق انقساماً شديداً بين صف الوالدين وأطفاله، فالتغييرات في طبقة القاعدة يمكن أن تمزق من خلال جميع الفئات الفرعية، مما يجعل النظام هشاً.
// Inheritance (rigid)
class Bird {
void fly() { ... }
}
class Penguin extends Bird {
@Override void fly() { throw new UnsupportedOperationException(); }
}
// Composition (flexible + simple)
interface FlyBehavior { void fly(); }
class CanFly implements FlyBehavior { ... }
class CannotFly implements FlyBehavior { ... }
class Bird {
private FlyBehavior flyBehavior;
Bird(FlyBehavior fb) { this.flyBehavior = fb; }
void performFly() { flyBehavior.fly(); }
}
هذه هي الرؤية الرئيسية وراء نمط الاستراتيجية .
الاستراتيجية 7: أنماط التصميم التي تضيف قيمة حقيقية
إن أنماط التصميم هي أدوات وليس أهدافا، فالفخ المشترك يستخدم نمطا لأنه " يهدر مهنيا " أو لأن شخصا ما على شبكة الإنترنت أوصى بذلك، قبل تطبيق أي نمط، يسأل:
- هل هذا النمط يحل مشكلة متتالية ؟]
- هل سيسهل الأمر على الشفرة أن تمدد بطريقة ما قيم الأعمال؟
- هل هناك بديل أبسط (مثل وظيفة، درجة بسيطة) يحقق نفس الشيء؟
أنماط غالبا ما تحقق توازنا جيدا بين المرونة والساطة:
- Factory Method] - for creating objects when the exact type varies.
- Adapter] - to integrate third-party Library without polluting your core logical.
- Repository] - to abstract data access behind a collection-like interface.
- Specification] - for querying domain objects without embedding SQL or conditions.
Avoid patterns that add many classes without proportional benefit. For instance, the Abstract Factory] is often overkill; a simple Factory Method plus DI is usually sufficient.
الاستراتيجية 8: كتابة الوثائق الوافية
وحتى نظام أفضل تصميم يمكن أن يشعر بالتعقيد إذا كان القصد من وراء الخلاصات غير واضح، وينبغي أن تركز الوثائق على ] لماذا تتخذ قرارات التصميم ، وتجنب تكرار ما يقوله الرمز بالفعل، والتعليق الذي يوجد في مكان جيد أو فرع قصير من نظام README الذي يفسر الأساس المنطقي للتفاعل يمكن أن يحول دون قيام مطورين في المستقبل ب " اختراق " الحل غير الضروري (ب)
الوثائق:
- حدود كل وحدة (ما هي مسؤولة عنه وما هو غير موجود).
- فالتوجه المتوقع للتغيير )مثلا، " من المرجح أن يحتاج هذا الواجهة إلى تنفيذات جديدة عندما نضيف قواعد أكثر تحديدا لبلد معين " (.
- )مثلا، " اخترنا التكوين على الميراث هنا للسماح بإجراء اختبارات قائمة بذاتها لكل قناة إخطار " (.
النموذج العالمي الحقيقي: بناء نظام الإخطار
لنطبق هذه الاستراتيجيات على سيناريو محدد، بل ستبني نظاما للإخطارات يرسل رسائل إلكترونية فقط في البداية، فالعمل لديه فكرة غامضة عن " قد نحتاج إلى إخطارات دفع لاحقا " ، ولكن ليس هناك جدول زمني محدد.
المرحلة الأولى - البدء في مرحلة بسيطة
class EmailService {
void send(String to, String subject, String body) { ... }
}
class NotificationService {
private EmailService email;
void sendWelcome(User user) {
email.send(user.getEmail(), "Welcome", "Thanks for joining!");
}
}
هذا بسيط كما يحصل لا يوجد تداخلات ولا مصانع ولا أنماط، ويتبع البرنامج (كل فئة لها مسؤولية واحدة) ومن السهل فهمه.
المرحلة الثانية - عندما يتم تأكيد القناة الثانية
الآن يطلب فريق المنتج إخطارات من إدارة الخدمات الخاصة لتنبيهات الحسابات، بدلاً من إضافة شرط في ، نستخدم نمط الاستراتيجية:
- Extract an interface with a method .]
- Implement and ].
- Inject the appropriate channel(s) into via the constructor.
وقد أضفنا موقفاً مضللاً، ولكن مبرراً لأن لدينا الآن تنفيذين حقيقيين، ولا يزال الرمز بسيطاً لكل قناة، والنظام العام مرناً في القنوات الجديدة دون تعديل.
المرحلة 3 - تجنب التجاوز في الخلاص
ويقترح شخص ما إضافة و enum. ما لم يكن لديك بالفعل ثلاث قنوات وحاجة واضحة إلى اختيار دينامي في وقت العرض، مقاومة، ويضيف المصنع والمقاطع تعقيداً دون دفع فوري، ويبقي النظام سائلاً في وقت لاحق عندما يظهر النمط.
الروابط مع المزيد من القراءة
- The Open-Closed Principle by Robert C. Martin] - Foundational perspective on OCP and its relationship to flexibility.
- YAGNI by Martin Fowler] - The original explanation and practical advice on when to apply it.
- Refactoring as a Habit by James Shore ] — why continuous refactoring is essential for maintaining balance.
- Composition vs Inheritance (DigitalOcean) ] - Clear examples that illustrate the trade-offs.
- Strategy Pattern – SourceMaking] – Detailed explanation of the pattern used in the notification example.
الاستنتاج: الرصيد ممارسة مستمرة
ولا يوجد " توازن دائم " بين المرونة والبساطة في التصميم المتوافق مع مبادرة " سوليد " ، فالتوازن الصحيح يعمق فهمك للمجال، حيث ينمو الفريق، ومع تغير أولويات الأعمال، والهدف ليس تحقيق دولة ثابتة بل إشاعة روح العقل: فالبدء في العمل، والإضافة إلى الخلاصات فقط عندما تُحدث مشكلة حقيقية، وتُعادل النمط المستمر.