Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ปัญหาทั่วไปของ Ruby on Rails และ Takeaways

ยินดีต้อนรับสู่ส่วนสุดท้ายของซีรี่ส์ Ruby on Rails Patterns และ Anti-Patterns เป็นการเขียนและค้นคว้าหัวข้อเหล่านี้ค่อนข้างมาก ในบล็อกโพสต์นี้ เราจะพูดถึงปัญหาที่พบบ่อยที่สุดที่ฉันพบเมื่อสร้างและจัดส่งแอปพลิเคชัน Ruby on Rails ตลอดหลายปีที่ผ่านมา

แนวคิดที่ฉันจะพูดถึงในที่นี้ใช้ได้กับเกือบทุกที่ในโค้ด ดังนั้นให้พิจารณาว่าเป็นแนวคิดทั่วไป ไม่ใช่สิ่งที่เกี่ยวข้องกับรูปแบบ Model-View-Controller หากคุณสนใจรูปแบบและการต่อต้านรูปแบบที่เกี่ยวข้องกับ Rails MVC คุณสามารถดูบล็อกโพสต์ Model, View และ Controller ได้

มาดูปัญหาทั่วไปและประเด็นสำคัญกันดีกว่า

วัตถุเห็นแก่ตัวและกฎแห่งความเสื่อม

The Law of Demeter เป็นฮิวริสติกที่มีชื่อมาจากกลุ่มคนทำงานในโครงการ Demeter แนวคิดก็คือว่าอ็อบเจ็กต์ของคุณใช้ได้ตราบใดที่พวกมันเรียกเมธอดทีละรายการและไม่โยงการเรียกเมธอดหลายรายการ ความหมายในทางปฏิบัติมีดังต่อไปนี้:

# Bad
song.label.address
 
# Good
song.label_address

ตอนนี้ song วัตถุไม่จำเป็นต้องรู้ว่าที่อยู่มาจากไหนอีกต่อไป — ที่อยู่เป็นความรับผิดชอบของ label วัตถุ. ขอแนะนำให้คุณโยงการเรียกเมธอดเพียงวิธีเดียว และทำให้ออบเจ็กต์ของคุณ 'เห็นแก่ตัว' เพื่อที่พวกเขาจะได้ไม่เปิดเผยข้อมูลทั้งหมดโดยตรงแต่ผ่านเมธอดของตัวช่วย

โชคดีที่ใน Rails คุณไม่จำเป็นต้องเขียนวิธีการช่วยเหลือด้วยตัวเอง คุณสามารถใช้ delegate ผู้ช่วย:

def Label < ApplicationModel
  belongs_to :song
 
  delegate :address, to: :song
end

คุณสามารถลองใช้ตัวเลือกต่างๆ ที่ผู้รับมอบสิทธิ์ยอมรับได้ในเอกสารของผู้รับมอบสิทธิ์ แต่แนวคิดและการดำเนินการนั้นค่อนข้างง่าย เมื่อใช้กฎ Demeter คุณจะลดการมีเพศสัมพันธ์ทางโครงสร้าง ร่วมกับ delegate . อันทรงพลัง คุณทำได้ในไม่กี่บรรทัดและมีตัวเลือกที่ยอดเยี่ยมรวมอยู่ด้วย

แนวคิดอื่นที่คล้ายกับกฎแห่งดีมิเตอร์มากคือหลักการความรับผิดชอบเดียว (หรือ SRP เรียกสั้นๆ ว่า SRP) มันระบุว่าโมดูล คลาส หรือฟังก์ชันควรรับผิดชอบส่วนเดียวของระบบ หรือนำเสนอในลักษณะอื่น:

รวบรวมสิ่งที่เปลี่ยนแปลงไปด้วยเหตุผลเดียวกัน แยกสิ่งที่เปลี่ยนแปลงด้วยเหตุผลที่แตกต่างกันออกไป

ผู้คนมักจะมีความเข้าใจเกี่ยวกับ SRP ที่แตกต่างกัน แต่แนวคิดก็คือการทำให้หน่วยการสร้างของคุณรับผิดชอบในสิ่งเดียว อาจเป็นเรื่องยากที่จะบรรลุ SRP เนื่องจากแอป Rails ของคุณมีการขยาย แต่ต้องระวังเมื่อทำการรีแฟคเตอร์

เมื่อเพิ่มคุณสมบัติและเพิ่ม LOC ฉันพบว่าผู้คนมักจะพยายามหาวิธีแก้ปัญหาอย่างรวดเร็ว มาดูวิธีแก้ไขด่วนกันดีกว่า

ฉันรู้จักผู้ชาย (คุณต้องการอัญมณีทับทิมนั่นไหม)

ย้อนกลับไปในวันที่ Rails เป็นประเด็นร้อน การทำงานร่วมกันแบบโอเพ่นซอร์สได้รับความนิยมอย่างมาก โดยมี Ruby gem ใหม่ปรากฏขึ้นทุกมุม (เช่นทุกวันนี้กับไลบรารี JavaScript ที่เกิดขึ้นใหม่ทั้งหมด แต่มีขนาดเล็กกว่ามาก):

👆 ข้อมูลจากจำนวนโมดูล

อย่างไรก็ตาม วิธีการทั่วไปก็คือการหาอัญมณีที่มีอยู่เพื่อแก้ปัญหาของคุณ

ไม่มีอะไรผิดปกติ แต่ฉันต้องการแบ่งปันคำแนะนำเล็กน้อยก่อนที่คุณจะตัดสินใจติดตั้งอัญมณี

ก่อนอื่น ให้ถามตัวเองด้วยคำถามเหล่านี้:

  • คุณจะใช้คุณสมบัติของอัญมณีส่วนใด
  • มีอัญมณีที่คล้ายกันที่ 'เรียบง่ายกว่า' หรือทันสมัยกว่านี้ไหม
  • คุณสามารถใช้คุณลักษณะที่คุณต้องการได้อย่างง่ายดายและมั่นใจหรือไม่

ประเมินว่าการดำเนินการนี้คุ้มค่าหรือไม่ หากคุณไม่ได้วางแผนที่จะใช้คุณลักษณะอัญมณีทั้งหมด หรือหากการติดตั้ง Gem ซับซ้อนเกินไป และคุณเชื่อว่าคุณทำได้ง่ายกว่านี้ ให้เลือกโซลูชันที่กำหนดเอง

อีกปัจจัยหนึ่งที่ฉันพิจารณาคือพื้นที่เก็บข้อมูลของอัญมณีมีการใช้งานอย่างไร — มีผู้ดูแลที่ทำงานอยู่หรือไม่? ครั้งล่าสุดที่เผยแพร่เกิดขึ้นเมื่อใด

คุณควรระวังการขึ้นต่อกันของอัญมณีด้วย คุณไม่ต้องการถูกล็อกเป็นเวอร์ชันเฉพาะของการขึ้นต่อกัน ดังนั้นให้ตรวจสอบ Gemfile.spec เสมอ ไฟล์. ศึกษาวิธีการระบุรุ่นอัญมณีของ RubyGems

ในขณะที่เรากำลังพูดถึงอัญมณี แต่ก็มีแนวคิดที่เกี่ยวข้องซึ่งฉันได้พบ:ปรากฏการณ์ 'ไม่ได้ประดิษฐ์ขึ้นที่นี่' (หรือ NIH) ที่ใช้กับโลก Rails/Ruby มาดูกันว่ามีอะไรบ้างในหัวข้อถัดไป

ไม่ได้ประดิษฐ์ขึ้นที่นี่ (คุณอาจต้องการอัญมณีทับทิมนั้นหรือไม่)

สองสามเหตุการณ์ในอาชีพการงานของฉัน ฉันมีโอกาสได้สัมผัสกับผู้คน (รวมถึงฉันด้วย) ตกหลุมรักกลุ่มอาการ 'ไม่ได้ประดิษฐ์ขึ้นที่นี่' แนวคิดนี้คล้ายกับ 'การคิดค้นล้อใหม่' บางครั้ง ทีมและองค์กรไม่เชื่อถือห้องสมุด (อัญมณี) ที่พวกเขาไม่สามารถควบคุมได้ การขาดความไว้วางใจอาจเป็นตัวกระตุ้นให้พวกเขาสร้างอัญมณีที่มีอยู่แล้วขึ้นใหม่

บางครั้งการได้สัมผัสกับ NIH อาจเป็นสิ่งที่ดี การสร้างโซลูชันภายในองค์กรนั้นยอดเยี่ยม โดยเฉพาะอย่างยิ่งหากคุณปรับปรุงให้ดีขึ้นเหนือโซลูชันอื่นๆ หากคุณตัดสินใจที่จะโอเพ่นซอร์สโซลูชัน นั่นอาจจะดียิ่งขึ้นไปอีก (ดู Ruby on Rails หรือ React) แต่ถ้าคุณต้องการที่จะคิดค้นวงล้อใหม่เพื่อประโยชน์ของมันอย่าทำอย่างนั้น ตัวล้อเองก็สวยดีอยู่แล้ว

หัวข้อนี้ค่อนข้างยุ่งยาก และหากคุณเคยตกอยู่ในสถานการณ์เช่นนี้ ให้ถามตัวเองด้วยคำถามเหล่านี้:

  • เรามั่นใจหรือไม่ว่าเราสามารถสร้างโซลูชันที่ดีกว่าที่มีอยู่ได้
  • หากโซลูชันโอเพนซอร์สที่มีอยู่แตกต่างไปจากที่เราต้องการ เราจะทำการสนับสนุนโอเพนซอร์สและปรับปรุงได้หรือไม่
  • นอกจากนี้ เราสามารถเป็นผู้ดูแลโซลูชันโอเพนซอร์ซและอาจปรับปรุงชีวิตของนักพัฒนาจำนวนมากได้หรือไม่

แต่บางครั้ง คุณก็ต้องไปตามทางของตัวเองและสร้างห้องสมุดด้วยตัวเอง บางทีองค์กรของคุณอาจไม่ชอบให้สิทธิ์การใช้งานไลบรารีโอเพนซอร์ซ ดังนั้นคุณจึงถูกบังคับให้สร้างไลบรารีของคุณเอง แต่ไม่ว่าคุณจะทำอะไร ฉันขอบอกว่าอย่าสร้างวงล้อขึ้นมาใหม่

ไลฟ์การ์ดประจำการ (ยกเว้นการช่วยเหลือมากเกินไป)

ผู้คนมักจะช่วยเหลือข้อยกเว้นมากกว่าที่พวกเขาตั้งเป้าไว้

หัวข้อนี้เกี่ยวข้องกับโค้ดมากกว่าหัวข้อก่อนหน้าเล็กน้อย อาจเป็นเรื่องธรรมดาสำหรับบางคน แต่สามารถเห็นได้ในโค้ดเป็นครั้งคราว ตัวอย่างเช่น:

begin
  song.upload_lyrics
rescue
  puts 'Lyrics upload failed'
end

หากเราไม่ระบุข้อยกเว้นที่ต้องการจะช่วยเหลือ เราจะตรวจพบข้อยกเว้นที่เราไม่ได้วางแผนไว้

ในกรณีนี้ ปัญหาอาจจะอยู่ที่ song วัตถุ nil . เมื่อข้อยกเว้นนั้นถูกรายงานไปยังตัวติดตามข้อผิดพลาด คุณอาจคิดว่ามีบางอย่างผิดปกติในกระบวนการอัปโหลด ในขณะที่จริงๆ แล้ว คุณอาจประสบกับสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง

ดังนั้น เพื่อความปลอดภัย เมื่อต้องช่วยเหลือข้อยกเว้น ตรวจสอบให้แน่ใจว่าคุณได้รับรายการข้อยกเว้นทั้งหมดที่อาจเกิดขึ้น หากคุณไม่สามารถรับข้อยกเว้นทั้งหมดได้ด้วยเหตุผลบางประการ การช่วยเหลือน้อยไปก็ดีกว่าการช่วยเหลือมากไป ช่วยเหลือข้อยกเว้นที่คุณรู้จักและจัดการกับผู้อื่นในภายหลัง

คุณถามมากเกินไป (แบบสอบถาม SQL มากเกินไป)

ในส่วนนี้ เราจะพูดถึงปัญหาด้านฐานข้อมูลและความสัมพันธ์ระหว่างการพัฒนาเว็บอื่น

คุณทิ้งระเบิดเว็บเซิร์ฟเวอร์ด้วยการสืบค้น SQL มากเกินไปในคำขอเดียว ปัญหานั้นเกิดขึ้นได้อย่างไร? อาจเกิดขึ้นได้หากคุณพยายามดึงข้อมูลหลายรายการจากหลายตารางในคำขอเดียว แต่สิ่งที่เกิดขึ้นบ่อยที่สุดคือปัญหาการสืบค้น N+1 ที่น่าอับอาย

ลองนึกภาพโมเดลต่อไปนี้:

class Song < ApplicationRecord
  belongs_to :artist
end
 
class Artist < ApplicationRecord
  has_many :songs
end

หากเราต้องการแสดงเพลงสองสามเพลงในแนวเพลงและศิลปินของพวกเขา:

songs = Song.where(genre: genre).limit(10)
 
songs.each do |song|
  puts "#{song.title} by #{song.artist.name}"
end

โค้ดชิ้นนี้จะทริกเกอร์การสืบค้น SQL หนึ่งครั้งเพื่อรับสิบเพลง หลังจากนั้น แบบสอบถาม SQL เพิ่มเติมหนึ่งรายการจะถูกดำเนินการเพื่อดึงข้อมูลศิลปินสำหรับแต่ละเพลง นั่นคือทั้งหมดสิบเอ็ด (11) ข้อความค้นหา

ลองนึกภาพสถานการณ์ถ้าเราโหลดเพลงมากขึ้น - เราจะใส่ฐานข้อมูลไว้ภายใต้ภาระที่หนักกว่าเพื่อพยายามหาศิลปินทั้งหมด

หรือใช้ includes จาก Rails:

songs = Song.includes(:artists).where(genre: genre).limit(10)
 
songs.each do |song|
  puts "#{song.title} by #{song.artist.name}"
end

หลังจาก includes ตอนนี้เราได้รับคำสั่ง SQL สองคำเท่านั้น ไม่ว่าเราจะแสดงกี่เพลงก็ตาม เรียบร้อยแค่ไหน

วิธีหนึ่งที่คุณสามารถวินิจฉัยการสืบค้น SQL มากเกินไปคืออยู่ในระหว่างการพัฒนา หากคุณเห็นกลุ่มของแบบสอบถาม SQL ที่คล้ายกันดึงข้อมูลจากตารางเดียวกัน แสดงว่ามีบางอย่างคาวเกิดขึ้นที่นั่น นั่นเป็นเหตุผลที่ฉันขอแนะนำอย่างยิ่งให้คุณเปิดการบันทึก SQL สำหรับสภาพแวดล้อมการพัฒนาของคุณ นอกจากนี้ Rails ยังรองรับบันทึกการสืบค้นแบบละเอียดซึ่งแสดงว่ามีการเรียกคิวรีจากที่ใดในโค้ด

หากการดูบันทึกไม่ใช่เรื่องของคุณ หรือคุณต้องการอะไรที่จริงจังกว่านี้ ให้ลองใช้การวัดประสิทธิภาพของ AppSignal และการตรวจจับการสืบค้น N+1 ที่นั่น คุณจะได้รับตัวบ่งชี้ที่ยอดเยี่ยมว่าปัญหาของคุณมาจากข้อความค้นหา N+1 หรือไม่ นี่คือลักษณะที่ปรากฏด้านล่าง:

สรุป

ขอบคุณที่อ่านชุดโพสต์บล็อกนี้ ฉันดีใจที่คุณเข้าร่วมกับฉันในการขับขี่ที่น่าสนใจนี้ โดยเราได้เปลี่ยนจากการแนะนำรูปแบบและการต่อต้านรูปแบบใน Rails ไปจนถึงการสำรวจว่ามีอะไรอยู่ในรูปแบบ Rails MVC ก่อนโพสต์บล็อกสุดท้ายนี้เกี่ยวกับปัญหาทั่วไป

ฉันหวังว่าคุณได้เรียนรู้มากหรืออย่างน้อยก็แก้ไขและสร้างสิ่งที่คุณรู้อยู่แล้ว อย่าเครียดกับการท่องจำทั้งหมด คุณสามารถปรึกษาซีรีส์ได้เสมอหากคุณมีปัญหาในพื้นที่ใด ๆ

คุณจะพบทั้งรูปแบบและการต่อต้านรูปแบบอย่างแน่นอนเพราะโลกนี้ (และโดยเฉพาะวิศวกรรมซอฟต์แวร์) ไม่เหมาะ ที่ไม่ควรทำให้คุณกังวลเช่นกัน

การเรียนรู้รูปแบบและการป้องกันรูปแบบจะทำให้คุณเป็นวิศวกรซอฟต์แวร์ที่ยอดเยี่ยม แต่สิ่งที่ทำให้คุณดียิ่งขึ้นไปอีกคือการรู้ว่าเมื่อใดควรทำลายรูปแบบและแม่พิมพ์เหล่านั้น เพราะไม่มีวิธีแก้ปัญหาที่สมบูรณ์แบบ

ขอขอบคุณอีกครั้งที่เข้าร่วมและอ่าน เจอกันใหม่ตอนหน้า — และเชียร์!

ป.ล. หากคุณต้องการอ่านโพสต์ Ruby Magic ทันทีที่ออกจากสื่อ สมัครรับจดหมายข่าว Ruby Magic ของเราและไม่พลาดแม้แต่โพสต์เดียว!