Angular تُفضّل البنية والنهج الموصى به لمساعدة الفرق الكبيرة على بناء تطبيقات قابلة للصيانة: أنماط متسقة، أدوات، TypeScript، حقن الاعتماد، وهندسة قابلة للتوسع.

غالبًا ما يُوصف Angular بأنه ذو آراء. من منظور إطار العمل، هذا يعني أنه لا يوفر فقط لبنات بناء—بل يوصي (وأحيانًا يفرض) طرقًا محددة لتجميعها. يتم توجيهك نحو تخطيطات ملفات معينة، أنماط، أدوات، واتفاقيات بحيث تميل مشاريع Angular المختلفة لأن "تشعر" بطريقة متشابهة حتى لو بنيت بواسطة فرق مختلفة.
تظهر آراء Angular في كيفية إنشاء المكونات، كيفية تنظيم الميزات، كيفية استخدام حقن الاعتماد بشكل افتراضي، وكيف يتم عادة تكوين التوجيه. بدلًا من مطالبتك بالاختيار بين طرق متنافسة كثيرة، يضيّق Angular مجموعة الخيارات الموصى بها.
هذه المقايضة مقصودة:
يمكن للتطبيقات الصغيرة تحمل التجريب: أنماط ترميز مختلفة، مكتبات متعددة لنفس الوظيفة، أو أنماط ارتجالية تتطور مع الوقت. تُكلِف المرونة ثمنًا كبيرًا في قواعد الشيفرة الضخمة—خاصة تلك التي تُدار لسنوات. في قواعد الشيفرة الكبيرة، تكون أصعب المشاكل غالبًا مشاكل تنسيق: إدماج مطورين جدد، مراجعة طلبات السحب بسرعة، إعادة هيكلة بأمان، والحفاظ على عمل عشرات الميزات معًا.
تهدف بنية Angular إلى جعل تلك الأنشطة قابلة للتوقّع. عندما تكون الأنماط متسقة، يمكن للفرق التحرك بين الميزات بثقة وقضاء مجهود أكبر في العمل المنتج بدلاً من إعادة تعلم "كيف بُني هذا الجزء".
باقي المقالة يشرح من أين تأتي بنية Angular—خياراتها المعمارية (مكونات، وحدات/standalone، DI، التوجيه)، أدواتها (Angular CLI)، وكيف تدعم هذه الآراء العمل الجماعي والصيانة على المدى الطويل والحجم الكبير.
يمكن للتطبيقات الصغيرة أن تنجو بالكثير من قرارات "أي شيء يصلح". عادة لا تستطيع تطبيقات Angular الكبيرة ذلك. بمجرد أن تتعامل فرق متعددة مع نفس قاعدة الشيفرة، تتضاعف التفاوتات الطفيفة إلى تكاليف حقيقية: أدوات مساعدة مكررة، هياكل مجلدات مختلفة قليلًا، أنماط حالة متنافسة، وثلاث طرق للتعامل مع نفس خطأ API.
مع نمو الفريق، ينسخ الناس ما يرونه حولهم بطبيعية. إذا لم تُشر قاعدة الشيفرة بوضوح إلى الأنماط المفضلة، تكون النتيجة انحراف الشيفرة—تتبع الميزات الجديدة عادات آخر مطوّر بدلاً من نهج مشترك.
تقلل الاتفاقيات عدد القرارات التي يجب على المطورين اتخاذها لكل ميزة. هذا يقصر وقت الإندماج (الموظفون الجدد يتعلمون "الطريقة Angular" داخل المستودع) ويقلل احتكاك المراجعة (تعليقات أقل من نوع "هذا لا يتطابق مع نمطنا").
واجهات المؤسسات نادرًا ما تكون "مكتملة". تمر بدورات صيانة، إعادة هيكلة، إعادة تصميم، وتغير مستمر في الميزات. في هذا السياق، تكون البنية أقل عن الجمالية وأكثر عن البقاء:
لا بد أن تشترك التطبيقات الكبيرة في احتياجات عابرة: التوجيه، الأذونات، التعريب، الاختبار، والتكامل مع الخلفيات. إذا حلّت كل فرقة هذه المسائل بشكل مختلف، تنتهي بك الحال إلى تصحيح التفاعلات بدلًا من بناء المنتج.
آراء Angular حول حدود الوحدات/الـstandalone، حقن الاعتماد، التوجيه، والأدوات تهدف لجعل هذه الاهتمامات متناسقة افتراضيًا. العائد بسيط: حالات خاصة أقل، عمل أقل لإعادة التنفيذ، وتعاون أكثر سلاسة على مدى سنوات.
الوحدة الأساسية في Angular هي المكون: قطعة واجهة مستخدم مكتفية ذاتيًا ذات حدود واضحة. عندما يكبر المنتج، تمنع تلك الحدود صفحات من أن تصبح ملفات ضخمة حيث "كل شيء يؤثر على كل شيء". تجعل المكونات واضحًا أين توجد ميزة، ماذا تملك (قالب، أنماط، سلوك)، وكيف يمكن إعادة استخدامها.
ينقسم المكون إلى قالب (HTML يصف ما يراه المستخدمون) وصنف (TypeScript يحتفظ بالحالة والسلوك). هذا الانقسام يشجّع فصلًا نظيفًا بين العرض والمنطق:
// user-card.component.ts
@Component({ selector: 'app-user-card', templateUrl: './user-card.component.html' })
export class UserCardComponent {
@Input() user!: { name: string };
@Output() selected = new EventEmitter\u003cvoid\u003e();
onSelect() { this.selected.emit(); }
}
<!-- user-card.component.html -->
<h3>{{ user.name }}</h3>
<button (click)="onSelect()">Select</button>
يشجّع Angular عقدة واضحة بين المكونات:
@Input() يمرّر البيانات للأسفل من الأب إلى الطفل.@Output() يرسل الأحداث للأعلى من الطفل إلى الأب.يجعل هذا الاتفاق تدفّق البيانات أسهل للفهم، خصوصًا في تطبيقات Angular الكبيرة حيث تتعامل فرق متعددة مع نفس الشاشات. عند فتحك لمكون، يمكنك بسرعة تحديد:
نظرًا لاتباع المكونات أنماطًا متسقة (المحدّدات، تسمية الملفات، الديكوريترز، الربط)، يمكن للمطوّرين التعرف على البنية بسرعة. هذا "الشكل" المشترك يقلل احتكاك التسليم، يسرّع المراجعات، ويجعل إعادة الهيكلة أكثر أمانًا—دون مطالبة الجميع بحفظ قواعد مخصصة لكل ميزة.
عندما يكبر التطبيق، غالبًا ما تكون المشكلة الأصعب ليست كتابة ميزات جديدة—بل إيجاد المكان المناسب لوضعها وفهم من "يملك" ماذا. تميل Angular نحو البنية حتى تتمكن الفرق من الاستمرار في التقدّم دون التفاوض المستمر على الاتفاقيات.
تجمّع NgModules تاريخيًا المكونات، الـdirectives، والخدمات ذات الصلة داخل حدود ميزة (مثلاً OrdersModule). يدعم Angular الحديث أيضًا المكونات standalone، التي تقلّل الحاجة إلى NgModules مع الاستمرار في تشجيع "شرائح ميزة" واضحة عبر التوجيه وبنية المجلدات.
الهدف واحد: جعل الميزات قابلة للاكتشاف والحفاظ على الاعتمادات مقصودة.
نمط قابل للتوسّع هو تنظيم حسب الميزة بدلًا من النوع:
features/orders/ (الصفحات، المكونات، الخدمات الخاصة بالطلبات)features/billing/features/admin/عندما يحتوي مجلد كل ميزة على معظم ما يحتاجه، يستطيع المطوّر فتح دليل واحد وفهم كيفية عمل ذلك الجزء بسرعة. كما يتطابق ذلك مع ملكية الفريق: "فريق Orders يملك كل شيء تحت features/orders."
غالبًا ما تقسم فرق Angular الشيفرة القابلة لإعادة الاستخدام إلى:
الخطأ الشائع هو تحويل shared/ إلى مستودع عام. إذا استورد الجميع "shared" وكل شيء فيه، تتشابك الاعتمادات وتطول أوقات البناء. النهج الأفضل هو إبقاء shared صغيرة، مركّزة، وخفيفة الاعتمادية.
بين حدود الوحدات/الـstandalone، افتراضات حقن الاعتماد، ونقاط دخول الميزات المعتمدة على التوجيه، يدفع Angular الفرق بشكل طبيعي نحو بنية مجلد متوقعة ورسم بياني أبسط للاعتمادات—مكوّنات أساسية لتطبيقات Angular الكبيرة القابلة للصيانة.
في Angular، “البنية” هي مجموعة الأنماط الافتراضية التي يشجعها الإطار والأدوات: مكونات مع قوالب، حقن الاعتماد، تكوين التوجيه، وتخطيطات مشروع مُولَّدة عبر CLI.
“الآراء” هي الطرق الموصى بها لاستخدام هذه الأنماط—لذلك تميل معظم تطبيقات Angular إلى التنظيم بطريقة متشابهة، ما يجعل قواعد الشيفرة الكبيرة أسهل للتنقّل والصيانة.
تقلل الآراء من تكاليف التنسيق في فرق كبيرة. مع اتفاقيات متسقة، يقضي المطورون وقتًا أقل في مناقشة بنية المجلدات وحدود الحالة وخيارات الأدوات.
المقايضة الأساسية هي المرونة: إذا كانت فرقك تفضل بنية مختلفة تمامًا، فقد تشعر ببعض الاحتكاك عند العمل عكس الافتراضات الافتراضية في Angular.
الانحراف في الشيفرة يحدث عندما ينسخ المطورون الشيفرة القريبة ويُدخلون أنماطًا مختلفة تدريجيًا.
للحد من الانحراف:
features/orders/, features/billing/).تجعل افتراضات Angular تبنّي هذه العادات أسهل باستمرار.
توفر المكونات وحدة ملكية واجهة مستخدم متسقة: قالب (عرض) + صنف (حالة/سلوك).
تتوسع جيدًا لأن الحدود صريحة:
@Input() ينقل البيانات من الأب إلى الطفل؛ @Output() يبث أحداثًا من الطفل إلى الأب.
ينتج عن ذلك تدفّق بيانات متوقع وسهل المراجعة:
تجمع NgModules تاريخيًا التصريحات والمزودات ضمن حدّ ميزة. المكونات standalone تقلل من الحاجة إلى الكثير من بو일ربل بينما تستمر في تشجيع تقطيع الميزات عبر التوجيه والمجلدات.
قاعدة عملية:
تقسيم شائع هو:
تجنّب "وحدة shared الإلهية" بجعل shared صغيرة وخفيفة الاعتمادية واستيراد ما تحتاجه فقط في كل ميزة.
حقن الاعتماد (DI) يجعل الاعتمادات صريحة وقابلة للاستبدال:
بدلًا من new ApiService()، تطلب المكونات الخدمات ويزوّد Angular المثيل المناسب.
نطاق المزود يتحكم في عمر الكائن:
providedIn: 'root' يعمل كمفرد للتطبيق—مناسب للقلق المشترك لكنه قد يخزن حالة متغيرة مخفية.كن متعمّدًا: وضّح ملكية الحالة وتجنب "العوالم الغامضة" التي تتراكم فيها الحالة لمجرد أنها مفردة.
التحميل الكسول يحسّن الأداء ويساعد على حدود الفرق:
الحراس (guards) وresolvers يجعلون قواعد التنقل صريحة: