كيف تكتب الرمز الذي سيفهمه الجميع؟


من مترجم: نشرنا مقال لكاميل ليلونيك لك عن معنى قراءة الشفرة و "تعاطف المبرمجين".

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

نذكرك: لجميع قراء "هبر" - خصم 10000 روبل عند التسجيل في أي دورة من دورات Skillbox باستخدام الرمز الترويجي "Habr".
رأيت مؤخرًا شيئًا مثل هذا:

defmodule Util.Combinators do def then(a, b) do fn data -> b.(a.(data)) end end def a ~> b, do: a |> then(b) end 

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

 import Util.{Reset, Combinators} # ... conn = conn!() Benchee.run( # ... time: 40, warmup: 10, inputs: inputs, before_scenario: do_reset!(conn) ~> init, formatter_options: %{console: %{extended_statistics: true}} ) 

حسنًا ، يبدو أنه لا يتم استيراد ~> فقط ، ولكن أيضًا وظائف conn! / 0 و do_reset! / 1. حسنًا ، دعنا نلقي نظرة على وحدة إعادة الضبط:

 defmodule Util.Reset do alias EventStore.{Config, Storage.Initializer} def conn! do {:ok, conn} = Config.parsed() |> Config.default_postgrex_opts() |> Postgrex.start_link() conn end def do_reset!(conn) do fn data -> Initializer.reset!(conn) data end end end 

بالنسبة إلى conn! ، هناك طريقتان لتسهيل هذا الموقع. ومع ذلك ، فإن التوقف عند هذه النقطة لا معنى له. أفضل التركيز على do_reset! / 1. تقوم هذه الدالة بإرجاع دالة تقوم بإرجاع وسيطة وتقوم بإعادة تعيين للمهيئ ؛ والاسم نفسه معقد للغاية.



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

  • تهيئة اتصال Postgrex.
  • إعادة تعيين EventStore.
  • استخدام قيم الإدخال كعناصر تكوين (الحديث عن عدد الحسابات).
  • تحضير البيانات للاختبارات (أي إنشاء مستخدمين ودخول التطبيق).
  • باستخدام المعايير.

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

الخطوة الأولى هي استخدام الاسم المستعار بشكل صريح بدلاً من عمليات الاستيراد الضمنية. لم أحب أبدًا ميزات "السحر" التي تظهر في الكود الخاص بي ، على الرغم من أن Ecto.Query يجعل الاستعلامات أنيقة. الآن تبدو وحدة الاتصال الخاصة بنا كما يلي:

 defmodule Benchmarks.Util.Connection do alias EventStore.{Config, Storage.Initializer} def init! do with {:ok, conn} = Config.parsed() |> Config.default_postgrex_opts() |> Postgrex.start_link() do conn end end def reset!(conn), do: Initializer.reset!(conn) end 

بعد ذلك ، قررت كتابة "ربط" ، كما هو مقترح في الوثائق:

before_scenario: مدخلات fn -> نهاية المدخلات

كل ما تبقى القيام به هو إعداد البيانات. النتيجة النهائية هي كما يلي:

 alias Benchmarks.Util.Connection conn = Connection.init!() # ... Benchee.run( inputs: inputs, before_scenario: fn inputs -> Connection.reset!(conn) init.(inputs) end, formatter_options: %{console: %{extended_statistics: true}} ) Connection.reset!(conn) 

هل هذا الرمز مثالي؟ ربما ليس بعد. ولكن هل من السهل فهمها؟ آمل ذلك. هل يمكن القيام به على الفور؟ نعم بالتأكيد.

ما هي المشكلة؟


عندما اقترحت حلاً للمؤلف ، سمعت: "رائع". ومع ذلك ، لم أكن أتوقع المزيد.

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

لإقناع المطورين الآخرين لجعل شفرتهم قابلة للقراءة ، تحتاج إلى شيء مقنع. والحجة "قررت إعادة رمزك ، لأنه غامض ،" لن يتم قبولها ، والجواب هو "يعني أنك مجرد مطور سيئ ، ماذا يمكنني أن أفعل ¯ \ _ (ツ) _ / ¯."



هذه مشكلة إدارة (غير)


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

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

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



دور التعاطف المهم


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

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

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



خاتمة


قمت مؤخرًا بكتابة كود على إكسير:

 result = calculate_results() Connection.close(conn) result 

ثم فكرت في طريقة روبي تاب التي تسمح لك بإعادة كتابة هذا الرمز:

 calculate_result().tap do Connection.close(conn) end 

IMHO ، سيكون من الأفضل القيام بذلك دون نتيجة المتغير المتوسط. فكرت في كيفية القيام بذلك ، وتوصلت إلى الاستنتاج التالي:

 with result = calculate_results(), Connection.close(conn), do: result 

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

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

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

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


All Articles