UMLでRailsモデリング


Railsエンジニアな皆さん、モデリングしてますか?

ひとりでシステム構築しているなら不要かもしれませんが、チームで活動し、ある程度の規模のシステムを構築/改修する場合は、いきなり実装するのではなくモデリングをしましょう!

モデリングの手段はたくさんありますが、統一記法であるUMLに従うといろいろ下記のようなメリットを享受できてよいかと思います。

* 視覚的な表現によって構造・振る舞いを直感的に把握できる
* 開発に関わるメンバ全員が共通の言語でコミュニケーションできる

本記事ではRailsシステムをUMLでモデリングする際の表現方法を紹介します。想定する読者は、上位者の指示の下Railsシステムの構築/改修をすることができ、今後ステップアップとして実装設計とか構造設計と呼ばれるフェーズを独力で実施できることを望むような人(およびその上位者)です。これによって少しでも多くの人が実装設計できるようになることを願います。

なお、モデリングツールとしては「astah* community」がオススメです。無償で使えて基本的なモデリング作業はほとんどできてしまう。しかも商用利用OK! (ただし、ver. 7.0からは商用利用できなくなってしまいました...)
モデリングツールをまだインストールしていない人はぜひ入れておきましょう。

[astah* community - 無償UMLモデリングツール | Astah](http://astah.change-vision.com/ja/product/astah-community.html)


## サンプルシステム

本記事で例示するシステムは下記のユースケースを想定したものとします。

![ユースケース.png](https://qiita-image-store.s3.amazonaws.com/0/65069/3a5b890e-eb80-d263-57b3-c58f8f6f47f5.png "ユースケース.png")


## 構造設計

### モデルの表現

RailsのモデルはO/Rマッピングなので、クラス図と特に相性がよいです。
コードと1対1で完全に一致するような正確性よりも、関係者間で共通の認識を持てることが重要です。そのため部分的に表現を省略することで、読み手に注目してもらいたい箇所が際立つようにします。機能改修テーマであれば、変更のある属性やメソッドだけを記載するといった工夫をすると良いと思います。

#### 属性の表現

クラス図ではクラスの属性とメソッドを表現できます。これを使ってモデルを表現します。

![ユーザー.png](https://qiita-image-store.s3.amazonaws.com/0/65069/890f1542-9348-0074-fc01-e9f91f3c24bf.png "ユーザー.png")


`id`や`created_at`、`updated_at`といった属性は大抵のモデルには存在しますが、煩雑になりますのでいちいち記述しないようにします。また、ActiveRecordの機能で属性に対するセッター/ゲッターは自動的に作成されますが、これも煩雑になりますので記述しないようにします。(属性をpublicにすることで表現してもいいのですが、毎度可視性を変更するのは面倒臭いのでやらないほうがいいでしょう。)

マイグレーションファイルにすると以下のようになります。

```ruby
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string   :login
      t.string   :email
      t.string   :hashed_password
      t.string   :password_salt
      t.datetime :activated_at
      t.boolean  :enabled, null: false, default: true
      t.timestamps
    end
  end
end
```

なお、`Datetime`型や`Text`型などRubyやRailsでは標準で存在するけどモデリングツールにはデフォルトで存在しないようなクラスは、`ruby`パッケージを作成してそこに突っ込んでおくとよいです。

![データ型.png](https://qiita-image-store.s3.amazonaws.com/0/65069/0b920452-fa13-6b1a-c58c-f2fadc0dfa05.png "データ型.png")


#### スコープの表現

モデルのスコープは静的メソッドにステレオタイプを付けて表現します。

![スコープ.png](https://qiita-image-store.s3.amazonaws.com/0/65069/76f12cbc-568e-ee56-119c-7c226e22d3a2.png "スコープ.png")

上図のようにクラス図では、静的メソッドは下線付き、ステレオタイプは`<< >>`で表現します。

#### STIの表現

STI(Single Table Inheritance: 単一テーブル継承)はクラスの継承線にステレオタイプを付けて表現します。

![STI.png](https://qiita-image-store.s3.amazonaws.com/0/65069/143acee5-5d78-84ad-acbd-b360950f9329.png "STI.png")

`type`カラムに具象クラス名を入れておくことで、インスタンスを取り出した時にActiveRecordが自動的にそのクラスのインスタンスに変換してくれます。

もうちょっと細かいSTIの話は下記のサイトを参照ください。
[【Rails】ActiveRecord：単一テーブル継承(sti)とポリモーフィック関連を未だにぱっと思い出せないのでまとめ。 - 記すに足らず。](http://shirusu-ni-tarazu.hatenablog.jp/entry/2012/11/04/173742)


継承線に`<<STI>>`というステレオタイプを付けることで表していますので、`type`カラムはクラス中に記載しなくてもよいのですが、「typeカラムに具象クラス名が入っているのでここはこのインスタンスになるんです〜」というSTIの説明を何度もすることがあるため、私はいつも記載するようにしています。関係者がSTIをしっかり理解してくれているなら`type`カラムは省略してもよいのではないでしょうか。

```ruby
class CreateImages < ActiveRecord::Migration
  def change
    create_table :images do |t|
      t.string   :type
      t.integer  :width
      t.integer  :height
      t.binary   :data
      t.timestamps
    end
  end
end

class Image < ActiveRecord::Base
end

class Avator < Image
end

class Photo < Image
end
```

#### has_one関連の表現

has_one関連はクラス間の集約を用いて表現します。白抜きひし形が付いている方が所有する側、線の繋がる先が所有される側になります。

![has_one.png](https://qiita-image-store.s3.amazonaws.com/0/65069/d904dab5-fd36-4765-46d9-ef9ff7a53c7e.png "has_one.png")


上記の例の場合、所有される側の`UserAttribute`に`user_id`カラムが必要ですが、関連線があることで自ずと必要なことがわかりますので記載を省略します。

```ruby
class CreateUserAttributes < ActiveRecord::Migration
  def change
    create_table :user_attributes do |t|
      t.integer  :user_id
      t.string   :title
      t.string   :zip_code
      t.string   :address
      t.string   :phone_number
      t.string   :url
      t.timestamps
    end
  end
end

class User < ActiveRecord::Base
  has_one :user_attribute
end

class UserAttribute < ActiveRecord::Base
  belongs_to :user
end
```

#### has_many関連の表現

has_many関連はクラス間の集約に多重度を付けて表現します。

![has_many.png](https://qiita-image-store.s3.amazonaws.com/0/65069/d39f7a5c-88c6-7088-8dfd-ebbf57734b9e.png "has_many.png")

has_one関連のときと同様に`Article`側の`user_id`カラムは省略します。

```ruby
class CreateArticles < ActiveRecord::Migration
  def change
    create_table :articles do |t|
      t.integer  :user_id
      t.string   :title
      t.text     :content
      t.timestamps
    end
  end
end

class User < ActiveRecord::Base
  has_many :articles
end

class Article < ActiveRecord::Base
  belongs_to :user
end
```

#### polymorphic関連の表現

polymorphic関連は、集約線にロール名をつけることで表現します。

![polymorphic.png](https://qiita-image-store.s3.amazonaws.com/0/65069/fd4d352e-cd5f-764b-dd3e-a3c49292e9c2.png "polymorphic.png")

上記の例ではSTIと組み合わせてあるのでちょっと複雑になっていますが、Imageモデルの所有者に`owner`というロール名を付けています。Imageモデルには`owner_type`と`owner_id`カラムを記載していますが、polymorphic関連であることを関係者が認識してくれるなら記載を省略してもよいでしょう。

polymorphic関連についてもうちょっと細かい話は下記のサイトを参照ください。
[【Rails】ActiveRecord：単一テーブル継承(sti)とポリモーフィック関連を未だにぱっと思い出せないのでまとめ。 - 記すに足らず。](http://shirusu-ni-tarazu.hatenablog.jp/entry/2012/11/04/173742)


```ruby
class AddOwnerToImages < ActiveRecord::Migration
  def change
    add_column :images, :owner_type, :string
    add_column :images, :owner_id,   :integer
  end
end

class User < ActiveRecord::Base
  has_one :avator, as: :owner
end

class Article < ActiveRecord::Base
  has_many :photos, as: :owner
end

class Image < ActiveRecord::Base
  belongs_to :owner, polymorphic: true
end
```

#### ネームスペースの表現

ネームスペースはパッケージを使用して表現します。

![namespace.png](https://qiita-image-store.s3.amazonaws.com/0/65069/4ef8b28f-507a-ad19-c994-421e6ec47374.png "namespace.png")

```ruby
class Image::Avator < Image
end

class Image::Photo < Image
end
```

#### Mix-inの表現

モジュールのMix-inは依存関係を用いて表現します。

![mix-in.png](https://qiita-image-store.s3.amazonaws.com/0/65069/74dcc88a-1d3c-4644-3e1c-6291ac5132cb.png "mix-in.png")

Mix-inされるモジュールにはモジュールであることを示すためにステレオタイプで`<<module>>`を記載します。そしてMix-inする側からされる側へ、`<<include>>`ステレオタイプ付きの依存関係を引いて表現します。

```ruby
class User < ActiveRecord::Base
  include User::Exportable
end

module User::Exportable
  extend ActiveSupport::Concern
  
  module ClassMethods
    def export
      ...
    end
  end
  
  def to_csv
      ...
  end
end

```


### コントローラの表現

コントローラの構造をクラス図で表現することはできますが、コントローラに複雑な構造を持たせることもあまりないでしょうから、わざわざ図に起こすまでもないかも。ここでは、もし可視化したい要求があった場合の書き方を示します。

#### アクションの表現

アクションはシンプルにクラスのpubicメソッドとして表現します。

![コントローラ.png](https://qiita-image-store.s3.amazonaws.com/0/65069/9a9d366f-6f8d-c6e4-9d7c-bff2244af9b4.png "コントローラ.png")

strong parameter用のメソッドなどのアクションから呼ばれるメソッドたちは可視性をprivate(もしくはprotected)にしたメソッドで表現します。

#### フィルターの表現

コントローラのフィルター機能はステレオタイプ付きprivateメソッドで表現します。

![filter.png](https://qiita-image-store.s3.amazonaws.com/0/65069/feec02f0-a91a-aeba-1020-ad4e16ce6377.png "filter.png")


### 完成図

以上を踏まえて作成したクラス図が下記になります。

![全体.png](https://qiita-image-store.s3.amazonaws.com/0/65069/e692640c-f2d8-423a-59bf-9b4218c860c6.png "全体.png")

(...うーん、配置にセンスがないなぁ。)

## 振る舞い設計

システムの振る舞いはシーケンス図などを利用して表現します。

### アクションの表現

![記事投稿.png](https://qiita-image-store.s3.amazonaws.com/0/65069/76bdba79-8999-f221-a41f-1abd398fcee7.png "記事投稿.png")

DelayedJobやsidekiqなどを用いた非同期処理を含む場合も上図のようにシーケンス図内に記載することができます。

## まとめ

本記事ではRailsシステムをUMLでモデリングする際の表現方法を紹介しました。特に(Rails的な意味の)モデルの構造やモデル間の関係を表現する際に役立つのではないでしょうか。

ソースコードで語り合う前に(UML的な意味の)モデルを使ってチームメンバ間で会話してみましょう。より早く問題点を見つけられるかもしれませんし、その後のコーディングがより速くなると思います。
お試しあれ。