أدوات التصميم المستندة إلى المجال

الحوت الأزرق هو مثال رائع على الخطأ الذي حدث في تصميم مشروع معقد. يبدو الحوت وكأنه سمكة ، ولكنه ثديي: فهو يغذي الأشبال بالحليب ، وله شعر ، ولا تزال عظام الساعد والأصابع ، مثل تلك الموجودة على الأرض ، محفوظة في الزعانف. يعيش في المحيطات ، لكنه لا يستطيع التنفس تحت الماء ، لذلك يرتفع بانتظام إلى السطح لابتلاع الهواء ، حتى عندما يكون نائمًا. الحوت هو أكبر حيوان في العالم ، بطول منزل من تسعة طوابق ، ويزن 75 سيارة فولكس واجن طوارق ، ولكنه ليس مفترسًا ، ولكنه يتغذى على العوالق.

عندما عمل المطورون على الحوت ، لم يبدأوا في كتابة كل شيء من الصفر ، ولكنهم استخدموا التجربة من المشاريع القديمة. يبدو أنه مرصوف بالحصى معًا من أجزاء غير متوافقة من الكود لم يتم اختبارها ، وقد جاء كل التصميم لاختيار إطار و "تدوير" عاجل قيد الإنتاج بالفعل. ونتيجة لذلك ، تبين أن المشروع جميل في المظهر ، ولكن مع قطع من التراث الكثيفة والعكازات تحت غطاء المحرك.



لإنشاء مشاريع تساعد الشركات على كسب المال ، بدلاً من أن تبدو كحيوان بحري لا يمكنه التنفس تحت الماء ، هناك DDD. هذا نهج لا يركز على الأدوات أو التعليمات البرمجية ، ولكن على دراسة مجال الموضوع ، وعمليات الأعمال الفردية وكيفية عمل التعليمات البرمجية أو الأدوات لمنطق الأعمال.

ما هو DDD وما هي الأدوات الموجودة فيه ، سنخبره في مقالة تستند إلى التقريرأرتيوم ماليشيف . نهج DDD في Python ، الأدوات ، المزالق ، برمجة العقد وتصميم المنتج حول المشكلة التي يتم حلها ، بدلاً من الإطار المستخدم ، كلها تحت القطع.

عرض كامل للتقرير .

أرتيم ماليشيف (برهان 404) - مطور مستقل ، كتب في Python لمدة 5 سنوات ، ساعد بنشاط مع Django Channels 1.0. في وقت لاحق ركز على الأساليب المعمارية: درس الأدوات التي يفتقر إليها المهندسون المعماريون في Python وبدأ مشروع الثعبان الجاف . المؤسس المشارك لـ Drylabs.

تعقيد


ما هي البرمجة؟
البرمجة هي صراع مستمر مع التعقيد الذي يبتكره المطورون أنفسهم عندما يحاولون حل المشكلات.
ينقسم التعقيد إلى نوعين: مقدمة وطبيعية. يمتد البرنامج المقدم إلى جانب لغات البرمجة ، والأطر ، ونظام التشغيل ، ونموذج عدم التزامن. هذا تحد تقني لا ينطبق على الأعمال. التعقيد الطبيعي مخفي في المنتج ويبسط حياة المستخدمين - لأن هؤلاء الناس يدفعون المال.
يجب على المهندسين الجيدين تقليل التعقيد الإضافي وزيادة الطبيعة لزيادة فائدة المنتج.
لكن نحن المبرمجين أشخاص معقدون ونحب إضافة التعقيد التقني للمشاريع. على سبيل المثال ، لم نهتم بمعايير التشفير ، ولم نستخدم ممارسات تصميم الوحدات النمطية ، واستلمنا الكثير من كود الأنماط في المشاريع if c==1.

كيف تعمل مع هذا الرمز؟ اقرأ الكثير من الملفات وافهم المتغيرات والظروف ومتى وكيف ستعمل جميعًا. من الصعب تذكر هذا الرمز - التعقيد الفني المضاف تمامًا.

مثال آخر على التعقيد الإضافي هو "رد الاتصال" المفضل لدي.



عندما نكتب في إطار بنية موجهة نحو الحدث (EDA) ونختار إطارًا حديثًا غير جيد ، نحصل على رمز لا يتضح فيه ما يحدث ومتى. من الصعب قراءة مثل هذا الرمز - هذا هو التعقيد الإضافي مرة أخرى.

لا يعشق المبرمجون الصعوبات التقنية فحسب ، بل يجادلون أيضًا أيهما أفضل:

  • AsyncIO أو Gevent ؛
  • PostgreSQL أو MongoDB ؛
  • Python أو Go ؛
  • Emacs أو Vim ؛
  • علامات التبويب أو المسافات ؛

الجواب الصحيح لمبرمج جيد لكل هذه الأسئلة: "لا فرق!" لا يجادل المطورون الجيدون حول الخيول الكروية في فراغ ، ولكنهم يحلون مشاكل العمل ويعملون على فائدة المنتج. قام بعضهم منذ فترة طويلة بتأسيس مجموعة من الممارسات التي تقلل من التعقيد الذي تم تقديمه وتساعدك على التفكير أكثر في العمل.

واحد منهم هو إريك إيفانز . في عام 2004 ، كتب كتاب تصميم المجال. لقد "أطلقت النار" وأعطت دفعة للتفكير أكثر في العمل ، ودفع التفاصيل الفنية في الخلفية.



ما هو DDD؟


أولاً حل المشكلة ، ثم الأدوات . بادئ ذي بدء ، استثمر إيفانز في مفهوم DDD ، أن هذه ليست تقنية ، ولكنها فلسفة. في الفلسفة ، تحتاج أولاً إلى التفكير في كيفية حل المشكلة ، وعندها فقط ، بمساعدة الأدوات.

اعمل على النماذج مع خبراء في الموضوع ومطوري البرامج. يجب أن نتواصل مع أشخاص من رجال الأعمال: ابحث عن لغة مشتركة ، وقم ببناء نموذج للعالم يعمل من خلاله منتجنا ويحل المشاكل.

اكتب برمجيات تعبر بوضوح عن النماذج. أهم فرق بين DDD والتعاون البسيط في الفريق هو أنه يجب علينا كتابة برنامج بنفس الأسلوب الذي نتحدث فيه مع خبراء المجال. يجب تخزين جميع المصطلحات ومناهج المناقشة واتخاذ القرار في شفرة المصدر حتى يتمكن الشخص غير التقني من فهم ما يحدث هناك.

تحدث نفس اللغة مع العمل . DDD هي فلسفة حول كيفية التحدث بنفس اللغة مع خبراء الأعمال في مجال معين وتطبيق المصطلحات على هذا المجال. لدينا لغة مشتركة أو لهجة مشتركة ضمن السياق المرتبط ، والذي نعتبره صحيحًا. نضع حدودًا حول الحلول المعمارية.

DDD لا يتعلق بالتكنولوجيا.

أولا ، الجزء الفني ، ثم - DDD. النحات الذي ينحت التمثال من الحجر لا يقرأ دليل كيفية حمل المطرقة والإزميل - فهو يعرف بالفعل كيفية العمل معهم. لإحضار DDD إلى مشروعك ، أتقن الجزء الفني: تعلم Django حتى النهاية ، واقرأ البرنامج التعليمي وتوقف عن الجدل حول استخدام PostgreSQL أو MongoDB.

معظم أنماط وأنماط التصميم هي ضوضاء فنية. معظم الأنماط التي نعرفها ونستخدمها تقنية. يقولون كيفية إعادة استخدام التعليمات البرمجية ، وكيفية بنائها ، لكنهم لا يذكرون كيفية استخدامها للمستخدمين والشركات ، ونمذجة العالم الخارجي. لذلك ، فإن المصانع أو الطبقات المجردة مرتبطة بشكل غير مباشر بـ DDD.

صدر أول كتاب "أزرق" قبل 20 عامًا تقريبًا. حاول الناس الكتابة بهذا الأسلوب ، وساروا في أشعل النار ، وأدركوا أن الفلسفة جيدة ، ولكن في الواقع غير مفهومة. لذلك ، ظهر كتاب ثان - "أحمر" ، حول كيف يفكر المبرمجون ويكتبون في DDD.


الكتب "الحمراء" و "الزرقاء" هي الركائز التي تقف عليها جميع DDD.

ملحوظة. الكتب الحمراء والزرقاء هي مصدر فريد للمعلومات حول DDD ، لكنها ثقيلة. ليس من السهل قراءة الكتب: في الأصل بسبب اللغة والمصطلحات المعقدة ، وباللغة الروسية بسبب الترجمة السيئة. لذلك ، ابدأ في تعلم DDD بكتاب أخضر . هذه نسخة مبسطة من الأولين مع أمثلة أبسط وأوصاف عامة. ولكن هذا أفضل مما لو كانت الكتب الحمراء والزرقاء تتغلب على رغبتك في الدراسة وتطبيق DDD. من الأفضل أن تقرأ في الأصل.

يتخطى الكتاب الأحمر فكرة أفضل طريقة لإدخال DDD في المشروع ، وكيفية تنظيم العمل حول هذا النهج. تظهر مصطلحات جديدة - "التصميم القائم على النموذج" ، حيث يتم وضع نموذجنا للعالم الخارجي في المقام الأول.



تم اختيار تقنية المكان الوحيد وهي Smart UI. هذه طبقة بين العالم الخارجي والمستخدم ولنا (إشارة إلى روبرت مارتن وهندسته النظيفة ذات الطبقات). كما ترون ، كل شيء يذهب إلى النموذج.

ما هو النموذج؟ هذا هو الألم الوهمي لأي مهندس معماري. يعتقد الجميع أن هذا هو UML ، ولكنه ليس كذلك.
النموذج هو مجموعة من الفئات والأساليب والروابط بينها التي تعكس سيناريوهات العمل في البرنامج.
يعكس النموذج كائنًا حقيقيًا يحتوي على جميع الخصائص والوظائف اللازمة. هذه مجموعة أدوات عالية المستوى لاتخاذ القرارات من وجهة نظر حالات العمل. ومع ذلك ، تعد الأساليب والفصول مجموعة أدوات منخفضة المستوى للحلول المعمارية.

الثعبان الجاف


لملء مكانة النموذج ، بدأت مشروع الثعبان الجاف الذي نما إلى مجموعة من مكتبة معمارية عالية المستوى لبناء تصميم مدفوع بالنموذج. كل من المكتبات تحاول إغلاق دائرة واحدة في الهندسة المعمارية ولا تتداخل مع الأخرى. يمكن استخدام المكتبات بشكل منفصل ، أو معًا إذا كان لديك ذوق.



يتوافق تسلسل السرد مع التسلسل الزمني للإضافة المثلى لـ DDD إلى المشروع - بواسطة طبقات. الطبقة الأولى هي الخدمات ، وهي وصف لسيناريوهات الأعمال (العمليات) في نظامنا. مكتبة القصص مسؤولة عن هذه الطبقة.

قصص


تنقسم سيناريوهات الأعمال إلى ثلاثة أجزاء:

  • المواصفات - وصف عملية الأعمال ؛
  • الحالة التي قد يوجد فيها سيناريو العمل
  • تنفيذ كل خطوة من البرنامج النصي.

يجب ألا تكون هذه الأجزاء مختلطة. تفصل مكتبة القصص هذه الأجزاء وترسم خطًا واضحًا بينها.

ضع في اعتبارك إدخال DDD و Stories مع مثال. على سبيل المثال ، لدينا مشروع على Django مع مزيج من إشارات Django ونماذج "سميكة" غامضة. أضف حزمة خدمات فارغة إليها. باستخدام مكتبة القصص في أجزاء ، نعيد كتابة هذه التجزئة إلى مجموعة واضحة ومفهومة من النصوص في مشروعنا.

مواصفات DSL. تسمح لك المكتبة بكتابة مواصفة وتوفر DSL لذلك. هذه طريقة لوصف إجراءات المستخدم خطوة بخطوة. على سبيل المثال ، للشراء subscription، أتبع عدة خطوات: سوف أجد طلبًا ، وأتحقق من صلة السعر ، وتحقق مما إذا كان بإمكان المستخدم تحمله. هذا وصف عالي المستوى.

عقد.أسفل هذه الفئة ، سنكتب عقدًا لحالة سيناريو الأعمال. للقيام بذلك ، نشير إلى منطقة المتغيرات التي تنشأ في عملية الأعمال ، ولكل متغير تعيين مجموعة من المصادقين.

بمجرد أن يحاول شخص ما تعيين متغير لهذه المنطقة كجزء من عملية العمل ، سيتم وضع مجموعة من أدوات التحقق. سنكون على يقين من أن حالة العملية في وقت التشغيل تعمل دائمًا. ولكن إذا لم يكن كذلك ، فإنه يسقط بشكل مؤلم ويصرخ بصوت عال حول هذا الموضوع.

مرحلة تنفيذ كل خطوة . في نفس الفصل ، subscriptionنكتب مجموعة من الأساليب التي تتوافق أسماؤها مع خطوات العمل. تتلقى كل طريقة إدخال حالة يمكنها العمل بها ، ولكن ليس لديها الحق في تعديلها. قد ترجع الطريقة بعض العلامات والتقرير:

  • , () ;
  • - , .


هناك علامات أكثر تعقيدًا: يمكنهم تأكيد أن الدولة تعمل ، وتقترح حذف أو تغيير بعض أجزاء من عملية الأعمال. يمكنك أيضًا الكتابة في الفصول.

إطلاق القصة. كيفية تشغيل القصة عند التنفيذ؟ هذا كائن أعمال يعمل كطريقة: نقوم بنقل البيانات إلى الإدخال ، والتحقق من صحتها ، وتفسير الخطوات. تتذكر القصة الجارية تاريخ التنفيذ ، وتسجل الحالة التي حدثت فيه في عملية الأعمال ، وتخبرنا من أثر على هذه الحالة .

شريط أدوات التصحيح. إذا كتبنا في Django واستخدمنا لوحة التصحيح ، فيمكننا رؤية سيناريوهات الأعمال التي تمت معالجتها في كل طلب وحالتها.

Py.test. إذا كتبنا في py.test ، فعند الاختبار المتساقط ، يمكننا أن نرى ما هي البرامج النصية للأعمال التي تم تنفيذها في كل سطر وما الخطأ الذي حدث. هذا مناسب - بدلاً من اختيار الشفرة ، نقرأ المواصفات ونفهم ما حدث.



خفير. والأفضل من ذلك ، عندما نحصل على الخطأ 500. في النظام العادي ، نتحمله ونبدأ في التحقيق. في Sentry ، سيظهر تقرير مفصل حول ما فعله المستخدم لارتكاب الخطأ. إنها مريحة وممتعة عندما يتم جمع هذه المعلومات في الساعة 3 صباحًا.


إلك . الآن نحن نعمل بنشاط على مكون إضافي يكتب كل هذا في Elasticsearch إلى مكدس Kibana ويبني فهارسًا مختصة.



على سبيل المثال ، لدينا عقد لحالة عملية تجارية. نحن نعرف ما هو موجود ، على سبيل المثال ،relation IDنقل. بدلاً من البحث القديم عما حدث هناك ، نكتب طلبًا في كيبانا. سيعرض كل القصص المتعلقة بمستخدم معين. بعد ذلك ، نقوم بفحص الحالة في عمليات الأعمال وسيناريوهات العمل الخاصة بنا. نحن لا نكتب سطرًا واحدًا من رمز التسجيل ، ولكن يتم تسجيل المشروع على مستوى التجريد الذي نحن مهتمون بمشاهدته.

لكني أريد شيئًا أعلى ، على سبيل المثال ، الأشياء الخفيفة. تحتوي هذه الكائنات على هياكل وطرق بيانات متعلمة تتعلق بتبني قرارات العمل ، وليس العمل مع قاعدة البيانات ، على سبيل المثال. لذلك ، ننتقل إلى الجزء التالي من العمارة القائمة على النموذج - الكيانات ، والمتفق عليها ، وكائنات القيمة.



الكيانات ، والاتفاق ، وقيمة الأشياء


كيف يتم ربط كل هذا؟ على سبيل المثال ، يقوم المستخدم بتقديم طلب منتج ونحن نقوم بعمل فاتورة. ما هو أصل التجميع ، وما هو الشيء البسيط؟



كل ما تم تسطيره هو جذر التجميع. هذا ما أريد أن أعمل معه مباشرة: مهم وقيم وشمولي.

من أين نبدأ؟ سنقوم بإنشاء حزمة فارغة في المشروع ، حيث سنضع وحداتنا. من الأفضل كتابة المجاميع باستخدام شيء إعلاني ، مثل dataclassesأو attrs.

مجموعات البيانات . إذا dataclassأشرنا إلى نوع ما من التجميع ، فسوف نكتب تعليقًا توضيحيًا عليه باستخدام NewType . في التعليق التوضيحي ، نشير إلى مرجع صريح ، يتم التعبير عنه في نظام النوع. إذا كان dataclassمجرد هيكل (كيان) بيانات ، فاحفظه داخل التجميع.

في سياق القصص ، يمكن أن تتجمع المجاميع فقط. لا يمكن الوصول إلى شيء مضمن فيها إلا من خلال الأساليب العامة والقواعد عالية المستوى. يسمح لك هذا ببناء نموذج منطقي وكفء نعمل من خلاله مع خبراء من مجال الموضوع. هذه هي نفس اللغة المفردة .



تبرز المشكلة على الفور - مستودعات. لدي قاعدة بيانات أعمل من خلالها من خلال Django ، وهي خدمة صغيرة مجاورة أرسل إليها الطلبات ، هناك JSON ومثيل من نموذج Django. لتلقي البيانات ونقلها يدويًا ، فقط للاتصال أو اختبار الطريقة بشكل جميل؟ بالطبع لا. تحتوي Dry-python على مكتبة Mappers التي تسمح لك بتعيين تجريدات عالية المستوى وتجميعات المجال إلى الأماكن التي نخزنها فيها.

مصممي الخرائط


نضيف حزمة أخرى إلى مشروعنا - مستودع نخزن فيه مشروعنا mappers. هذه هي الطريقة التي سننقل بها منطق الأعمال عالي المستوى إلى العالم الحقيقي.

على سبيل المثال ، يمكننا أن نصف كيف نقوم بتعيين واحد dataclassلنموذج Django.

Django ORM. قارنا نموذج الطلب مع وصف Django ORM - نحن ننظر إلى الحقول.

على سبيل المثال ، يمكننا إعادة كتابة بعض الحقول من خلال التكوين الاختياري. سيحدث ما يلي: mapperسيقارن أثناء الإعلان كيفية كتابة dataclassالنموذج. على سبيل المثال ، التعليقات التوضيحية int( Order dataclassيوجد حقل costبه تعليق توضيحي int) في نموذج Django تتوافق integer fieldمع الخيار nullable="true". هنا سوف dataclassتقدم لإضافة optionalل dataclass، أو لإزالةnullableمن field.

من خلال مصممي الخرائط ، يمكنك إضافة وظائف لقراءة أو كتابة شيء ما. القراء هم الوظائف التي تتلقى تجميعًا عند الإدخال وإرجاع مرجع إليه. يقوم الكتاب بالعكس - وحدات العودة. تحت غطاء المحرك ، على سبيل المثال ، قد يكون هناك طلب لقاعدة البيانات من خلال Django.

تعريفات اختيال يمكن إجراء نفس العمليات باستخدام الخدمات الدقيقة. يمكنك كتابة جزء من مخطط التبادل عليها والتحقق من مدى تطابق مخطط التبجح لخدمة معينة مع نماذج المجال الخاص بك. علاوة على ذلك ، سيتم ترجمة الطلب المرتجع من مكتبة الطلبات بشفافية إلى dataclass.

استعلامات GraphQL. GraphQL و microservices: يعمل مخطط نوع واجهة GraphQL بشكل جيد مقابلdataclass. يمكنك ترجمة استعلامات GraphQL محددة إلى هياكل بيانات داخلية.

لماذا تهتم بنموذج البيانات الداخلي عالي المستوى داخل التطبيق؟ لتوضيح "لماذا" ، سأروي قصة "مسلية".

في أحد مشاريعنا ، عملت مآخذ الويب من خلال خدمة Pusher. لم نتعب نفسك ، قمنا بلفه في واجهة حتى لا نتصل مباشرة. تم ربط هذه الواجهة في جميع القصص وكانت راضية.

لكن متطلبات العمل تغيرت. اتضح أن الضمانات التي يوفرها Pusher لمقابس الويب ليست كافية. على سبيل المثال ، أنت بحاجة إلى تسليم رسائل مضمون وسجل الرسائل لآخر دقيقتين. لذلك ، قررنا الانتقال إلى خدمة Ably Realtime. يحتوي أيضًا على واجهة - سنكتب محولًا وربطه في كل مكان ، كل شيء سيكون رائعًا. ليس صحيحا.

يتم تجريد الملخصات التي يستخدمها Pusher (وسيطات الدوال) في كل عنصر أعمال. كان عليّ أن أصلح حوالي 100 قصة ، وأصلح تشكيل قناة المستخدم التي نرسل إليها شيئًا.

العودة إلى الاختبارات.

الاختبارات والنماذج


كيف تختبر عادة هذا السلوك مع الخدمات الخارجية؟ نحن نبلل شيئًا ، نحن نشاهد كيف يتم استدعاء مكتبة طرف ثالث ، وهذا كل شيء - نحن على يقين من أن كل شيء على ما يرام. ولكن عندما تتغير المكتبة ، تتغير صيغ الحجة أيضًا.

يمكنك توفير أسبوع لإعادة كتابة آلاف الاختبارات ومئات الحالات التجارية إذا اختبرت سلوك النموذج الداخلي بشكل مختلف. على سبيل المثال ، شيء مشابه لاختبار التكامل: نكتب إلى دفق المستخدم ، وبالفعل داخل المهايئ ، Pusher أو Ably نترجم هذا الدفق إلى اسم القناة العادية حتى لا نكتبه كله في منطق الأعمال.

التبعيات


في بنية النموذج هذه ، تظهر العديد من الكيانات غير الضرورية. في السابق ، أخذنا نوعًا من وظيفة Django وكتبناها: الطلب والاستجابة والحد الأدنى من حركات الجسم. هنا تحتاج إلى تهيئة المخططين ، ووضع القصص وتهيئة ، ومعالجة سطر الطلب الخاص بطلب HTTP ، ومعرفة الإجابة التي يجب تقديمها. كل هذا يؤدي إلى 30-50 سطرًا من رمز استدعاء الغلاية قصص داخل Django-view.

من ناحية أخرى ، قمنا بالفعل بكتابة واجهات ومصممي الخرائط. يمكننا التحقق من توافقها مع حالة عمل معينة ، على سبيل المثال ، باستخدام مكتبة التبعيات. كيف؟ من خلال نمط حقن التبعية ، يتم لصق كل شيء بشكل معلن على الحد الأدنى من الصفيحة.

هنا نشير إلى مهمة أخذ فئة في حزمة الخدمات ، وطرح ثلاثةmappers، قم بتهيئة كائن القصص وإعطائه لنا. مع هذا النهج ، يتم تقليل عدد الصفيحة في الرمز بشكل كبير.

خريطة إعادة بيع ديون


باستخدام كل ما تحدثت عنه ، قمنا بتطوير مخطط نعيد من خلاله إعادة كتابة مشروع كبير من إشارات Django ("جحيم رد الاتصال" الضمني) إلى Django باستخدام DDD.

الخطوة الأولى بدون DDD . في البداية لم يكن لدينا DDD - كتبنا MVP. عندما حققوا أول أموالهم ، دعوا المستثمرين ، وأقنعوهم بالانتقال إلى DDD.

قصص بدون عقود. قمنا بتقسيم المشروع إلى حالات عمل منطقية بدون عقود بيانات.

العقود و الركام . ثم ، واحدًا تلو الآخر ، قمنا بسحب عقد البيانات لكل نموذج ، والذي يمكن تتبعه في هندستنا.

مصممي الخرائط . كتب مصممو الخرائط للتخلص من قوالب مستودع البيانات.

حقن التبعية . تخلص من أنماط اللصق.

إذا تجاوز مشروعك MVP ويحتاج بشكل عاجل إلى تغييره في الهندسة المعمارية بحيث لا ينزلق إلى إرث - انظر نحو DDD.

legacy Python-, , , Moscow Python Conf++ 27 . Python . unconference, , , , Drylabs.

DDD Python, TechLead ConfIT-, DDD . 8 , Call for Papers 6 .

All Articles