Computer >> Máy Tính >  >> Lập trình >> Ruby

General Ruby on Rails Problems và Takeaways

Chào mừng đến với phần cuối cùng của loạt bài về Ruby on Rails Patterns and Anti-Patterns. Đó là một chuyến đi khá vất vả khi viết và nghiên cứu tất cả các chủ đề này. Trong bài đăng trên blog này, chúng ta sẽ xem xét các vấn đề phổ biến nhất mà tôi gặp phải khi xây dựng và vận chuyển các ứng dụng Ruby on Rails qua nhiều năm.

Những ý tưởng tôi sẽ trình bày ở đây áp dụng cho hầu hết mọi nơi trong mã. Vì vậy, hãy coi chúng là những ý tưởng chung chung, không phải thứ gì đó liên quan đến mẫu Model-View-Controller. Nếu bạn quan tâm đến các mẫu và phản mẫu liên quan đến Rails MVC, bạn có thể xem các bài đăng trên blog Mô hình, Chế độ xem và Bộ điều khiển.

Vì vậy, chúng ta hãy chuyển sang các vấn đề chung và những điểm cần lưu ý.

Đối tượng ích kỷ và định luật Demeter

Định luật Demeter là một heuristic có tên khi một nhóm người làm việc trong Dự án Demeter. Ý tưởng là các đối tượng của bạn vẫn ổn miễn là chúng gọi một phương thức tại một thời điểm và không xâu chuỗi nhiều cuộc gọi phương thức. Điều này có nghĩa trong thực tế như sau:

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

Vì vậy, bây giờ, song đối tượng không còn cần biết địa chỉ đến từ đâu - địa chỉ là trách nhiệm của nhãn label sự vật. Bạn được khuyến khích chỉ chuỗi một lệnh gọi phương thức và làm cho các đối tượng của bạn trở nên 'ích kỷ' để chúng không chia sẻ thông tin đầy đủ trực tiếp mà thông qua các phương thức trợ giúp.

May mắn thay, trong Rails, bạn không phải viết một phương thức trợ giúp - bạn có thể sử dụng delegate người trợ giúp:

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

Bạn có thể tiếp tục và thử với các tùy chọn mà người được ủy quyền chấp nhận trong tài liệu của người xóa. Nhưng ý tưởng và cách thực hiện khá đơn giản. Bằng cách áp dụng Định luật Demeter, bạn giảm sự ghép nối cấu trúc. Cùng với delegate mạnh mẽ , bạn làm điều đó trong ít dòng hơn và có các tùy chọn tuyệt vời.

Một ý tưởng khác rất giống với Định luật Demeter là Nguyên tắc một trách nhiệm (hay viết tắt là SRP). Nó nói rằng một mô-đun, lớp hoặc chức năng phải chịu trách nhiệm cho một phần của hệ thống. Hoặc, được trình bày theo cách khác:

Tập hợp những điều thay đổi vì những lý do giống nhau. Tách biệt những thứ thay đổi vì những lý do khác nhau.

Mọi người thường có cách hiểu khác nhau về SRP, nhưng ý tưởng là giữ cho các khối xây dựng của bạn chịu trách nhiệm về một việc duy nhất. Có thể là một thách thức để đạt được SRP khi ứng dụng Rails của bạn mở rộng, nhưng hãy lưu ý khi tái cấu trúc.

Khi thêm các tính năng và tăng LOC, tôi nhận thấy rằng mọi người thường tìm kiếm một giải pháp nhanh chóng. Vì vậy, hãy bắt đầu khắc phục nhanh chóng.

Tôi biết một chàng trai (Bạn có cần viên ngọc Ruby đó không?)

Trở lại thời mà Rails còn là một chủ đề nóng, đã có sự bùng nổ trong cộng tác mã nguồn mở, với những viên ngọc Ruby mới xuất hiện ở mọi ngóc ngách (giống như ngày nay với tất cả các thư viện JavaScript mới nổi, nhưng ở quy mô nhỏ hơn nhiều):

👆 Thông tin từ Số lượng Mô-đun.

Dù sao, một cách tiếp cận phổ biến là tìm một viên ngọc hiện có để giải quyết vấn đề của bạn.

Không có gì sai với điều đó, nhưng tôi muốn chia sẻ một số lời khuyên trước khi bạn quyết định cài đặt một viên ngọc.

Trước tiên, hãy tự hỏi bản thân những câu hỏi sau:

  • Bạn sẽ sử dụng phần nào trong số các tính năng của đá quý?
  • Có viên ngọc nào tương tự ngoài kia 'đơn giản hơn' hoặc cập nhật hơn không?
  • Bạn có thể triển khai tính năng mình cần một cách dễ dàng và tự tin không?

Đánh giá xem nó có đáng để thực hiện không nếu bạn không có kế hoạch sử dụng toàn bộ mảng tính năng đá quý. Hoặc, nếu việc triển khai của gem quá phức tạp và bạn tin rằng mình có thể làm điều đó đơn giản hơn, hãy chọn một giải pháp tùy chỉnh.

Một yếu tố khác mà tôi xem xét là kho lưu trữ của đá quý hoạt động như thế nào - có bất kỳ người bảo trì nào đang hoạt động không? Lần cuối cùng phát hành là khi nào?

Bạn cũng nên chú ý đến sự phụ thuộc của đá quý. Bạn không muốn bị khóa trong một phiên bản phụ thuộc cụ thể, vì vậy hãy luôn kiểm tra Gemfile.spec tập tin. Tham khảo cách RubyGems để chỉ định các phiên bản đá quý.

Trong khi chúng ta đang nói về chủ đề đá quý, có một ý tưởng liên quan mà tôi đã gặp phải:hiện tượng 'Không được phát minh ở đây' (hoặc NIH) áp dụng cho thế giới Rails / Ruby. Hãy xem nội dung của nó trong phần tiếp theo.

Không được phát minh ở đây (Có lẽ bạn cần viên ngọc Ruby đó?)

Trong một vài lần xảy ra trong sự nghiệp của mình, tôi đã có cơ hội trải nghiệm những người (bao gồm cả tôi) mắc phải hội chứng 'Not Invented Here'. Ý tưởng tương tự như 'phát minh lại bánh xe'. Đôi khi, các nhóm và tổ chức không tin tưởng vào các thư viện (đá quý) mà họ không thể kiểm soát. Sự thiếu tin tưởng có thể là nguyên nhân khiến họ tái tạo lại một viên ngọc đã có sẵn.

Đôi khi, trải nghiệm NIH có thể là một điều tốt. Việc tạo ra một giải pháp trong nhà có thể rất tuyệt vời, đặc biệt nếu bạn cải thiện nó hơn các giải pháp khác ngoài kia. Nếu bạn quyết định sử dụng giải pháp mã nguồn mở, điều đó còn có thể tốt hơn (hãy xem Ruby on Rails hoặc React). Nhưng nếu bạn muốn phát minh lại bánh xe vì lợi ích của nó, đừng làm điều đó. Bản thân bánh xe đã khá tuyệt rồi.

Chủ đề này khá phức tạp và nếu bạn rơi vào tình huống như vậy, hãy tự hỏi mình những câu hỏi sau:

  • Chúng tôi có tự tin rằng mình có thể tạo ra một giải pháp tốt hơn những giải pháp hiện có không?
  • Nếu giải pháp nguồn mở hiện tại khác với những gì chúng tôi cần, chúng tôi có thể đóng góp cho nguồn mở và cải thiện nó không?
  • Hơn nữa, chúng ta có thể trở thành người duy trì giải pháp nguồn mở và có thể cải thiện rất nhiều cuộc sống của các nhà phát triển không?

Nhưng đôi khi, bạn chỉ cần đi theo cách riêng của mình và tự tạo một thư viện. Có thể tổ chức của bạn không thích cấp phép cho một thư viện mã nguồn mở, vì vậy bạn buộc phải xây dựng thư viện của riêng mình. Nhưng bất cứ điều gì bạn làm, tôi muốn nói rằng hãy tránh phát minh lại bánh xe.

Nhân viên cứu hộ đang làm nhiệm vụ (Các trường hợp ngoại lệ cứu hộ quá mức)

Mọi người có xu hướng giải cứu nhiều trường hợp ngoại lệ hơn so với mục tiêu ban đầu.

Chủ đề này liên quan đến mã nhiều hơn một chút so với những chủ đề trước. Nó có thể là cảm giác thông thường đối với một số người, nhưng nó có thể được nhìn thấy trong mã đôi khi. Ví dụ:

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

Nếu chúng tôi không chỉ định ngoại lệ mà chúng tôi muốn giải cứu, chúng tôi sẽ bắt gặp một số ngoại lệ mà chúng tôi không dự định.

Trong trường hợp này, vấn đề có thể là song đối tượng là nil . Khi ngoại lệ đó được báo cáo với trình theo dõi lỗi, bạn có thể nghĩ rằng quá trình tải lên đã xảy ra lỗi, trong khi thực tế, bạn có thể đang gặp phải điều gì đó hoàn toàn khác.

Vì vậy, để an toàn, khi cứu các trường hợp ngoại lệ, hãy đảm bảo rằng bạn có được danh sách tất cả các trường hợp ngoại lệ có thể xảy ra. Nếu bạn không thể có được mọi ngoại lệ vì lý do nào đó, tốt hơn là nên giải cứu dưới mức hơn là giải cứu quá mức. Giải cứu các trường hợp ngoại lệ mà bạn biết và xử lý các trường hợp khác ở giai đoạn sau.

Bạn hỏi quá nhiều (quá nhiều truy vấn SQL)

Trong phần này, chúng ta sẽ đi qua một vấn đề phát triển web khác, vấn đề cơ sở dữ liệu quan hệ.

Bạn đánh bom máy chủ web với quá nhiều truy vấn SQL trong một yêu cầu. Làm thế nào mà vấn đề phát sinh? Chà, nó có thể xảy ra nếu bạn cố gắng tìm nạp nhiều bản ghi từ nhiều bảng trong một yêu cầu. Nhưng điều thường xảy ra nhất là vấn đề truy vấn N + 1 khét tiếng.

Hãy tưởng tượng các mô hình sau:

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

Nếu chúng tôi muốn thể hiện một vài bài hát trong một thể loại và nghệ sĩ của họ:

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

Đoạn mã này sẽ kích hoạt một truy vấn SQL để nhận được mười bài hát. Sau đó, một truy vấn SQL bổ sung sẽ được thực hiện để tìm nghệ sĩ cho mỗi bài hát. Đó là tổng số mười một (11) truy vấn.

Hãy tưởng tượng kịch bản nếu chúng tôi tải nhiều bài hát hơn - chúng tôi sẽ đặt cơ sở dữ liệu dưới tải nặng hơn khi cố gắng tải tất cả các nghệ sĩ.

Ngoài ra, hãy sử dụng includes từ Rails:

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

Sau khi includes , bây giờ chúng tôi chỉ nhận được hai truy vấn SQL, bất kể chúng tôi quyết định hiển thị bao nhiêu bài hát. Thật gọn gàng.

Một cách bạn có thể chẩn đoán quá nhiều truy vấn SQL đang được phát triển. Nếu bạn thấy một nhóm các truy vấn SQL tương tự đang tìm nạp dữ liệu từ cùng một bảng, thì có điều gì đó khó hiểu đang xảy ra ở đó. Đó là lý do tại sao tôi đặc biệt khuyến khích bạn bật ghi nhật ký SQL cho môi trường phát triển của bạn. Ngoài ra, Rails hỗ trợ nhật ký truy vấn dài dòng cho biết vị trí truy vấn được gọi trong mã.

Nếu xem nhật ký không phải là việc của bạn hoặc bạn muốn điều gì đó nghiêm túc hơn, hãy thử đo hiệu suất của AppSignal và phát hiện truy vấn N + 1. Ở đó, bạn sẽ nhận được một chỉ báo tuyệt vời về việc liệu vấn đề của bạn có xuất phát từ một truy vấn N + 1 hay không. Đây là cách nó trông như bên dưới:

Tổng kết

Cảm ơn vì đã đọc loạt bài đăng trên blog này. Tôi rất vui vì bạn đã tham gia cùng tôi trong chuyến đi thú vị này, nơi chúng tôi đã giới thiệu các mẫu và anti-pattern trong Rails đến khám phá chúng bên trong mẫu Rails MVC, trước bài đăng blog cuối cùng này về các vấn đề chung.

Tôi hy vọng bạn đã học được rất nhiều, hoặc ít nhất là sửa đổi và thiết lập những gì bạn đã biết. Đừng căng thẳng về việc ghi nhớ tất cả. Bạn luôn có thể tham khảo loạt bài này nếu bạn gặp khó khăn trong bất kỳ lĩnh vực nào.

Bạn chắc chắn sẽ gặp phải cả mô hình và mô hình phản đối bởi vì thế giới này (và đặc biệt là kỹ thuật phần mềm) không lý tưởng. Điều đó cũng không khiến bạn lo lắng.

Nắm vững các mẫu và chống mẫu sẽ khiến bạn trở thành một kỹ sư phần mềm tuyệt vời. Nhưng điều khiến bạn thậm chí còn tốt hơn là biết khi nào nên phá vỡ những khuôn mẫu và khuôn mẫu đó, bởi vì không có giải pháp hoàn hảo.

Cảm ơn một lần nữa vì đã tham gia và đọc. Hẹn gặp lại các bạn trong chương trình tiếp theo - và chúc mừng!

Tái bút. Nếu bạn muốn đọc các bài đăng của Ruby Magic ngay khi chúng xuất hiện trên báo chí, hãy đăng ký bản tin Ruby Magic của chúng tôi và không bao giờ bỏ lỡ một bài đăng nào!