زن تذهب



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

اذهب اصطلاحيًا


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

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

Idiom (n.): ثورة في الكلام ، تُستخدم ككل ، ولا تخضع لمزيد من التحلل ولا تسمح عادةً بالتبديل داخلها.

التعابير هي السمات المميزة للمعاني المشتركة. لن تعلمك الكتب اللغة التلقائية ، وهي تُعرف فقط عندما تصبح جزءًا من المجتمع.

أنا قلق بشأن شعار Go الاصطلاحي لأنه غالبًا ما يكون مقيدًا. تقول: "لا يمكنك الجلوس معنا". أليس هذا ما نعنيه عندما ننتقد عمل شخص آخر على أنه "غير اصطلاحي"؟ لقد فعلوا ذلك خطأ. هذا لا يبدو صحيحا. هذا لا يتطابق مع نمط الوقت.

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

اقوال


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

لا أعتقد ذلك. لا أريد التقليل من عمل المؤلف. إن الأقوال التي ألفها هي مجرد ملاحظات وليست تعاريف للمعاني. يأتي القاموس إلى الإنقاذ مرة أخرى:

المثل (اسم): بيان قصير له معنى حرفي أو رمزي.

مهمة Go Proverbs هي إظهار الجوهر العميق للهندسة اللغوية. ولكن هل سيكون من المفيد تقديم المشورة مثل " الواجهة الفارغة لا تقول أي شيء " للمبتدئ الذي جاء من لغة بدون كتابة هيكلية؟

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

قيم التصميم


عثر Dan Liu على عرض تقديمي قديم قدمه Mark Lukowski حول ثقافة التصميم في فريق تطوير Windows NT-Windows 2000 Windows. لقد ذكرت ذلك لأن Lukowski يصف الثقافة بأنها طريقة شائعة لتقييم البنى وإجراء التنازلات.


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

اذهب القيم


ما هي قيم Go الصريحة؟ ما هي المفاهيم أو الفلسفات الرئيسية التي تحدد كيف يفسر مبرمجو Go العالم؟ كيف أعلنوا؟ كيف يتم تعليمهم؟ كيف يتم اتباعها؟ كيف تتغير بمرور الوقت؟

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

قيم اللغات الأخرى


لإعداد الطريق لما أريد أن أقوله ، يمكننا الانتباه إلى اللغات الأخرى ، إلى قيم التصميم الخاصة بهم.

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

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

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

Zen Python Go


قبل عقود قليلة ، جلس تيم بيترز وكتب PEP-20 - The Zen of Python . حاول توثيق قيم التصميم التي التزم بها غيدو فان روسوم باعتباره دكتاتور حياة ثعبان سخي.

دعونا نلقي نظرة على The Zen of Python ونرى ما إذا كان بإمكاننا معرفة أي شيء عن قيم تصميم Go Designer.

تبدأ الحزمة الجيدة باسم جيد


لنبدأ بالحدة الحادة:

تعد مساحات الأسماء فكرة رائعة ، فلنجعلها أكبر!

زين بيثون ، سجل 19.

بشكل لا لبس فيه بما فيه الكفاية: يجب على مبرمجي Python استخدام مساحات الأسماء. الكثير من المساحات.

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

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

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

— , .


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

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

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

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

وإذا بدلاً من توسيع المكونات ، فسنستبدلها؟ إذا لم يقم المكون بما هو محدد في التعليمات ، فقد حان الوقت لتغييره.

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

البساطة مهمة


بسيط هو أفضل من المجمع.

زين بيثون ، دخول 3.

يدعي PEP-20 أن البساطة أفضل من المعقد ، وأنا أوافق تمامًا. قبل بضع سنوات كتبت:


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

وفقا لملاحظاتي ، على الأقل في ذلك الوقت ، لم أكن أتذكر لغة كنت أعرف أنها لن تعتبر بسيطة. كمبرر وإغراء ، أعلن مؤلفو كل لغة جديدة البساطة. لكنني وجدت أن البساطة ليست القيمة الأساسية للعديد من اللغات في نفس عمر Go (روبي ، سويفت ، إلم ، جو ، NodeJS ، Python ، Rust). ربما هذا سيصيب بقعة مؤلمة ، ولكن ربما يكون السبب هو أن أيا من هذه اللغات ليست بسيطة. أو لم يعتبرها مؤلفوها بسيطة. لم يتم تضمين البساطة في قائمة القيم الأساسية.

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

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

تشارلز هوار ، ملابس الإمبراطور القديمة ، محاضرة جائزة تورينج ، 1980

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

البساطة هي مفتاح الموثوقية.

Edsger Dijkstra، EWD498، 18 يونيو 1975

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

جوهر البرمجة هو إدارة التعقيد.

بريان كيرنيجان ، أدوات البرمجيات (1976)

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

تجنب حالات مستوى الحزمة


صريح أفضل من ضمني.

زين بيثون ، دخول 2

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

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

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

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

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

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

وهذا ما يسمى الدولة ، وإدارة الدولة مشكلة في علوم الكمبيوتر.

package counter

var count int

func Increment(n int) int {
        count += n
        return count
}

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

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

بالطبع لا. من الواضح أن الحل هو تغليف المتغير variableفي النوع.

package counter

type Counter struct {
        count int
}

func (c *Counter) Increment(n int) int {
        c.count += n
        return c.count
}

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

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

ضع خطط للفشل وليس النجاح


لا تمر الخلل بصمت.

زين بيثون ، دخول 10

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

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

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

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

بيتر بورجون ، GoTime # 91

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

إسهاب هذا الرمز

if err != nil {
    return err
}

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

من الأفضل أن تعود مبكراً من أن تستثمر بعمق


الشقيق أفضل من التعشيش

The Zen of Python ، الإدخال 5

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

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

أعتقد أن أفضل استخدام للمدخل الخامس من The Zen of Python هو إنشاء تدفق تحكم داخل دالة. بمعنى آخر ، تجنب تدفق التحكم الذي يتطلب مسافة بادئة متعددة المستويات.

الرؤية المباشرة عبارة عن خط مستقيم لا يتم حجب المنظر من خلاله بأي شيء.

May Ryer ، Code: محاذاة المسار السعيد إلى الحافة اليسرى

تصف ماي راير هذه الفكرة بأنها برمجة في خط البصر المباشر:

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

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

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

إذا كنت تعتقد أن شيئًا ما يسير ببطء ، فقم بإثباته بمعيار


التخلي عن إغراء التخمين في مواجهة الغموض.

زين بيثون 12

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

يجب أن تكون واجهة برمجة التطبيقات سهلة الاستخدام وصعبة الاستخدام بشكل غير صحيح.

جوش بلوخ

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

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

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

قبل بدء gorutin ، اكتشف متى سيتوقف


أعتقد أنني قمت بإدراج العناصر القيمة من PEP-20 وربما قمت بتوسيع تفسيرها بما يتجاوز الذوق السليم. هذا أمر جيد ، لأنه على الرغم من أن هذا جهاز بلاغي مفيد ، فإننا ما زلنا نتحدث عن لغتين مختلفتين.

اكتب ز ، س ، مسافة ، ثم استدعاء دالة. يضغط ثلاثة زر ، لا يمكن أن يكون أقصر. ثلاث نقرات زر ، وقمت بتشغيل العملية الفرعية.

روب بايك ، البساطة معقدة ، dotGo 2015

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

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

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

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

إن أبسط طريقة لتحرير الموارد هي ربطها بدورة حياة الغوروتين. عند اكتمالها ، يتم تحرير الموارد. ونظرًا لأنه من السهل جدًا تشغيل الغوروتين ، قبل كتابة "go and space" ، تأكد من أن لديك إجابات على هذه الأسئلة:

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


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

المثال الرئيسي هو net / http. من السهل جدًا إيقاف الخادم الذي يمتلك مقبس الاستماع ، ولكن ماذا عن goroutines التي يتم إنشاؤها بواسطة هذا المقبس؟ يوفر net / http كائن سياق داخل كائن الطلب يمكن استخدامه لإخبار المستمع بضرورة إلغاء الطلب ، وبالتالي مقاطعة المقاطعة. ولكن ليس من الواضح كيفية معرفة متى يجب القيام بكل هذا. شيء ما للاتصال به context.Cancel، شيء آخر لمعرفة أن الإلغاء قد اكتمل.

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

لذا ، أريد أن أحضر net / http كإجراء مضاد للممارسة الجيدة. نظرًا لأن كل اتصال تتم معالجته بواسطة goroutine الذي تم إنشاؤه داخل النوع net/http.Server، لا يمكن لبرنامج خارج حزمة net / http التحكم في goroutins التي يتم إنشاؤها بواسطة مقبس الاستلام.

هذا المجال من الهندسة المعمارية لا يزال يتطور. يمكنك استدعاء run.Groupgo-kit ، أو ErrGroup ، من فريق تطوير Go ، الذي يوفر إطارًا للتنفيذ والغاء وانتظار الوظائف المنفذة بشكل غير متزامن.

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

اكتب الاختبارات لمنع سلوك واجهة برمجة تطبيقات الحزمة الخاصة بك


ربما كنت تأمل أنني لن أذكر في هذه المقالة الاختبار. آسف ، في وقت آخر.

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

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

تحظر الاختبارات سلوك واجهة برمجة التطبيقات. يجب أن تتضمن أي تغييرات تضيف أو تغير أو تزيل واجهة برمجة التطبيقات العامة تغييرات في الاختبارات.

الاعتدال فضيلة


Go هي لغة بسيطة بها 25 كلمة رئيسية فقط. بطريقة ما ، يسلط هذا الضوء على الميزات المضمنة في اللغة. هذه هي الميزات التي تسمح للغة بالترويج لنفسها: المنافسة البسيطة ، الكتابة الهيكلية ، إلخ.

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

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

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

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

سهولة الصيانة


أخيرًا ، سأعطيك إدخالًا آخر من PEP-20:

مسائل القراءة.

زين بيثون ، سجل 7

قيل الكثير عن أهمية قراءة التعليمات البرمجية في جميع لغات البرمجة. أولئك الذين يروجون لـ Go يستخدمون كلمات مثل البساطة والقراءة والوضوح والإنتاجية. ولكن كل هذه مرادفات لمفهوم واحد - راحة الصيانة.

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

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

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

ما تعمل بجد سيكون مناسبًا لمرافقته بعد مغادرتك؟ كيف يمكنك تسهيل الحفاظ على رمزك لمن يأتي بعدك اليوم؟

All Articles