ขณะเขียน Rails app อาจเจอปัญหาที่แก้ง่ายกว่าด้วย data store อื่น เช่น leaderboard rank users โดย points จากตอบคำถาม ด้วย Redis Sorted Sets implementation มากทำให้แล้ว Awesome! แตโค้ด interact กับ Redis ไว้ไหน?
User model คุย Redis:
class User < ActiveRecord::Base
def award_points(points)
Redis.current.zincrby("leaderboard", points, id)
end
endตอนนี้ User model รับผิดชอบ represent user, คุย Redis, และ manage leaderboard! ทำให้ User ยากเข้าใจและทดสอบ ตรงข้ามที่อยาก
แทน wrap Redis requests ใน object ใหม่ represent สิ่งที่用 Redis ทำ เช่น สร้าง Leaderboard class wrap Redis communication ไม่ inherit ActiveRecord::Base แตยังอยู่ใน app/models directory จะดูแบบนี้:
class Leaderboard
def award_points_to_user(user_id, points)
Redis.current.zincrby("leaderboard", points, user_id)
end
endclass User < ActiveRecord::Base
def award_points(leaderboard, points)
leaderboard.award_points_to_user(id, points)
end
endทั้งสอง classes อยู่ใน app/models แตตอนนี้ไม่ปน ActiveRecord models ด้วย logic เพิ่ม Leaderboard จัดการ Redis communication User ไม่ต้อง care leaderboards implemented ยังไง ทดสอบง่ายขึ้น
ได้ประโยชน์เยอะสร้าง classes ใหม่สำหรับ responsibilities ใหม่ app/models ที่ดีเก็บพวกมัน ได้ benefits lean on another service สำหรับ feature implementation ขณะที่โค้ดง่ายต่อการทำงาน
ลองทำดู
คิดถึง network service communication เรียกตรงจาก ActiveRecord models, controllers, views ไหม? ลองย้ายโค้ดเข้า non-ActiveRecord data model ดู โค้ดเข้าใจง่าย ทำงานง่าย ทดสอบง่ายขึ้นไหม? ส่ง email บอกผมผล!
จำได้:
All problems in computer science can be solved by another level of indirection.
— David Wheeler
…except for the problem of too many layers of indirection.
— Kevlin Henney