AASM を使ってみた。主に Callback。

STATESMAN を使ってみたかったのだけど、使いたかったシーンが state を持ったテーブル1つだったので、ちょっと STATESMAN だと冗長だったので断念。

AASM

github.com

The Ruby Toolbox - State Machines

state machine カテゴリでは 2 位で、今でも開発は行われているようなので良さそうに見える。

日本語の解説記事も発見。

使ってみる

対象

ActiveRecord Enum を使って status というカラムを列挙型として使っているモデルがあるとします。

class Task < ActiveRecord::Base
  enum status: {opened: 0, assigned: 1, rejected: 2, finished: 3}
end

このステータスは、それぞれ遷移する順序があるという場合です。

state の設定

https://github.com/aasm/aasm#activerecord-enums

AASM は標準で ActiveRecord Enum を上手く扱えます。ポイントは column: enum名 と指定するところです。今回は enum が integer のカラムなので enum: true というオプションを省略できる。

class Task < ActiveRecord::Base
  include AASM

  enum status: {opened: 0, assigned: 1, rejected: 2, finished: 3}

  aasm column: :status do
    state :opened, initial: true
    state :assigned
    state :rejected
    state :finished
  end
end

event と transition の指定

class Task < ActiveRecord::Base
  include AASM

  enum status: {opened: 0, assigned: 1, rejected: 2, finished: 3}

  aasm column: :status do
    state :opened, initial: true
    state :assigned
    state :rejected
    state :finished

    event :assign do
      transitions from: :opened, to: :assigned
    end

    event :reject do
      transitions from: %i(opened assigned), to: :rejected
    end

    event :finish do
      transitions from: :assigned, to: :finished
    end
  end
end

ここは特に説明不要ですかね。

Callback を指定してみる

https://github.com/aasm/aasm#callbacks

以下の順序と関連を押さえておけばなんとなく大丈夫かと。

begin
  event           before
  event           guards
  transition      guards
  old_state       before_exit
  old_state       exit
  transition      after
  new_state       before_enter
  new_state       enter
  ...update state...
  event         success             # if persist successful
  old_state       after_exit
  new_state       after_enter
  event           after
rescue
  event           error
end

aasm/callbacks_spec.rb at master · aasm/aasm · GitHub

Callback のテストを見ると、順序、設定場所、渡ってくる引数がわかりやすい。

class Task < ActiveRecord::Base
  include AASM

  enum status: {opened: 0, assigned: 1, rejected: 2, finished: 3}

  aasm column: :status do
    state :opened, initial: true
    state :assigned
    state :rejected, after_enter: :after_enter_rejected
    state :finished, after_enter: :after_enter_finished

    event :assign do
      transitions from: :opened, to: :assigned do
        after do |user|
          self.user = user
          self.assigned_at = Time.zone.now
        end
      end
    end

    event :reject do
      transitions from: %i(opened assigned), to: :rejected
    end

    event :finish do
      transitions from: :assigned, to: :finished
    end
  end

  def after_enter_rejected
     # reject 時の処理
  end

  def after_enter_finished
    # finish 時の処理
  end
end

今回の特殊な点として、assign 時に一緒にアサインされたユーザーと、アサイン時刻を記録したかったので、transition に対する after callback を指定した。

transition after callback は名前は after だが、status の値の更新前に実行されるので、結果的に UPDATE 文が1つにできる。もちろん、status の更新が不可能な状態ならば実行されない。

task = Task.create
task.opened? # => true
task.assign!(current_user) 

task.assigned? # => true
task.user # => current_user 

# ダメな場合
task.update(status: 3, user_id: nil)
task.may_assign? # => false
task.assign!(current_user) # => AASM::InvalidTransition
task.user # => nil

Transaction 使えばもっとキレイにかけるのかなぁ。 https://github.com/aasm/aasm#transaction-support

結局もう一度 save するのか。

aasm/validator.rb at 44a17aa5357d60e20cbd1a5da4a27063e113ffa2 · aasm/aasm · GitHub

#

今回は Guards に関しては利用用途が無かったのだが、いろいろできそうなのでまた調べたい。

Auto Layout を設定する時に使いそうな Xcode の画面のメモ

慣れない IDE は、慣れるまでが大変ですね。。いろいろ高機能になっているせいか、6 年前に Eclipse から Visual Studio に移った時よりもしんどさを感じる。。

とりあえず使いそうな部分だけ

  • イシューナビゲータで問題があるか確認できる
  • Dock でエラーの詳細を確認できる
  • Canvas エリアの下でサイズクラスと制約に関する設定ができる
  • サイズインスペクター内で制約の閲覧と設定ができる

きっと他にもある。。

f:id:dany1468:20150705182340p:plain

Align, Pin, Resolve Auto Layout Issue

Auto Layout 関連はだいたいここから設定できる。Editor メニューからもできる。

f:id:dany1468:20150705182354p:plain

制約を直接編集

サイズインスペクターからでなくても編集できる

f:id:dany1468:20150705182350p:plain

Dock 内でエラーを確認

赤いボタンを押したら一気に解決してくれたりする

f:id:dany1468:20150705182359p:plain

サイズクラスを指定する場合に使う

まだ良くわかりません

f:id:dany1468:20150705182346p:plain

#

こういうのに疲れるとコードで指定するようになるんですかね。。

Ruby でもメソッドをブロックの代わりに渡したい

C# でコードを書いていると以下のようなコードを R# がよく薦めてきます。(久しぶりに C# 書いたけど、これで合ってるかな。。)

// 前提
var list = new[] {1, 2, 3, 4};

private int Method(int) {
  // なんか処理して int を返す
}

// before
list.Select(x => Method(x));

// after
list.Select(Method);

ここで使ってる SelectIEnumerableメソッドですが、引数は System.Func<TSource, TResult>delegate となっています。

after のようにできるのは、その delegateシグネチャが一致しているメソッドであれば同じように扱えるという仕様を利用しています。

Ruby の Symbol#to_proc

RubySymbol#to_proc があるので配列の各要素のメソッドを以下のように呼び出せます。

list = [1, 2, 3, 4]

list.map(&:to_s) # 単に数値を文字に変えるだけですが、int の to_s メソッドを呼び出している。
=> ["1", "2", "3", "4"]

これは Ruby を使い出してすごい便利と思った機能だったのですが、一方で C# のようにメソッドを渡せないのかなぁと思ってました。

def double(num)
  num * 2
end

list.map {|num| double(num) }

# これを list.map(double) ぐらいで書きたい

Method は to_proc できるらしい

Object#method で Method のオブジェクトにできるので

double_method = method(:double)
=> #<Method: Object#double>

double_method.to_proc
=> #<Proc:0x007fb79abcf0d0 (lambda)>

list.map(&double_method)
# or
list.map(&method(:double))

ちょっと冗長に見えるけど、少しだけ C# の書き方に近い感じになって嬉しい。でも method を呼び出すのは、ちょっと微妙っちゃ微妙ですよね。。

参考リンク

Web Designing vol.186 を読んだ

今年登壇させてもらったイベントがきっかけで一年間 Web Designing を送ってもらえる事になったのでちょっとした感想など。 Web デザインやってたころは毎月買ってたので懐かしい。

Web Designing 2015年 07月号

Web Designing 2015年 07月号

佐藤ねじさんと吉永龍樹さんの特集

個人にフォーカスした2つの記事がとても面白かった。

二足のわらじで仕事を分ける吉永さんの働き方や、本職のデザイナではない所で見出したクリエイティブでの戦い方は興味深かかったし、勉強になった。

佐藤ねじさんの記事では「面白い」と「真面目」の配合率や「funny」と「interesting」の配合率の話しが面白かった。 「仕事は楽しい方がいい」と口にする事があるのだけど、自分にとって「仕事で楽しい」とはどういう事なのか言語化できていなかったので、「配合率」というのは考え方として取り入れたいと思った。

作品も素敵なものが多くて、同じ 82 年生まれとして背筋が伸びる思いがした。

座談会:Web と IoT の「いま」と「これから」

IoT というワードや、Kickstarter みたいなサイトで面白いプロダクトがたくさん出ているのは見ていても、「今どういうものが作られているのか?」というのは見えていなかったのでありがたい特集でした。

Pepper くんがガリバーで接客してて、それが効率よくお客さんの意見を引き出すというのは、最近見たマツコとマツコの実験みたいで面白い。 一口に IoT といっても、単なる便利ガジェットから、Beacon 使って広告に活用したりビッグデータ人工知能をバックエンドに置いてインタラクティブなレコメンドに使ったり、それこそサメのアラート( Celever Buoy ) みたいに人命のためやヘルスケア用のものもあったりと多岐にわたっているんだなぁと改めて感じた。

個人的には排泄タイミングを教えてくれる DFree がとても気になったというか欲しいです。。

トップの特集は Web プロジェクトの立ち上げ方みたいなものだったんですが、WBS やら出てきて既視感がすごかったのでさらっと流し読みに。。そういう分野でもプロジェクトマネジメントの課題はあるんだなぁと。。

第九回 tokushima.rb に参加してきた

第九回tokushima.rb

先月は予定があって参加できなかったので、一ヶ月ぶりの参加となりました。

Twitterライクなサービスを実際に自分の手で作ってみよう

これまで私が参加した回はほぼもくもく会だったのですが、今回は初めてお題がある感じに。

講師役の ka さんが説明しつつ、みんながそれに沿ってコマンド打ったり、コード書いたり、コード書いたりしてました。

とは別に ka さんの Public contributions が半端無い。500 日以上連続だと。

あまり個別の工夫点まで作れませんでしたが、とりあえず私がいけたのはここまで。

github.com

Rails Tutorial と違い、mongoid を使って作るので、ActiveRecord とは微妙にできる事が違ったりして、簡単な部分もありつつ、ハマる部分もありでした。( has_many through ができないのは意外。)

公式にあたるの大事

(英語が多いけど)公式ドキュメントをちゃんと読むようにしようと、ka さんが何度か言われてました。

これまでも何度かいろんな人に言われた記憶があります。

感想

仕事でも Ruby/Rails を使っているはずなのですが、日々の仕事は既存のコードの修正がほとんど(というか全て)なので、なかなか rails new からすることはないんですよね。

Rails Tutorial をやったのも、少し遠い記憶になってしまって、こうやって何も無い所から機能を追加していくのは、また Rails の違った側面や魅力が見えて楽しいなぁと感じました。(というか、いろいろ調べながらじゃないと全然進められなかった。。)

次回は 「Gem を作ってみよう」だそうですので、また楽しみですね!

久しぶりに Rails でテストの環境作る

プライベートで作ってた Rails のアプリを久しぶりに改造しようと思ったら、テスト全く書いて無くて死にそうになった。。集中して開発してる時はいいけど、やっぱダメですね。

設定したもの

  • RSpec
  • FactoryGirl
  • spring
  • direnv

Gemfile

group :development do
  gem 'pry-byebug', group: 'test'
  gem 'spring'
  gem 'tapp-awesome_print', group: 'test'
end

group :test do
  gem 'database_rewinder'
  gem 'factory_girl_rails', group: 'development'
  gem 'fuubar', '~> 2.0.0.beta'
  gem 'rspec-rails'
  gem 'spring-commands-rspec'
end

prytapp も使いたいので追加

RSpec

$ rails generate rspec:install

spec_helper.rb, rails_helper.rb が生成される。

$ bundle binstubs rspec-core

bin/rspec を追加

DatabaseRewinder

spec/rails_helper.rb

  config.before :suite do
    DatabaseRewinder.clean_all
  end

  config.after :each do
    DatabaseRewinder.clean
  end

FactoryGirl

spec/rails_helper.rb

-# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
+Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

spec/support/factory_girl.rb

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods

  config.before :suite do
    begin
      DatabaseRewinder.start
      FactoryGirl.lint
    ensure
      DatabaseRewinder.clean
    end
  end
end

spring

$ bundle exec spring binstub --all

direnv

bin って打つのを省略します。

$ export EDITOR=vi
$ direnv edit .

エディタが開くので .envrc に以下を記述

export PATH=$PWD/bin:$PATH

とりあえずこれで書き始める事ができました。capybara 系はまた書くときに。

Agile Japan 2015 愛媛サテライトに参加して楽しかった

Agile Japan 2015 サテライト<愛媛>「自分につなげるアジャイル」

昨年は私の地元徳島で開催していただいたご縁もあり、今回は「いくぞ!」と意気込んでいた所に、パネルディスカッションのご依頼もいただき意気揚々と参加してきました。

仕事のプロジェクトのピーク週でもありその週ほとんど寝れてなかったのですが、居眠りすることなく懇親会二次会までとても楽しい時間を過ごさせていただきました。

運営の皆様、一緒にお話いただいた皆様、本当にありがとうございました!!!!!!

以下、感想やら。

午前の部(東京の中継)

徳島からの移動中だったので中継は見れなかったのですが、実践アジャイルテストの方だと聞いていたので、超楽しみにしていたのですが、結果内容は分散リモートの話だったということで、もっと聞きたかったという残念な結果に。。。

ただ、「全てを共有する」「気遣いがすべて」というキーワードを教えてもらい、なんかそれだけで結構ぐっときた。

平鍋さんがスライドを共有してくださっていて感謝です。

agilejapan-2015 - An Agile Way

午後(サテライトオンリー)

アジャイルに取り組んでみえた気づきと課題」

株式会社エイチビーソフトスタジオ の 影浦 義丈さん のお話。

社長さんだったり、JAWS-UG愛媛 の支部長だったりと、いつもいつ休んでるんだろうと思っていたのですが、会社の詳しいお話を聞くのは初めてでした。

月額定額の受託開発 を実践されているお話がメインだったのですが、そういう新しい契約形態のチャレンジは失敗例の方が多く耳にしていたので、四国でそういう先端的な事例を聞けるとは正直なところ思っていませんでした。

定額にすることによるメリット

月額ながら、一週間のタイムボックスで成果物をお客さんに見せるというサイクルにしているようです。

月額定額なので、自然と月にできる作業量は決まってくるため、当然一週間での作業量もある程度顧客と共有できます。(と書きつつ、ここはすごく苦労されたそうなので後述します。)

よって、要望や不具合修正も全て、「タスクの優先順位の変更」という形で調整する事ができるため自然と無茶な要望が出にくくなったそうです。 開発側としてもできる作業量が決まっている以上は「それは本当に必要ですか?」と顧客にとって不要なものを作らなくていいように提言することもできたとか。

作業量の認識合わせ

上述した苦労点についてですが、契約開始当初は顧客も開発側も手探り状態だったため、明らかに金額よりも仕事をし過ぎてしまったそうです。

当然ながらそのペースは持続しないので、顧客からしてみれば進捗が落ちているように映ってしまい、そこは正直なところで話し合い、半年程かけて金額に見合うペースにもっていけたそうです。

仕事のやり方にもよりますが、最初に進捗だそうとがんばってしまうのはすごく分かるので、結構難しいなぁと。ちゃんと見積もる事が大事なのだなと。

仕様書はいらない

バッドノウハウぽく聞こえそうですが、そこは開発側も顧客側も担当者をこれまで一度も変えずにやってこれたことで、コンテキストの共有が高いレベルでできているので新機能追加は細かい仕様書を作る必要が無かったようです。 また、開発が終了した機能に関してはきちんと仕様書を残されているとか。

来るべき引き継ぎに備える意味でも、なんだかんだ必要ですよね。

変化すること

月額定額にしろ、作る前に仕様書を作らない事にせよ、 なぜ必要か? をまず考える事を怠らないそうです。 少数精鋭で、かつ時短勤務の女性も数人居るチームであるため、いかにそのメンバーで最大のバリューを出すかを考える、すごく大事なことだなと思います。

とりあえず人数増やし続ければ開発速度は上がるというのは、まあ無いですよね。。 制約があるから、ツールにせよ、やり方にせよ工夫が生まれるというのは素敵だなぁと思いました。

とりあえずやってみる

やってみないと分からない事が多いので、動き出せないよりは、まずやってみて失敗してみようという事を仰っていました。 本だけ読んでも分かんない事多いよねと。

よくあるこういうケースでダメなのは、「やりっ放し」だそうですが、そこは「タイムボックスを決める」「必ず振り返る」という事を決めているそうです。

会社レベルでやり始めた事を振り返るって経営サイドの体裁もあるしフラットに振り返るのはすごく大変だと思うので、どんな雰囲気でやってるのかすごく気になる。

見える化する

社内社外両方にとって、 目に見える のはすごく大事だそうです。 ただ、習慣化するには時間がかかると。

ただ適当にログを残すと、共有するってまた違いますものね。

Pivotal Tracker や Chatwork、 Cybozu Live 等を使い分けているそうですが、タスクについてはお客さんも出来る限り一緒にツールを使ってもらって、一緒にみてもらうようにしているようです。

ツールを使うのは、勤務体制が多岐にわたって来ている中で、社内に居る時間を短くするためには、壁の付箋では限界が来たからだそうです。 お母さんエンジニアが居る会社ならではだなーと感心します。

管理しない

なんと影浦さんは、こうやって月額定額の話しをしつつも、実際にその業務の事は最低限の事しか把握していないそうです。

見るべきものは見えるようにしておいてもらうが、あえて報告させたりはしないと。なんというか、すごく高度な情報共有が実現できているなぁと思います。

正直、私の現場ではツールも意識もバラバラで結局「報告してください」が氾濫している気がします。 これって、上司や部下の怠慢ではなく、単に情報共有の仕組みを作ったつもりになってるだけなんですよね。

見えてきた課題

情報共有や管理不要の組織体制ができたことで、「自己組織化」や「自分たちでプロジェクトをドライブする意識」ができてきたそうですが、一方で属人化も進んでしまい、「チームとして」の動きが取りづらくなってきた側面もあるそうです。

「変化への対応を」

ツールやプロセスに縛られず、常に変化に対応できるように、というメッセージをいただきました。

私が感じたのは、

  • 正しく、恐れず今の悪い状態を直視し
  • それに対して現状の延長線上では無い解決策を模索し
  • それをまずやってみて
  • 正面から結果を振り返り
  • 改善をし続けてきた

という事なのかなと。どれを取っても難しい事だと思います。特に決して余裕がある訳ではない状況で上記を実行するのは、覚悟と危機感があってこそなのだなと。

今こう書いていても、胸にぐさぐさ刺さります。。

なんか結果だいぶ自分の解釈がメモに入ってしまっていた気がする。。言ってない事書いてしまってたらごめんなさい。。

アジャイルなリモートワークをどう実現するか - リモートワーク実践者と推進者の座談会 -」

◆話し手
岩井 克之さん 合同会社ネクストコード
團 洋一さん  Sansan株式会社
早瀬 潤也さん フリーランス
◆聞き手
懸田 剛さん  合同会社カルチャーワークス

私もパネラーの一人でお話させていただきました。

なんか自分も話してたのであまりメモが残ってないのですが、覚えていることを。

早瀬さんのお話

受ける仕事の依頼元どこの地方かでの単価の話しはリアルでした。地方に仕事が無いどうこうもあるけど、仮に選択できてもそれだけ単価が違うとどうしても首都圏の仕事を受けてしまうかもなぁと。

在宅勤務でのリモートワークのお話は、自分の体験とも被る部分があって、なんというか自分だけじゃないんだと安心しました。

ただ、「チーム」という形態はやはり異なるので、そこにはメリット・デメリットあるなぁと思いました。 ただ、組織に所属するか否かは、個人の適正や気分にも依る部分があるので、一概にどっちがいいとかは無いのかなぁとは個人的には思います。

岩井さんのお話

岩井さんは過去の4拠点開発でのお話だったのですが、かなりエクストリームで、全員日本にいるのに活動時間がまるで違ったり、結局最後まで顔をみることなく終わったり、それでもとても上手くいったりと。

成功した要因は、

  • 参加メンバー全員がデキル人だった(リモート慣れもしてる)
  • Agile に進めていけたので、後半での手戻りや仕様変更がほぼ無かった

みたいな感じだったらしいです。なんか夢のリモートチームーって感じです。

ただ、現在は自社の社員は全員同じオフィスに集めているそうです。 受託開発もやりつつ、自分たちでのアイデアベースの開発も積極的に進めているため、創発的な活動はやりやすいと。 他には、メンバー間でのツール等の共有等が、ディスプレイを覗くだけでできるので、技術力の向上等にも役立っているとか。

確かに、教育とかそういう面も考えると、リモートはまだまだ課題がありますよね。自分も教えられる側でしたが、似た経験があります。

ただ、岩井さんの会社自体は勤務体制もかなり自由で、リモートでなくとも、勤務時間も自由なので、遠隔でもなければそもそもリモートワークを許可する制度自体必要が無いという、またまたエクストリームな面があるようです。

Basecamp の例なんかみても、まあわざわざ制度っていうよりは、そういう社風なら自然にそうなるって感じなんですかね。

雑談

懸田さんから、 雑談 に関する問いが投げかけられました。

この点に関しては、私個人としては「組織的な解決」と「個人的な解決」の2つがあると思っていて、私は前者には限界があるので後者が大事かなと思っていました。後者は、まあローカルコミュニティ等を大事にしようって事ですが。

ただ、ソニックガーデンさん Remotty の例等を見ても、前者に対する機運も高まっているのかなというのも感じます。 この辺はリモートワーカーがマイノリティではない会社になると、そういう意識が高まるのかなぁという、現状感想です。

「もっと身近にスクラムを!」

上田 和亨さんがファシリテーターとなって、紙飛行機ワークショップをおこないました。

わかったこと

「品質を作りこまなくては、生産性を上げたところで、成果は上がらない!!!!!!」

きっとエンジニアの方なら、紙飛行機で難しいことが、ソフトウェアで簡単になるはずは無いということがわかっていただけると思います。

正直、紙飛行機作りで、ペアワーク、品質保証の話しまで飛躍するとは思いませんでしたが、すごくいいワークショップだなぁと思いました。「品質は絶対落としていけないんですよ」ということがここまで体感して理解できるとは。

懇親会とか

ここ最近の疲れが吹っ飛ぶ、とても楽しい飲み会でした!!東京とも神山ともまた違う、すごいエネルギーがある場所だなと改めて感じました。

岩井さんのお誘いで翌日はネクストコードさんのオフィスで半日仕事させて貰ったりお話させてもらったりで、充実した松山遠征となりました。

ネット上でしか知らなかった人にも会えたりして、いろいろと出会いも多くありがたかったです。

まとめ

東京会場は有料にも関わらずすごい人数が集まったり、島根も 50 人ぐらい集まったとか聞きましたが、愛媛サテライトは規模こそコンパクトでしたが、内容のめちゃ濃い会場だったと思います!

関連

いくつかレポートが出ておりました。