إن هذا الدليل مستوحى من دليل GitHub ودليل Bozhidar Batsov.
ولدينا أيضًا دليل جافاسكربت لتنسيق الشيفرة البرمجية
جدول المحتويات
- المسافات البيضاء
- الأسطر الجديدة
- التعليقات
- الدوال
- التعابير الشرطيّة
- قواعد التسمية
- الأصناف
- الاستثناءات
- التجميعات
- السلاسل النصية
- التعابير النمطية
- محارف النسبة المئوية
- ريلز
- انسجم مع الشيفرة
المسافات البيضاء
المسافة البادئة في الشيفرة
-
استخدم الزر (
tabs
) بمقدار مسافتين (وتسمى أيضًا Soft-Tab نظرًا لأن زر Tab الإفتراضي يكون ثمان مسافات). -
سيكون عمق الكلمة المفتاحية
when
بقدر عمقcase
.case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end
-
حاذِ وسطاء الّدالة فإما أن يكونوا على نفس السطر أو سطر لكلّ واحدٍ منهم.
# bad def self.create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # good def self.create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # good def self.create_translation( phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification ) ... end
-
حاذِ الأسطر المتتابعة بمقدار مسافتين في جملة التنفيذ للتعابير المنطقية متعددة الأسطر.
# bad def is_eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end # good def is_eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end
المسافات السطرية
-
لا تترك مسافة زائدة.
-
عند تضمين التعليقات في السطر، اترك مسافة واحدة بين نهاية الشيفرة البرمجية وبداية تعليقك.
# bad result = func(a, b)# we might want to change b to c # good result = func(a, b) # we might want to change b to c
-
استخدم المسافات حول المعاملات (operators)، وبعد الفواصل، وبعد النقطتين، وبعد الفاصلة المنقوطة، وبعد فتح قوس ما
{
وقبل إغلاقه أيضًا}
.sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false; puts 'Hi' [1, 2, 3].each { |e| puts e }
-
لا تضع أبدًا مسافة فارغة قبل الفاصلة.
result = func(a, b)
-
لا تضع مسافة داخل كتلة وسطاء الأنبوب (pipe)، بل ضع واحدًا بين الوسطاء في الكتلة، وواحدًا آخر خارج كتلة وسطاء الأنبوب.
# bad {}.each { | x, y |puts x } # good {}.each { |x, y| puts x }
-
لا تضع مسافات بين إشارة التعجب
!
ومعاملاتها.!something
-
لا تترك فارغات بعد الأقواس من نوع
(
و[
أو قبلها)
و]
.some(arg).other [1, 2, 3].length
-
تجنب وضع المسافات عند إنشاء السلاسل النصية.
# bad var = "This #{ foobar } is interpolated." # good var = "This #{foobar} is interpolated."
-
لا تستخدم مسافة إضافية في النطاق الحرفي (range literals).
# bad (0 ... coll).each do |item| # good (0...coll).each do |item|
الأسطر الجديدة
-
أضف سطرًا جديدًا بعد الجملة الشرطية
if
ذات الشروط المتعددة لتصبح في عدة أسطر، ولتساعد في التفريق بين الشروط وجسم الشرط.if @reservation_alteration.checkin == @reservation.start_date && @reservation_alteration.checkout == (@reservation.start_date + @reservation.nights) redirect_to_alteration @reservation_alteration end
-
أضف سطرًا جديدًا بعد نهاية الجمل الشرطية، والكتل، والبيانات …إلخ.
if robot.is_awesome? send_robot_present end robot.add_trait(:human_like_intelligence)
-
لا تضف أسطرًا جديدةً فارغةً بين المناطق ذات مسافات بادئة مختلفة (مثلًا حول أجزاء الصنف أو أجسام الوحدة).
# bad class Foo def bar # body omitted end end # good class Foo def bar # body omitted end end
-
أضف سطرًا جديدًا فارغًا بين الدوالّ.
def a end def b end
-
أضف سطرًا فارغًا لفصل البيانات المترابطة في الدوالّ لتشكيلّ فقرات منطقية داخلها.
def transformorize_car car = manufacture(options) t = transformer(robot, disguise) car.after_market_mod! t.transform(car) car.assign_cool_name! fleet.add(car) car end
-
أضف سطرًا فارغًا في نهاية كل ملف، ولا تضف أبدًا عدة أسطر.
طول السطر
- حافظ على كلّ سطر من الشيفرة البرمجية ليكون بطول مناسب للقراءة، وابقِ طول الأسطر أقل من 100 محرف (إليك السبب) إلا إن كان لديك سبب وجيه لجعله أطول من ذلك.
التعليقات
اقتباسعلى الرغم من أن التعليقات متعبة عند كتابتها، إلا أنها مفيدة للغاية للحفاظ على مقروئية شيفرتك البرمجية، ستصف القواعد التالية ما يجب التعليق عليه، وأين تضع هذا التعليق، لكن تذكر: على الرغم من أن التعليقات مهمة جدًا إلا أنه من الأفضل دومًا أن تكون الشيفرة البرمجية هي من تشرح نفسها بنفسها، فإعطاؤك أسماءً منطقية للأنواع والمتغيرات أفضل بكثير من استخدام أسماء غامضة تستوجب عليك شرحها من خلال التعليقات.
عند كتابتك للتعليقات، اكتبها لجمهورك وللمساهم القادم الّذي سيحتاج لفهم شيفرتك البرمجية، وكن سخيًا، فيمكن أن يكون المساهم القادم أنت!- دليل Google لتنسيق الشيفرة البرمجية للغة C++
كُتِبَ هذا الشرح باستعانة كبيرة من دليل Google لتنسيق الشيفرة البرمجية للغة C++ ولغة Python.
تعليقات على مستوى الملف/الصنف
عند التعريف عن صنف ما يجب أن يوجد تعليق مصاحب له يصف ماهيّة الصنف وكيفية استخدامه.
يجب أن يملك الملف الذي لا يحتوي على أصناف، أو يحتوي على أكثر من صنف على تعليق في أعلاه يصف محتوياته.
# Automatic conversion of one locale to another where it is possible, like # American to British English. module Translation # Class for converting between text between similar locales. # Right now only conversion between American English -> British, Canadian, # Australian, New Zealand variations is provided. class PrimAndProper def initialize @converters = { :en => { :"en-AU" => AmericanToAustralian.new, :"en-CA" => AmericanToCanadian.new, :"en-GB" => AmericanToBritish.new, :"en-NZ" => AmericanToKiwi.new, } } end ... # Applies transforms to American English that are common to # variants of all other English colonies. class AmericanToColonial ... end # Converts American to British English. # In addition to general Colonial English variations, changes "apartment" # to "flat". class AmericanToBritish < AmericanToColonial ... end
يجب أن تملك جميع الملفات من بينهم ملفات البيانات والإعداد، على تعليقات على مستوى الملف.
# List of American-to-British spelling variants. # # This list is made with # lib/tasks/list_american_to_british_spelling_variants.rake. # # It contains words with general spelling variation patterns: # [trave]led/lled, [real]ize/ise, [flav]or/our, [cent]er/re, plus # and these extras: # learned/learnt, practices/practises, airplane/aeroplane, ... sectarianizes: sectarianises neutralization: neutralisation ...
تعليقات الدالة
يجب أن يكون هنالك تعليقات عند تعريف كلّ دالة وتكون قبلها مباشرة لتصف ما تؤديه هذه الدالة وكيفية استخدامها، ويجب أن تكون هذه الملفات وصفية ("يُفتح الملف") بدلًا من أمرية ("افتح الملف"). التعليقات التي تصف الدالّة، لا تشرح ما تقوم به الدالّة خطوة بخطوة. عمومًا، لا تصف هذه التعليقات كيفية تنفيذ هذه الدالّة عملها حرفيًا، وإنما، يجب ترك هذه التعليقات لتتخلل الشيفرة البرمجية للدالّة.
يجب أن تذكر كلُّ دالّة ما هي مدخلاتها ومخرجاتها، إلا إن كانت لا تستوف جميع المعايير التالية:
- غير مرئية من الخارج.
- قصيرة جدًا.
- واضحة وبديهية.
يمكنك استخدام أي تنسيق تريده، في لغة Ruby، يوجد مخططين لتوثيق وشرح عمل الدالّة وهما TomDoc
وYARD
كما يمكنك أيضًا كتابة تعليقات موجزة:
# Returns the fallback locales for the_locale. # If opts[:exclude_default] is set, the default locale, which is otherwise # always the last one in the returned list, will be excluded. # # For example: # fallbacks_for(:"pt-BR") # => [:"pt-BR", :pt, :en] # fallbacks_for(:"pt-BR", :exclude_default => true) # => [:"pt-BR", :pt] def fallbacks_for(the_locale, opts = {}) ... end
التعليقات الكتلية والمضمّنة
المكان الأخير للتعليقات هو في الأجزاء الصعبة من الشيفرة البرمجية، فعّلق عليها الآن إذا توجب عليك شرحها عند مراجعة القادمة للشيفرة البرمجية. يجب أن تحصل العمليات المعقدة على بضعة أسطر من التعليقات قبل بدء العمليات، بالنسبة للأجزاء غير الواضحة فإنها التعليقات ستكون في نهاية السطر.
def fallbacks_for(the_locale, opts = {}) # dup() to produce an array that we can mutate. ret = @fallbacks[the_locale].dup # We make two assumptions here: # 1) There is only one default locale (that is, it has no less-specific # children). # 2) The default locale is just a language. (Like :en, and not :"en-US".) if opts[:exclude_default] && ret.last == default_locale && ret.last != language_from_locale(the_locale) ret.pop end ret end
من ناحية أخرى، لا تصف طريقة عمل التعليمات البرمجية، افترض أن الشخص الذي يقرأ شيفرتك البرمجية يعرف اللغة البرمجية (وإن لم يكن ما تحاول القيام به) أفضل منك.
وفي سياق متصل: لا تستخدم التعليقات الكتلية، فلا يمكن أن تسبقها بمسافة وليس من السهل رؤيتها كالتعليقات العادية.
# bad =begin comment line another comment line =end # good # comment line # another comment line
علامات الترقيم والإملاء والنحو
اهتم بعلامات الترقيم، والإملاء، والنحو. فمن السهل قراءة التعليقات المكتوبة بعناية على عكس نظيرتها غير المكتوبة بعناية.
ينبغي أن تكون التعليقات قابلة للقراءة كنص سردي، مع وجود الحروف الكبيرة وعلامات الترقيم المناسبة. في حالات كثيرة، تكون الجمل الكاملة قابلة للقراءة أكثر من الجمل القصيرة.
يمكن للتعليقات القصيرة، مثل الّتي توضع في نهاية آخر سطر في شيفرة برمجية أن تكون أقل رسمية، لكن على كلّ الأحوال يجب أن تكون متسقة مع تنسيقك للتعليقات ككلّ.
على الرغم من أنه من المحبط أن يشير مُراجِع لشيفرتك البرمجية لاستخدامك فاصلة عادية في مكان الفاصلة المنقوطة، لذا من المهم أن تحافظ على شيفرتك البرمجية لتكون بمستوى عالٍ من الوضوح وقابلية القراءة، وستُساعدنا علامات الترقيم والكتابة الإملائية الصحيحة واستخدام الصحيح للقواعد النحوية في تحقيق هذا الهدف.
تعليقات TODO
استخدم تعليقات TODO للشيفرات البرمجية المؤقتة، أو للحلّ قصير الأجل، أو الحلّ الجيد بما يكفي ولكنه ليس مثاليًا. يجب أن تتضمن تعليقات TODO على كلمة TODO بالأحرف الكبيرة متبوعة بالاسم الكامل للشخص الذي يمكنه توفير أفضل حل للمشكلة في الشيفرة المشار إليها من قِبل تعليق TODO بين قوسين. يمكنك إضافة النقطتين ومن ثمّ ضع تعليق يشرح ما يجب القيام به، فالغرض الرئيسي هو تنسيق تعليق TODO ليصبح قابلًا للبحث ليجده الشخص الّذي يمكنه توفير مزيد من التفاصيل عند الطلب. إن تعليق TODO لا يُلزم الشخص المشار إليه لإصلاح المشكلة، ولذلك عند إنشائك تعليق TODO، فغالبًا -إن لم يكن دائمًا- ستكتب اسمك.
# bad # TODO(RS): Use proper namespacing for this constant. # bad # TODO(drumm3rz4lyfe): Use proper namespacing for this constant. # good # TODO(Ringo Starr): Use proper namespacing for this constant.
شيفرات برمجية بدون تعليقات
- لا تترك أبدًا شيفراتك البرمجية بدون تعليقات.
الدوال
تعريف الدوال
-
استخدم الكلمة المفتاحية
def
مع الأقواس عند وجود وسطاء، واحذف الأقواس عندما لا تقبل الدوالّ أي وسطاء.def some_method # body omitted end def some_method_with_parameters(arg1, arg2) # body omitted end
-
لا تستخدم الوسطاء الموضوعة افتراضيًا، بل استخدم معاملات الكلمات الرئيسية (keyword) – الموجودة في إصدار لغة روبي Ruby 2.0 أو الأحدث - أو يمكنك استخدام أسماء hash أيضًا.
# bad def obliterate(things, gently = true, except = [], at = Time.now) ... end # good def obliterate(things, gently: true, except: [], at: Time.now) ... end # good def obliterate(things, options = {}) options = { :gently => true, # obliterate with soft-delete :except => [], # skip obliterating these things :at => Time.now, # don't obliterate them until later }.merge(options) ... end
-
تجنب الدوالّ المتكونة من سطر واحد، على الرغم من انتشارها، إلا أنه توجد بعض الغرابة حول طريقة صياغتها مما يجعل استخدامها أمرًا غير مرغوب به.
# bad def too_much; something; something_else; end # good def some_method # body end
دوال الاستدعاء
استخدم الأقواس لدالة الاستدعاء في الحالات التالية:
-
إذا كانت الدالة ترجع قيمة.
# bad @current_user = User.find_by_id 1964192 # good @current_user = User.find_by_id(1964192)
-
إذا كان الوسيط الأول للدالّة يستخدم الأقواس.
# bad put! (x + y) % len, value # good put!((x + y) % len, value)
-
لا تضع أبدًا مسافة بين اسم الدالّة والقوس الأول.
# bad f (3 + 2) + 1 # good f(3 + 2) + 1
-
تجنب الأقواس عند استدعاء الدالّة إذا لم تقبل الدالّة أي وسطاء.
# bad nil?() # good nil?
-
ستكون الأقواس اختيارية ما لم تكن الدالة تُعيدّ قيمة (أو لا نهتم بما تُعيده)، أما إذا كان الوسطاء في عدة أسطر، فيمكن للأقواس أن تزيد من قابلية القراءة.
# okay render(:partial => 'foo') # okay render :partial => 'foo'
في كِلا الحالتين:
-
في حالة قبول الدالة hash كوسيط أخير اختياري، لا تستخدم الأقواس
{
أو}
أثناء الاستدعاء.
# bad get '/v1/reservations', { :id => 54875 } # good get '/v1/reservations', :id => 54875
-
في حالة قبول الدالة hash كوسيط أخير اختياري، لا تستخدم الأقواس
التعابير الشرطيّة
الكلمات المفتاحية للجمل الشرطية
-
لا تستخدم الكلمة المفتاحية
then
للجملة الشرطيةif/unless
المتعددة الأسطر.# bad if some_condition then ... end # good if some_condition ... end
-
لا تستخدم الكلمة المفتاحية
do
معwhile
أوuntil
المتعددات الأسطر.# bad while x > 5 do ... end until x > 5 do ... end # good while x > 5 ... end until x > 5 ... end
-
إن الكلمات المفتاحية
and
وor
وnot
محظورة، فهي لا تستحق العناء، استخدم دائمًا&&
و||
و!
بدلًا منها. -
يمكنك استخدام المعدِل
if/unless
عندما يكون الجسم بسيط والشرط بسيط وكلّ شيء في سطر واحد، وخلافًا لذلك، تجنب استخدامif/unless
.# bad - this doesn't fit on one line add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty? # okay if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty? add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) end # bad - this is complex and deserves multiple lines and a comment parts[i] = part.to_i(INTEGER_BASE) if !part.nil? && [0, 2, 3].include?(i) # okay return if reconciled?
-
لا تستخدم أبدًا الكلمة المفتاحية
unless
معelse
، أعد كتابة الشرط لتصبح الحالة الصحيحة الأولى أولًا.# bad unless success? puts 'failure' else puts 'success' end # good if success? puts 'success' else puts 'failure' end
-
تجنب
unless
مع الشروط المتعددة.# bad unless foo? && bar? ... end # okay if !(foo? && bar?) ... end
-
تجنب استخدام
unless
مع معاملات الموازنة فإن استطعت استخدام الشرطif
مع عكس الشرط الموجود فيunless
ففعل ذلك.# bad unless x == 10 ... end # good if x != 10 ... end # bad unless x < 10 ... end # good if x >= 10 ... end # ok unless x === 10 ... end
-
لا تستخدم أقواسًا حول الشروط
if/unless/while
.# bad if (x > 10) ... end # good if x > 10 ... end
المعامل الثلاثي
-
تجنب استخدام العامل الثلاثي (
:?
) إلا في الحالات الّتي تكون فيها جميع التعابير بسيطة، إلا أنه يمكنك استخدامه بدلًا منif/then/else/end
في الشروط المتكونة من سطر واحد.# bad result = if some_condition then something else something_else end # good result = some_condition ? something : something_else
-
استخدم تعبير واحد لكلّ فرع في المعامل الثلاثي، كذلك يجب ألا يكون المعامل الثلاثي متشعبًا، إذ يُفضّل استخدام بنية
if/else
في هذه الحالات.# bad some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else # good if some_condition nested_condition ? nested_something : nested_something_else else something_else end
-
تجنب الشروط المتعدّدة في المعامل الثلاثي إذ يُفضّل استخدام الأخير مع الشروط الفردية.
-
تجنب الأسطر المتعدّدة
:?
في المعامل الثلاثي، واستخدمif/then/else/end
بدلا منه.# bad some_really_long_condition_that_might_make_you_want_to_split_lines ? something : something_else # good if some_really_long_condition_that_might_make_you_want_to_split_lines something else something_else end
الشروط المتشعّبة
-
تجنب استخدام الشروط المتشعّبة لزيادة التحكم بالشيفرة (يمكنك الاطلاع على هذا المقال لمزيد من المعلومات).
يُفضّل استخدام تعبير الحراسة (
guard clause
) عندما تريد التحقق بيانات غير صالحة، فشرط الحراسة هو عبارة شرطية في أعلى الدالة التي تعيد النتيجة بأسرع ما يمكن.المبادئ العامة هي:
- أعدّ القيمة (النتيجة) مباشرة بمجرد معرفتك بأن الدالّة لا طائل منها، أو أنها لا تضف أي زيادة حقيقة للشيفرة.
-
قلل التشعّب والمسافات البادئة في الشيفرة البرمجة من خلال إعادة النتيجة بأسرع وقت ممكن. وهذا يجعل الشيفرات البرمجية أسهل للقراءة، وتتطلّب جهدً عقليًا أقل أثناء قراءة الفرع الثاني من الشرط
else
. - ينبغي أن تكون الشروط الجوهرية أو الأكثر أهمية ذات مسافات بادئة أقل.
# bad def compute server = find_server if server client = server.client if client request = client.make_request if request process_request(request) end end end end # good def compute server = find_server return unless server client = server.client return unless client request = client.make_request return unless request process_request(request) end
يُفضّل استخدام
next
في الحلقات بدلًا من الكتل الشرطيّة.# bad [0, 1, 2, 3].each do |item| if item > 1 puts item end end # good [0, 1, 2, 3].each do |item| next unless item > 1 puts item end
الصياغة
-
لا تستخدم
for
إلّا إذا كنت تعرّف تمامًا لماذا ستستخدمها، فغالبًا، يجب استخدام المكرّرات (iterator
) بدلًا منها، فتعملfor
بنفس شروطeach
(أي أنك ستضيف مستوى جديد من المراوغة للبرنامج) لكن مع عيب صغير، فلا تُعرّفfor
نطاق جديد (على عكسeach
) وستظهر المتغيرات المعرّفة في كتلتها خارجيًا.arr = [1, 2, 3] # bad for elem in arr do puts elem end # good arr.each { |elem| puts elem }
-
يفضل استخدام
{...}
بدلًا منdo...end
للكتل المكوّنة من سطر واحد، وتجنّب استخدام{...}
للكتل المكونة من عدة أسطر (فسَلّسَلةُ عدة أسطر هو شيء قبيح)، واستخدمdo...end
دائمًا للتحكم في التدفّق ولتعريف الدوالّ، وتجنب استخدامdo...end
عند السَلّسَلة.names = ["Bozhidar", "Steve", "Sarah"] # good names.each { |name| puts name } # bad names.each do |name| puts name end # good names.each do |name| puts name puts 'yay!' end # bad names.each { |name| puts name puts 'yay!' } # good names.select { |name| name.start_with?("S") }.map { |name| name.upcase } # bad names.select do |name| name.start_with?("S") end.map { |name| name.upcase }
سيُجادلنا البعض ويقول أن سَلّسَلَة الأسطر المتعددة تبدو جيّدة عند استخدام
{...}
، لكن هل سألوا أنفسهم هل هذه الشيفرة البرمجية قابلة للقراءة حقًا. وهل يمكن استخلاص محتوى الكتلة لوضعها في دوالّ فعّالة. -
استخدم معاملات الإسناد المختصرة كلما كان ذلك ممكنًا.
# bad x = x + y x = x * y x = x**y x = x / y x = x || y x = x && y # good x += y x *= y x **= y x /= y x ||= y x &&= y
-
تجنب الفواصل المنقوطة باستثناء حالة تعريفك لصنف ذو سطر واحد، وعندما يكون من الملائم استخدام فاصلة منقوطة، ينبغي أن تكون متاخمة مباشرةً للعبارة التي ستنهيها. لا يجب ترك مسافة قبل الفاصلة المنقوطة.
# bad puts 'foobar'; # superfluous semicolon puts 'foo'; puts 'bar' # two expressions on the same line # good puts 'foobar' puts 'foo' puts 'bar' puts 'foo', 'bar' # this applies to puts in particular
-
استخدم
::
للثوابت المرجعيّة فقط (ويشمل هذا الأصناف والوحدات) والبواني (مثل:Array()
أوNokogiri::HTML()
) ولا تستخدم::
لاستدعاء الدالّة العادية.# bad SomeClass::some_method some_object::some_method # good SomeClass.some_method some_object.some_method SomeModule::SomeClass::SOME_CONST SomeModule::SomeClass()
-
تجنب استخدام
return
عندما تكون غير مطلوبة.# bad def some_method(some_arr) return some_arr.size end # good def some_method(some_arr) some_arr.size end
-
لا تستخدم القيمة المُعادة من المساواة
=
في الجمل الشرطيّة.# bad - shows intended use of assignment if (v = array.grep(/foo/)) ... end # bad if v = array.grep(/foo/) ... end # good v = array.grep(/foo/) if v ... end
-
استخدم
||=
كما تريد لتهيئة المتغيّرات.# set name to Bozhidar, only if it's nil or false name ||= 'Bozhidar'
-
لا تستخدم
||=
لتهيئة المتغيرات المنطقيّة، (فكر في ما سيحدث إذا كانت القيمة الحالية تساويfalse
).# bad - would set enabled to true even if it was false enabled ||= true # good enabled = true if enabled.nil?
-
استخدم
.call
الصريحة عند استدعاءlambda
.# bad lambda.(x, y) # good lambda.call(x, y)
-
تجنب استخدام متغيرات الخاصة على نمط بيرل Perl (مثل:
$
أو$0-9
…إلخ)، فهي مبهمة فعلًا. واستخدامها سيُعيقنا بكلّ شيئ عدا في السكربتات ذات السطر الواحد. يُفضّل اصدارات ذات الشكل الطويل مثل:$PROGRAM_NAME
. -
استخدم الاختصار
&:
عندما تأخذ كتلة الدالّة وسيط واحد فقط، ويعمل الجسم على قراءة سِمة أو استدعاء دالّة بدون وسطاء .# bad bluths.map { |bluth| bluth.occupation } bluths.select { |bluth| bluth.blue_self? } # good bluths.map(&:occupation) bluths.select(&:blue_self?)
-
يفضلُ استخدام
some_method
علىself.some_method
عند استدعاء الدالّة داخليًا.# bad def end_date self.start_date + self.nights end # good def end_date start_date + nights end
يجب عليك استخدام
self.
في الحالات الثلاثة التالية:
-
عند تعريف دالّة صنف:
def self.some_method
. -
عندما تكون
self
هي نموذج سجل فعالّActiveRecord
ويكون الجانب الأيسر هو استدعاء دالّة اِسناد بما في ذلك اِسناد سِمة:self.guest = user
. -
الإشارة للصنف داخليًا:
self.class
.
-
عند تعريف كائن من أي نوع قابل للتحويل وتريده أن يكون ثابتًا، تأكد من استدعاء
freeze
عليه، ومن الأمثلة الشائعة على ذلك هي السلاسل النصية، والمصفوفات، ومتغيرات من نوعhash
(انظر لهذا المقال لمزيد من المعلومات). والسبب في ذلك أن الثوابت في لفة روبي (Ruby) هي أنواع قابلة للتحويل، وبعضها الآخر ليس كذلك. ستتأكد من عدم قابليتها للتحويل عند استدعاءfreeze
عليها لأنه سيصدر استثناء عند محاولة تعديلهم إن كانت غير قابلة للتعديل، وبالنسبة للسلاسل النصية، سيُسمح بالتعامل معهم لنسخ روبي ذات الاصدار الأقدم من 2.2.# bad class Color RED = 'red' BLUE = 'blue' GREEN = 'green' ALL_COLORS = [ RED, BLUE, GREEN, ] COLOR_TO_RGB = { RED => 0xFF0000, BLUE => 0x0000FF, GREEN => 0x00FF00, } end # good class Color RED = 'red'.freeze BLUE = 'blue'.freeze GREEN = 'green'.freeze ALL_COLORS = [ RED, BLUE, GREEN, ].freeze COLOR_TO_RGB = { RED => 0xFF0000, BLUE => 0x0000FF, GREEN => 0x00FF00, }.freeze end
قواعد التسمية
-
استخدم أسلوب التسمية
snake_case
(جميع حروف اسم المتغير صغيرة) للدوالّ والمتغيرات. -
استخدم أسلوب التسمية
camelCase
(تكبير أول حرف من كلّ كلمة في اسم المتغير عدا أول كلمة) للأصناف والوحدات. (احتفظ بالاختصارات مثل" HTTP وRFC وXML بحالة حروف كبيرة). -
استخدم أسلوب التسمية
SCREAMING_SNAKE_CASE
(جميع حروف اسم المتغير كبيرة) للثوابت الأخرى. -
يجب أن تنتهي الدوالّ الإسنادية (الّتي ترجع قيمة منطقية) بعلامة استفهام. (هكذا:
Array#empty?
). -
يجب أن تنتهي أسماء الدوالّ التي يُحتمل أن تكون خطرة (مثل الدوالّ الّتي تُعدلّ
self
أو الوسطاء، أوexit!
…إلخ) بعلامة تعجب، ويجب أن تتواجد الدوالّ الخطرة (bang
) إذا تتواجدت الدوالّ غير الخطرة (non-bang
) معها (يمكنك الاطلاع على المقال للمزيد من المعلومات). -
سمِّ متغيّرات رمي الأخطاء
_
.version = '3.2.1' major_version, minor_version, _ = version.split('.')
الأصناف
-
تجنب استخدام متغيرات (
@@
) بسبب سلوكهم السيئ في الوراثة.class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => will print "child"
كما ترى أن جميع الأصناف في التسلسل الهرمي للصنف تتشارك في متغير صنف واحد، ويجب أن تُفضّل متغيّرات مثيل الصنف على متغيّرات الصنف.
-
استخدم
def self.method
لتعريف الدوالّ المتفرّدة (Singleton Methods)، وسيجعل هذا الدوالّ أكثر مقاومة لتغييرات إعادة الهيكلة.class TestClass # bad def TestClass.some_method ... end # good def self.some_other_method ... end
-
تجنب استخدام
class << self
إلا عند الضرورة، فمثلًا، الجالبات المفردة (single accessors
) والسمات مستعارة (aliased attributes
).class TestClass # bad class << self def first_method ... end def second_method_etc ... end end # good class << self attr_accessor :per_page alias_method :nwo, :find_by_name_with_owner end def self.first_method ... end def self.second_method_etc ... end end
-
ضع مسافة بادئة لدوالّ
public
وprotected
وprivate
بقدر تعريف الدالّة الّتي ينتمون إليها، واترك سطرًا فارغًا أعلاها وأسفلها.class SomeClass def public_method # ... end private def private_method # ... end end
الاستثناءات
-
لا تستخدم الاستثناءات للتحكم بسير البرنامج.
# bad begin n / d rescue ZeroDivisionError puts "Cannot divide by 0!" end # good if d.zero? puts "Cannot divide by 0!" else n / d end
-
تجنب إنقاذ (
rescue
) صنف الاستثناءException
.# bad begin # an exception occurs here rescue Exception # exception handling end # good begin # an exception occurs here rescue StandardError # exception handling end # acceptable begin # an exception occurs here rescue # exception handling end
-
لا تحدّد في استثناء
RuntimeError
وسيطين فقط في الكلمة المفتاحيةraise
، ومن الأفضل استخدام خطأ الأصناف الفرعية لتوضيح الخطأ وشرحه بطريقة أفضل.# bad raise RuntimeError, 'message' # better - RuntimeError is implicit here raise 'message' # best class MyExplicitError < RuntimeError; end raise MyExplicitError
-
يُفضّل توفير صنف استثناء والرسالة كوسيطين في الكلمة المفتاحية
raise
بدلًا من نسخة استثناء عادي.# bad raise SomeException.new('message') # Note that there is no way to do `raise SomeException.new('message'), backtrace`. # good raise SomeException, 'message' # Consistent with `raise SomeException, 'message', backtrace`.
-
تجنب استخدام
rescue
في شكل مُعدّل (Modifier).# bad read_file rescue handle_error($!) # good begin read_file rescue Errno:ENOENT => ex handle_error(ex) end
التجميعات (Collections)
-
يفضّل استخدام الخارطة (أو الخريطة)
map
بدلًا من تجميعةcollect
. -
يفضّل استخدام
detect
علىfind
، فاستخدامfind
غامض بسبب دالّةfind
الخاصة بكائن السجل الغعال (ActiveRecord) وسيُظهرdetect
على أنك تعمل مع تجميعة في لغة روبي وليس كائن سجل فعال. -
يُفضّل استخدام
reduce
علىinject
. -
يُفضّل استخدام
size
علىlength
وcount
لتحسين أداء الشيفرة. -
يفّضل استخدام تدوين الإنشاء (creation notation) ومصفوفة مجزئة مصنّفة النوع (Literal)، إلّا إذا كنت بحاجة لتمرير الوسطاء لمنشئيها.
# bad arr = Array.new hash = Hash.new # good arr = [] hash = {} # good because constructor requires parameters x = Hash.new { |h, k| h[k] = {} }
-
يُفضّل استخدام
Array#join
بدلًا منArray#*
لوضوح الشيفرة.# bad %w(one two three) * ', ' # => 'one, two, three' # good %w(one two three).join(', ') # => 'one, two, three'
-
استخدم الرموز (
symbols
) بدلًا من السلاسل النصية كمفاتيح لجدولHash
.# bad hash = { 'one' => 1, 'two' => 2, 'three' => 3 } # good hash = { :one => 1, :two => 2, :three => 3 }
-
على نحو مماثل، استخدم رموز واضحة بدلًا من رموز السلاسل النصية عندما يكون ذلك ممكنًا.
# bad :"symbol" # good :symbol
-
استخدم
Hash#key?
بدلًا منHash#has_key?
وHash#value?
بدلًا منHash#has_value?
. فوفقًا لماتز (Matz
)، تعدّ الأشكال الطويلة مُهملة.# bad hash.has_key?(:test) hash.has_value?(value) # good hash.key?(:test) hash.value?(value)
-
استخدم جدول
hash
متعدّد الأسطر لأنه يجعل الشيفرة أكثر قابليّة للقراءة، واستخدم الفواصل التذييلية للتأكد من أن أي تغيّر للوسطاء لن يتسبب بتغيّرات غريبة لشكل هذه الأسطر، وذلك عندما لا يتغيّر منطق الحلّ.hash = { :protocol => 'https', :only_path => false, :controller => :users, :action => :set_password, :redirect => @redirect_url, :secret => @secret, }
-
استخدم الفاصلة التذيليّة في المصفوفة الّتي تمتد لأكثر من سطر واحد.
# good array = [1, 2, 3] # good array = [ "car", "bear", "plane", "zoo", ]
السلاسل النصية
-
يُفضّل توليد السلسلة النصية (
string interpolation
) بدلًا من دمج السِلاسل النصية:# bad email_with_name = user.name + ' <' + user.email + '>' # good email_with_name = "#{user.name} <#{user.email}>"
وعلاوة على ذلك، لا تنس توليد نمط روبي 1.9، لنفترض أنك تُنشئ مفاتيح ذاكرة التخزين المؤقت كالتالي:
CACHE_KEY = '_store' cache.write(@user.id + CACHE_KEY)
مرةً أخرى يُفضّل توليد السلسلة النصية (
string interpolation
) بدلًا من دمج السِلاسل النصية:CACHE_KEY = '%d_store' cache.write(CACHE_KEY % @user.id)
-
تجنب استخدام
String#+
عندما تحتاج لإنشاء قطع بيانات كبيرة، واستخدم بدلًا من ذلكString#<<
. تحور عملية دمج نسخ السلاسل النصية في مكانها، وهي أسرع دومًا منString#+
، والّذي ينشئ مجموعة جديدة من كائنات السلسلة النصية.# good and also fast story = '' story << 'The Ugly Duckling' paragraphs.each do |paragraph| story << paragraph end
-
استخدم
\
في نهاية السطر بدلًا من+
أو<<
لدمج السلاسل النصية متعددة الأسطر.# bad "Some string is really long and " + "spans multiple lines." "Some string is really long and " << "spans multiple lines." # good "Some string is really long and " \ "spans multiple lines."
التعابير النمطية
-
تجنب استخدام
$1-9
لأنه من الصعب متابعة ما يحتويه، واستخدم بدلًا منه المجموعات المسماة (Named groups).# bad /(regexp)/ =~ string ... process $1 # good /(?<meaningful_var>regexp)/ =~ string ... process meaningful_var
-
كن حذرًا عند استخدام
^
و$
لأنها تطابق بداية/نهاية السطر، وليس نهايات السلسلة النصية، فإذا أردت مطابقة كامل السلسلة النصية فاستخدم:\A
و\z
.string = "some injection\nusername" string[/^username$/] # matches string[/\Ausername\z/] # don't match
-
استخدم المُعدّل
x
للتعابير النمطية المعقدة، فهذا سيجعلها أكثر قابلية للقراءة، ويمكنك إضافة بعض التعليقات المفيدة، فقط كن حذرًا لأنه سيتجاهل المسافات.regexp = %r{ start # some text \s # white space char (group) # first group (?:alt1|alt2) # some alternation end }x
محارف النسبة المئوية
-
يفضل استخدام الأقواس الهلالية على الأقواس المعقوصة، أو الأقواس المعقوفة، أو حتى الأنابيب (
pipes
) عند استخدام محددات مجردة%
للتناسق ولأن سلوك محارف%
أقرب إلى استدعاء الدالّة منه إلى البدائل.# bad %w[date locale] %w{date locale} %w|date locale| # good %w(date locale)
-
استخدم
%w
كما يحلو لك.STATES = %w(draft open closed)
-
استخدم
()%
للسلاسل النصية المتكونة من سطر واحد، والّتي تتطلّب عملية توليد سلسلة وعلامات الاقتباس المزدوجة المضمّنة، وبالنسبة للسلاسل النصية المتكونة من عدة أسطر، يُفضل استخدامheredocs
.# bad - no interpolation needed %(Welcome, Jane!) # should be 'Welcome, Jane!' # bad - no double-quotes %(This is #{quality} style) # should be "This is #{quality} style" # bad - multiple lines %(Welcome, Jane!\nPlease enjoy your stay at #{location}\nCheers!) # should be a heredoc. # good - requires interpolation, has quotes, single line %(Welcome, #{name}!)
-
استخدم
٪r
للتعابير النمطية فقط والّتي تتطابق مع أكثر من محرف/
.# bad %r(\s+) # still bad %r(^/(.*)$) # should be /^\/(.*)$/ # good %r(^/blog/2011/(.*)$)
-
تجنب استخدام
%x
إلا إذا أردت استدعاء أمر مع علامة الاقتباس الخلفية (`) - وهو أمر مستبعد إلى حد ما -.# bad date = %x(date) # good date = `date` echo = %x(echo `date`)
ريلز
عند العودة فورًا بعد استدعاء render
أو redirect_to
، ضع الكلمة المفتاحية return
في السطر التالي وليس في نفس السطر.
# bad render :text => 'Howdy' and return # good render :text => 'Howdy' return # still bad render :text => 'Howdy' and return if foo.present? # good if foo.present? render :text => 'Howdy' return end
نطاقات
-
عند تعريف نطاقات نموذج السجل الفعّال (ActiveRecord)، أحِط العلاقة بـ
lambda
، وخلافًا لذلك سيفرض الاتصال المجردة لقاعدة البيانات تنفيذه في وقت تحميل الصنف (مشابهة لطريقة بدء التشغيل).# bad scope :foo, where(:bar => 1) # good scope :foo, -> { where(:bar => 1) }
انسجم مع الشيفرة
إذا كنت تعدل شيفرة برمجية ما، فألقِ نظرة عليها لعدة دقائق، وحدّد أسلوب تنسيقها، فإن كانوا يستخدمون مسافات حول جميع المعاملات الرياضية، فانسجم مع هذه الطريقة، وإن كان للتعليقات صناديق صغيرة من المربعات hash
حولها، فانسجم معها أيضًا.
الهدف من امتلاك مبادئ توجيهية لتنسيق الشيفرة هي الحصول على مفردات مشتركة من الشيفرات ليتمكن الناس من فهم ما تقوله بدلًا من كيف تقوله، واستعرضنا هنا قواعد التنسيق العالمية حتى يعرف الناس المفردات، لكن التنسيقات شيفراتك المحلية مهمة أيضًا، فإذا كانت الشيفرة البرمجية الّتي ستضيفها تختلف اختلافًا كبيرًا عن الشيفرات البرمجية الّتي حولها فعندها ستجعل قراءة الشيفرة صعبة ولذلك تجنب هذا الأمر - دليل Google لتنسيق الشيفرة البرمجية للغة C++
ترجمة لدليل Ruby Style Guide من شركة Airbnb على موقع GitHub
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.