#016 — Software Architecture | معمارية البرمجيات
قبل أن تبدأ في كتابة التفاصيل الصغيرة داخل النظام، هناك سؤال أهم:
كيف سيبدو النظام كاملًا من الأعلى؟
هنا تأتي Software Architecture — معمارية البرمجيات.
المعمارية لا تهتم فقط بالـClasses أو Methods، بل تحدد الصورة الكبرى للنظام:
كيف نقسمه إلى مكونات؟
كيف تتواصل هذه المكونات؟
أين تُخزن البيانات؟
كيف سنتعامل مع الخدمات الخارجية؟
وكيف نجعل النظام قادرًا على التوسع، وآمنًا، ومستقرًا؟
ببساطة:
Architecture = Big Picture
Design = Details
فمثلًا:
Client → API Gateway → Services → Database
هذا قرار معماري.
أما تحديد:
OrderService
createOrder()
cancelOrder()
getOrder()
فهذه تفاصيل أقرب إلى Software Design.
لكن المعمارية لا تعتمد فقط على الوظائف التي يقدمها النظام.
قد تقول المتطلبات
يجب أن يستطيع المستخدم إنشاء طلب.
لكن ماذا لو كان النظام سيخدم مئات الآلاف من المستخدمين؟
ماذا لو تعطل Server؟
ماذا لو توقفت Payment Gateway؟
ماذا لو كان فقدان عملية دفع واحدة غير مقبول؟
هنا تدخل Quality Attributes:
Scalability — قابلية التوسع
Availability — التوفر
Performance — الأداء
Security — الأمان
Reliability — الموثوقية
Maintainability — قابلية الصيانة
وهذه المتطلبات قد تغيّر Architecture النظام بالكامل.
ومن أكثر القرارات التي يواجهها المطورون:
Monolith أم Microservices؟
لا توجد إجابة واحدة تناسب الجميع.
قد يكون Monolith هو الخيار الأفضل لمشروع صغير أو فريق محدود لأنه أبسط في التطوير والنشر والتشغيل.
بينما قد تكون Microservices مناسبة عندما يكبر النظام، وتحتاج الخدمات إلى التوسع والنشر والعمل باستقلالية.
لكن تذكّر:
Microservices
ليست دائمًا أفضل.
لأنها تضيف تحديات في:
التواصل بين الخدمات، إدارة البيانات الموزعة، المراقبة، الاختبارات، النشر، والتعامل مع الأعطال.
لذلك لا تختَر Architecture لأنها "رائجة" او شائعة.
اخترها لأنها تحل مشكلة حقيقية في مشروعك
المعادلة الأهم:
Requirements + Constraints + Trade-offs → Architecture
ولهذا:
Good Architecture ≠ More Services
بل:
Good Architecture =
Right Decisions for the Context
المهندس الجيد لا يبحث عن أعقد Architecture، بل عن أبسط Architecture تستطيع تحقيق متطلبات النظام اليوم، وتسمح له بالتطور غدًا دون أن تتحول إلى عبء على الفريق.
Think Big → Decide Carefully → Design Clearly → Then Code
سؤال للنقاش:
لو كنت ستبدأ متجرًا إلكترونيًا جديدًا مع فريق صغير، هل ستختار Monolith أم Microservices؟ ولماذا؟
التالي في السلسلة:
#017 — Architectural Styles
Monolith، Layered، Microservices، Event-Driven… وما الفرق بينها ومتى نستخدم كل أسلوب؟
م. طارق العمري
Software Engineer | Backend Developer
#SoftwareEngineering #SoftwareArchitecture #Architecture #SystemDesign #SoftwareDesign #Monolith #Microservices #Scalability #BackendDevelopment #SystemArchitecture #SoftwareDevelopment #SoftwareEngineer #هندسة_البرمجيات #معمارية_البرمجيات #تصميم_الأنظمة #تطوير_البرمجيات
قبل أن تبدأ في كتابة التفاصيل الصغيرة داخل النظام، هناك سؤال أهم:
كيف سيبدو النظام كاملًا من الأعلى؟
هنا تأتي Software Architecture — معمارية البرمجيات.
المعمارية لا تهتم فقط بالـClasses أو Methods، بل تحدد الصورة الكبرى للنظام:
كيف نقسمه إلى مكونات؟
كيف تتواصل هذه المكونات؟
أين تُخزن البيانات؟
كيف سنتعامل مع الخدمات الخارجية؟
وكيف نجعل النظام قادرًا على التوسع، وآمنًا، ومستقرًا؟
ببساطة:
Architecture = Big Picture
Design = Details
فمثلًا:
Client → API Gateway → Services → Database
هذا قرار معماري.
أما تحديد:
OrderService
createOrder()
cancelOrder()
getOrder()
فهذه تفاصيل أقرب إلى Software Design.
لكن المعمارية لا تعتمد فقط على الوظائف التي يقدمها النظام.
قد تقول المتطلبات
يجب أن يستطيع المستخدم إنشاء طلب.
لكن ماذا لو كان النظام سيخدم مئات الآلاف من المستخدمين؟
ماذا لو تعطل Server؟
ماذا لو توقفت Payment Gateway؟
ماذا لو كان فقدان عملية دفع واحدة غير مقبول؟
هنا تدخل Quality Attributes:
Scalability — قابلية التوسع
Availability — التوفر
Performance — الأداء
Security — الأمان
Reliability — الموثوقية
Maintainability — قابلية الصيانة
وهذه المتطلبات قد تغيّر Architecture النظام بالكامل.
ومن أكثر القرارات التي يواجهها المطورون:
Monolith أم Microservices؟
لا توجد إجابة واحدة تناسب الجميع.
قد يكون Monolith هو الخيار الأفضل لمشروع صغير أو فريق محدود لأنه أبسط في التطوير والنشر والتشغيل.
بينما قد تكون Microservices مناسبة عندما يكبر النظام، وتحتاج الخدمات إلى التوسع والنشر والعمل باستقلالية.
لكن تذكّر:
Microservices
ليست دائمًا أفضل.
لأنها تضيف تحديات في:
التواصل بين الخدمات، إدارة البيانات الموزعة، المراقبة، الاختبارات، النشر، والتعامل مع الأعطال.
لذلك لا تختَر Architecture لأنها "رائجة" او شائعة.
اخترها لأنها تحل مشكلة حقيقية في مشروعك
المعادلة الأهم:
Requirements + Constraints + Trade-offs → Architecture
ولهذا:
Good Architecture ≠ More Services
بل:
Good Architecture =
Right Decisions for the Context
المهندس الجيد لا يبحث عن أعقد Architecture، بل عن أبسط Architecture تستطيع تحقيق متطلبات النظام اليوم، وتسمح له بالتطور غدًا دون أن تتحول إلى عبء على الفريق.
Think Big → Decide Carefully → Design Clearly → Then Code
سؤال للنقاش:
لو كنت ستبدأ متجرًا إلكترونيًا جديدًا مع فريق صغير، هل ستختار Monolith أم Microservices؟ ولماذا؟
التالي في السلسلة:
#017 — Architectural Styles
Monolith، Layered، Microservices، Event-Driven… وما الفرق بينها ومتى نستخدم كل أسلوب؟
م. طارق العمري
Software Engineer | Backend Developer
#SoftwareEngineering #SoftwareArchitecture #Architecture #SystemDesign #SoftwareDesign #Monolith #Microservices #Scalability #BackendDevelopment #SystemArchitecture #SoftwareDevelopment #SoftwareEngineer #هندسة_البرمجيات #معمارية_البرمجيات #تصميم_الأنظمة #تطوير_البرمجيات
#017 — Detailed Design | التصميم التفصيلي
بعد ما نحدد المعمارية العامة (Software Architecture) ونرسم الهيكل العالي للنظام، نوصل للسؤال اليومي اللي يسأله أي مهندس برمجيات حقيقي قبل ما يفتح الـ IDE:
"كيف سيعمل كل جزء داخل الكود فعليًا؟"
هنا يجي دور الـ Detailed Design (التصميم التفصيلي).
المعمارية تعطيك الصورة الكبيرة:
Services — Components — Database — Communication
أما التصميم التفصيلي، فينزل معك للتفاصيل الدقيقة اللي تبني عليها شغلك اليومي:
Classes — Methods — Interfaces — Data Models — Validation — Error Handling
التسلسل الطبيعي لأي نظام متين هو:
Architecture → Detailed Design → Code
الهدف هنا مش كتابة وثائق رسمية معقدة ولا رسم مخططات لمجرد الرسم، الهدف الحقيقي هو إزالة الغموض تمامًا قبل كتابة أول سطر كود.
فصل المسؤوليات داخل المكونات
لما يكون عندك مكون مثل Order Service، الخطأ الشائع اللي ينقع فيه في البداية هو تحويله لـ Class ضخم (God Object) يعمل كل شيء:
يتأكد من المدخلات، يحفظ في الدعم، ينفذ الدفع، ويرسل الإشعار!
التصميم الهندسي الصح هو توزيع المسؤوليات بشكل نظيف:
OrderController:
يستقبل الـ Request وينظم الـ HTTP Response.
OrderValidator:
يتحقق من صحة المدخلات وسلامة الـ Data Format.
OrderService:
يحتوي على الـ Business Logic الصافي فقط.
OrderRepository:
يتعامل مع طبقة البيانات وتخزينها.
PaymentService:
يدير عمليات التواصل مع بوابة الدفع.
NotificationService:
يتكفل بإرسال الإشعارات والبريد.
وهنا نطبق القاعدة الذهبية:
One Responsibility → One Clear Reason to Change
كلما كانت مسؤولية كل Class واضحة ومحددة، كلما كان النظام أسهل في الفهم، الصيانة، التعديل، والـ Unit Testing.
نمذجة التفاعل بين المكونات (Interactions)
التصميم التفصيلي لا يتوقف عند تحديد الـ Classes فقط، بل يتعداه لمعرفة كيف تتعاون هذه الأجزاء وتتواصل أثناء تنفيذ الـ Flow.
وهنا يأتي دور Sequence Diagram.
في سيناريو إنشاء طلب جديد (Create Order):
Customer → OrderController → OrderValidator → OrderService → OrderRepository → PaymentService → NotificationService
المخطط هذا يوضح لك بوضوح:
من يبدأ العملية؟
من يستدعي من؟
ما هو ترتيب الرسائل والعمليات؟
ومن المسؤول عن كل خطوة بدقة؟
تقليل التبعية والاعتماد على التجريد (Loose Coupling)
التصميم الجيد يقلل الارتباط المباشر بين التفاصيل التنفيذية.
بدل الاعتماد المباشر:
OrderService → MySQLOrderRepository
نعتمد على التجريد (Abstraction):
OrderService → OrderRepository Interface ← MySQLOrderRepository
بالمفهوم هذا، يمكنك مستقبلاً تغيير قاعدة البيانات من MySQL إلى PostgreSQL أو MongoDB، أو حتى استخدام Mock Repository أثناء كتابة الاختبارات، بدون ما تلمس سطر واحد في الـ Business Logic.
Depend on abstractions, not concrete details.
التفكير في الحالات الاستثنائية (Edge Cases)
أكبر خطأ يقع فيه المطور هو التصميم للـ Happy Path فقط:
Create Order → Payment Success → Order Confirmed
مهندس البرمجيات الخبير يسأل دائمًا الأسئلة الصعبة قبل البرمجة:
ماذا لو المنتج غير متوفر في المخزن؟
ماذا لو فشلت عملية الدفع أو انتهت الجلسة (Timeout)؟
ماذا لو تعطلت قاعدة البيانات أثناء الحفظ؟
ماذا لو فشل سيرفر الإشعارات؟
التصميم التفصيلي المتين يحدد الطرق التالية مسبقًا:
Success Flow
Alternative Flow
Failure & Exception Flow
قبل ما تتحول هذه الحالات إلى مفاجآت وأخطاء غريبة أثناء Production.
خريطة طريق التصميم التفصيلي
يمكن تلخيص رحلة Detailed Design في هذه الخطوات المتسلسلة:
Architecture
↓
Identify Classes
↓
Assign Responsibilities
↓
Define Interfaces
↓
Design Methods & Data Models
↓
Model Interactions (Sequence Diagrams)
↓
Handle Errors & Edge Cases
↓
Review Coupling & Cohesion
↓
Implement Code
المعادلة البسيطة:
Architecture + Detailed Design = Clean & Implementable Code
القاعدة التي يجب أن ترافقك دائمًا:
لا تجعل مرحلة الـ Coding هي المكان الذي تكتشف فيه تصميم النظام لأول مرة.
Think → Model → Detail → Code
سؤال للنقاش:
لو مر عليك كود في مشروعك الحالي فيه OrderService يقوم بإنشاء الطلب، الحفظ، الدفع، وإرسال الإشعارات... كيف تبدأ بالتدرج في إعادة هيكلته (Refactoring) وتوزيع مسؤولياته بدون ما تكسر الـ Features الشغالة؟
المنشور القادم:
#018 — Design Principles
بعد ما نحدد المعمارية العامة (Software Architecture) ونرسم الهيكل العالي للنظام، نوصل للسؤال اليومي اللي يسأله أي مهندس برمجيات حقيقي قبل ما يفتح الـ IDE:
"كيف سيعمل كل جزء داخل الكود فعليًا؟"
هنا يجي دور الـ Detailed Design (التصميم التفصيلي).
المعمارية تعطيك الصورة الكبيرة:
Services — Components — Database — Communication
أما التصميم التفصيلي، فينزل معك للتفاصيل الدقيقة اللي تبني عليها شغلك اليومي:
Classes — Methods — Interfaces — Data Models — Validation — Error Handling
التسلسل الطبيعي لأي نظام متين هو:
Architecture → Detailed Design → Code
الهدف هنا مش كتابة وثائق رسمية معقدة ولا رسم مخططات لمجرد الرسم، الهدف الحقيقي هو إزالة الغموض تمامًا قبل كتابة أول سطر كود.
فصل المسؤوليات داخل المكونات
لما يكون عندك مكون مثل Order Service، الخطأ الشائع اللي ينقع فيه في البداية هو تحويله لـ Class ضخم (God Object) يعمل كل شيء:
يتأكد من المدخلات، يحفظ في الدعم، ينفذ الدفع، ويرسل الإشعار!
التصميم الهندسي الصح هو توزيع المسؤوليات بشكل نظيف:
OrderController:
يستقبل الـ Request وينظم الـ HTTP Response.
OrderValidator:
يتحقق من صحة المدخلات وسلامة الـ Data Format.
OrderService:
يحتوي على الـ Business Logic الصافي فقط.
OrderRepository:
يتعامل مع طبقة البيانات وتخزينها.
PaymentService:
يدير عمليات التواصل مع بوابة الدفع.
NotificationService:
يتكفل بإرسال الإشعارات والبريد.
وهنا نطبق القاعدة الذهبية:
One Responsibility → One Clear Reason to Change
كلما كانت مسؤولية كل Class واضحة ومحددة، كلما كان النظام أسهل في الفهم، الصيانة، التعديل، والـ Unit Testing.
نمذجة التفاعل بين المكونات (Interactions)
التصميم التفصيلي لا يتوقف عند تحديد الـ Classes فقط، بل يتعداه لمعرفة كيف تتعاون هذه الأجزاء وتتواصل أثناء تنفيذ الـ Flow.
وهنا يأتي دور Sequence Diagram.
في سيناريو إنشاء طلب جديد (Create Order):
Customer → OrderController → OrderValidator → OrderService → OrderRepository → PaymentService → NotificationService
المخطط هذا يوضح لك بوضوح:
من يبدأ العملية؟
من يستدعي من؟
ما هو ترتيب الرسائل والعمليات؟
ومن المسؤول عن كل خطوة بدقة؟
تقليل التبعية والاعتماد على التجريد (Loose Coupling)
التصميم الجيد يقلل الارتباط المباشر بين التفاصيل التنفيذية.
بدل الاعتماد المباشر:
OrderService → MySQLOrderRepository
نعتمد على التجريد (Abstraction):
OrderService → OrderRepository Interface ← MySQLOrderRepository
بالمفهوم هذا، يمكنك مستقبلاً تغيير قاعدة البيانات من MySQL إلى PostgreSQL أو MongoDB، أو حتى استخدام Mock Repository أثناء كتابة الاختبارات، بدون ما تلمس سطر واحد في الـ Business Logic.
Depend on abstractions, not concrete details.
التفكير في الحالات الاستثنائية (Edge Cases)
أكبر خطأ يقع فيه المطور هو التصميم للـ Happy Path فقط:
Create Order → Payment Success → Order Confirmed
مهندس البرمجيات الخبير يسأل دائمًا الأسئلة الصعبة قبل البرمجة:
ماذا لو المنتج غير متوفر في المخزن؟
ماذا لو فشلت عملية الدفع أو انتهت الجلسة (Timeout)؟
ماذا لو تعطلت قاعدة البيانات أثناء الحفظ؟
ماذا لو فشل سيرفر الإشعارات؟
التصميم التفصيلي المتين يحدد الطرق التالية مسبقًا:
Success Flow
Alternative Flow
Failure & Exception Flow
قبل ما تتحول هذه الحالات إلى مفاجآت وأخطاء غريبة أثناء Production.
خريطة طريق التصميم التفصيلي
يمكن تلخيص رحلة Detailed Design في هذه الخطوات المتسلسلة:
Architecture
↓
Identify Classes
↓
Assign Responsibilities
↓
Define Interfaces
↓
Design Methods & Data Models
↓
Model Interactions (Sequence Diagrams)
↓
Handle Errors & Edge Cases
↓
Review Coupling & Cohesion
↓
Implement Code
المعادلة البسيطة:
Architecture + Detailed Design = Clean & Implementable Code
القاعدة التي يجب أن ترافقك دائمًا:
لا تجعل مرحلة الـ Coding هي المكان الذي تكتشف فيه تصميم النظام لأول مرة.
Think → Model → Detail → Code
سؤال للنقاش:
لو مر عليك كود في مشروعك الحالي فيه OrderService يقوم بإنشاء الطلب، الحفظ، الدفع، وإرسال الإشعارات... كيف تبدأ بالتدرج في إعادة هيكلته (Refactoring) وتوزيع مسؤولياته بدون ما تكسر الـ Features الشغالة؟
المنشور القادم:
#018 — Design Principles
كيف تساعدنا مبادئ مثل SRP و OCP و Dependency Inversion على بناء تصميم مرن، قابل للتوسع والتغيير بكل سهولة؟
م.طارق العمري
Software Engineer| Backend Developer
#SoftwareEngineering #DetailedDesign #SoftwareDesign #SystemDesign #CleanArchitecture #SOLID #BackendDevelopment #CleanCode #SoftwareEngineer #هندسة_البرمجيات #التصميم_التفصيلي #تطوير_البرمجيات
م.طارق العمري
Software Engineer| Backend Developer
#SoftwareEngineering #DetailedDesign #SoftwareDesign #SystemDesign #CleanArchitecture #SOLID #BackendDevelopment #CleanCode #SoftwareEngineer #هندسة_البرمجيات #التصميم_التفصيلي #تطوير_البرمجيات