الهندسة المعمارية النظيفة في Next.js
هذا الريبو هو مثال على كيفية تحقيق الهندسة المعمارية النظيفة في Next.js. يوجد برنامج تعليمي فيديو يمر عبر هذا المشروع. انقر على الصورة للتحقق من ذلك على YouTube:
يمكنك تشغيل المشروع فقط عن طريق تشغيل npm install و npm run dev .
الهندسة المعمارية النظيفة

ملحوظة
؟ رسمت هذه النسخة المبسطة من مخطط الهندسة المعمارية الأصلية. لقد قمت بتبسيطها بطريقة أكثر منطقية بالنسبة لي ، ومن الأسهل فهمها. آمل أن يساعدك ذلك أيضًا.
أوصي بشدة بقراءة المقال الأصلي من قبل العم بوب إذا كانت هذه هي المرة الأولى التي تسمع فيها عن الهندسة المعمارية النظيفة ، لكنني سأحاول تلخيصها لك أدناه.
الهندسة المعمارية النظيفة هي مجموعة من القواعد التي تساعدنا على تنظيم تطبيقاتنا بطريقة أسهل في الحفاظ عليها واختبارها ، ويمكن التنبؤ بأبوابها. إنها مثل اللغة المشتركة التي يفهمها المطورون ، بغض النظر عن خلفياتهم التقنية وتفضيلات لغة البرمجة.
الهندسة المعمارية النظيفة ، والبنية المماثلة/المشتقة ، كلها لها نفس الهدف - الفصل بين المخاوف . يقدمون طبقات تجمع رمزًا مشابهًا معًا. تساعدنا "الطبقات" على تحقيق جوانب مهمة في قاعدة الشفرات الخاصة بنا:
- بغض النظر عن واجهة المستخدم - لا يقترن منطق العمل بإطار واجهة المستخدم المستخدم (في هذه الحالة Next.js). يمكن استخدام نفس النظام في تطبيق CLI ، دون الحاجة إلى تغيير منطق العمل أو القواعد.
- بغض النظر عن قاعدة البيانات - يتم عزل تنفيذ/عمليات قاعدة البيانات في طبقتها الخاصة ، وبالتالي فإن بقية التطبيق لا يهتم بالمعتمة التي يتم استخدامها ، ولكنها تتصل باستخدام النماذج .
- بغض النظر عن الأطر - لا تعرف قواعد العمل والمنطق ببساطة أي شيء عن العالم الخارجي. يتلقون البيانات المحددة باستخدام JavaScript العادي ، ويستخدمون JavaScript العادي والخدمات والمستودعات لتحديد منطقهم ووظائفهم. يتيح لنا ذلك استخدام الأطر كأدوات ، بدلاً من الاضطرار إلى "تشكيل" نظامنا في تطبيقاتها وقيودها. إذا استخدمنا معالجات الطريق في تطبيقنا ، وترغبوا في إعادة تشكيل بعضهم إلى إجراءات الخادم ، كل ما نحتاج إلى فعله هو فقط استدعاء وحدات التحكم المحددة في إجراء خادم بدلاً من معالج الطريق ، ولكن لا يزال منطق العمل الأساسي دون تغيير.
- يمكن اختباره - يمكن اختبار منطق العمل والقواعد بسهولة لأنه لا يعتمد على إطار واجهة المستخدم ، أو قاعدة البيانات ، أو خادم الويب ، أو أي عنصر خارجي آخر يبني نظامنا.
تحقق العمارة النظيفة هذا من خلال تحديد التسلسل الهرمي التبعية - تعتمد الطبقات فقط على الطبقات الموجودة أسفلها ، ولكن ليس أعلاه.
هيكل المشروع (فقط البتات المهمة)
-
app - طبقة الأطر والبرامج تشغيل - بشكل أساسي كل شيء next.js (الصفحات ، إجراءات الخادم ، المكونات ، الأنماط وما إلى ذلك) أو أي شيء "يستهلك" منطق التطبيق -
di - حقن التبعية - مجلد نقوم بإعداد حاوية DI والوحدات النمطية -
drizzle - كل شيء ديسيبل - تهيئة عميل ديسيبل ، وتحديد المخطط ، والهجرة -
src - "جذر" النظام-
application - طبقة التطبيق - يحتفظ بحالات الاستخدام والواجهات للمستودعات والخدمات -
entities - طبقة الكيانات - تحمل النماذج والأخطاء المخصصة - تحتوي
infrastructure - طبقة البنية التحتية - على تطبيقات المستودعات والخدمات ، وتسحب الواجهات من application -
interface-adapters - طبقة محولات الواجهة - تحكم وحدات تحكم بمثابة نقطة دخول للنظام (المستخدمة في طبقة الأطر والبرامج التشغيل للتفاعل مع النظام)
-
tests - اختبارات الوحدة تعيش هنا - بنية المجلد unit يتطابق مع src -
.eslintrc.json - حيث يتم تعريف المكون eslint-plugin-boundaries - هذا يمنعك من كسر قاعدة التبعية -
vitest.config.ts - لاحظ كيف يتم تعريف الاسم @ !
تفسير الطبقات
- الأطر والسائقين : يحتفظ بجميع وظائف إطار واجهة المستخدم ، وكل شيء آخر يتفاعل مع النظام (على سبيل المثال في هذا السيناريو ، هذا هو معالجات الطريق NEXT.JS ، وإجراءات الخادم ، والمكونات (الخادم والعميل) ، والصفحات ، ونظام التصميم ، وما إلى ذلك ...
- يجب أن تستخدم هذه الطبقة فقط وحدات التحكم والنماذج والأخطاء ، ويجب ألا تستخدم حالات الاستخدام والمستودعات والخدمات .
- محولات الواجهة : تحدد وحدات التحكم :
- تقوم وحدات التحكم بإجراء عمليات التحقق من المصادقة والتحقق من صحة الإدخال قبل تمرير الإدخال إلى حالات الاستخدام المحددة.
- وحدات التحكم تنظم حالات الاستخدام. إنهم لا ينفذون أي منطق ، لكنهم يحددون العمليات بأكملها باستخدام حالات الاستخدام.
- تخطو الأخطاء من الطبقات الأعمق ويتم التعامل معها حيث يتم استخدام وحدات التحكم.
- تستخدم وحدات التحكم مقدمي العروض لتحويل البيانات إلى تنسيق صديق للاتصال قبل إعادته إلى "المستهلك". يساعدنا هذا في شحن جافا سكريبت إلى العميل (المنطق والمكتبات لتحويل البيانات) ، ويساعد على منع تسرب أي خصائص حساسة ، مثل رسائل البريد الإلكتروني أو كلمات مرور التجزئة ، كما تساعدنا على تخفيف كمية البيانات التي نرسلها إلى العميل.
- التطبيق : حيث يعيش منطق العمل. في بعض الأحيان تسمى الأساسية . تحدد هذه الطبقة حالات الاستخدام والواجهات للخدمات والمستودعات.
- حالات الاستخدام :
- تمثل العمليات الفردية ، مثل "Create ToDo" أو "تسجيل الدخول" أو "Toggle ToDo".
- قبول المدخلات المعزولة مسبقا (من وحدات التحكم) والتحقق من التفويض .
- استخدم المستودعات والخدمات للوصول إلى مصادر البيانات والتواصل مع الأنظمة الخارجية.
- يجب ألا تستخدم حالات الاستخدام حالات الاستخدام الأخرى . هذه رائحة رمز. وهذا يعني أن حالة الاستخدام تقوم بأشياء متعددة ويجب تقسيمها إلى حالات استخدام متعددة.
- واجهات للمستودعات والخدمات:
- يتم تعريفها في هذه الطبقة لأننا نريد أن نتفوق على تبعية أدواتهم وأطرهم (برامج تشغيل قاعدة البيانات ، وخدمات البريد الإلكتروني ، إلخ ...) ، لذلك سنقوم بتنفيذها في طبقة البنية التحتية .
- نظرًا لأن الواجهات تعيش في هذه الطبقة ، يمكن استخدام حالات استخدام (والطبقات العليا بشكل عابر) من خلال حقن التبعية .
- يتيح لنا حقن التبعية تقسيم التعريفات (الواجهات) من التطبيقات (الفئات) والحفاظ عليها في طبقة منفصلة (البنية التحتية) ، ولكن لا تزال تسمح باستخدامها.
- الكيانات : حيث يتم تعريف النماذج والأخطاء .
- النماذج :
- حدد أشكال بيانات "المجال" مع JavaScript العادي ، دون استخدام تقنيات "قاعدة البيانات".
- لا ترتبط النماذج دائمًا بقاعدة البيانات - يتطلب إرسال رسائل البريد الإلكتروني خدمة بريد إلكتروني خارجية ، وليس قاعدة بيانات ، ولكن لا يزال يتعين علينا الحصول على شكل بيانات يساعد الطبقات الأخرى على التواصل "إرسال بريد إلكتروني".
- تحدد النماذج أيضًا قواعد التحقق من الصحة الخاصة بها ، والتي تسمى "قواعد أعمال المؤسسة". القواعد التي لا تتغير عادة ، أو من المرجح أن تتغير عندما يتغير شيء خارجي (التنقل في الصفحة ، الأمان ، إلخ ...). مثال على ذلك نموذج
User يحدد حقل اسم المستخدم الذي يجب أن يبلغ طوله 6 أحرف على الأقل ولا يتضمن أحرفًا خاصة .
- الأخطاء :
- نريد أخطاءنا لأننا لا نريد أن ننطلق من أخطاء خاصة في قاعدة البيانات ، أو أي نوع من الأخطاء المحددة للمكتبة أو الإطار.
-
catch الأخطاء التي تأتي من مكتبات أخرى (على سبيل المثال رذاذ) ، ونحول تلك الأخطاء إلى أخطائنا. - هذه هي الطريقة التي يمكننا بها الحفاظ على جوهرنا بشكل مستقل عن أي أطر والمكتبات والتقنيات - أحد أهم جوانب الهندسة المعمارية النظيفة.
- البنية التحتية : حيث يتم تعريف المستودعات والخدمات .
- تسحب هذه الطبقة واجهات المستودعات والخدمات من طبقة التطبيق وتنفيذها في فصولها الخاصة.
- المستودعات هي كيفية تنفيذ عمليات قاعدة البيانات. إنها فئات تعرض الأساليب التي تؤدي عملية قاعدة بيانات واحدة - مثل
getTodo أو createTodo أو updateTodo . هذا يعني أننا نستخدم مكتبة / برنامج تشغيل قاعدة البيانات في هذه الفئات فقط. لا يقومون بأي التحقق من صحة البيانات ، فقط تنفيذ الاستعلامات والطفرات ضد قاعدة البيانات وإما رمي أخطاءنا المحددة المخصصة أو نتائج الإرجاع. - الخدمات هي خدمات مشتركة يتم استخدامها عبر التطبيق - مثل خدمة المصادقة ، أو خدمة البريد الإلكتروني ، أو تنفيذ أنظمة خارجية مثل Stripe (إنشاء المدفوعات ، والتحقق من الإيصالات ، إلخ ...). تستخدم هذه الخدمات أيضًا وتعتمد على الأطر والمكتبات الأخرى. لهذا السبب يتم الاحتفاظ بتنفيذها هنا إلى جانب المستودعات.
- نظرًا لأننا لا نريد أن تعتمد أي طبقة على هذه الطبقات (ونعتمد بشكل عبور على قاعدة البيانات وجميع الخدمات) ، نستخدم مبدأ انعكاس التبعية . يتيح لنا ذلك الاعتماد فقط على الواجهات المحددة في طبقة التطبيق ، بدلاً من التطبيقات في طبقة البنية التحتية . نستخدم انعكاس مكتبة التحكم مثل Ioctopus لتجريد التنفيذ وراء الواجهات و "حقن" كلما احتجنا إليها. نخلق التجريد في دليل
di . نقوم "بربط" المستودعات والخدمات ووحدات التحكم واستخدام الحالات للرموز ، ونحن "حلها" باستخدام تلك الرموز عندما نحتاج إلى التنفيذ الفعلي. هكذا يمكننا استخدام التنفيذ ، دون الحاجة إلى الاعتماد بشكل صريح (استيراده).
التعليمات
نصيحة
إذا كان لديك سؤال غير مغطى بالأسئلة الشائعة ، فلا تتردد في فتح مشكلة في هذا الريبو ، أو الانضمام إلى خادم Discord الخاص بي وبدء محادثة هناك.
هل الهندسة المعمارية النظيفة / هذا التنفيذ سهل الاستغناء عن الخادم؟ هل يمكنني نشر هذا على Vercel؟
نعم! يمكنك استخدامه مع جهاز توجيه الصفحة ، وموجه التطبيق ، والوسيط ، ومجالات واجهة برمجة التطبيقات ، وإجراءات الخادم ، وأي شيء حقًا! عادةً ما يتم تحقيق حقن التبعية في مشاريع JavaScript مع مكتبة Conversify.js ، والتي لا تتوافق مع أوقات التشغيل الأخرى باستثناء العقدة. يقوم هذا المشروع بتنفيذ Ioctopus ، وهي حاوية IOC بسيطة لا تعتمد على reflect-metadata وتعمل على جميع أوقات التشغيل.
هل يجب أن أبدأ في تنفيذ الهندسة المعمارية النظيفة على الفور عندما أقوم بإنشاء مشروع Next.js؟
أود أن أقول لا . إذا كنت تبدأ مشروعًا جديدًا ، فإنني أنصحك بالتركيز على تحقيق حالة MVP بأسرع وقت ممكن (حتى تتمكن من التحقق من صحة فكرتك / معرفة ما إذا كان هناك مستقبل لمشروعك). عندما تبدأ الأمور في الحصول على جدية (تبدأ المزيد من الميزات في التنفيذ ، فإن قاعدة المستخدمين الخاصة بك تنمو بشكل كبير ، أو كنت على متن المطورين الآخرين في مشروعك) ، وذلك عندما تريد الاستثمار في بعض الوقت في تكييف هذه البنية (أو أي بنية لهذه المسألة).
إذا كنت عميقًا بالفعل في الأعشاب الضارة في المشروع ، فيمكنك (وفريقك) التخطيط لإعادة إنشاء تدريجي بدءًا من العدو التالي. في هذه الحالة ، لديك بالفعل الرمز المكتوب ، تحتاج فقط إلى إعادة تنظيمه قليلاً ، ويمكنك القيام بذلك الجزء حسب الجزء ، معالج الطريق حسب المعالج ، إجراء خادم عن طريق إجراء الخادم. بالمناسبة ، أقول ذلك باستخفاف "أنت فقط بحاجة إلى إعادة تنظيمها قليلاً" ، ولكن يمكن أن تكون بعيدة عن أن تكون بسيطًا مثل ذلك. خذ في الاعتبار دائمًا "الأشياء الخاطئة" عندما تخطط لإعادة إنشاء. ووضع بعض الوقت في اختبارات الكتابة!
هذا يبدو مثل التكليف الزائد ، ويعقد تطور الميزات.
إذا كنت لا تقضي أكثر من 3 دقائق في التفكير في هذا ، فبناء نعم ، فهذا يبدو كأنه من الهندسة. ولكن إذا قمت بذلك ، فسوف تدرك أن الهندسة المعمارية = الانضباط . الهندسة المعمارية هي عقد بين المطورين الذين يحددون ما يحدث. إنه في الواقع يبسط تطوير الميزة لأنه يجعل قاعدة الشفرة يمكن التنبؤ بها ، ويتخذ تلك القرارات نيابة عنك.
لا يمكنك تنمية مشروع بشكل مستدام إذا كتب كل مطور يعمل عليه الكود حيث يكون الأكثر ملاءمة. سوف تتحول قاعدة كود إلى كابوس للعمل معه ، وذلك عندما ستشعر بعملية تطوير ميزة معقدة حقيقية. لمحاربة هذا ، في النهاية ستضع بعض القواعد. ستنمو هذه القواعد حيث يواجه فريقك ويحل مشكلات جديدة. ضع كل هذه القواعد في وثيقة ، وهناك تعريف الهندسة المعمارية الخاصة بك. لا تزال تنفذ نوعًا من الهندسة المعمارية ، لقد وصلت للتو إلى هذه النقطة ببطء شديد ومؤلمة.
يمنحك العمارة النظيف اختصارًا وبنية محددة مسبقًا تم اختبارها. ونعم ، بالتأكيد ، تحتاج إلى تعلم كل هذا ، لكنك تفعل ذلك مرة واحدة في حياتك ، ثم فقط تطبيق المبادئ بأي لغة أو إطار عمل ستستخدمه في المستقبل.
هل يجب علي تطبيق الهندسة المعمارية النظيفة في جميع مشاريعي؟
لا . ليس إذا كنت لا تتوقع أن ينمو المشروع ، أو في عدد من الميزات ، أو عدد المستخدمين ، أو عدد المطورين الذين يعملون عليه.
ما هي البنى الأخرى المماثلة لتنظيف الهندسة المعمارية؟
كما ذكر في منشور المدونة الأصلي الذي ذكرته في الجزء العلوي من ReadMe ، حصلت على:
- الهندسة المعمارية السداسية (المعروفة أيضًا باسم المنافذ والمحولات) بقلم أليستير كوكبورن
- بنية البصل بقلم جيفري باليرمو
- الهندسة المعمارية الصراخ من قبل العم بوب (نفس الرجل وراء الهندسة المعمارية النظيفة)
- وزوجين أكثر (تحقق من منشور المدونة الأصلي)