الدول العالمية: لماذا وكيف نتجنبها


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

كل هذا يمكن أن يكون عواقب مزعجة للعالمية: المتغيرات الخفية التي تغير حالتها في أماكن غير معروفة ، لأسباب لم تكتشفها بعد.

هل ترغب في التجول في الظلام بينما تحاول تغيير التطبيق؟ بالطبع أنا لا أحب ذلك. لحسن الحظ ، لدي شموع لك:

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

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

هل أنت مستعد ، أيها القارئ العزيز ، للقفز على حصان ومعرفة عدوك؟ اذهب لتجد هذه الكرات العالمية واجعلها تتذوق سيوفنا!

ما هو الشرط؟




لنبدأ بالأساسيات حتى يتسنى للمطورين فهم بعضهم البعض.

الحالة هي تعريف للنظام أو الكيان. تم العثور على الدول في الحياة الحقيقية:

  • عند إيقاف تشغيل الكمبيوتر ، يتم إيقاف حالته.
  • عندما يكون كوب الشاي ساخنًا ، تكون حالته ساخنة.

في تطوير البرمجيات ، قد يكون لبعض التركيبات (مثل المتغيرات) حالات. لنفترض أن السلسلة "hello" أو الرقم 11 لا تعتبر حالات ، إنها قيم. تصبح حالة عند إرفاقها بمتغير ووضعها في الذاكرة.

<?php echo "hello"; // No state here! $lala = "hello"; // The variable $lala has the state 'hello'. 

يمكن تمييز نوعين من الحالات:

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

 <?php $lala = "hello"; // Initialisation of the variable. $lala = "hallo"; // The state of the variable $lala can be changed at runtime. 

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

 <?php define("GREETING", "hello"); // Constant definition. echo GREETING; GREETING = "hallo"; // This line will produce an error! 

الآن دعونا نستمع إلى محادثة افتراضية بين دينيس وفاسيلي ، زملائك المطورين:

- دان! لقد قمت بإنشاء متغيرات عالمية في كل مكان! لا يمكن تغييرها دون كسر كل شيء! سوف اقتلك!
- نيفيجا ، فاسيك! ثرواتي العالمية رائعة! أنا وضعت روحي فيها ، هذه هي روائع! أنا أعشق بلدي globals!

في معظم الأحيان ، يدعو المطورون الدول العالمية أو المتغيرات العالمية أو ما يجب أن يسموه بالدول القابلة للتغيير. بمعنى ، الحالات التي يمكن تعديلها في أكبر النطاقات المتاحة لك: في التطبيق بأكمله.

عندما لا يحتوي المتغير على التطبيق بالكامل كنطاق ، فإننا نتحدث عن المتغيرات المحلية أو اللغات. توجد في بعض مجالات الرؤية المحددة ، أقل من مساحة التطبيق بالكامل.

 <?php namespace App\Ecommerce; $global = "I'm a mutable global variable!"; // global variable class Shipment { public $warehouse; // local variable existing in the whole class public function __construct() { $info = "You're creating a shipment object!"; // local variable bound to the constructor scope echo $info; } } class Product { public function __construct() { global $global; $global = "I change the state now 'cause I can!"; echo "You're creating a product object!"; // no state here } } 

قد تعتقد: مدى ملاءمة وجود متغيرات يمكنك الوصول إليها من كل مكان وتغييرها! يمكنني نقل الحالات من جزء واحد من التطبيق إلى آخر! لا حاجة لتمريرها من خلال الوظائف وكتابة الكثير من التعليمات البرمجية! حائل ، دولة قابلة للتغيير العالمي!

إذا كنت تعتقد ذلك حقًا ، فإنني أوصي بشدة بمتابعة القراءة.

الدول العالمية أسوأ من الطاعون والكوليرا؟


أكبر مخطط الارتباط


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

لماذا؟

دعنا نقول لديك تطبيق كبير مع المتغيرات العالمية. في كل مرة تحتاج إلى تغيير شيء ما ، يجب عليك:

  • أذكر أن هذه الدول العالمية القابلة للتغيير موجودة.
  • قم بتقدير ما إذا كانت ستؤثر على النطاق الذي ستغيره.

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

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

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

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

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

تضارب الأسماء العالمية


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

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

في كل مرحلة سوف تمزق شعرك من الغضب واليأس. قريبا لن تحتاج إلى مشط. هذا السيناريو من غير المرجح أن يغري لك. ربما يتذكر أحدهم أن مكتبات Mootools و Underscore و jQuery في مكتبات JavaScript تصادمت دائمًا مع بعضها البعض إذا لم يتم وضعها في نطاقات أصغر. أوه ، والكائن العالمي الشهير $ في مسج!

الاختبار سوف يتحول إلى كابوس


إذا لم أقنعك حتى الآن ، فلنلقِ نظرة على الموقف من وجهة نظر اختبار الوحدة: كيف تكتب الاختبارات بحضور متغيرات عالمية؟ نظرًا لأن الاختبارات يمكن أن تغير من المستويات العالمية ، فأنت لا تعرف الاختبار الذي كانت عليه الحالة. تحتاج إلى عزل الاختبارات عن بعضها البعض ، وتربطها الدول العالمية ببعضها البعض.

هل سبق لك أن خضعت لذلك في اختبارات العزلة بشكل جيد ، وعندما تقوم بتشغيل الحزمة بأكملها ، هل ستفشل؟ لا؟ وكان لي ذلك. في كل مرة أتذكر هذا ، أعاني.

مشاكل التزامن


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

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

تجنب الدول القابلة للتغيير العالمي




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

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

يمكن أيضًا دعم الحالات القابلة للتغيير العالمي في تطبيقات اللغة. على سبيل المثال ، في PHP هناك superglobals .

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

وسيطات الدالة


أسهل طريقة لتفادي globals هي تمرير المتغيرات باستخدام وسيطات الدالة. خذ مثال بسيط:

 <?php namespace App; use Router\HttpRequest; use App\Product\ProductData; use App\Exceptions; class ProductController { public function createAction(HttpRequest $httpReq) { $productData = $httpReq->get("productData"); if (!$this->productModel->validateProduct($productData)) { return ValidationException(sprintf("The product %d is not valid", $productData["id"])); } $product = $this->productModel->createProduct($productData); } } class Product { public function createProduct(array $productData): Product { $productData["name"] = "SuperProduct".$productData["name"]; // This is not what you should do; I talk about it later in the article. try { $product = $this->productDao->find($productData["id"]); return product; } catch (NotFoundException $e) { $product = $this->productDao->save($productData); return $product; } } } class ProductDao { private $db; public function find(int $id): array { return $this->db->find(['product' => $id]); } public function save(array $productData): array { return $this->db->saveProduct($productData); } } 

كما ترون ، $productData من وحدة التحكم ، من خلال طلب HTTP ، يمر عبر مستويات مختلفة:

  1. تلقى وحدة تحكم طلب HTTP.
  2. المعلمات مرت إلى النموذج.
  3. المعلمات التي تم تمريرها إلى DAO .
  4. يتم حفظ المعلمات في قاعدة بيانات التطبيق.

يمكننا أن نجعل مجموعة المعلمات هذه عالمية عندما نسترجعها من طلب HTTP. يبدو أبسط من ذلك: لا حاجة لنقل البيانات إلى 4 وظائف مختلفة. ومع ذلك ، تمرير المعلمات كوسائط إلى الدالات:

  • سيُظهر بوضوح أن هذه الدالات تستخدم $productData .
  • سوف تظهر بوضوح الوظائف التي تستخدم المعلمات. يمكن ملاحظة أنه بالنسبة إلى ProductDao::find من $productData ProductDao::find $productData ، لا يلزم سوى $id ، وليس كل شيء.

تجعل Globals الكود أقل قابلية للفهم وربط الأساليب ببعضها البعض ، وهو سعر مرتفع جدًا للغياب شبه الكامل للمزايا.

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

الأسئلة عادلة ، عزيزي القارئ. كمطور جيد ، يجب أن تشرح لـ Denis ، باستخدام مهارات الاتصال الخاصة بك ، هذا ما يلي:

"دينيس ، إذا كانت لوظائفك العديد من الوسائط ، فإن الوظائف نفسها قد تكون مشكلة. ربما يفعلون الكثير ، مسؤولون عن أشياء كثيرة للغاية. لم تفكر في تقسيمها إلى وظائف أصغر؟ " .

تشعر كأنك متحدث في الأكروبول في أثينا ، أنت تواصل:

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

قد يبدو الأمر أكثر تعقيدًا عندما يكون لديك المزيد من الحجج (ربما هذا هو الحال) ، لكنني أكرر ، المزايا تفوق العيوب: من الأفضل أن تكون الشفرة واضحة قدر الإمكان ، ولا تستخدم حالات خفية قابلة للتغيير العالمي.

كائنات السياق


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

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

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

أنت تقول: "إنه رائع وكل ذلك ، لكن ماذا يعطي؟"

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

لكن كل شيء في التنمية له ثمن. كائنات السياق يمكن أن تكون ضارة:

  • بالنظر إلى وسيطات الوظيفة ، فلن تعرف البيانات الموجودة في كائن السياق.
  • يمكنك وضع أي شيء في كائن السياق. احرص على عدم وضع الكثير ، على سبيل المثال ، جلسة المستخدم بالكامل ، أو حتى معظم بيانات التطبيق. وبعد ذلك يمكن أن يحدث هذا: $context->getSession()->getUser()->getProfil()->getUsername() . كسر قانون ديميتر ، وسوف يكون لعنتك تعقيد مجنون.
  • كلما كان كائن السياق أكبر ، زادت صعوبة معرفة البيانات وفي أي مجال يستخدم.

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

إذا لم يكن لديك أي فكرة قبل تنفيذ أي برنامج عن عدد الحالات التي سيتم تمريرها إلى وظائفك (على سبيل المثال ، المعلمات من طلب HTTP) ، فإن كائنات السياق يمكن أن تكون مفيدة. لذلك ، يستخدم البعض منهم ، تذكر ، على سبيل المثال ، كائن Request في Symfony.

حقن التبعية


البديل الجيد الآخر للحالات القابلة للتغيير العالمي هو تضمين البيانات التي تحتاجها في الكائن مباشرة عند إنشائها. هذا هو تعريف حقن التبعية: مجموعة من التقنيات لتضمين الكائنات في مكوناتك (الفئات).

لماذا حقن التبعية بالضبط؟


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

يقسم حقن التبعية دورة حياة التطبيق إلى مرحلتين مهمتين:

  1. إنشاء كائنات التطبيق وتنفيذ تبعياتها.
  2. استخدم الأشياء لتحقيق أهدافك.

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

تستخدم العديد من الأطر حقن التبعية ، في بعض الأحيان في مخططات معقدة إلى حد ما ، مع ملفات التكوين وحاوية حقن التبعية (DIC). لكن ليس من الضروري على الإطلاق تعقيد الأمور. يمكنك ببساطة إنشاء تبعيات على مستوى واحد وتنفيذها على مستوى أقل. على سبيل المثال ، في عالم Go ، لا أعرف أي شخص يستخدم DIC. يمكنك ببساطة إنشاء التبعيات في الملف الرئيسي باستخدام الرمز (main.go) ، ثم نقلها إلى المستوى التالي. يمكنك أيضًا إنشاء مثيل لكل شيء في حزم مختلفة من أجل الإشارة بوضوح إلى أنه يجب تنفيذ "مرحلة حقن التبعية" فقط في هذا المستوى المحدد. في Go ، يمكن أن يجعل نطاق الحزم الأمور أسهل من PHP ، حيث يتم استخدام DICs على نطاق واسع في كل إطار أعرفه ، بما في ذلك Symfony و Laravel.

التنفيذ عن طريق المنشئ أو المستوطنين


هناك طريقتان لحقن التبعيات: من خلال المُنشئ أو المستوطنين. أنصحك ، إن أمكن ، بالالتزام بالطريقة الأولى:

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

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

تغليف التغليف


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

هل قلت التغليف؟


إن استخدام الدول العالمية سيؤدي في النهاية إلى كسر التغليف ، تمامًا كما يمكنك كسره مع الدول المحلية.

لنبدأ من البداية. ماذا تخبرنا ويكيبيديا عن تعريف التغليف؟ آلية اللغة لتقييد الوصول المباشر إلى بعض مكونات الكائن. تقييد الوصول؟ لماذا؟

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

تزايد نطاق وتسرب الدولة




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

خذ مثالاً: يمكن أن يزيد Anemic Domain Model من نطاق النماذج القابلة للتغيير. في الواقع ، يقسم Anemic Domain Model بيانات وسلوك كائنات المجال إلى مجموعتين: النماذج (الكائنات التي تحتوي على بيانات فقط) والخدمات (الكائنات التي لها سلوك فقط). في معظم الأحيان ، سيتم استخدام هذه النماذج في جميع الخدمات. لذلك ، من المحتمل أن يزيد نوع النموذج باستمرار من النطاق. لن تفهم النموذج الذي يتم استخدامه في أي سياق ، ستتغير حالته ، وستقع عليك جميع المشكلات نفسها.

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

, . , .

? - . , , -.

, - , , . , , — . , : , . . .


. Product , , :

 class Product { public function createProduct(array $productData): Product { $productData["name"] = "SuperProduct".$productData["name"]; // This is not what you should do; I talk about it later in the article. try { $product = $this->productDao->find($productData["id"]); return product; } catch (NotFoundException $e) { $product = $this->productDao->save($productData); return $product; } } } 

$productData . , , , .

, . , - ? , . .

, , . .

:

 class Product { public function createProduct(array $productData): Product { // Since $productData is passed to other variable, it has to be immutable. $name = "SuperProduct".$productData["name"]; try { $product = $this->productDao->find($productData["id"]); return product; } catch (NotFoundException $e) { $product = $this->productDao->save($name, $productData); return $product; } } } 

, , $productData . , . $productData , , HTTP-.

, : «, ».

?




. , .

?

  • , , .
  • , , (, ) .

. , .

, ShipmentDelay , , , . , -, ShipmentDelay , , , . ? , DRY .

, , . : , , . , , , . , , .

?


, (, ), , , . , , , , .

. :

  • .
  • , .
  • — : , , .
  • , .

. , — . , .

, , .

, , . , . , , . , !

Source: https://habr.com/ru/post/ar454946/


All Articles