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

Giới thiệu về Ruby on Rails Patterns và Anti-pattern

Chào mừng bạn đến với bài đăng đầu tiên trong loạt bài của chúng tôi về Mẫu và Chống mẫu của Ruby on Rails. Trong mỗi bài đăng, chúng tôi sẽ đi sâu vào tất cả các loại mẫu bạn có thể gặp khi làm việc với ứng dụng Rails.

Hôm nay, chúng ta sẽ chỉ ra mẫu (thiết kế) là gì và sau đó sẽ cố gắng giải thích mẫu chống là gì. Để giải thích rõ hơn, chúng tôi sẽ sử dụng khung công tác theRuby on Rails đã có từ khá lâu. Nếu Rails không phải là tách trà của bạn vì một lý do nào đó, hãy chờ đợi, những ý tưởng (hoặc mô hình) được mô tả ở đây có thể cộng hưởng với bất kỳ công nghệ nào bạn kết hợp sử dụng.

Nhưng trước khi chúng ta đi vào giải thích các mẫu và phản mẫu là gì, làm thế nào chúng ta đi đến điểm chúng ta cần chúng? Tại sao chúng ta cần có tất cả những thứ này cho phần mềm của mình? Tại sao chúng ta cần thiết kế giải pháp của chúng tôi?

Có, bạn là nhà thiết kế

Ngay cả từ những ngày đầu lập trình máy tính, mọi người đã phải đối phó với các chương trình mà họ đang viết. Viết một chương trình (hoặc phần mềm) là thiết kế một giải pháp cho một vấn đề. Khi bạn viết phần mềm, bạn là một nhà thiết kế — tự do gắn nó vào chức danh công việc của bạn. Thiết kế các giải pháp tốt rất quan trọng vì phần mềm chúng tôi viết sẽ được người khác đọc và / hoặc chỉnh sửa. Ngoài ra, các giải pháp chúng tôi đưa ra sẽ được người khác xây dựng trong tương lai.

Với tất cả những điều này, các thế hệ kỹ sư bắt đầu nhìn thấy sự tương đồng trong mã và kiến ​​trúc trong suốt sự nghiệp của họ. Folks bắt đầu lập văn bản và ghi lại các giải pháp tiêu chuẩn cho các vấn đề. Một số người sẽ nói rằng đó là một cách tự nhiên về cách chúng ta hoạt động như con người. Chúng tôi muốn phân loại và tìm kiếm các mẫu trong mọi thứ và phần mềm cũng không ngoại lệ.

Là con người, cũng như chúng ta, các mô hình bắt đầu xuất hiện ngày càng nhiều khi kỹ thuật mềm ngày càng phức tạp hơn. Các mẫu thiết kế phần mềm bắt đầu tự phát triển và thực thi với các kỹ sư trên khắp thế giới. Sách, bài luận và bài nói chuyện đã được đánh giá cao, tiếp tục truyền bá những ý tưởng về các giải pháp được suy nghĩ kỹ lưỡng và đã được thử nghiệm trong trận chiến. / P>

Mẫu thiết kế là gì?

Trong kỹ thuật phần mềm, một mẫu được mô tả như một giải pháp có thể được tận dụng để giải quyết một vấn đề chung. Mô hình là thứ được coi là thông lệ tốt giữa các kỹ sư phần mềm. Kể từ khi các kỹ sư phần mềm thiết lập chúng, chúng có thể nhanh chóng đi từ các mẫu sang đối diện của chúng - chống lại các mẫu - nhưng chúng ta sẽ làm điều đó sau.

Một mẫu thiết kế sẽ chỉ cho bạn cách giải quyết nhưng nó sẽ không cung cấp cho bạn từng đoạn mã đã sẵn sàng để cắm vào phần còn lại của phần mềm của bạn. Hãy coi apattern như một hướng dẫn để viết mã được thiết kế tốt, nhưng bạn phải đưa ra cách triển khai. Sử dụng các mẫu trong mã hóa hàng ngày xuất hiện vào cuối những năm 80, nơi Kent Beck và Ward Cunningham nảy ra ý tưởng sử dụng 'ngôn ngữ mẫu'.

Ý tưởng về ngôn ngữ hoa văn được Christopher Alexander đưa ra vào cuối những năm 70 trong cuốn sách Ngôn ngữ hoa văn của ông. Bạn có thể ngạc nhiên, nhưng cuốn sách không nói về kỹ thuật phần mềm mà là kiến ​​trúc của các tòa nhà. Ngôn ngữ mẫu là một tập hợp các mẫu có tổ chức và mạch lạc, mỗi mẫu mô tả một vấn đề và cốt lõi của một giải pháp có thể được sử dụng theo nhiều cách. Âm thanh quen thuộc? (Gợi ý:framework, khác:Rails)

Sau đó, các mẫu thiết kế trong kỹ thuật phần mềm trở nên nổi tiếng với đông đảo khán giả sau cuốn sách huyền thoại Design Patterns của Gang Of Four xuất bản năm 1994. Trong cuốn sách, có giải thích và định nghĩa về các mẫu được sử dụng ngày nay— Factory, Singleton, Decorator, chỉ để đặt tên một số ít.

Tuyệt vời, bây giờ chúng ta đã làm quen hoặc nâng cao kiến ​​thức của mình về các mẫu chỉ định, hãy cùng tìm hiểu các mẫu chống là gì.

Design Anti-Pattern là gì?

Nếu bạn coi các mẫu là tốt, thì anti-pattern là xấu. Nói chính xác hơn, phần mềm anti-pattern là một mẫu có thể được sử dụng phổ biến nhưng bị coi là không hiệu quả hoặc phản tác dụng. Ví dụ điển hình của mô hình là đối tượng Chúa chứa nhiều chức năng và phụ thuộc, có thể được trích xuất và tách thành các đối tượng khác nhau.

Nguyên nhân phổ biến của việc chống lại các mẫu trong mã có rất nhiều. Ví dụ, một tốt là khi một người tốt (khuôn mẫu) trở thành kẻ xấu (một khuôn mẫu chống đối). Giả sử bạn đã quen với việc sử dụng một công nghệ cụ thể ở công ty trước đây của mình và bạn đã đạt được năng lực cao về nó. Vì lợi ích của ví dụ, hãy sử dụng Docker. Bạn biết cách đóng gói hiệu quả các ứng dụng vào Dockercontainers, sắp xếp chúng trên đám mây và kéo nhật ký của chúng xuống khỏi đám mây. Đột nhiên, bạn nhận được một công việc mới mà bạn cần gửi các ứng dụng giao diện người dùng. Vì bạn biết nhiều về Docker và cách gửi ứng dụng với nó, nên quyết định đầu tiên của bạn là đóng gói mọi thứ và triển khai nó lên đám mây.

Tuy nhiên, bạn ít biết rằng, các ứng dụng giao diện người dùng không quá phức tạp trong công việc hiện tại của bạn và việc đưa chúng vào các thùng chứa có thể không phải là cách giải quyết hiệu quả nhất. Đầu tiên nghe có vẻ là một ý kiến ​​hay, nhưng sau đó, nó phản tác dụng. Mẫu chống này được gọi là "Golden Hammer".

Có thể tóm gọn lại bằng câu nói “Nếu bạn có một cái búa, thì mọi thứ giống như một cái đinh”. Nếu bạn thực sự giỏi với Docker và điều phối các dịch vụ, mọi thứ đều là một dịch vụ Docker được tạo ra để được điều phối trên đám mây.

Những điều này xảy ra và sẽ xảy ra. Người tốt chuyển sang mua xấu, và ngược lại. Nhưng Ruby và Rails phù hợp với bức tranh này ở đâu?

Ruby First, then Rails

Hầu hết mọi người đã được làm quen với Ruby bằng cách sử dụng Ruby on Rails, một khuôn khổ phổ biến để xây dựng các trang web một cách nhanh chóng. Tôi đã làm quen với Ruby theo cách tương tự, không có gì sai với điều đó. Rails dựa trên phần mềm đã được thiết lập tốt này được gọi là Model-View-Controller, viết tắt là MVC. Nhưng trước khi chúng ta đi sâu vào chi tiết về mẫu MVC trong Rails, một sai lầm lớn thường xảy ra là sử dụng Rails mà không học Ruby đúng cách.

Khung công tác Rails là một trong những khung công tác phù hợp khi bạn có ý tưởng và muốn xây dựng nó nhanh chóng. Ngày nay, đó là một câu chuyện hoàn toàn khác, Rails vẫn được sử dụng, nhưng không đến mức như thời kỳ đỉnh cao của nó. Rất dễ sử dụng và chạy, những người mới bắt đầu lotof bắt đầu xây dựng các ứng dụng web của họ bằng lệnh mới rails. Những gì đã xảy ra sau đó, dọc theo con đường, các vấn đề bắt đầu xảy ra. Khi mới bắt đầu, bạn bị thu hút bởi tốc độ và sự đơn giản của quá trình phát triển với Rails, và mọi thứ lúc đầu hoạt động rất kỳ diệu và trơn tru. Sau đó, bạn thấy rằng bạn đã coi thường rất nhiều điều 'tưởng tượng', và bạn không hiểu điều gì đang xảy ra đằng sau bức màn.

Tôi đã gặp vấn đề này và tôi chắc rằng nhiều người mới bắt đầu và người mới bắt đầu nâng cao đang gặp phải vấn đề này. Bạn bắt đầu với một khuôn khổ trong tay, bạn xây dựng trên nó, và khi bạn cố gắng thêm một cái gì đó có tính tùy chỉnh cao, bạn không thể, bởi vì bạn đã sử dụng tất cả các điểm kỳ diệu từ khuôn khổ đó. Tại thời điểm đó, bạn phải quay lại từ đầu và học những điều cơ bản. Quay trở lại không có vấn đề gì, xảy ra với tất cả chúng ta. Nhưng vấn đề trở nên nghiêm trọng hơn nếu bạn tiếp tục mà không biết những thứ thiết yếu, như trong Ruby. Một cuốn sách hay có thể giúp bạn về vấn đề này là The Well-Grounded Rubyist.

Là một người mới bắt đầu, bạn không cần phải đọc nó từ đầu đến cuối. Nhưng hãy giữ nó bên mình để bạn có thể tham khảo nó một cách nhanh chóng. Tôi không nói rằng bạn nên dừng lại ngay bất cứ điều gì bạn đang làm và đọc hết cuốn sách, nhưng thỉnh thoảng dừng lại và cập nhật kiến ​​thức của bạn về những điều cơ bản về Ruby, nó có thể mở ra một số newhorizon cho bạn.

MVC:Rails 'Bread &Butter

OK, nhưng MVC thì sao? Mô hình Model-View-Controller đã có từ lâu. Nó đã được áp dụng bởi nhiều khung công tác trên rất nhiều ngôn ngữ nhưRuby (Rails), Python (Django), Java (Play, Spring MVC). Ý tưởng là tạo ra các thành phần riêng biệt mà mỗi thành phần thực hiện công việc của chúng:

  • Mô hình xử lý dữ liệu và logic nghiệp vụ.
  • Chế độ xem dành cho việc trình bày dữ liệu và giao diện người dùng.
  • Bộ điều khiển gắn kết cả hai với nhau bằng cách lấy dữ liệu từ Mô hình và hiển thị Chế độ xem cho người dùng.

Về lý thuyết thì có vẻ tuyệt vời, và thật tuyệt vời khi logic ở mức tối thiểu và trang web của bạn không chứa logic phức tạp. Đó là lúc mọi thứ trở nên phức tạp, nhưng chúng ta sẽ đạt được điều đó sau một giây.

MVC lan rộng như cháy rừng trong cộng đồng phát triển web. Thư viện chẵn như React, ngày nay cực kỳ phổ biến được giải thích là lớp giao diện của ứng dụng web của bạn. Không có mô hình nào khác đã được phổ biến đến mức không thể bị lay chuyển. Rails đã thêm thePublish-Subscriberewith ActionCable, trong đó khái niệm kênh được mô tả như là bộ điều khiển của mẫu MVC.

Nhưng những mẫu phản ở đó là gì, trong những mẫu được sử dụng rộng rãi như vậy? Hãy cùng tìm hiểu một số mẫu chống phổ biến nhất cho từng phần của mẫu MVC.

Các vấn đề về mô hình

Khi một ứng dụng phát triển và logic kinh doanh được mở rộng, mọi người có xu hướng tập trung quá nhiều vào các mô hình của họ. Tăng trưởng liên tục có thể dẫn đến một mô hình chống lại được gọi là Mô hình béo.

Mô hình nổi tiếng 'Người mẫu béo, Người điều khiển gầy' xác định là một kẻ xấu, một số khác là một chàng trai tốt. Chúng tôi sẽ nói rằng có bất kỳ chất béo nào là một mô hình chống lại. Để hiểu rõ hơn, chúng ta hãy đi vào một ví dụ. Hãy tưởng tượng chúng ta có một dịch vụ phát trực tuyến như Spotify hoặc Deezer. Bên trong nó, chúng tôi có một mô hình cho các bài hát như thế này:

class Song < ApplicationRecord
  belongs_to :album
  belongs_to :artist
  belongs_to :publisher
 
  has_one :text
  has_many :downloads
 
  validates :artist_id, presence: true
  validates :publisher_id, presence: true
 
  after_update :alert_artist_followers
  after_update :alert_publisher
 
  def alert_artist_followers
    return if unreleased?
 
    artist.followers.each { |follower| follower.notify(self) }
  end
 
  def alert_publisher
    PublisherMailer.song_email(publisher, self).deliver_now
  end
 
  def includes_profanities?
    text.scan_for_profanities.any?
  end
 
  def user_downloaded?(user)
    user.library.has_song?(self)
  end
 
  def find_published_from_artist_with_albums
    ...
  end
 
  def find_published_with_albums
    ...
  end
 
  def to_wav
    ...
  end
 
  def to_mp3
    ...
  end
 
  def to_flac
    ...
  end
end

Vấn đề với các mô hình như thế này là chúng trở thành bãi rác cho các logic khác nhau có thể liên quan đến một bài hát. Điều này xảy ra khi các phương thức được bổ sung từ từ từng cái một theo thời gian. Sau đó, toàn bộ mô hình có vẻ lớn và đơn giản, và việc tách logic thành một vài chỗ khác có thể có lợi trong tương lai.

Ngay lập tức, bạn có thể thấy rằng có một số thực hành được khuyến nghị mà mô hình này đang vi phạm. Nó đang phá vỡ Nguyên tắc Trách nhiệm Đơn lẻ (SRP). Nó liên quan đến việc thông báo cho những người theo dõi và nhà xuất bản. Nó kiểm tra văn bản để tìm những lời tục tĩu, có các phương pháp xuất bài hát sang các định dạng âm thanh khác nhau, v.v. Có tất cả những điều này làm tăng thêm độ phức tạp của mô hình và tôi thậm chí không thể tưởng tượng ra tệp thử nghiệm cho mô hình này.

Cách cấu trúc lại mô hình này chủ yếu phụ thuộc vào cách các phương thức được gọi và sử dụng ở những nơi khác. Tôi sẽ trình bày một số ý tưởng chung về cách chúng tôi có thể xử lý những vấn đề này và bạn có thể chọn ý tưởng phù hợp nhất với trường hợp của mình.

Các lệnh gọi lại thông báo cho người theo dõi và nhà xuất bản có thể được trích xuất để vui mừng. Các công việc sẽ được xếp vào hàng và logic không nằm ngoài mô hình, như sau:

class NotifyFollowers < ApplicationJob
  def perform(followers)
    followers.each { |follower| follower.notify }
  end
end
 
class NotifyPublisher < ApplicationJob
  def perform(publisher, song)
    PublisherMailer.song_email(publisher, self).deliver_now
  end
end

Các công việc sẽ tự vận hành theo quy trình riêng biệt, không theo mô hình. Bây giờ, bạn có thể kiểm tra logic công việc của mình một cách riêng biệt và chỉ cần kiểm tra xem công việc phù hợp có được xếp lại từ mô hình của bạn hay không.

Giả sử rằng việc kiểm tra các ngôn từ tục tĩu và liệu người dùng đã tải xuống bản nhạc đó hay chưa đều diễn ra trong phần xem của ứng dụng của chúng tôi. Trong trường hợp đó, chúng ta có thể sử dụng mẫu aDecorator. Một giải pháp phổ biến có thể giúp bạn bắt đầu nhanh chóng là đá quý Draper. Với nó, bạn có thể viết một trình trang trí tương tự như sau:

class SongDecorator < Draper::Decorator
  delegate_all
 
  def includes_profanities?
    object.text.scan_for_profanities.any?
  end
 
  def user_downloaded?(user)
    object.user.library.has_song?(self)
  end
end

Sau đó, bạn sẽ gọi decorate trong bộ điều khiển của bạn, ví dụ:

def show
  @song = Song.find(params[:id]).decorate
end

Và sử dụng nó trong quan điểm của bạn như vậy:

<%= @song.includes_profanities? %>
<%= @song.user_downloaded?(user) %>

Nếu bạn không thích sử dụng phụ thuộc, bạn có thể cuộn trang trí của mình, nhưng chúng ta sẽ nói về điều này trong một bài đăng blog khác. Bây giờ bạn đã tách biệt được phần lớn các mối quan tâm về mô hình của mình, hãy giải quyết các phương pháp tìm bài hát và chuyển đổi bài hát. Chúng tôi có thể sử dụng các mô-đun để phân tách chúng:

module SongFinders
  def find_published_from_artist_with_albums
    ...
  end
 
  def find_published_with_albums
    ...
  end
end
 
module SongConverter
  def to_wav
    ...
  end
 
  def to_mp3
    ...
  end
 
  def to_flac
    ...
  end
end

Mô hình Bài hát sẽ mở rộng SongFinders mô-đun, vì vậy các phương thức của nó là các phương thức lớp khả dụng. Mô hình Bài hát sẽ bao gồm SongConverter mô-đun, do đó, các phương thức của nó có sẵn trên các phiên bản mô hình.

Tất cả những điều này sẽ làm cho mô hình Song của chúng tôi khá mỏng và đúng điểm:

class Song < ApplicationRecord
  extend SongFinders
  include SongConverter
 
  belongs_to :album
  belongs_to :artist
  belongs_to :publisher
 
  has_one :text
  has_many :downloads
 
  validates :artist_id, presence: true
  validates :publisher_id, presence: true
 
  after_update :alert_artist_followers, if: :published?
  after_update :alert_publisher
 
  def alert_artist_followers
    NotifyFollowers.perform_later(self)
  end
 
  def alert_publisher
    NotifyPublisher.perform_later(publisher, self)
  end
end

Có rất nhiều mẫu chống mô hình khác, và đây chỉ là một ví dụ về những gì có thể đi về phía nam với các mô hình. Hãy theo dõi một bài đăng trên blog khác trong loạt bài này, nơi chúng ta sẽ đi vào chi tiết về các mẫu chống mô hình khác. Hiện tại, hãy xem điều gì có thể xảy ra với lượt xem.

Xem sự cố

Bên cạnh các vấn đề về mô hình, những người sử dụng Rails đôi khi có thể gặp khó khăn với sự phức tạp của chế độ xem của họ. Dần dần theo thời gian, JavaScript trở nên thống trị và hầu hết các khía cạnh của giao diện người dùng đều được viết bằng JavaScript. Rails tuân theo một mô hình khác nhau về điều này. Thay vì có mọi thứ trong dạng xem JavaScriptin, bạn chỉ nên "rắc" JS lên nó.

Trong mọi trường hợp, việc phải xử lý HTML, CSS, JS và Ruby tại cùng một nơi có thể trở nên lộn xộn. Điều khó khăn khi xây dựng các khung nhìn Rails là logic miền đôi khi có thể được tìm thấy bên trong khung nhìn. Đây là điều không nên vì nó phá vỡ mô hình MVC, ngay từ đầu.

Một trường hợp khác có thể là do sử dụng quá nhiều Ruby được nhúng trong các khung nhìn và các phần tử của bạn. Chúng ta sẽ xem xét các ví dụ về nó trong một số bài viết tiếp theo của loạt bài này, vì vậy hãy chú ý theo dõi.

Sự cố với bộ điều khiển

Bộ điều khiển đường ray cũng có thể gặp phải nhiều vấn đề khác nhau. Một trong số đó là chống mẫu Fat Controller.

Trước đây, mô hình của chúng tôi béo, nhưng nó đã giảm một số trọng lượng và bây giờ chúng tôi nhận thấy rằng bộ điều khiển đã tăng thêm một số trọng lượng trong quá trình này. Thông thường, điều này xảy ra khi logic nghiệp vụ được đặt bên trong Bộ điều khiển, nhưng vị trí thực tế của nó là trong mô hình hoặc ở nơi khác. Một số ý tưởng được chia sẻ trong phần Mô hình lớn vẫn có thể áp dụng cho bộ điều khiển - trích xuất mã cho người trình bày, sử dụng lệnh gọi lạiActiveRecord, định dạng các đối tượng toService.

Một số người thậm chí còn sử dụng đá quý nhưTrailblazer ordry-transaction Ý tưởng ở đây là tạo ra các lớp xử lý các giao dịch cụ thể. Di chuyển mọi thứ ra khỏi bộ điều khiển và giữ cho mô hình mỏng, bạn lưu trữ và kiểm tra logic bên trong các lớp riêng biệt này, mà một số gọi các dịch vụ, giao dịch, hành động và tương tự.

Kết luận

Có rất nhiều mẫu chống và thậm chí nhiều giải pháp hơn cho chúng. Để cố gắng che đậy mọi thứ trong bài đăng này sẽ tốn quá nhiều không gian và thời gian và nó sẽ làm cho bài đăng của chúng ta trông mập mạp (giống như mô hình và bộ điều khiển mà chúng ta đã nói ở trên). Hãy chắc chắn theo dõi loạt bài của chúng tôi, nơi chúng tôi sẽ đi sâu vào mọi khía cạnh của mô hình MVC trong Rails. Ở đó, bạn sẽ tìm ra cách đối phó với những mẫu chống nổi tiếng nhất. Cho đến lúc đó, tôi hy vọng bạn thích phần tổng quan này về các mẫu và anti-pattern là gì và những cái phổ biến nhất trong Ruby on Railsframework.

Cho đến ngày tiếp theo, hãy cổ vũ!

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!