قم ببناء غبي ، معيد البناء الذكي: كيفية تدليك المشاكل من روبي أون ريلز كود
نشرت: 2022-03-11في بعض الأحيان ، يقدم لنا العملاء طلبات مميزة لا نحبها حقًا. ليس الأمر أننا لا نحب عملائنا - فنحن نحبهم. لا يعني ذلك أننا لا نحب الميزة — فمعظم الميزات التي يطلبها العميل تتوافق تمامًا مع أهداف أعمالهم ودخلهم.
في بعض الأحيان ، لا نحب طلب الميزة لأن أسهل طريقة لحلها هي كتابة تعليمات برمجية سيئة ، وليس لدينا حل أنيق في مقدمة رؤوسنا. سيؤدي هذا إلى إرسال العديد منا من مطوري Rails إلى عمليات بحث غير مثمرة من خلال RubyToolbox و GitHub ومدونات المطورين و StackOverflow للبحث عن جوهرة أو مكون إضافي أو رمز مثال يجعلنا نشعر بتحسن تجاه أنفسنا.
Refactor روبي أون ريلز كود
حسنًا ، أنا هنا لأخبرك: لا بأس في كتابة تعليمات برمجية سيئة. في بعض الأحيان ، يكون من الأسهل إعادة بناء كود ريلز السيئ إلى كود جميل أكثر من حل غير مدروس جيدًا يتم تنفيذه في ظل أزمة زمنية.
هذه هي عملية إعادة هيكلة ريلز التي أحب أن أتبعها عند معالجة المشاكل من حلول ضماداتي الرهيبة:
لمنظور بديل ، إليك سجل التزام Git لميزة تم إعادة بنائها خطوة بخطوة:
وإليك مقالة أخرى مثيرة للاهتمام حول إعادة بناء ديون ضخمة من زميل في شبكة Toptal.
دعونا نرى كيف يتم ذلك.
المناظر
الخطوة 1. ابدأ في "المشاهدات"
لنفترض أننا بدأنا تذكرة لميزة جديدة. يخبرنا العميل: "يجب أن يكون الزائرون قادرين على عرض قائمة بالمشاريع النشطة على صفحة الترحيب."
تتطلب هذه البطاقة تغييرًا واضحًا ، لذلك سيكون مكانًا معقولًا لبدء العمل في طرق العرض. المشكلة واضحة ومباشرة وتم تدريبنا جميعًا على حلها عدة مرات. سأقوم بحلها بطريقة خاطئة وأشرح كيفية إعادة تشكيل الحل الخاص بي في مناطقه المناسبة. حل مشكلة يمكن أن تساعدنا الطريقة الخاطئة في التغلب على مشكلة عدم معرفة الحل الصحيح.
للبدء ، افترض أن لدينا نموذجًا يسمى Project
بسمة منطقية تسمى active
. نريد الحصول على قائمة بجميع Projects
التي يكون active
فيها مساويًا لـ true
، حتى نتمكن من استخدام Project.where(active: true)
، ونقوم بالتكرار فوقه مع each
كتلة.
app/views/pages/welcome.haml: %ul.projects - Project.where(active: true).each do |project| %li.project= link_to project_path(project), project.name
أعرف ما تقوله: "هذا لن يجتاز مراجعة الكود أبدًا" أو "موكلي سوف يطردني بالتأكيد من أجل هذا." نعم ، يكسر هذا الحل الفصل بين المخاوف ، وقد يؤدي إلى استدعاءات قاعدة بيانات ضالة يصعب تتبعها ، وقد يصبح من الصعب الاحتفاظ بها في المستقبل. لكن ضع في اعتبارك قيمة فعل ذلك بالطريقة الخاطئة :
- يمكنك الحصول على هذا التغيير عند بدء التشغيل في أقل من 15 دقيقة.
- إذا تركت هذه الكتلة ، فمن السهل تخزينها مؤقتًا.
- يعد إصلاح مشكلة ريلز هذه أمرًا بسيطًا (يمكن إعطاؤه إلى مطور مبتدئ).
الخطوة 2. الجزئيات
بعد القيام بذلك بطريقة خاطئة ، أشعر بالسوء تجاه نفسي وأريد عزل الكود السيئ الخاص بي. إذا كان من الواضح أن هذا التغيير كان مصدر قلق فقط لطبقة العرض ، فيمكنني إعادة تشكيل خزي إلى جزء.
app/views/pages/welcome.haml: = render :partial => 'shared/projects_list' app/views/shared/projects_list.haml: %ul.projects - Project.where(active: true).each do |project| %li.project= link_to project_path(project), project.name
هذا أفضل قليلاً. من الواضح أننا ما زلنا نرتكب خطأ استعلام نموذجي في طريقة عرض ، ولكن على الأقل عندما يأتي المشرف لاحقًا ويرى جزئي الرهيب ، سيكون لديهم طريقة مباشرة لمعالجة مشكلة كود ريلز هذه على وجه الخصوص. من الواضح أن إصلاح شيء غبي أسهل دائمًا من إصلاح تجريد عربات التي تجرها الدواب سيئة التنفيذ.
الخطوة 3. المساعدون
تعد المساعدون في ريلز طريقة لإنشاء DSL (لغة خاصة بالمجال) لقسم من طرق العرض الخاصة بك. يجب عليك إعادة كتابة التعليمات البرمجية الخاصة بك باستخدام content_tag بدلاً من haml أو HTML ، ولكن يمكنك الاستفادة من السماح لك بمعالجة هياكل البيانات دون الحاجة إلى جعل المطورين الآخرين يراقبونك لمدة 15 سطرًا من رمز العرض غير المطبوع.
إذا كنت سأستخدم مساعدين هنا ، فمن المحتمل أن أعيد تصنيع بطاقة li
.
app/views/shared/projects_list.haml: %ul.projects - Project.where(active: true).each do |project| = project_list_item(project) app/helpers/projects_helper.rb: def project_list_item(project) content_tag(:li, :class => 'project') do link_to project_path(project), project.name end end
المتحكمات
الخطوة 4. انقلها إلى وحدات التحكم

ربما لا تكون التعليمات البرمجية الفظيعة مصدر قلق للعرض فقط. إذا استمرت الرائحة في الرمز الخاص بك ، فابحث عن الاستفسارات التي يمكنك نقلها من طرق العرض إلى وحدات التحكم.
app/views/shared/projects_list.haml: %ul.projects - @projects_list.each do |project| = project_list_item(project) app/controllers/pages_controller.rb: def welcome @projects = Project.where(active: true) end
الخطوة 5. مرشحات التحكم
السبب الأكثر وضوحًا لنقل الكود إلى وحدة تحكم قبل التصفية أو before_filter
هو الرمز الذي after_filter
في إجراءات تحكم متعددة. يمكنك أيضًا نقل الكود إلى عامل تصفية وحدة التحكم إذا كنت تريد فصل الغرض من إجراء وحدة التحكم عن متطلبات طرق العرض الخاصة بك.
app/controllers/pages_controller.rb: before_filter :projects_list def welcome end def projects_list @projects = Project.where(active:true) end
الخطوة 6. وحدة تحكم التطبيق
افترض أنك بحاجة إلى ظهور التعليمات البرمجية الخاصة بك في كل صفحة ، أو أنك تريد إتاحة وظائف مساعد وحدة التحكم لجميع وحدات التحكم ، يمكنك نقل وظيفتك إلى ApplicationController. إذا كانت التغييرات عامة ، فقد ترغب في تعديل تخطيط التطبيق الخاص بك أيضًا.
app/controllers/pages_controller.rb: def welcome end app/views/layouts/application.haml: %ul.projects - projects_list.each do |project| = project_list_item(project) app/controllers/application_controller.rb: before_filter :projects_list def projects_list @projects = Project.where(active: true) end
نماذج
الخطوة 7. إعادة هيكلة النموذج
كما يقول شعار MVC: نموذج الدهون ، أدوات التحكم النحيفة ، والمشاهد البكم . يُتوقع منا إعادة تشكيل كل ما في وسعنا في النموذج ، وصحيح أن معظم الوظائف المعقدة ستصبح في النهاية ارتباطات نموذجية وطرق نموذجية. يجب علينا دائمًا تجنب القيام بتنسيق / عرض الأشياء في النموذج ، ولكن تحويل البيانات إلى أنواع أخرى من البيانات مسموح به. في هذه الحالة ، فإن أفضل شيء يمكن إعادة تشكيله في النموذج هو عبارة where(active: true)
، والتي يمكننا تحويلها إلى نطاق. يعد استخدام النطاق أمرًا ذا قيمة ليس فقط لأنه يجعل المكالمة تبدو أجمل ، ولكن إذا قررنا في أي وقت إضافة سمة مثل delete
أو outdated
، فيمكننا تعديل هذا النطاق بدلاً من تعقب كل عبارات where
.
app/controllers/application_controller.rb: before_filter :projects_list def projects_list @projects = Project.active end app/models/project.rb: scope :active, where(active: true)
الخطوة 8. نموذج المرشحات
ليس لدينا استخدام خاص before_save
أو after_save filters
في هذه الحالة ، ولكن الخطوة التالية التي أتخذها عادةً هي نقل الوظائف من أساليب التحكم والطراز إلى عوامل تصفية النموذج.
لنفترض أن لدينا سمة أخرى ، num_views
. إذا كان num_views > 50
، يصبح المشروع غير نشط. يمكننا حل هذه المشكلة في طريقة العرض ، ولكن إجراء تغييرات قاعدة البيانات في طريقة العرض أمر غير مناسب. يمكننا حلها في وحدة التحكم ، ولكن يجب أن تكون وحدات التحكم الخاصة بنا رفيعة قدر الإمكان! يمكننا حلها بسهولة في النموذج.
app/models/project.rb: before_save :deactivate_if_over_num_views def deactivate_if_over_num_views if num_views > 50 self.active = false fi end
ملاحظة: يجب تجنب استدعاء self.save
في مرشح النموذج ، لأن هذا يتسبب في أحداث حفظ متكررة ، ويجب أن تكون طبقة معالجة قاعدة البيانات في تطبيقك هي وحدة التحكم على أي حال.
الخطوة 9. المكتبات
في بعض الأحيان ، تكون ميزتك كبيرة بما يكفي بحيث تضمن أنها مكتبتها الخاصة. قد ترغب في نقله إلى ملف مكتبة لأنه يُعاد استخدامه في العديد من الأماكن ، أو لأنه كبير بما يكفي بحيث ترغب في تطويره بشكل منفصل.
من الجيد تخزين ملفات المكتبة في الدليل lib / ، ولكن مع نموها ، يمكنك نقلها إلى RubyGem حقيقي! الميزة الرئيسية لنقل التعليمات البرمجية الخاصة بك إلى مكتبة هي أنه يمكنك اختبار المكتبة بشكل منفصل عن النموذج الخاص بك.
على أي حال ، في حالة قائمة المشروع ، يمكننا تبرير نقل scope :active
من نموذج Project
إلى ملف مكتبة ، وإعادته إلى روبي:
app/models/project.rb: class Project < ActiveRecord::Base include Activeable before_filter :deactivate_if_over_num_views end lib/activeable.rb: module Activeable def self.included(k) k.scope :active, k.where(active: true) end def deactivate_if_over_num_views if num_views > 50 self.active = false end end end
ملاحظة: يتم استدعاء الأسلوب self.included
عند تحميل فئة نموذج ريلز وتمرر في نطاق الفئة كمتغير k
.
خاتمة
في هذا البرنامج التعليمي لإعادة هيكلة Ruby on Rails ، أخذنا أقل من 15 دقيقة وقمنا بتنفيذ حل ووضعه على مراحل لاختبار المستخدم ، ليكون جاهزًا لقبوله في مجموعة الميزات أو إزالته. بنهاية عملية إعادة البناء ، لدينا جزء من التعليمات البرمجية التي تحدد إطار عمل لتنفيذ العناصر القابلة للتنشيط والقائمة عبر نماذج متعددة من شأنها اجتياز حتى أكثر عمليات المراجعة صرامة.
في عملية إعادة هيكلة ريلز الخاصة بك ، لا تتردد في تخطي بضع خطوات أسفل خط الأنابيب إذا كنت واثقًا من القيام بذلك (على سبيل المثال ، الانتقال من العرض إلى وحدة التحكم ، أو من وحدة التحكم إلى النموذج). فقط ضع في اعتبارك أن تدفق التعليمات البرمجية من العرض إلى النموذج.
لا تخف من أن تبدو غبيًا. ما يفصل اللغات الحديثة عن تطبيقات تقديم نموذج CGI القديم ليس أننا نفعل كل شيء بالطريقة الصحيحة في كل مرة - إنه أننا نأخذ الوقت الكافي لإعادة تشكيل وإعادة استخدام ومشاركة جهودنا.