製品の品質を落とさずに開発チームを拡大する方法
開発チームの規模を拡大中ですか?製品の品質を犠牲にすることなく成長する方法を学びましょう。このガイドでは、スケールする時期、チーム構成、採用、リーダーシップ、ツールなどの兆候に加え、The Codestがどのように...
多くの人がRailsフレームワークからRubyを学んでいますが、残念ながらこれはこの言語を学ぶ上で最悪の方法です。誤解しないでください:Railsは素晴らしく、多くの技術的な細部に触れることなく、Webアプリケーションを迅速かつ効率的に構築するのに役立ちます。
多くの人が学んでいる ルビー しかし残念ながら、これはこの言語を学ぶ上で最悪の方法です。誤解しないでほしい:Railsは素晴らしいもので、技術的な詳細に触れることなく、Webアプリケーションを迅速かつ効率的に構築するのに役立ちます。Railsは、物事を単純に動作させる「Railsマジック」をたくさん提供してくれます。初心者プログラマにとって、これは本当に素晴らしいことです。なぜなら、プロセスの中で最も楽しい瞬間は、「生きている!」と言えるとき、そしてすべてのパーツが組み合わさって、人々があなたのアプリを使うのを確認できるときだからです。私たちは「クリエイター」であることが好きです🙂 しかし、優秀なプログラマーと平均的なプログラマーを区別するものが1つあります。ツールを理解する」というのは、フレームワークが提供するすべてのメソッドやモジュールを知っているという意味ではなく、フレームワークがどのように動作するのか、「Railsマジック」がどのように起こるのかを理解するという意味です。そうして初めて、オブジェクトを使ってRailsでプログラミングすることに安心感を持てるようになります。オブジェクト指向プログラミングの基礎であり、複雑なRailsアプリケーションを簡単にする秘密兵器が、タイトルにもあるPORO(Plain Old Ruby Object)です。
その名の下にある本当のものとは?この偉大な秘密兵器は何なのか?それは、何も継承しないシンプルなRubyのクラスである。そう、ただそれだけなのだ。
クラス AwesomePoro
終了 あなたはアプリケーションを継続的に開発し、新しい機能を追加しています。そのような場所は、勇敢な開発者でさえ疫病のように避ける場所です。そのような場所が多ければ多いほど、アプリケーションを管理し開発するのは難しくなります。標準的な例は、新規ユーザーを登録するアクションで、このイベントに関連する他のアクションのグループ全体をトリガーします:
サンプル コード ユーザー登録の責任者は次のようになる:
class RegistrationController < ApplicationController
def create
user = User.new(registration_params)
if user.valid? && ip_valid?(registration_ip)
user.save
user.add_bonuses
user.synchronize_related_accounts
user.send_email
終了
終了
終了 よし、コード化できた、すべてうまくいった、でも......このコード、本当に全部でいいの?もっとうまく書けないだろうか?まず第一に、これはプログラミングの基本原則である単一責任を破っている。でもどうやって?そこで、すでに述べたPOROが役に立つ。RegistrationServiceクラスを分離すれば十分で、そのクラスはただ一つのこと、つまり関連するすべてのサービスに通知することだけに責任を持つ。サービスとは、上記ですでに取り上げた個々のアクションを指します。同じコントローラ内で必要なことは、RegistrationServiceオブジェクトを作成し、"fire!"メソッドを呼び出すことだけです。コードはより明快になり、コントローラの占有スペースも小さくなりました。また、新しく作成したクラスはそれぞれ1つのアクションを担当するだけなので、必要に応じて簡単に置き換えることができます。
クラス RegistrationService
def fire!(params)
user = User.new(パラメータ)
if user.valid? && ip_validator.valid?(registration_ip)
user.save!
after_registered_events(user)
終了
ユーザー
終了
private
def after_registered_events(user)
BonusesCreator.new.fire!(ユーザー)
AccountsSynchronizator.fire!(user)
EmailSender.fire!(user)
終了
def ip_validator
ip_validator ||= IpValidator.new
end
end
class RegistrationController < ApplicationController
def create
user = RegistrationService.new.fire!(registration_params)
end
エンド However Plain Old Ruby Object may prove useful not only for controllers. Imagine that the application you are creating uses a monthly billing system. The exact day of creating such a billing is not important to us, we only need to know that it concerns a specific month and year. Of course you can set the day for the first day of each month and store this information in the object of the “Date” class, but neither is it a true information, nor do you need it in your application. By using PORO you can create a class “MonthOfYear”, the objects of which will store the exact information you need. Moreover, when applying in it the module “Comparable”, it will be possible to iterate and to compare its objects, just like when you are using the Date class.
クラス MonthOfYear
include 比較可能
attr_reader :年, :月
def initialize(month, year)
raise ArgumentError unless month.between?(1, 12)
年, 月 = 年, 月
終了
def (other)
[年, 月] [その他.年, その他.月].
end
終了 Railsの世界では、各クラスがモデル、ビュー、コントローラであるという事実に慣れています。また、ディレクトリ構造内の正確な位置も決まっています。では、私たちの小さなPORO軍団はどこに置けばいいのでしょうか?いくつかの選択肢を考えてみましょう。最初に思いつくのは、作成されたクラスがモデルでもビューでもコントローラでもない場合、それらをすべて「/lib」ディレクトリに置くべきだということです。理論的には、それは良いアイデアですが、しかし、すべてのPOROファイルが1つのディレクトリにあり、アプリケーションが大きくなる場合、このディレクトリはすぐに、開くのが怖い暗い場所になるでしょう。従って、間違いなく良いアイデアではありません。
オーサムプロジェクト
アプリ
├── コントローラー
モデル
ビュー
│
└──lib
サービス
1TP63トールポロはこちら また、ActiveRecordモデルでないクラスに名前を付けて "app/models "ディレクトリに置き、他のクラスの処理を担当するクラスに名前を付けて "app/services "ディレクトリに置くこともできます。これはかなり良い解決策ですが、1つ欠点があります。新しいPOROを作成するときに、毎回、それがモデルなのかサービスなのかを決めなければなりません。新しいPOROを作成するときに、それがモデルなのかサービスなのかを毎回決めなければなりません。つまり、名前空間付きのクラスとモジュールを使う方法です。コントローラやモデルと同じ名前のディレクトリを作成し、その中にコントローラやモデルで使用するすべてのPOROファイルを置くだけです。
オーサムプロジェクト
アプリ
│ ├──controllers
│ ├─registration_controller
│ │ └─registration_service.rb
│ └─registration_controller.rb
モデル
│ ├──settlement
│ │ └──month_of_year.rb
│ │ └─settlement.rb
│ └──views
│
└─lib この配置のおかげで、これを使うときにクラス名の前に名前空間を付ける必要がなくなります。より短いコードと、より論理的に整理されたディレクトリ構造を得ることができます。
POROを使うと、アプリケーションの単体テストがより速く、より簡単に書けるようになり、後で他の人に理解されやすくなるというのは、嬉しい驚きです。各クラスが1つのことだけを担当するようになったので、境界条件をより早く認識でき、適切なテストシナリオを簡単に追加できます。
記述 MonthOfYear do
subject { MonthOfYear.new(11, 2015) }.
it { be_kind_of Comparable }とする。
describe "新しいインスタンスの作成" do
it "正しい年と月で初期化する" do
期待 { described_class.new(10, 2015) }.to_not raise_error
終了
it "指定された月が正しくない場合にエラーを発生させる" do
expect { described_class.new(0, 2015) }.to raise_error(ArgumentError)
expect { described_class.new(13, 2015) }.to raise_error(引数エラー)
終了
終了
end 我々が提示した例は、POROを使うことでアプリケーションの可読性が向上し、よりモジュール化され、その結果、管理や拡張が容易になることを明確に示している。単一責任の原則を採用することで、必要に応じて特定のクラスを交換することが容易になり、他の要素に干渉することなく交換することができます。また、テストをよりシンプルかつ迅速に行うことができます。さらに、Railsのモデルやコントローラを短くまとめるのはずっと簡単です。