نحوّل الكيان لجدول… من غير ما نبوّظ منطق السيستم

أحمد رمضان

. 4 د قراءة

Advanced Web Application ArchitectureChapter: The Domain Model – Mapping entity data to table columns (2.5)في النقط اللي فاتت من الكتاب، اتكلمنا عن مفاهيم مهمة جدًا:Domainهو المجال اللي التطبيق شغال فيه (بيع كتب – حجز – توصيل… إلخ) Modelهو التمثيل المنطقي للحكاية اللي البزنس عايز يحكيهاGatewayطريقة نشيل بيها الـ SQL من الكود، وكل Class يمثل جدول كامل في الداتابيزEntityلما نقول Orderإحنا مش بنقول row في جدول إحنا بنقول: Order = طلب حقيقي في البزنس عنده:
Email
Quantity
Amount
ومحمي بقواعد (Assertions) مينفعش يبقى مش تمام

Repository Pattern

الـ Repository مجرد طبقة وسيطة بين عالمين:

👈 Domain → Objects، Rules، Business Logic
👈 Database → Tables، Rows، Arrays، SQL
----------------------------------------------------------------------------------------------------------------------

كده إحنا واقفين فين؟

إحنا وصلنا للحالة دي:


و بعد كدا عملنا كدا 

save وفي الكنترولر ارجع للريبو باترن الفصل الي فات 

كده تمام… شكليًا.

لكن ❗

لسه مفيش Implementation وهنا بيبدأ فصل 2.5 


يعني إيه: Mapping entity data to table columns؟


👈 تحويل بيانات الـ Entity من Object إلى Array مناسب للداتابيز

ليييييييييييه

👈 علشان الدومين بيتكلم Object
👈 الداتابيز بتفهم Array
👈 أنا كلمت البزنس بلغته دلوقتي محتاج أكلم الداتابيز بلغتها

وهنا بيظهر دور الـ Repository

👈 يا Repo خد الـ Object وترجمه لـ Array علشان أقدر أكلّم SQL

ال Mapping شكله عامل إزاي؟

👈 زي الترجمة بالظبط cat => قطة

هنا ف ال Implementation بقا اي بيقابل اي 


👈 property في الـ Object يقابلها column في الجدول
Entity (Order)                                 Table (orders)
emailAddress                                                 quantity
pricePerUnitInCents                                                        price
quantityOrdered                                                 quantity


وده اسمه Mapping


المشكلة التقنية الحقيقية

الواقع التقني بيقول الدومين شغال بـ Objects SQL شغال بـ Tables / Columns / Rows


SQL محتاج 

لكن أنا معايا:


-------------------------------------------------------------------------------------------------

وده اسمه رسميًا  Object–Relational Impedance Mismatc و هوه عدم توافق طبيعي بين عالمين مختلفين 


و هنستخدم له Mapping  الي انتا لسه قارءه فوق علشان نحلها 

-------------------------------------------------------------------------------------------------

ازااااي بقا

اولا هيه المشكلة بتظهر فين؟

جوه الـ Repository

السؤال الكبير و المهم جدااااااااااااااااااااااااااااااا


أجيب الـ $data ده منين؟

أنا معايا: Order Object
والـ SQL عايز: columns => values

Listing 2.10 – أول محاولة حقيقية



-------------------------------------------------------------------

كل حاجة واضحة… إلا حتة واحدة $data ييجي منين؟

-------------------------------------------------------------------

في حلّين أساسيين

1️⃣ ORM
2️⃣ Manual Mapping


2.5.1

Using an ORM

Object Relational Mapper يعني إيه؟


أداة تاخد Object تحوّله SQL وترجعه Object
من غير ما تكتب:( mapping بعدين insert او update) 

هنستخدم Doctrine ORM

👈 يقرأ الـ Entity
👈 يعرف الـ properties
👈 يعرف اسم الجدول
👈 يعرف الأعمدة
👈 يبني SQL
👈 يحفظ
👈 ويرجع ID


EntityManager يعني إيه؟


هو العقل المدبر يتتبع الـ objects يعرف مين جديد مين اتعدل ينفذ SQL في الآخر


Listing 2.11 – الـ Annotations



دي مش SQL دي Metadata عبارة عن تعليمات بتقول:


ده Entity يتحفظ في جدول اسمه orders الـ property دي تتحفظ في column


مميزات ORM

كود أقل
سرعة في البداية
Tools جاهزة

عيوب ORM

Magic كتير
Debug صعب
مفاجآت أداء
abstraction زيادة


--------------------------------------------------------------------------------------------------

2.5.2 Manual Mapping (المهم بقى)


طب ما نكتب المابنج بإيدنا من غير ORM من غير سحر كل حاجة واضحة

الاختيار الأول – Entity تعمل المابنج (Listing 2.14)

هنخش جوه ال entity و هتكون كدا 

وفي الريبو:


المميزات => هنشرحها تحت كمل المقال للاخر

Encapsulation محفوظ
Entity متحكمة في نفسها
Refactoring أسهل

العيب

Entity عرفت أسماء الأعمدة


الاختيار التاني – Repo تعمل المابنج (Listing 2.15)

العيب الكبير =>هنشرحها تحت كمل المقال للاخر

كسر Encapsulation
Repository عرف تفاصيل داخلية
أي تغيير يكسر الاتنين


--------------------------------------------------------------------------------------------------

Entity من حقها تعرف إزاي تتحفظ Mapping مش dependency تشغيلية 

mappedData() شغالة من غير DB Core Code لسه Core

--------------------------------------------------------------------------------------------------


يعني إيه Encapsulation أصلًا؟


Encapsulation = التغليف

يعني اي 
يعني الكلاس مسؤول عن نفسه هو الوحيد اللي يعرف
تفاصيله الداخلية و أسماء الـ properties و ترتيبهم و منطق التعامل معاهم

واللي برّه الكلاس 

يتعامل معاه عن طريق methods واضحة من غير ما يعرف هو متكوّن من إيه جوه

---------------------------------------------------------------------------------------

Encapsulation مش معناها  ”مفيش حد يشوف حاجة“

Encapsulation معناها ”إنت اللي تقرر إيه يطلع وإيه يفضل مستخبي“

--------------------------------------------------------------------------------------

إحنا عندنا Entity  عارفة كل ال props بتاعتها و دا الي مميزها 


الـ properties private
محدش برّه الكلاس يقدر يلمسهم
ده أول مستوى Encapsulation


Encapsulation الحقيقي مش بس private

Encapsulation = مين مسيطر على الداتا؟

--------------------------------------------------------------------------------------


اما لما خليت الEntity تطلع كل ال props خام كدا و ال Repo هوه الي يعمل ال map ع الداتا عنده 

دا الي انا عملته ب الظبط الOrder قال خد كل اللي جوايا زي ما هو
من غير فلترة
من غير تحكم


و زي موضحنا فوق الريبو خد الداتا و عمل map ليه بقا ال Encapsulation اتكسر 


علشان الـ Repository عرف

👈 اسم الـ property
👈 شكل الـ Entity من جوه
👈 ترتيب الداتا
👈 إن email اسمها emailAddress
👈  إن quantity اسمها quantityOrdered


----------------------------------------------------------------------------------

Repository بقى معتمد على التفاصيل الداخلية

Order بقى مش حر يغيّر نفسه

----------------------------------------------------------------------------------

لو قررت تغيّر:

private string $emailAddress

الي 

private string $email

هيحصل إيه؟

👈  Repository يبوظ
👈  مفيش Error واضح
👈  Bug صامت
👈  كسر في السيستم

وده اسمه Encapsulation Leak

يعني التغليف اتفتح، واللي برّه بقى شايف جوه.

ليه ده خطر؟

علشان أي refactor صغير في الـ Entity يكسر الـ Repository من غير ما تحس ومن غير ما الكود يقولك وده عكس هدف الدومين تمامًا.


سؤال طب ما Entity كده عرفت أسماء columns دا كدا مش ده كسر؟

وجود أسماء أعمدة ≠ كسر Encapsulation

ليه؟

علشان Entity ما طلّعتش internals و ما كشفتش properties و قدّمت API واضح و هوه لما عملنا الmappedData 

الفرق الجوهري هنا مين متحكم و لو عملت Refactor جوه ال Entity هتأثر ع الي برا ولا لأ ؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟

internalData → Repository
mappedData → Entity

----------------------------------------------------------------------------------

الخلاصة اللي تمسكها بإيدك

كسر Encapsulation يحصل لما

👈 Repository يعرف أسماء properties
👈 Repository يعتمد على شكل الكلاس من جوه
👈 Repository يعمل mapping بنفسه

Encapsulation محفوظ لما:

👈 Entity تتحكم في اللي يطلع
👈 Repository يتعامل مع method مش internals
👈 التغيير جوه Entity ما يكسرش اللي برّه

الجملة الذهبية بقى 🧠

Encapsulation مش إنك تخبّي الداتا
Encapsulation إنك تتحكم في مين يشوف إيه

وده بالظبط اللي حصل في:

mappedData()
واتفشل في:
internalData()