اذهب إلى المحتوى

إن هذا الدليل مستوحى من دليل 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'

في كِلا الحالتين:

# 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.‎ في الحالات الثلاثة التالية:

  1. عند تعريف دالّة صنف: def self.some_method.
  2. عندما تكون self هي نموذج سجل فعالّ ActiveRecord ويكون الجانب الأيسر هو استدعاء دالّة اِسناد بما في ذلك اِسناد سِمة: self.guest = user.
  3. الإشارة للصنف داخليًا: 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.


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...