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

รหัสของคุณไปไหน?

หลังจากที่คุณอ่านบทแนะนำ Rails เสร็จแล้ว และเริ่มใช้งานแอปของคุณเอง สิ่งต่างๆ จะเกิดความสับสน เช่นเดียวกับที่ไม่ใช่ CRUD ตรรกะทั่วไปของคุณไปที่ไหน? การดึงดูดผู้ติดตามจาก Twitter เข้ากับ MVC ได้อย่างไร ถามสองคน คุณจะได้สี่คำตอบ หรือกระทู้ของคุณกลายเป็นกลุ่มคนฉลาดที่ดูถูกกันเป็นชั่วโมงๆ ในขณะที่คุณเอาหัวโขกโต๊ะ ไม่ว่าจะด้วยวิธีใด คุณก็ต้องปวดหัวอยู่ดี

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

จุดเริ่มต้นที่ง่าย

เมื่อฉันมีตรรกะที่รู้สึกว่าเกี่ยวข้องกับโมเดล ActiveRecord ที่มีอยู่ ฉันจะเริ่มด้วยการใส่ลงในโมเดลนั้น ตัวอย่างเช่น ถ้าฉันมี Game model และฉันต้องการนำเข้าเกมจำนวนมากจากไฟล์ CSV ฉันจะใส่วิธีการนั้นลงใน Game คลาส:

app/models/game.rb
class Game < ActiveRecord::Base
  def self.parse_from_csv(csv_string)
    games = []
    CSV.parse(csv_string, quote_char: "'") do |row|
      games << Game.from_csv_row(row) if (row[0] == 'G')
    end
    games
  end

  def self.from_csv_row(row)
    Game.new({
      dgs_game_id: row[1],
      opponent_name: row[2],
      created_at: row[4],
      updated_at: row[4],
    })
  end
end

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

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

ในกรณีดังกล่าว คุณอาจต้องการจัดโครงสร้างโค้ดใหม่ให้เป็นโมเดลที่ไม่ใช่ ActiveRecord

โมเดล Non-ActiveRecord

เพียงเพราะมันอยู่ในแอป Rails ไม่ได้หมายความว่าจะต้องรับช่วงจาก Active/Action แต่อย่างใด

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

ครั้งต่อไปที่ฉันทำงานกับตัวแยกวิเคราะห์ CSV ของเกมนั้น Game ชั้นเรียนใหญ่เกินไปเล็กน้อย ดังนั้นฉันจึงย้ายตรรกะ parser ไปเป็น GameCSVParser ชั้นเรียน

คอมมิตทั้งหมดอยู่ที่นี่ แต่นี่คือสิ่งที่คลาสที่ไม่ใช่ ActiveRecord ดูเหมือน:

แอพ/models/game_csv_parser.rb
class GameCSVParser

  def initialize(csv_string)
    @rows = CSV.parse(csv_string, quote_char: "'")
  end

  def games
    game_rows.map { |row| Game.new(game_attributes(row)) }
  end

  private

  def game_rows
    @rows.select { |row| is_game_row?(row) }
  end

  def game_attributes(row)
    {
      dgs_game_id: row[1],
      opponent_name: row[2],
      created_at: row[4],
      updated_at: row[4],
    }
  end

  def is_game_row?(row)
    row[0] == 'G'
  end
end

ฉันจะไปทางขวาเพื่อสร้างวัตถุ Ruby ธรรมดาใหม่หากตรรกะที่ฉันกำลังเพิ่มไม่รู้สึกว่าเกี่ยวข้องกับรุ่น ActiveRecord ใด ๆ หรือหากโค้ดดูเหมือนว่าควรเป็นส่วนหนึ่งของสิ่งที่ยังไม่มีอยู่ในแอป มิฉะนั้น ส่วนใหญ่จะปรากฏขึ้นผ่านการปรับโครงสร้างใหม่

ด้วยวัตถุ Ruby ธรรมดา คุณสามารถเขียนอะไรก็ได้ แต่รู้ว่าคุณสามารถเขียน อะไรก็ได้ ไม่ได้ช่วยให้คุณมีทิศทาง คุณต้องการวิธีการอะไร? วัตถุใหม่ทั้งหมดของคุณจะโต้ตอบกันอย่างไร

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

วัตถุบริการ ผู้นำเสนอ และงาน

ไม่มีอะไรพิเศษเกี่ยวกับวัตถุที่ให้บริการ ผู้นำเสนอ และงาน พวกมันเป็นเพียงวัตถุ Ruby ธรรมดาที่ทำงานในลักษณะที่จดจำได้โดยเฉพาะ

ตัวอย่างเช่น งานที่ต้องการ เป็นคลาส Ruby ธรรมดาที่มี perform เมธอดและ @queue :

แอพ/workers/fetch_games_for_player.rb
class FetchGamesForPlayer
  @queue = :default

  def self.perform(player_id)
    player = Player.scoped_by_id(player_id).ready_for_fetching.first
    player && player.fetch_new_games!
  end
end

perform จะถูกเรียกเมื่อมีการเรียกใช้งาน

พรีเซ็นเตอร์ เป็นวัตถุ Ruby ธรรมดาที่มีรหัสที่เหมาะสมในมุมมองเท่านั้น:

app/presenters/user_presenter.rb
class UserPresenter
  def show_related_users?
    @user.related.count > 3
  end
end

นอกจากนี้ยังอาจรวมถึงตัวช่วยดูของ Rails หรือนำวัตถุที่แตกต่างกันสองสามรายการและถือว่าเป็นวัตถุที่รวมเป็นหนึ่งเดียวเพื่อความสะดวกของมุมมอง

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

  1. แสดงความคิดเห็น
  2. ส่งอีเมลแจ้งเตือนไปยังผู้เขียนโพสต์

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

มีวัตถุบริการที่ยอดเยี่ยมที่นี่ เต็มไปด้วยตัวอย่าง

สำหรับกระบวนการง่ายๆ ฉันไม่กังวลกับออบเจ็กต์บริการ แต่ถ้าตัวควบคุมเริ่มหนักเกินไป ก็ควรวางตรรกะพิเศษนั้นไว้

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

คุณเริ่มที่ไหน

มีหลายๆ ที่ที่ตรรกะทางธุรกิจที่ไม่ใช่ Rails ของคุณสามารถนำไปใช้ได้ อาจจะเลือกยาก นี่คือสิ่งที่ฉันทำ:

  1. หากตรรกะส่วนใหญ่เกี่ยวข้องกับคลาสที่มีอยู่ แม้ว่าจะเป็นโมเดล ActiveRecord ฉันก็ใส่มันไว้ในคลาสนั้น
  2. หากไม่เข้ากับคลาสที่มีอยู่ ฉันจะสร้างคลาส Ruby ธรรมดาใหม่เพื่อใช้ตรรกะ
  3. หากรู้สึกว่าตรรกะควรเป็นส่วนหนึ่งของสิ่งที่ยังไม่มี ฉันจะสร้างคลาส Ruby ธรรมดาขึ้นมาใหม่
  4. หากฉันกลับมาที่โค้ดในภายหลัง และโมเดลเริ่มซับซ้อนเกินไป หรือโค้ดไม่สมเหตุสมผลในโมเดลนั้นอีกต่อไป ฉันจะปรับโครงสร้างให้เป็นคลาส Ruby แบบธรรมดา
  5. หากโค้ดดูสมเหตุสมผลในมุมมองหนึ่ง ฉันจะเพิ่มโค้ดนั้นในผู้ช่วยหรือสร้างผู้นำเสนอ
  6. หากโค้ดไม่ต้องการรันระหว่างการร้องขอ HTTP หรือต้องรันในเบื้องหลัง โค้ดจะทำงาน
  7. หากฉันกำลังเล่นกลแบบจำลองหรือขั้นตอนต่างๆ ของกระบวนการ และทำให้ตัวควบคุมเข้าใจยากเกินไป ฉันจะใส่มันลงในวัตถุที่ให้บริการ

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

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