Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyonRailsのパターンとアンチパターンの概要

RubyonRailsのパターンとアンチパターンに関するシリーズの最初の投稿へようこそ。それぞれの投稿では、Railsアプリの操作中に遭遇する可能性のあるあらゆる種類のパターンについて詳しく説明します。

今日は、(デザイン)パターンとは何かを示してから、アンチパターンとは何かについても説明します。説明をわかりやすく説明するために、かなり前から存在しているRubyonRailsフレームワークを使用します。 Railsが何らかの理由であなたのお茶ではない場合は、しばらくお待ちください。ここで説明するアイデア(またはパターン)は、最終的に使用するテクノロジーに共鳴する可能性があります。

しかし、パターンとアンチパターンとは何かを説明する前に、どのようにしてそれらが必要なポイントに到達したのでしょうか。ソフトウェアにこれらすべてのものが必要なのはなぜですか?なぜ設計する必要があるのですか 私たちのソリューション?

はい、あなたはデザイナーです

コンピュータプログラミングの初期の頃から、人々は自分たちが書いているプログラムの設計に取り組まなければなりませんでした。プログラム(またはソフトウェア)を作成することは、問題の解決策を設計することです。あなたがソフトウェアを書くとき、あなたはデザイナーです—それをあなたの肩書きに自由に付け加えてください。私たちが作成するソフトウェアは他の人が読んだり編集したりするため、優れたソリューションを設計することは重要です。また、私たちが思いついたソリューションは、将来、他の人によって構築される予定です。

これらすべてを念頭に置いて、何世代にもわたるエンジニアは、キャリアを通じてコードとアーキテクチャに同様の設計が見られるようになりました。人々は問題の標準的な解決策を抽出して文書化し始めました。それは人間としての私たちの機能の自然な方法だと言う人もいます。私たちはすべてのパターンを分類して見つけるのが好きで、ソフトウェアも例外ではありません。

私たちがそうであるように、人間であるということは、ソフトウェアエンジニアリングがより複雑になるにつれて、パターンがますます出現し始めました。ソフトウェアデザインパターンは、世界中のエンジニアと一緒に開発され、定着し始めました。本、エッセイ、トークが提供され、よく考えられ、戦いでテストされたソリューションのアイデアがさらに広がりました。これらのソリューションは多くの人の時間とお金を節約したので、用語のデザインパターンを調べて、それが本当に何であるかを見てみましょう。

デザインパターンとは何ですか?

ソフトウェアエンジニアリングでは、パターンは一般的な問題を解決するために再利用できるソリューションとして説明されます。このパターンは、ソフトウェアエンジニアの間で良い習慣と見なされているものです。ソフトウェアエンジニアがそれらを設定したので、パターンからその反対のアンチパターンにすばやく移行できますが、後で説明します。

デザインパターンはソリューションへの道を示しますが、ソフトウェアの残りの部分にプラグインする準備ができているコードの一部を提供しません。 apatternは、適切に設計されたコードを作成するためのガイドと考えてください。ただし、実装を考え出す必要があります。日常のコーディングでパターンを使用することは、80年代後半に登場し、ケントベックとウォードカニンガムは「パターン言語」を使用するというアイデアを思いつきました。

パターン言語のアイデアは、70年代後半にクリストファーアレクサンダーが著書「パターン言語」で発表したものです。驚くかもしれませんが、この本はソフトウェアエンジニアリングではなく、建物の建築に関するものです。パターン言語は、体系化された一貫性のあるパターンのセットであり、各パターンは、さまざまな方法で使用できる問題とソリューションのコアを記述します。おなじみですか? (ヒント:フレームワーク、別のヒント:Rails)

その後、ソフトウェアエンジニアリングのデザインパターンは、1994年に出版された伝説の本「GangOf Fourによるデザインパターン」の後に多くの聴衆に知られるようになりました。この本には、今日使用されているパターンの説明と定義があります。いくつか。

すばらしいです。デザインとパターンに関する知識を習得または更新したので、アンチパターンとは何かを調べてみましょう。

デザインアンチパターンとは何ですか?

パターンを良い人と考えると、アンチパターンは悪いものです。より正確には、ソフトウェアのアンチパターンは、一般的に使用される可能性があるパターンですが、効果がないか、逆効果であると見なされます。アンチパターンの典型的な例は、多くの機能と依存関係を含む神オブジェクトであり、これらを抽出してさまざまなオブジェクトに分離することができます。

コードのアンチパターンの一般的な原因はたくさんあります。たとえば、良いものは、良い人(パターン)が悪い人(アンチパターン)になるときです。以前の会社で特定のテクノロジーを使用することに慣れていて、そのテクノロジーで高いレベルの能力を獲得したとしましょう。例として、Dockerを使用してみましょう。アプリケーションをDockercontainerに効率的にパックし、クラウドでオーケストレーションし、クラウドからログを取得する方法を知っています。突然、フロントエンドアプリケーションを出荷する必要がある新しい仕事に就きます。 Dockerとそれを使用してアプリを出荷する方法についてはよく知っているので、最初の決定はすべてをパッケージ化してクラウドにデプロイすることです。

しかし、ほとんど知らなかったのですが、フロントエンドアプリは現在の仕事ではそれほど複雑ではなく、コンテナーに入れることが最も効果的なソリューションではない可能性があります。最初は良いアイデアのように聞こえますが、後で逆効果になることがわかります。このアンチパターンは「ゴールデンハンマー」と呼ばれます。

「ハンマーを持っていれば、すべてが釘のように見える」と要約することができます。 Dockerとサービスのオーケストレーションが本当に得意な場合は、すべてがクラウドでオーケストレーションされるように作成されたDockerサービスです。

これらのことが起こり、これからも起こります。善人は悪い買い物に目を向け、逆もまた同様です。しかし、RubyとRailsはこの図のどこに当てはまりますか?

最初にルビー、次にレール

ほとんどの人は、Webサイトをすばやく構築するための人気のあるフレームワークであるRubyonRailsを使用してRubyを紹介されました。私も同じようにRubyに精通しましたが、それは間違いではありません。 Railsは、Model-View-Controller(略してMVC)と呼ばれるこの確立されたソフトウェアパターンに基づいています。しかし、RailsのMVCパターンの詳細に飛び込む前に、よくある大きな誤謬の1つは、Rubyを適切に学習せずにRailsを使用することです。

Railsフレームワークは、アイデアがあり、それを迅速に構築したいと思ったときに頼りになるフレームワークの1つでした。今日では、まったく別の話です。Railsはまだ使用されていますが、最盛期にはありませんでした。非常に使いやすく、実行しやすいため、多くの初心者は、railsnewコマンドを使用してWebアプリを構築しようと試みました。その後、何が起こったのか、道に沿って、問題が発生し始めました。初心者として、Railsを使用した開発のスピードとシンプルさに魅了され、最初はすべてが魔法のようにスムーズに機能します。それから、あなたはあなたが多くの「魔法」を当然のことと思っているのを見ます、そしてあなたはカーテンの後ろで何が起こっているのか理解していません。

私はこの問題を抱えていました、そして私は多くの初心者と上級の初心者がそれに苦しんでいると確信しています。手元にあるフレームワークから始めて、それを基に構築します。高度にカスタム化されたものを追加しようとすると、そのフレームワークのすべての魔法のポイントを使い果たしたため、追加できません。その時点で、最初に戻って基本を学ぶ必要があります。戻ることは大したことではありません、私たちの最善を尽くします。しかし、Rubyのように本質的なことを学ばずに先に進むと、問題はさらに深刻になります。この点であなたを助けることができる1つの良い本はTheWell-GroundedRubyistです。

初心者として、最初から最後まで読む必要はありません。ただし、すぐに相談できるように、脇に置いておきます。何をしているのかを突然止めて本全体を読むべきだと言っているのではありませんが、時々立ち止まってRubyの基本についての知識を更新してください。そうすれば、いくつかの新しい視野が開かれるかもしれません。

MVC:Railsのパンとバター

OK、でもMVCはどうですか? Model-View-Controllerパターンは、飼料の周りにありました。これは、Ruby(Rails)、Python(Django)、Java(Play、Spring MVC)などの多数の言語の多くのフレームワークで採用されています。アイデアは、それぞれがそれぞれの仕事をする別々のコンポーネントを持つことです:

  • モデルはデータとビジネスロジックを処理します。
  • ビューは、データとユーザーインターフェイスを表示するためのものです。
  • コントローラーは、モデルからデータを取得し、ビューをユーザーに表示することで、2つを結び付けます。

理論的には素晴らしいと思いますが、ロジックが最小限で、Webサイトに複雑なロジックが含まれていない場合に最適です。ここで注意が必要ですが、すぐにわかります。

MVCは、Web開発コミュニティ全体に山火事のように広がりました。最近めちゃくちゃ人気のあるReactのようなライブラリも、Webアプリのビューレイヤーとして説明されています。他のパターンは、それを振り払うことができないほど普及していません。 Railsは、チャネルの概念がMVCパターンのコントローラーとして記述されているActionCableを使用してPublish-Subscribeを追加しました。

しかし、非常に広く使用されているパターンのアンチパターンは何ですか? MVCパターンの各部分で最も一般的なアンチパターンのいくつかを調べてみましょう。

モデルの問題

アプリケーションが成長し、ビジネスロジックが拡張されるにつれて、人々はモデルを過密にする傾向があります。絶え間ない成長は、ファットモデルと呼ばれるアンチパターンにつながる可能性があります。

有名な「ファットモデル、スキニーコントローラー」のパターンは、悪者、場合によっては善人として識別されます。脂肪のいずれかを持つことはアンチパターンであると言います。それをよりよく理解するために、例を見てみましょう。 SpotifyやDeezerのようなストリーミングサービスがあると想像してみてください。その中には、次のような曲のモデルがあります:

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

このようなモデルの問題は、曲に関連する可能性のあるさまざまなロジックのダンプグラウンドになることです。これは、メソッドが時間の経過とともに1つずつゆっくりと追加されるときに発生します。その場合、モデル全体が大きく複雑に見え、ロジックを他のいくつかの場所に分割することは、将来的に有益であることが証明される可能性があります。

すぐに、このモデルが破っている推奨プラクティスがいくつかあることがわかります。これは、単一責任原則(SRP)に違反しています。フォロワーと発行者への通知を扱います。冒とく的な表現がないかテキストをチェックし、曲をさまざまなオーディオ形式にエクスポートする方法などがあります。これらすべてを使用すると、モデルが複雑になり、このモデルのテストファイルを想像することすらできません。

このモデルをリファクタリングする方法は、メソッドが他の場所でどのように呼び出されて使用されるかに大きく依存します。これらをどのように処理できるかについての一般的なアイデアをいくつか紹介します。ケースに最適なものを選択できます。

フォロワーとパブリッシャーに通知するコールバックは、ジョブに抽出される可能性があります。次のように、ジョブはキューに入れられ、ロジックはモデルから除外されます。

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

ジョブは、モデルから離れて、別のプロセスで単独で実行されます。これで、ジョブロジックを個別にテストして、適切なジョブがモデルからキューに入れられたかどうかを確認できます。

冒とく的な表現のチェックと、ユーザーが曲をダウンロードしたかどうかのチェックはすべて、アプリのビュー部分で行われているとしましょう。その場合、aDecoratorパターンを使用できます。すぐに始められる人気のあるソリューションの1つは、Drapergemです。これを使用すると、次のようなデコレータを作成できます。

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

次に、decorateを呼び出します コントローラ内の例:

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

そして、次のようにビューで使用します:

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

依存関係を使用したくない場合は、デコレータをロールすることができますが、これについては別のブログ投稿で説明します。モデルの懸念事項の大部分が分離されたので、曲を見つけて変換する方法を見てみましょう。モジュールを使用してそれらを分離できます:

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

Songモデルは、SongFindersを拡張します モジュールなので、そのメソッドはクラスメソッドとして利用できます。 Songモデルには、SongConverterが含まれます。 モジュールなので、そのメソッドはモデルインスタンスで使用できます。

これらすべてにより、Songモデルはかなりスリムで適切なものになるはずです:

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

モデルのアンチパターンは他にもたくさんありますが、これはモデルで南に行くことができるものの一例にすぎません。このシリーズの別のブログ投稿に注目してください。ここでは、より多くのモデルのアンチパターンについて詳しく説明します。とりあえず、ビューで何がうまくいかないか見てみましょう。

問題の表示

モデルの問題に加えて、Railsの人々はビューの複雑さに苦労することがあります。当時、HTMLとCSSはWebアプリケーションのビュー部分の王様でした。ゆっくりと時間が経つにつれて、JavaScriptが支配するようになり、フロントエンドのほぼすべての側面がJavaScriptで記述されました。 Railsは、これに関して少し異なるパラダイムに従います。 JavaScriptをすべて表示するのではなく、JSをJavaScriptに「振りかける」だけです。

いずれにせよ、HTML、CSS、JS、Rubyを同じ場所で処理しなければならないのは面倒です。 Railsビューを構築する際に注意が必要なのは、ドメインロジックがビュー内にある場合があることです。まず、MVCパターンを壊すので、これはノーノーです。

別のケースは、ビューとパーシャルに埋め込まれたRubyを使いすぎている可能性があります。ロジックの一部は、ヘルパーまたはデコレーター(ビューモデルまたはプレゼンターとも呼ばれます)の内部にある可能性があります。シリーズの次の投稿のいくつかでその例を取り上げますので、ご期待ください。

コントローラーの問題

Railsコントローラーもさまざまな問題に悩まされる可能性があります。それらの1つは、FatControllerのアンチパターンです。

以前、私たちのモデルは太っていましたが、ある程度の重量が減りました。そして今、コントローラーがその過程でいくらかの余分な重量を追加したことに気づきました。通常、これはビジネスロジックがコントローラ内に配置されている場合に発生しますが、実際の場所はモデル内または他の場所にあります。大規模なモデルセクションで共有されているアイデアの一部は、引き続きコントローラーに適用できます。つまり、ActiveRecordコールバックを使用して、プレゼンターにコードを抽出し、toServiceオブジェクトを使用します。

一部の人々は、Trailblazerやdry-transactionのような宝石を使用することにさえ頼っています。ここでのアイデアは、特定のトランザクションを処理するクラスを作成することです。すべてをコントローラーから移動し、モデルをスキニーに保ちながら、ロジックをこれらの個別のクラス内に格納してテストします。これらのクラスは、サービス、トランザクション、アクションなどを呼び出します。

結論

より多くのアンチパターンとそれらに対するさらに多くのソリューションがあります。この投稿のすべてをカバーしようとすると、スペースと時間がかかりすぎて、投稿が太く見えます(先ほど説明したモデルやコントローラーのように)。 RailsのMVCパターンのあらゆる側面を深く掘り下げるシリーズを必ずフォローしてください。そこでは、最も有名なアンチパターンに対処する方法を見つけることができます。それまでは、パターンとアンチパターン、およびRubyonRailsフレームワークで最も一般的なものの概要をお楽しみいただけたでしょうか。

次の人まで、乾杯!

P.S。 Ruby Magicの投稿をマスコミから離れたらすぐに読みたい場合は、Ruby Magicニュースレターを購読して、投稿を1つも見逃さないでください。


  1. Rubyのニューラルネットワーク:それほど怖くない紹介

    この投稿では、ニューラルネットワークの基本と、Rubyを利用してそれらを実装する方法を学びます。人工知能とディープラーニングに興味があるが、開始方法がわからない場合は、この投稿が最適です。重要な概念を強調するために、簡単な例を見ていきます。 Rubyを使用して多層ニューラルネットワークを作成することはほとんどありませんが、単純さと読みやすさのために、何が起こっているのかを理解するための優れた方法です。まず、一歩下がって、どうやってここにたどり着いたかを見てみましょう。 映画ExMachniaの静止画。写真クレジット Ex Machinaは2014年に公開された映画です。Googleでタ

  2. Ruby on Railsとは何ですか?なぜそれが役立つのですか?

    Ruby on Rails(RoRの場合もある)は、最も人気のあるオープンソースのWebアプリケーションフレームワークです。 Rubyプログラミング言語で構築されています。 Railsを使用すると、単純なものから複雑なものまで、アプリケーションの構築に役立ちます。Railsで実行できることには制限がありません。 フレームワークとは何ですか? フレームワークは、ソフトウェアを作成するときに使用する特定の構造を提供するコード、ツール、およびユーティリティのコレクションです。 この構造により、コードがより整理されます。 正しく使うことを学ぶと、作業が簡単になります。 レールは正確に何を