Mohamed Lahlah

الأعضاء
  • المساهمات

    23
  • تاريخ الانضمام

  • تاريخ آخر زيارة

السُّمعة بالموقع

7 Neutral

1 متابع

  1. إن هذا الدليل مستوحى من دليل GitHub ودليل Bozhidar Batsov. ولدينا أيضًا دليل جافاسكربت لتنسيق الشيفرة البرمجية جدول المحتويات المسافات البيضاء المسافة البادئة في الشيفرة المسافات السطرية الأسطر الجديدة طول السطر التعليقات تعليقات على مستوى الملف/الصنف تعليقات الدالة التعليقات الكتلية والمضمّنة علامات الترقيم والإملاء والنحو تعليقات TODO شيفرات برمجية بدون تعليقات الدوال تعريف الدوال دوال الاستدعاء التعابير الشرطيّة الكلمات المفتاحية للجمل الشرطية المعامل الثلاثي الشروط المتشعّبة الصياغة قواعد التسمية الأصناف الاستثناءات التجميعات السلاسل النصية التعابير النمطية محارف النسبة المئوية ريلز نطاقات انسجم مع الشيفرة المسافات البيضاء المسافة البادئة في الشيفرة استخدم الزر (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++‎ ولغة 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 التعابير الشرطيّة الكلمات المفتاحية للجمل الشرطية لا تستخدم الكلمة المفتاحية 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
  2. يشير مصطلح مفتوح المصدر (open source) لأي شيء يمكن لأي شخص تعديله ومشاركته لأن تصميمه متاح للجميع. نشأ هذا المصطلح في سياق تطوير البرمجيات للدلالة على نهج خاص لإنشاء برامج للحاسوب. أما اليوم، فإن مصطلح "مفتوح المصدر" يشير لمجموعة أوسع من القيم - والّتي نسميها "الثقافة مفتوحة المصدر. تتبنى المشاريع، أو المنتجات، أو المبادرات مفتوحة المصدر مبادئ التبادل المفتوح والمشاركة التعاونية والنماذج الأولية السريعة والشفافية العالية والجدارة والتنمية الموجهة للمجتمع. ما هي البرمجية مفتوحة المصدر؟ البرمجيات مفتوحة المصدر: هي برمجيات يمكننا رؤية شيفرتها البرمجية وفحصها وتعديلها وتحسينها. "الشيفرة البرمجية" هي جزء من برمجية لا يراه معظم مستخدمي الحاسوب على الإطلاق، ويتلاعب مبرمجو الحاسوب بالشيفرة لتغيير طريقة عمل البرمجية - سواءً أكانت "برنامج" أو "تطبيق". يمكن للمبرمجين الّذين يستطيعون الوصول للشيفرة البرمجية لبرنامج الحاسوب تحسين هذا البرنامج من خلال إضافة ميزات إليه أو إصلاح الأجزاء الّتي لا تعمل دائمًا عملًا صحيحًا. ما الفرق بين البرمجيات مفتوحة المصدر والأنواع أخرى؟ هناك بعض البرمجيات الّتي لا تُملكُ شيفرتها أو يمكن التعديل عليها سوى الجهة الّتي أنشأتها سواءً أكانت ممثلة بشخص أو فريق أو مؤسسة وتحتفظ هذه الجهة بالسيطرة الحصرية عليها. ويطلق الناس على هذا النوع من البرمجيات "بالبرمجيات المحتكرة" (proprietary) أو "مغلقة المصدر" (closed source). يمكن لأصحاب البرمجيات المحتكرة وحدهم نسخ هذه البرمجيات، وفحصها وتغييرها بطريقة قانونية. ولاستخدام البرمجيات المحتكرة لابد أن يوافق مستخدمي الحاسوب (للتوقيع على الترخيص المعروض والّذي يعرض عادةً عند التشغيل للمرة الأولى للبرمجيات) والّتي تنص على أنهم لن يفعلوا أي شيء للبرمجية مخالف صراحةً لما يسمح به منشئي هذه البرمجية. ومن هذه البرمجيات نذكر Microsoft Office وAdobe Photoshop. تختلف البرمجيات مفتوحة المصدر عن نظيرتها المحتكرة. إذ يتيح منشئي البرمجيات المفتوحة المصدر عرض الشيفرة البرمجية، ونسخها، والتعلم منها، وتغييرها، ومشاركتها أيضًا. ومن هذه البرمجيات نذكر محرر النصوص ليبر أوفيس LibreOffice وبرنامج التلاعب بالصور Gimp. وكما هو الحال مع البرمجيات المحتكرة يجب على المستخدمين عند استخدامهم البرمجيات مفتوحة المصدر الموافقة على شروط الترخيص بيدَ أن هذه الشروط تختلف اختلافًا كبيرًا عن شروط البرمجيات المحتكرة. تحدّد تراخيص البرمجيات مفتوحة المصدر طريقة استخدام البرمجيات، وتعديلها، وتوزيعها. وعمومًا تَمنحُ هذه التراخيص إذنًا باستخدام البرمجيات لأي غرض يرغب به المستخدم. إلا أن البعض الأخر من التراخيص والّتي يسميها البعض "الحقوق المتروكة" تنص على وجوب عرض الشيفرة البرمجية الخاصة لكلّ نُسخة مُعدلة من هذه البرمجية علنيًا. علاوة على ذلك بعض التراخيص تُوجبُ على أي شخص يعدلّ البرمجية ويشاركها مع الآخرين أن يشارك أيضًا المصدر الأصلي للشيفرة بدون فرض رسوم الترخيص عليها. تعمدُ تراخيص البرمجيات مفتوحة المصدر على تعزيز روح التعاون والمشاركة لأنها تسمح للجميع بإجراء تعديلات على الشيفرات البرمجية، ودمج هذه التغييرات في مشاريعهم الخاصة. وهم بذلك يشجعون مبرمجي الحاسوب بالوصول إلى البرمجيات مفتوحة المصدر وعرضها وتعديلها بأي وقت يحلو لهم، طالما أنهم سمحوا للآخرين بفعل نفس الشيئ عندما يشاركون برمجياتهم. هل البرمجيات مفتوحة المصدر مهمة لمبرمجي الحاسوب فقط؟ بالتأكيد لا. بل إن التكنولوجيا مفتوحة المصدر والعقلية المنفتحة للمصادر المفتوحة عمومًا تفيد كلًا من المبرمجين وغير المبرمجين. لأن المخترعين الأوائل للإنترنت شيدوا جزءًا كبيرًا منه على تقنياتٍ مفتوحة المصدر - مثل: نظام التشغيل Linux وتطبيق خادم الوِب المحلي Apache - وبذلك أي شخص يستخدم الانترنت فهو في الحقيقة يستفيد من البرمجيات مفتوحة المصدر. عند كلّ عملية استعراض لصفحة وِب أو التحقق من البريد الإلكتروني، أو الدردشة مع الأصدقاء، أو استخدام منصات البث الموسيقي عبر الإنترنت، أو اللعب بألعاب فيديو متعددة اللاعبين فإن حاسوب المستخدم، أو هاتفه المحمول، أو طرفيات الألعاب ستتصل بشبكة عالمية من الحواسيب من خلال برمجيات مفتوحة المصدر من أجل توجيه ونقل البيانات إلى أجهزتهم "المحلية" الموجودة أمام أعينهم. عادةً ما تتواجد هذه الحواسيب الّتي تؤدي كلّ هذا العمل الهام في أماكن بعيدة عن أنظار المستخدمين أو لا يستطيعون الوصول إليها فعليًا - وهذا هو السبب في أن بعض الأشخاص يطلقون على هذه الحواسيب "بالحواسيب البعيدة". يعتمد الناس أكثر فأكثر على الحواسيب البعيدة عند أداء مهامهم بدلًا من أجهزتهم المحلية. فمثلًا، قد يستخدمون برمجيات معالجة الكلمات وإدارة البريد الإلكتروني وتحرير الصور وهي غير مثبتة على حواسيبهم الشخصية. وإنما، ببساطة يصلون لها عبر الحواسيب البعيدة من خلال متصفح الوِب أو تطبيق على الهاتف محمول. وعندما يفعلون ذلك، فهم ينخرطون في "الحوسبة عن بُعد". يطلق بعض الأشخاص على الحوسبة عن بُعد "بالحوسبة السحابية" وذلك لأنها تتضمن أنشطة (مثل: تخزين الملفات أو مشاركة الصور أو مشاهدة مقاطع الفيديو) والّتي لا تتضمن حواسيب محلية فقط وإنما شبكة عالمية من الحواسيب البعيدة أيضًا الّتي تشكل سحابة. تتوالى أهمية الحوسبة السحابية يومًا بعد يوم وخصيصًا في الحياة اليومية للأجهزة المتصلة بالإنترنت. ومن بعض تطبيقات الحوسبة السحابية المحتكرة Google Apps. أما بعض التطبيقات الأخرى مفتوحة المصدر نذكر: ownCloud وNextcloud. تعمل تطبيقات الحوسبة السحابية "على قمة" من البرمجيات الإضافية المساعدة لها لتعمل بسلاسة وكفاءة، لذلك غالبًا ما سيقول الناس أن البرمجيات الّتي تعمل "تحت" تطبيقات الحوسبة السحابية تعمل بمثابة "منصة" لتطبيقات الحوسبة السحابية، وتكون هذه المنصات إما مفتوحة المصدر أو مغلقة المصدر. فمثلًا المنصة OpenStack هي منصة مفتوحة المصدر. لماذا يفضل الناس استخدام برمجيات مفتوحة المصدر؟ يفضل الناس البرمجيات مفتوحة المصدر على حساب البرمجيات المحتكرة لعدد من الأسباب: زيادة السيطرة على البرمجية يفضل كثير من الناس البرمجيات مفتوحة المصدر لأنها تعطيهم مزيدًا من السيطرة والتحكم. إذ يمكنهم فحص الشيفرة البرمجية للتأكد من أنها ستؤدي نفس المهمة الّتي يريدونها، بل ويمكنهم حتى تغيير أي جزء منها لا يحبونه. كما يستفيد غير المبرمجين من هذه البرمجيات أيضًا، لأنهم يمكنهم استخدام هذه البرمجية لأي غرض يرغبون فيه - وبذلك لا تُفرض عليهم الطريقة الّتي يعتقد شخص ما -صاحب البرمجية مثلًا- بأنه يجب عليهم استخدام البرمجية وفقًا لها (كما يحدث في البرمجيات المحتكرة). التعلم والتدرب من هذه البرمجيات يحبُ البعض الآخر من الناس هذه البرمجيات لأنها تساعدهم ليصبحوا مبرمجين أفضل. نظرًا لأن الشيفرة البرمجية متاحة للجميع، وبذلك يمكن للطلاب دراستها بسهولة أثناء تعلمهم لإنشاء برمجية أفضل. يمكن للطلاب مشاركة عملهم مع الآخرين أيضًا، ودعوتهم للتعليق والنقد البناء، وبذلك يصقل الطلاب مهاراتهم. عندما يكتشف الأشخاص أخطاءً في الشيفرات البرمجية لبرامجهم، يمكنهم مشاركة هذه الأخطاء مع الآخرين لمساعدتهم على تجنب ارتكاب نفس هذه الأخطاء. الحماية والأمان يُفضل بعض الأشخاص هذه البرمجيات لأنهم يرونها أكثر أمانًا واستقرارًا من البرمجيات المحتكرة. نظرًا من كون الجميع يستطيع عرض وتعديل البرمجيات مفتوحة المصدر، فيمكن لأي شخص أن يكتشف خطأ غفِلَ عنه أصحاب البرمجية أنفسهم بل ويمكن أن يصحح أو يحذف هذا الخطأ. ولأن العديد من المبرمجين يمكنهم العمل على جزء معين من البرمجية بدون طلب إذن من أصحابها، فسيُسرّع ذلك من وتيرة إصلاح البرمجية وتحديثها وترقيتها أكثر من البرمجيات المحتكرة. الاستقرار والثبات يفضل العديد من المستخدمين البرمجيات مفتوحة المصدر على نظيرتها المحتكرة للمشاريع المهمة وطويلة الأمد. نظرًا لتوزيع المبرمجين الشيفرة البرمجية علنًا للبرمجيات مفتوحة المصدر، فيمكن للمستخدمين الّذين يعتمدون على هذه البرمجيات في المهام الحرجة التأكد من أن أدواتهم لن تختفي أو تتعطل إذا توقف أصحابها عن تطويرها -وذلك لأن لديها عدة مبرمجين آخرين مهتمين بها- علاوة عن ذلك، تميل البرمجيات مفتوحة المصدر للاندماج والعمل وفقًا للمعايير المفتوحة. المجتمع الداعم للبرمجية غالبًا ما تستقطب البرمجيات مفتوحة المصدر جمهورًا من المستخدمين والمطورين المحبين لها. وهذا ليس حكرًا على هذه البرمجيات بل العديد من التطبيقات الشعبية لها مجتمعات كبيرة ومواضيع يناقشونها في لقاءاتهم واجتماعاتهم. غير أن في البرمجيات مفتوحة المصدر يكون المجتمع ليس مجرد قاعدة جماهيرية تشتري (سواء عاطفيًا بالدعم أو ماليًا بسعر البرمجية) وتكوّن بذلك مجموعة مميزة من المستخدمين وحسب، وإنما مجموعة من الأشخاص الّذين ينتجون ويختبرون ويستخدمون ويروجون بل ويؤثرون تأثيرًا جوهريًا على البرمجية الّتي يحبونها. هل يعني مصطلح "مفتوح المصدر" بأنه مجاني؟ لا. هذا مفهوم خاطئ ومنتشر حول ما يعنيه مصطلح "مفتوح المصدر"، وممكن ألا يتعلق هذا المصطلح بالمال. يمكن لمبرمجي هذه البرمجيات أن يتقاضوا المال مقابل البرمجيات مفتوحة المصدر الّتي يصنعونها أو يساهمون فيها. ولكن في بعض الحالات، نظرًا لأن ترخيص المصدر المفتوح يتطلب منهم إصدار الشيفرة البرمجية علنًا عندما يبيعون هذه البرمجيات للآخرين، ولذلك يجدُ بعض المبرمجين أن فرض رسوم على المستخدمين مقابل الخدمات والدعم الفني للبرمجية (بدلًا من البرمجية بحد ذاتها) أكثر ربحًا. وبهذا تظل برمجياتهم مجانية، ويكسبون المال من مساعدة الآخرين في تثبيتها واستخدامها واستكشاف أخطائها وإصلاحها. على الرغم من كون بعض البرمجيات مفتوحة المصدر مجانية، إلا أن مهارة البرمجة واستكشاف الأخطاء وإصلاحها في البرمجيات مفتوحة المصدر يمكن أن تكون ذات قيمة كبيرة. يسعى الكثير من أرباب العمل لتوظيف مبرمجين لديهم خبرة سابقة بالعمل على برمجيات مفتوحة المصدر تحديدًا. ما هي الثقافة مفتوحة المصدر "أي أبعد من الشيفرة البرمجية"؟ إن التعامل مع جميع جوانب الحياة بثقافة مفتوحة المصدر يعني التعبير عن الرغبة في المشاركة والتعاون مع الآخرين بشفافية (ليتمكن الآخرين من المشاهدة أو حتى الانضمام أيضًا)، واحتضان الفشل كوسيلة للتطوّر، وتوقع -أو حتى تشجيع- الجميع ليشاركوا وينضموا إلى هذه الثقافة. ويعني الالتزام أيضًا بدور فعّال في تحسين العالم، وهو أمر ممكن في حال تمكن الجميع من الوصول للطريقة الّتي صُمّم بها هذا العالم. إن العالم مليء "بالشيفرات البرمجية" - المخططات والوصفات والقواعد - الّتي توجه طريقة تفكيرنا وتشكلها من أجل أن نتصرف على أساسها. نؤمن تمامًا بأن هذه الشيفرة الضمنية (مهما كان شكلها) يجب أن تكون مفتوحةً وقابلة للوصول والمشاركة من قِبل الجميع — ليتمكنوا من تغييرها للأفضل. ترجمة -وبتصرف- للمقال What is open source software?‎
  3. تعلم كيفية حلّ المشاكل الشائعة في أنظمة المعالجة المتزامنة وتفادى صداع المرافق لحلّها في المستقبل. عند التعامل مع أنظمة موزعة ومعقدة، فمن الوارد جدًا أن تحتاج للمعالجة المتزامنة. ولكن لن يكون بناء شبكة عالمية خاصة توجه الحزم ديناميكيًا بدقة تصلّ للملّي ثانية أمرًا ممكنًا بدون نظام شديد التزامن. يعتمد هذا التوجيه الديناميكي على حالة الشبكة، وبينما توجد العديد من المعاملات الّتي يجب مراعاتها في هذا الأمر، سينصبُ تركيزنا على مقاييس الارتباط. في سياق الحالة الّتي سنناقشها، يمكن أن تكون مقاييس الارتباط أي شيء متعلق بالحالة رابط الشبكة و خصائصه (مثل: زمن تأخير الارتباط). الفحص المتزامن لمقاييس الارتباط تعتمد خوارزمية HALO (وهي اختصارًا Hop-by-Hop Adaptive Link-State Optimal Routing) على التوجيه الديناميكي جزئيًا على مقاييس الارتباط لحساب جدول التوجيه الخاص بها. تُجمعُ هذه المقاييس من خلال مكون مستقل متواجد بكلّ PoP (نقطة مشاركة). أما نقاط المشاركة (PoPs) وهي آلات تمثل كيانًا موجهًا واحدًا في شبكاتنا، ومتصلة بارتباطات متعددة وتنتشر في مواقع كثيرة مشكلةً بذلك شبكتنا. يستكشف هذا المكون الأجهزة المجاورة باستخدام حزم الشبكة، وسيُردُ هؤلاء الجيران بجواب أولي. يمكن استخلاص قيم زمن تأخير الارتباط من الأجوبة المتلقاة من هذه النقاط. نظرًا لأن لكل نقطة اتصال أكثر من جار واحد، فإن طبيعة هذه المهمة متزامنة جوهريًا: نحتاج إلى قياس وقت الاستجابة لكل رابط مجاور في الوقت الفعلي. لا يمكننا تحمل المعالجة التسلسلية ويجب معالجة كلّ جواب بأقرب وقت ممكن لحساب مقياس الارتباط. أرقام التسلسل وإعادة الضبط: حالة إعادة الترتيب تتبادل نقطة المشاركة الخاصة بنا الحزم وتعتمد على الأرقام المتسلسلة لمعالجة الحزم. وذلك بهدف تجنب معالجة الحزم المكررة أو الحزم غير المرتبة. اعتمد تطبيقنا الأول للخوارزمية على الرقم التسلسلي 0 لإعادة تعيين الأرقام المتسلسلة. ويستخدم هذا الرقم أثناء تهيئة المكونات فقط. المشكلة الرئيسية الّتي واجهتنا هي أننا كنا نفكر في زيادة قيمة الرقم التسلسلي الّذي يبدأ دائمًا عند 0. ولكن نلاحظ أن بعد إعادة تشغيل نقطة المشاركة، يمكن أن يحدث إعادة ترتيب للحزمة، ويمكن لحزمة ما استبدال رقمها التسلسلي برقم حزمة مستخدمة قبل عملية إعادة الترتيب. هذا يعني أن هذه الحزمة ستُتجاهلُ حتى يتغير رقمها التسلسلي ليصبح الرقم الّذي كانت تستخدمه قبل إعادة الترتيب. عملية تأسيس اتصال UDP وحالات الآلة المحدودة كانت المشكلة السابقة بانسجام الرقم التسلسلي بعد إعادة تشغيل نقطة المشاركة (ليستخدم الرقم الصحيح). هناك عدة طرق للتعامل مع هذا الأمر، وبعد مناقشة خياراتنا، اخترنا تطبيق بروتوكول مصافحة ثلاثي الاتجاهات مع تعريف واضح للحالات. تحدد عمليات تأسيس الاتصال الجلسات عبر الروابط أثناء التهيئة. وهذا يضمن أن العقد تتواصل خلال نفس الجلسة وتستخدم رقم تسلسلي مناسب لها. لتطبيق هذا الأمر تطبيقًا صحيحًا، يجب علينا تحديد حالات الآلة المحدودة وكما يجب أن تكون الانتقالات واضحة بينهم. وهذا بدوره سيسمح لنا بإدارة جميع حالات الحرجة لتأسيس الاتصال تأسيسًا صحيحًا. تُنشأ مُعرّفات الجلسة من خلال مؤسس الاتصالات. ويكون التسلسل الكامل لعملية الإنشاء على الشكل التالي: يرسل المرسل حزمة SYN(ID)‎. يخزن المُستقبل المُعرّف الواصل له (وهو ID) ويرسل SYN-ACK (ID)‎. يتلقى المرسل SYN-ACK (ID)‎ ويرسل ACK (ID)‎. كما يبدأ أيضًا في إرسال الحزم الّتي تبدأ بالتسلسل رقم 0. يتحقق المرسل من آخر معرّف ID استلمه، ويقبل ACK (ID)‎ إذا كان معرّفه مطابقًا للمعرّف (ID) السابق. كما يبدأ بقبول الحزم الّتي تبدأ برقم تسلسلي 0. معالجة المُهلة الزمنية للحالة ستحتاج كلّ حالة افتراضيًا لمعالجة ثلاثة أنواع من الأحداث على الأكثر: أحداث عمليات الارتباط، وأحداث تراسل الحزم، وأحداث انتهاء المُهلة. وتظهر هذه الأحداث في وقت واحد، لذلك عليك التعامل معها بطريقة متزامنة. أحداث الارتباط: وهي تحديث لحالة الارتباط فإما عملية ارتباط أو عملية فصل الارتباط. يمكن لهذا إما بدء جلسة اتصال أو إنهاء جلسة موجودة. أحداث تراسل الحزم: وهي لحزم التحكم مثل: (SYN/SYN-ACK/ACK) أو استقصاء الاستجابات فقط. أحداث انتهاء المُهلة: هي الأحداث الّتي تُشغّل بعد انتهاء المهلة المُجدولة لحالة الجلسة الحالية. يكمن التحدي الرئيسي الّذي نواجهه هنا هو كيفية التعامل مع انتهاء زمن المُهلة المتزامنة والأحداث الأخرى بنفس الوقت. وهنا يمكن للمرء أن يسقط بسهولة في مشاكلة القفل المستعصي (Deadlocks) ومشكلة السباق (Race conditions). النهج الأول سنستخدم في هذا المشروع لغة Golang لإنها توفر آليات مزامنة أصيلة مثل: القنوات والأقفال الأصيلة وهي قادرة أيضًا على تدوير الخيوط (Threads) الخفيفة لمعالجتهم بطريقة متزامنة (لمزيد من المعلومات يمكنك الاطلاع على مقال سابق أخذنا فيه نظرة سريعة على لغة Golang). سنبدأ أولًا بتصميم هيكلًا (Struct) لتمثيل مُعالجات جلسات العمل والمُهلة. type Session struct { State SessionState Id SessionId RemoteIp string } type TimeoutHandler struct { callback func(Session) session Session duration int timer *timer.Timer } تُحددُ (Session) جلسة الاتصال بمعرّف الجلسة (ID)، وعنوان IP للارتباط المجاور (RemoteIp)، وحالة الجلسة الحالية (State). كما يحدد معالج المُهلة (TimeoutHandler) بدالّة رد النداء (callback)، والجلسة الّتي يجب أن يعمل من أجلها (session)، والمدة (duration)، ومؤشر للوقت المُجدول (timer). ستُخزن خارطة (أو خريطة) عامة (Global Map) -الخرائط Maps في لغة Go هي مصفوفات ترابطية يمكن التعديل عليها ديناميكيًا وهي تشبه نوع القاموس او الهاش في اللغات البرمجية الأخرى- مُعالج المُهلة المُجدولة لكل جلسة ارتباط مجاورة. SessionTimeout map[Session]*TimeoutHandler تُسجّل مُهلةٌ ما وتُلغى بالدوالّ التالية: // الدالّة المسؤولة عن جدولة المهلة لرد النداء func (timeout* TimeoutHandler) Register() { timeout.timer = time.AfterFunc(time.Duration(timeout.duration) * time.Second, func() { timeout.callback(timeout.session) }) } func (timeout* TimeoutHandler) Cancel() { if timeout.timer == nil { return } timeout.timer.Stop() } لإنشاء المُهل وتخزينها، يمكنك استخدام دالّة مشابه لهذه: func CreateTimeoutHandler(callback func(Session), session Session, duration int) *TimeoutHandler { if sessionTimeout[session] == nil { sessionTimeout[session] := new(TimeoutHandler) } timeout = sessionTimeout[session] timeout.session = session timeout.callback = callback timeout.duration = duration return timeout } بمجرد إنشاء معالج المُهلة وتسجيله بنجاح، سيُشغل عندها رد النداء بعد انقضاء المدة الزمنية (duration) المقدرة بالثانية. بينما بعض الأحداث الأخرى ستتطلبُ منك إعادة جدولة معالج المُهلة (كما يحدث في حالة SYN - كلّ 3 ثوان). لذلك، يمكنك إعادة جدولة المُهلة لرد نداء معين. هكذا: func synCallback(session Session) { sendSynPacket(session) // reschedules the same callback. newTimeout := NewTimeoutHandler(synCallback, session, SYN_TIMEOUT_DURATION) newTimeout.Register() sessionTimeout[state] = newTimeout } سيعيد رد النداء جدولة نفسه في معالج مهلة جديد ويحدّث الخارطة العامة بقيمة sessionTimeout الجديدة. سباق البيانات والمراجع الحل أصبح جاهزًا تقريبًا. لنطبق اختبار واحد بسيط للتحقق من تنفيذ رد النداء بعد انقضاء زمن المؤقت للمُهلة. للقيام بذلك، نسجلّ المُهلة، وندخلها بمرحلة النوم أو السُبات (sleep) بحسب مدتها، ثم نتحقق فيما إذا كانت إجراءات رد النداء نُفذت بالفعل. بعد تنفيذ الاختبار، من الأفضل إلغاء المُهلة المُجدولة (إذ يمكننا أيضًا إعادة جدولتها لاحقًا)، لذلك لن يكون له آثار جانبية بين الاختبارات. والمثير للدهشة أن هذا الاختبار رغم بساطته أوجد خطأ في حلنا السابق. إذ أن إلغاء المُهل المُجدولة باستخدام دوالّ الإلغاء لن يُؤدي الوظيفة الّتي نريدها. فمثلًا يمكن أن يؤدي الترتيب التالي للأحداث للدخول بحالة سباق على البيانات: لديك معالج (handler) مجدول بمُهلة معينة. الخيط 1 (Thread 1): أ) تتلقى حزمة تحكم، وتريد الآن إلغاء المُهلة المسجلة والانتقال لحالة الجلسة التالية. (مثلًا، أن تتلقى SYN-ACK بعد إرسال ** SYN **). ب) يمكنك استدعاء الدالّة timeout.Cancel()‎، والّتي بدورها ستستدعي الدالّة timer.Stop()‎. (لاحظ أن توقف مؤقت لغة Golang لن يمنع تشغيل المؤقت الّذي انتهت مدته الزمنية بالفعل). الخيط 2: أ) قبل استدعاء دالة الإلغاء مباشرةً، انقضت المدة الزمنية للمؤقت، وكان رد النداء على وشك التنفيذ. ب) نفذَّ رد النداء، وسجُلّت المُهلة الجديدة وحُدّثت أيضًا الخارطة العامة. الخيط 1: أ) الانتقال لحالة الجلسة الجديدة وتسجيل مُهلة جديدة، وتحديث الخارطة العامة. كلا الخيطين حدثا الخارطة العامة بالمُهلة الجديدة تحديثًا متزامنًا. والنتيجة النهائية هي أنك فشلتَ في إلغاء المُهلة المسجلة، وفقدتَ أيضًا الإشارة للمُهلة المُعادُ جدولتها والّتي نفذّت بواسطة الخيط 2. وبذلك سيستمر المعالج في التنفيذ وإعادة الجدولة لفترى من الزمن، مما سيؤدي لسلوك غير مرغوب به في البرنامج. هل يعد استخدام القفل كافيًا لحل المشكلة؟ في بعض الأحيان لا تَحلُّ الأقفال المشكلة تمامًا. فإن أضفنا أقفالًا قبل معالجة أي حدث وقبل تنفيذ رد النداء، فلا يزال هذا الحل لا يمنع تشغيل رد النداء المنتهية مدته الزمنية: func (timeout* TimeoutHandler) Register() { timeout.timer = time.AfterFunc(time.Duration(timeout.duration) * time._Second_, func() { stateLock.Lock() defer stateLock.Unlock() timeout.callback(timeout.session) }) } إن الفرق الآن هو أن التحديثات على الخارطة العامة متزامنة، ولكن هذا لا يمنع رد النداء من العمل بعد استدعاء الدالّة timeout.Cancel()‎ - وتحدث هذه الحالة إذا انتهت المدة الزمنية للمؤقت المُجدول ولكنه لم يجلب القفل بعد. عندها يجب أن تُفقدُ مرة أخرى الإشارة لأحد المُهل المسجلة. استخدام قنوات الإلغاء بدلًا من الاعتماد على الدالّة timer.Stop()‎ في لغة Golang، الّذي لن يمنع رد النداء المنتهية مُهلته الزمنية من التنفيذ، سنعتمد على قنوات الإلغاء. هذا النهج مختلف قليلًا عن سابقه. فالآن لن نعيد الجدولة بطريقة تعاودية من خلال ردود النداء وإنما سننشئ حلقة لا نهائية تنتظر إشارات الإلغاء أو أحداث انتهاء المُهل. إن الدالّة Register()‎ ستُولّد خيوطًا جديدة والّتي ستُشغل رد النداء بعد انتهاء المُهلة، وكما أنها ستُجدولّ المهلة الجديدة بعد تنفيذ المُهلة السابقة. ستُعاد قناة إلغاء إلى المستدعي ليتحكم بالوقت المناسب لإيقاف الحلقة. func (timeout *TimeoutHandler) Register() chan struct{} { cancelChan := make(chan struct{}) go func () { select { case _ = <- cancelChan: return case _ = <- time.AfterFunc(time.Duration(timeout.duration) * time.Second): func () { stateLock.Lock() defer stateLock.Unlock() timeout.callback(timeout.session) } () } } () return cancelChan } func (timeout* TimeoutHandler) Cancel() { if timeout.cancelChan == nil { return } timeout.cancelChan <- struct{}{} } يمنحك هذا النهج قناة إلغاء مخصّصة لكل مُهلة تسجلها. يُرسلُ استدعاء الإلغاء كهيكل (Struct) فارغ إلى القناة، ويؤدي ذلك إلى الإلغاء. ومع ذلك، هذا النهج لن يحلّ المشكلة السابقة الّتي عانينا منها؛ إذ يمكن أن تنتهي المدة الزمنية للمهلة فورًا قبل استدعاء الإلغاء عبر القناة، وقبل أن يُجلبُ القفل بواسطة مُهلة الخيط. الحل في هذه الحالة هو التحقق من قناة الإلغاء بداخل نطاق المُهلة بعد جلب القفل. case _ = <- time.AfterFunc(time.Duration(timeout.duration) * time.Second): func () { stateLock.Lock() defer stateLock.Unlock() select { case _ = <- handler.cancelChan: return default: timeout.callback(timeout.session) } } () } أخيرًا، هذا سيضمنُ أن يُنفذّ رد النداء فقط بعد جلب القفل وقبل تفعيل الإلغاء. احذر من مشكلة القفل المستعصي يبدو أن هذا الحل يعمل عملًا جيدًا. إلا أنه بالرغم من ذلك نلاحظ وجود مشكلة القفل المستعصي المخفية. حاول أن تعيد قراءة الشيفرة البرمجية أعلاه وأن تحاول العثور عليها بنفسك. فكر في الاستدعاءات المتزامنة للدوالّ الموضحة. المشكلة الأخيرة هنا هي قناة الإلغاء نفسها. لقد أنشأنا قناةً بدون تفعيل ميزة التخزين المؤقت فيها، مما يعني أن عملية الإرسال هي عملية استدعاء الحجب. بمجرد استدعاء الإلغاء في مُعالج المُهلة، يمكنك المتابعة عند حدوث عملية الإلغاء. تكمن المشكلة هنا عندما يكون لديك عدة استدعاءات لنفس قناة الإلغاء، ولكن يُستهلكُ طلَبُ الإلغاء لمرة واحدة فقط. ويمكن أن يحدث هذا السيناريو ببساطة في حال كانت الأحداث المتزامنة ستلغي نفس مُعالج المُهلة، مثل حدث فصل الارتباط أو حدث تراسل حزمة التحكم. وينتج عن ذلك حالة استعصاء، والتي بدورها ستؤدي لتوقف التطبيق. الحل هنا هو تفعيل ميزة التخزين المؤقت للقناة من قبل أحد الأحداث، لذا فإن الإرسال لن يؤدي دومًا للحجب، وجعل الإرسال لن يؤدي للحجب بطريقة صريحة في حالة الاستدعاءات المتزامنة. وهذا سيضمن أن عملية الحجب ستكون بعملية إرسال واحدة فقط، ولن تؤدي الاستدعاءات المتتالية لعملية الإرسال للحجب. func (timeout* TimeoutHandler) Cancel() { if timeout.cancelChan == nil { return } select { case timeout.cancelChan <- struct{}{}: default: // can’t send on the channel, someone has already requested the cancellation. } } الخلاصة تعلمنا من خلال التطبيقات العملية كيف تظهر الأخطاء الشائعة أثناء العمل مع الشيفرات المتزامنة. نظرًا لطبيعتها غير الحتمية، يمكن اكتشاف هذه المشكلات بسهولة، بدون إجراء اختبارات مكثفة. وإليك المشاكل الرئيسية الثلاث الّتي واجهناها في تطبيقنا. تحديث البيانات المشتركة بدون مزامنة يبدو هذا الأمر جليًا، ولكن من الصعب تحديد ما إذا كانت التحديثات المتزامنة تحدث في مواقع مختلفة. والنتيجة هي حالة السباق على البيانات، حيث يمكن أن تؤدي التحديثات المتعددة لنفس البيانات لفقدان التحديث، بسبب تجاوز أحد التحديثات لتحديث آخر. في مثالنا، حدثنا مرجع المُهلة المُجدولة على نفس الخارطة المشتركة (Shared Map). (من المثير للاهتمام أنه إذا اكتشفت لغة Go عملية قراءة/كتابة متزامنة على نفس كائن الخارطة، فسترمي خطأ مُميت - يمكنك تشغيل مثال حي لكاشف سباق البيانات). يؤدي هذا في النهاية إلى فقدان مرجع المُهلة، ويجعل من المستحيل إلغاء المُهلة المحددة. تذكر دائمًا استخدام الأقفال عند الحاجة إليها. فقدان عمليات التحقق من الحالة يلزم التحقق من الحالة في المواقف الّتي لا يمكنك فيها الاعتماد فقط على حصرية القفل. موقفنا مختلف قليلًا، لكن الفكرة الأساسية مشابهة تمامًا لمتغيرات الحالة. تخيل موقفًا كلاسيكيًا حيث يكون لديك مُنتج واحد والعديد من المستهلكين يعملون في قائمة انتظار مشتركة. يمكن للمُنتج إضافة عنصر واحد لقائمة الانتظار وإيقاظ جميع المستهلكين. تعني عملية الاستيقاظ للمستهلكين بأن هنالك بعض البيانات المتاحة في قائمة الانتظار، ولأن قائمة الانتظار مشتركة، يجب مزامنة الوصول لها من خلال قفل. كلّ مستهلك لديه فرصة للاستيلاء على هذا القفل. ومع ذلك، لا يزال الحلّ غير كامل ومازلنا بحاجة للتحقق إن كان هناك عناصر في قائمة الانتظار. يلزم التحقق من الحالة لأنك لا تعرف حالة قائمة الانتظار في الوقت الّذي تمسك القفل فيه. في مثالنا، تلقى مُعالج المُهلة استدعاء الاستيقاظ (لفك حالة السُبات) من مؤقت منتهية مُهلته الزمنية، ولكنه لا يزال بحاجة للتحقق من أن إشارة الإلغاء قد أرسلت إليه بالفعل قبل أن يتابع تنفيذ رد النداء. مشكلة القفل المستعصي تحدث هذه المشكلة عندما يكون هنالك خيط ما عالقًا، ويدخل في مرحلة انتظار غير منتهية للإشارة المعنية بإيقاظه، ولكن هذه الإشارة لن تصل أبدًا. وهذا بدوره يمكن أن يقضي على تطبيقك بالكامل عن طريق إيقاف تنفيذ البرنامج بالكامل. في مثالنا، حدث ذلك بسبب استدعاءات عمليات الإرسال المتعددة لقناة غير مفعل بها ميزة التخزين المؤقت. وهذا يعني أن استدعاء الإرسال لن تعود إلا بعد نجاح العملية واستلامها التنفيذ من نفس القناة. كانت حلقة المُهل للخيوط الخاصة بنا تستقبل على الفور إشارات على قناة الإلغاء؛ ومع ذلك، بعد تلقي الإشارة الأولى، سنخرج من الحلقة ولن نستطيع الاستقبال من هذه القناة مرة أخرى. والاستدعاءات المتبقية عالقة إلى الأبد. لتجنب هذا الموقف، تحتاج للتفكير بعناية بطريقة استخدام القنوات في شيفرتك البرمجية، والتعامل مع استدعاءات الحجب بحذر، وضمان عدم حدوث مجاعة لأي خيط (انتظاره إشارة معينة للأبد). وكان الحلّ في مثالنا هو بجعل استدعاءات الإلغاء غير مؤدية للحجب - إذ لم نحتاج لاستدعاءات الحجب في حالتنا. ترجمة -وبتصرف- للمقال Lessons learned from programming in Go لكاتبه Eduardo Ferreira
  4. المنهجية الأكثر منطقية لتنسيق شيفرة ملفات CSS وSASS المصطلحات التصريح عن قاعدة التصريح عن قاعدة (rule declaration): هو الاسم المختار لمحدّد معين (أو لمجموعة من المحددات) مع مجموعة من الخاصيات المصاحبة. إليك مثالًا لتوضيح الأمر: .listing { font-size: 18px; line-height: 1.2; } المحددات إن المحددات التي رأينها عند التصريح عن قاعدة، هي الجزء الّذي سيُحدد طريقة تنسيق العناصر في شجرة DOM، وذلك بحسب الخاصيات المعرّفة في المحدّد. يمكن أن تُطابقُ المحددات عناصر HTML، أو صنف العنصر (class)، أو معرّف العنصر (ID)، أو أي سِمة من سماته. وهذه بعض الأمثلة عن المحدّدات: .my-element-class { /* ... */ } [aria-hidden] { /* ... */ } الخاصيات أخيرًا، الخاصيات هي ما يمنح العناصر المحددة تنسيقها والتي صرحنا عنها في المحدد. والخاصيات هي أزواج مؤلفة من الخاصية وقيمتها، ويمكن للقاعدة المصرح عنها أن تحتوي على تعريف خاصية أو أكثر. وهكذا ستبدو طريقة التصريح عن الخاصيات: /* بعض المحددات */ { background: #f1f1f1; color: #333; } ملفات CSS التنسيق استخدم الزر (tabs) بمقدار مسافتين (وتسمى أيضًا Soft-Tab نظرًا لأن زر Tab الإفتراضي يكون ثمان مسافات). يفضل استخدام الشرطة العادية (وهي -) بدل تسمية الأصناف بأسلوب سنام الجمل (camelCasing). لا بأس باستخدام الشرطات السفلية والتسمية بأسلوب PascalCasing (وهي طريقة مشابهة لطريقة سنام الجمل إلا أنه يجب أن يكون أول حرف كبير) إن كنت تستخدم BEM ( والّتي سنتطرق إليها لاحقًا في هذا الدليل). لا تستخدم مُحدِّدات المُعرِّفات (ID). عند استخدام محددات متعددة في تصريح واحد لقاعدة ما، امنح كل مُحدّد سطر خاص به. ضع مسافة قبل قوس الافتتاح { عند التصريح عن قاعدة. ضع مسافة بعد : وليس قبله في الخاصيات. ضع أقواس الإغلاق } عند التصريح عن قاعدة في سطر جديد. ضع أسطر فارغة بين تصريحات القواعد. طريقة تنسيق سيئة .avatar{ border-radius:50%; border:2px solid white; } .no, .nope, .not_good { // ... } #lol-no { // ... } طريقة تنسيق جيدة .avatar { border-radius: 50%; border: 2px solid white; } .one, .selector, .per-line { // ... } التعليقات يفضلُ استخدام التعليقات السطرية (وهي // في Sass-land) للتعليقات الكتلية. يفضلُ أن تضع التعليق بسطر خاص به. تجنب التعليقات في نهاية السطر. اكتب تعليقات تفصيلية للشيفرة البرمجية التي لا تشرح نفسها بنفسها: استخدام الخاصية z-index. استخدام المميزات التوافقية أو بعض الخدع المخصصة للمتصفحات. OOCSS و BEM نشجع على استخدام مزيج من OOCSS و BEM وذلك للأسباب التالية: يساعدنا هذا المزيج في إنشاء علاقات واضحة وصارمة بين ملفات التنسيق CSS وملفات HTML. ينشئ مكونات قابلة لإعادة الاستخدام والتركيب. يسمح بتقليل التداخل والتخصيص. يساعد في زيادة قابلية تطوير ملفات التنسيق. OOCSS (اختصارًا "Object Oriented CSS") وهي التنسيق كائني التوجه لملفات التنسيق، هو نهج لكتابة تنسيق CSS يشجعك على التفكير بملفات التنسيق على أنها مجموعة من "الكائنات": أي أنها قابلة لإعادة استخدام أجزاءٍ منها، وقابلة للتكرار، ويمكن استخدامها بشكل مستقل عبر موقع الوِب. لمزيد من المعلومات يمكنك الاطلاع على: توثيق نيكول سوليفان (Nicole Sullivan's)‏ OOCSS wiki. مقال مدخل إلى OOCSS‏ (Introduction to OOCSS). BEM (اختصارًا Block-Element-Modifier) معدلّ عنصر الكتلة وهو عبارة عن اصطلاح تسمية للأصناف في HTML و CSS. طوّر في الأصل من خلال شركة Yandex ووضعوا في حسبانهم الشيفرات البرمجية الكبيرة وقابلية التطوّر والتوسع للشيفرة، ويمكن اعتبارها بمثابة مجموعة قوية من المبادئ التوجيهية لتطبيق OOCSS. لمزيد من المعلومات يمكنك الاطلاع على: خدع CSS دليلك إلى منهجية BEM - CSS مدخل إلى BEM‏ (introduction to BEM). نوصي بالتنويع بأشكال BEM مع "كتل" مسماة بأسلوب PascalCased، والّتي تعمل بطريقة جيدة خصيصًا عند دمجها مع المكونات (مثلما يحدث في React). لا تزال تُستخدم الشُرط السفلية والشرطات للمعدلات وسلالتهم (من سيرثُ منهم). مثال // ListingCard.jsx function ListingCard() { return ( <article class="ListingCard ListingCard--featured"> <h1 class="ListingCard__title">Adorable 2BR in the sunny Mission</h1> <div class="ListingCard__content"> <p>Vestibulum id ligula porta felis euismod semper.</p> </div> </article> ); } /* ListingCard.css */ .ListingCard { } .ListingCard--featured { } .ListingCard__title { } .ListingCard__content { } ‎.ListingCard: وهي عبارة عن "كتلة" وتمثل مكون عالي المستوى. ‎.ListingCard__title: عبارة عن "عنصر" وتمثل سلالة ‎.ListingCard التي تساعد في تكوين الكتلة ككلّ. ‎.ListingCard--featured: وهو عبارة عن "معدلّ" ويمثل الحالات أو التشكيلات المتختلفة لكتلة ‎.ListingCard. محددات المعرفات في حين أنه من الممكن تحديد العناصر حسب المعرّف في CSS، إلا أن هذه المحددات تعدّ أسلوبًا مضادًا للنمط (anti-pattern). تقدم محدّدات المعرّفات مستوى عاليًا من التخصيص غير ضروري للتصريح عن قاعدة، بل ولن يمكننا إعادة استخدام هذه المحدّدات. لمزيد من المعلومات حول هذا الموضوع، أحيلك لهذه المقالة CSS Wizardry's article والّتي تتحدث عن طريقة التعامل مع التخصيص. خطاف الجافاسكربت تجنب ربط نفس الصنف في كلّ من ملفات التنسيق CSS والجافاسكربت. لأنه غالبًا ما سيُؤدي لخلط الاثنين معًا، وبأحسن الأحوال سيؤدي ذلك لإضاعة الوقت أثناء إعادة البناء عندما يتعين على المطوّر العودة لكلّ صنف يغيره، وفي أسوأ الأحوال، سيخشى المطوّرون إجراء تعديلات عليها خوفًا من كسر الوظيفة ما المرتبطة بها. نوصي بإنشاء أصناف مخصصة للربط مع جافاسكربت مسبوقة بـ ‎.js-‎: الحدود استخدم 0 بدلًا من none لتحديد أن النمط ليس له حدود. الطريقة السيئة .foo { border: none; } الطريقة الجيدة .foo { border: 0; } ملفات SASS الصياغة استخدم الصيغة ‎.scss، ولا تستخدم أبدًا الصيغة ‎.sass الأصلي رتب شيفرة ملفات CSS العادية وعمليات التضمين ‎@include بطريقة منطقي (انظر أدناه) ترتيب طريقة التصريح عن الخاصيات التصريح عن خاصية أدرج جميع التصاريح القياسية للخاصيات، وأي شيء آخر ما عدا عمليات التضمين ‎@include أو المحددات المتشعّية. .btn-green { background: green; font-weight: bold; // ... } تصريح عن عملية تضمين ‎@include إن تجميع ووضع جميع عمليات التضمين ‎@include في نهاية المحدّد سيسهل قراءة المحدد بالكامل. .btn-green { background: green; font-weight: bold; @include transition(background 0.5s ease); // ... } المحددات المتشعّبة يكون ترتيب المحددات المتشعّبة ( إن اضطررنا لاستخدامها) بعد عمليات التضمين ولا شيء بعدها. أضف مسافة بين عمليات التصريح عن القواعد والمحددات المتشعّبة، وكذلك بين المحددات المتشعّبة المتجاورة. طبّق نفس الإرشادات المذكورة سابقًا على المحددات المتشعّبة الخاصة بك. .btn { background: green; font-weight: bold; @include transition(background 0.5s ease); .icon { margin-right: 10px; } } المتغيرات يفضل استخدام أسماء المتغيرات التي تحتوي على شرطة عادية (مثل: ‎$my-variable) بدلًا من أسماء متغيرات مثل أسلوب تسمية سنام الجمل (camelCased) -تكبير أول حرف من كلّ كلمة في اسم المتغير عدا أول كلمة- أو أسلوب snake_cased -جميع حروف اسم المتغير صغيرة-. لا مشكلة بإضافة شرطة سفلية لأسماء المتغيرات الّتي نود استخدامها فقط داخل نفس الملف(هكذا: ‎$_my-variable). المخاليط يجب استخدام المخاليط (mixins) لتصغير شيفرتك البرمجية، أو لتوضيحها، أو لعزل تعقيدها - بطريقة مشابهة تمامًا للدوالّ المسماة جيدًا. يمكن للمخاليط الّتي لا تقبل أي وسطاء أن تكون مفيدة لذلك، ولكن انتبه فأذا لم تستخدم خوارزميات ضغط للملفات المشروع (مثل خوارزمية gzip)، فسيُساهم ذلك في تكرار الشيفرات البرمجية غير الضرورية في التنسيقات الناتجة. توسعة المحدّدات المُركّبة يجب تجنب التوسعة باستخدام التعليمة ‎@extend لأنه يسلك سلوك غير معروف للبعض وغالبًا ما يكون خطير، خاصة عند استخدامه مع محددات متشعّبة. حتى إن توسيع محددات العناصر الأساسية عالية المستوى يمكن أن يسبب مشاكل إذا انتهى الأمر بتغيير ترتيب المحددات في وقت لاحق (فمثلًا إذا كانت هذه المحددات في ملفات أخرى، وتغير ترتيب تحميل الملفات فهذا سيُشكل مشكلة). يجب أن تتعامل خوارزمية الضغط Gzipping مع عمليات تصغير أحجام الملفات الّتي ستحصلُ عليها باستخدام ‎@extend، وستمنحُك المخاليط تصغيرًا جيدًا لملفات التنسيق خاصتك. المحددات المتشعّبة ** لا تنشئ محددات متشعّبة بعمق يزيد عن ثلاثة مستويات!** .page-container { .content { .profile { // STOP! } } } عندما تصبح المحددات طويلة، من المحتمل أنك تضطر أن لتكتب تنسيق لديه المميزات التالية: مقترن بشدة بملفات HTML (وهذا يعدّ نقطة ضعف في التنسيق) -أو محدد للغاية (وهذا يعدّ نقطة قوة في التنسيق) -أو غير قابل لإعادة الاستخدام. مرة أخرى: لا تستخدم نهائيًا محددات المعرّفات المتشعبة! في حال وجب عليك استخدام محدّد المعرّف في البداية (ويجب أن تحاول بأقصى جهدك أن تتجنبه)، فلا يجب أن تكون متشعّبة أبدًا. وإن وقعت بهذه المشكلة، فعاود النظر في الشيفرة البرمجية أو أسأل نفسك لما كلّ هذا التخصيص الشديد؟ وإن أردت كتابة ملفات HTML وCSS ذات بنية جيدة، فيجب عليك ألا تستخدم محدّدات المعرّفات المتشعبة نهائيًا. ترجمة -وبتصرف- لدليل Airbnb لتنسيق ملفات CSS وSASS‏ (Airbnb CSS / Sass Styleguide) الموجود على موقع GitHub
  5. أثناء عملي مطورًا لووردبريس كنت أرى أن منصة سكويرسبيس (Squarespace) كالإعصار القوي الّذي سيدمر حياتي المهنية بالكامل، لقد كان شيئًا مجهولًا تمامًا بالنسبة لي ولا أدري هل سيجعل حياتي أفضل؟ أم أنه سيزيدها تعقدًا؟ لطالما كان هذا السؤال يراودني كثيرًا ولم أجد له إجابة تشفي صدري إلا عندما جربته بنفسي. النظرة الأولى لسكويرسبيس أتذكر ذلك الشعور تمامًا عندما أرى إعلانًا لمنصة سكويرسبيس وذلك عندما أطفئ حاجب الإعلانات (Ad blocker) على المتصفح أو عندما أجلس أمام التلفاز أثناء فقرة الإعلانات التجارية، وكثيرًا ما كان يراودني شعورًا بأن هذه المنصة تكبر يومًا بعد يوم وتزداد شعبيتها وخصيصًا خلال الأشهر الستة الماضية. وكلما أرى أحد المواقع ذو التصميم الجميل، أبدأ مثل العادة بتصفح الشيفرة البرمجية له فأتفاجئ بوجود جملة في أعلى الصفحة تقول صُمم هذا الموقع بواسطة سكويرسبيس (<‎!-- This is Squarespace. --‎>). أذكر أن أول مرة أرى فيها موقعًا مبنيًا بالسكويرسبيس هي عندما فتحت موقع الموسيقار المفضل لدي براد ميلداو وكان ذلك منذ حوالي أربع سنوات، وبعدها بدأت عجلة انتشاره تتسارع بقوة لذا قررت بأن استطلع تلك المنصة وأرى سبب انتشارها، وبالفعل بدأت باكتشافها وبنيت موقعًا تجريبيًا لاعرف أبرز مميزاتها وخمن كيف وجدتها؟ نعم، وجدتها جيدة جدًا جدًا بل وحتى أفضل من ووردبريس (في بعض الوظائف الّتي سنأتي على ذكرها لاحقًا في هذا المقال). سأتحدث في هذا المقال عن تجربتي في منصة سكويرسبيس وليكون ذلك دليلًا لمعرفة الفروقات بينها وبين ووردبريس من وجهة نظري الشخصية. ملاحظة: سأتحدث في هذا المقال عن سكويرسبيس فقط دون التطرق إلى منصتي ويبلي (Weebly) أو ويكس (Wix) لماذا؟ ببساطة، ﻷني لم أجد موقعًا من المواقع المصممة بعناية (من وجهة نظري) مبنية على هذه المنصات، بينما وجدت الكثير والكثير من المواقع الرائعة المبنية بالسكويرسبيس. إذا كنت تعتقد بأن إحدى هاتين المنصتين أفضل من سكويرسبيس أو كان لك رأيٌ أخر لطفًا أخبرنا به في التعليقات. التجربة الأولى لمنصة سكويرسبيس لطالما كان التأمل شغفي وهوايتي في الحياة، ولطالما أردت أن أتخذها كمهنة لي وأبدأ بتدريب الناس عليها ولقد بنيت بالفعل علامتي التجارية بهذه المهنة (والّتي بنيتها بناءً سيئًا للأسف)، وبما أني عندما بدأت مهنتي كمطور ووردبريس إن أول موقعًا تجريبيًا بنيته هو علامتي التجارية للتدريب على التأمل، لذا قررت أن أبدأ مسيرتي مع سكويرسبيس بنفس الأسلوب ﻷجرب هذه المنصة. كتبت بعض المتطلبات الرئيسية التي سأحتاجها في الموقع وهي كاﻵتي: استخدام شعار مخصص للموقع. استخدام خط مخصص (نفس الموجود في الشعار). شرح نظام التأمل في الموقع. تقديم كتاب إلكتروني هديةً للزوار عند اشتراكهم في القائمة البريدية. حجز المواعيد من خلال الموقع. مدونة خاصة بالموقع. النتائج التي حصلت عليها لتنفيذ النقاط المذكورة باستخدام منصة سكويرسبيس تطلب مني العمل لمدة 3 ساعات لإنهاء الموقع التجريبي بالكامل (الموقع لم يعد متاحًا بسبب انتهاء الفترة التجريبية للموقع والّتي هي 14 يوم فقط)، ولكني التقطت بعض الصور له لعرضه في هذا المقال. منصة سكويرسبيس: منصة ووردبريس: سأتحدث في بقية المقال عن تجربتي في بناء موقع باستخدام سكويرسبيس وما الأدوات المساعدة المضمنة في هذه المنصة والمشابهة للأدوات الموجودة في ووردبريس من أجل تكوين فكرة واضحة عن هذه المنصة لمطوري ووردبريس ولمجتمع ووردبريس بالكامل. ووردبريس مقابل سكويرسبيس (لعبة تركيب القطع مقابل لعبة تلوين الكتب) كلما أتذكر مدى سهولة بناء موقع بالسكويرسبيس أول شيء يخطر ببالي هو لعبة تلوين الكتب إذ كلّ ما عليك فعله في هذه اللعبة هو تلوين الرسومات والأشكال المرسومة مسبقًا. وبالمقابل إن تجربة بناء موقع باستخدام ووردبريس أشبه ما تكون بتجربة لعبة تركيب القطع. إذ يكون لديك جميع الأشكال والقطع الجاهزة وكلّ ما عليك فعله هو تركيب هذه القطع مع بعضها بعضًا ليصبح لديك الشكل النهائي الّذي بنيته. ووردبريس ولعبة تركيب القطع لدينا في لعبة تركيب القطع المئات من القطع الصغيرة لتركيب مختلف الأشكال، إذ يمكنك بناء أي شكلٍ تريده بهذه القطع، ولكن يجب عليك قبل البدء في البناء أن تعرف تمامًا ما الّذي ستبنيه (وفي الحقيقة هذه الخطوة مشتركة في جميع أُطر العمل البرمجية [Framework]) أيضًا. إذ يكون لديك جميع المكتبات والحزم الجاهزة ولكن قبل أن تبدأ ببناء البرنامج أو الموقع يجب عليك معرفة ما المكتبات الّتي ستستخدمها) وهذا مشابه تمامًا لكيفية بناء موقع بالووردبريس. لدى ووردبريس مزايا عديدة مثل وراثة القوالب الّتي تجعل من عملية إنشاء الموقع عملية سهلة للغاية مثل سهولة بناء سيارة في لعبة تركيب القطع عندما يكون لديك قطع على شكل عجلات. لكن هنالك منعطف تعليمي حاد في هذه النقطة، فإذا أردت أن تبني أفعوانية (وهي نموذج مصغّر لسكة حديدية، مرتفعة عن الأرض، وملتوية صعودًا وهبوطًا) كبيرة تملأ الغرفة بأكملها سيتعين عليك أولًا أن تخطط جيدًا لبنائها وتبنيها تدريجيًا إنطلاقًا من الأساسات وحتى أخر قطعة في السفينة، وغالبًا ما ستحتاج أيضًا لتعلم قدرٍ لا بأس به من الهندسة الإنشائية لتحقيق ذلك. لذا إن وضعنا لعبة تركيب القطع في أيدي أحد الخبراء الماهرين الّذين يعلمون تمامًا كيفية بناء الكتل والهياكل فعندها حتمًا ستبهرك الأشكال الّتي سيبنونها. هذا هو شعور أي مطور ووردبريس عندما يلقي نظرةً على سكويرسبيس. سكويرسبيس وكتب التلوين في الحقيقة إن كتب التلوين رائعة حقًا، ولقد شهدت منذ فترة قريبة إقبالًا جنونيًا عليها من قِبل المراهقين وحققت مبيعات كبيرة آنذاك. ويعود سبب جماليتها أنها تعطينا ميزتين أساسيتين وهما: السيطرة بالطريقة الّتي نريدها. هيكل جميل يشعرنا بأننا نمتلك قوى تصميم خارقة. يمكن من خلال كتب التلوين أن تقرر اللون الّذي سيكون عليه قميص المرأة في شارع باريس وما إذا كان يومًا صافيًا أو ضبابيًا. لذا ستشعر بالسيطرة الكاملة وتشعر بأن المشروع جزءًا من إبداعك فنّك. وفي نهاية المشروع ستجلس وتتأمل مدى جمالية اللوحة الّتي رسمتها. لقد رسمت منظرًا كاملًا لشارع باريس ويبدو رائعًا! والّذي كان من المستحيل رسمه بمفردك. هذا هو بالضبط ما ستشعر به مع منصة سكويرسبيس إذ يفرض عليك تصميمًا جيدًا للغاية عبارة عن شبكة تخطيط للصفحة مؤلفة من 12 عمود وخيارات كتابة رائعة وتخطيطات متنوعة والّتي يمكنك من فعل أشياء رائعة باستخدامها. ولكن لبناء مشهدٍ جميلٍ يستحق المشاهدة يجب عليك اتخاذ قرارات مدروسة بالخيارات المتاحة أمامك. الرسمة موجودة، والمشهد يشبه باريس تمامًا، وإذا أردت أن تفسد الأمر بتلوينك لبرج إيفل باللون الزهري أو أن تخربش على وجه المرأة باللون الذهبي يمكنك ذلك، ولكن إذا ركزت في خياراتك والتزمت الحيطة والحذر ستبني مشهدًا باريسيًا بامتياز. إن العمل مع منصة سكويرسبيس حقًا مريح جدًا. مثل لعبة تلوين الكتب، شيئًا فشيئًا أحسست بأني أترك اتخاذ القرارات لمنصة سكويرسبيس بدلًا عني وحتى تلك القرارات الّتي لم أكُ على استعداد لتركها لمنصة ووردبريس. هل أرغب بوجود بطة على البركة بدلًا من البجعة؟ أيًا كان، فلربما البجعة أجمل من البطة وبكل تأكيد هي أجمل من أي بطة سأحاول رسمها بنفسي. إذًا لنلوّن البِركة باللّون الأزرق ومنقار البجعة باللون البرتقالي ولننتقل لبقية التفاصيل. هل أنا قلق قليلًا بأن معظم محتوى صفحتي الرئيسية هو في الواقع في وسوم H3؟ في الحقيقة نعم، ولكنني لا اعتقد بأنها مسألة مهمةٌ لمحركات البحث وإنه لمن الممتع حقًا أن أبني موقعًا كاملًا باستخدام الواجهات الأمامية بدون أن أزعج نفسي بالذهاب إلى ملفات تنسيقات CSS وأصلحها. هل أريد أن استخدم صور مجانية؟ أو أن استخدم متجر صور جيتي (Getty) الرائع والمتكامل بشكل سلس مع منصة سكويرسبيس؟ صراحةً، لا أعلم ولكن عن نفسي أعتقد بأن مكتبة جيتي جميلة حقًا. لذا إن كنت تتطلع لشيء بسيط (مثل رسم مدينة) ومقنع ووجدت هذه الرسمة موجودة في كتاب تلوين كلّ ما عليك فعله في ذلك الوقت هو تلوينها. يمكنك مزج عدة ألوان للحصول على نتائج رائعة بإبداعك الشخصي ومع البنية المريحة لمنصة سكويرسبيس ستنتج العديد من القرارات الجيدة. هذا هو وعد سكويرسبيس وبالفعل هذا ما شعرتُ به عندما أنشاء الموقع التجريبي إذ لم أكُ أرغب بالتوقف عن التلوين. بعض التفاصيل حول استخدام سكويرسبيس هذه بعض النقاط من وجهة نظري عند العمل على مشروع مبني من خلال منصة سكويرسبيس. استخدام سكويرسبيس أرخص من ووردبريس إن استخدام منصة سكويرسبيس أرخص بكافة السيناريوهات من منصة ووردبريس في حال استخدمت النسخة الرسمية المحمولة وتُخصصها بنفسك وتستخدم قوالب مدفوعة وإضافات مساعدة …إلخ، بل إن كلّ ما ستدفعه في سكويرسبيس سيكون مقابل سعر الاستضافة في ووردبريس، إذ أن أسعار سكويرسبيس تبلغ 12 دولار أمريكي للخطة الشخصية و 18 دولار أمريكي شهريًا للخطة الإحترافية تكون أغلى قليلًا من السعر الّذي تدفعه مقابل الاستضافة المشتركة الجيدة. إلا أن سعر القالب المدفوع للوردبريس ومع بعض الإضافات المدفوعة الأخرى، ربما سيكون أغلى. وأضف أجر ساعات العمل لمطور ووردبريس الّذي ستستأجره عندها وبكل تأكيد سيكون ووردبريس أغلى بكثير من سكويرسبيس. تجربة المستخدم الرائعة عمومًا، يعدّ سكويرسبيس أعجوبة من ناحية تصميم واجهة المستخدم/تجربة المستخدم (UI/UX). وفي محاولتي لبناء موقع باستخدامه واجهتني بعض المتاعب، ولكن هذه المتاعب لا شيء عندما أرى بأني أنشأت موقعًا كاملًا والّذي أعتقد بأنه رائع، ودون أيّ تدريب رسمي سابق على هذه المنصة، وفقط خلال 3 ساعات. وحتى أني وجدت العديد من الحلول البديلة للمتاعب الّتي واجهتني ببعض البحث والتدقيق في هذه المنصة. أحببت طريقة منع المستخدم من تغيير قياس عرض العناصر تغييرًا عشوائيًا وإنما تقدم مقاساتٍ جاهزة مختلفة الأحجام لوضعها في الصفحة والّتي تكون مؤلفة من شبكة 12 عمودًا. وهذا يؤدي لمنع قياسات العرض السيئة مثل 701.4 بكسل، وتقدم تجربة جميلة على الأجهزة المحمولة دون أن يضطر المستخدم للتفكير بالأحجام المتناسقة لعرض العناصر. كما أحب قرارات التخطيط الجيدة جدًا الّتي يتخذها القالب مثل زيادة مقاس عرض الصفحة إذا كانت هناك عناصر متعددة جنبًا إلى جنب، أو إنشاء عمود مركزي واحد ضيّق إذا كان هناك عنصر واحد فقط. وأحب أيضًا تجربة التحرير ونشر المحتوى في سكويرسبيس. لطالما كنت متلهفًا إلى محرر ووردبريس لفترة طويلة: بالنسبة لي، فإن الكتابة على منصة سكويرسبيس تشعرني بقدر كبير من الاختلاف، كالفرق بين الحماسة والإكتئاب. وفي الحقيقة كتبت هذه المقالة على أنها منشور في مدونة سكويرسبيس فقط لاستخدام المحرر الخاص بالسكويرسبيس، على الرغم من أنه لا يحتوي على وسوم h4 ونظام تحديد النص كشيفرة برمجية معطل (أُصلحت هذه المشكلة في تحديثات المنصة) إلا أنه يقدم تجربةً جيدة جدًا. وأحب محرر الصور أيضًا، الّذي يمتلك طريقة جميلة للتلاعب بحجم الصور، وكما ستشعر بأن مدير الوسائط في سكويرسبيس أسرع قليلًا من مدير الوسائط في ووردبريس، والّذي اعتقد بأنه الشيء اللطيف حول كون الشيفرة البرمجية مغلقة المصدر هو أن الشركة تكون المسؤولة عن تحسينها أو ربما الشيء الجميل في كون الشركة ذات المليار الدولار هي الشركة المستضيفة للموقع، أو الأمرين معًا. إن التكاملية الرائعة مع تطبيقات الطرف الثالث مثل منشئي النماذج (Form Creator)، وخرائط غوغل، وخدمة البريد الإلكتروني MailChimp، وحتى خدمة الحجز Acuity Scheduling -والّتي لا تملك الكثير من المميزات- ولكنها تعمل عملًا جميلًا وسهلًا على الحالات البسيطة مثل الموقع الّذي كنت أجرب عليه. وبالإضافة إلى ذلك أنه لا يمكنني عرض جدولة المقدمة من هذه الإضافة إلا بخط Arial، ولا يمكنني إعادة تصميمه لأنه إطار iframe مضمن. ولا أعتقد أن دمج خدمة البريد الإلكتروني MailChimp تتيح لي القيام بجميع الأمور الّتي كنت أتطلع لها. إلا أني ومع ذلك، ما زلت أشعر بأنني مستعد لتقديم هذه التضحيات الصغيرة من أجل الراحة الشاملة للتكاملات الصغيرة الّتي تعمل بشكل جميل. لمَّا كنت مطورًا معتادًا على كتابة الشيفرات البرمجية لأفعل بالضبط ما أريده، فقد يعتريني العجز أحيانًا عند العمل مع منشئ صفحات مثل عندما يضع فراغات بين العناصر والّذي عادةً ما أفضل جعله كهوامش علوية، وجعل معظم النص الخاص بي في وسم h3 عوضًا عن التصميم الافتراضي للنص، وهكذا من الخيارات. ولكن مع ذلك، لم أشعر أن أيّ من هذه التنازلات ارتفعت إلى مستوى أن تكون منصة سكويرسبيس "كومة من القمامة". الأخطاء في منصة سكويرسبيس إن منصة سكويرسبيس ليست تجربة نموذجية بالكامل بل هنالك بعض والأخطاء ومن أكثرها خطورة برأيي هي واجهة السحب والإفلات: الخطأ الأكثر أهمية هو أن النقر المستمر على عنصر قابل للسحب، ثمّ محاولة تمريره للأعلى أو للأسفل، يؤدي إلى التمرير اللانهائي. هذا الخطأ مزعج بشكل لا يصدق ويكاد يكون خرقًا كبيرًا في واجهة المستخدم. يتمثل الحل البديل في إزاحة أي عنصر تريد تحريكه قطعة تلو الأخرى للأعلى أو للأسفل، مثل تسلق جبل بيد واحدة في وقت واحد. كما هو الحال مع العديد من حلول السحب والإفلات (مثل عرض قائمة التخصيص في الووردبريس)، من الممكن الحصول على أمور عكسية عند وضع العناصر الّتي تريدها بمكان معين، خاصة بجوار أو أسفل بعضها البعض. لا يوجد خيار التراجع عن التغييرات. لنفترض أنك حصلت على مجموعة منسقة تنسيقًا جيدًا من النصوص والصور، وسحبت صورةً واحدةً وأفلتها خطأً فوق عنوان الصفحة، مما تسبب في ارتفاعها إلى 1500 بكسل ومفسدًا بذلك عرض كلّ المخططات على الصفحة؛ لا يمكنك في هذه الحالة التراجع عن ذلك. لم أعمل مطلقًا في أداة إنشاء صفحات من قبل، لكن يبدو أن هذا خطأ فادحًا ولا مفر منه. هناك بعض الحيل لتجاوز هذه المشاكل مثل حفظ التغييرات من وقت لآخر، ولكن لا تظهر التحديثات لم تظهر حتى تحميل صفحة أو صفحتين في وقت لاحق، مما يخلق قدرًا لا بأس به من التشويش. وهناك مشكلة مزعجة أخرى، لنقل أن لدينا عناصر h2 ونصًا عاديًا تحتها فهنا لن يظهر هذا التنسيق إلا عندما نحول العناصر h2 إلى نص عادي أو نحول النص الّذي تحت h2 إلى تنسيق h2 أيضًا. ومع ذلك، لم أجد مشكلة تمنعني بشكل دائم في مساراتي. وعمومًا، كان البناء باستخدام سكويرسبيس ممتعًا مثل بعض التجارب الأخرى الّتي جربتها على الوِب. لقد وجدت نفسي أمضي وقتًا في الموقع التجريبي أكثر مما كنت أنوي فعله، فقط لمعرفة ما إذا كان سكويرسبيس قادرًا عليه. خلاصة الأمر في استخدام منصة سكويرسبيس بالنسبة لي، فإن الفائدة الأساسية لاستخدام سكويرسبيس هي أنني بنيت موقع تجريبي بالكامل في 3 ساعات فقط ودون أي تدريب مسبق والّذي يعمل بشكل رائع ويبدو شكله أفضل بكثير من الموقع الّذي كنت سأبنيه في 8 إلى 15 ساعة مع ووردبريس والّذي يبدو أفضل بكثير من أي موقع يمكن أن أصممه بمفردي. أشعر بالسعادة والراحة لتغيير نظام التخطيط والتصميم وإدارة المحتوى بسهولة تامة وحتى مواصلة إنشاء الموقع من هنا. فإذا أردت بأيّ وقتٍ من الأوقات أن أطلق موقعًا بعد اختباره اختبارًا شموليًا، فسأطلق وبدون أدنى شك الإصدار الأول من الموقع المبني على سكويرسبيس. الاستنتاجات العامة والآثار المترتبة عليها بناء موقع مع سكويرسبيس كان مثيرًا للغاية. لقد خرجت بالكثير من الأفكار حول المستقبل المحتمل لبناء المواقع و نظم إدارة المحتوى، وكيف يمكننا في مجتمع ووردبريس أن نضع أنفسنا في أفضل مكان لذلك المستقبل. فيما يلي المسارات الرئيسية الّتي أعتقد أنها مفيدة لاستكشافها. تكاملية القوالب مع الإضافات مع منشئي الصفحات يسعى معظم الناس لوجود هذه التكاملية في نظام إدارة المحتوى وباعتقادي إن موقع ووردبريس التجريبي الّذي بنيته لم يحقق هذا المطلب لعدم وجود منشئ صفحات جيد. لماذا لم يكُ موقع ووردبريس جاهزًا للنشر على عكس موقع المبني بالسكويرسبيس؟ بالعودة للوراء والنظر إلى التفاصيل أجد بأن السبب الرئيسي هو عدم وجود منشئ صفحات جيد يسرّع من عملية بناء الموقع تسريعًا كبيرًا من خلال إنشاء مخططات للصفحات الّتي أريدها. لطالما كرهت منشئي الصفحات والّتي أصبحت في هذه الأيام من الأشياء الأساسية في أي قالب ومن أكثر منشئي الصفحات شهرة هما Divi و Visual Composer اللذان يشكلان السبب الرئيسي لسوء مشاريع ووردبريس أكثر من أي شيء آخر. ولكن منذ فترة قريبة بدأت ألاحظ بأني لا أكره فعليًا منشئي الصفحات بشكل عام وإنما أكره منشئي الصفحات السيئين. في الحقيقة إن أكثر الأماكن الّتي أمضي بها وقتي عند العمل عليها في منصة ووردبريس هي تخطيط الصفحات إذ أني دائمًا ما أريد أن أنشئ تخطيطًا لصفحةٍ ما بدون كتابة شيفرة برمجية معقدة، وهذا السبب الرئيسي لوجود منشئي الصفحات ألا وهو حل مشكلة تخطيط الصفحات. عندما أعمل على منشئ صفحات جيد أرى تمامًا ما فاتني من فائدة وتسهيلٍ لعملي ولوقتي عن طريق بناء صفحات كاملة بدون كتابة أي شيفرة برمجية. في المشاريع الأخير الّتي عملت عليها استخدمت منشئ الصفحات Beaver والّذي ساعدني كثيرًا في إدراك ذلك وأعطاني نفس الشعور الّذي أحسست به عندما استخدمت منشئ الصفحات في سكويرسبيس. دعنا نلق نظرة لماذا منشئ الصفحات في ووردبريس سيء جدًا بالموازنة مع منشئ الصفحات في سكويرسبيس. يمتلك منشئ الصفحات في سكويرسبيس: مجموعة صغيرة من القوالب الجميلة والمصممة بعناية وذات تنسيق جيد جدًا. مجموعة صغيرة من تطبيقات الطرف الثالث والمتكاملة مع بعضها بعضًا ومع جميع القوالب المتاحة في المنصة. غني بالمميزات ومصمم بعناية وموجود في كلّ قالب بشكل افتراضي ويحتوي على عدد صغير من عناصر المفيدة لإنشاء الصفحات (مثل عناصر لعرض الصور والاقتباسات)، والمتكاملة كليًا مع جميع القوالب وتطبيقات الطرف الثالث. بينما يمتلك منشئ الصفحات في ووردبريس: الكثير من القوالب التجارية الإحترافية ذات الجودة ممتازة المجانية منها والمدفوعة. الكثير من الإضافات المجانية والتجارية ذات الجودة الممتازة. وهنالك العديد من الإضافات زائدة عن الحاجة (مثلًا هنالك العشرات من الإضافات المخصصة لإنشاء النماذج [Forms Builders]، وفي الحقيقة ما يُستخدم منها لا يتعدى الثلاث أو الأربع إضافات). وقد لا تتكامل هذه الإضافة مع الإضافات أو قوالب الأخرى (وينتج عن ذلك مشكلة في الموقع تؤدي لعدم عمل جزء منه أو حتى تعطله بالكامل). الكثير من منشئي الصفحات سواءً المجانية منها أو المدفوعة والّتي تختلف اختلافًا كبيرًا في الجودة، وتأتي إما مع قالبٍ ما أو كإضافة مستقلة. العديد من منشئي الصفحات تجارية بحتة ولا تقدم أي جودة من حيث الشيفرة البرمجية أو التكاملية مع بقية العناصر في الموقع. وحتى منشئي الصفحات ذوي الجودة العالية قد لا يتوافقون مع القالب أو الإضافات المثبتة. وبناءً على ذلك يكون منشئي الصفحات في سكويرسبيس أفضل من ووردبريس لأن منشئ الصفحات في سكويرسبيس متواجد دائمًا وبشكل رئيسي في أي قالب سكويرسبيس، ويعمل بكل سلاسة لمساعدتك على اتخاذ قرارات تصميمة ذكية لتخطيط الصفحات. أما منشئ صفحات ووردبريس وخصوصًا الّذي يأتي على شكل إضافة لا يعلم أي شيء عن هيكلية وبنية القالب (وحتى الأشياء الرئيسية عن بنية القالب)، أو حتى الإضافات الأخرى الّتي تعمل لأنه مهمته ببساطة مساعدتك على تخطيط الصفحة ولكن لا يؤخذ بالحسبان أي اعتبار لمستوى التكاملية مع بقية المكونات في الموقع. ما الّذي جلبه سكويرسبيس إلى عالم ووردبريس إذا أراد ووردبريس أن يبقى مناسبًا لمواقع الوِب الصغيرة (ذات تكلفة أقل من 2000 دولار أمريكي)، فاعتقد أنه سيحتاج إلى بذل جهد كبير لإنشاء مجموعة من قوالب وإضافات متوافقة مع بعضها بعضًا والّتي يمكن لمستخدمي ووردبريس الاختيار من بينها، وكلها متوافقة أيضًا مع منشئ صفحات موحد وكامل الميزات. نظرًا للطلب الكبير على وجود إضافة تمكننا من إنشاء الصفحات تتكامل فعليًا مع قوالب الووردبريس، يستمر السوق بطرح العديد من هذه الحلول ومع تحديث إصداراتها دوريًا. إذ يوجد مئات من المئات من القوالب الموجودة على الثيم فورست (ThemeForest) والّتي تتوافق مع منشئ الصفحات Visual Composer و Divi، وهي فعليًا مجرد إطار عمل للقالب مع منشئ صفحات متكامل خاص بها، وهكذا. مرة أخرى، نظرًا للطلب المرتفع، تعد هذه الحلول أكبر الكيانات الاقتصادية في منصة ووردبريس، لكنها أسوأ الكيانات برمجيًا أيضًا، نظرًا لأن صانعيها هي مؤسسات تضع الاحتياجات الفورية للسوق مباشرة بدون الأخذ بمعايير الجودة أو التوافقية أو التماسك بالحسبان على المستوى طويل الأمد. ما نحتاجه بدلًا من ذلك هو مشروع منظم ومدروس لإنشاء نظام متكامل يدعم كلّ من القوالب والإضافات ومنشئي الصفحات. وسيتضمن المشروع أمورًا مثل: تنسيق جسم قوالب ووردبريس وكتابة شيفراتها البرمجية بطريقة جيدة. فعلى سبيل المثال، جعل عناوين صفحات كلّ قالب عبارة عن وسم h1 مع عنوان post_title للصنف، ويكون قسم تذييل في كلّ قالب عبارة عن عنصر تذييل (footer) مع صنف (site_footer)، وستستخدم جميع القوالب شبكة ذات 12 عمودًا، وهكذا. جعل الإصدار المُستخدم في كلّ الإضافات واضحًا مثل "نحن نستخدم هذا الإصدار" وذلك للإضافات المشهورة للووردبريس مثل: خدمة البريد الإلكتروني MailChimp، وخدمة منشئ النماذج Gravity (لإنشاء نماذج مثل نموذج إتصل بنا)، وخدمة خرائط Google WP (لتكامل خرائط غوغل)، وخدمة بناء قوائم الأحداث Modern Tribe، وخدمة التجارة الإلكترونية WooCommerce (لإنشاء متاجر إلكترونية)، وجميع الإضافات الأخرى المشهورة. استخدام جميع القوالب في المنصة منشئ صفحات إفتراضي ومتوافق توافقًا تامًا مع جميع الإضافات المذكورة والّذي سيستخدم عند إجراء أي تعديل على الصفحات. على سبيل المثال، سيكون لكل قالب تخطيط افتراضي جميل، وشكل جميل أيضًا لكل من لنموذج اتصل بنا (باستخدام إضافة Gravity) بالإضافة إلى خريطة من خرائط غوغل. يمكن جلب إضافات أخرى (إما لهذه المتطلبات المذكورة أو متطلبات أخرى) في النظام، ولكن بدون تقديم ضمان بالتوافقية مع بقية المكونات. تستخدم جميع القوالب منشئ صفحات موحد في الواجهة الأمامية، والّذي سيكون مثل الطريقة المتبعة في سكويرسبيس وتكون هي الطريقة الافتراضية لإجراء تغييرات على محتوى وتخطيط الصفحات. كما يفترض أن يبنى منشئ الصفحات بناءً عموميًا لكي يستطيع أن يتعامل مع جميع القوالب بنفس الطريقة، مثل أن تكون أسماء الأصناف مشتركة post_title و site_footer، بالإضافة إلى دمجها بعمق وبشكل خاص مع جميع المكونات الإضافية كمنظومة متكاملة. أنا على دراية بسرعة التغييرات الّتي تحدث والّتي تجعل هذا الأمر صعبًا. أعلنت شركة Automattic مؤخرًا إتاحة القوالب الموجودة على WordPress.com لمستخدمي WordPress.org، وهو خطوة من خطوات الدمج والّتي ستكون ضرورية لـ Automattic نفسها لإنشاء بيئة مركزية لمجموعة للقوالب والإضافات ومنشئ الصفحات الّتي أتخيلها. إنني أفهم سبب الخلاف أيضًا، وهو على نطاق واسع القلق من أن شركة Jetpack تستغل مكانتها في السوق لتبطئ المنافسين لها في سوق القوالب والإضافات ولكن هذا هو السوق الحر. إذا كانت هذه الديناميكية مستحيلة التحقيق، فلربما يمكن للمجتمع أن ينمو حول واحد من أكثر منشئي الصفحات رصانةً وقوة ويبدو لي أن منشئ الصفحات Beaver على وجه الخصوص يجذب مجتمعًا متحمسًا من مطوري ووردبريس الّذين يهتمون بالجودة. سيتطلب الأمر قدرًا عاليًا من الرؤية والتركيز للمجتمع لمثل هذا النجاح في إنشاء نظام متكامل يمكن أن يُنافس تجربة المستخدم فيه تجربة المستخدم في سكويرسبيس، وبكل تأكيد ستكون الفوائد العائدة فلكية. ولكن بالنسبة للوضع الراهن هو استمرار سكويرسبيس بالنمو، وبناء المزيد من المواقع من خلاله، وظهوره أكبر وأكبر متحديًا بذلك ووردبريس. أرجح هذه النتيجة بشكل كبير، ولذلك سأفكر بإيجاز ما هو إنعكاس ذلك على حياتي المهنية كمطور ووردبريس. مطور ووردبريس في عالم سكويرسبيس الجميل إذا كنت من مطوري ووردبريس المحترفين الّذين يركزون على المشروعات الصغيرة والمتوسطة للأفراد والشركات الصغيرة، فإن التطور السريع لسكويرسبيس يجب ألا يخيفك نهائيًا. بل سيكون لديك مجال واسع كونك مطور ووردبريس. لكن عليك القيام بأمرين: أن تكون مستعدًا للتوصية بمنصة سكويرسبيس عندما تكون هي الحلّ الأفضل للمشروع. أن تكون مطور ووردبريس بنفس الوقت. الأداة المناسبة للمشروع المناسب إذا كنت مطور ووردبريس وعلى دراية تامة بأن سكويرسبيس أفضل لمتطلبات العميل - لكنك تواصل تقديم حلول مبنية على الووردبريس لجميع العملاء - فأنت تقدم منتجًا رديئًا. وهو ليس نوع العمل الّذي أرغب بالقيام به. لذلك أنا ملتزم بتقديم سكويرسبيس لعملائي عندما يكون هو الحل الصحيح لهم، وووردبريس عندما لا يكون كذلك. ولكن متى لا يكون سكويرسبيس هو الحل الصحيح؟ في الواقع العديد من المشاريع تتطلب تطويراً مخصصًا وهذه بعض الأمور الّتي تساعدك في معرفة ذلك. إليك هذه السناريوهات الواضحة الّتي من المستحيل تنفيذها بواسطة سكويرسبيس: إنشاء نموذج مخصص للتبرع للحيوانات الأليفة المتبناة، ومع إظهار قائمة المتبرعين والمبالغ الّتي تبرعوا بها في شريط جانبي لصفحة عرض الحيوان الأليف. إنشاء نموذج تسليم (إرسال) المنتجات ومؤلف من خمس أجزاء لموقع سوق متعدد البائعين. إنشاء "تقويم إنتاج" والّذي يعرض قائمة المعلومات الحالية للتاريخ مع موازنتها مع معلومات الشهر السابق بنفس التاريخ بالإضافة إلى المعلومات الوصفية للمنتجات (الفواكه أو الخضروات المحددة في الموسم في سوق المزارعين على سبيل المثال). توسعة وظائف إضافة معينة ولتكن على سبيل المثال إضافة IssueM (والمستخدمة من قبل المجلات الرقمية للتحكم في الإصدارات الرقمية للمجلة) توسيعها ليستطيع مالكي المواقع إختيار التخطيط المناسب لكل فئة من إصدارات المجلة الّتي ينشرونها. بعبارة أخرى، إن أي متطلب تشعر بأنه غير عادي غالبًا ما يدخل في مجال ووردبريس. وبما أن الشيفرة البرمجية لسكويرسبيس مغلقة المصدر، تكون إمكانية التعديل عليها محدودة جدًا على عكس النسخة المحمولة من ووردبريس والمتاحة على موقعهم الرسمي. ولذلك من الصعب جدًا أن نتخيل السيناريوهات الأربعة المذكورة سابقًا مبنية بالسكويرسبيس. هل يحتاج العالم إلى محترفين انشاء مواقع بالسكويرسبيس؟ اذا كان هنالك بعض العملاء الّذين تتناسب احتياجاتهم مواصفات سكويرسبيس سأقدم لهم خدماتي ﻹنشاء المواقع بالسكويرسبيس. هل سنتقاضى أجرًا على تنفيذ مواقع باستخدام سكويرسبيس؟ بعبارة أخرى، هل سنأخذ أجرًا مقابل أنشاء مواقع بالسكويرسبيس؟ أعتقد بأن الاجابة نعم وبكل تأكيد. في الحقيقة بالنسبة للعملاء الّذين تناسبهم حلول سكويرسبيس، والّذين تبلغ ميزانية مشروعهم 1000 أو 2000 دولار أمريكي، ويحناجون لموقع رسمي بدون أي متطلبات خاصة سأقوم فورًا بعرض خدماتي عليهم كمنشئ مواقع باستخدام سكويرسبيس. طبعًا أنت لست بحاجة لأي شخص لبناء موقع باستخدام سكويرسبيس، ولكن يمكن للمطور الخبير أن يوفر وقتك، ويحقق لك نتيجة أفضل من الّتي قد تحققها بنفسك. حتى في موقع التجريبي الّذي أنشأته للتو استفدت جيدًا من معرفتي السابقة في CSS، وأصبحت خبراتي السابقة كمطور ويب رهن إشارتي في العديد من الأماكن خلال تطوير موقع التجريبي. فعلى سبيل لقد أدركت أخيرًا أن التخطيط لـ 5 أعمدة أمر مستحيل لأن موقع سكويرسبيس يستخدم شبكة من 12 عمود. لقد ظللت غير متأكدًا من ذلك لولا أني أعرف كيف استخدم أدوات المطور في غوغل كروم. وفهمت أيضًا أن أساس الشبكة في سكويرسبيس مكون من 12 عمود. لذا وبالنسبة للمطورين فإن تقديم عرض لإنشاء موقع على منصة سكويرسبيس لا يزال مطلوب وخصوصًا للأشخاص المشغولين جدًا ولا يملكون الوقت الكافي لتعلم كيفية بناء موقع بأنفسهم. ولذلك فإن هنالك فرصة كبيرة في هذا المجال. لتقديم عرض لأحد العملاء يجب عليك أخباره بأن تكلفة المشروع ستكون 2000 دولار أمريكي باستخدام منصة الووردبريس و1500 دولار أمريكي باستخدام منصة سكويرسبيس وبإمكانك تسليمه إياه خلال أسبوع واحد وسيكون جميلًا وسهلًا في الإدارة (مع التأكيد على توضيح فكرة للعميل أن أي ميزات إضافية ستحتاجها في المستقبل من الممكن أن تتطلب الانتقال من سكويرسبيس إلى ووردبريس ويمكنك أيضًا مساعدته في هذا الانتقال) برأيي أنه اقتراح جميل وصادق للغاية، ويفترض أن يكون العميل راضي تمامًا على النتائج وممتن لك في نهاية المطاف. تذكر: معظم العملاء لا يهتمون مطلقًا بالتقنيات المستخدمة في تنفيذ مشاريعهم وإنما يكون هدفهم الأساسي الحصول على منتج خالٍ من الأخطاء مقابل المال الّذي يدفعونه، وإلى أن يصبح استخدام منصة سكويرسبيس سهلًا جدًا ويتساوى الخبير مع المستخدم الجديد في طريقة إنشاء الموقع فهذا -ولحسن الحظ- يحتاج لوقت طويل للوصول إليه. سباق تحطيم الأسعار نصيحتي الأولى والأخيرة لك هي تجنب سباق تحطيم الأسعار حتى لا ينتهي بك المطاف بالعمل بشكل مجاني أو شبه مجاني. كثيرٌ من الأشخاص يطلبون أشياء غير واقعية بميزانيات منخفضة جدًا أو يحاولون تبخيس السعر بشكل كبير، فكن حذرًا عند تعاملك معهم ومناقشة السعر معهم لأننا غالبًا سنراهم في السنوات القليلة القادمة. أمرٌ آخر حافظ على معدل سعر الساعة لديك. فإذا كُنتُ محاميًا مشغولًا فسأقوم وبكل سرور بدفع 750 دولارًا أمريكيًا أو حتى 1500 دولار أمريكي لموقع وِب جميل مبني باستخدام سكويرسبيس. إذا كان دفع المال يعني أني لم أضطر إلى التضحية بأربع عطلات نهاية الأسبوع متوالية لاستكشاف المنصة بنفسي وبناء الموقع بالكامل. وحتى وإن استغرق منشئ مواقع سكويرسبيس لـ 5 ساعات فقط لإنشاء موقعي فأنا لا أزال سعيدًا بذلك. وبالمجمل سأكون سعيدًا بدفع 150 دولارًا أمريكيًا أو حتى 300 دولارًا أمريكيًا في الساعة طالما أن العمل متقن والتصميم جميل. لذا إذا أردت العمل كمنشئ مواقع باستخدام سكويرسبيس فأخذ أجرًا كاملًا وفقًا لذلك. ختامًا شخصيًا أرحب بمنصة سكويرسبيس، أنها تعمل عملًا لا بأس به في الوقت الحالي -برأيي الشخصي- بل وإنها تفعل ذلك أفضل من ووردبريس. عمومًا، من الصعب أن أغضب من الحل الّذي وفر لي واجهة مستخدم ذكية وجعلني أتخذ قرارات تصميمة أفضل. وقدم لي سهولة في الاستخدام بشكل عام لبناء موقع وِب متكامل بالرغم من أنها تنافس مهنتي اليومية (كمطور ووردبريس). آمل حقًا أن يتمكن ووردبريس من إنشاء تجربة مستخدم تنافس سكويرسبيس لمواقع إعلامية بسيطة، ولكن هذا سيتطلب قدرًا كبيرًا من الإرادة من مجتمع المطورين لإقامة "نظام متوافق ومتكامل" يضم مجموعة من القوالب والإضافات و منشئي الصفحات لينجح. في غضون ذلك، إذا كنت مطور ووردبريس، أقترح عليك بإلقاء نظرة فاحصة إما على تطوير ووردبريس أو على تطبيق إنشاء موقع بالسكويرسبيس. من المؤكد أن مواقع ووردبريس لا تزال مطلوبة ولا يزال لديها مكانة في السوق (لأنه حتى لو كنت لا تعرف الشيفرة البرمجية لسكويرسبيس، فهناك أشياء كثيرة يمكن أن يقوم بها ووردبريس ولا يستطيع سكويرسبيس القيام بها)، لكنني أعتقد أن المكان المناسب لسكويرسبيس سيكون لمواقع إعلامية صغيرة والّتي لا تتطلب مميزات خاصة إضافية. ترجمة -وبتصرف- للمقال squarespace-vs-wordpress-developers-perspective لصاحبه Fred Meyer
  6. إن تزايد تعقيد تطبيقات الوِب في وقتنا الحالي جعل من ضرورة زيادة قابلية تطبيقات الوِب للتوسعة والتطوير أمرًا في غاية الأهمية. وعلى الرغم من أن الحلول القديمة المخصصة لكتابة شيفرات جافاسكربت و jQuery كانت فعَالة وكافية إلى حدٍ ما، ولكن بناء تطبيق وِبٍ في وقتنا الحاضر يتطلب درجة كبير من الانضباط والمنهجية الرسمية في تطوير البرمجيات. وهذه بعض الأمثلة على الممارسات الجيدة في تطوير البرمجيات: استخدام اختبارات الوحدة (Unit tests) وذلك للتأكد من أن تعديلات ما على الشيفرة البرمجية لن يعطّل شيفرة أُخرى. استخدام عملية كشف الأخطاء المحتملة (Linting) لضمان كتابة شيفرة برمجية خالية من الأخطاء. استخدام طرق مختلفة للبنية الهيكلية للشيفرة البرمجية لكلّ من وضع التطوير ووضع النشر. بالإضافة إلى ذلك فإن معايير الوِب بشكلها الحالي طرحت تحديات جديدة لتطوير تطبيقات الوِب. على سبيل المثال صفحات الوِب الحالية تُنشئ الكثير من الطلبات غير المتزامنة والّذي بدوره يؤدي إلى خفض أداء تطبيق الوِب انخفاضًا كبيرًا بسبب معالجة طلبات ملفات التنسيق والجافاسكربت. إذ أن لكل طلبٍ من هذه الطلبات (حتى وإن كان لملف صغير الحجم) فإنه سيحتاج إلى ترويسة اتصال (Header) وكُلفة إنشاء اتصال (handshakes). وهذه المشكلة تحديدًا تُعالجُ من خلال تجميع الملفات معًا لتصبح في ملف واحد وبذلك سنستدعي ملف جافاسكربت وملف تنسيق بدلًا من المئات الملفات. من الشائع في وقتنا الحالي استخدام لغات ذات معالجة مُسبّقة (language preprocessors) مثل: SASS و JSX والّتي تُترجم من هذه اللغات إلى ملفات جافاسكربت وملفات تنسيقات. بالإضافة إلى ذلك شاع أيضًا استخدام المحوّل (Transpilers) وهو محوّل يغيّر الشيفرة البرمجية من إصدار معين للغة جافاسكربت إلى إصدار أقدم، وذلك لضمان عمل هذه الشيفرة البرمجية على جميع المتصفحات. مثل المحوّل Babel. إن هذه المهام (والّتي لا علاقة لها بالمنطق البرمجي لتطبيق الوِب بحد ذاته) تمثل عبئًا على على المطور. ولكن لحسن الحظ يوجد حلٌ لهذا الأمر وهو منفذ المهام (Task Runner) والّذي جاء لمساعدتنا في أتمتة هذه المهام حتى نستطيع أن نحسّن من بيئة التطوير مع التركيز على بناء المنطق البرمجي لتطبيق الوِب. بمجرد ضبط الإعدادات الخاصة بمنفذ المهام كلّ ما عليك فعله هو استدعاء أمرٍ على الطرفية وستُنفذ بعدها المهام المؤتمتة. سأستخدم الأداة Gulp كمنفذ للمهام وذلك لأنه مناسب للمبرمجين وسهل التعلّم ومفهوم (تحدثنا في مقال سابق كيفية استخدام هذه الأداة بكلّ التفاصيل). مقدمة سريعة لأداة Gulp تتألف واجهة برمجة التطبيقات (API) لهذه الأداة من أربع دوالّ: gulp.src gulp.dest gulp.task gulp.watch في المثال التالي نلاحظ أن المهمة my-first-task ستستخدم ثلاثة دوال من أصل الأربعة. gulp.task('my-first-task', function() { gulp.src('/public/js/**/*.js') .pipe(concat()) .pipe(minify()) .pipe(gulp.dest('build')) }); عند تنفيذ المهمة my-first-task ستصغّر أولًا جميع الملفات المطابقة للنمط ‎/public/js/**/*.js‏ ومن ثمّ ستُنقل إلى المجلد build. الجميل في التعليمة ‏pipe()‎. هي أنه يمكنك أخذ مجموعة من ملفات الإدخال وتمريرها عبر الأنبوب لتنفيذ بعض التحويلات المناسبة عليهم ومن ثمّ إعادة ملفات الخرج المطلوبة. لجعل الأمور أكثر توافقية. غالبًا ما تنفذ العمليات المطلوبة في الإنبوب (مثل: minify()‎) من خلال مكتبات مدير الحزم npm، ونتيجة ذلك من النادر جدًا في التطبيق الفعلي لهذه االعمليات أن نحتاج لكتابة تفاصيل هذه العمليات كتابةً يدوية إلا إذا أردت أن تُعيد تسمية الملفات في الأنبوب. من الجدير بالذكر أن Gulp يَستخدم المجاري (streams) الّتي توفرها node.js، وهذا يسمح بتمرير البيانات الّتي ستُعالَج عبر الأنابيب (pipes) وهذا ما تفعله الدالة ‎.pipe()‎؛ لشرحٍ تفصيليٍ عن المجاري في node.js، سأحيلك إلى هذه المقالة. الخطوة التالية لفهم Gulp هي فهم مصفوفة تبعيات المهام. gulp.task('my-second-task', ['lint', 'bundle'], function() { ... }); في هذا المثال إن المهمة my-second-task تُعيد نتيجة الدالة المجهولة (anonymous function)، وذلك بعد اكتمال مهمة lint ومهمة التجميع bundle. وبذلك يُسمح لنا بفصل الاهتمامات عن بعضها بعضًا كما يمكنك أيضًا إنشاء سلسلة من المهام الصغيرة بمسؤولية واحدة مثل تحويل LESS إلى CSS. وإنشاء مهمة رئيسية (Master Task) والّتي ستستدعي ببساطة جميع المهام الأخرى (الصغيرة) عبر مصفوفة من تبعيات المهام. وأخيرًا لدينا التعليمة gulp.watch والّذي يراقب التغييرات في ملف (أو ملفات) ما والمطابق لنمط مرّر لها، وما إن يحدث تغيير ما في هذا الملف حتى تُنفذّ سلسلة من المهام المحددة. gulp.task('my-third-task', function() { gulp.watch('/public/js/**/*.js', ['lint', 'reload']) }) في المثال السابق أي تغيير في الملفات الّتي تطابق النمط /public/js/**/*.js سيؤدي إلى تشغيل مهمة كشف الأخطاء المحتملة lint وبعدها مهمة إعادة التحميل reload. إن الاستخدام الشائع للتعليمة gulp.watch هو تشغيل عمليات إعادة التحميل المباشر في المتصفح، وهي ميزة رائعة جدًا أثناء مرحلة التطوير ولن تستطيع العمل بدونها بمجرد أن تجربها. وإلى هنا نستطيع القول بأننا فهمنا كلّ ما سنحتاج لاستخدامه في الأداة Gulp. أين سنستخدم أداة Webpack؟ عندما نستخدام نمط CommonJS فإن تجميع كلّ ملفات الجافاسكربت ليصبحوا في ملف واحد ليس بهذه البساطة. إذ إن الخاصية (entry point) والّتي تُسند عادةً للقيمة index.js أو app.js مع سلسلة من التعليمات require أو import الموجودة في أعلى الملف. وسيكون شكل ملف جافاسكربت في الإصدار ES5 على الشكل التالي: var Component1 = require('./components/Component1'); var Component2 = require('./components/Component2'); وسيكون شكل ملف جافاسكربت في الإصدار ES6 على الشكل التالي: import Component1 from './components/Component1'; import Component2 from './components/Component2'; إن المثالين السابقين يجلبان التبعيات قبل تنفيذ بقية الشيفرات البرمجية في ملف app.js، وممكن أن يكون لهذه التبعيات تبعيات أخرى والّتي ستُجلب أيضًا. وبالإضافة إلى ذلك من الممكن أن تُستدعى نفس التبعية في أماكن متعددة في تطبيق الوِب خاصتك. ولكننا نريد جلب هذه التبعية مرة واحدة فقط. لهذا فأن كانت شجرة التبعيات بعمق عدة مستويات (أي التبعيات ذات هرمية كبيرة) فعندها ستزداد صعوبة تجميع هذه التبعيات في ملف واحد. ولكن لحسن الحظ يوجد حلّ رائع لهذه المشكلة وهو مُجمّع الحزم (الوحدات) مثل:Browserify أو Webpack. لماذا يفضل المطورون استخدام Webpack بدلًا من Gulp؟ بما أن أداة Webpack (تحدثنا في مقال سابق عن كيفية استخدام مجمع الحزم Webpack وأشهر طرق استعمالها في المشاريع) لتجمّيع الحزم وأداة Gulp لتنفيذ المهام من الممكن أن نتوقع أن نرى استخدام هاتين الأداتين مع بعضهما بعضًا، ولكن هنالك توجّه عام نحو استخدام Webpack بدلًا من Gulp وخصيصًا في مجتمع مطوري React. ولكن لما هذا التوجه؟ ببساطة إن قوة أداة Webpack مكنتها من تنفيذ الغالبية العظمى من المهام الملقاة على عاتق منفذ المهام (مثل: Gulp أو أي منفذ مهام عمومًا). فعلى سبيل المثال توفر Webpack خيارات تصغير وخرائط الشيفرة البرمجية المحوّلة Source Maps (لمزيد من المعلومات عنها يمكنك الإطلاع على المقال التالي) للشيفرة البرمجية المُجمعّة. بالإضافة إلى ذلك يمكن استخدامها كوسيط (Middleware) من خلال خادم مخصص يدعى webpack-dev-server والّذي يدعم كلًا من إعادة التحميل المباشر (live reloading) وإعادة التحميل النشط (hot reloading) لصفحات الوِب (والّتي سنتحدث عنها لاحقًا في هذا المقال). وكما يمكنك أيضًا تحويل الشيفرة البرمجية (transpiling) من إصدار جافاسكربت حديث مثل ES6 إلى إصدارٍ قديم مثل: ES5. ويمكنك أيضًا استخدام طريقة المعالجات المُسبقة (pre-processors) أو المُلحقة (post-processors) لملفات التنسيق. وبذلك تُترك عملية إختبار الوحدة (Unit Tests) وعملية كشف الأخطاء المحتملة (linting) كمهام رئيسية مستقلة نظرًا من كوننا قلصنا ما لا يقلّ عن ستة مهام محتملة للأداة Gulp لمهمتين فقط. يلجأ العديد من المطورين لاستخدام NPM Scripts بدلًا من استخدام Gulp، وذلك لتجنب إضافة أداة Gulp إلى المشروع في حين وجود بديل قوي ينوب عنها. في الحقيقة إن السيئة الرئيسية لاستخدام Webpack هي صعوبة ضبط إعداداته، مما يجعله خيارًا غير مرغوب به في حال أردنا إنشاء مشروع وتشغيله بأسرع وقتٍ ممكن. طرق إعداد منفذ مهام سنتعرف على ثلاث طرق لإنشاء وإعداد منفذ مهام مساعد في المشاريع البرمجية. وكلّ واحدٍ منهم سينفذ المهام التالية: إعداد خادم تطوير مع ميزة إعادة التحميل المباشر (live reloading) فور حدوث أي تعديل على صفحة الوِب المُراقبة. تجميع ملفات التنسيق والجافاسكربت (بالإضافة إلى تحويل الشيفرة البرمجية للغة جافاسكربت من الإصدار ES6 إلى ES5، وتحويل ملفات التنسيق من SASS إلى ملفات CSS وخرائط الشيفرة البرمجية المحوّلة) وذلك بطريقة قابلة للتطوير والتوسّع لهذه الملفات المحوّلة. تشغيل اختبار الوحدة (Unit Tests) سواءً كمهمة قائمة بحد ذاتها أو في وضع المراقبة. تشغيل عملية الكشف عن الأخطاء المحتملة (Linting) سواءً كمهمة قائمة بحد ذاتها أو في وضع المراقبة. توفير القدرة على جمع كلّ المهام السابقة عبر أمر واحد لكتابته عبر الطرفية. وجود أمر آخر لتجميع الملفات وضغطها أو تنفيذ تحسينات أخرى عليها من أجل عملية النشر. وستكون طرق إعداد منفذ المهام على الشكل التالي: Gulp + Browserify Gulp + Webpack Webpack + NPM Scripts سنعتمد في تطبيقنا العملي على استخدام React للواجهات الأمامية. في الحقيقة أردت في البداية أن أعمل بدون إطار عمل، ولكن استخدام React سيُبسط مسؤوليات منفذ المهام، إذ سيلزمنا فعليًا وجود ملف HTML واحد فقط، بالإضافة إلى أن React يعمل بسلاسة مع نمط CommonJS ولذلك اعتمدت أخيرًا على استخدامه. سنعمد على توضيح جميع المزايا والعيوب الخاصة بكل طريقة إعداد، وذلك لمنحك المعلومات الكاملة والصورة الشاملة لاتخاذ قرارٍ صائبٍ يناسب احتياجات المشروع الّذي تعكف على تطويره. سننشئ مشروعًا على Git وسنضيف له ثلاثة تفريعات من أجل اختبار كلّ طريقة من الطرق git checkout <branch name> npm prune (optional) npm install gulp (or npm start, depending on the setup) لنناقش الآن كلّ تفريعة (طريقة) من هذه الفروع على حدة. ستكون البنية الهرمية لمجلد المشروع على الشكل التالي: - app - components - fonts - styles - index.html - index.js - index.test.js - routes.js سنتطرق لشرح أهم الملفات الموجودة في المشروع وذلك حرصًا على كمال المعلومة. سيكون الملف index.html على الشكل التالي: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="bundle.css"> <title>Gulp Browserify Setup</title> </head> <body> <div id="app"></div> <script src="bundle.js"></script> </body> </html> نلاحظ أن هذا الملف بسيط جدًا إذ إنه يُحمّلُ تطبيق React في الوسم <div id="app"></div> ولن نستخدم إلا ملف واحد للتنسيقات وملف آخر للجافاسكربت، في الواقع في طريقة الإعداد هذه لن نستخدم حتى ملف التنسيق bundle.css. وسيكون الملف index.js على الشكل التالي: import React from 'react'; import {render} from 'react-dom'; import {Router, browserHistory} from 'react-router'; import routes from './routes'; render(<Router history={browserHistory} routes={routes} />, document.getElementById('app')); نلاحظ أن هذا الملف سيكون بمثابة نقطة الدخول (entry point) لتطبيقنا. إذ إننا بصدد تحميل React Router في الوسم div مع السِمة app الّتي أشرنا لها في الملف السابق. وسيكون الملف routes.js على الشكل التالي: import React from 'react'; import {Route, IndexRoute} from 'react-router'; import App from './components/App'; import HomePage from './components/home/HomePage'; import AboutPage from './components/about/AboutPage'; import ContactPage from './components/contact/ContactPage'; export default ( <Route path="/" component={App}> <IndexRoute component={HomePage} /> <Route path="about" component={AboutPage} /> <Route path="contact" component={ContactPage} /> </Route> ); نلاحظ أن هذا الملف يحدد مسارات المشروع. وستكون المسارات / و ‎/about و ‎/contact مرتبطة مع المكونات HomePage و AboutPage و ContactPage على التتالي. وسيكون الملف index.test.js على الشكل التالي: import expect from 'expect'; describe('Array', () => { it('should return -1 when the value is not present', () => { expect(-1).toBe([1,2,3].indexOf(4)); }); it('should correctly filter elements in an array', () => { const arr = [1,2,3,4,5]; const newArr = arr.filter(el => el > 3); expect(newArr.length).toBe(2); }); it('should correctly map elements in an array', () => { const arr = [1,2,3,4,5]; const newArr = arr.map(el => el * 2); expect(newArr).toEqual([2,4,6,8,10]); }); }); describe('Object', () => { it('should convert an int to a string with the toString method', () => { const val = 5; const valToString = val.toString(); expect(val).toNotBe(valToString); expect(valToString).toBe('5'); }); it('should correctly test whether an object has a certain property', () => { const obj = {a: 1, b: 2}; expect(obj.hasOwnProperty('a')).toBe(true); expect(obj.hasOwnProperty('c')).toBe(false); }); }); describe('String', () => { it('should convert a string to lowercase', () => { const str = 'HELLO'; const strLower = str.toLowerCase(); expect(strLower).toBe('hello'); }); it('should convert a string to uppercase', () => { const str = 'hello'; const strLower = str.toUpperCase(); expect(strLower).toBe('HELLO'); }); it('should remove spaces from both ends of a string', () => { const str = ' hello there '; const strTrimmed = str.trim(); expect(strTrimmed).toBe('hello there'); }); it('should split the string into an array of strings based on the provided delimiter', () => { const str = 'she-sells-seashells-down-by-the-seashore'; const strSplit = str.split('-'); expect(Array.isArray(strSplit)).toBe(true); expect(strSplit.length).toBe(7); }); }); نلاحظ أن هذا الملف يحتوي على سلسلة من اختبارات الوحدة (Unit Tests) والّتي ستختبر سلوك الشيفرة الأصلية للجافاسكربت (Native JavaScript) في عملية النشر الفعلية للتطبيق يمكنك إنشاء اختبار لكل مكون React (اختبار واحد على الأقل لكل مكوّن يعالج حالة معينة) واختبار السلوك الخاص بإطار العمل React. وعلى أية حال يكفي أن يكون لديك اختبار وحدة بسيط والّذي نستطيع تشغيله في وضع المراقبة (watch mode عند تفعيل هذا الوضع تثبت ملفات مخصصة لمراقبة أي تغييرات تحصل في الملفات الأخرى وفي حال حصول أي تغييرات في الملفات سيعاد ترجمة الملفات للحصول على الخرج الجديد). وسيكون الملف components/App.js على الشكل التالي: import React, {PropTypes} from 'react'; import Header from './common/Header'; class App extends React.Component { render() { return ( <div> <Header /> {this.props.children} </div> ); } } App.propTypes = { children: PropTypes.object.isRequired }; export default App; يمكن اعتبار الملف السابق حاوية لجميع مكونات العرض الموجودة لدينا. إذ تحتوي كلّ صفحة لدينا على الترويسة <Header/> بالإضافة إلى this.props.children والّذي يقيّم لعرض محتواه في الصفحة نفسها. فعلى سبيل المثال إذا كان في المتصفح /contact سيقيّم إلى ContactPage. وسيكون الملف components/home/HomePage.js على الشكل التالي: import React from 'react'; import {Jumbotron, Grid, Row, Col, Panel} from 'react-bootstrap'; class HomePage extends React.Component { render() { return ( <div className="HomePage"> <Jumbotron> <Grid> <h1>Home Page</h1> </Grid> </Jumbotron> <Grid> <Row> <Col sm={6}> <Panel header="Panel 1"> <p>Content A</p> <p>Content B</p> </Panel> </Col> <Col sm={6}> <Panel header="Panel 2"> <p>Content A</p> <p>Content B</p> </Panel> </Col> </Row> </Grid> </div> ); } } export default HomePage; هذا الملف سيكون الصفحة الرئيسية المعروضة. استخدمت react-bootstrap نظرًا لأن نظام الشبكة (Grid) في إطار العمل Bootstrap ممتاز لإنشاء صفحات متجاوبة. وعند استخدامه استخدامًا صحيحًا سيُقّلل عدد استعلامات الوسائط (media queries) الّتي سنكتبها للأجهزة صغيرة الحجم تقليلًا كبيرًا. المكونات الأخرى المتبقية (مثل: Header و AboutPage و ContactPage) مبنية بطريقة مشابهة (باستخدام react-bootstrap بدون التلاعب بالحالة [state manipulation]). أما الآن لنتحدث أكثر عن ملفات التنسيق. منهجية الملفات التنسيق أسلوبي المفضل في تنسيق ملفات React هو امتلاك ملف تنسيق خاص لكلّ مكوّن من المكونات. إذ سيكون هذا التنسيق ضمن نطاق هذا المكون فقط. ستلاحظ أنه في كلّ مكون من المكونات هنالك وسم div ذو مستوى أعلى وسيكون أسم الصنف التابع له مطابق لأسم المكون نفسه. لذلك المكون HomePage.js سيكون مغلف بوسم له الشكل التالي: <div className="HomePage"> ... </div> وسيكون هنالك أيضًا ملف HomePage.scss والّذي سيكون مهيكل على الشكل التالي: @import '../../styles/variables'; .HomePage { // Content here } لماذا هذه المنهجية مفيدة للغاية؟ لأنها تنتج لنا وحدات (Modular) ذات جودة عالية. مما يُلغي الكثير من المشاكل غير المرغوب بها في التنسيق. لنفترض أن لدينا مكونين React وهما Component1 و Component2. وفي كلّ واحد منهما نريد إعادة تنسيق الوسم h2 ليصبح حجم الخط كما في الملف التالي: /* Component1.scss */ .Component1 { h2 { font-size: 30px; } } /* Component2.scss */ .Component2 { h2 { font-size: 60px; } } إن حجم الخط المخصص للوسم h2 في المكونين Component1 و Component2 مكتوبان بمعزل عن بعضهما البعض سواءً أكان المكونين متجاورين أو متداخلين لن يؤثر أحدهما على الآخر. أي أن المكون سيبدو شكله مثل ما خُطط له تمامًا بغض النظر عن مكان وجوده. في الحقيقة إن الأمر ليس بهذه السهولة دائمًا، ولكنه وبكل تأكيد خطوة كبيرة باتجاه أفضل الممارسات الصحيحة للتنسيق. وبالنسبة للتنسيقات المُسبقة للمكونات (per-component styles) أحب أن أخصص مجلد تنسيقات styles يحتوي على جميع التنسيقات العامة في الملف global.scss بجانب تنسيقات SASS مخصصة والّتي تكون مسؤولة عن معالجة التنسيقات المخصّصة (في حالتنا مثل: ‎_fonts.scss و ‎_variables.scss من أجل الخطوط والمتغيّرات على التوالي). تتيح لنا هذه التنسيقات العامة تحديد الشكل العام للتطبيق بأكمله بينما يمكن للتنسيقات الأخرى المخصصة أن تُستورد بحسب الحاجة لها. والآن بعد أن استكشفنا بعمق الشيفرة البرمجية المشتركة بين كلِّ طرق إعداد منفذ المهام. لننتقل إلى أول طريقة منهم. 1. طريقة Gulp + Browserify يتكون ملف gulpfile.js من 22 سطرًا من تعليمات لاستيراد المكتبات والحزم و150 سطرًا من الشيفرات البرمجية الأخرى. لذا ومن أجل الإيجاز سنراجع بالتفاصيل أهم النقاط الرئيسية في هذا الملف (مثل: js و css و server و watch و default). محزم ملفات جافاسكربت // ضبط إعداد Browserify const b = browserify({ entries: [config.paths.entry], debug: true, plugin: PROD ? [] : [hmr, watchify], cache: {}, packageCache: {} }) .transform('babelify'); b.on('update', bundle); b.on('log', gutil.log); (...) gulp.task('js', bundle); (...) function bundle() { return b.bundle() .on('error', gutil.log.bind(gutil, 'Browserify Error')) .pipe(source('bundle.js')) .pipe(buffer()) .pipe(cond(PROD, minifyJS())) .pipe(cond(!PROD, sourcemaps.init({loadMaps: true}))) .pipe(cond(!PROD, sourcemaps.write())) .pipe(gulp.dest(config.paths.baseDir)); } نلاحظ في الدالّة bundle أن ملفات الجافاسكربت ستُحزّم باستخدام Browserify وستُستخدم خرائط الشيفرة البرمجية المحوّلة (Source maps) في وضع التطوير بينما ستُستخدم عملية التصغير لملفات جافاسكربت في وضع الإنتاج. في الحقيقة إن هذا النهج سيء وذلك لعدة أسباب إحداها أن المهمة ستقسّم إلى ثلاثة أجزاء منفصلة. إذ في البداية سننشئ كائن للتحزيم وليكن b وسنمرر له بعض الخيارات المطلوبة، ومن ثمّ نحدد بعض مُعالِجات الأحداث (event handlers). ثم لدينا مهمة Gulp والّتي يجب أن نمرر لها اسم الدالة بدلًا من تمريرها سطريًا (إن b.on('update') تستخدم نفس الطريقة). إن هذه الطريقة غير أنيقة مثل الطريقة الموجودة في مهام Gulp والّتي تتطلب فقط تمرير gulp.src وتوجيه بعض التغييرات. هناك مشكلة أخرى تجبرنا على اتباع طرق مختلفة لإعادة تحميل ملفات html و css و js في المتصفح. لاحظ طريقة إعداد مهمة المراقب الموضحة في الشيفرة التالية: gulp.task('watch', () => { livereload.listen({basePath: 'dist'}); gulp.watch(config.paths.html, ['html']); gulp.watch(config.paths.css, ['css']); gulp.watch(config.paths.js, () => { runSequence('lint', 'test'); }); }); عندما سيحصل أي تغيير في ملف html سيعاد تشغيل مهمة html من جديد. gulp.task('html', () => { return gulp.src(config.paths.html) .pipe(gulp.dest(config.paths.baseDir)) .pipe(cond(!PROD, livereload())); }); إن آخر تعليمة في الأنبوب هي عملية إعادة التحميل المباشرlivereload() إذا كانت قيمة الخاصية NODE_ENV ليست production، ستُحدث الصفحة في المتصفح تحديثًا تلقائيًا. يتكرر نفس السيناريو من أجل مُراقب ملفات التنسيق. إذ عند حدوث أي تغيير في أحد ملفات التنسيق تُستدعى المهمة css ويعاد تشغيلها من جديد، وأخر تعليمة في الأنبوب تكون لاستدعاء التحميل المباشر في المتصفح وذلك لعرض التغييرات مباشرة. غير أن المراقب الخاص بملفات الجافاسكربت لا يستدعي مهمة js على الإطلاق، وإنما معالج الأحداث في الأداة Browserify يتعامل مع إعادة التحميل باستخدام منهجية مختلفة تمامًا (يطلق عليها اسم مبدل الوحدات النشط [hot module replacement]). إن التضارب في هذه المنهجية مزعج للغاية. ولكنه للأسف ضروري وإذا استدعينا تعليمة إعادة التحميل المباشر في نهاية دالة bundle فعندها سيؤدي ذلك إلى إعادة بناء كلّ ملفات جافاسكربت في حال حدث أي تغيير في أي ملف منهم. من الواضح أن هذه المنهجية غير قابلة للتوسّع والتطوّر. إذ كلما زاد عدد ملفات جافاسكربت كلما استغرقت عملية إعادة التجميع وقتًا أطول. وفجأة عملية البناء الّتي كانت تستغرق 500 ميلي ثانية ستستغرق 30 ثانية مما سيُعيق منهجية التطوير الرشيق (agile development). محزم ملفات التنسيق gulp.task('css', () => { return gulp.src( [ 'node_modules/bootstrap/dist/css/bootstrap.css', 'node_modules/font-awesome/css/font-awesome.css', config.paths.css ] ) .pipe(cond(!PROD, sourcemaps.init())) .pipe(sass().on('error', sass.logError)) .pipe(concat('bundle.css')) .pipe(cond(PROD, minifyCSS())) .pipe(cond(!PROD, sourcemaps.write())) .pipe(gulp.dest(config.paths.baseDir)) .pipe(cond(!PROD, livereload())); }); إن المشكلة الأولى الّتي تظهر هنا هي تضمين المكتبات أو ملفات التنسيق. إذ يجب علينا أن نتذكر أن نغيّر اسم الملف في كلّ مرة يظهر بها إصدار جديد سواءً للمكتبة (أو لأي ملف تنسيق) وذلك بحذف اسم المكتبة القديمة واستبدالها بالجديدة إلى مصفوفة gulp.src؛ بدلًا من إضافة أمر التضمين في مكان مناسب أكثر في الشيفرة البرمجية. المشكلة الرئيسية الأخرى هي المنطق المعقد في كلّ أنبوب. إذ إنني اضطررت لإضافة مكتبة من مستودع مدير الحزم NPM تدعى gulp-cond فقط لإضافة الجمل الشرطية في تعليمات الأنبوب، والنتيجة النهائية لتعليمات الأنبوب ليس من السهل قراءتها (لأن الأقواس الثلاثية في كلّ مكان!). مهمة الخادم gulp.task('server', () => { nodemon({ script: 'server.js' }); }); هذه المهمة واضحة للغاية. إذ إنه في الأساس مُغلّف لأمر استدعاء nodemon server.js والّذي سيُشغّل ملف server.js في بيئة Node.js. استخدامنا nodemon بدلًا من node إذ ستؤدي أي تغييرات تحدث في الملف إلى إعادة تشغيل الخادم. افتراضيًا nodemon تُعيد تشغيل العملية عند أي تغيير في ملف الجافاسكربت ولهذا السبب من المهم لتضمين ملف nodemon.json للحدّ من مجاله. { "watch": "server.js" } لنراجع الآن الشيفرة البرمجية الخاصة بملف server.js const baseDir = process.env.NODE_ENV === 'production' ? 'build' : 'dist'; const port = process.env.NODE_ENV === 'production' ? 8080: 3000; const app = express(); يؤدي هذا الإعداد إلى تعيين الدليل الأساسي للخادم والمنفذ (port) بناءً على بيئة Node.js. وينشئ نسخة من express. app.use(require('connect-livereload')({port: 35729})); app.use(express.static(path.join(__dirname, baseDir))); ستضيف هذه التعليمات برمجية وسيطة (Middleware) وهي connect-livereload وذلك لأنها الضرورية لإعداد ميزة إعادة التحميل المباشر، كما ستضيف هذه التعليمات أيضًا برمجية وسيطة ساكنة (Static Middleware) والّتي ستتعامل مع الملحقات الثابتة. app.get('/api/sample-route', (req, res) => { res.send({ website: 'Toptal', blogPost: true }); }); إن الشيفرة البرمجية السابقة هي مجرد مسار بسيط لواجهة برمجة التطبيقات. فإذا انتقلت إلى المسار localhost:3000/api/sample-route في المتصفح سترى ما يلي: { website: "Toptal", blogPost: true } في الواجهات الخلفية للتطبيق سيكون لدينا مجلد كامل مخصص لمسارات الواجهة البرمجية للتطبيقات، وملفات منفصلة لإنشاء اتصالات مع قاعدة البيانات. هكذا أُضيف المسار وبهذه البساطة لإثبات أننا يمكننا بناء الواجهات الخلفية بعد بناء الواجهات الأمامية. app.get('*', (req, res) => { res.sendFile(path.join(__dirname, './', baseDir ,'/index.html')); }); هذا المسار الشامل يعني أنه مهما يكن الرابط التشعبي الّذي تودّ الذهاب إليه من خلال المتصفح فسيعرض لك الخادم صفحة index.html الوحيدة، وبعدها تأتي مهمة موجّه المسارات في React لعرض الصفحة المناسبة الّتي طلبتها من جانب العميل بدلًا من جانب الخادم. app.listen(port, () => { open(`http://localhost:${port}`); }); الشيفرة البرمجية السابقة تُخبر نسخة express للتنصت على المنفذ الّذي خصصناه وفتح تبويب جديد في المتصفح لعنوان الرابط الّذي طلبتَ الوصول إليه. الشيء الوحيد الّذي لا يعجبني في طريقة إعداد الخادم هو: app.use(require('connect-livereload')({port: 35729})); نظرًا لأننا نستخدم بالفعل gulp-livereload في ملفنا gulpfile، مما يدل على وجود مكانين منفصلين وجب علينا استخدام إعادة التحميل المباشر. إعداد المهام الافتراضية gulp.task('default', (cb) => { runSequence('clean', 'lint', 'test', 'html', 'css', 'js', 'fonts', 'server', 'watch', cb); }); تنفذ المهمة السابقة من خلال كتابة الأمر gulp في الطرفية. الغريب في الأمر أنك تحتاج لاستخدام runSequence من أجل تنفيذ التعليمات تسلسليًا. عادة ما تنفذ المهام بالتوازي ولكن هذه الطريقة ليست مطلوبة دومًا. فعلى سبيل المثال نحتاج لتشغيل مهمة clean قبل مهمة html للتأكد من أن مجلدات الهدف فارغة قبل نقل الملفات إليها. عندما صدرت النسخة الرابعة من gulp 4 كان إحدى مميزاتها أنها دعمت تعليمتي gulp.series لتنفيذ التعليمات بالتسلسل و gulp.parallel لتنفيذ التعليمات بالتوازي. وفضلًا عن ذلك، إن عملية إنشاء واستضافة التطبيق من خلال أمرٍ واحد هو فعلًا أمرٌ رائع، وإمكانية فهم أي جزء من أجزاء سير العمل بسهولة مثل سهولة اختبار مهمة ما في تسلسل التنفيذ. بالإضافة إلى ذلك يمكننا تفكيك المهام الكبير إلى أجزاء أصغر لنهج أكثر دقة في إنشاء واستضافة التطبيق. على سبيل المثال يمكننا إعداد مهمتين منفصلتين لإجراء عمليات إختبار المهام الأخرى وكشف الأخطاء المحتملة (linting). أو يمكن أن يكون لدينا مهمة المضيف والّتي ستُشغل الخادم والمراقب. هذه القدرة على تنظيم المهام قوية جدًا، وخاصةً عندما يتغيّر تطبيقك ويتطلب المزيد من المهام المؤتمتة. بناء التطبيق وتخصيصه لوضع التطوير مقابل وضع النشر if (argv.prod) { process.env.NODE_ENV = 'production'; } let PROD = process.env.NODE_ENV === 'production'; من خلال استخدام مكتبة yargs الموجودة في مستودعات مدير الحزم NPM. يمكننا تزويد الأداة Gulp بالرايات (Flags). هنا مثلًا سنوجّه ملف gulpfile لتعيين بيئة Node.js في وضع النشر إذا مرّرنا الراية ‎--prod مع التعليمة في الطرفية. سيستخدم هذا المتغيّر PROD كشرط للتمييز بين وضع التطوير ووضع النشر في ملف gulpfile. على سبيل المثال أحد الخيارات الّتي نمررها لإعدادات الأداة Browserify هي: plugin: PROD ? [] : [hmr, watchify] إن التعليمة الشرطية في الشيفرة السابقة مفيدة جدًا لأنها توفر علينا كتابة ملف gulpfile منفصل لكل من وضع التطوير ووضع النشر، والّذي سيحتوي على الكثير من التعليمات المكررة. بدلًا من ذلك يمكننا تمرير gulp --prod لتشغيل وضعية النشر في تنفيذ المهام. أو تمرير gulp html --prod لتشغيل المهمة html فقط في وضع النشر. من جهة أخرى رأينا سابقًا كيف أن تمرير التعليمات الشرطية عبر الأنبوب مثل: .pipe(cond(!PROD, livereload())) ليست من السهل قراءتها. ولكن في نهاية المطاف أنها مسألة تفضيلات شخصية إذا ما كنت تريد استخدام المتغيير المنطقي (PROD) أو إنشاء ملفين منفصلين (gulpfile) للإعداد. لننتقل الآن إلى طريقة الإعداد الثانية، وهي عندما نبدل الأداة Browserify لتحل محلها الأداة Webpack. 2. طريقة Gulp + Webpack نلاحظ أن ملف الإعداد gulpfile انخفض حجمه انخفاضًا كبيرًا إذ يحتوي الآن على 12 سطرًا من تعليمات استيراد المكتبات و 99 سطرًا من الشيفرات البرمجية الأخرى. إذا فحصنا من المهمة الافتراضية: gulp.task('default', (cb) => { runSequence('lint', 'test', 'build', 'server', 'watch', cb); }); يتطلب إعداد تطبيق الوب خاصتنا الآن خمسة مهام فقط، بدلًا من تسعة. وهو في الحقيقة تحسنٌ كبير. بالإضافة إلى ذلك ألغينا الحاجة لاستخدام ميزة إعادة التحميل المباشر livereload، كما أن مهمة المراقب أصبحت كالتالي: gulp.task('watch', () => { gulp.watch(config.paths.js, () => { runSequence('lint', 'test'); }); }); هذا يعني أن المراقب لن يشغل سلوك إعادة بناء التطبيق من جديد. وكميزة إضافية لن نحتاج إلى نقل الملف index.html من app إلى dist أو build بعد الآن. وبالعودة إلى فكرة تقليل المهام، نلاحظ إن المهام المخصصة لكلٍ من ملفات html و css و js و fonts استبدلت بمهمة واحدة: gulp.task('build', () => { runSequence('clean', 'html'); return gulp.src(config.paths.entry) .pipe(webpack(require('./webpack.config'))) .pipe(gulp.dest(config.paths.baseDir)); }); بكلّ بساطة شغّل مهمتي clean و html بالتسلسل، وبمجرد ما ينتهي تنفيذهُم إجلب نقطة الدخول الخاصة بتطبيق الوب خاصتنا ومرّره إلى الأنبوب من خلال الأداة Webpack ثم مررها إلى ملف الإعداد الخاص بالأداة Webpack وهو webpack.config.js وذلك لتهيئه وأرسال الحزمة المُجمّعة الناتجة إلى baseDir (إما dist أو build اعتمادًا على الملف الإعداد ل Node.js). يمكنك إلقاء نظرة على ملف الإعداد webpack.config.js الخاص بالأداة Webpack، لكننا لن نشرحه كله، وإنّما سنشرح الخصائص المهمة المسندة للكائن module.exports. devtool: PROD ? 'source-map' : 'eval-source-map', تعيّن هذه التعليمة نوع خرائط الشيفرة البرمجية المحوّلة (source maps) والّتي سيستخدمها Webpack. تدعم Webpack مجموعة من الخياراتٍ المتنوعة من خرائط الشيفرة البرمجية المحوّلة. ويوفر كلّ وخيارٍ منهم توازنًا مختلفًا في الأداء. فمنهم خرائط ذات تفاصيل كثيرة مقابل خرائط ذات تفاصيل قليلة ولكن إعادة بنائها سريع (وهو الوقت المستغرق لإعادة تجميع الملف بعد إجراء التغييرات). وبناءً عليه يمكننا استخدام خرائط ذات تفاصيل قليلة من أجل زيادة سرعة إعادة التحميل في وضع التطوير واستخدام خرائط ذات تفاصيل كثيرة في وضع النشر. entry: PROD ? './app/index' : [ 'webpack-hot-middleware/client?reload=true', // reloads the page if hot module reloading fails. './app/index' ] هذه هي نقطة الدخول إلى مُجمّع الحزم. لاح المصفوفة المُمررة لنقطة الدخول، وهذا يدلّ على إمكانية استخدام نقاط دخول متعددة. في حالتنا نقطة الدخول هي الملف app/index.js، وكذلك نقطة الدخول الخاصة لإعداد إعادة التحميل النشط للوحدات (hot module reloading) output: { path: PROD ? __dirname + '/build' : __dirname + '/dist', publicPath: '/', filename: 'bundle.js' }, وهنا نحدد مجلد الخرج والّذي سيوضع فيه الملفات المترجمة والمجمّعة. إن أكثر خيارٍ مربكٍ هنا هو publicPath والّذي يعيّن عنوان الرابط التشعبي الّذي سيُجمّع فيه ويوضع على الخادم. لذلك على سبيل المثال إذا كان publicPath هو /public/assets عندها ستكون الحزمة المجمّعة في هذا المسار /public/assets/bundle.js على الخادم. devServer: { contentBase: PROD ? './build' : './app' } هذه التعليمة ستُعلِم الخادم بالمجلد الجذر الّذي ستستخدمه في مشروعك. إذا شعرت بالإرتباك في طريقة تعيين مجلد الخرج لوضع الملف المجمّع فما عليك سوى تذكر هذه الدلالات لكلّ مما يلي: path + filename: الموقع المحدد للحزمة المُجمّعة في الشيفرة البرمجية للمشروع. contentBase (مثل: ملف الجذر /) + publicPath: موقع الحزمة على الخادم. plugins: PROD ? [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.DefinePlugin(GLOBALS), new ExtractTextPlugin('bundle.css'), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) ] : [ new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ], هذه بعض الملحقات الوظيفية الّتي ستعزز وظائف Webpack بطريقة ما. فعلى سبيل المثال إن الملحق webpack.optimize.UglifyJsPlugin هو المسؤول عن تصغير ملفات جافاسكربت. loaders: [ {test: /\.js$/, include: path.join(__dirname, 'app'), loaders: ['babel']}, { test: /\.css$/, loader: PROD ? ExtractTextPlugin.extract('style', 'css?sourceMap'): 'style!css?sourceMap' }, { test: /\.scss$/, loader: PROD ? ExtractTextPlugin.extract('style', 'css?sourceMap!resolve-url!sass?sourceMap') : 'style!css?sourceMap!resolve-url!sass?sourceMap' }, {test: /\.(svg|png|jpe?g|gif)(\?\S*)?$/, loader: 'url?limit=100000&name=img/[name].[ext]'}, {test: /\.(eot|woff|woff2|ttf)(\?\S*)?$/, loader: 'url?limit=100000&name=fonts/[name].[ext]'} ] هذه هي المُحمّلات والّتي تعالج بشكل أساسي الملفات الّتي تُضمّن بواسطة require()، وهي تشبه إلى حدٍ ما الأنابيب في Gulp والّتي تمكنك من ربط المُحمّلات مع بعضهم بعضًا. لنستكشف أحد المُحمّلات: {test: /\.scss$/, loader: 'style!css?sourceMap!resolve-url!sass?sourceMap'} إن الخاصية test تُخبر الأداة Webpack أن الملفات الّتي يجب على المُحمّل التعامل معها يجب أن تحقق التعبير النمطي المُمرر لهذه الخاصية. في حالتنا تكون /\.scss$/. أما الخاصية loader فهي تُحدد المُحمّل الّذي يجب أن نستخدمه. هنا نحدد المُحملات style و css و resolve-url و sass والّتي ستُنفذ بترتيب عكسي. يجب علي أن أعترف بأنني لست ماهرًا في بناء جملة تحديد المُحملات loader3!loader2!loader1. ولكن متى يجب علينا قراءة شيفرة برمجية من اليمين إلى اليسار؟ عدا هذا السطر. على الرغم من ذلك تعدّ المُحمّلات ميزة قوية جدًا لمُجمّع الحزم Webpack. في الحقيقة يسمح لنا المُحمّل الّذي استخدمته للتو باستيراد ملفات SASS بداخل الشيفرة البرمجية للجافاسكربت. فعلى سبيل المثال يمكننا استيراد ملفات التنسيق المخصّصة العامة الّتي عملنا عليها في المشروع في ملف الّذي حددنا كنقطة دخول وهو index.js وسيكون شكله كما يلي: import React from 'react'; import {render} from 'react-dom'; import {Router, browserHistory} from 'react-router'; import routes from './routes'; // CSS imports import '../node_modules/bootstrap/dist/css/bootstrap.css'; import '../node_modules/font-awesome/css/font-awesome.css'; import './styles/global.scss'; render(<Router history={browserHistory} routes={routes} />, document.getElementById('app')); وبطريقة مشابهة في مكوّن الترويسة يمكننا استيراد الملف import './Header.scss' المرتبط بهذا المكون، وهذا وبكل تأكيد ينطبق على كافة المكونات الأخرى في التطبيق. من وجهة نظري الشخصية أرى بأن هذا الأمر يعدُّ تغييرًا ثوريًا في عالم التطوير بلغة جافاسكربت. إذ لا داعي للقلق بشأن تجميع ملفات التنسيق وتصغيرها وحتى خرائط الشيفرة البرمجية المحوّلة (source maps) أيضًا، وذلك لأن مُحمّلنا يتعامل مع كلّ هذه الأمور عوضًا عنا. حتى إعادة التحميل النشط للوحدات (hot module reloading) ستعمل على ملفات التنسيق خاصتنا، ومن ثمّ فإن القدرة على التعامل مع تعليمات الاستيراد من داخل ملف الجافاسكربت سيجعل من عملية التطوير أبسط من الناحية المفاهيمية، وأكثر تناسقًا، وتقلل من تبديل السياق في التطوير (وذلك عند استخدام أدوات مساعدة مختلفة)، والمنطق البرمجي أسهل في التفكير. لإعطاء ملخص موجز حول كيفية عمل هذه الميّزة مع مُجمّع الحزم Webpack وكيف سيضع ملفات التنسيق في ملف جافاسكربت المُجمّع. في الحقيقة لا يقتصر الأمر على ملفات التنسيق وحسب بل يمكنه أيضًا فعل ذلك من أجل الصور والخطوط. {test: /\.(svg|png|jpe?g|gif)(\?\S*)?$/, loader: 'url?limit=100000&name=img/[name].[ext]'}, {test: /\.(eot|woff|woff2|ttf)(\?\S*)?$/, loader: 'url?limit=100000&name=fonts/[name].[ext]'} إن الشيفرة البرمجية السابقة توجّه المُحمّل إلى تضمين الصور والخطوط بداخل الملف المُجمّع إن كان حجمهم لا يتعدى 100 كيلوبايت، وإلا فسيعرضهم كملفات منفصلة، كما يمكننا في أي وقت تغيير حجم المسموح به، ليصبح مثلًا 10 كيلوبايت. هذا هو باختصار طريقة إعداد مُجمّع الحزم Webpack وفي الحقيقة إنه يتطلب قدرًا لا بأس به من الإعداد. ولكن فوائد استخدامه رائعة للغاية. على الرغم من أن مُجمّع الحزم Browserify لديه أيضًا ملحقاته الجميلة وتحويلاته ولكنه لا يستطيع أن ينافس محملات Webpack من ناحية الخصائص الوظيفية المُضافة. 3. طريقة Webpack + NPM Scripts في هذه الطريقة من الإعداد سنستخدم npm scripts مباشرة بدلًا من الاعتماد على Gulp لأتمتة مهامنا. سيكون ملف package.json على الشكل التالي: "scripts": { "start": "npm-run-all --parallel lint:watch test:watch build", "start:prod": "npm-run-all --parallel lint test build:prod", "clean-dist": "rimraf ./dist && mkdir dist", "clean-build": "rimraf ./build && mkdir build", "clean": "npm-run-all clean-dist clean-build", "test": "mocha ./app/**/*.test.js --compilers js:babel-core/register", "test:watch": "npm run test -- --watch", "lint": "esw ./app/**/*.js", "lint:watch": "npm run lint -- --watch", "server": "nodemon server.js", "server:prod": "cross-env NODE_ENV=production nodemon server.js", "build-html": "node tools/buildHtml.js", "build-html:prod": "cross-env NODE_ENV=production node tools/buildHtml.js", "prebuild": "npm-run-all clean-dist build-html", "build": "webpack", "postbuild": "npm run server", "prebuild:prod": "npm-run-all clean-build build-html:prod", "build:prod": "cross-env NODE_ENV=production webpack", "postbuild:prod": "npm run server:prod" } لتشغيل طريقة البناء من أجل وضع التطوير أو وضع النشر يمكنك كتابة الأوامر npm start و npm run start:prod على التتالي. نلاحظ أن هذا الملف أفضل وبكل تأكيد من ملف الإعداد gulpfile الّذي بنيناه سابقًا في هذا المقال. إذ اختصرنا الكثير من الشيفرات البرمجية لتكون عدد التعليمات بدلًا من 150 أو 99 تعليمة أصبحت 19 تعليمة (12 تعليمة إذا استثنينا التعليمات الخاصة بوضع النشر لأن معظمها مشابهة للتعليمات في وضع التطوير الّتي في بيئة Node.js لتصبح في وضع النشر). إن العيب الوحيد هو أن التعليمات مبهمة إلى حدٍ ما بالموازنة مع التعليمات الخاصة للأداة Gulp وليست معبرة مثلها. فعلى سبيل المثال لا توجد (على حسب اطلاعي على الأقل) بوجود تعليمة واحدة تشغّل npm script لينفذ تعليمات معينة تنفيذًا متسلسلًا وتعليمات أخرى ليُنفذها تنفيذًا متوازيًا. وإنما تعليمة واحدة لكل منهما. ومع ذلك هنالك الكثير من الميّزات الكبيرة لهذا المنهج. بالإضافة إلى أنه يوجد حزمة مقابلة لكل مكتبة من المكتبات الّتي كنا نستخدمها في السابق مع أداة Gulp. فبدلًا من استخدام المكتبات الموجودة في Gulp مثل: gulp-eslint gulp-mocha gulp-nodemon etc يمكننا استخدام الحزم التالية في Webpack: eslint mocha nodemon etc نقلًا عن كوري هاوس في مقالته "لماذا تركت أداة Gulp و Grunt وتوجهت إلى NPM Scripts": يحدد كوري هاوس ثلاث مشاكل رئيسية وهي: مشكلة الاعتماد على منشئي الملحقات. مشكلة تنقيح الأخطاء المرهقة. مشكلة التوثيقات الرسمية المفككة والضعيفة. ومن وجهة نظري أتفق مع جميع هذه المشاكل. 1. مشكلة الاعتماد على منشئي الملحقات مثلًا عندما تُحدّث مكتبة مثل: eslint، ستحتاج المكتبة المرتبطة بها gulp-eslint إلى تحديث مناظر لكي يتوافقوا مع بعضهم بعضًا. فإذا فقد المشرف الاهتمام بالعمل على تعديل وصيانة المكتبة، فإن الإصدار المخصص لأداة gulp من هذه المكتبة لن يتزامن مع النسخة الأصلية للمكتبة. وينطبق نفس الشيء عند إنشاء مكتبة جديدة. فعلى سبيل المثال إذا قام شخص ما بإنشاء مكتبة "xyz" وأطلقها، واحتجت فجأة إلى نسخة مخصصة من المكتبة للعمل مع أداة Gulp مثل: gulp-xyz. بمعنى آخر، هذا النهج غير قابل للتوسّع. ومن الناحية المثالية، نريد نهجًا مثل Gulp ولكن بإمكانه استخدام المكتبات الأصلية مباشرة. 2. مشكلة تنقيح الأخطاء المرهقة على الرغم من أن المكتبات مثل gulp-plumber تساعد في تخفيف هذه المشكلة تخفيفًا كبيرًا، إلا أنه من المعروف أن الإبلاغ عن الأخطاء في gulp ليس مفيدًا جدًا. فإذا كان هناك تعليمة واحدة خاطئة في الأنبوب فإنها سترمي استثناءً غير قابل للمُعالجة، وعندما تلاحق المشكلة في المكدس ستظهر مشكلة تبدو غير مرتبطة تمامًا بالسبب الحقيقي للمشكلة الّتي ظهرت في الشيفرة البرمجية. لهذا السبب يمكن أن يجعل من علمية تنقيح الأخطاء كابوسًا في بعض الحالات. ومهما بحثت عن حلول لهذه المشاكل سواءً على محركات البحث مثل: Google أو موقع Stack Overflow فلن يساعدك هذا البحث فعليًا إذا كان الخطأ مبهمً أو مضللًا. 3. مشكلة الوثائق الرسمية المفككة والضعيفة في كثير من الأحيان ألاحظ أن أحد مكتبات gulp الصغيرة يكون توثيقها الرسمي محدودًا للغاية. أظن بأن هذا الأمر يرجعُ من أن المُنشئ عادة لهذه المكتبة يكون هدفه الأساسي استخداماته الخاصة. بالإضافة إلى ذلك من الشائع أن تنّظر إلى التوثيق الرسمي لكلّ من الملحقات الإضافية للأداة Gulp والمكتبة الأصلية (الّتي تعتمد عليها تلك الملحقات)، مما يعني الكثير من تبديل السياق وزيادة كمية القراءة إلى الضعف بسبب ذلك. الخاتمة يبدو لي أنه من الواضح جدًا أن Webpack أفضل من Browserify وأن NPM scripts أفضل من Gulp، على الرغم من أن كلّ خيارٍ منهم له فوائده وعيوبه. ومن المؤكد أيضًا أن تعابير وتعليمات Gulp أكثر مقروئية وملاءمة للاستخدام من NPM scripts، ولكنك ستدفع الثمن غاليًا في جميع عمليات التعقيد المضافة. قد لا تكون كلّ طريقة من طرق الإعداد السابقة مثالية لتطبيقك، ولكن إذا رغبت في تجنب عدد هائل من تبعيات التطوير وتجربة تنقيح الأخطاء المحبطة، فإن Webpack مع NPM scripts هي الطريقة المناسبة لك. آمل أن تجد هذه المقالة مفيدة في اختيار الأدوات المناسبة لمشروعك القادم. ترجمة -وبتصرف- للمقال Webpack or Browserify & Gulp: Which Is Better? لصاحبه Eric Grosse
  7. شهد مجال تطوير الوِب في السنوات الأخيرة تطورات هائلة على جميع المستويات والذي أدى إلى تحسنيات كبيرة على مستوى السرعة والجودة وقابلية الصيانة. ليس ذلك فحسب بل تعدى الأمر إلى إمكانية أتمتة بعض المهام الروتينية والتركيز على جودة العمل المُسلم ورفع الإنتاجية وذلك باستخدام أدوات مساعدة مثل Webpack، والتي تعدّ من أشهر الأدوات المساعدة بل إنها أصبحت عنصرًا أساسيًا في أي مشروع يُبنى بلغة جافاسكربت. حدثت بعض هذه التطورات على صعيد تطوير الواجهات الخلفية (Back-end) مثل ظهور Node.js والّتي تستخدم استخدامًا كبيرًا في هذه الأيام، وبعضها الآخر كان في تطوير الواجهات الأمامية (front-end)، ومن أبرز هذه التطورات هي النقلة النوعية للغة جافاسكربت ودعمها للعديد من المميزات والخصائص، والتي أدت في نهاية المطاف لجعلها واحدةً من أبرز الخيارات القوية في برمجة الوِب. بل وحتى إنها احتلت المرتبة الأولى في ترتيب أشهر لغات البرمجة شعبية لعام 2019 وذلك بحسب إحصائية موقع Stackoverflow. وكما أعلنت شركة Web3Techs أن لغة جافاسكربت مُستخدمة من قِبل حوالي 95% من مواقع العالم قاطبةً، وهي أيضًا على رأس قائمة "أكثر لغة مشهورة في برمجة الواجهات الأمامية" بحسب نفس الشركة. ولكن كيف جرت هذه التحولات السريعة والقوية بنفس الوقت لهذه اللغة؟ وما هي المراحل الأساسية الّتي مرت بها؟ وما هي الأدوات المختلفة الّتي ظهرت بالتزامن مع تطور هذه اللغة؟ وما هي أدوات البناء (مثل Gulp)؟ وما هو مجمع الوحدات (مثل Webpack)؟ ولماذا ظهر؟ وما هي مميزاته؟ سنحاول في هذا الدليل مرافقتكم في رحلة استكشافية للإجابة على هذه الأسئلة، ولنستعرض فيها أيضًا التاريخ العريق لهذه اللغة، ومعرفة الاسباب الرئيسية لتطورها وكيف احتلت بهذه السرعة المكانة العالية الّتي هي عليها اليوم. فهل أنت مستعد لمشاركتنا في هذه الرحلة؟ لمحة تاريخية بالعودة إلى زمن ما قبل الأدوات الحديثة كيف كان الحال آنذاك؟ في الحقيقة كانت الأمور بسيطة وسهلةً جدًا. سنبدأ رحلتنا بالتعرف على طرق استخدام لغة جافاسكربت في ملفات HTML. طرق استخدام لغة جافاسكربت يوجد طرقٌ عديدة يمكننا لتضمين الشيفرات البرمجية للغة جافاسكربت في ملفات HTML، يعتمد اختيارنا للطريقة بحسب حجم المشروع الّذي سنعمل عليه وسنذكر أهم الطرق المستخدمة من البداية وحتى يومنا الحالي. الشيفرة السطرية بدأت لغة جافاسكربت في كتابة شيفرتها البرمجية بهذه الطريقة البسيطة إذ أن الشيفرة البرمجية مكتوبة مباشرة في ملف HTML داخل وسم <script>. لا بدّ بأن معظمنا كتبَ شيفرة برمجية بهذه الطريقة في بداية تعلمه لهذه اللغة وذلك من كونها أسهل الطرق لتطبيق شيفرة برمجية معينة. في المثال التالي يحتوي الملف index.html على شيفرة جافاسكربت سطرية: <html> <head> <meta charset="UTF-8"> <title>Inline Example</title> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script type="text/javascript"> function add(a, b) { return a + b; } function reduce(arr, iteratee) { var index = 0, length = arr.length, memo = arr[index]; for(index += 1; index < length; index += 1){ memo = iteratee(memo, arr[index]) } return memo; } function sum(arr){ return reduce(arr, add); } /* Main Function */ var values = [ 1, 2, 4, 5, 6, 7, 8, 9 ]; var answer = sum(values) document.getElementById("answer").innerHTML = answer; </script> </body> </html> هذه الطريقة جيدة جدًا للبدء إذ لا يوجد أي ملفات خارجية أو تبعية ناشئة بين الملفات، ولكن هذه هي الطريقة المثالية لبناء شيفرة برمجية غير قابلة للصيانة وذلك بسبب المشاكل التالية: عدم إمكانية إعادة استخدام الشيفرة البرمجية: فإذا احتجنا إلى إضافة صفحة أخرى وهذه الصفحة تحتاج إلى بعض الوظائف المحققة في الشيفرة البرمجية الّتي كتبناها سابقًا في الملف السابق فيجب علينا حينها نسخ الشيفرة البرمجية المطلوبة ولصقها في الصفحة المراد تحقيق الوظائف فيها. عدم وجود ثبات في التبعية بين الشيفرة البرمجية: أنت مسؤول عن تنسيق التبعية بين الدوال المستخدمة على سبيل المثال إن كان هنالك دالة معينة تعتمد في وظيفتها على نتيجة دالة أخرى محققة قبلها فيجب علينا حينها الانتباه لهذا الأمر وعدم تغيير ترتيب تواجد الدوال في الشيفرة البرمجية. التضارب في المتغيرات العامة (Global Variables): جميع الدوال والمتغيرات ستكون موجودة على نطاق عام (Global Scope) وهذا بدوره سيؤدي إلى تضارب في المتحولات، ويحدث هذا عند ازدياد ضخامة المشروع وكتابة شيفرة برمجية كبيرة مما يجعل إمكانية إعادة استخدام نفس أسماء المتحولات أمر وارد الحدوث بقوة، وخصيصًا إن كان هنالك أكثر من مبرمج يعمل على نفس المشروع. استخدام الملفات الخارجية الطريقة الأخرى المستخدمة في كتابة الشيفرة البرمجية للغة جافاسكربت هي استخدام ملفات منفصلة إذ سنجزّء الشيفرة البرمجية إلى أجزاء صغيرة ونحملها تباعًا في ملف index.html. وبهذه الطريقة يمكننا استدعاء مكتبات منفصلة والّتي تقدم لنا وظائف إضافية مثل مكتبة moment (والتي تتيح لنا التلاعب بالتواريخ وإمكانية إجراء تحويلات معينة من نمط تاريخٍ معين إلى نمطٍ آخر). وبالإضافة إلى ذلك أدى استخدام الملفات المنفصلة في الشيفرة البرمجية إلى إتاحة الفرصة لنا بإعادة استخدام الشيفرة البرمجية أكثر من مرة ومن أي مكان نريد، وبذلك نكون تخلصنا من فكرة نسخ الشيفرة البرمجية من مكان ما ولصقها في مكان آخر متى ما أردنا استخدام هذه الشيفرة. الملف index.html هو الملف الّذي سيستدعي جميع التبعيات (ملفات جافاسكربت) الّتي سيحتاجها ويكون محتواه على الشكل التالي: <html> <head> <meta charset="UTF-8"> <title>External File Example</title> <!-- الملف الرئيسي الّذي سيستدعي ملفات جافاسكربت --> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script type="text/javascript" src="./add.js"></script> <script type="text/javascript" src="./reduce.js"></script> <script type="text/javascript" src="./sum.js"></script> <script type="text/javascript" src="./main.js"></script> </body> </html> إن هذا المثال يجمع عناصر المصفوفة الموجودة في الملف main.js ويظهرها في صفحة index.html ويكون محتوى الملفات على الشكل التالي: الملف add.js: function add(a, b) { return a + b; } الملف reduce.js function reduce(arr, iteratee) { var index = 0, length = arr.length, memo = arr[index]; index += 1; for(; index < length; index += 1){ memo = iteratee(memo, arr[index]) } return memo; } الملف sum.js function sum(arr){ return reduce(arr, add); } الملف main.js var values = [ 1, 2, 4, 5, 6, 7, 8, 9 ]; var answer = sum(values) document.getElementById("answer").innerHTML = answer; ولكن هذا الحل لم يكُ مثاليًا بل واجه المشاكل التالية: عدم وجود ثبات في التبعية بين الشيفرة البرمجية. التضارب في المتغيرات العامة مازالت موجودة. تحديث المكتبات أو الملفات المستدعاة سيكون يدويًا في حال ظهور نسخة جديدة للمكتبة (أو الملف). زيادة عدد طلبات HTTP بين المخدم والعميل: يؤدي زيادة الملفات المتضمنة في إلى زيادة الحمل على المخدم. فعلى سبيل المثال في الشيفرة السابقة سيحتاج كلّ ملف من الملفات الأربع طلب HTTP منفصل (أي أربع رحلات ذهاب وعودة من المخدم وإلى جهاز العميل) وبناءً عليه سيكون من الأفضل لو استخدمنا ملفًا واحدًا بدلًا من أربع ملفات منفصلة. كما في المثال التالي: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>External File Example</title> <!-- الملف الرئيسي الّذي سيستدعي ملفات جافاسكربت --> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script src="/dist/bundle.js"></script> </body> </html> استخدام كائن الوحدات (Module Object) ونمط الوحدات (Module Pattern) باستخدام نمط الوحدات (والذي تحدثنا عنه في مقال مفصّل) يمكننا أن نقلل التضارب في المتغيّرات العامة. إذ إننا سنكشف عن كائن واحد للمجال العام (Global Scope) وهذا الكائن سيحتوي على كافة الدوال والقيم الّتي سنحتاج إليها في تطبيق الوِب خاصتنا. في المثال التالي سنكشف عن كائن واحد وهو myApp للمجال العام (Global Scope)، وكلّ الدوال ستكون متاحة عن طريق هذا الكائن. والمثال التالي سيُوضح الفكرة: الملف my-app.js: var myApp = {}; الملف add.js: (function(){ myApp.add = function(a, b) { return a + b; } })(); الملف reduce.js: (function () { myApp.reduce = function (arr, iteratee) { var index = 0, length = arr.length, memo = arr[index]; index += 1; for (; index < length; index += 1) { memo = iteratee(memo, arr[index]) } return memo; } })(); الملف sum.js: (function () { myApp.sum = function (arr) { return myApp.reduce(arr, myUtil.add); } })(); الملف main.js: (function (app) { var values = [1, 2, 4, 5, 6, 7, 8, 9]; var answer = app.sum(values) document.getElementById("answer").innerHTML = answer; })(myApp); الملف index.html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JS Modules</title> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script type="text/javascript" src="./my-app.js"></script> <script type="text/javascript" src="./add.js"></script> <script type="text/javascript" src="./reduce.js"></script> <script type="text/javascript" src="./sum.js"></script> <script type="text/javascript" src="./main.js"></script> </body> </html> لاحظ أن كلّ ملف من الملفات غُلّف بطريقة نمط الوحدات ما عدا my-app.js إذ أن طريقة التغليف العامة المتبعة في نمط الوحدات هي على الشكل التالي: (function(){ /*... your code goes here ...*/ })(); بهذه الطريقة نجد أن كلّ المتحولات المحلية ستبقى ضمن مجال الدالة المستخدمة فيه. وبذلك لن يكون هنالك أي احتمالية لحدوث تضارب في المتغيرات العامة. وهكذا نكون حللنا مشكلة التضارب في المتغيرات العامة. سيكون الوصول إلى الدوال المعرفة في الملفات مثل (add و reduce ..إلخ) عن طريق ربط اسم الدالة مع الكائن myApp كما في المثال التالي: myApp.add(1,2); myApp.sum([1,2,3,4]); myApp.reduce(add, value); كما يمكننا أيضًا تمرير الكائن myApp كوسيط مثل ما فعلنا في ملف main.js وذلك من أجل تصغير أسم الكائن وجعل الشيفرة البرمجية أصغر حجمًا. تعدّ هذه الطريقة تحسنًا ممتازًا بالموازنة مع المثال السابق وفي الحقيقة إن أشهر مكتبات جافاسكربت مثل jQuery تستخدم هذه الطريقة؛ إذ أنها فقط تكشف عن متغير عام وهو $ وكل التوابع تُستدعى عن طريق هذا الكائن. في الحقيقة إننا إلى هذه اللحظة لم نصل إلى الحل النهائي إذ أن الحل السابق لا يزال يعاني من بعض المشاكل مثل: عدم وجود ثبات في التبعية بين الشيفرة البرمجية: نلاحظ في ملف index.html الملفات لا تزال بحاجة إلى وضعها وفق ترتيب معين يحافظ على التبعية بين الملفات إذ أن الملف myApp.js يجب أن يأتي قبل أي ملف وملف main.js يجب أن يأتي بعد كلّ الملفات. التضارب في المتغيّرات العامة: صحيح أننا قللنا عدد المتغيّرات العامة إلى الواحد ولكنها لا تزال موجودة. تحديث المكتبات: إن تحديث المكتبات (أو التبعيات أو أي ملف عمومًا) المستدعاة سيكون يدويًا في حال ظهور نسخة جديدة للمكتبة أو للتبعية. زيادة عدد طلبات HTTP بين الخادم والعميل: وذلك بعد زيادة عدد الملفات المستدعاة في ملف index.html. ظهور CommonJS جرت نقاشات عديدة في عام 2009 حول إمكانية جلب لغة جافاسكربت إلى الواجهات الخلفية (استخدامها من جانب الخادم) وفعلًا كان ذلك على يد مهندسٍ شاب يعمل لدى شركة موزيلا ويُدعى كيفن دانجور (Kevin Dangoor). قدمت CommonJS طريقة لتعريف الوحدات لحل مشكلة المجال في جافاسكربت من خلال التأكد من تنفيذ كلّ وحدة في فضاء الأسماء (namespace) الخاص بها وذلك بإجبار الوحدات على تصدير تلك المتغيّرات صراحةً (الذين نريد عرضهم واستخدامهم في المجال العام) وأيضًا تعريف تلك الوحدات المطلوبة للعمل بالشكل الصحيح مع بعضها بعضًا. بالإضافة إلى ذلك قدمت CommonJS واجهة برمجية مخصصة للجافاسكربت هذه المميزات فتحت أبصار العالم لإمكانيات هذه اللغة العظيمة، وجذبت اهتمام كبير من المطورين والذي انعكس في سرعة تطورها وتأقلمها مع جميع التغيّرات والمشاكل الّتي واجهتها. إن CommonJS ليست مكتبة جافاسكربت وإنما هي معايير تنظيمية لكتابة الشيفرة البرمجية (على سبيل المثال الطريقة الّتي خصصتها لاستيراد الوحدات استيرادً منظمًا) وهذه المعايير شبيه بالّتي تطرحها منظمة ECMA ‏(European Computer Manufacturers Association). ولتحقيق التنظيم في طريقة استدعاء الوحدات تقدم لنا CommonJS الدوال والأغراض المساعدة لذلك وهي: دالة require()‎: والّتي تسمح لنا باستيراد وحدات معينة في المجال المحلي الّذي نكون فيه. كائن الوحدة module.exports: والذي يسمح لنا بتصدير دالة ما من المجال الحالي إلى الوحدة. ولنأخذ مثلًا بسيطًا عن كيفية استخدام CommonJS: الملف moduleA.js: module.exports = function( value ){ return value*2; } الملف moduleB.js: var multiplyBy2 = require('./moduleA'); var result = multiplyBy2( 4 ); لاحظ أننا لم نستخدم الاسم الكامل للملف moduleA.js وإنما حذفنا اللاحقة، كما أن /. تشير إلى أن الوحدة moduleA موجودة في نفس المجلد الموجود فيه moduleB. وبفضل مشروع CommonJS ظهر أكبر مشروع معتمدًا عليه وهو Node.js وهي بيئة تشغيل لغة جافاسكربت مفتوحة المصدر وتعمل على جميع أنظمة التشغيل، والّتي تستطيع تشغيل شيفرة جافاسكربت خارج المتصفحات. بالإضافة إلى ذلك تسمح Node.js للمطوري الواجهات الخلفية باستخدام جافاسكربت لكتابة برمجيات تعمل من جهة الخادم وذلك لتوليد صفحات الوِب توليدًا ديناميكيًا قبل إرسالها إلى المتصفح، وكما تستطيع أيضًا التعامل مع الملفات وقواعد البيانات، ومختلف أنظمة الشبكات وخدمات أنظمة التشغيل. الوحدة غير المتزامنة AMD علِمنا إن الهدف الرئيسي الّذي بنيت عليه CommonJS هو استخدامها في الواجهات الخلفية (من طرف المخدم) ولذلك مشكلة استدعاء الوحدات استدعاءً متزامنًا لم تكُ مشكلة في ذلك الحين، بل ولم تكُ لتظهر لولا إصرار مجتمع المطورين على جلب CommonJS إلى الواجهات الأمامية ولنُلخص مشكلة CommonJS هي عندما نستدعي الوحدة معينة في ملف ما ولتكن مثلًا add كما في السطر التالي: var add=require('add'); سيتوقف النظام حتى تصبح الوحدة add جاهزة؛ أي أن هذا السطر البرمجي سيجمد المتصفح أثناء تحميل هذا الملف. ماذا لو كان هنالك أكثر من وحدة مطلوبة كيف ستكون الأمور عندها؟ لذلك إنها ليست أفضل طريقة لتعريف الوحدات من جانب المتصفح. من أجل نقلِ صياغة تعريف وحدة ما من صياغة يفهمها الخادم إلى صياغة يفهمها المتصفح قدمت لنا CommonJS العديد من التنسيقات لتعريف الوحدات وكانت واحدة من أشهرها هي تعريف الوحدات بالطريقة غير المتزامنة (Asynchronous Module Definition) والّتي تُعرف إختصارًا AMD وتكون طريقة تعريفها كما في المثال التالي: define([‘add’, ‘reduce’], function(add, reduce){ return function(){...}; }); إن الدالة define تأخذ قائمة بالتبعيّات الموجودة والتي مرّرناها لها كقائمة وستُعيد النتيجة إلى الدالة المجهولة (Anonymous function) كوسطاء (الدالة المجهولة هي الدالة الّتي ليس لديها اسم ولقد فصلنا في مقالٍ سابق كيفية استخدمها وذلك في سلسلة تعلم جافاسكربت). وسيكون ترتيب التبعيات بنفس الترتيب الموجود في القائمة ومن ثم ستُعيد الدالة المجهولة النتيجة والتي سنُصدرها ونستخدمها في نهاية المطاف. هذه الطريقة تُكافئ الطريقة السابقة لاستدعاء الوحدات (التبعيات) لأنها تعطي نفس النتائج الوظيفية، إلا أن هذه الطريقة تستخدم التحميل غير المتزامن للوحدات. إن CommonJS و AMD حلّت آخر مشكلتين متبقيتين مع نمط الوحدات وهما على الشكل التالي: عدم وجود ثبات في التبعية بين الشيفرة البرمجية. التضارب في المتغيرات العامة. نحن فقط سنهتم بالتبعيات الموجودة من أجل كلّ وحدة (أو ملف) وبالتأكيد في هذه الحالة لا يوجد هناك أي تضارب في المتغيرات العامة. مُحمل الوحدات RequireJS في الحقيقة إن طريقة استخدام AMD مع CommonJS كانت مفيدة جدًا، ولكن كيف يمكننا استخدامها في المتصفح وهنا جاء محمل الوحدات RequireJS إلى الساحة والّذي سيساعدنا لتحميل الوحدات تحميلًا غير متزامن AMD. والذي يعتبر من أوائل التطبيقات الفعلية لمكتبة CommonJS مع AMD. على الرغم من إسمها، إلا أن هدفها ليس دعم بناء جملة 'require' في CommonJS. إن RequireJS تُتيح لنا كتابة وحدات من نمط AMD. ملاحظة: قبل أن تطبق المثال التالي، يجب عليك تنزيل ملف require.js من موقعه الرسمي. لاحظ أن الاستدعاء الوحيد الموجود في ملف index.html هو: <script data-main=”main” src=”require.js”> </script> هذا الوسم سيُحمِّلُ محليًا مكتبة require.js إلى الصفحة، ومن بعدها السمة data-main في الوسم <script> ستخبر المكتبة من أي ملف ستبدأ. بعد أن تستدعي require.js ملف main.js سيقودنا هذا الملف إلى التبعيات المتعلقة به، وهكذا إلى أن نحمل جميع التبعيات (الملفات) المطلوبة. ملاحظة: استخدمنا main فقط بدون الإشارة إلى اللاحقة والتي هي js وذلك لأن هذه المكتبة تفترض بأن كلّ القيم الّتي سنُسندها لهذه الخاصية ستكون ملفات جافاسكربت. وسيكون تحميل التبعيات للمثال السابق كما في الصورة التالية: نلاحظ أن المتصفح يحمّل الملف index.html والملف بدوره يحمّل المكتبة require.js والّذي سيتكفل ببقية الملفات الأخرى. وبهذا نكون حللنا جميع المشاكل الّتي واجهتنا حتى هذه اللحظة، ولكن وكما هي العادة في عالم البرمجة في كلّ محاولة لإصلاح مشكلةٍ ما تظهر مشكلةٌ أخرى، ولكن عادة ما تكون أخف من سابقتها في التأثير. ومن المشاكل الّتي ظهرت مع هذا الحل هي: صياغة AMD طويلة ومضجرة: إذ أن كلّ شيء يجب تغليفة بالدالة define ولذا يوجد مسافة بادئة (يُقصد تعريف الدالة define) للشيفرة البرمجية وهذه المشكلة يمكن ألا تظهر مع الملفات الصغيرة ولكن ما إن يكبر حجم الملف وتزداد تفاصيله ستصبح مشكلة كبيرة. قوائم الاعتماديات الموجودة في المصفوفة: إن قائمة الاعتماديات الموجودة في المصفوفة يجب أن تتشابه تمامًا مع القائمة المررة كوسيط للدالة وإذا كان لدينا العديد من التبعيات ستزداد الأمور تعقيدًا. في النسخة الحالية من HTTP للمتصفحات تحميل العديد من الملفات الصغيرة سيخفف من الأداء (وخصيصًا بدون استخدام أي تقنيات مساعدة مثل: ذاكرة التخزين المؤقت Cache). مجمع الوحدات أو مجمع الحزم (Module Bundler) انطلاقًا من الأسباب السابقة أراد بعض الأشخاص بناء التعليمات من خلال CommonJS لكن هذه الأخيرة مخصصة للعمل على الخوادم وليس المتصفح وهي تدعم التحميل المتزامن أيضًا. بقيت هذه الإشكالية عصية على الحل حتى جاء مجمع الوحدات Browserify لينقذ الموقف ويقدم لنا حلولً مناسبة. وهو يعدّ أول مجمع وحدات وجد آنذاك، وكان باستطاعته تحويل الوحدات المكتوبة بصياغة CommonJS والتي لا يستطيع المتصفح أن يفهمها بطبيعة الحال (وذلك لأنها بُنيت بالأساس للتعامل مع الخادم) إلى صياغة يفهمها المتصفح. يمكننا التعامل مع مجمع الحزم Browserify من خلال سطر الأوامر إذ يمكنك إعطاؤه أمرًا ما وتمرير بعض الخيارات الإضافية المتاحة لكل أمر من الأوامر الموجودة. وهو يعتمد في بنيته على مدير الحزم npm وبيئة Node.js. يمكن لمُجمع الوحدات Browserify تجميع شجرة التبعيات للشيفرة البرمجية الخاصة بك وتحزيمها في ملف واحد. وأيضًا يحل مشكلة عدم إمكانية الوصول إلى الملفات من قبل المتصفح إذ إنه يبحث عن جميع تعليمات require (والتي لا يمكن للمتصفح أن يستدعي الملف المطلوب لأنه لا يملك الصلاحيات المناسبة لذلك) فيستبدلها بمحتوى الملف المراد تضمينه (وذلك انطلاقًا من اعتماده على Node.js والتي تستطيع الوصول إلى الملفات) وهكذا يصبح الملف جاهزًا للتنفيذ في المتصفح ولا يواجه أي مشكلة. حلول كثيرة فأي منها سنستخدم؟ إذا لدينا الكثير من الخيارات المتاحة فأي واحدة منهم سنستخدم في مشروعنا القادم؟ إذ إننا حتى هذه اللحظة ناقشنا العديد من الخيارات المتاحة لكتابة الوحدات مثل: نمط الوحدات (Module Pattern) وطريقة CommonJS مع AMD وطريقة RequireJS فأي منهم سنعتمده لمشروعنا القادم؟ الجواب: ولا واحدة منها. كما نعلم بأن لغة جافاسكربت لم تكُ تدعم نظام الوحدات في أصل اللغة، ولهذا نلاحظ وجود العديد من الخيارات المتاحة لتعويض هذا النقص. ولكن هذا الأمر لم يستمر طويلًا إذ بعد تحديث المواصفات القياسية للغة جافاسكربت ES6 أصبح وأخيرًا نظام الوحدات جزءًا أساسيًا منها وهذا يكون جواب سؤالنا الرئيسي أي الخيارات سنستخدم؟ إنها طريقة ES6 (تحدثنا في سلسلة مقالاتٍ سابقة عن المميزات الجديدة لهذا الإصدار من لغة جافاسكربت ES6). تُستخدم التعليمة import و export لاستيراد وتصدير الوحدات في التحديث الجديد ES6. وإليك مثالًا عمليًا يوضح لك كيفية استخدامها: الملف main.js: import sum from "./sum"; var values = [ 1, 2, 4, 5, 6, 7, 8, 9 ]; var answer = sum(values); document.getElementById("answer").innerHTML = answer; الملف sum.js: import add from './add'; import reduce from './reduce'; export default function sum(arr){ return reduce(arr, add); } الملف add.js: export default function add(a,b){ return a + b; } الملف reduce.js: export default function reduce(arr, iteratee) { let index = 0, length = arr.length, memo = arr[index]; index += 1; for(; index < length; index += 1){ memo = iteratee(memo, arr[index]); } return memo; } في الحقيقة دعم جافاسكربت لنظام الوحدات بهذا الشكل المختصر قلبَ مجريات الُلعبة، بل إن نظام الوحدات هذا سيحكم عالم جافاسكربت في نهاية المطاف. إنها باختصار مستقبل لغة جافاسكربت. ولكن! (أعلم بأنك سئمت من هذه الكلمة ولكن يجب علينا إكمال بقية جوانب هذه الطريقة لتوضيح جميع تفاصيل المشهد لديك) هذا التحديث من اللغة لم تدعمه جميع المتصفحات المستخدمة في هذا اليوم، أو لنكن أكثر دقة ما تزال بعض المتصفحات لا تدعم هذه التحديث وخصوصًا المتصفحات القديمة وفي الحقيقة نسبة المستخدمين لهذه المتصفحات كبيرة وتؤخذ بعين الإعتبار. إذا ما الّذي يجب علينا فعله الآن؟ وكيف سنحوّل الشيفرة البرمجية من الإصدار ES6 إلى الإصدار ES5؟ هنا يأتي دور أهم أداة سنتعرف عليها اليوم ألا وهي مجمع الوحدات Webpack. ما هي Webpack؟ هي عبارة عن مجمع واحدات (Module Bundler) أو أداة بناء (Build Tool) مثل أداة Browserify وهي تحول شجرة تبعية الملفات وتُجمعها في ملف واحد. ليس ذلك فحسب وإنما تحوي على الكثير من المميزات الأخرى نذكر منها: تقسيم الشيفرة البرمجية: عندما يكون لدينا تطبيقات متعددة تتشارك نفس الوحدات يمكننا من خلال هذه الأداة تجميع الشيفرة البرمجية في ملفين أو أكثر. فمثلًا إذا كان لدينا التطبيقين التاليين app1 و app2 ويشترك كلاهما في العديد من الوحدات إذا استخدمنا Browserify سيكون لدينا app1.js و app2.js وكل ملف منهم مجمع فيه الشيفرات البرمجية الخاصة بكل تطبيق، بينما مع أداة Webpack يمكننا إنشاء ملف app1.js وملف app2.js وبالإضافة إلى الملف المشترك shared-lib.js. نعم ستضطر إلى تحميل ملفين في صفحة Html ولكن مع إمكانية استخدام تقنيات مساعدة مثل: التخزين في الذاكرة المؤقتة للمتصفح (Cache) واستخدام شبكة توصيل المحتوى الموزعة CDN ‏(Content Delivery Network) كلّ هذه التقنيات ستقلل من وقت التحميل الإبتدائي للصفحات. المُحملات (Loaders): مع استخدام المُحمل المخصص يمكنك تحميل أي ملف إلى التطبيق إذ يمكنك استخدام الدالة reuiqre ليس فقط لتحميل ملفات جافاسكربت فقط (مثلما كانت أداة Browserify) وإنما ملفات التنسيقات وملفات SaSS وملفات Less بالإضافة إلى إمكانية تحميل الصور والخطوط والملفات والكثير غيرها. الملحقات (Plugins): تقدم Webpack ميزة الملحقات مجموعة واسعة من المهام مثل تحسين الحزمة وإدارة الملحقات (مثل الصور) بالإضافة إلى ذلك يمكننا حتى التلاعب بالملفات قبل تحميلها وتحزيمها في الملف الهدف (على سبيل المثال إمكانية ضغط الصور قبل رفعها على المخدم سنتطرق لهذه الميزّة لاحقًا في هذا الدليل). نظام الأوضاع (Mode): توفر لك هذه الأداة ثلاث أنواع من الأوضاع وضع التطوير ووضع الإنتاج أو بدون وضع. باختصار يستخدم كلّ وضع من الأوضاع من أجل سيناريو معين: وضع التطوير: يستخدم عند العمل في مرحلة التطوير لمشروع الوِب وتكون الشيفرة البرمجية مقروءة ومفهومة. وضع الإنتاج: يستخدم عند العمل في مرحلة عرض مشروع الوِب على الإنترنت وتكون الشيفرة البرمجية مختصرة وغير مقروءة. بدون وضع: يكون الشيفرة الّتي استخدمت في مرحلة التطوير هي ذاتها الّتي ستعرض على الإنترنت بدون أي تعديل. تسهل عملية تحويل الشيفرات البرمجية إلى إصدار أقدم (Transpiling): إمكانية تحويل شيفرات جافاسكربت البرمجية الحديثة مثل ES6 والّتي لا تدعمها بعض المتصفحات إلى شيفرات جافاسكربت البرمجية القديمة مثل ES5 من خلال Babel على سبيل المثال، وبذلك نكون ضربنا عصفورين بحجر واحد أولهما أننا كتبنا التطبيق بالإصدار الحديث من اللغة، وثانيهما أننا استطعنا تشغيل التطبيق على كافة المتصفحات. أليس هذا رائعًا؟ لابد بأنك متحمسٌ جدًا للتعرف على هذه الأداة والبدء في استخدامها على الفور في مشاريعك القادمة إذًا هيا بنا نبدأ لنتعرف عليها أكثر ونتعلم كيفية استخدامها. مفاهيم أساسية قبل الشروع في العمل مع هذه الأداة لا بدّ لنا من التعرف على بعض المفاهيم الرئيسية والتي سنستخدمها بكثرة في الأمثلة ملف الإعداد webpack.config.js :هو عبارة عن ملف يحدد كيفية تعامل الأداة Webpack مع بعض الخصائص للمحملات أو الملحقات وبعض خصائص الأداة نفسها. وعند إنشائنا لمشروع جديد لن نجده في مجلد المشروع وذلك بسبب ميزة التعديلات الصفرية (zero configuration) الجديدة الّتي جاءت مع الإصدار الرابع أو الأحدث من هذه الأداة والتي تمكننا من استخدام الأداة بدون الحاجة لأي تعديل في ملف الإعداد. بل يمكننا عدم إنشاؤه من الأساس. يمكن تخصيص هذا الملف تخصيصًا بسيطًا أو متقدمًا وذلك بحسب المشروع الّذي تعكفُ على تطويره، وهنالك بعض الخصائص الأساسية المشتركة في كلّ المشاريع، والّتي يجب التنويه إليها: الخاصية Entry: تحدد هذه الخاصية ملف الأولي من الشروع الّذي سنبنيه (نجمعه) في أول التنفيذ. الخاصية Output: تحدد مجلد المشروع الّذي سنستخدمه في مرحلة الإنتاج (أو النشر) يكون فيه الشيفرة البرمجية الّتي نريد استخدامها لنشر المشروع على الإنترنت. تحتوي هذه الخاصية على بعض الخيارات نذكر منها: filename: نحدد فيها أسم الملف الّذي نريد تجميع الحزم فيه. path: نحدد فيها مسار الملف الّذي نريد تجميع الحزم فيه. الخاصية Loaders: تحدد المحملات الّتي نريد أن نستخدمها مع Webpack. كلّ مُحمل يحتوي على بعض الخيارات نذكر منها: test: تحدد نوع الملفات الّتي سيُحملها هذا المُحمل (يمكننا استخدام التعابير النمطية في تحديد الملفات). exclude: الملفات الّتي نريد استبعادها (والتي من الممكن أن تحقق الخاصية الأولى). use: ما هو المُحمل الّذي سنستخدمه لإجراء التغييرات على الملفات المقبولة في test ولم تُستبعد في الخاصية exclude. الخاصية Plugins: تحدد هذه الخاصية الملحقات الّتي نريد استخدامها وكما تحدد بعض الخيارات لهذه الملحقات. الخاصية Mode: تحدد هذه الخاصية الوضع الّذي نريد العمل عليه أي طريقة نشر المشروع إلى مجلد الخرج (output). كانت هذه أبرز المفاهيم الأساسية الّتي سنتعامل معها في الأمثلة القادمة. إعداد بيئة التطوير بما أن مجمعات الحزم (الوحدات) تعتمد على Node.js اعتمادً أساسيًا للوصول إلى نظام الملفات من أجل تجميع الاعتماديات بشكلها النهائي لذا لابد لنا من تثبيت Node.js في البداية وإليك الخطوات الكاملة لتثبيته على نظام التشغيل ويندوز (يمكنك الاطلاع على مقال سابق تحدثنا فيه عن كيفية تثبيت Node.js على نظام لينكس): ندخل إلى الموقع الرسمي الخاص ببيئة Node.js ونحمل النسخة الموافقة لنظام التشغيل الخاص بك (يفضل تحميل الإصدارات ذات الدعم الطويل والتي تُدعى LTS). بمجرد إنتهاء التنزيل نفتح الملف المُنزّل. سيسألك معالج التثبيت عن موقع التثبيت والمكونات الّتي تريد تضمينها في عملية التثبيت يمكنك ترك تلك الخيارات بوضعها الافتراضي. انقر فوق تثبيت وانتظر حتى ينتهي معالج التثبيت. تهانينا أصبحت بيئة Node.js جاهزة للعمل. ملاحظة: يمكنك التأكد من تثبيت البيئة تثبيتًا صحيحًا من خلال تنفيذ الأمر التالي على سطر الأوامر (Command line) node –v يجب أن يظهر لك نسخة Node.js المثبتة وفي حالتنا ستظهر 12.16.1. كما يمكنك التأكد من تثبيت مدير الحزم Node Package Manager والّذي يُعرف اختصارًا npm من خلال الأمر npm –v يجب أن تظهر لك نسخة npm المثبتة وفي حالتنا ستظهر 6.13.4. نحن جاهزون الآن لإنشاء مشروع جديد وتثبيت Webpack! إنشاء مشروع جديد وتثبيت Webpack في البداية ننشئ مجلدًا جديدًا للمشروع وندخل إليه عبر التعليمات التالية: $ mkdir project; cd project ثم ننشئ مشروعًا جديدًا عبر التعليمة التالية: $ npm init -y ثم نثبت أداة Webpack عبر التعليمة التالية: $ npm install -D webpack webpack-dev-server يجب أن يظهر لك نتيجة مماثلة للصورة التالية: الآن لننشئ بنية الملفات الهرمية التالية: webpack-demo |- package.json + |- index.html + |- /src + |- index.js ملاحظة: جرى عرض الملفات في هذه المقالة بأسلوب عرض التغييرات في git فالأسطر الّتي بجانبها إشارة موجبة + يجب عليك إضافتها والّتي بجانبها إشارة سالبة - يجب عليك حذفها. الآن نفتح ملف index.js الموجود في مجلد src ونجري عليه التعديلات التالية: unction component() { const element = document.createElement('div'); // Lodash, currently included via a script, is required for this line to work element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component()); ونعدل الملف index.html الموجود في مجلد webpack-demo ونجري عليه التعديلات التالية: <!doctype html> <html> <head> <title>Getting Started</title> <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> <script src="./src/index.js"></script> </body> </html> كما يجب علينا أن نعدل ملف package.json لتفعيل الوضع الخاص كي نمنع النشر العرضي للشيفرة البرمجية الخاصة بنا ليصبح على الشكل التالي: { "name": "webpack-demo", "version": "1.0.0", "description": "", + "private": true, - "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.20.2", "webpack-cli": "^3.1.2" }, "dependencies": {} } لمزيد من المعلومات حول التفاصيل الداخلية لملف package.json ننصحك بأخذ جولة في التوثيق الرسمي الخاص به. في المثال السابق هنالك تبعيات ضمنية إذ أن الملف index.js يعتمد على loadash (وهي مكتبة تساعد المبرمجين على كتابة شيفرة برمجية أكثر إيجازًا وتزيد من قابلية الصيانة) في عمله وبناءً عليه يجب أن يكون loadash مُضمن قبل أن تعمل الشيفرة البرمجية للملف index.js. ولكن إن الملف index.js لم يُصرح بوضوح عن حاجته لهذه المكتبة وإنما افترض أنها موجودة ضمن المتحولات العامة. في الحقيقة إن إدارة المشروع بهذه الطريقة تعدّ مشكلة وذلك للأسباب التالية: ليس من الواضح أن الشيفرة البرمجية للملف index.js تعتمد على مكتبة خارجية. إذا كانت التبعية مفقودة، أو ضُمنت في الترتيب الخطأ، فلن يعمل التطبيق بالطريقة الصحيحة. إذا ضُمنت تبعيةً ما ولكن لم تُستخدم، سيضطر المتصفح إلى تنزيلها مع أنها غير ضرورية. لنستخدم Webpack لإدارة هذه المشروع بدلًا من الطريقة الحالية. إنشاء حزمة باستخدام Webpack سنعدل بنية المشروع قليلًا لفصل الشيفرة البرمجية الّتي سنعمل عليها عن الشيفرة البرمجية الّتي سننشرها. وتجدر الإشارة إلى أن الشيفرة البرمجية الّتي سننشرها هي الناتج المصغّر والمحسّن لعملية البناء الناتجة عن الشيفرة الّتي كتبناها والتي ستُحمّل في نهاية المطاف في المتصفح. إذًا سنضع الشيفرة البرمجية الّتي سنعمل عليها في المجلد src أما الّتي سننشرها ستكون في مجلد dist أي ستكون بهذا الشكل: webpack-demo |- package.json + |- /dist + |- index.html - |- index.html |- /src |- index.js لتحزيم مكتبة loadash (والّتي هي تبعية في ملف index.html) باستخدام الملف index.js سنحتاج أولًا إلى تثبيت هذه المكتبة محليًا باستخدام الأمر التالي: npm install --save lodash عند تثبيت حزمة (مكتبة) معينة والّتي سنحتاجها في عملية التحزيم النهائية قبل النشر النهائي يجب علينا إضافة install --save أما إذا أردت تثبيت حزمة (مكتبة) معينة لمرحلة التطوير فقط يجب عليك إضافة install --save-dev. لمزيد من المعلومات ننصحك بالإطلاع على التوثيق الرسمي لمدير الحزم NPM. الآن لنضيف تعليمة استيراد الحزمة في الشيفرة البرمجية للملف index.js الموجود في المجلد src كما في الشكل التالي: + import _ from 'lodash'; + function component() { const element = document.createElement('div'); - // Lodash, currently included via a script, is required for this line to work element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component()); بما أننا قمنا باستيراد مكتبة loadash في الملف السابق لنعدل الملف index.html بما يتوافق مع ذلك ليكون كما في الشكل التالي: <!doctype html> <html> <head> <title>Getting Started</title> - <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> - <script src="./src/index.js"></script> + <script src="main.js"></script> </body> </html> ملاحظة: يتطلب ملف index.js صراحة وجود المكتبة (أو أي تبعية إذا أردنا تعميم الفكرة) loadash ويربطه كمتحول _ (أي لا يوجد تضارب في المجال). من خلال تحديد التبعيات الّتي تحتاجها الوحدة، يمكن لمُجمع الوحدات (المقصود Webpack) استخدام هذه المعلومات لإنشاء مخطط بياني للاعتماديات (dependency graph). ثم يستخدم الرسم البياني لإنشاء حزمة محسنة والّتي ستُنفذ الاستدعاءات بالترتيب الصحيح. لننفذ التعليمة التالية npx webpack والتي ستأخذ الشيفرة البرمجية في الملف index.js وهو القيمة المسندة للخاصية entry وتنشر الخرج في ملف main.js والذي سيكون القيمة في المسندة للخاصية output. إن تعليمة npx والتي تأتي مع نسخة 8.2 من Node.js أو أحدث، و 5.2.0 من مدير الحزم NPM أو أحدث. إذ تعمل على أداة Webpack الثنائية الموجودة في (‎./node_modules/.bin/webpack) الّتي ثبتناها في البداية. ويكون ناتج التنفيذ كما يلي: npx webpack ... Built at: 13/06/2018 11:52:07 Asset Size Chunks Chunk Names main.js 70.4 KiB 0 [emitted] main ... WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/ ملاحظة: من الممكن أن يختلف الناتج الّذي سيظهر لك بعض الشيء ولكن إذا نجحت عملية البناء فلا تقلق من رسالة التحذير فإن الأمور على ما يرام. افتح الملف index.html يجب أن يظهر لك Hello webpack فإذا ظهرت لديك تهانينا هذا يدلّ على أنك أنجزت جميع الخطوات بنجاح. إذا ظهرت لديك رسالة خطأ في صياغة ملف جافاسكربت المصغّرة (minified) وذلك عند فتحك لملف index.html فعيّن وضع التطوير ومن ثم شغل الأمر npx webpack من جديد. هذا الخطأ يتعلق بتشغيل حزمة الوٍب npx على أحدث نسخة من Node.js (الإصدار 12.5 أو الأحدث) بدلًا من الإصدار ذو الدعم الطويل LTS. الوحدات في المواصفات القياسية لنسخة جافاسكربت ES6 دُعمت تعليمتي import وexport إذ أن معظم المتصفحات تدعمها في الوقت الحالي (ولكن يوجد بعض المتصفحات لا تدعمها) وWebpack ليست استثناءً بل إنها تدعمها دعمًا متميزًا. تدعم Webpack هذه الخاصية من خلال تحويل (transpiles) الشيفرة البرمجية المقابلة للتعليمتين import وexport إلى نسخة أقدم من ES6 مثل ES5 وبذلك تؤمن فهم المتصفح ما تعنيه هذه التعليمتين باللغة الّتي يفهمها. إضافةً إلى ذلك يدعم Webpack العديد من صيغ الوحدات الأخرى لمزيد من المعلومات يمكنك زيارة التوثيق الرسمي. ملاحظة: إن Webpack لن يحوّل أي تعليمة برمجية عدا تعليمتي import وexport ولذلك في حال كنت تستخدم مميزات أخرى من المواصفات القياسية ES6 فعندها يجب عليك استخدام محولات المخصصة لذلك مثل Babel أو Bublé. استخدام ملف الإعداد إن جميع الإصدارات الّتي جاءت بعد الإصدار الرابع من Webpack تدعم ميزة التعديلات الصفرية الّتي تحدثنا عنها سابقًا في هذا الدليل، ولذا إذا أردنا أن نخصص بعض الإعدادات في المشروع لا بد لنا من إنشاء ملف الإعداد إنشاءً يدويًا. إذًا سنضيف ملف الإعداد على بنية الملفات وستصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json + |- webpack.config.js |- /dist |- index.html |- /src |- index.js وسنُضيف إليه بعض التعليمات المهمة والتي سنستخدمها كثير في المشروع وبذلك ستتحسن إنتاجيتنا أكثر من ذي قبل. وتكون الإضافة كما يلي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), }, }; أما الآن لنجرب تنفيذ التعليمة التالية: npx webpack --config webpack.config.js ... Asset Size Chunks Chunk Names main.js 70.4 KiB 0 [emitted] main ... WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/ ملاحظة: في حالة وجود أكثر من ملف للإعداد تلتقط التعليمة Webpack ذلك إلتقاطًا إفتراضيًا. ونستخدم خيار ‎--config وبعده اسم الملف لتوضيح فكرة أنه بإمكانك تمرير أسم أي ملف تريده تمريرًا يدويًا، وهذا سيكون مفيدًا جدًا لملفات الإعداد الأكثر تعقيدًا والتي سنحتاج لتقسيمها إلى ملفات متعددة. يتيح ملف التكوين مرونة أكبر بكثير من استخدام سطر الأوامر CLI ‏(Command Line Interface) البسيط. إذ يمكننا تحديد وتثبيت قواعد معينة للمُحمل (Loader) والملحقات (Plugin) وتخصيص الخيارات بالإضافة للعديد من التحسينات الأخرى. لمزيد من المعلومات يمكنك الإطلاع على التوثيق الرسمي لملف الإعداد. إنشاء إختصار لتعليمة البناء يمكننا استخدام مميزات Webpack لجعل الأمور أسهل من خلال وضع بعض اللمسات الجمالية مثل اختصار بعض الخطوات، وذلك من خلال كتابة الأوامر في ملف package.json وتحديدًا في scripts. وبذلك نختصر على أنفسنا عناء كتابة بعض التعليمات الطويلة والمُملة. إذًا لنعدل ملف package.json ليصبح على الشكل التالي: { "name": "webpack-demo", "version": "1.0.0", "description": "", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.20.2", "webpack-cli": "^3.1.2" }, "dependencies": { "lodash": "^4.17.5" } } يمكننا الآن استخدام الأمر npm run build بدلًا من الأمر npx الّذي استخدمنا سابقًا. لاحظ بأنه يمكننا دائمًا الإشارة إلى الحزم المثبتة محليًا في مدير الحزم npm في السمة scripts في الملف package.json بنفس الطريقة الّتي استخدمناها مع التعليمة npx. هذا الطريقة هي متعارف عليها في معظم المشاريع القائمة على مدير الحزم npm لأنه يسمح لجميع المساهمين لاستخدام نفس التعليمات المشتركة (وحتى مع بعض الخيارات مثل ‎--config). ملاحظة: يمكنك تمرير الخيارات الخاصة لتعليمة ما من خلال إضافة شرطتين -- بين الأمر npm run build والخيارات الّتي نريد تخصيصها مثل npm run build -- --colors. npm run build ... Asset Size Chunks Chunk Names main.js 70.4 KiB 0 [emitted] main ... WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/. أما الآن وبعد أن تعلمنا الأساسيات عن كيفية استخدام Webpack لننتقل إلى الاستخدامات الأهم لهذه الأداة مثل إدارة الصور والخطوط ..إلخ. إذا نفذت جميع التعليمات السابقة تنفيذًا صحيحًا يجب أن يكون البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- main.js |- index.html |- /src |- index.js |- /node_modules ملاحظة: إذا كنت تستخدم الإصدار الخامس من مدير الحزم npm من الممكن أن ترى ملفًا إضافيًا اسمه package-lock.json. استخدام Webpack لإدارة الملحقات بعد أن تعلمنا أساسيات Webpack وإنشأنا مشروعًا صغيرًا يعرض "Hello Webpack"، سنحاول الآن أن نركز أكثر على الأمور المهمة والتي تخدمنا بها هذه الأداة مثل إدارة ملفات التنسيق والصور وسنرى بالضبط كيف تتعامل هذه الأداة مع كلٍّ منهم. يستخدم مطورو الواجهات الأمامية أدوات بناء مثل: Grunt و Glup لمعالجة هذه الملحقات ونقلها من مجلد src إلى مجلد dist أو حتى لإنشاء مجلد جديد لهذه الملحقات، تستخدم Webpack نفس الفكرة للتعامل مع الوحدات، بالإضافة إلى أن Webpack تجمع كلّ التبعيات ديناميكيًا وتنشئ ما يعرف بمخطط التبعيات وهذا أمر رائع لأن كلّ وحدة (Module) توضح صراحة ما هي تبعياتها وبذلك نتجنب تجميع الوحدات غير المستخدمة في المشروع. واحدة من أروع مميزات Webpack هي إعطاؤك إمكانية تضمين أي نوع آخر من الملفات، إلى جانب جافاسكربت، ولهذه الفكرة تحديدًا أنشئ المحمل (Loader). أي يمكن تطبيق نفس المزايا المذكورة أعلاه (التبعيات المستخدمة من قبل الوحدات) على كلّ شيء مستخدم في إنشاء المواقع أو تطبيقات الوِب أيضًا. إدارة ملفات التنسيق CSS في البداية سنعدل قليلًا في بنية الملفات وبعض الملفات قبل أن ندير ملفات التنسيق. سنعدل الملف dist/index.html ليصبح كما يلي: <!doctype html> <html> <head> - <title>Getting Started</title> + <title>Asset Management</title> </head> <body> - <script src="main.js"></script> + <script src="bundle.js"></script> </body> </html> وكما سنعدل أيضًا ملف الإعداد webpack.config.js ليصبح: const path = require('path'); module.exports = { entry: './src/index.js', output: { - filename: 'main.js', + filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, }; وبذلك يُصبح كلّ شيء جاهز لنبدأ. أولًا لنثبت محمل ملفات التنسيق css-loader الّذي سيساعدنا في معالجة تعليمة الاستيراد import الّتي سنستخدمها أيضًا من أجل استيراد ملفات التنسيق ومحمل التنسيق style-loader الّذي سيساعدنا في أخذ ملف التنسيق ووضعه في ملف (أو ملفات) تنسيق منفصلة. إذًا لنُنفذ الأمر التالي: npm install --save-dev style-loader css-loader ولنُعدل ملف الإعداد webpack.config.js ليحوي المعلومات اللازمة لحزم المُحمل (Loader) الّتي ثبتناها للتو وسيصبح الملف على الشكل التالي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + 'style-loader', + 'css-loader', + ], + }, + ], + }, }; ملاحظة: تستخدم Webpack التعابير النمطية (Regular Expression) لتحديد الملفات الّتي يجب البحث عنها وتقديمها إلى مُحمل (Loader) محدد. في الحالة السابقة نلاحظ أنه ستُقدم جميع ملفات التنسيق (ذات اللاحقة css) إلى المُحمل style-loader والمُحمل css-loader. وهذا بدوره سيمكنك من استيراد ملف التنسيق الّذي سيكون مثل هذا import './style.css' إلى الملف الّذي يعتمد على ملف التنسيق هذا. عند تشغيل مجمع الحزم Webpack سيُضاف ملف تنسيق مخصص في وسم <style> وذلك في داخل الوسم <head>. لنجرب ذلك من خلال إضافة ملف تنسيق جديد style.css إلى مشروعنا واستيراده في الملف index.js: لننشئ أولًا ملف التنسيق style.css في مشروعنا لتصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- bundle.js |- index.html |- /src + |- style.css |- index.js |- /node_modules ومن ثم لنُضف بعض الخصائص إلى ملف style.css ليصبح على الشكل التالي: .hello { color: red; } ولنستدعي ملف التنسيق style.css في ملف index.js ليصبح على الشكل التالي: import _ from 'lodash'; + import './style.css'; function component() { const element = document.createElement('div'); // Lodash, now imported by this script element.innerHTML = _.join(['Hello', 'webpack'], ' '); + element.classList.add('hello'); return element; } document.body.appendChild(component()); ومن ثم نُنفذ أمر البناء التالي: npm run build ... Asset Size Chunks Chunk Names bundle.js 76.4 KiB 0 [emitted] main Entrypoint main = bundle.js لنفتح الآن ملف index.html ولنرى ما هي التغييرات الّتي جرت عليه. لاحظ أن كلمة "Hello Webpack" أصبحت الآن باللون الأحمر. لمعرفة ما الّذي فعلته Webpack افحص الصفحة من خلال أدوات المطوّر (المُقدمة من متصفح جوجل كروم على سبيل المثال)، ولكن لا تعرض مصدر الصفحة لأنها لن تقدم لك النتيجة الّتي نود الإشارة إليها. إذ أن الوسم <style> سيُنشئ ديناميكيًا من قِبل جافاسكربت. لذلك افحصها حصرًا من خلال أدوات المطوّر وافحص تحديدًا الوسم <head> يجب أن يحتوي على الوسم <style> والذي استوردناه في ملف index.js. ملاحظة: سابقًا كان علينا تصغير (Minimize) ملفات التنسيق تصغيرًا يدويًا قدر الإمكان وذلك بحذف المساحات الفارغة بين الخصائص الموجودة في الملف من أجل زيادة سرعة تحميل الصفحة، ولكن مع الإصدار الرابع من مجمع الحزم 4 Webpack أو الأحدث منه أصبح تصغير ملفات التنسيق خطوة افتراضية في الأداة، وبذلك أضافت لنا هذه الأداة بُعدًا آخر لتحسين الشيفرة البرمجية وسبب وجيّه لزيادة محبتنا لها. إدارة ملفات SASS تتيح لنا Webpack إمكانية التعامل مع ملفات SASS وتحويلها إلى ملفات تنسيق عادية. ولنأخذ مثالًا عمليًا نطبق فيه كيفية تحويل ملفات SASS إلى ملفات تنسيق عادية. سنركز في هذا المثال على دعم الملفات SCSS مثل: (your-styles.scss) و الملفات SCSS modules مثل: (your-component.module.scss). تجنبًا لتعقيد الأمور أكثر من اللازم سنبدأ بمشروع جديد ننفذ فيه هذه الفكرة. سنفترض أنك أنشأت مشروعًا جديدًا وثبتّ أداة Webpack، لننتقل الآن لتثبيت الإضافات والمُحملات اللازمة لهذا المشروع. سنبدأ أولًا بتثبيت الحزم التالية: npm install --save-dev node-sass sass-loader style-loader css-loader mini-css-extract-plugin ستكون مهمة كلّ حزمة من الحزم على الشكل التالي: node-sass: ستوفر هذه الحزمة ربط Node.js مع LibSass وهذا الأخير هو مترجم SASS. sass-loader: هو مُحمّل ملفات SASS إلى مشروعنا. css-loader: تستخدم هذه الحزمة لتفسير التعليمة @import و @url() بما تشير إليه في ملفات التنسيق. style-loader: تستخدم هذه الحزمة لإسناد الخصائص الموجودة في ملفات التنسيق إلى الوسوم الفعلية في شجرة DOM الافتراضية. mini-css-extract-plugin: هذه الحزمة تستخرج الخصائص الموجودة في ملفات التنسيق إلى ملفات منفصلة. إذ أنها تنشئ لكل ملف جافاسكربت ملف تنسيق الخاص به وهو لدعم ميّزة التحميل عند الطلب (On-Demand-Loading) لملفات التنسيق و خرائط الشيفرة البرمجية المحوّلة Source Maps (لمزيد من المعلومات عنها يمكنك الإطلاع على المقال التالي). سنحتاج إلى إضافة مُحملين، أحدهما للتنسيقات العامة والأخرى للتنسيقات المركبة. واللّذان يشار إليهما بملفات (SCSS modules). إذ أن هذه الأخيرة تعمل جيدًا مع المكتبات أو أطر العمل المُعتمدة على المكونات (component-based) مثل: React. سنضيف هذه الحزمة الملحقة إلى ملف الإعداد webpack.config.js على الشكل التالي: + const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { plugins: [ + new MiniCssExtractPlugin({ + filename: isDevelopment ? '[name].css' : '[name].[hash].css', + chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css' + }) ] } نلاحظ أننا أضفنا خاصية أسماء الملفات المجزأة من أجل زيادة فعالية وسهولة خرق ذاكرة التخزين المؤقّت (Cache Bustring وهي تحِلُّ مشكلة التخزين المؤقت في المتصفح باستخدام إصدار معرف فريد للملف يميزه وذلك من أجل أخباره في حال وجود نسخة جديدة من الملف الذي حفظه فعلًا في هذه الذاكرة، وذلك من أجل أن يحملها تلقائيًا إلى ذاكرة التخزين المؤقت بدلًا من نسخة الملف القديمة الموجودة فيه)، والآن سنضيف الخواص المناسبة لملف الإعداد webpack.config.js من أجل عملية التحويل المناسبة للملفات: module.exports = { module: { rules: [ + { + test: /\.module\.s(a|c)ss$/, + loader: [ + isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, + { + loader: 'css-loader', + options: { + modules: true, + sourceMap: isDevelopment + } + }, + { + loader: 'sass-loader', + options: { + sourceMap: isDevelopment + } + } + ] + }, + { + test: /\.s(a|c)ss$/, + exclude: /\.module.(s(a|c)ss)$/, + loader: [ + isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, + 'css-loader', + { + loader: 'sass-loader', + options: { + sourceMap: isDevelopment + } + } + ] + } ] }, resolve: { - extensions: ['.js', '.jsx'] + extensions: ['.js', '.jsx', '.scss'] } } نلاحظ أن القاعدة الأولى المطبقة في الشيفرة السابقة ستُطبق على الملفات ذات الامتدادات .module.scss أو .module.sass إذ في البداية ستُحوّلُ ملفات SASS إلى CSS من خلال sass-loader ومن ثم ستُمرّر إلى الحزمة css-loader لمعالجة التعليمات ‎@import()‎ و url()‎ ..إلخ. ومن ثمّ ستُسندُ الحزمة style-loader الخصائص المناسبة في DOM أو ستسند من خلال الحزمة Mini CSS Extract Plugin وذلك لإخراج ملفات التنسيق أثناء وضع النشر. القاعدة الثانية مشابهة جدًا للقاعدة الأولى باستثناء أننا لا نحوّل أسماء الأصناف. الآن أصبح ملف الإعداد جاهز نحتاج الآن لإنشاء ملف تنسيقات SASS للتأكد من أن كل شيء يعمل مثلما خطط له. أنشئ مجلد src ثم أنشئ بداخله ملفًا جديدًا باسم app.module.scss وأضف الشيفرة البرمجية التالية: .red { color: red; } أي عنصر سيأخذ الصنف red سيكون لونه أحمر. افتح الملف app.js واستدعي الملف السابق على الشكل التالي: import styles from './app.module' نلاحظ أن اسم الملف لا يحتوي على اللاحقة .scss وذلك لأننا سبق وأخبرنا Webpack بأن يأخذ بعين الاعتبار هذه اللاحقة وذلك في ملف الإعداد. ثم لنُضيف الآن الدالة التالية في نفس الملف app.js ليصبح على الشكل التالي: function App() { return <h2 className={styles.red}>This is our React application!</h2> } أليست سهلة جدًا؟ بغض النظر عن كيفية تحويل الحزمة css-loader اسم الصنف الّذي بنيناه (red) والّذي سيصبح مثل: ‎_1S0lDPmyPNEJpMz0dtrm3F أو شيء من هذا القبيل، ولكنها ساعدتنا في مهمتنا مساعدةً كبيرة. لنُضيف الآن بعض التنسيقات العمومية. لننشئ ملف جديد وليكن global.scss في المجلد src ولِنفتحه ونُضيف بداخله الشيفرة البرمجية التالية: body { background-color: yellow; } هذا الملف سيجعل لون خلفية الصفحة الرئيسية لتطبيق الوِب خاصتنا أصفر. ولكن يجب أن نفتح الملف index.js ونستدعي ملف التنسيق السابق في بداية الملف. مثلما هو موضح في الشيفرة التالية: import './global' واخيرًا سنحصل على الخرج التالي: نلاحظ أن استخدام وحدات SCSS يتطلب منا جهدًا لا بأس به، ولكن بالموازنة مع كمية الفائدة الّتي تقدمها وحدات SCSS من سهولة في الصيانة لتطبيق الوِب في المستقبل فأعتقد أن الأمر يستحق هذا الجهد. بالإضافة إلى ذلك توفر أداة Webpack حزم أُخرى مخصصة لأي نكهة من نكهات ملفات التنسيق مثل الحزمة: postcss لتوفير دعم Postcss أو الحزمة Less لدعم ملفات التنسيق من نوع Less أيضًا. إدارة الصور تتيح Webpack لنا إمكانية إدارة الصور مثل: الخلفيات والأيقونات وذلك من خلال مُحمل الملفات. في البداية لنثبت أولًا مُحمل الملفات من خلال الأمر التالي: npm install --save-dev file-loader ومن ثم سنضيف إلى ملف الإعداد webpack.config.js المعلومات اللازمة لعمل هذا المُحمل كما في الشكل التالي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ], }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + 'file-loader', + ], + }, ], }, }; عند استيراد لصورة معينة ولتكن import MyImage from './my-image.png' ستضاف هذه الصورة إلى مجلد الخرج (output) الّذي حددناه في ملف الإعداد وسيحمل المتغير MyImage عنوان الرابط التشعبي الخاص بالصورة (URL) بعد معالجتها. عندما استخدمنا محمل ملفات التنسيق css-loader جرى نفس السيناريو السابق. أي أنه سيكون الخاصية التالية في ملفات التنسيق url('./my-image.png') والمُحمل سيلاحظ أن الملف هذا موجود محليًا وبذلك سيُحول '‎./my-image.png' إلى المسار النهائي المُسند للخاصية (output) في ملف الإعداد webpack.config.js ومُحمل ملفات html‏ (html-loader) سيتعامل مع <img src="./my-image.png" /‎> بنفس الطريقة. لنُضف الآن الصور اللازمة في مشروعنا. وهنا يمكنك استخدام أي صورة تريدها. لننسخ الصورة الّتي سنعمل عليها ولتكن icon.png إلى مشروعنا. لتصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- bundle.js |- index.html |- /src + |- icon.png |- style.css |- index.js |- /node_modules ومن ثم لنستورد هذه الصورة في ملف src/index.js، ولنُضيفها إلى وسم <div> المتواجدة فيه، ولتصبح الشيفرة البرمجية للملف src/index.js على الشكل التالي: import _ from 'lodash'; import './style.css'; + import Icon from './icon.png'; function component() { const element = document.createElement('div'); // Lodash, now imported by this script element.innerHTML = _.join(['Hello', 'webpack'], ' '); element.classList.add('hello'); + // Add the image to our existing div. + const myIcon = new Image(); + myIcon.src = Icon; + + element.appendChild(myIcon); return element; } document.body.appendChild(component()); ومن ثم سنعدل ملف التنسيق من أجل تضمين الصور الّتي نعمل عليها ليصبح بذلك ملف التنسيق src/style.css على الشكل التالي: .hello { color: red; + background: url('./icon.png'); } ولننفذ الآن أمر البناء التالي: npm run build ... Asset Size Chunks Chunk Names da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big] bundle.js 76.7 KiB 0 [emitted] main Entrypoint main = bundle.js ... إذا نفذت جميع الخطوات السابقة تنفيذًا صحيحًا يجب أن ترى الأيقونة (الصورة) مكررة في الخلفية، بالإضافة إلى وسم <img> بجوار النص "Hello webpack". وإذا فحصت الصورة ستجد أن اسمها الفعلي تغيّر إلى شيء شبيه بهذا الاسم 5c999da72346a995e7e2718865d019c8.png هذا يعني أن Webpack عثرت على الملف في مجلد src وعالجته. الخطوة المنطقية التالية الّتي سننفذها هي تصغير حجم الصور الّتي سنستخدمها في المشروع وتحسينها وذلك من خلال الحزم المساعدة المتوفرة مع الأداة Webpack مثل الحزمة Imagemin. ضغط الصور باستخدام Imagemin إن طريقة ضغط الصور الّتي سنستخدمها في المشروع هي باستخدام حزمة Imagemin إذ تعدّ هذه الحزمة خيارًا ممتازًا وذلك لأنها تدعم مجموعة متنوعة من أنواع الصور وسهلة التكامل مع الشيفرة البرمجية لأدوات البناء أو مجمع الحزم (الوحدات). سنعمل على مشروع جديد تجنبًا للمشاكل التي من الممكن أن تظهر لنا في حال أكملنا العمل على المشروع السابق. سنفرض أنك أنشأت مشروعًا جديدًا وثبّت الأداة Webpack تثبيتًا صحيحًا. في البداية لنثبت هذه الحزم عبر التعليمة التالية: npm install imagemin-webpack-plugin copy-webpack-plugin --save-dev ملاحظة: أن الحزمة copy-webpack-plugin ستساعدنا على نسخ الصور من مجلد images/ إلى مجلد dist/ وهو مجلد النشر وهو اختصار لكلمة distribution. لننشئ ملف الإعداد webpack.config.js ولنعدله ليتناسب مع الحزم الجديدة ليصبح على الشكل التالي: const ImageminPlugin = require('imagemin-webpack-plugin').default; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyWebpackPlugin([{ from: 'img/**/**', to: path.resolve(__dirname, 'dist') }]), new ImageminPlugin() ] } تعدّ هذه الطريقة من أسهل الطرق لإعداد لهذه الحزمة. ولنضغط الصور الّتي في المجلد images/ وننسخها إلى المجلد dist/ من خلال تنفيذ الأمر التالي: webpack --config webpack.config.js --mode development نلاحظ من التعليمة السابقة أن وضع التنفيذ الحالي هو وضع التطوير، ولكن ما الّذي سيحدث إذا نفذنا التعليمة في وضع النشر؟ لنرى ما الّذي سيحدث. webpack --config webpack.config.js --mode production ستُظهر لنا في هذه المرة أداة Webpack تحذيرًا يخبرك بأن الصور ذات النوعية PNG الخاصة بك لا تزال تتجاوز الحد الأقصى للحجم الموصى به، على الرغم من بعض الضغط. ولذلك سنحتاج إلى ضبط اليدوي لعملية الضغط لهذا النوع من الصور لتصبح أفضل مما قبل. لنعدل قيمة الضغط للصور ذات النوعية PNG لتصبح 50% وسيكون ملف الإعداد على الشكل التالي: const ImageminPlugin = require('imagemin-webpack-plugin').default; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyWebpackPlugin([{ from: 'img/**/**', to: path.resolve(__dirname, 'dist') }]), new ImageminPlugin({ pngquant: ({quality: [0.5, 0.5]}), }) ] } نلاحظ أننا مررنا للغرض Pngquant مجالًا لقيمة جودة الصور من 0.5 إلى 0.5 أي من الحدّ الأدنى إلى الحدّ الأعلى لجودة الصورة. إذ أن الحدّ الأعلى الأفتراضي 1 والحدّ الأدنى الافتراضي 0. ولكن ماذا لو أردنا أن نضبط الجودة (نسبة الضغط) المستخدمة لبقية الأنواع من الصور بنفس الطريقة السابقة؟ في الحقيقة يوجد بعض الملحقات الإضافية المساعدة لهذا الغرض تحديدًا والّتي سنستعرضها في هذا الجدول: نوع الصور ضغط مع خسارة بعض معلومات الصورة ضغط بدون خسارة بعض معلومات الصورة JPEG imagemin-mozjpeg imagemin-jpegtran PNG imagemin-pngquant imagemin-optipng GIF imagemin-giflossy imagemin-gifsicle SVG Imagemin-svgo WebP imagemin-webp table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } نلاحظ أن لدينا نوعين من طرق ضغط الصور وهما كالتالي: ضغط مع خسارة بعض معلومات الصورة (Lossy): يؤدي استخدام هذا النوع إلى تصغير حجم الصورة تصغيرًا ملحوظًا، ولكن مع فقدان بعض معلومات الصورة. ضغط بدون خسارة بعض معلومات الصورة (Lossless): يؤدي استخدام هذا النوع إلى تصغير حجم الصورة تصغيرًا أقل من الطريقة السابقة، ولكن بدون فقدان بعض معلومات الصورة. إن طريقة الضغط الإفتراضية للحزمة imagemin للصور ذات النوعية JPEG هي الطريقة imagemin-jpegtran، سنستعرض كيفية ضغط الصور باستخدام الحزمة الأخرى وهي imagemin-mozjpeg. في البداية يجب علينا تثبيت هذه الحزمة من خلال الأمر التالي: npm install imagemin-mozjpeg ولنُعدل ملف الإعداد webpack.config.js لضبط طريقة ضغط الصور وفق ما نريده. ليصبح الملف على الشكل التالي: const imageminMozjpeg = require('imagemin-mozjpeg'); const ImageminPlugin = require('imagemin-webpack-plugin').default; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyWebpackPlugin([{ from: 'img/**/**', to: path.resolve(__dirname, 'dist') }]), new ImageminPlugin({ pngquant: ({quality: [0.5, 0.5]}), plugins: [imageminMozjpeg({quality: 50})] }) ] } نلاحظ أن نسبة الضغط في هذه الحزمة من 100 إذ مررنا القيمة 50 وبذلك نخبره بأننا نريد ضغط الصور من النوع JPEG بنسبة 50%. ولنُنفذ الآن التعليمة التالية لنرى النتيجة: webpack --config webpack.config.js --mode production تهانينا في حال نفذّت جميع الخطوات تنفيذًا صحيحًا يجب أن تكون الصور مضغوطة وفقَ المطلوب. إن الأداة Webpack تحذرنا من الصور ذات الحجم الكبير، ولكنها لا تستطيع إخبارنا إن كانت الصور مضغوطة أم لا، ولهذا السبب سنستخدم الأداة Lighthouse للتحقق من التغييرات المُنفّذة. تسمح لنا الأداة Lighthouse من التحقق من ترميز الصور بكفاءة وإن كانت الصور الموجودة في صفحتك مضغوطة على نحوٍ أمثلي أم لا (لمزيد من المعلومات حول هذه الأدة ننصحك بالاطلاع على هذا المقال المفصّل). وستكون النتيجة مشابهة للصورة التالية: بنفس الطريقة يمكنك استخدام بقية الحزم لتخصيص قيمة الضغط المطلوب للأنواع الأخرى من الصور المستخدمة في مشروعك. إدارة الخطوط يمكننا إدارة الخطوط أيضًا مع Webpack من خلال مُحمل الملفات الّذي ثبتناه في إدارة الصور (سنعمل على نفس المشروع الّذي بنيناه في فقرة إدارة الصور)، والذي سيأخذ أي ملف تضعه له في ملف الإعداد ويضعه في المسار النهائي المُسند للخاصية (output) في ملف الإعداد webpack.config.js. أي أن مُحمل الملفات قادر على التعامل الخطوط أيضًا. لنعدل الآن ملف الإعداد webpack.config.js ليصبح على الشكل التالي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ], }, { test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader', ], }, + { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: [ + 'file-loader', + ], + }, ], }, }; أضف خطًا معينًا إلى مجلد المشروع لتصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- bundle.js |- index.html |- /src + |- my-font.woff + |- my-font.woff2 |- icon.png |- style.css |- index.js |- /node_modules من خلال التعديلات الّتي أجريناها على ملف الإعداد لمُحمل الملفات يمكننا الآن جعل التعليمة الّتي تصرح بها عن المسارات للخطوط ‎@font-face إلى الشكل التالي url(...)‎. سيعاد توجيه هذه المسارات إلى المسار النهائي المُسند للخاصية (output) في ملف الإعداد webpack.config.js تمامًا كما تعامل مع الصور. إذا سيصبح ملف التنسيق src/style.css على الشكل التالي: + @font-face { + font-family: 'MyFont'; + src: url('./my-font.woff2') format('woff2'), + url('./my-font.woff') format('woff'); + font-weight: 600; + font-style: normal; + } .hello { color: red; + font-family: 'MyFont'; background: url('./icon.png'); } لنرى كيف سيتعامل Webpack مع الخطوط ولننفذ أمر البناء على الشكل التالي: npm run build ... Asset Size Chunks Chunk Names 5439466351d432b73fdb518c6ae9654a.woff2 19.5 KiB [emitted] 387c65cc923ad19790469cfb5b7cb583.woff 23.4 KiB [emitted] da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big] bundle.js 77 KiB 0 [emitted] main Entrypoint main = bundle.js ... افتح ملف index.html وانظر إلى النص "Hello webpack" كيف تغير شكل الخط ليصبح مطابق لشكل الخط الجديد. أما الآن لننتقل إلى واحدٍ من أبرز استخدامات مجمع الحزم Webpack وهو تحويل الشيفرات البرمجية الخاصة بالإصدارات الحديثة من المواصفات القياسية للغة جافاسكربت مثل ES6 إلى ES5. تحويل الشيفرة البرمجية باستخدام Babel بعد أن تعرفنا كيف ندير جميع التبعيات الموجودة في شيفرات جافاسكربت البرمجية من خلال Webpack. لا بُدّ لنا من جعل هذه الشيفرة البرمجية تعمل على جميع المتصفحات وذلك لكي نضمن أنه مهما يكن المتصفح الّذي سيستخدمه العميل (أو المستخدم) ستظهر النتيجة المطلوبة تمامًا مثل ما نريده. عملية التحويل (Transpiling): هي عملية تغيير الشيفرة البرمجية من إصدار معين إلى إصدار أقدم وذلك لضمان عمل هذه الشيفرة البرمجية على المتصفحات كلها. مقتطف من المخطط التفصيلي لدعم المتصفحات للمميزات الإصدار ES5 والإصدار ES6 من لغة جافاسكربت. سننشئ مشروعًا بسيطًا لشرح طريقة استخدام هذا المُحول: mkdir webpack-demo2 cd webpack-demo2 npm init -y npm install webpack webpack-cli --save-dev ملاحظة: لن نتطرق للتفاصيل نظرًا لأنها شُرحت في بداية هذا الدليل. ستكون البنية الهرمية للمشروع على الشكل التالي: webpack-demo2 |- package.json + |- index.html + |- /src + |- index.js في البداية سنحتاج لتثبيت ثلاث حزم للتعامل مع المحول Babel وستكون على الشكل التالي: npm install babel-core babel-loader babel-preset-env --save-dev الحزمة babel-core: تحتوي على الشيفرة البرمجية للنواة الأساسية للمُحول Babel. الحزمة babel-preset-env: تحتوي على الشيفرة البرمجية الّتي ستمكن النواة الأساسية للمحول Babel من تحويل الشيفرة البرمجية للجافاسكربت ذات الإصدار 6ES إلى الإصدار ES5. الحزمة babel-loader: أو (مُحمل المحول) وهي الّتي ستستخدمها Webpack في تحميل المحول والتعامل معه في عملية التحزيم (Bundling). أما الآن سننشئ ملف babelrc. والذي سيطلب من المحول Babel أن يستخدم الحزمة babel-preset-env أثناء عملية التحويل وسيكون الملف babelrc. على الشكل التالي: +{ "presets": ["env"] } ومن ثم سننشئ ملف الإعداد webpack.config.js ونطلب من Webpack الإستعانة بالمحمل Babel أثناء تحزيمه. وسيكون ملف الإعداد webpack.config.js على الشكل التالي: + const path = require('path'); + module.exports = { + entry: { main: './src/index.js' }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'main.js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader' + } + } + ] + } + }; سنضع الآن في ملف src/index.js شيفرة برمجية من الإصدار ES6، وليصبح على الشكل التالي: + const fn = () => "Arrow functions're Working!"; + alert(fn()); ومن ثم ننفذ الأمر التالي: npm run dev ومن ثم لنفتح ملف dist/main.js نلاحظ أن الدالة السهمية (Arrow function) تُحوّلُ إلى دالة عادية وذلك وفق الطريقة المتبعة في الإصدار ES5 من لغة جافاسكربت. وسيكون محتوى الملف dist/main.js على الشكل التالي: 'use strict'; var fn = function fn() { return "Arrow functions're Working!"; }; alert(fn()); وبذلك استطعنا استخدام مميزات الإصدار الحديث من لغة جافاسكربت ES6 وتحويله إلى إصدار أقدم ES5 لتفهمه المتصفحات القديمة. هل من المخاطرة تعلم Webpack؟ بعد أن تعرفنا سريعًا على Webpack يمكن لسائل أن يسأل ماذا لو أنني تعلمت العمل على Webpack وبعدها ظهرت أداة جديدة أفضل منها أو تغطي مجال أوسع في العمل؟ أليس ذلك هدرًا لوقتي ولجهدي؟ صراحة، الشيء الوحيد الّذي استطيع تأكيده لك هو أن عجلة التحديث في مجال الواجهات الأمامية سريع الدوران، وما إن تظهر مشكلة ما حتى يتسارع المطورون لحلها فمن الممكن أن تظهر أداة أقوى منها (وهذا لا اتوقعه أن يحدث قريبًا وخصيصًا مع الدعم الكبير الّتي تشهده هذه الأداة من الشركات العملاقة مثل فيسبوك) هذا وارد الحدوث، ولكن هذا الأمر لا يُلغي فكرة أهمية تعلمك العمل مع هذه الأداة إذ أن معظم الأدوات الّتي تظهر لحل مشكلة معينة تكون متشابهة في البنية وطريقة العمل مع بعض الإختلافات. أي إن تعلمك العمل مع هذه الأداة سيجهزك للعمل مع الأدوات الأخرى المستقبلية. ومن يعلم ربما تكون أنت صاحب فكرة الأداة الجديدة الّتي ستتفوق على Webpack! والسؤال الأخر الّذي من الممكن يخطر في أذهاننا أيضًا هل تستحق هذه الأداة الوقت المبذول لتعلمها؟ أو بتعبير أخر هل النتائج الّتي سأجنيها من استخدام هذه الأداة ستغطي على الوقت المبذول لتعلمها؟ في الحقيقة لا أبالغ أن قُلت أنه من الواجب عليك تعلمها فورًا وبدون تردد وخصيصًا إن كُنت تتخذُ من مهنة تطوير الواجهات الأمامية (أو مطور برمجيات عمومًا) مصدرًا أساسيًا للدخل في حياتك! لأنها ستعزز كثيرًا من إنتاجيتك وسرعتك وجودة العمل المُسلّم وهذا ما ستشعر به من أول شهر من استخدامك لها. في الحقيقة إن مجيئ Webpack بكل هذه المميزات وقابلية التخصيص والإمكانيات أطاح بجميع المنافسين لديها مثل Browserify، ليس ذلك فحسب بل تخطّت إمكانياتها حدود الفكرة التي أُنشأت من أجلها لتهدد أدواتٍ مساعدةٍ أخرى كأدوات البناء مثل Gulp (والتي تحدثنا عنها في مقالٍ سابق) إذ أنه يمكننا من خلال NPM Script أن نعوّض عمل Gulp ولكن هذا سيكون على حساب الصعوبة إذ أن العمل مع Webpack ليس بسهولة العمل مع Gulp. ننصحك بالانتقال بعد الانتهاء من هذا المقال إلى مقال، أيهما أفضل كأداة مساعدة Webpack أم Browserify مع Gulp؟ الذي يشرح الفروقات بين كل هذه الأدوات وحالات استخدامها وغيرها من التفاصيل المفيدة. بالإضافة إلى ذلك وفرت لنا Webpack إمكانية التكامل مع أدوات مساعدة أُخرى مثل أداة السقالة Yeoman (والتي تحدثنا عنها في مقالٍ سابق) وبذلك نحصل على فوائد كِلتا الأداتين ونختصر وقتنا اختصارًا ملحوظًا. وبذلك يمكننا القول بأن المرونة الموجودة لدى Webpack وملحقاتها الرائعة والدعم المتميز من مجتمعها ومستخدميها جعلها من أقوى الخيارات الموجودة في الساحة حاليًا. الخاتمة بدأنا هذا الدليل ونحن لا نعرف شيئًا عن Webpack، ثم حفرنا عميقًا في تاريخها لنفهم تمامًا ما هي الأسباب الّتي أدت لظهور أداةٍ قوية كهذه الأداة، ثم بدأنا بتجهز المتطلبات اللازمة لتشغيلها، وفصلّنا في جميع المفاهيم الأساسية لها، وتعلمنا كيفية استخدامها في إدارة ملفات التنسيق والصور والخطوط ، وكيفية استخدامها لضغط الصور قبل رفعها وتعلمنا طريقة استخدامها لتحويل الشيفرة البرمجية من إصدار حديث إلى إصدار أقدم منه. وأخيرًا ناقشنا أهمية تعلمها وفوائده. وختامًا إن هذا الدليل لم يغطي كافة المميزات والجوانب الموجودة في أداة Webpack وإنما فقط أردنا من هذا الدليل أن يلفت نظرك لأهمية هذه الأداة وقدراتها المتميزة في مساعدتك في العمل على المشاريع وخصوصًا الكبيرة منها. بل وجعلها يدك اليمنى في أي مشروع جديد وبالتأكيد إن كلّ هذه المعلومات لن تُشبع فضول المطوّر المحترف ولذلك يمكنك دومًا الاطلاع على التوثيق الرسمي للأداة لمزيد من المعلومات. المصادر التوثيق الرسمي لأداة Webpack. التوثيق الرسمي لمدير الحزم npm. المقال Using Imagemin with webpack لصاحبته Katie Hempenius. المقال How to configure SCSS modules for Webpack لصاحبه Jon Preece. المقال Brief history of JavaScript Modules لصاحبه SungTheCoder.
  8. شهد قطاع صناعة الألعاب في الأونة الأخيرة تطورًا كبيرًا وفي كلّ عام يزداد الإقبال عليها أكثر مما قبل؛ فصُمّمت الألعاب الإلكترونية في عام 1960، إذ كانت تحتاج لحواسيب ضخمة لم تكُ متاحة للعموم آنذاك. وبعد ذلك بعشر سنوات تطورت الألعاب لتصبح تجارية في عام 1970، وذلك مع مجيء أول أجهزة الألعاب الإلكترونية والحواسيب المنزلية. ونظرًا إلى القدرات المنخفضة للحواسيب آنذاك كان بإمكان مطوّر واحد أن يُنتج لعبة بكاملها. ولكن عند مطلع القرن 21 ومع تزايد قدرات الحواسيب على معالجة البيانات، وتصاعد توقعات المستهلك أصبح من المستحيل أن ينتج مطور واحد لعبة تناسب هذا العصر بل ستحتاج إلى فريق عمل متكامل من منتجين ومصممين ومبرمجين ومهندسي صوت ومؤلفين موسيقيين ومصممي المراحل والعديد من الإختصاصات الأخرى لإنتاج لعبة تناسب هذا العصر. يوجد في وقتنا الحالي العديد من منصات الألعاب، مثل أجهزة البلايستيشن (PlayStation) أو أجهزة الإكس بوكس (Xbox) إذ أن لكل منصة منصة ألعاب صُممت لتُعلب عليها فقط، والبعض الأخر من الألعاب مخصصة لأجهزة الحواسيب (مثل الويندوز أو الماك أو اللينكس)، أو بعض الألعاب الأخرى المخصصة لمتصفح الوِب (تدعى ألعاب المتصفح [Browser Game]) والّتي سنناقشها اليوم ونعلمك كيفية إنشاء لعبة بسيطة تعمل على المتصفح. ألعاب المتصفح (Browser Game) عادةً ما تُعرف ألعاب المتصفح بألعاب الوِب، وهي نمط من الألعاب الّتي تُلعب باستخدام متصفح الإنترنت (مثل غوغل كروم أو أوبرا أو أي متصفح أخر) وذلك من خلال طلب عنوان موقع اللعبة، وبعد تحميل الموقع تظهر لدينا اللعبة ويمكننا بعدها البدء باللعب. غالبًا ما تُصمم هذه الألعاب باستخدام تقنيات الوِب القياسية (مثل: HTML5، و CSS3، و JavaScript وغيرها) أو بتقنيات أخرى مثل أدوبي فلاش ولكن جميع هذه التقنيات لديها إمكانيات محدودة؛ وذلك بسبب مسائل التكاملية والجودة مع المتصفح، ولكن مع ذلك فإن هذه التقنيات هي الّتي تجعل هذه الألعاب تعمل على جميع المتصفحات. واجهت ألعاب المتصفح منذ بدايتها العديد من التحديات، بعضها من ناحية الرسوميات، وبعضها الأخر من ناحية الأداء والسرعة، وبعضها من ناحية الضغط على المخدمات الّتي تستضيف هذه الألعاب (وذلك بسبب كثرة العناصر المحملة من ملفاتٍ وصورٍ والعديد من المكونات الأخرى الموجودة في اللعبة). ولكن ما لبثت هذه التحديات بالظهور حتى أُوجدت لها حلولٌ عديدة فعّالة، ولكن مع ذلك فإنها لم تستطع أن تنافس الألعاب التقليدية وخصوصًا مع الفارق الكبير بين طريقة تعامل كلّ منهم مع موارد الحاسوب. حجزت ألعاب المتصفح لنفسها مكانًا في الألعاب التنافسية متعددة اللاعبين (مثل لعبة الشطرنج ولعبة البلياردو وعلى غرارها من الألعاب)، وهي عادةً ما تركز على الجانب الإجتماعي من اللعبة أكثر من اللعبة بحد ذاتها، إذ تمنح إمكانية الدردشة بين اللاعبين أثناء اللعب، وإمكانية إنشاء ملفاتهم الشخصية (User Profile)، وبالإضافة إلى نظام تنافسي مبني على النقاط والكؤوس مما يعزز روح المنافسة ويضيف متعةً أخرى للعبة. نشأة وتاريخ صناعة ألعاب المتصفح وتطورها ظهرت ألعاب متصفح الوِب في بداية التسعينات من القرن الماضي ولكن لم تبدأ بالانتشار إلا في عام 1996 تزامنًا مع ظهور برنامج Macromedia Flash (المستخدم لتعديل الرسوميات) ولغة البرمجة أكشن سكربت (Action Script) وسرعان ما شكّلا مع بعضهما أول أدوات صناعة ألعاب المتصفح آنذاك. وبعد عام واحد أطلقت شركة Sun Microsystems موقعها الخاص هوت جافا (HotJava) لاستضافة الشيفرات البرمجية المحمولة للغة جافا (Java applet) وتعمل هذه الألعاب على جميع المتصفحات الّتي تدعم لغة جافا، والّذي كان شرارة البدء لعصر ألعاب المتصفح. وبعد النجاح الكبير لألعاب المتصفح والّذي لوحظ من خلال الازدياد الكبير لعدد الأشخاص المنضمين لمواقع ألعاب المتصفح والإقبال الشديد عليها، مما أدى لاهتمام بعض الشركات الكبرى لهذا النمط من الألعاب من بينها شركة ياهو والّتي انضمت إلى هذا المجال لتطلق موقعها Yahoo! Games في عام 1998، والّذي يحتوي على العديد من الألعاب ولتصبح بذلك من أوائل شركات صناعة ألعاب المتصفح آنذاك. وفي عام 2016 أعلنت الشركة عن إغلاق الموقع بسبب عدم تمكن الفرق البرمجية لشركة ياهو من حل المشاكل المتزايد للتقنيات المستخدمة في بناء الألعاب وعدم تلبية هذه الألعاب لمتطلبات الوِب الحديثة كلّ هذه العوامل أدت إلى إغلاق موقع في شهر فبراير من عام 2016. الفرق بين ألعاب المتصفح والألعاب التقليدية تختلف ألعاب المتصفح عن الألعاب التقليدية بعدة نواحي أهمها: 1. طريقة اللعب إن ألعاب المتصفح تتطلب الاتصال الدائم بالإنترنت طوال زمن اللعب لأنه من دون الاتصال بالإنترنت لا يمكن تشغيل الألعاب وذلك لأنها مخزنة على مخدمات موجودة عبر الإنترنت وليس في الحاسوب الشخصي. على عكس الألعاب التقليدية إذ أن أغلبها لا يتطلب اتصالًا دائمًا بالإنترنت. وعلى صعيد أخر في دراسة أجراها باحثون من جامعة ماينتس الألمانية على 8203 شخص من لاعبي لعبة المتصفح الشهيرة ترافيان (Travian) تبين لهم أن ألعاب المتصفح يُستمتع بها أساسًا بسبب الجانب الاجتماعي منها الّذي ينطوي عليه خصائص الوقت، والمرونة العالية في العب، وسهولة الاستخدام، والتنافس بين اللاعبين، وكما أشارت الدراسة نفسها أن سهولة الوصول إلى هذا النوع من الألعاب (لعبة ترافيان-وبشكل عام جميع ألعاب المتصفح) أدت إلى زيادة عدد مرات فتح اللعبة بالموازنة مع الألعاب التقليدية، ولكن مدة جلسات اللعب المتواصلة قصيرة. 2. مصادر الدخل للألعاب يختلف اعتماد ألعاب المتصفح على مصادر الدخل فمنها من يعتمد على عرض إعلانات داخل اللعبة (مثل إعلانات غوغل أدسنس وغيرها)، أو إلى عرض عمليات الشراء داخل اللعبة للحصول على مميزات أو نقاطٍ تتفوق بها على المنافسين، ومنها من تعتمد على الاشتراك الشهري أو السنوي، والبعض الأخر يعتمد على شراء اللعبة لمرة واحدة فقط. وفي بعض الحالات النادرة تكون الألعاب مجانية بالكامل. وفي المقابل فإن غالبية الألعاب التقليدية تعتمد على شراء اللعبة لمرة واحدة بالإضافة لعمليات الشراء داخل اللعبة في حال كانت تُلعب على الإنترنت. 3. استخدام موارد الحاسوب تعدّ ألعاب المتصفح ذات رسوميات منخفضة بالموازنة مع الألعاب التقليدية وذلك من كونها تتعامل مع إمكانيات المتصفح والموارد الّتي يستخدمها، على عكس الألعاب التقليدية الّتي تتعامل مع موارد الجهاز تعاملًا مباشرًا ولكن على صعيد أخر تستهدف ألعاب المتصفح شريحة كبيرة من المستخدمين وعلى كافة الأجهزة وخصوصًا أصحاب الأجهزة الضعيفة والمتوسطة. وعلى صعيدٍ آخر إن غالبية الألعاب التقليدية تحجز مساحة كبيرة من سعة القرص الصلب على عكس ألعاب المتصفح، كما تستهلك الألعاب التقليدية قدرًا كبيرًا من ذاكرة الوصول العشوائي (RAM) بالموازنة مع ألعاب المتصفح مما يجعل ألعاب المتصفح خفيفة جدًا على موارد الحاسوب مهما كانت مواصفاته. مشاكل وحلول وكما ذكرنا سابقًا عانت ألعاب المتصفح العديد من المشاكل فما أن تُحلّ مشكلة حتى تظهر أخرى. وإن من أبرز المشاكل الّتي واجهتها هي: معالجة الرسوميات إن تصاعد توقعات المستهلكين أثقلت كاهل المطورين من ناحية رفع جودة الألعاب وتعزيز تجربة المستخدم، وفي ظل الإمكانيات المحدودة لألعاب المتصفح والّتي جعلت من عملية مواكبة تطور الألعاب عمليةً شاقةً جدًا. ومن أكثر المشاكل الّتي تواجه مطوري ألعاب المتصفح هي معالجة الرسوميات ذات الأبعاد الثنائية أو الثلاثية والّتي شكلت لفترة طويلة سدًا منيعًا في تطور هذا النمط من الألعاب. كان ذلك إلى أن جاءت تقنية WebGL والّتي سمحت لنا بكتابة رسوميات ثلاثية الأبعاد في صفحات الوِب باستخدام جافا سكربت (JavaScript) عبر العنصر canvas (وكما تحدثنا في عدة مقالات عن هذه التقنية وأهميتها). ولكن تقنية WebGL لا تُنشِئ «عناصر» على الصفحة، إذ تتعامل مباشرةً مع البكسلات؛ ولذا نقول عن تقنية WebGL أنّها تقنيةٌ منخفضة المستوى: إذ أنّها توفِّر تحكمًا دقيقًا بالفضاء ثلاثي الأبعاد. والجدير بالذكر أن هذه التقنية، WebGL، مبنية على الواجهة البرمجية OpenGL ES والّتي هي نسخة فرعية من OpenGL. ولكن ماهي OpenGL؟ (Open Graphics Library) هي عبارة عن واجهة برمجية رسومية مستقلة تعمل على مختلف أنظمة التشغيل، ومتوافقة مع عدة لغات برمجية، وصُممت لإنتاج رسوميات ثنائية وثلاثية البعد سواءً المعقدة منها أو البسيطة من خلال تركيبها من مكونات هندسية بسيطة مثل المضلعات أو المثلثات أو المستقيمات …إلخ، وكما أنها تشكّل همزة الوصل بين وحدة المعالجة المركزية CPU ووحدة معالجة الرسوميات GPU. أما OpenGL ES (والتي تعرف اختصارًا للعبارة Open Graphics Library for Embedded Systems) فهي نسخة فرعية من OpenGL الرئيسية، ومبنية خصوصًا للأنظمة المدمجة مثل: الأجهزة الذكية وأجهزة التابلت …إلخ. وهي الّتي بنيت عليها تقنية WebGL. ومع أن WebGL مبنية على OpenGL ولكن يوجد فرق بين إمكانيات كلٍّ منهما وهذه بعض النقاط الّتي تختلف فيها WebGL عن OpenGL. تملك WebGL المميزات التالية: مبنية بلغة جافا سكربت. تُستخدم خصيصًا لمعالجة رسوميات المتصفح. إمكانياتها قليلة بالموازنة مع OpenGL لأنها مبينة على نسخة فرعية من OpenGL وهي OpenGL ES. سهلة التعلم والاستخدام. أما OpenGL فلديها المميزات التالية: مبنية بلغة C. تُستخدم خصيصًا لمعالجة رسوميات تطبيقات سطح المكتب والألعاب. إمكانياتها كثيرة نظرًا لأنها تتخاطب مع العتاد تخاطبًا مباشرًا. صعبة التعلم والاستخدام. وبناءً على ذلك تعدّ WebGL خيارًا جيدًا لمعالجة الرسوميات في المتصفح وتصييرها. الضغط على الخادم تعدّ مشكلة الضغط على المخدم وتوقفه عن العمل من أبرز المشاكل المطروحة، إذ أن بنية ألعاب المتصفح المؤلفة من ملفاتٍ (HTML أو CSS أو JavaScript أو أي ملفات أخرى) وصورٍ والمقاطع الصوتية وفي بعض الأحيان مقاطع فيديو تجعل من استقرار المخدم المضيف وبقائه بالخدمة مهمةً صعبةً للغاية بل شبه مستحيلة، وخصوصًا في حال استقبال الموقع عددًا كبيرًا من الزوار في آنٍ واحد. ولقد ظهر في الأونة الأخير حلٌ عملي ومناسب جدًا لهذه المشكلة وهو استخدام الاستضافة السحابية. ولكن ما هي الاستضافة السحابية؟ هي خدمة استضافة تُمكّن العملاء من الاستفادة من خدماتها بقدر ما يحتاجون إليه، اعتمادًا على مطالب مواقعهم على الإنترنت، وأنهم سيدفعون فقط مقابل ما يستخدمونه. وتعتمد الاستضافة السحابية على مفهوم موازنة الحمل (Load Balancing) والّذي يوزع الأحمال (الزوار) على أكثر من خادوم لتحقيق أكبر سرعة استجابة لموقع الوِب. ومن أبرز المميزات الّتي تقدمها الاستضافة السحابية هي: الوثوقية: بدلًا من استضافة الموقع على خادم واحد مادي يستضاف الموقع على قسم افتراضي إذ يستمد موارده من شبكةٍ واسعةٍ من الخوادم المادية. أي أنه في حال توقف أحد الخوادم لن يؤثر ذلك على توافر الموقع وسوف يستمر بسحب الموارد من شبكة الخوادم المتبقية. المرونة: تبقى موارد الموقع متاحة حتى في حال ارتفاع حركة الزوار أو ازدياد الطلبات على الموقع، أو طلب موارد إضافية تبقى إمكانية الوصول للموارد سلسة. الدفع على قدر الاستخدام: يدفع العميل فقط على قدر ما يستخدم، أي ليس هنالك أي هدر في حال كان الطلب أقل من المعتاد. صناعة ألعاب المتصفح تستخدم العديد من اللغات البرمجية لتصميم ألعاب المتصفح ولكل لغة خواص معينة تميزها عن الأخرى. فعلى سبيل المثال يمكنك بناء لعبة على محرك Unity وذلك باستخدام برنامج Unity3D باستخدام لغة #C أو لغة ++C. والّذي يمكنك بناء ألعاب متميزة نظرًا لإمكانياته القوية والكبيرة (ولقد تناولنا في سلسلة سابقة عن أبرز مميزات هذا البرنامج ننصحك بالاطلاع عليها). وكما يمكنك استخدام تقنيات الوِب القياسية مثل HTML5/CSS أو PHP أو حتى لغة جافاسكربت (JavaScript)، والّتي تعدّ من الخيارات الجيدة لبناء هذه النوع من الألعاب نظرًا من كونها تتيح إمكانية عالية لتفاعل المستخدم مع الموقع (في حالتنا اللعبة). وكما لديها العديد من أُطر العمل المتاحة وشعبية كبيرة تجعلها من أبرز اللغات لتطور ألعاب المتصفح. وبعد أن تعرفنا عن ماهية ألعاب المتصفح، وتجولنا في تاريخها ونشأتها، وبيّنا أهم الفروقات بينها وبين الألعاب التقليدية، وناقشنا أهم المشاكل الّتي تتعرض لها والحلول المناسبة، ما رأيك بأن نُكّمل هذا المشوار ونبدأ ببناء أول لعبة لنا؟ بكل تأكيد أنت متحمس لخوض هذه المغامرة ومعرفة تفاصيلها إذًا اِربط الأحزمة واستعد للانطلاق. سنستخدم لغة جافاسكربت لإنشاء هذه اللعبة. وذلك لإنّها تتطلّب مجهودًا قليلًا بالموازنة مع بقية الخيارات المتاحة وتعمل في كلّ البيئات. سوف ننطلق من لا شيء وننشئ لعبةً ممتعة دون أن نستغرق أي وقت يُذكر. تتألف هذه السلسلة حول صناعة لعبة عبر جافاسكربت من خمس مقالات هي: حلقات اللعبة التكرارية جلب المدخلات من اللاعب كشف التصادمات الجاذبية إنشاء السلالم وختام اللعبة نرجو لك قراءة ممتعة! اقرأ أيضًا المقال التالي: حلقات اللعبة التكرارية
  9. يتطلب كلّ موقع الكتروني استضافة وذلك ليكون متاحًا للزوار عبر شبكة الإنترنت. يُدرك المصممون والمدونون أهمية ذلك تمامًا وأغلبهم يستخدم المواقع الإلكترونية لنشر أعمالهم وعلاماتهم التجارية. عندما يتعلق الأمر باختيار مزود استضافة المواقع فهنالك العديد من الخيارات المتاحة بعضها مجاني ويوفر لك ميزات محدودة جدًا بينما البعض الأخر قد يكلفك القليل من المال ولكن يقدم ميزات غير محدودة. وأنا أفضل خدمات لاستضافة المدفوعة وذلك لتوفيرها العديد من التسهيلات بالموازنة مع المزودات الرخيصة أو المجانية. 1. BlueHost وهو أحد الشركات الرائدة في تقديم خدمات استضافة المواقع والّتي توفر استضافة ووردبريس ممتازة وموصّى بها من قِبل شركة ووردبريس الرسمية، وتستطيع إدارة ازدياد عدد الزوار إلى موقعك بدون إبطائه. عروض الشركة: استضافة مشتركة - يعدّ خيارًا مناسبًا للمصممين والمدونين الّذين لا يتوقعون ملايين الزيارات شهريًا. استضافة VPS والاستضافة المخصصة - تعدّ خيارًا مناسبًا للأعمال الّتي تحتاج المزيد من موارد المخدم. ويوجد خبراء جاهزين لمساعدتك على مدار ساعة وطيلة أيام الأسبوع. استضافة الموزّعين - يعدّ هذا الخيار مناسبًا للأشخاص الّذين يعملون في مجال بيع خدمات الاستضافة حيث يمكنك شراؤها واستخدام مساحة التخزين في القرص الصلب المخصصة وعرض النطاق (Bandwidth) لاستضافة مواقع العملاء. وهذه بعض الميزات فيما يخص خيار المصممين والمدونين وتعرض الشركة العديد من الميزات منها: استضافة نطاقات (Domains) بشكل غير محدود. مساحة استضافة بشكل غير محدودة. شهادة SSL مجانية. استقبال 100 دولار أمريكي كهدية من شركة غوغل و100 من شركة مايكروسوفت عند إنفاقك 25 دولار أمريكي في حسابك الجديد على منصاتهم الإعلانية. تراسل بيانات بشكل غير محدود. حسابات بريد إلكتروني بشكل غير محدود. نطاق (Domain) مجاني مخصص. يمكنك الحصول على هذه الميزات والكثير غيرها الموجودة في الخطة الاستضافة المشتركة مقابل 2.95 دولار أمريكي شهريًا، ومن ناحية أخرى استضافة المواقع المخصصة غالية بعض الشيء ولكنها توفر المزيد من موارد المخدم مثل: وحدة معالجة مركزية 4×2.3 غيغا هرتز. ذاكرة وصول عشوائي (RAM) بسعة 4 غيغا بايت. سعة تخزين 500 غيغا بايت (منسوخة احتياطيًا في حال فشل النسخة الأصلية). 5 تيرا بايت عرض النطاق (Bandwidth). 3 عناوين IP. شهادة SSL مجانية. اسم نطاق مجاني. دعم فني على مدار الساعة وطيلة أيام الأسبوع. ضمان استرداد أموالك خلال 30 يوم. تبلغ كلفة الاستضافة المخصصة القياسية 79.99 دولار أمريكي شهريًا. يمكنك أيضًا الحصول على خطة المتاجر الإلكترونية والّتي تتيح مجموعة من المميزات الّتي يحتاجها جميع أصحاب المتاجر الإلكترونية ومن بين المميزات المتوفرة في جميع خطط المتاجر الإلكترونية هي: اسم نطاق مجاني. تثبيت تلقائي لمتجر WooCommerce. شهادة SSL مجانية. تراسل بيانات بشكل غير محدود. استقبال 100 دولار أمريكي كهدية من شركة غوغل و100 من شركة مايكروسوفت عند إنفاقك 25 دولار أمريكي في حسابك الجديد على منصاتهم الإعلانية. عنوان IP مخصص. ويمكنك الحصول على الخطة الابتدائية والّتي تأتي مع مميزات أخرى مثل: استضافة متجر واحد. سعة تخزين تبلغ 100 غيغا بايت. مجموعة من القوالب المجانية الجاهزة للتركيب. حماية خصوصية النطاق. مكالمة مجانية للمساعدة في التثبيت. شهر كامل مجانًا لبرنامج أوفيس 365 Mailbox. كل هذه المميزات مقابل 6.95 دولار أمريكي شهريًا للخطة الابتدائية ويوجد ميزات أخرى في الخطط الأخرى المتوفرة للمتاجر الإلكترونية. 2. WP Engine تعدّ هذه الشركة الخيار الإحترافي لمواقع الووردبريس حيث تمنحك الشركة خادم استضافة لا ينقطع مع القدرة على التعامل مع ازدياد عدد الزوار، ولا داعي للقلق بشأن الحماية لأنه محمي جيدًا من الاختراق. مع خدمة عملاء قوية وسريعة بنفس الوقت تجعل هذه الشركة مرشحًا قويًا جدًا لخدمات استضافة المواقع ومع فريق من الخبراء في الووردبريس ستشعر بالإطمئنان بشأن أي مشكلة قد تصيب موقعك. وتعد هذه الشركة خيارًا جيدًا للمدونين والمصممين الّذين يبحثون عن استضافة بسعر معقول. جميع الخطط المُقدمة من قبل هذه الشركة تأتي مع ضمان استرداد أموالك بالكامل خلال 60 يومًا إذا لم تعجبك الخدمة أو المنصة وتشمل بعض عروضهم ما يلي: النسخ الاحتياطي اليومي. استعادة النسخ الاحتياطي بنقرة زر واحدة. أمان عالي الجودة. تفعيل التخزين المؤقت (Caching) بشكل تلقائي. إلغاء الخدمة بشكل مجاني خلال 60 يومًا. وحاليًا تقدم الشركة خطة للشركات الناشئة بمبلغ 35.00 دولار أمريكي شهريًا وهي تشمل ما يلي: تثبيت موقع ووردبريس عدد 1. 25000 زيارة للموقع شهريًا. تبادل بيانات 50 غيغا بايت. سعة التخزين تساوي 10 غيغا بايت. أكثر من 35 قالب جاهز للتثبيت. بيئة متكاملة لتطوير معتمدة على إطار العمل Genesis. دعم فني على مدار الساعة وطيلة أيام الأسبوع. قابلية نقل الموقع على إستضافة أخرى. إصدار PHP 7.3. خوادم موزعة CDN (وهي شبكة توصيل المحتوى تتألف من مجموعة من الخوادم المتزامنة والموزعة على شبكة الانترنت في أماكن جغرافية مختلفة، تحتوي على نسخ من المواقع الّتي تضيفها شركة الإستضافة، وفي حال رغب المستخدم في الوصول لمحتوى على الانترنت مدعوم بهذه الميزة فإن الشبكة ستقوم بارساله لأقرب خادم لموقعة الجغرافي يحتوى على نسخة من المحتوى المطلوب) من أجل سرعة الوصول من كافة المناطق. أداة تقيس مدى تفاعل صفحة الويب. تشمل الخطط الأخرى ما يلي: الخطة الاحترافية - تتضمن نفس ميزات الخطة الشخصية مع مزيد من موارد الخادم وتبدأ أسعارها من 99.00 دولار أمريكي شهريًا. خطة الأعمال (Business) - تأتي بنفس الميزات مع مزيد من موارد الخادم المتاحة في الخطة الاحترافية وذلك لاستضافة مواقع الأعمال الكبيرة وتبدأ أسعارها 249.00 دولار أمريكي شهريًا. 3. Media Temple تقدم هذه الشركة تجربة استضافة من الطراز العالمي وخصوصًا للمصممين والمدونين ومهما يكن حجم موقعك فإن الشركة تستطيع التعامل معه. جميع خدمة الشركة تتناسب مع سعر الخدمة. يوجد العديد من الخيارات والخطط المتاحة والّتي تختلف من حيث السعر والمميزات والسعة وتوفر كل خطة قابلية الترقية للخطة الأعلى منها وذلك لكي تتناسب مع نمو موقعك وتشمل الخطط الّتي تقدمها هذه الشركة ما يلي: خطة الشبكة (Grid): وهي استضافة مشتركة. خطة DV Managed. خطة DV Developer. خطة DV Enterprise. خطة Managed WordPress. وعندما نتحدث عن المصممين والمدونين فإن أفضل خطة تناسبهم هي خطة Grid وهي تتكامل بشكل مثالي مع الووردبريس مع العديد من الفوائد للمبتدئين ومن بعض هذه الميزات: استضافة 100 موقع. عرض نطاق (Bandwidth) يصل إلى 1 تيرا بايت. إمكانية تخزين قواعد البيانات بعدد يصل 100 قاعدة. سعة تخزين تصل إلى 20 غيغا بايت. 1000 حساب بريد الكتروني. تقديم الدعم الفني على مدار الساعة وطيلة أيام الأسبوع وعلى مدار السنة. كلّ هذه الميزات متوفرة بسعر 20 دولار أمريكي شهريًا. وتعدّ المنصة سهلة الاستخدام ويمكنك ترقية الخطة متى تشاء. وبعض الخطط المطروحة الأخرى مثل خطة المطورين (DV Developer) والّتي تبدأ بمبلغ 30 دولار أمريكي وخطة المدراء (DV Managed) تبدأ بمبلغ 55 دولار شهريًا. 4. Arvixe هي شركة استضافة معروفة لدى أغلب المطورين والمصممين والمدونين.أفضل ميزات هذه الشركة هي الموثوقية والجودة وتوفرها بأسعار معقولة. هناك العديد من الخطط الّتي تقدمها هذه الشركة للمطورين والمصممين من ضمنها: الخطط الشخصية خطط الأعمال خطط الموزّعين توجد أيضًا خوادم VPS وخوادم مخصصة تعمل على أنظمة التشغيل Windows و Linux إذا كنت تبحث عن أداة بسيطة تستطيع تحمّل ازدياد عدد الزوار على موقعك والتأكد من أن الموقع لا يزال متوفر وفي أي وقت فاطلب خدمات هذه الشركة. من خلال الاستضافة المشتركة الممتازة، يمكن للمصممين والمدونين أن يرتاحوا حيال التعامل مع الزيارات لمواقعهم على الإنترنت وزيادة نمو هذه المواقع. توفر هذه الاستضافة ميزات مختلفة بما في ذلك: سعة التخزين غير محدودة. تناقل بيانات غير محدود. حسابات بريد إلكتروني غير محدودة. عدد قواعد بيانات غير محدود. اسم نطاق مجاني. أداة مجانية لبناء المواقع. متجر إلكتروني مجاني. لوحة تحكم سهلة. تقديم الدعم الفني على مدار الساعة وطيلة أيام الأسبوع وعلى مدار السنة. كل هذه الميزات والكثير غيرها ستكلفك 7 دولار أمريكي شهريًا فقط. مع ضمان عدم وجود رسوم مخفيّة، يمكنك أيضًا الحصول على ضمان استرداد الأموال خلال 60 يومًا في حالة عدم رضاك عن المنصة. الخطط الأخرى تشمل: استضافة الأعمال مقابل مبلغ 25 دولار أمريكي شهريًا. استضافة الموزّعين مقابل مبلغ 23 دولار أمريكي شهريًا. استضافة VPS مقابل مبلغ 43 دولار أمريكي شهريًا. 5. HostGator تعدّ هذه الشركة واحدة من أفضل مواقع الاستضافة وتشتهر بدعم العملاء على مدار الساعة وطيلة أيام الأسبوع، وهو ما يفضله العديد من المصممين والمدونين. وتقدم خدماتها بأسعار معقولة جدًا، تقدم خطط استضافة تتضمن: استضافة مشتركة. استضافة الموزّعين. استضافة VPS والخطط المخصصة. تم تصميمها لتعمل بشكل مثالي مع المبتدئين والمحترفين. وتقدم ميزة نقل الاستضافة بشكل سهل للغاية وعندما تنقل من مضيف إلى شركة HostGator فإنها توفر لك المميزات التالية: نقل نطاق مجانًا. نقل الملفات مجانًا. نقل قاعدة البيانات مجانًا. نقل الموقع مجانًا. تشمل الميزات الّتي تقدمها الشركة لمستخدميها: سعة التخزين وعرض نطاق غير محدود. لوحة تحكم سهلة. تثبيت سكربت بنقرة واحدة. دعم فني على مدار الساعة وطيلة أيام الأسبوع. يمكنك الحصول على كلّ هذه الميزات بسعر 3.96 دولار شهريًا. الخطط الأخرى تتضمن: استضافة الموزّعين بمبلغ يبدأ من 19.95 دولار أمريكي شهريًا. استضافة مخصصة لمواقع الووردبريس بمبلغ يبدأ من 5.95 دولار أمريكي شهريًا. استضافة VPS بمبلغ يبدأ من 29.95 دولارًا أمريكي للشهر الأول. خوادم مخصصة تبدأ من 119 دولار أمريكي للشهر الأول. توفر هذه الشركة ضمان وقت تشغيل المخدم بنسبة 99.9 ٪ وضمان استعادة الأموال لمدة 45 يومًا أيضًا. 6. GoDaddy هي واحدة من أكثر شركات شهرةً في مجال استضافة المواقع، كل مصمم ومطور يعرف ذلك جيدًا، وهي الخيار الأول لدى المصممين. تقدم الخدمة ميزات كثيرة للمبتدئين والخبراء. تعرف الشركة مدى أهمية موقعك الويب بالنسبة لك، لذا فإنها تعتني به جيدًا وتهتم بكلّ شيء من مدير الملفات ومدير النطاق وإدارة قواعد البيانات والّذي يعدّ رائعًا وسهل الاستخدام للغاية ويمكنك الحصول على الدعم الفني والمساعدة الّتي تحتاجها من خلال فريق الدعم الّذي يعمل على مدار الساعة وطيلة أيام الأسبوع ويمكنك التواصل معهم عبر الهاتف أو البريد الإلكتروني. ومع ذلك، فإن إدارة ملايين النطاقات تجعل الدعم أبطأ قليلًا ولكن فريق الدعم سريع الاستجابة دائمًا ويتم حل الشكاوى عادةً خلال 24 ساعة فقط. وتشمل الميزات الّتي تقدمها هذه الشركة لكل خطة: نطاق مجاني بشرط شراء الخطة السنوية. بريد الكتروني مجاني. التثبيت بنقرة واحدة لأكثر من 125 قالب مجاني. عرض نطاق غير محدود. سعة تخزين قواعد البيانات 1 غيغا. لوحة تحكم سهلة الاستخدام ومرنة. حماية ومراقبة على مدار الساعة وطيلة أيام الأسبوع لهجمات حجب الخدمة DDoS والحماية منها. على الرغم من توفر هذه الميزات بالإضافة للكثير غيرها في كل خطة، إلا أن الأسعار تختلف من حيث التخزين وعدد المواقع المستضافة. يمكنك استضافة موقع ويب فردي بمبلغ 5.99 دولار أمريكي للشهر الأول مع سعة تخزين 100 غيغا بايت لاستضافة عدد مواقع غير محدود وبسعة تخزين غير محدودة يجب عليك دفع 7.99 دولار أمريكي للشهر الأول. الخطة الأخرى تشمل استضافة مدونة أو موقع ووردبريس يبدأ من 6.99 دولار أمريكي شهريًا. 7. Eleven2 تعدّ هذه الشركة من الشركات الّتي يُنصح بها بسبب جودة الخدمة والدعم والتجهيزات والميزات ووقت التشغيل.وأغلب المصممين والمدونين يفضلون الاستضافة المشتركة بسبب أسعارها المعقولة جدًا. وتوفر أداة مجانية لمساعدتك في إنشاء موقع متميز ومتكامل في دقائق معدودة، ويمكنك إدارة موقعك بسهولة باستخدام أدوات وميزات لوحة التحكم القياسية cPanel. مع دعم فني للعملاء، فهي متوفرة على مدار الساعة وطيلة أيام الأسبوع لمساعدتك. كما أنها توفر ميزة فريدة للدردشة المباشرة الّتي تمكنك من الدردشة مع الخبراء حول مسائل استضافة الموقع الخاص بك وضمان وقت تشغيل المخدم بنسبة 99.9 ٪. إنها بالفعل شركة استضافة مُتقنة. وتقدم هذه الشركة ميزات وفقًا لخططها المختلفة الّتي تكون إما شهرية أو سنوية. تتوفر خطة S-200 القياسية مقابل 7 دولارات أمريكية شهريًا وتشمل: مساحة تخزين 250 غيغا بايت. عرض نطاق 20 تيرا بايت شهريًا. مجالات (Domains) غير محدودة. ضبط الإعدادات بشكل فوري. عدد قواعد بيانات غير محدود. امكانية النسخ الاحتياطي. ضمان استرداد الأموال خلال 60 يومًا. تقدم هذه الشركة العديد من الخطط الأخرى الّتي ستناسب احتياجاتك حتمًا. تشمل الخطط الأخرى: خطة S-300 مقابل 14 دولار شهريًا مع سعة تخزين 500 غيغا بايت وعرض النطاق 40 تيرا بايت شهريًا. خطة R-100 للبائعين مقابل 13.97 دولار شهريًا مع سعة تخزين 100 غيغا بايت وعرض النطاق 1 تيرا بايت شهريًا. خطة R-200 للبائعين مقابل 24.47 دولار شهريًا مع سعة تخزين 200 غيغا بايت وعرض النطاق 2 تيرا بايت شهريًا. خطة R-300 للبائعين مقابل 34.97 دولار شهريًا مع سعة تخزين 300 غيغا بايت وعرض النطاق 3 تيرا بايت شهريًا. تقدم أيضًا الشركة خطة استضافة سحابية والّتي تعدّ من الخطط الرخيصة نسبيًا بالموازنة مع خدمات أمازون السحابية أو خدمات مايكروسوفت. وتقدم الاستضافة السحابية الخدمات التالية: منصة سريعة جدًا باستخدام حاويات لينكس مع أقراص صلبة من نوع SSD. نسخ احتياطي يومي لضمان عدم خسارة أي جزء من بياناتك. فريق من المهندسين يعملون على صيانة الخدمة السحابية لضمان عدم توقفها. عدد من المراكز السحابية موزعة على مختلف الدول. دعم فني سريع جدًا مع سرعة رد تبلغ 10 دقائق فقط. تقدم كل هذه الخدمات مقابل 25 دولار شهريًا مع سعة تخزين 125 غيغا بايت وعرض النطاق 10 تيرا بايت شهريًا. 8. Fatcow تعدّ خيارًا جيدًا للمصممين والمدونين الّذين بحوزتهم رأس مال قليل أو الّذين يطلقون الموقع الإلكتروني لأغراض شخصية. وهي تحافظ على خدمات وميزات موقعك يعمل طول الوقت وبلا انقطاع، يجد الناس أنها موثوقة وودية للغاية. تتأكد الشركة من حصول كلّ عميل على موقع متاح دائما عبر الشبكة وغير متقطع بمساعدة النسخ الاحتياطي للخادم يوميًا. خدمة العملاء موثوقة جدًا ومتاحة على مدار الساعة وطيلة أيام الأسبوع ويمكنك أيضًا التواصل معهم عبر البريد الإلكتروني. وتقدم الشركة برامج تعليمية ومكتبة لأكثر الأسئلة شيوعًا والأجوبة عليها. وتشمل حلول الاستضافة الّتي تقدمها ما يلي: خطة Fatcow. استضافة ووردبريس. حجز دومين. استضافة VPS. استضافة مخصصة. تسجيل نطاقات. مجموعة أيقونات Farm-Fresh. تشمل الميزات الّتي تقدمها: سعة تخزين غير محدودة. عرض النطاق غير محدود. ضمان التشغيل والمتابعة بنسبة 90%. قاعدة بيانات MySQL غير محدودة. استضافة نطاقات بشكل غير محدود. صندوق بريد نوع POP غير محدود. ضمان استرداد المال خلال 30 يوم. استقبال 100 دولار أمريكي كهدية من شركة مايكروسوفت و 100 دولار أمريكي من شركة غوغل عند إنفاقك 25 دولار أمريكي في حسابك الجديد على إعلانات غوغل أو مايكروسوفت. كل هذه الميزات متوفرة بسعر 4.08 دولار أمريكي شهريًا وأما خطة استضافة مواقع الووردبريس فهي بأقل سعر على الإطلاق وهو 3.75 دولار أمريكي شهريًا. وتشمل الخطط الأخرى: استضافة خوادم VPS الأساسية وتبدأ من 19.99 دولار أمريكي شهريًا وتأتي مع معالج واحد وذاكرة وصول عشوائي بسعة 1 غيغا بايت وسعة تخزين تبلغ 40 غيغا بايت وعرض النطاق 1 تيرا بايت. استضافة خوادم VPS للأعمال وتبدأ من 47.99 دولار أمريكي شهريًا وتأتي مع معالجين وذاكرة وصول عشوائي بسعة 4 غيغا بايت وسعة تخزين تبلغ 90 غيغا بايت وعرض النطاق 3 تيرا بايت. استضافة خوادم VPS المثالية وتبدأ من 79.99 دولار أمريكي شهريًا وتأتي مع 4 معالجات وذاكرة وصول عشوائي بسعة 8 غيغا بايت وسعة تخزين تبلغ 120 غيغا بايت وعرض النطاق 4 تيرا بايت. استضافة مخصصة تبدأ من 119.99 دولار أمريكي شهريًا وتأتي مع معالجين وذاكرة وصول عشوائي بسعة 4 غيغا بايت وسعة تخزين تبلغ 500 غيغا بايت وعرض النطاق 5 تيرا بايت. 9. InMotion Hosting تعدّ هذه الشركة ذائعة الصيت بين الشركات المتوسطة والكبيرة، سواءً أكان موقع أو مدونة تقدم لك الشركة الخدمة الّتي تريدها وتأتي شهرة هذه الشركة من فريق الدعم الفني الحائز على عدة جوائز ويصل وقت تشغيل المخدم إلى 99.9٪. تتعامل الشركة مع احتياجات العمل المتنامية، من الأعمال التجارية الصغيرة إلى مستوى الشركات. تضمن الشركة سرعة جيدة وخدمة عالية مع مراكز بيانات متعددة. توفر ميزة منطقة السرعة القصوى (Max Speed Zone) لخطط VPS ورجال الأعمال والّتي تمكن المستخدمين القريبين من مراكز البيانات في الشركة الاستمتاع بالتصفح أسرع بست مرات من أي شخص أخر. تتأكد الشركة من حصولك اتاحية موقعك بشكل دائم عبر الإنترنت وبدون انقطاع ومع توفر دعم الفني العملاء على مدار الساعة وطيلة أيام الأسبوع. تم تحسين استضافة مواقع الووردبريس بشكل كبير للمدونين وتقدم لك الشركة بعض الميزات الرائعة لجعل مدونتك تنمو بسرعة. تتضمن خدمات الاستضافة: استضافة رجال الأعمال. استضافة رخيصة. استضافة VPS. خوادم مخصصة. استضافة الموزّعين. تشمل الميزات الّتي توفرها الشركة: سعة التخزين غير محدودة عرض النطاق غير محدود. باقة مواقع مجانية بأكثر من 400 مواقع مع ميّزة التثبيت بنقرة واحدة. أقراص التخزين الصلبة من نوع SSD. تقدم لوحة تحكم cPanel & WHM بشكل مجاني. إعلانات مجانية بقيمة 150 دولار أمريكي. اسم نطاق مجاني. ضمان استرداد المال خلال 90 يوم (تشمل خطة استضافة الموزّعين والاستضافة المخصصة والاستضافة المشتركة). هنالك الكثير من الميزات الأخرى المضمنة في الخطة وهي متاحة مقابل 6.39 دولار أمريكي شهريًا. وتشمل الخطط الأخرى استضافة VPS تبدأ من 29.19 دولار أمريكي شهريًا. استضافة مخصصة تبدأ من 105.69 دولار أمريكي شهريًا. استضافة الموزّعين تبدأ من 15.39 دولار أمريكي شهريًا. 10. TMDHosting عندما تقوم بتشغيل موقع أو مدونة مشهورة، فإنك ستحتاج إلى المعرفة بالعديد من الأدوات والمعلومات التسويقية. إن هذه الشركة ستسهل الأمر عليك وستقوم بتشغيل موقع الويب الخاص بك أو مدونة. وتوفر لك وقت تشغيل مضمون بنسبة 99.9٪ في جميع خطط الاستضافة، وتقدم لك أفضل تجربة استضافة وتضمن لك استرداد أموالك لمدة 30 يومًا في حالة عدم رضاك عن المنصة. توفر الشركة أيضًا استضافة للتطبيقات المفتوحة المصدر بما في ذلك استضافة Joomla، واستضافة Magneto …الخ. الميزة الّتي تتفوق بها هذه الشركة على منافسيها هي دعم العملاء السريع على مدار الساعة وطيلة أيام الأسبوع، وسيتم حل استفساراتك في غضون 15 دقيقة. كما تقدم مساعدة على أعلى مستوى مع أحدث التقنيات المتاحة. بالنسبة للمبتدئين، تقدم الشركة برامج تعليمية تساعدك خطوة بخطوة في أي مسألة تتعلق باستضافة المواقع. وتقدم العروض الترويجية بشكل يومي والّتي تكون تحديثات على خطط الاستضافة الحالية وتقدمها بأقل الأسعار للعملاء. خدمات الاستضافة الّتي تقدمها الشركة تشمل: استضافة المواقع. استضافة الموزّعين استضافة VPS استضافة الخدمات السحابية (Cloud). خوادم مخصصة تشمل الميزات المختلفة الّتي توفرها استضافة الشركة اسم نطاق مجاني للأبد. خوادم CloudLinux-powered. سعة التخزين وعدد زيارات غير محدودة. إصدارات PHP متعددة. قواعد بيانات MySQL بشكل غير محدود. ضمان استعادة المال خلال 60 يوم. وهنالك عدة ميزات أخرى مع الحزمة. تتوفر خطة استضافة الويب بمبلغ 2.95 دولار أمريكي شهريًا. والخطط أخرى تشمل: استضافة الموزّعين تبدأ من 19.95 دولار أمريكي شهريًا مع ضمان استعادة المال خلال 30 يوم. استضافة VPS تبدأ من 19.97 دولار أمريكي شهريًا. استضافة سحابية تبدأ من 5.95 دولار أمريكي شهريًا. خوادم مخصصة تبدأ من 229 دولار أمريكي شهريًا. ختامًا إن كل شركات الاستضافة السابقة موصّى بها للمصممين والمدونين، ومع ذلك أنصحك بتصفح كل خطة عن كثب لتقرر أي العروض هي الأفضل بالنسبة لك. ففي بعض الأحيان يكون الدعم الفني للعملاء هو الفارق الوحيد بين الشركات الاستضافة العادية والشركات المتميزة. ترجمة -وبتصرف- للمقال Unbiased Review of the 10 Top Web Hosting Services
  10. إن معظم المؤسسات في هذه الأيام تنتقل من نموذج أعمال المُحسن للموارد والذي يستند إلى النفقات الرأسمالية (CAPEX) إلى نموذج أعمال المُحسن للسوق والذي يستند إلى النفقات التشغيلية (OPEX). ولكن ما الذي يقود هذا التحول؟ في الحقيقة أن الهدف الأساسي من هذا التحول هو تقليل الوقت اللازم للتسوق وإسعاد الزبائن باستمرار عن طريق تقديم قيمة (Value) لهم وتُعرف القيمة بأنها منتج أو خدمة معينة والتي يكون الزبون مستعدًا للدفع مقابلها. مرحبا بك في التحول الرقمي. هل أنت مستعد لتبني عقلية DevOps في شركتك؟ لقد أشار مدير DevOps السيد Donovan Brown إلى أن DevOps إن DevOps هي رحلة تعلم وتطوير بشكل مستمر، مع وجهة لن تصل إليها أبدًا. ولهذا فإن جميع الصور الواردة في هذا المقال على شكل رمز اللانهاية. ولكوني شخصًا ذو عقلية مرئية (visual-minded)، فقد أنشأت عرضًا تقديميًا يحتوي على صور من أجل مخيم تدريب DevOps العالمي GDBC (Global DevOps Bootcamp) وهذا الحدث السنوي الذي تنسقه المجتمعات المحلية في جميع أنحاء العالم وذلك لخلق بيئة استكشافية وتعاونية لاستعراض مبادئ التحول الرقمي ورؤى DevOps. دعنا نستكشف سريعًا أربعة من الصور المرجعية (والتي تدعى أيضًا بالصور المرئية والإنفوجرافيك). واذا أردت التعمق أكثر يمكنك مراجعة كتاب The DevOps Handbook، لكُتّابه Gene Kim، و Jez Humble، وPatrick Debois، وJohn Willis. الممارسات بناءً على استطلاع قامت به شركة مايكروسوفت على مستوى العالم لتحديد أهم المجالات التي يجب التركيز عليها في DevOps والمجالات التي تحتاج إلى تحسين، والذي جاء فيه أن جميع المشاركين الذين يستخدمون DevOps يركزون على نفس الممارسات في استخدام DevOps ونفس التقنيات لتحقيق DevOps و سوف نستعرضها في الصورتين التاليتين. في الصورة الأولى نلاحظ الممارسات الخمس الأولى الرئيسية: يشجع كبار المختصين في الأداء (Performers) على تعزيز عقلية استسراع النمو، والمكافأة على الابتكار، والتعاون، والتجريب، والتعلم، والتعاطف مع المستخدمين. والسعي لعملية تسليم تطبيقات سريعة الاستجابة، والجدولة المرنة، والتجارب التكرارية. ورصد المشاكل والتعرف عليها وتخفيفها، والقضاء باستمرار على الاختناقات التي تهدر الأداء، وقياس مؤشرات الأداء المهمة وذلك لتحسين المخرجات، مثل معدل فشل التغيير المنخفض (CFR Change Failure Rate)، والوقت الأدنى للاستعادة من الفشل ( Minimal Time To Recover MTTR)، ويجب دومًا أن نحرص على معالجة المشكلات من جذورها. وأخيرًا، لنأتي إلى التكنولوجيا، والتي هي أداة تمكين ستكون محور الصورة التالية. نلاحظ في هذه الصورة التقنيات التي تركز عليها DevOps: يقوم نظام التحكم في النُسخ (Version Control System) بإدارة إصدارات التطبيق واعداداته، والبنية الأساسية، وغيرها من الشيفرات البرمجية للتطبيق. وهو يتيح التعاون بين الفِرق ومراقبة الأنشطة مثل عمليات النشر (Deployments). يستخدم كبار المختصين في الأداء نسخ فرعية من التطبيق وذلك لعزل التغييرات قصيرة الأجل ومعاينتها قبل أن يتم دمجها في النسخة الأساسية (Master)، ويستمر مراجعة وتدقيق طلبات الدمج باستمرار ويتم إصدار النُسخ على أساس ذلك. يجب أن يُنظر للاختبار على أنه نشاط مستمر، وأن يُدمج في مخطط سير العمل للمطور وذلك من أجل تحقيق التكامل المستمر مع التغيّرات (Continuous Integration CI) والتسليم المستمر للتطبيق (Continuous Delivery CD). يتيح لك التخزين السحابي توفير البنية التحتية اللازمة والفعّالة وذلك للتحرك بأقصى سرعة ممكنة عند الضرورة وذلك تجنبًا للوقت المبذول في بناء البنية التحتية المناسبة للشركة. وأخيرًا، تمكنك المراقبة من تكوين فرضية، أو التحقق من صحة التجارب، أو دحضها، واكتشاف المشاكل بشكل استباقي قبل حدوثها وفهم حالة التطبيق. يسرد الشريط الأسود الموجود على يمين الصورة المنتجات التي يجب أخذها في عين الاعتبار عند البحث عن تقنية للتطوير والإنتاج والهندسة المشتركة وبيئات أخرى. حاول أن تقيّم المنتجات المدرجة وحدّث هذه القائمة بانتظام لأن هذا الجزء متغير وإلزامي بنفس الوقت من أجل اختصار الوقت. العادات بناءً على قصة تحوّل 65,000 مهندس إلى DevOps بمساعدة فريق خدمات Visual Studio، تركز هذه الصورة على العادات الخمس الرئيسية التي تعلموها أثناء تحولهم إلى DevOps. يعدّ التركيز على العملاء، والاستقلال الذاتي للفِرق، وتنسيق الشركة، والتركيز على عادات Shift Left، هي عوامل التطوير لمنهجية التصميم المرن (Agile)، كما أن عقلية الإنتاج أولًا والبنية التحتية مثل الموارد المرنة جميعهم خواص تتفرد بها عقلية DevOps. يعدّ التركيز على العملاء جزءًا من سعينا لإمتاعهم وهاجسنا بتقديم خدمة قيّمة لهم. ويجب أن تُصغ إلى المستخدمين بشكل نشط أي أن تسمع لمشاكلهم واقتراحاتهم، وتمكين الميزات وتعطيلها تدريجيًا، وإجراء التجارب المستمرة، وقياس مؤشرات الأداء الرئيسية. واستخدام المُراجعات المتوفرة لتحسين الأداء أو المنتج ومحاولة الإستفادة بأكبر قدر منها وزيادة التأثير على العملاء إلى أقصى حد. تُعد عادات Shift left طريقةً لاختبار البرمجيات والنظام، ويتم إجراء الاختبار في وقت مُبكر من دورة الحياة (أي تم نقله إلى اليسار في الجدول الزمني للمشروع). ويشجع shift left على المراجعات، والتحقق من الصحة، والموافقات على كل من الاختبار والأمان في أقرب وقت ممكن في دورة توصيل الميزات وذلك لزيادة الجودة وتمكين أسلوب الفشل السريع (أحد أهداف هذه الفلسفة هي تقليل الخسائر، وذلك عندما يكشف الاختبار وجود شيء ما لا يعمل فالأفضل دومًا تجربة شيء آخر بسرعة. أي تجاوز الفشل بسرعة). عندما يتجاوز الأعطال الفنية الحد المحدد مسبقًا (مثلا خمسة أخطاء لكل مهندس)، يجب تشجيع الفِرق التي تعمل على المميزات على تعليق العمل حتى يتم جميع الأخطاء الموجودة. إن استقلالية الفريق وتنسيق الشركة يهتمان بما تقوم الشركة بإنشائه وكيفية إنشائه وسبب إنشائه. لذا ستحتاج إلى وتيرة عمل سريعة ونشاط دائم داخل الشركة لتمكين فِرق القيادة وفِرق المميزات من التعاون بشفافية وفعالية. تمتلك أكثر فرق المميزات فعالية خاصية تحويل الفكرة إلى نتائج، مع الاستقلال الذاتي للقرارات حول كيفية تطويرها ودعمها لخصائص ومميزات هذه الفكرة. إن عقلية الإنتاج أولًا لا تُميّز كيفية التعامل مع المميزات والأخطاء خلال التطوير والاختبار والدعم الفني. وإنما كل شيء يجب أن يكون مُؤتمت، ومُحرر، ومُحسن في الإنتاج. ويتم الاعتماد على النشر الدائري والحلقات (ring-based deployment and rings) والتي تنص على عرض التغييرات لمستخدمين محددين ومراقبتها والتحقق من صحتها قبل عرضها على جميع المستخدمين وذلك للحد من الأخطاء التي تنتج أثناء إحداث تغييرات في المميزات المطروحة، ومعالجة جميع المشكلات من جذورها، وتذكر أن تكون واضحًا عند حدوث مشكلة معينة وتوضيحها وما هو السبب الرئيسي لظهورها والحل الذي استخدمته لتجاوزها (لان المستخدم سيكون أكثر تفهما في حال كان لديه معرفة بسبب حدوث المشكلة والآلية المتبعة في حلها). تصف البنية التحتية مثل الموارد المرنة كيفية تكيّف الحلول المطروحة مع الخدمات السحابية والحاويات (container) والخدمات المصغّرة (Microservices). يجب تبني تحوّل عملي يكون منطقيًا لشركتك وأهدافك ومنتجاتك وثقافتك. كما هو الحال مع العادات السابقة، من المهم أن نُفضّل البنية الاستقلالية على بنية الوصفية وألا نُغير كل شيء في وقت واحد. الشروع في العمل يجمع التصور الأخير بين كل ما سبق ويقترح خمس خطوات للبدء مع Devops. أفضّل أن أبدأ بالتقييم لقدرته في تحديد المناطق الرئيسية التي يمكن تحسينها. توفر التقييمات معيارًا لعقلية وأداء DevOps مقارنة بباقي المنهجيات المتبعة في قطاع الصناعات الأخرى. من المهم أن نفهم أي جزء من عملك يسير على ما يرام وأي جزء يحتاج لأن تستثمر فيه لنقله إلى المستوى التالي. إن كُلًا من التقييمات التابعة لشركة DORA و تقييمات شركة مايكروسوفت بالنسبة Devops هي تقييمات رائعة للبداية. بالإضافة إلى ذلك، إجمع أدوات القياس لاستخدامها كقاعدة لقياس التقدم - على سبيل المثال، معدل تكرار النشر (Deployment Frequency) والوقت اللازم لتطبيق التغييرات (lead time for changes)، ومتوسط وقت الإصلاح (mean time to repair)، ومعدل فشل التغيير (change failure rate). إن التحدي الأكبر الذي سوف يواجهك هو الناس وثقافاتهم. يحتاج كل شخص لأن يعتنق فكرة التحول الرقمي، وأن يفهم كيف سيتأثر في هذا التغيير، وأن يُشجع على رفع مستوى الشفافية, ويجب عليه المشاركة بشكل فعّال وأن يتحمل المسؤولية الكاملة للقيمة المضافة للخدمة المتوقعة منهم. ويشمل هذا التحدي أيضًا مجلس قيادة الشركة والذي يحتاج لأن يقدم الدعم والإلهام والتمكين وتوجيه الموظفين لرؤية واضحة. وبناء عليه ستقوم إما بإنجاح هذا التحول كفريق واحد أو بإفشاله. وبدون وجود أشخاص ملتزمين وثقافة تجريبية، فإن بقية رحلة التحول إلى DevOps ستفشل. إن العملية (Process) هي نظامك الهندسي، والذي يقوم بتمكين الفرق من إصلاح المشاكل بشكل مباشر، واستخدام الإدارة والتطوير الرشيق (lean management and development)، وتقديم خدمة قيّمة باستمرار. ويوفر نظام الهندسة المشترك الثبات، ويخول فِرق المميزات، ويتيح ويشجع الجميع على دعم بعضهم بعضًا والمساهمة فيه. يجب أن تتضمن أهم أهداف عملياتك التركيز على الجودة، واحتضان البنيات خفيفة الترابط (loosely coupled architectures) لتمكين التطوير، والإدارة الخفيفة، والأتمتة، والإصدارات المتعددة في اليوم، والاحتفال بالنجاح كفريق وكشركة. المنتجات هي أسهل وصلة في السلسلة. فهي تمكن الجميع من التركيز على ما هو مهم ألا وهو توفير قيمة (Value) للعملاء. تعدّ القيمة من أهم الأشياء الّتي تُرضي المستخدمين. تتضمن مؤشرات الأداء الرئيسية مثل تكرار النشر، والوقت اللازم لتطبيق التغييرات، ومعدل فشل التغيير، ووقت الاسترداد من الخطأ. سواء كنت تتعامل مع كل هذه الخطوات دفعة واحدة أو خطوة بخطوة أو حتى لو أنك ابتكرت خطة للانتقال وذلك بالاستعانة بكل الخطوات التي ناقشناها. تذكر دومًا أن تكون واقعيًا. أيّ من صور أحببتها؟ أيّ منها أحسست بأنها لا تضيف أي قيمة؟ وما الجزء الذي تعتقد بأنه مفقود؟ دعونا نتعاون لكشف الغموض عن DevOps ومساعدتك وموظفينك على التألق. يحتاج المستخدمون إلى فهم أنهم ليسوا وحدهم وأن يعرفوا بأنه يمكنهم الاعتماد على الممارسات المُجربة والمُثبت فعاليتها وعلى النهج التعليمي الواقعي. ترجمة -وبتصرف- للمقال Visualizing a DevOps mindset لصاحبه Willy-Peter Schaub
  11. تعدّ المواقع المبنية على ووردبريس من أكثر الأهداف عرضةً للهجوم على الإنترنت، إذ أن قابلية تعرضها للاختراق أكثر من أي نوع آخر من المواقع. فإذا كنت تملك موقعًا مبني على ووردبريس، أو أحد أصدقائك، أو أحد معارفك ولم يتعرض أي منكم للاختراق بعد، فأنتم إما محظوظون جدًا أو أنك تملك أشخاص حذرين جدًا يحيطون بك! وبما أن هذه المواقع تعمل على الإنترنت وتُشغّل مئات الآلاف من الشيفرات البرمجية في الخلفية، فمن المهم الاهتمام بالقضايا الأمنية الخاصة بالموقع وخاصة أن ووردبريس منصة معروفة ومشهورة واستهدافها من قبل المهاجمين هو أمر وارد الحدوث. عندما كانت شركة مايكروسوفت ويندوز منصة جديدة نسبيًا ومسيطرة على مواضيع تخص قضايا الحماية والأمن، صرّح القائمون عليها أن من أسباب تعرض المنصة لعدد من الهجمات هو الأخطاء والثغرات الأمنية المرتكبة من قِبل الشركة نفسها، وهو ما تم استغلاله على الفور عند صدور نظام الويندوز. وكذلك هو الحال في المواقع المبنية على ووردبريس والّتي تحتل وبقوة حوالي 34.8% من إجمالي عدد المواقع على مستوى العالم وذلك بحسب إحصائية نشرها موقع w3techs. وهذا شيء رائع، ولكنه أيضًا يفرض علينا أن نأخذ قضايا الحماية الأمنية على محمل الجد، فعلى سبيل المثال لو وجد شخصٌ ما ثغرة أمنية رئيسيّة في ووردبريس عندها سيكون بإمكانه وبكل سهولة أن يسيطر على الآلاف من الخوادم في غضون ساعات. ولهذا السبب تعد مواقع ووردبريس الهدف الأكثر عرضةً للهجوم ويجب علينا الاهتمام بحمايتها اهتمامًا بالغًا. هل يعدّ هذا المقال دليلًا كاملًا لحماية ووردبريس بالطبع لا وإنما هو مجموعة من أفضل الممارسات الأمنية في ووردبريس. أدرك جيدًا أن عنوان هذا المقال "الدليل الكامل في أمن مواقع ووردبريس" مبالغ فيه قليلًا، فهو بحد ذاته ليس كذلك وذلك لأن المسائل الأمنية ليست عبارة عن قواعد ثابتة، أو مجرد تثبيت إضافة أمنية معينة، أو عمل أي شيء آخر مقيّد بفترة زمنية. لا إنه ليس كذلك! بل هو عبارة عن ممارسات تتطور باستمرار وذلك لأن الثغرات الأمنية متجددة باستمرار وتفرض علينا دومًا تحديث سياساتنا الأمنية الّتي نتبعها. يمكن تمثيل مفهوم الأمن بأشياء تم وضعها في صندوق ومن ثم تم وضع الصندوق بعمق 400 قدم تحت سطح الأرض في مكان لا يعرفه أحد وسط الصحراء، الواضح هنا أن الأشياء في مأمن ولكنها غير مفيدة أبدًا. من الجدير بالذكر هنا أن أي شيء يعمل على شبكة الإنترنت، على سبيل المثال المواقع المبنية على ووردبريس، لديها بيئة متغيرة باستمرار ويمكن أن يشكّل ذلك خطرًا عليها فيصبح من الواجب العمل على حمايتها من التهديدات. وحتى يتم ذلك، سوف نعمل جاهدين على تحديث كافة المعلومات الّتي تحتاجها في هذا المقال. سأغطي في هذا المقال جميع الأساسيات الّتي ستحتاجها والكثير من الممارسات الأخرى الّتي ستساعدك في مواجهة القضايا الأمنية. بالرغم من أنني أتفق بأنه لا يمكن اعتباره دليلًا كاملًا. هل مواقع ووردبريس ليست آمنة؟ من الأمور الأكثر شيوعًا عند الناس الّذين يبحثون في موضوع أمن وورد بريس أنهم يشكّون في كونه آمن ومحمي في الأصل، أو أنهم يسمعون من شخص أخر يؤكد لهم على أنه ليس كذلك، وهذه تعد شائعات وشكوكًا حول أمان ووردبريس، هناك الكثير ممن يحاولون استغلال جهلك بآلية حماية ووردبريس فيحاولون بيعك منتجاتهم على الإنترنت سواءً أكانت خطة لأمن ووردبريس، أو خطة استضافة، أو حتى برنامج يدير كلمات المرور، لذلك هدفي في هذا المقال إزالة الغموض عن أفضل ممارسات الأمنية لحماية موقعك المبني على ووردبريس. وحتى نجيب على هذا التساؤل يجب علينا معرفة أن ووردبريس عبارة عن نظام نظام إدارة محتوى إلكتروني مفتوح المصدر ويتميز بأنه واسع وله العديد من الطرق للتركيب على مواقع الاستضافة وضبط إعداداته وتخصيصه والّتي يمكن أن تكون بأكثر من طريقة. وانطلاقًا من هذا التنوع نجد في بعض الأحيان مواقع ووردبريس غير آمنة والّتي من المحتمل أن تُخترق خلال الـ 24 أو 48 ساعة القادمة. وإذا كنا نتحدث عن النظام الأساسي الموجود في الملف المضغوط والّذي يمكنك تنزيله من الموقع الرسمي للوردبريس فإنه وبرأيي الشخصي آمن تمامًا. بشكل عام، كلّ يوم هناك احتمال 0.00001٪ بأن تظهر مشكلة غير مسبوقة في ووردبريس والّتي يمكن أن يتعرض من خلالها هذا النظام للهجوم على مستوى العالم. في الوقت الحالي تأتي مواقع ووردبريس مع ميزة التحديث التلقائي المدمج، وبإمكان شركات الاستضافة تحديث إصدار موقعك في حال فشل التحديث التلقائي. فهذا أمر بالغ الأهمية، لأنه يمكن أن يكون الإصدار 5.2.4 يواجه مشكلة أمنية ما والّتي سيكتشفها شخص ما في الأشهر أو السنوات القادمة. فتعمل منظمة ووردبريس جاهدة على تحديث نظامها باستمرار، فتصدر مثلًا إصدار 5.2.5 وتصدر بعدها إصدار 5.2.50 والّذي يعمل على إصلاح تلك المشاكل أو الثغرات الأمنية المكتشفة في الإصدار الّذي قبله. يمكن عد ووردبريس آمن وذلك عندما تحافظ على تحديث موقعك بأحدث إصدارات ووردبريس المتاحة. والتأكد من أن موقعك موجود على استضافةٍ موثوقٍ بها، والقيام بتثبيت التحديثات الموثوقة للإضافات الموجودة لديك، وعندها فقط يمكنك عد ووردبريس آمنًا تمامًا. ولكن عندما لا تقوم بأي شيء مما سبق، فمن المحتمل وبشدة أن يكون موقعك غير محمي بل ومُعرض للاختراق أيضًا. شبكة الروبوتات المقرصنة (Botnets) عمومًا إن المواقع المبنية على ووردبريس ليست معرضة للخطر بسبب الهجمات الفردية من أشخاص مجهولين وإنما الخطر الحقيقي يأتي من الهجمات الآلية. بالتأكيد هناك احتمال كبير أن تجد ولو شخص واحد يحاول الوصول لموقعك. ولكنه لن يشكل خطرًا مثل الهجمات الآلية. بالطبع هذا في حال ما لم تكن أغضبت أحدًا من عباقرة الاختراق. في الحقيقة إن التهديد الحقيقي لمواقع ووردبريس والّذي يعرضها للخطر هو الهجمات الآلية والّتي تُبرمج من قِبل أشخاص يحاولون الاستيلاء على موقعك، فيتحكم هؤلاء الأشخاص بالهجمات باستخدام الحواسيب، ولذلك ليس هنالك أشخاص يحاولون بأنفسهم الدخول إلى موقعك بواسطة أسماء مستخدمين وكلمات مرور مختلفة وإنما هي عملية آلية تُدار بواسطة الحواسيب. وغالبًا ما تجد هؤلاء الأشخاص (المخترقين) يكتبون برامج للبحث عن مواقع ووردبريس على شبكة الإنترنت بالكامل ومحاولة تسجيل الدخول إلى جميع هذه المواقع الّتي يجدونها. وهم نفسهم أيضًا من يحاولون استغلال الثغرات الأمنية المعروفة في الإضافات. ويكون هدفهم في أغلب الأحيان اختراق الكثير من الحواسيب لتكوين شبكة كبيرة من الحواسيب المقرصنة والّتي تسمى شبكة الروبوتات المقرصنة وتسمية الروبوتات جاءت من كون جميع هذه الحواسيب تخدم المخترق دون اختيارها تمامًا مثل أجهزة الروبوت وبمجرد أن ينضم جهاز جديد لشبكة الروبوتات فإن المخترق يستطيع التجسس على صاحب الجهاز دون أن يشعر صاحب الحاسوب بذلك. ويكون هدف هذا المخترق إما جمع المعلومات من خلال التجسس وسرقة معلوماتك السرية مثل بطاقات الائتمان والحسابات البنكية أو شن هجمة حجب الخدمة الموزعة (DDos Attack)، أو إرسال رسائل مزعجة (Spam)، أو تنفيذ مهام أخرى يريدها المخترق. وهنا يبرز لدينا مفهوم واضح لنموذج التهديد الخاص بموقع ووردبريس الخاص بك إذ أنه يتكون في الغالب من هجمات تلقائية مُدارة من قِبل أشخاصٍ بواسطة عناصر غير بشرية، ولذلك فإن القيام ببعض الممارسات الأمنية أمر مهم للغاية. لماذا تتعرض مواقع ووردبريس للاختراق؟ يجب في معظم الأحيان أن تقلق بشأن الهجمات الآلية، بدلًا من التركيز على هجمات الأفراد، وأن تعرف السبب وراء محاولتها الهجوم والسيطرة على الموقع الخاص بك. فهذا الموقع الصغير بالنهاية موقع ويب خاص بك أنشئ لأحد هذه الأسباب: مشاركة صورك الخاصة مع الأصدقاء. بيع الحاجات الخاصة بك على الإنترنت. الكتابة والتدوين للترفيه والسعادة …إلخ. هذه الروبوتات في الحقيقة لا تستهدف موقع ووردبريس الخاص بك إلا إذا كان موقعك يحتوي على بعض الثغرات الأمنية والّتي ستكون مدخلها للسيطرة عليه. وتختلف الأهداف الّتي تدفع المخترقين للاستيلاء على موقعك ولكن من أكثر الأسباب شيوعًا للاستيلاء المواقع هي كالتالي: إعادة توجيه حركة المرور إلى مواقعهم. الاستيلاء على تفضيلات محرك البحث الخاص بك المتصدر في جوجل (SEO rankings) لسرقة عصير الروابط ووضعها في صفحاتهم. تشويه الموقع للغطرسة والتفاخر أو لإيصال رسائل سياسية. التنزيل بالتنقل - مما يتسبب بجعل زوار موقعك ينزلون برامج ضارة وفيروسات …إلخ. فتح ثغرات في الموقع لاستغلالها لاحقًا. الوصول إلى بيانات موقعك، وقوائم المستخدمين، وسجل عمليات الشراء …إلخ. إرسال رسائل عبر البريد الإلكتروني عشوائيًا - فإذا كان موقعك يمكنه إرسال بريد إلكتروني، فيمكنهم استخدام ذلك لإرسال رسائل البريد الإلكتروني الخاصة بهم أيضًا. استخدام موارد الخادم (وحدة المعالجة المركزية في الغالب) لإجراء عمليات حسابية مفيدة والّتي تقوم غالبًا بتعدين العملات الرقمية مثل البتكوين. إن هذه الهجمات الآلية هي الّتي يتوجب عليك التفكير بها والحذر منها. فمن المحتمل جدًا أن يكون المتسلل ذكيًا ولديه أسبابه الدافعة اختراق موقعك والّتي من الممكن أنني لم أذكرها. ما أحاول توضيحه هو أن موقعك غير محمي حمايةً كافية. قد تظن أنه لا يوجد لديك قائمة مستخدمين مثيرة للاهتمام، ولكن عليك أن تضع ببالك أن هناك خادمًا يمكن استخدامه لتعدين العملات الرقمية أو لإرسال رسائل البريد المزعج، وذلك باعتبار أن لكل خادم وحدة معالجة مركزية، ولذا فإن الغالبية العظمى من الخوادم تستطيع إرسال بريد إلكتروني. الحماية المتكاملة للموقع يعتمد أمان مواقع ووردبريس على تكامل مجموعة من المسائل، وليس على مسألة واحدة بحد ذاتها. وفي الحقيقة إن ووردبريس قائم على مجموعة كبيرة ومتنوعة من التقنيات، وهذا ما يجب علينا أخذه بالحسبان فمن الممكن أن تحتوي بعض الأجزاء الّتي يتكون منها ووردبريس على ثغرات. على سبيل المثال يستخدم ووردبريس لغة PHP (وهي لغة برمجة صُمّمت أساسًا لتطوير وبرمجة تطبيقات الويب) في بناء نواته الأساسية ومن الممكن إن تحتوي بعض إصداراتها أحيانًا على ثغرات أمنية. ولكن إذا كنت تُحدّث الإصدارات بانتظام، فلن تؤثر عليك. أما إذا لم تكن كذلك، فقد تؤثر المشكلات الّتي تحتوي عليها لغة PHP على الموقع الخاص بك. هناك احتمال بأن يكون هناك شيء آخر في ممارسات الأمان الرئيسية الخاصة بالموقع غير صحيحة. فمثلًا إذا كانت خبرتك قليلة في ضبط إعدادات خوادم الويب، فقد تفعل أشياءً تظن بأنها ضرورية لتشغيل شيء ما في موقعك دون أن تدرك أنها ستؤدي إلى آثار أمنية سلبية عميقة. وهذا يعد أحد الأسباب الرئيسية الّتي تجعلني أعطي أكبر قدر من الأهمية لضبط إعدادات خوادم الويب للمحترفين. هذا لا يعني أنه لا يمكنك إعداد الخادم الفعلي الخاص بك بنفسك، أو شراء خادم افتراضي خاص VPS بسعر رخيص وضبط إعداداته باستخدام سكربت إعداد كتبه شخص آخر. ولكن فعليًا عليك أن تكون على ثقة ودراية في الاعدادات الّتي تشغّل ووردبرس فوقها. لأنك إذا قمت بضبط موقعك ضبطًا صحيحًا، ولم تنتبه لوجود خطأ في ضبط إعدادات قواعد البيانات MySQL، فعندها لا تزال أشياء سيئة جدًا ممكن أن تحدث لموقعك. تجنب توصيات الأمان الشائعة غير الضرورية قبل ذكر ما يجب عليك اتباعه، لابد أن أذكر لك أمرًا أرى أنه من الواجب ذكره هنا إذ شاع استخدامه رغم قلة الفائدة المرجوة منه. معظم هذه النصائح لا تضر نسبيًا بالموازنة مع فائدتها إذا أدت عملها. ولكن سبب عدم توصيتي لك باستخدامها هو أن فوائدها وإن وجدت ستكون قليلة جدًا. ومن الممكن أن تتجاهل الممارسات الأمنية الأكثر قيمة منها عندما تنفق على هذه الممارسات وقتًا طويلًا لا تستحقه بالموازنة مع المكاسب الّتي تحققها. لديك مطلق الحرية بالقيام بها أو لا. ومن هذه التوصيات ما يلي: 1. إخفاء نسخة ووردبريس سنبدأ بأكثر نصيحة مشهورة وهي إخفاء رقم إصدار ووردبريس الخاص بك، أو إخفاء بأنك تعمل على ووردبريس من الأساس وهذا صعب جدًا القيام به أما الخيار الأول فهو في الأساس لا قيمة له. عمومًا من الصعب إخفاء أنك تقوم بتشغيل ووردبريس، ومعظم الأشخاص يحاولون القيام بذلك يغيرون وسم في مواقعهم أو التخلص منها. ولكن أي مخترق ذكي لن يعتمد فعليًا على ذلك، فذكر أحد مشرفي المواقع الّتي تعمل على أنظمة مختلفة غير ووردبريس بأنه لاحظ أشخاص يبحثون في موقعهم كما لو أن موقعهم مبني على ووردبريس بالفعل. إخفاء إصدار ووردبريس الخاص بك أقل حساسية. جوهر الموضوع هنا هو أن الهجمات الآلية ستقوم بالتحقق في كون موقع ووردبريس الخاص بك موجود على إصدار معروف ومحدّث من ووردبريس، ومن ثم يهاجمك إذا كان إصدار ووردبريس مدرجًا في قائمة الإصدارات المستهدفة. شخصيًا لم أسمع بأي أحد ذكر أن الهجمات الآلية تعمل بهذا الأسلوب، ولا أدري لماذا يفترضون مثل هكذا افتراض. اعتقد أن هذه النصيحة تفقد قيمتها لو كان موقعك محدّث بأحدث إصدار من ووردبريس، لذلك هنا تكمن أهمية تحديث الإصدار بدلًا من إخفاء رقم إصدار ووردبريس. 2. تعطيل الواجهتان البرمجيتان XML-RPC و JSON REST في هذا الصعيد أشعر أن الحديث موجه إلى الأشخاص الّذين يستخدمون موقعهم كواجهة تطبيقات برمجية (API) فقط، فليس هناك أي ضرر حقيقي في تعطيل الواجهة البرمجية XML-RPC لووردبريس (وهو بروتوكول إجراء عن بعد يستخدم صيغة الترميز XML لتمثيل البيانات ويستخدم HTTP لنقل البيانات ولتنفيذ الإستدعاءات). تُستخدَم الواجهة XML-RPC بواسطة عدة أدوات مثل أداة Marse edit وتطبيق ووردبريس للهواتف المحمولة وأدوات أخرى مشابهة من أجل الاتصال بموقعهم. وأصبح من الممكن الآن لتلك الأدوات الاعتماد على واجهة التطبيقات البرمجية Restful (وهي طريقة للتخاطب بين الأنظمة على الإنترنت والّتي تعتمد على بروتوكول HTTP وعلى الدوال المعروفة في هذا البروتوكول وتعتمد أيضًا على خاصية أن كلّ خدمة يمكن الوصول إليها عن طريق رابط فريد) أصبح من الممكن أيضًا استخدام هذه الأدوات للاعتماد على واجهة Rest بدلًا من XML-RPC، على الرغم من أن أغلب هذه الأدوات لم تُنشأ لهذا الغرض. وتعد واجهة التطبيقات البرمجية JSON REST إضافة جديدة إلى ووردبريس، ويمكن أن تلبي استخدامات مشابهة للتقنيات السابقة. بالإضافة إلى ذلك، تعمل ووردبريس داخليًا على الاستفادة من الواجهة JSON Rest للميزات الّتي توفر تفاعلًا أفضل. إن كلا الطريقتين السابقتين تعد من الطرق الّتي يمكن للمهاجم تتبعها بعد موقعك. وهناك سجلات معروفة للأشخاص الّذين يقومون بهذه الهجمات. والسبب وراء إدراجها في قائمة الأشياء الّتي لا أوصي بها، هو أن كلا النوعين من الهجمات ليسا شائعين للغاية. كما أن واجهات التطبيقات البرمجية (APIs) مفيدة للغاية، وربما تجد شيئًا ما في المستقبل يكون مفيدًا لموقعك وعندما تحاول القيام به على موقعك فتجد أنه لا يعمل أو يتسبب في تعطل موقعك وذلك لأنك حظرت واجهات التطبيقات البرمجية بشكل كامل. إذًا الحل الأفضل هو الحصول على جدار حماية على الإنترنت، ومن الناحية المثالية أن يكون مضيف موقعك يحتوي على جدارٍ ناري. وإن لم يكن الحال كذلك، فيمكنك شراء جدار ناري بنفسك من شركات مثل Sucuri (وهي شركة أمنية معروفة، ولديها شهرة كبيرة على شبكة الإنترنت. توفر جدار حماية قوي للمواقع المبنية على ووردبريس، وتعمل على حماية المواقع من هجمات الحرمان من الخدمة [DDos Attack]، وغيرها من تهديدات أمان مواقع ووردبريس) أو Cloudflare وكلاهما يوفر خدمات متشابهة. وباستعمال هذا الجدار يجب أن يتوقف احتمال حدوث حركة زيارات غير طبيعية لواجهات التطبيقات البرمجية، وعمومًا أن تدع الأشياء الجيدة فقط تمر عبرها هو أمر غير مضمون ولكنه يعتبر حلًا أفضل من إيقافها بالكامل. 3. تغيير بادئة قاعدة بيانات في مرحلة ضبط إعدادات ووردبريس يوجد حقل نصي يتطلب بادئة لقاعدة البيانات، والقيمة الافتراضية له تكون _wp. يخزن ووردبريس بياناتك، والمنشورات والتعليقات والمنتجات وغيرها في جداول قاعدة البيانات والّتي تبدأ بهذه البادئة. ما أريد توضيحه هنا هو أن القيمة الافتراضية أقل أمانًا ويجب عليك بدلًا من ذلك جعلها مثل _jadfl، والّتي من غير المحتمل أن تمتلكها مواقع ووردبريس أخرى. في هذه الحالة احتمالية حمايتك بتطبيق هذه الخطوة قليل. بدلًا من ذلك يجب عليك أن تحمي نفسك بشكل خاص من هجوم حقن قواعد البيانات (SQL-injection) لأنه غالبًا من خلاله تُخترق مواقع وورديريس، ولكن لكي يحدث ذلك، يجب أن يكون إصدار ووردبريس أو مكون إضافي يحوي على ثغرة تُمكّن المخترق من حقن قواعد البيانات من خلالهم. لذلك إذا كانت الإضافات أو القوالب في ووردبريس محدّثة، فلن تحصل فعليًا على فائدة إضافية من ذلك. وعلاوةً على ذلك أنه من السهل جدًا إذا كان لديك ثغرة أمنية تتيح هجوم حقن قواعد البيانات في موقعك، فإن المهاجم سيستعرض جداول قاعدة البيانات الخاصة بك، ولكن ليس بالسرعة العمياء على افتراض أن المنشورات موجودة في جدول باسم wp_posts، بل إن عدد المهاجمين الّذين يفترضون أن هذا هو موقع جدولك ولا يتحققون منه ربما يكونون نسبة مئوية صغيرة من الأشخاص الأذكياء بما يكفي للقيام بالهجوم في المقام الأول. أعتقد أنه إذا كنت تقوم بضبط إعدادات موقع جديد، ووجدت طريقة سهلة لتغيير بادئة قاعدة البيانات الخاصة فغيّرها مباشرةً، ولكن إذا كان موقعك يستخدم بادئة _wp لقواعد البيانات، فلا تُضع وقتك في محاولة القيام بذلك وخاصةً إن لم تكن مطور ويب. 4. إعادة تسمية عنوان URL لتسجيل الدخول إلى ووردبريس النصيحة الأخيرة الّتي اعتقد أنها لا تستحق الاهتمام فعلاً هي نقل عنوان URL لتسجيل الدخول الخاص بك من example.com/wp-login.php إلى شيء مثل example.com/my-secret-url-for-puppy-login. تم تسهيل ذلك من خلال بعض إضافات الأمان في ووردبريس وهي ليست مضيعة للوقت تمامًا. لا أستطيع أن أنكر فكرة أنه إذا تعذر على المهاجم العثور على صفحة تسجيل الدخول الخاصة بك، فلن يتمكن حتى من محاولة شن هجوم القوة الغاشمة (Brute force) على كلمات المرور الخاصة بك (سنتحدث لاحقًا في هذا المقال عن هذه النقطة بالتفصيل). المشكلة في هذه النصيحة هي أنه إذا وجد أحد المهاجمين صعوبة في العثور على صفحة تسجيل الدخول لموقعك، فربما ستجد أنت أو زملاؤك صعوبةً في ذلك أيضًا. إذا كانت لديك طريقة آمنة وموثوق بها لوضع إشارة مرجعية (Bookmark) على الصفحات الّتي تجدها سهلة الاستخدام، ففعل ذلك مباشرة فأنت بهذه الخطوة تحظى ببعض الفوائد الأمنية المتواضعة. ولكن مرة أخرى، فإن الفائدة ليست كبيرة إذا قمت ببعض الأشياء الأخرى بشكل صحيح. إذا كانت جميع الحسابات على موقعك تملك كلمات مرور جيدة، فمن غير المرجح أن ينجح هجوم تخمين كلمة المرور. أضف إلى ذلك أنه إذا كان لديك طريقة ما للحد من عدد محاولات تسجيل الدخول الفاشلة لحساب معين في موقعك ضمن فترة زمنية قصيرة، فأنت بذلك تقلص احتمال نجاح هجوم تسجيل الدخول. وهذان العاملان معًا - كلمات مرور جيدة وقيود على عمليات تسجيل الدخول الفاشلة - أكثر قيمة من عنوان URL الغامض لتسجيل الدخول إلى موقعك. أفضل الممارسات العامة لتأمين مواقع ووردبريس هناك بعض المهام الشائعة الّتي يجب عليك القيام بها إذا كنت تريد أن تحافظ على أمان موقعك. يوجد العديد منها ولكن سأسرد لك أبرزها وما يحب عليك فعله دائمًا. هذه القائمة ليست مرتبة حسب الأهمية، ولكن نسبيًا عند قيامك بالخطوات الخمس الأولى، فستكون متقدمًا على 50٪ من مواقع ووردبريس الأخرى على الإنترنت. ومن غير المحتمل أن تواجه مشكلة أمان لا يمكن إصلاحها في موقعك، وإذا كنت تطبق جميعها، فسأتفاجأ حقًا إذا تعرض موقعك للاختراق. هذا بالطبع ليس ضمانًا، بل إحتمال أرجحه من واقع خبرتي الشخصية. 1. استعمال كلمات مرور قوية الطريقة الأساسية الّتي يمكن من خلالها مهاجمة كلّ موقع من مواقع ووردبريس على الإنترنت هي طريقة بسيطة وهي تخمين الروبوتات كلمات المرور للحساب بانتظام، على كلّ موقع من مواقع ووردبريس على الإنترنت تقريبًا. فإذا كان لديك كلمة مرور سيئة فاحتمال أن تفقد حسابك كبيرة، وبالتالي موقعك. بعض كلمات المرور السيئة مثل: password p455w0Rd [اسم الموقع] charlieiscute هناك العديد من المدارس الّتي تشرح أهمية قوة كلمة المرور وطريقة جعلها كذلك. لكن جميعنا نتفق على أن هذه الكلمات سيئة إلى حد كبير، نظرًا لاحتمالية أن يخمنها المهاجم إذا علِم المنهجية المتبعة في صنع كلمة المرور. كلمة "password" وما شابهها -حتى تلك البدائل الرائعة الممزوجة بالمحارف والأرقام- تكون دائمًا على رأس قائمة البرامج المخصصة لتخمين كلمة المرور الّتي يجب تجربتها. أسماء المواقع هي أيضا مرشحة بشكل كبير للتخمين. وبعبارة "[اسم الموقع]"، أقصد مثلا مثل "academy.hsoub" أو "hsoub" ككلمة مرور لحساب المدير. تتميز "charlieiscute" عن غيرها بأنها ليست كلمة مأخوذة من القاموس، وهي أطول من سابقتها. كما أنها أيضًا فريدة من نوعها بعض الشيء، ولكن ليس من الصعب تخمينها لأنها تستخدم أحرفًا صغيرة فقط، فلا توجد فيها أحرف كبيرة أو أرقام أو رموز. رغم أنه من غير المرجح أن يعرف المهاجم ذلك، ولكن عندما تقوم بتضمين فئات أخرى من المحارف، فإنك تقلل من احتمال قيام نظام التخمين العشوائي بتخمين كلمة المرور بشكل أسرع. خطوات لتعزيز قوة كلمات المرور للووردبريس هناك مجموعة من الخطوات تحسّن أمان كلمة المرور في موقع ووردبريس. ولكن سأذكر هنا أهم ثلاثة خطوات: امتلك كلمة مرور يصعب تخمينها: كلمات المرور الجيدة تكون صعبة القراءة ومعقدة مثل "RP@yu3ohd&LtpwzM}rWhgp6#AtY6HAzjvxKnz9zh". كلمة المرور هذه طويلة وعشوائية وفريدة من نوعها. وهنا احتمالية تخمينها منخفضة. ولأنها فريدة من نوعها - وهي طبعًا ليست كلمة المرور الخاصة بي على Facebook أو ArtWorld أو RandomInternetReseller أو أي شيء آخر- فكشف كلمة المرور الخاصة بموقع ووردبريس لن يعرض بقية الحسابات للخطر. إبطاء هجمات التخمين لكلمة المرور: بشكل افتراضي، يستطيع الروبوت تخمين 1000 كلمة مرور في الدقيقة (تقريبًا) على موقع ووردبريس الخاص بك. وهذا العدد كبير أو مرتفع. إذا منعت الأشخاص من الاستمرار في محاولة تسجيل الدخول بعد عدد معين من المحاولات الفاشلة مثل ثلاث أو أربع أو خمس مرات، أياً كان - فسوف تبطئ من هجمات كثيرة محتملة. الطريقة المفضلة للقيام بذلك هي تقييد محاولات تسجيل الدخول. استعن بهذا الدليل السريع والّذي يشرح كيفية الحد من محاولات تسجيل الدخول بخطوات تفصيلية. استخدم مدير كلمات المرور: إذا نفذت الخطوة الأولى، فسوف تتعب بسرعة من كتابة كلمة المرور هذه، أو ربما تنساها. بهذه اللحظة ستحتاج برنامج يدير لكلمات المرور. هناك أنواع كثيرة جدًا من مديري كلمات المرور الّتي بإمكاني إخبارك باستخدامها ولماذا. ولكنني شخصيًا أستخدم 1Password ولكن يمكنك استخدام أي مدير كلمات مرور أخر مثل KeePass و LastPass والّتي تعدّ من البرامج المشهورة أيضًا. 2. تحديث إصدار ووردبريس وجميع الإضافات والقوالب الطريقة الأخرى الّتي من المؤكد أن كلّ موقع من مواقع ووردبريس على الإنترنت مضمون للهجوم من قبل الهجمات الآلية المنتشرة وهو استغلال الثغرات المعروفة في البرامجيات الّتي تشغّل على الموقع. سواءً أكنت تستخدم Revolution Slider أو TimThumb أم لا أو أحد إضافات ووردبريس الشهيرة، فمن المحتمل أن تحاول الروبوتات الاستفادة من المشاكل المكتشفة في الإصدار القديم من هذه الإضافات. ولذا فإن هناك فرصة جيدة للاختراق بالرغم من أن هذه الطرق تعدّ قديمة جدًا، إلا أن الروبوت تحاول مهاجمتك عن طريقها. لهذا السبب يجب عليك أن تبقي إصدار ووردبريس محدّثًا باستمرار. بالإضافة إلى كلّ القوالب الّتي تستخدمها أيضًا. من الشائع حاليًا أن تحوي إضافات أو قوالب ووردبريس على ثغرات أمنية أكثر من نظام ووردبريس بحد ذاته، مع العلم أنه يمكن أن يكون الثلاثة يحتوون على ثغرات. عندما يدرك باحث خارجي أو مطور داخلي أن هناك مشكلة أمنية في بعض الشيفرات البرمجية في مواقعهم، فتقع على مسؤوليته أن يُنشىء نسخة جديدة من الموقع لا تحتوي على هذه الثغرة الأمنية. ومعظم المستخدمين لنظام ووردبريس يجيدون القيام بذلك. لذلك السبب، يجب عليك أن تؤدي دورك عندما يقدمون تحديثات بالإصلاحات أو ترقيعات الأمان فيجب عليك تثبيتها مباشرةً. ويمكنك جعل ووردبرس يثبت هذه التحديثات نيابةً عنك، أو يمكنك القيام بذلك بنفسك، أو حتى باستخدام إضافة مخصصة لإدارة موقعك الخاص مثل ManageWP. بعض الاستضافات توفر ذلك نيابةً عنك، ويمكنك أيضًا استئجار شخص ما للقيام بذلك إن لم تكن تستطيع فعلها بنفسك. ولكن يجب عليك فعل ذلك إذا كنت جادًا بشأن أمان وحماية موقعك. 3. إنشاء نسخ احتياطية بشكل دوري وتلقائي من أفضل الأشياء الّتي يمكنك القيام بها للحفاظ على أمان موقعك هو التأكد من حماية بياناتك في حال حدث أي مكروه لموقعك أو بياناتك. أي يجب أن يكون لديك على الأقل نسخة احتياطية حديثة واحدة لموقعك يمكنك استخدامها لإعادة بناء موقعك أو استعادته في حالة حدوث اختراق أو تخريب. أعتقد أن الطريقة الوحيدة للحصول على نسخة احتياطية حديثة وموثوقة من موقعك هي القيام بذلك تلقائيًا. نظرًا لأننا بشر، وومن الممكن جدًا أن نخطئ، أو ننسى، فغالبًا إذا طلبتُ منك أن تضغط 1-10 نقرات في موقعك للحصول على نسخة احتياطية محدّثة، فغالبًا لن تقوم بذلك. لهذا السبب يجب أن تحاول استخدام الإضافات الجاهزة الّتي توفر النسخ الاحتياطي. ويجب أن يكون هذا النسخ الاحتياطي مثاليًا أيضًا بحيث يحتوي على كلّ ملفاتك من صور وملفات PDF وقاعدة البيانات وجميع المعلومات المهمة في موقعك. وستقوم الإضافات نسخة احتياطية لبياناتك ووضعها على خادم آخر غير الخادم الّذي تستخدمه، لأن ذلك سيجعل موقعك أكثر أمانًا في حال استطاع المتسلل التسلل إلى خادمك فلن يستطيع بسهولة الوصول إلى الخادم الّذي يحوي النسخ الاحتياطية الخاصة بك. نظرًا لأن هذا منشور حول أمان ووردبريس وليس عن النُسخ الاحتياطية، فلن أملأ لك قائمة كاملة بجميع الخيارات المتاحة للنسخ الاحتياطي ولكنني أظن أن Updraft Plus و Jetpack/Vaultpress و Backup Buddy الّتي تتبادر إلى ذهني حاليًا هي حلول جيدة للنسخ الاحتياطي. 4. التحقق من موقعك وفحصه بانتظام في الحقيقة أن هذه الخطوة مهمة ولكنها لن تستطيع أن تمنع حدوث شيء سيء لموقعك، والسبب في أنه من المهم أن تبقى على اطلاع على حالة موقعك كي تمنع حدوث أشياء أسوأ. فعندما ترى أشياء غريبة تحدث على موقعك، فمن السهل إصلاحها مبكرًا. ويصبح الأثر أقل سوءًا - لأن محرك البحث Google سيحذر الزائرين من موقعك في حال اكتشافه أي مشكلة أمنية تسبب الضرر للزوار - وتخفف الضرر الّذي سيلحق بموقعك. إذا لم تُسجل الدخول بانتظام إلى موقعك لتفقده، فيجب عليك على الأقل التأكد بانتظام بأن الشكل الّذي يظهر للزبائن يبدو جيدًا. وإذا لم تكن قادرًا على القيام بذلك، فيجب أن تتأكد على الأقل من متاح ويمكن الوصول إليه وذلك باستخدام خدمات خارجية (مثل Pingdom). تتأكد هذه الخدمات من إمكانية استعادة نسختك الاحتياطية عند الدخول الجديد للموقع مباشرةً في حالة حدوث شيء سيء أو غريب. هذا في أسوأ الحالات، ولكنه ضروري لصحة الموقع على المدى الطويل. 5. تجنب الشيفرات البرمجية المقرصنة أو المسروقة هذه ليست خطوة مهمة للغاية لمعظم الناس. فمعظمنا يستخدم إصدار ووردبريس من الموقع الرسمي أو من المطورين الّذين استأجرناهم أو من البائعين الآخرين ذوي السمعة الطيبة. فإذا كنت تقوم بكل هذه الأشياء فليس عليك القلق من هذه النقطة. في الغالب الّذي يجب عليه أن يقلق هم الأشخاص الّذين يحاولون توفير المال عن طريق قرصنة الإضافات، أو القوالب، وما إلى ذلك أو الأشخاص الّذين يحاولون توفير المال عن طريق الحصول على الشيفرات البرمجية من "نوادي الإضافات" أو غيرها من المصادر منخفضة الثقة. إذا قمت بذلك، فمن المحتمل أن تكون هذه الشيفرات مجانية وذلك لأن شخصًا ما وضع ثغرة بداخله تتيح له التسلل إلى موقعك في المستقبل. في بعض الأحيان، يمكن للإضافات المجانية لووردبريس المتاحة في الموقع الرسمي أن يستولى عليها من قِبل جهات شريرة وتجري عمليات سيئة لها. ولكنه ولحسن الحظ نادر الحدوث، وفريق المشرفين على حماية ووردبريس يقوم بمراقبة وإصلاح أي مشكلة. ولكن إذا كنت قلقًا بشأن هذه النقطة فإن أفضل حلّ هو أن تكون أكثر تركيزًا ومعرفةً في الإضافة الّتي ستقوم بتثبيتها. 6. تعزيز أمان تسجيل دخول للووردبرس بواسطة HTTPS و 2FA واحدة من أكثر الأشياء شيوعًا في نصائح الأمان للووردبريس هي الحصول على شهادة SSL. إنها بالتأكيد خطوة جيدة. ولكن الشيء المهم الّذي يدركه عدد قليل جدًا من الأشخاص هو أن HTTPS / SSL لا تؤمن حقًا موقع ووردبرس الخاص بك، ولكن تؤمن الاتصال بين موقعك ومن يتصفحه؛ لذلك فهو ذو قيمة عالية، ولكن هذا ليس كلّ شيء. في صميم الموضوع، يجب اعتبار HTTPS بمثابة نفق آمن بين موقعك وأي شخص يشاهده في متصفح الويب. يمكن اختراق اتصالات HTTP بواسطة أي من الأجهزة المختلفة الموجودة بين الزائر والخادم. أما مع HTTPS، فإنه من المستحيل تقريبًا أن يتطفل هؤلاء الأشخاص على الاتصال. لذا فإن الفائدة المباشرة من HTTPS هي أن بيانات تسجيل الدخول الخاصة بك من اسم المستخدم وكلمة المرور أو بيانات اعتماد بطاقة الائتمان أو أي بيانات حساسة ستكون أكثر أمانًا. ومن غير المرجح أن يرى شخص ما يتطفل على الشبكة اللاسلكية الموجودة في المقهى على كلمة المرور الخاصة بك إذا كنت تستخدمها. لذلك يجب أن تحصل على شهادة HTTPS بكل الوسائل. لا تعتقد أن ذلك يؤمن تثبيت ووردبريس الحقيقي على الخادم بأي طريقة من الطرق، لأنه ليس كذلك. وهناك خطوة أخرى جيدة ولكنها غير مريحة إلى حد ما وهي استخدام الاستيثاق الثنائي (Two-Factor Authentication) والّذي يعرف اختصارًا 2FA وتثبيته على موقعك. عند القيام بذلك، ستحتاج إلى ثلاثة أشياء لتسجيل الدخول بدلًا من شيئين. عادةً ما نقوم بتسجيل الدخول إلى موقع ووردبريس باستخدام اسم المستخدم أو عنوان البريد الإلكتروني وكلمة المرور.ولكن مع الاستيثاق الثنائي، فستحتاج أيضًا إلى "معلومة أخرى"، وبما أن الهواتف أصبحت أساسيات الحياة في عصرنا الحالي فيمكننا إرسال رسائل نصية إليه للتحقق من المستخدم. في كلتا الحالتين، فأنت أكثر أمانًا لأن معرفة كلمة المرور الخاصة بك لن تكون كافية للاستيلاء على حسابك وسيحتاجون إلى رمز مكون من 4 أو 6 أرقام أيضًا والّذي سيرسل إلى هاتفك. هناك مجموعات متغيرة باستمرار من الإضافات الّتي تعطي هذه الميزة في ووردبريس حاليًا، فمثلًا Jetpack تقدم هذه الخدمة أو بإمكانك استخدام إضافة مستقلة. يمكنك الرجوع إلى مقالة كيف تستعمل SSL وHTTPS معووردبريس ومقالة كيف تحمي حسابك على مدوّنةووردبريسباستعمال الاستيثاق الثنائي2FA لمزيد من المعلومات. 7. التحكم في إمكانية الوصول لموقعك من المهم جدًا أن تكون على دراية وفهم كامل بما يتعلق بمن توفر لهم خدمة الوصول إلى موقعك ومعرفة الممارسات الأمنية اللازمة لتأمين ذلك. ويمكن عدها مجموعة من الخطوات إذ أنها أشمل من كونها خطوة واحدة. ومن بعض الخطوات الّتي اعتقد أنها مناسبة تحت هذا العنوان هي كالتالي: إعطاء كلّ مستخدم صلاحية الوصول إلى حساب مخصص مثلًا لديك جمال وسارة كلاهما يسجلان الدخول إلى موقعك باستخدام حساب مستخدم مثل المسؤول. هنا عليك تمييز كلّ منهم بحساب خاص به وصلاحيات خاصة بهم وذلك باستخدام إدارة صلاحيات المستخدمين وأدوارهم في ووردبريس. على سبيل المثال امنح الكاتب جمال حساب "محرر"، وامنح سارة حساب "المدير" والّذي يملك كافة الصلاحيات على الموقع. يعتمد هذا على مبدأ يسمى الحد الأدنى من الأمتيازات والّذي ينص على إعطاء القدرة على الوصول إلى المعلومات والموارد الضرورية فقط من الموقع أي أقل قدر من الصلاحيات الضرورية. لا تمنح المستخدمين إمكانية إنشاء حسابات بكلمات مرور ضعيفة إذا اتبعت النصيحة السابقة، فستريد أيضًا التأكد من عدم استخدام جمال وسارة كلمات المرور ضعيفة. يمكنك القيام بذلك عن طريق سؤالهم أو إخبارهم بعدم جواز ذلك عن طريق وضع رسالة خطأ تخبرهم عدم جواز ذلك أو عبر آلية معينة تمنع كلمات المرور الضعيفة بأوامر مثل استخدام إضافة مخصصة لذلك. لا تعطي صلاحيات الوصول للكثيرين، أعني بذلك المزيد من النصائح الحساسة، والّتي أصبحت في الغالب أسهل مع إضافات الكثيرة المتوفر لأمان ووردبريس، وإذا كنت مطورًا، قم بتعيين بعض ثوابت للووردبريس مثل عدم السماح بتحرير الملفات في منطقة إدارة الووردبرس، والتأكد من أنك لا تمنح الأشخاص حق الوصول إلى مخدم الموقع الويب أو الوصول إلى SFTP (وهو بروتوكول نقل البيانات بشكل آمن باستخدام التشفير من دون نقل أي بيانات خالصة في الملفات النصية ويعدّ أكثر أمانًا من بروتوكول FTP لنقل الملفات) ولا أي صلاحية لا يحتاجون إليها أي حافظ بذلك على إطار الحماية العام. 8. تثبيت الإضافات الأمنية الخاصة بووردبريس يوجد العديد من الإضافات الأمنية الجيدة في ووردبريس، والّتي تعد عاملًا مساعدًا جيدًا في العديد من الاحتياجات الأمنية الشائعة الّتي أدرجتها أعلاه (وبعضها أيضًا يساعد في ما لم أذكره أو ما عددته في الفئة غير المفيدة). من أسماء الإضافات الّتي تتبادر إلى ذهني سريعًا هي Sucuri و WordFence و Jetpack Protect و iThemes Security. وهناك العديد من الإضافات الأخرى، فهذه القائمة لا يمكن اعتبارها قائمة نهائية، وأتمنى منك ألّا تأخذ درجة الترتيب المذكورة كمقياس للأهمية. الإضافات تساعد في العمل فهي تفعل أشياء كثيرة مثل إنشاء سجلات الوصول، وتعمل على حظر واستبعاد الجهات السيئة المعروفة، وتعمل أيضًا على الحد من محاولات تسجيل الدخول الفاشلة، وتساعدك على إصلاح المزيد من المسائل الداخلية مثل مشاكل أذونات الملفات على موقعك. وتوفر لك الإضافات WordFence و Sucuri آلية مفيدة لمنع دخول الهجمات الآلية وإدارة حركة الزيارات الخبيثة إلى الموقع ومن ثم التخلص منها بما يسمى "جدار حماية تطبيق الويب". ختامًا الحصول على الأمن هو أمر صعب للغاية، ولكن أتمنى أن أكون وفقت في توضيح بعض الأمور المهمة، صحيح أن المقال طويل نوعًا ما، فهو يشتمل على 5000 كلمة، ولكن إذا ركزت بشكل جيد فيها، أو قرأت البنود الّتي ذُكرت بعناية، فسوف تتعلم الكثير وهذا ما أتمناه. بالرغم من أنني وكما ذكرت منذ البداية لا أشعر أن هذا العنوان الّذي وضعته "الدليل الكامل في أمن مواقع ووردبريس" عنوانًا دقيقًا، إلا أنني أعتقد بأني ذكرت بعض من أفضل الممارسات الأمنية لأصحاب مواقع ووردبريس. إن المسائل الأمنية في ووردبريس بشكل عام موضوع يحتاج منك فقط أن تحدّث إصدار ووردبريس وجميع الإضافات والقوالب باستمرار ويحتاج أيضًا لاستخدام كلمات مرور قوية ومن هنا تكون بقية النصائح الأمنية مفيدة ولكن غير ضرورية لأن ووردبريس بحد ذاته آمن تمامًا ولكن النسخ الاحتياطي يجلب لك الثقة في آمان موقعك مثل مشاهدة موقعك واستباق الخطوات في حال حدوث مكروه وضبط صلاحيات الوصول للمستخدمين والحصول على إضافات مخصصة للحماية ولكن العديد من النصائح الّتي تسمعها من الناس بالرغم من أنها ليست عديمة الفائدة، إلا أنني لا أنصح بقضاء بعض الوقت في التركيز عليها. وأخيرًا إن جعل موقعك آمنًا تمامًا إلى الأبد أمر مستحيل بضغطة أو خطوة واحدة. وإنما هي مهمة متغيرة ومتطورة باستمرار. حاول أن تكون على اطلاع بأخر الأخبار عن أمن ووردبريس، وفكر في انعكاس ذلك على موقعك، وستتعلم أكثر بكثير مما تعلمته في هذا المقال أو في أي مقال أخر يتحدث حول هذا الموضوع. ترجمة -وبتصرف- للمقال The Complete Guide to WordPress Security لصاحبه David Hayes
  12. لقد أحدثت الحاويات (Containers) والخدمات المصغّرة (Microservices) ثورة في تطوير التطبيقات وإدارة البنية التحتية لها، وقدمت لنا تحديات أمنية جديدة دون أن تعالج التحديات السابقة. إذن ما هي أبرز التحديات الأمنية الجديدة؟ وما الذي يجب علينا فعله تجاهها؟ تقنيات جديدة وتحديات جديدة تُعدّ الخدمات المصغّرة (Microservices) من أشهر المعماريات البرمجية في وقتنا الحالي، والتي جاءت لتحل مشاكل الطريقة التقليدية في تطوير المشاريع والتي تُعرف باسم (Monolithic) وهي معمارية تجعل كلّ خدمات المشروع عبارة عن وحدات برمجية متراصّة ومتجانسة مع بعضها بعضًا وتعمل جميعها في وقت واحد. فإذا حدث مشكلة ما في أحد خدمات المشروع سوف تتأثر جميع الأجزء المتجانسة الأخرى أمّا (Microservices) قسّمت المشروع الواحد إلى عِدّة مشاريع منفصلة، وكلّ مشروع يكون عبارة عن خدمة مصغرة، وتعمل كل خدمة منهم بشكل مستقل عن الخدمة الأخرى مع إمكانية إتصال خدمة معينة بخدمة أخرى من خلال قنوات اتصال محددة. لقد غيّرت الخدمات المصغّرة كلّ شيء. إذ نلاحظ أن أغلب الشركات في وقتنا الحالي تتجه لوضع خارطة عملٍ معتمدة على الخدمات المصغّرة باستخدام بنى معمارية مثل البنية التحتية الثابتة (Immutable infrastructure)، أو البنية المعمارية التي لا تدعم التشارك (shared-nothing architecture)، أو التطبيقات المتوضعة في الحاويات (containerized applications). لقد كانت طريقة الكشف عن فعالية المشاريع في حالات معينة مثل العمل في نطاق صغير، أو في الإستقلالية، أو في تحقيق الإستدامة الذاتية تُعرف عند بناء الواجهة البرمجية API وتشغيلها على الآلة الوهمية (virtual machine) أو بداخل حاوية، أو حتى بتشغيلها على القرص الصلب (حيث يكون مُثبت عليه نظام التشغيل)، أما الآن فيمكننا الكشف عن فعالية هذه المشاريع باستخدام الخدمات المصغّرة بحيث يتم إختبار كلّ حالة على حدة ومعرفة فعالية المشاريع بدون بناء واجهة برمجية. وعلى الرغم من المزايا المتعددة لإستخدام الحاويات إلا أنها تقدم لنا مجموعة من التحديات أيضًا من بين تلك التحديات المباشرة التي تواجه الحاويات هي الزحف على الحاويات (container crawl)، وحماية الحاويات، وتعقب الخدمات المصغّرة، ومعرفة مصدر نُسخ الحاويات. إذًا ما تأثير ذلك على الأمن في بيئة الخدمات المصغّرة؟ إن التحديات الأمنية لا تزال موجودة في بيئة التطبيقات أحادية النواة monolithic applications، ولا نزال نحتاج إلى معرفتها وتحديدها لمعالجتها. بالإضافة إلى ذلك، نحتاج إلى النظر في التحديات الأمنية الإضافية التي تفرضها الخدمات المصغّرة وتقنيات الحاويات. ومن منظور أمني، زادت إمكانية التعرض للهجوم بشكل كبير في عالم الخدمات المصغّرة بالموازنة مع التطبيقات أحادية النواة. أن زيادة قابلية النشر للوحدات وللأجهزة البعيدة (مثل: الهواتف الذكية والأجهزة المحمولة والأجهزة اللاسلكية الأخرى) أدى إلى زيادة التعرض للخطر، وإحتمالية حدوث هجوم أمني على الأجهزة البعيدة، ومشكلات التكاملية. بالإضافة إلى ذلك، قد تحتوي نُسخ Docker الأساسية على ثغرات أمنية والتي قد تضر بالخدمات المصغّرة. لذا ينبغي إدارة مصدر نُسخ Docker لضمان صحتها وخلوها من الثغرات. ويشكّل نشر تحديثات الأمنية والترقيعات مع المحافظة على أدنى مدة زمنية لتعطل الحاويات تحديًا آخر يصعب تجاوزه. يمكن أن تضيف DevOps المزيد من التركيز على الاحتياجات الأمنية في عالم الخدمات المصغّرة. حيث تركز أدوات النشر والبناء المستمرة حاليًا على تبسيط عملية التسليم، على الرغم من عدم تركيزها كثيرًا على حماية DevOps . أفضل الممارسات الأمنية لمواجهة بعض التحديات المذكورة أنفًا، دعونا نُلق نظرة على أفضل الممارسات التي يمكن إتخاذها. كجزء من استراتيجية DevOps الفعالة، يجب دمج خطوات الحماية والتدقيق المستمرة في منهجية DevOps. ويجب أن يتضمن الاختبار المستمر مُميزات إختبار الأمان المختلفة ويجب إضافة التحقق من سلامة نُسخ الحاويات إلى منهجية DevOps. وكما يمكننا أيضًا استخدام السجلات الخاصة private registries والتي تضمن لنا أن النُسخ موثوق بها وموجودة داخل الشركة. وينبغي تعزيز المراقبة من خلال آليات للكشف عن حالات الشذوذ لاكتشاف أي استخدام خاطئ للموارد أو الأحداث الغير طبيعية مع الحاويات، كما ينبغي تعزيز جميع قدرات المراقبة لتتبع العمليات المعتمدة على وكيل (agent-based) والعمليات بدون وكيل (agentless). كما يجب تحديث إدارة الترقيعات (Patch management) وتحسينها لضمان ترقيع الحاويات بأحدث التحديثات مع ضمان الحد الأدنى من وقت التوقف عن العمل. ولقد قدم Docker آلية لتحديد مصدر النُسخ تسمى (Notary)، والتي تستند إلى TUF (اختصارًا إلى The Update (Framework الذي يُستخدم في توزيع وتحديث البرامج بشكل نموذجي). ولكن العديد من أخصائيي الحاويات في وقتنا الحالي لا يستخدمونه Notary وذلك لأنه لا يزال في مرحلة التطوير. كما أن Notary يتطلب عملية إدارة رئيسية خبيرة في الشركة. تعدّ المنطقة التي تقع بين الخدمات المصغّرة من المناطق التي تُرتكب فيها الأخطاء أمنية، ويمكن استخدام Gateway API (وهي برمجية تقع أمام الواجهة البرمجية وتعمل كنقطة دخول واحدة لمجموعة محددة من الخدمات المصغّرة) بفعالية في هذا الموقف. إن تشفير الرسائل باستخدام تشفير الرسائل التقليدي PKI (البنية التحتية للمفتاح العام Public Key Infrastructure وهو إطار التشفير والأمن السيبراني الذي يحمي الاتصالات بين الخادم والعميل) ليس خيارًا قابلًا للتوسعة في هذا الموقف. لذا بدلًا من ذلك، يمكننا استخدام JSON Web Token) JWT) وهو رمز مشفّر مع مجموعة من سياسات التأكيد assertion policies حول الطالب للخدمة (requestor).حيث يوقعّ خادم الهوية الرسائل برمز مُميز والذي يُمكن التحقق منه بواسطة نظام المستلم (recipient system). كما يمكن تشفير JWT رقميًا للحفاظ على سرية وسلامة التأكيدات (assertions) والتي تسمى حينَئِذٍ JSON Web Encryption) JWE). غالبًا ما تكون الحماية صعبة وباهظة الثمن. لذا حاول أن تجعل من الحماية سمة أساسية للبنية التحتية للخدمات المصغّرة لتوفير أفضل مستوى من الأمان والأداء. ترجمة -وبتصرف- للمقال Secured DevOps for microservices لصاحبه Sreekanth Nyamars
  13. على مدار الأشهر القليلة الماضية، نشرت بعض المقالات الّتي تستكشف النقاط الأساسية الثلاث في تحولك الرقمي وهي المنتج والعملية والناس، وذلك لتمكينك من الانتقال من نموذج عمل مُحسن للموارد استنادًا إلى النفقات الرأسمالية (CAPEX) إلى نموذج مُحسن للسوق استنادًا إلى النفقات التشغيلية (OPEX). ومن الأمثلة على الانتقال من CAPEX إلى OPEX هو استخدام خدمات أمازون السحابية AWS بدلًا من إنشاء بنية تحتية من الصفر والتي ستُخدّم المشروع. ومن بين الفوائد الأخرى، يساعدك إتحاد الأشخاص والعمليات والمنتجات على رفع قيم العمل الأساسية، مثل زيادة قيمة الأعمال Business Value، مثل: زيادة قيمة الموظف، وقيمة العميل وقيمة الموارد وكثير من هذه القيم التي لا تقاس مباشرة بالقيم النقدية، بالإضافة إلى تقليل أوقات دورة التسليم، وتمكين الجميع من التعلم والتكيّف وتطوير مستواهم بشكل مستمر. يركز المهندسون (مثلي) عادة على المنتجات والأدوات والتقنيات. إذا أردنا النجاح في الانتقال إلى DevOps، فمن المهم أن ندرك أنه لا يمكنك شراء أو تركيب DevOps! المنتجات هي أدوات داعمة، وليست الحل السحري للأمر، فهي تتيح لك التركيز على النتائج، مثل الأتمتة، والتطابق، والموثوقية، والقدرة على الصيانة، وتمكين الميزات أو تعطيلها بشكل تدريجي، و تصور الخطوات اللازمة للانتقال من إنشاء المنتج إلى تسليمه إلى العميل النهائي أو ما يسمى flow of value. عندما نتحدث عن العملية، فإننا غالبًا ما نتجه نحو الأتمتة لرفع قيمة الكفاءة والاستقرار والثبات. ومن المهم أيضا تضمين أهداف الاحتفال بالنجاح سواءً كفريق أو منظمة، والتركيز على الجودة انطلاقًا من تصوّرها وتخيلها وانتهاءً بتحقيقها على أرض الواقع، وإنشاء عملية إدارة التغيير بحيث تكون سريعة الاستجابة وخفيفة، واحتضان البنيات المترابطة بشكل خفيف (loosely coupled architectures) لتمكين التطوير، والسعي إلى إصدار عدة مميزات جديدة في اليوم. إن جوهر هذا التحول هو تحول الناس وثقافتهم وليس المنتجات أو العمليات أو حتى حجم المنظمة. يحتاج الناس لأن يدركوا أهمية التحول وأن يعتنقوا فكرة DevOps، وأن يفهموا كيف ستتأثر مهامهم ووظائفهم، ويجب عليهم تحمل مسؤولية أدوارهم المنوطة إليهم في هذا التحول. ويجب عليهم أيضًا أن يدركوا أن DevOps لا تقتصر على التنمية والعمليات، حتى وإن كان اسمها بحد ذاته يدل على ذلك ويستبعد أصحاب المصلحة الآخرين.إنك تحتاج إلى إزالة جميع العوائق والمفاهيم الخاطئة داخل مؤسستك والتي تمنع من الانتقال إلى DevOps، وأن تجمع بين كلّ أصحاب المصلحة ومن جميع الأقسام في الشركة، بما في ذلك أقسام التطوير وخدمات البيانات والعمليات والأمان والأعمال إلى أن يتم تحقيق التحول إلى DevOps. ترجمة -وبتصرف- للمقال Breaking down walls between people, process, and products لصاحبه Willy-Peter Schaub
  14. إذا كنت مهتما بتعلم البرمجة، فعلى الأرجح أنك رأيت هذا الاقتباس من قبل: في الحقيقة لا أبالغ إن قلت أن البرمجة أصبحت من أهم المهارات في عصرنا الحالي، وذلك لأنها دخلت في جميع مجالات حياتنا سواءً كنا ندرك ذلك أم لا فانطلاقًا من الهواتف المحمولة ومرورًا بالمنازل والشاشات الذكية وانتهاءً بالسيارات ذاتية القيادة. كل شيء من حولنا لم نكن لنراه بهذا الشكل لولا البرمجة، فأنا على سبيل المثال أكتب وأعدل هذا الموضوع من خلال برنامج بُرمج عبر لغة برمجة وأنت تقرأه على الإنترنت باستخدام برنامج (المتصفح) وربما رأيته على مواقع التواصل الاجتماعي وكُلها برامج أيضًا. ومما لا شك فيه أن تعلم البرمجة أصبح ضرورة مُلحة في هذا العصر بل إن تعلمك لها سيزيد من فرصك بشكل كبير في الحصول على عمل. ولقد تحدثنا في مقالٍ سابق عن كيفية تعلم البرمجة والدخول إلى هذا المجال من أوسع أبوابه (إن كنت حديث عهدٍ في البرمجة أو تخطط للبدء بها، فننصحك بقراءته قبل إكمال هذا المقال) وسوف نتحدث في هذا المقال عن أكثر المهارات صعوبةً في احتراف البرمجة ألا وهي «حل المشاكل». حل المشكلات وارتباطها بالبرمجة لطالما وقفنا حائرين أمام مشكلةٍ ما ونسأل أنفسنا ماهي الطريقة الصحيحة للخروج من هذا المأزق؟ هل ستكون طريقة الحلّ التي أتبعها مشابهة للطريقة التي يتبعها المبرمجين المحترفين؟ كيف أستطيع أن أفكر مثلما يفكر المبرمجين المحترفين؟ في البداية وقبل الخوض في التفاصيل دعنا نُعرف البرمجة بحد ذاتها ولنذهب للمقال السابق ونلقي نظرة سريعة عليها: نلاحظ أن التعريف السابق صحيح ولكنه مُقْتضَب ولا يقدم لنا المعنى الكامل والدقيق للبرمجة لذا لابدّ لنا من تعريفٍ أكثر دقة وموضوعية يساعدنا في فهم هذا المقال. يعرف موقع HackerRank في تقريره عن مهارات المطورين بعام 2018: نستنتج مما سبق أن البرمجة تعتمد اعتمادًا أساسيًا على التفكير المنطقي والرياضي والقدرة على حلّ المشاكل وإن لغات البرمجة ما هي إلا وسيلة للتخاطب مع الحاسوب. إذن الأمر كله يتعلق بتطوير قدرتك في حلّ المشاكل وجعل هذه العملية سهلة وسلسة بنفس الوقت لذا فاسمح لي بأن آخذك معي برحلة صغيرة في هذا المقال نتعرف فيها على أهمية حلّ المشاكل وضرورتها في مشوارك البرمجي. لماذا حلّ المشاكل مهم؟ تأتي أهمية حل المشاكل من كونها من أكثر المهارات المطلوبة عالميًا فوفقًا لتقرير أصدره موقع HackerRank جاء فيه: احتلت مهارة حلّ المشاكلالمرتبة الأولى بنسبة 94.9% لأكثر مهارة مطلوبة لأصحاب الشركات سواء الصغيرة منها أو الكبيرة. وعلى الصعيد العملي، إن عملية بناء أي شيء من الصفر سواء أكانت آلة معينة أو أي مُنتج جديد ستواجه الكثير من المشاكل في البداية، فعلى سبيل المثال بناء خدمات أمازون السحابية (AWS)، والّتي جاءت حلًا لمشكلة النفقات العالية للبنية التحتية لتجارتها الإلكترونية بالإضافة إلى الوقت الطويل الّتي تحتاجه في عملية البناء والذي شكل تحدي كبير في إمكانية توسع الشركة، إلى أن جاء آندي جاسي كبير مستشاري جيف بيزوس في ذلك الوقت والذي استطاع إيجاد حلّ لهذه المشكلة ولم يتوقف عند ذلك الحد وإنما أختار تحويل هذا الحلّ إلى خط أعمال جديد تحت أسم خدمات أمازون السحابية والّتي بلغت عائداتها السنوية لعام 2018 قيمة تناهز 25 مليار دولار. نجد من التجربة السابقة أنه حصلت مشكلة فأُوجِد لها حلًا وأثناء خلق حل للمشكلة ظهرت الكثير من المشاكل الأخرى لتقع في سلسلة من المشاكل لا تنتهي. وبعد حلّ جميع المشاكل سيصبح المنتج جاهزًا للعمل، أي أن دورة حياة أي منتج سواءً أكان برمجيًا أو ماديًا ستحتوي على المشاكل، وبناءً على ذلك تكون مهارة حل المشاكل اللَبِنَة الأساسية في بناء مشوارك البرمجي، والّتي يجب علينا الإهتمام بها عند الإقدام على تعلّم البرمجة. تكون طريقة تعاملنا مع المشاكل غير منظمة وعشوائية في أغلب الأحيان، فمعظمُ المبرمجين الجُدد يَبْدَؤُونَ بحلّ أي مشكلة تُواجهُهُم بالطريقة التالية: جرّب أي حلّ للمشكلة. إذا لم ينجح الحلّ الأول حاول أن تجرّب أي حلّ آخر. إذا لم يفلح الحلّ كرر الخطوة الثانية إلى أن تصل إلى الحلّ. لا يحصل هذا الأمر مع المبرمجين فقط، وإنما يحصل مع أي شخص يواجه مشكلة ولا يستعن على حلها بالتحليل والتفكير المنطقي. في الحقيقة، قد يحالفك الحظ أحيانًا ويتم حلّ المشكلة ولكن كن حذرًا! فهذه هي الطريقة الأسوأ لحلّ المشكلات بل وإنها ستهدر وقتك بشكل كبير لذا من الأفضل استخدام طريقة منظمة توصلنا للحلّ، واسمح لي بأن أشاركك طريقة شاملة توصلك إلى حلّ أي مشكلة قد تواجهك. بناء خطة حلّ شاملة إن خطة الحلّ الشاملة هي مجموعة من الخطوات الَّتي تتبعها لحلّ أي مشكلة تواجهك، حيث تكون هذه الخطة عامة وتخصص بحسب المشكلة، وهي ليست تعليمات ثابتة وإنما مبادئ ننطلق منها جميعًا، وكلٌ منا يطبقها بأسلوبه الخاص، وفي نهاية المطاف إذا انطلقنا جميعًا من نفس المبادئ، فسنصل حكمًا على نفس جودة الحلّ أيضًا. إن هذه الخطة مؤلفة من عدة أجزاء ويناقش كلّ جزء فيها جانبًا معينًا من المشكلة إلى أن نصل للحلّ، وهي على الشكل التالي: 1. فهم المشكلة إن فهمنا للمشكلة المطروحة هي الخطوة الأكثر صعوبة في طريقنا لحلّها، بل إن أكثر المشاكل تأتي صعوبتها من عدم تمكننا من فهم عميق لها. ولكن متى تعلم بأنك استطعت فهم المشكلة؟ إذا كنت قادرًا على شرحها بكلمات واضحة وسهلة بحيث يستطيع أي شخص فهمها عندها تكون بالفعل قد فهمت المشكلة. هل تذكر عندما كنت عالقًا في مشكلة وبدأت بشرحها فوجدت أخطاء منطقية كثيرة لم تكن قد انتبهت لها من قبل؟ أغلب المبرمجين قد مروا بهذه الحالة من قبل، لذلك من الأفضل دومًا أن تكتب المشكلة الَّتي تواجهك باستخدام مخططات الحالة (State diagram وهي نوع من المخططات الَّتي تستخدم لتوصيف سلوك نظام ما) أو بأن تخبر شخص آخر عن المشكلة سواءً أكان زميل لك في الشركة أو عضو في الفريق أو أي شخص أخر. شاع بين المبرمجين استخدام البطة المطاطية في شرح أجزاء المشكلة لها لفهمها وإيجاد حل لها. يعد أسلوب البطة المطاطية في تنقيح الأخطاء من أكثر الأساليب سهولة وبساطة، إذ يضع المبرمج بطةً بجوار حاسوبه، وعند مواجهته لأي مشكلة يشرع في شرح الشيفرة البرمجية للبطة وما هي النتيجة المرتقبة من الشيفرة وموازنتها مع النتيجة الحالية وغالبًا ما يجد الخطأ أثناء شرحه. وخلاصة لهذه الخطوة أنقل إليك مقولة ألبرت أينشتاين: 2. تحليل المشكلة إن تقسيم المشكلة يلعب دورًا مهمًا في طريقك لإيجاد الحلّ، لذا حاول أن تقسّمها إلى أجزاء صغيرة ثمّ حُلّ كلَّ جزء منها على حدة ويُنصح في البداية بحلّ أسهل جزء منها ومن ثمّ الأصعب فالأصعب وهكذا إلى أن يتمّ حلّ جميع أجزائها، وبعدها إجمع هذه الأجزاء مع بعضها للحصول على الحلّ النهائي للمشكلة الأصلية (الكبيرة). منذ فترة كنا بصدد برمجة إضافة لمتصفح غوغل كروم بهدف تسهيل مهمة لموقع ما، فقررنا تجربة هذه الطريقة وبدأنا بتقسّيم المهمة على أجزاء ثم عملنا على حلّ كل جزء منها، وبعدها جمعنا هذه الأجزاء مع بعضها بعضًا لبناء الإضافة، وبالفعل كان العمل بهذه الطريقة سهلًا جدًا ومريحًا كما لم نعهده من قبل. في بعض الأحيان عندما تواجه شيفرات برمجية كتبها مبرمجون لا يتبعون مبادئ SOLID (وهي مجموعة من العادات والمبادئ الَّتي يتبعها المبرمجون للحصول على شيفرة برمجية قابلة للصيانة وسهلة التعديل والتكيف مع متطلبات المشروع المتغيرة)، وغالبًا ما تكون شيفرات أولئك المبرمجين غيرمفهمومة ومتشابكة ويطلق عليها اسم Spaghetti code (تكون هذه الشيفرات ذات بنية معقدة ومتشابكة وصعبة القراءة وغير مرتبة أي تكون مثل المعكرونة ملتوية ومتشابكة) ولنفرض أنه طُلبَ منك تعديل هذه الشيفرة أو إضافة وظائف جديدة إليها،عندها حتمًا ستواجه العديد من المشاكل في عملية تقسيم المشكلة ومعرفة أي جزء من الشيفرة البرمجية المُسبب للخطأ لذا كان الحصول على شيفرات برمجية مرنة وقابلة للتعديل هي الأرضية المشتركة بين العديد من تقنيات تبسيط الشيفرات البرمجية مثل مبادئ SOLID أو مبدأ MVC والذي ينص على تقسيم الوحدات من حيث طبيعة مهمتها إلى ثلاثة أقسام (Model-View-Controller) والبرمجة كائنية التوجه OOP (Object-Oriented Programming)، إذ أن جميعهم يهدفون إلى فصل الأكواد إلى أقسام ليسهل تطويرها وتنقيحها وصيانتها. 3. إعداد خطة للحل بعد أن فهمت وحللت المشكلة، يأتي دور وضع الخطة المناسبة للحلّ بحيث تغطي كافة الجوانب والتفاصيل للمشكلة، ولا تشرع في الحلّ من دون خطة (على أمل أن تجد الحلّ بطريقة ما) لأن المفتاح الرئيسي للوصول للحلّ هي الخطة الواضحة والمنظمة والتي تضمن وصولنا للحلّ النهائي. أعط لنفسك وقتًا لتحلّيل المشكلة وربط المعلومات المدخلة إلى البرنامج ونوعها والمعلومات الَّتي ستظهر كخرج للبرنامج وفهم سياقها وللحصول على خطة جيدة يجب عليك الإجابة على السؤال التالي: إذا أُعطي للبرنامج الدخل س، ما هي الخطوات اللازمة للحصول على الخرج ع؟ إن إجابتك على هذا السؤال سوف يحدد ماهي الخطوات اللازمة لحلّ المشكلة ومن ثَمَّ تقوم بترتيبها في خطة واضحة ومنظمة من أجل الحصول على الخرج الذي تريده. 4. مواجهة حالة السكتة البرمجية ماذا لو فرضنا أنك لم تستطع حلّ أي جزء من المشكلة، ولا حتى الأجزاء السهلة منها (وهذا قد يحدث في بعض الأحيان)، إن كثير من المبرمجين يقعون في هذه الحالة فلا يستطيعون أن يُحرزوا أي تقدم يذكر في تطوير الشيفرة البرمجية وهذا أشبه ما يمكن بالسكتة الدماغية (حيث لا يستطيع المريض القيام بأي حركة)، في الحقيقة إن هذه الحالة طبيعية جدًا ومعظمنا قد تعرض لها في بداية مشواره والاختلاف الوحيد هو أن المبرمج المحترف لديه فضول أكثر حول المشكلة ومعرفة سبب حدوثها بدلًا من أن يكون منزعجًا أو غاضبًا منها. وفي هذه الحالة هنالك حلّين يمكنك تجربتهما للخروج من هذا المأزق: 1-4. تنقيح الأخطاء (Debug) ليس المقصود هنا الأخطاء الكتابية في صياغة اللغة (Syntax errors) مثل نسيان فاصلة منقوطة أو أي خطأ في استخدام المتغيرات أو الدوال أو ما شابه ذلك من أخطاء والَّتي تقوم باكتشافها أي بيئة تطوير متكاملة (IDE وهي عبارة عن محرر شيفرة برمجية مدمج مع نظام ذكي لإكمال الكود ومصحح أخطاء). وبالطبع ليست أيضًا الأخطاء الّتي تظهر أثناء التنفيذ (Runtime Errors) والّتي تكون عادة نتيجة لفشلٍ في فتح ملف ما أو محاولة القسمة على صفر أو مثل هذه الأخطاء، وإنما المقصود هنا هو أخطاء المنطق البرمجي (Logic errors) الّتي ينفِّذ فيها البرنامج أمرًا غير الَّذي بُرمج من أجله، لذا من الأفضل أن تحاول أن تفحص الشيفرة البرمجية سطرًا سطرًا لعلك تجد هذا الخطأ، أوإذا كنت تعمل على لغاتٍ مثل (C++, C) والّتي تدعم استخدام المُنقِّح Debugger (الذي يراقب عمل البرنامج ويتحكم في تنفيذه بطريقة تستطيع فيها إيقاف تنفيذ البرنامج أو حتى تغييره في أي موضع من الشيفرة وذلك من خلال مجموعة من الأدوات الّتي يقدمها المُنقِّح، مثل: GNU Debugger) فيمكنك استخدامه لإيجاد الخطأ ومن ثَمّ إصلاحه. ملاحظة : من المنهجيات البرمجية الجيدة هي كتابة تعليقات توضيحية قبل كلّ دالة (Function) أو صنف (Class) برمجي وخُصوصًا تلك الأجزاء المعقدة منها لأن ذلك سوف يساعدك كثيرًا في عملية مراجعة الشيفرة البرمجية وتنقيحها. 2-4. مراجعة وتقييم الحلّ في كثير من الأحيان عند مواجهتنا للمشاكل وخصوصًا للكبيرة منها قد نضيع في التفاصيل الصغيرة للمشكلة الَّتي نواجهها وننسى المشكلة الرئيسية ولذلك من الأفضل دومًا أن نسأل أنفسنا هل هذه هي الطريقة الأفضل للحلّ؟ هل هنالك حلًّا عموميًا أفضل من الموجود؟ هل الشيفرة البرمجية أمثلية؟ هل الحلّ يخرق معايير الجودة المطلوبة؟ ارجع خطوة إلى الوراء وحاول أن تراها من منظور مختلف، وحتمًا ستلاحظ العديد من المشاكل التي غفلت عنها أثناء انشغالك بالتفاصيل الصغيرة. ملاحظة : هنالك طريقة أخرى يتبعها بعض المبرمجين لإعادة تقييم الحلّ وهي حذف الشيفرة البرمجية الخاطئة بالكامل وإعادة كتابتها من جديد فكثير ما يأخذ ذلك وقتًا أقل من تتبع المشكلة ذاتها وحلها. 5. البحث عن حلول عبر الإنترنت إن أغلب المشاريع البرمجية تكون متشابهة بكثيرٍ من الوظائف والخصائص، ونادرًا ما نرى مشروع ذو أفكارٍ جديدة بالكامل لذا فإن أي مشكلة برمجية تواجهها قد واجهها عدد كبير من المبرمجين من قبلك وأوجدوا لها حلولًا وشاركوها مع غيرهم، وكل ما عليك فعله هو أن تتعلم كيف تبحث عن المشكلة. وبالطبع صديقنا stackoverflow والذي يعد من أشهر منصات مشاركة الحلول البرمجية الّذي يقدم لك الحلّ الَّذي أجمع عليه أغلب، المبرمجين، ويوجد العديد من المنصات الأخرى المشابهة مثل AskUbuntu وهو النسخة العربية من موقع stackoverflow والكثير غيرهم، وحتى لو أنك قد حللت المشكلة أنصحك بتصفح الحلول الموجودة لأنك سوف تتعلم طرقًا أُخرى لحلّها قد تكون أسهل وأفضل بكثير من الحلّ الَّذي وصلت اليه. إلى الآن نكون قد ناقشنا الخطوة الأولى من الطريقة الشاملة لحلّ المشاكل والآن لننتقل إلى الخطوة الثانية. التدرب على هذه الخطة إن أي مهارة جديدة تحتاج إلى تدريبٍ مُمنهجٍ ومستمرٍ حتى تتقنها. لذا لا بدّ لك من وضع خطة واضحة للتدريب وتخصيص زمن محدد وثابت تقضيه في صقل تلك المهارة.يمكنك البدء مثلًا بتخصيص ساعة للتدريب يوميًا لمدة شهر كامل، وبعدها توازن نفسك مع ما كنت عليه في السابق من سرعةٍ في تحديد المشكلة وجودةٍ الحل المطروح والوقت الإجمالي لحل المشكلة وبكل تأكيد ستلاحظ تحسنًا واضحًا في أدائك. وقد تساءل نفسك كيف يمكنني التدرب على حلّ المشاكل؟ في الحقيقة هنالك طريقة مفيدة جدًا أنصحك بها لتكوين قاعدة صلبة تنطلق منها، وهي على الشكل التالي. 1. التدرب على المسائل البرمجية تعد المسابقات البرمجية سواءً على مستوى الجامعة أو على مستوى القطر أو حتى على مستوى العالم مثل مسابقة ACM ICPC من أفضل الفرص للتدريب في مجال البرمجة وصقل هذه المهارة بل وتعتبر دفعة كبيرة لك في رحلتك كمبرمج ولمستقبلك المهني أيضًا، إذ تبادر العديد من الشركات العالمية لِضمّ أولئك المنافسين المتميزين إليها بعد أن أثبتوا بالفعل أنهم النخبة في مجالهم. فإن كنت تخطط للانضمام إلى هذه المسابقة فلا تتردد وبادر بالتحضير لها من الآن. ويقدم لنا الكاتب Steven Halim في كتابه Competitive Programming بعض الفوائد الَّتي نجنيها من التدرب على حلّ المشاكل البرمجية في المسابقات. السرعة في كتابة الشيفرة البرمجية كتابة الشيفرة البرمجية بسرعة في المسابقات يوفر لك الكثير من الوقت للتفكير في بقية المشاكل واختبارها لذلك نرى أغلب المبرمجين يتدربون على سرعة الكتابة على لوحة المفاتيح لينصب تركيزهم على حلّ المشكلة فقط، ولذلك من المنطقي أن تفضل الشركات الموظفين الَّذين سَبق إن شاركوا في المسابقات البرمجية لمعرفتها بسرعة إنتاجيتهم وقدرتهم على تطوير وإيصال منتج برمجي بسرعة عالية بِالْمُوازنة مع أقرانهم ممن لم يشاركوا في المسابقات. العصف الذهني وحصر الخوارزميات الممكنة لا بدّ من تحسين قدرتك على تحديد نوع المسألة بسرعة وأن تمتلك المعرفة الكافية بالخوارزميات لتتمكن من تطبيقها مباشرة على المسألة المطروحة، لذلك ينبغي على المبرمج الَّذي ينوي الانضمام إلى المسابقة أن يتمكن من جميع الخوارزميات الشائعة في المسائل البرمجية. العمل الجماعي وروح الفريق تعتمد المسابقة البرمجية على ترتيب الفرق بحسب عدد المسائل الَّتي أجابوا عليها، والوقت الَّذي استهلكوه لحلّ كُلَ مشكلة، وعدد الحلول الخاطئة الَّتي أُرسلت للحكم. وانطلاقًا من ذلك تكون فوائد العمل كفريق واحد متعددة منها إمكانية توزيع المسائل على كلّ عضو في الفريق بحيث يزداد العدد الكلي للمسائل المحلولة بتوزيعها بين بعضهم بعضًا، ومناقشة حلّ كلّ مسألة وبذلك ينقص عدد الحلول الخاطئة الَّتي قد تُرسل للحكم، وحُكمًا سينقص الوقت المستغرق لحلّ المسائل. وعلى الصعيد العملي أيضًا نجد أن طبيعة عمل المبرمجين سواءً في الشركات الصغيرة أو الكبيرة، يُطلب منهم العمل كفريق واحد، فعلى سبيل المثال منذ فترة طَلَبَ مني أحد العملاء بناء موقع ويب، وكنت عندها قد أنتهيت من بناء فريقي البرمجي. وبالفعل بدأنا العمل على الموقع و قسّمنا العمل على أجزاء فعكف كلُّ واحد منا على تطوير جزئه الخاص من الموقع، إذ استلمتُ جزء الواجهات الخلفية، وقام أحد أعضاء الفريق باستلام الواجهات الأمامية، والآخَر استلم بناء تطبيق للهواتف الّتي تعمل بنظام أندرويد وفي نهاية الأسبوع جمعنا كل الأجزاء مع بعضها بعضًا وأنهينا المشروع بوقتٍ قياسي لم نكن لنستطيع بلوغهُ لو أننا لم نعمل كفريقٍ واحد، ولذا فإن انضمامك إلى المسابقة البرمجية يجعلك تتدرب على العمل ضمن فريق قبل أن تواجهها في سوق العمل في حال أردت العمل مع أي شركة مستقبلًا. المرونة العصبية إن تدريبك المستمر على المسائل البرمجية سيؤدي إلى زيادة منطقة الحصين (المنطقة المسؤولة عن الذاكرة والتوجيهات) في الدماغ وهذا ما أثبتته الباحثة اليانور ماجواير من كلية لندن الجامعية عندما أجرت دراسة على سائقي الأجرة في مدينة لندن فقاموا بإجراء فحص بالرنين المغناطيسي الوظيفي fMRI لأدمغة السائقين الذين قضوا قرابة عامين من التدريب في سبيل تعلم كيفية التنقل في منعطفات المدينة وذلك من أجل الحصول على رخصة القيادة ومقارنتها بصور لأدمغة رجال أصحاء من نفس العمر ولا يعملون كسائقي أجرة فتبين أن منطقة الحصين أصبحت أكبر لدى السائقين، كما لاحظوا أنه كلما أمضى سائق الأجرة فترة أطول في التدريب، زاد حجم الحصين، وذلك استجابة إلى الخبرة الّتي يكتسبها السائق. والآن تخيل معي ما سيحدث في حال تدربك على حل المشاكل لمدة عام أو أكثر، سيصبح حلّك للمشاكل البرمجية عادة سهلة ومسلية خلاف ما كانت عليه من صعوبة وتعقيد. يوجد العديد من المواقع الَّتي تقدم المسائل البرمجية مثل HackerRank أو موقع TopCoder والكثير غيرهم. 2. التدرب باستخدام الألعاب نعم أنت لم تخطئ القراءة إنها الألعاب! تعد الألعاب أداة قوية جدًا لتنمية المهارات العقلية والقدرات الدماغية على التفكير والتذكر وربط المعلومات ببعضها بعضًا، حيث أن غالبية الألعاب تحتاج لتجميع المعلومات وتنظيمها بحيث تستطيع الاستفادة منها وجعلها مفتاحًا للحلّ، بل إن الركيزة الأساسية الَّتي تشترك بها كافة الألعاب هي حلّ المشاكل! بالتأكيد نحن لا نقصد هنا ألعاب الفيديو فقط وإنما ألعاب الذكاء أيضًا مثل : لعبة الشطرنج، والألغاز الرياضية، ولعبة سودوكو، ولعبة Go، والكثير من الألعاب الَّتي تندرج تحت هذا السياق تعد ألعاب مفيدة. فعند محاولتك حلّ الألغاز في Saw أنت فعليًا تقوم بحلّ المشاكل (ولكن بإطار مختلف). وتساعدنا أيضًا في انشاء سيناريوهات للحلّ وهذه المهارة مفيدة في عالم البرمجة في حال تعثرت في أسلوب حلّ معين فتغير سيناريو الحلّ وتبدأ من جديد. في الحقيقة إن الشيء المشترك بين جميع الناس الناجحين هي اكتسابهم لعادات يومية لحلّ المشاكل الصغيرة على سبيل المثال بيتر تيل (أحد مؤسسي شركة باي بال والمصنف كرابع أغنى شخص على مستوى العالم لعام 2014 بميزانية تفوق $2.2 بليون دولار) صرح بشكل رسمي أنه يلعب الشطرنج يوميًا بل وشارك في بطولات الشطرنج مرات عديدة، وإيلون ماسك (رائد الأعمال والرئيس التنفيذي لعدة شركات مثل: سبيس إكس لتصنيع مركبات الفضاء وتسلا لصناعة السيارات الكهربائية وغيرها)أكد بأنه يلعب ألعاب الفيديو والكثير غيرهم كرسوا جزءًا من وقتهم اليومي لتنمية مهارة حلّ المشاكل. ولكن يجب أن تكون حذرًا في إدارة وقت اللعب ويُفضل أن تختار الأوقات المناسبة للعب ووضع مدة زمنية مخصصة لها، وذلك لأن الهدف ليس إضاعة الوقت والتسلية فقط وإنما التدرب على حل المشاكل ولكي لا ينتهِ بك المطاف إلى قضاء اليوم بأكمله على الألعاب. الخلاصة اعتقد أنك قد كونت فكرة جيدة عن أهمية حلّ المشاكل وضرورتها في مشوارك البرمجي وكيفية بناء خطة حلّ شاملة انطلاقًا من فهم المشكلة وتحليلها ومرورًا بإعداد خطة مخصصة لكلّ مشكلة وتقسيم المشكلة إلى أجزاء ليسهل حلّها ومواجهة حالة السكتة البرمجية وكيفية التغلب عليها من خلال تنقيح الأخطاء أو مراجعة وتقييم الحلّ، وأهمية البحث عن حلول على الإنترنت لنفس المشكلة وانتهاءً بالأسلوب الصحيح للتدرب على حل المشاكل وما هي أفضل الوسائل لتحقيق ذلك سواءً بالانضمام إلى المسابقات البرمجية أو بالتدرب بإستخدام الألعاب. وختامًا، لا تتوقع أن تصبح مبرمجًا محترفًا في غضون أسبوعٍ أو شهر واحد فهذا ضرب من الخيال بل ستحتاج لحلّ الكثير من المشاكل لبناء قاعدة معرفية صلبة تمكنك من مواجهة أي مشكلة مهما كانت صعوبتها وعندها بالتأكيد سوف تستحق لقب مبرمج محترف.
  15. إن الحصول على اسم نطاق جيد لن يؤدي في كثير من الأحيان إلى زيادة عدد الزيارات إلى موقعك فحسب، بل سيسهل أيضًا تذكره - وهذا يجلب المزيد من الزيارات أيضًا. هناك كثير من الأشياء التي يجب على مصمم المواقع أن بفكر بها عندما يصمم موقع. وخصوصًا إن كانت لديه المسؤولية الكاملة عن الموقع، فيجب عليه أن يأتي باسم نطاق جيد للموقع. على الرغم من أن الكثيرين يعتقدون أن اختيار اسم جيد ليس بتلك الأهمية، إلا أن اسم النطاق مهم مثل اسم شركتك أو موقع الويب أو صفحة فيس بوك. إن العثور على اسم نطاق مثالي ليس سهلًا على الإطلاق في يومنا الحالي. كثير من النطاقات التي من الممكن أن تفكر بها إما أن تكون مستخدمة من قِبل شركة أخرى أو شخص ما اشتراها للربح أو حتى في الأعمال التجارية. غالبًا ما يمضي خبراء الويب وقتًا في العثور على اسم نطاق مناسبٍ أكثر من الوقت في تصميم هوية أو موقع ويب. العلامة التجارية تعد العلامة التجارية مفهوما مهما جدًا بالنسبة للأعمال. يوجد لكل شركة علامة تجارية، تمثل اسمها وشعارها ومخطط ألوانها وهويتها البصرية. ومع ذلك، لا نجد أن كل العلامات التجارية معروفة. وهذا هو الفرق في الوعي بالعلامة التجارية. تعتمد الشركة التي لديها وعي بالعلامة التجارية على قدرة عملائها على تذكر علامتهم التجارية والتعرف عليها في ظروف مختلفة وربطها بعناصر علامتها التجارية. وهو يتعلق برضى العملاء عن أحد المنتجات وإدراك المنتجات فور رؤيتهم للعلامة التجارية. إنه الفرق بين كوكا كولا وشركة كولا بلا اسم. أو الفرق بين منتج شركة Apple ومنتج شركة غير معروف اسمها. قبل 10 سنوات لم يكن الموضوع بهذا الحجم كما هو عليه الآن، إلّا أن اليوم إن كنت تملك شركة وتريد علامة تجارية قوية ، فإن المعرفة الأساسية في اختيار اسم نطاق لموقعك يعتبر مهمًا جدًا، كما هو الحال مع عنوان مكتبك. وحيث يمكّن الأشخاص من العثور عليك والاتصال بك. الامتدادات (Extensions) إن أكثر الامتدادات استخدامًا في العالم هي الامتدادات الثلاثة التالية com. و net. و org.. يبدو اسم النطاق مع واحدة من هذه الامتدادات مثاليًا لأي نوع من الأعمال. فاستخدام أحد الامتدادات المجانية مثل TK. قد لا يكون ناجحًا جدًا. في كثير من الأحيان لا يستطيع الزوار تذكر موقعك، لذلك هم يحاولون استخدام اسم شركتك مع هذه الامتدادات الثلاثة المشهورة. وهذا ما أفعله في كثير من الأحيان ، لذا أني أفترض أن إحدى الشركات التي سأكون مهتمًا بالتعامل معها، أو أن أحد مواقع الويب التي سأكون مهتمًا بزيارتها سيكون له واحد من هذه الامتدادات الثلاثة. وكما قلت للتو أن هذه الامتدادات ذات شعبية كبيرة، لذا يتوقع الزوار أن تستخدم الشركات هذه الامتدادات الثلاثة فقط. يقدم بعض مقدمي خدمات حجز النطاقات عروضًا لمن يشتري الامتدادات الثلاثة سيحصل على خصم. لذا فإن حصولك على الامتدادات الثلاثة سيكون مفيد جدًا لك في المستقبل - تعدّ هذه الخطوة ذكية جدًا وستضعك في موضع الصدارة. من الميزات الأخرى لاستخدام الامتدادات الثلاثة (أو واحد منها) أن أسعارهم رخيصة جدًا. ومدعومين في جميع أنحاء العالم ومن الصعب العثور على مقدم خدمات حجز النطاقات لا يبيعها. بالتأكيد أن لا أقول أنه يجب عليك أن تملك واحدًا منهم. الشريك المؤسس لووردبريس Matt Mullenweg لديه واحد من أروع أسماء النطاقات ألا وهو www.ma.Tt. نعم، لديه امتداد غريب إلا أنه يتوافق مع إسمه بشكل مثالي. إذا تمكنت من العثور على شيء ذكي مثل هذا الامتداد، فاحصل عليه مباشرة، ولكن فكر في حقيقة أن الأشخاص الذين لا يعرفون الكثير عن الويب لا يعرفون عن وجود شيء آخر غير امتدادات com. و net. و org.. وينبغي أن يكون هذا الجزء غذاء لأفكارك. ومع ذلك، يعدّ اختيار امتداد لاسم النطاق واحدًا من أسهل المهام في إنشاء علامة تجارية قوية. ولكن انتظر! هناك الكثير من الأمور التي يجب عليك متابعتها أيضًا. الموقع بالتحدث عن الإمتدادات، يعدّ الموقع شيء آخر يجب عليك التفكير فيه. إنه يعتمد بشكل كبير على نوع أعمالك والغرض منها. ويعتمد كثيرًا على الجمهور والسوق وسلوكهم. إذا كان لديك شركة دانماركية تستهدف الدنماركيين فقط، فإن وجود موقع ويب ينتهي في com. لن يكون له داعٍ لأننا نستطيع الحصول على امتداد سهل التمييز مثل dk.. جميع البلدان لديها امتدادات نطاق (Top-level Domain). وبالتأكيد dk. ليس هو الخيار الوحيد المتوفر. يُستخدم رمز البلد TLD في أغلب الأحيان للشركات والأفراد في البلد المَعني. ويكيبيديا لديها قائمة طويلة وكاملة من TLDS في جميع أنحاء العالم. من السهل ملاحظة أن بعض هذه الامتدادات يتطلب إما تسجيل شركة في البلد أو على الأقل الحصول على تصريح إقامة، لذلك فإن التسجيل عليها ليس بتلك السهولة، وخصوصًا إن كنت تتطلع أن تفعل مثلما فعل Matt في امتداد موقعه. وهو أيضا خيار للشركات التي تستهدف الدول التي لا تستخدم الأبجدية الإنجليزية، مثل الدول الآسيوية، أو العربية، أو روسيا. وتسمى IDNs (أسماء النطاقات الدولية Internationalized Domain Names) ويجب أن تستخدمها فقط لاستكمال عنوان com. (أو أي TLD آخر) وإلا فإنه سيكون مربكًا للزائرين الذين لغتهم الرئيسية الإنجليزية أو أحد الأبجديات المستخدمة في أوروبا أو أمريكا. خدع وحِيَل لقد تحدثنا عن الخدع قبل قليل وهي الأشياء الذكية التي تقوم بها لدمج اسم النطاق مع الامتداد. صدق أو لا تصدق أنه يوجد على الإنترنت أدوات مخصصة لمساعدتك في إيجاد تركيبات ممكنة لاسم موقعك وامتداده! يعدّ موقع Domai.NR من أفضل الخيارات المتوفرة للاستخدام في هذا المجال، لأنه يعطيك العديد من الخيارات في بحث بسيط. تستعمل الناس هذه الخدع ليست لأنها رائعة فحسب، بل لأنه في أغلب الأحيان يكون الأسم المناسب لشركتهم مأخوذ بالفعل وهذا محبط جدًا، وإنه يحدث في كثيرٍ من الأحيان . لأن العثور على اسم مناسب ليس سهلًا إلى هذه الدرجة. لذلك أحيانًا قد ترغب في الإطلاع على بعض الخدع. قبل الشراء رائع، الآن وجدت اسم النطاق الذي تبحث عنه وأنت مستعدٌ لشرائه. لا، أنت لست مستعد! لقد نسيت شيئًا ما. وهو تتأكد من أن اسم النطاق الخاص بك لا يؤدي بك إلى مشاكل قانونية مع شركات أخرى. تأكد من أنه ليس هنالك شركة أخرى مشابهة تقوم بنفس الأعمال التي تقوم بها. مايكروسوفت (Microsoft) ضد ميكروايسوفتيس (MikeRoweSoftis) النزاع الأكثر شعبية بشأن انتهاك اسم النطاق. حدث هذا قبل عشر سنوات تقريبًا وكانت قضية دسمة لوسائل الإعلام عندما كان مصمم المواقع الشاب مايك رو ينازع اسم نطاقه مع العملاق الأميركي بسبب تشابه اسم النطاق الخاص به مع اسم نطاق شركة مايكروسوفت. إن التقدم بطلب العلامة التجارية هو أمر تقوم به الشركات الضخمة، بما أنهم يعرفون أن مواقعهم ستكون ذات شعبية قوية بطبيعة الحال، لكن هذا أمر مكلف للغاية. وخصوصًا إذا كنت في البداية، لذا فقد ترغب في حماية اسمك بطريقة أخرى وترك فكرة شراء علامتك التجارية لوقت لاحق. بعض التقنيات التي يمكنك استخدامها تسمى الشراء بالجملة. يفضل العديد من الأفراد شراء الكثير من النطاقات ذات الأسم نفسه والامتدادات المختلفة، وإعادة توجيههم جميعًا إلى الموقع الرئيسي. خدمات Whois من الأخطاء التي يرتكبها العديد من الأفراد هي تسجيل نطاقاتهم ضمن خدمة الخصوصية WHOIS. وهذه الطريقة خطيرة للغاية، على الرغم من أنها تبدو مفيدة عندما تسمع بها لأول مرة. ولكن ماذا يحدث إذا قمت بتسجيل نطاقك ضمن خدمة خصوصية WHOIS هو أن تفاصيل الاتصال الخاصة بك مخفية. بدلاً من أن تملئ الحقول بالمعلومات الخاصة بك يجب عليك أن تملئ الحقول بالمعلومات الخاصة بالمزود الذي اشتريت من عنده. ولكن لماذا يعدّ هذا الشيء خطير؟ لأنه وفقًا لسياسات ICANN ، يكون الاسم في تفاصيل WHOIS للذي يملك النطاق (في هذه الحالة اسم الشركة الّتي اشتريت منها النطاق). هذا يعني أنه إذا تم اختراق موقعك، فلديك فرصة ضئيلة لإثبات أن النطاق هو ملكك بالفعل. إذا كان اسم المخترق في السجلات، فهو في الواقع يمتلك النطاق الذي دفعته مقابله. لذلك حتى لو كنت ترغب في حماية اسم نطاقك، لا أنصحك أن تفعل ذلك باستخدام هذه الخدمات، لأنها خطيرة جدًا. الخاتمة يمكن أن يؤدي امتلاك اسم نطاق جيد إلى تحسين تجربة المستخدم على موقع الويب الخاص بك. حتى لو كانت اليوم العديد من زيارات موقع الويب تأتي من محركات البحث والإحالات، إلا أن وجود اسم سهل للتذكر سيكون دائمًا مفيدًا. ومن المحتمل أن ينخفض نسبة الأشخاص الذين ينسون كيفية العثور عليك. ضع في حساباتك أن نطاقات المستوى الأعلى (Top-level domains) يمكن أن تساعدك في تصدر نتائج محرك البحث. وذلك لأنه يتم فهرسة ‎.com دومًا بشكل أسرع وأفضل من ‎.ru. إن قضاء الوقت في التفكير في كل التفاصيل والعثور على اسم النطاق الصحيح هو أمر سيستغرق الكثير من الوقت. ترجمة -وبتصرف- للمقال Essential Tips for Registering a New Domain Name