Born Too Late

Yuya's old tech blog.

DSL で音声教材をハックするツール AudioHacker を作った

2014-02-03 01:30:57

はじめに

この記事は試験前日に部屋の模様替えをやりきったときみたいな気持ちで書かれています。

TL; DR

英語教材をハックしたい。

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

例えば英語教材の CD のトラックの切り分けが気に入らなくて、何人かで協力して切り分ける作業をしたいとき、音源自体を Web 上にアップするのは著作権法上問題になるので、そこを回避しつつコラボレーションするためのソリューションが必要。

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

全員が同じ音源を持っていて、Web 上では音源上のどこからどこまでをカットするのか、という情報だけ共有するようにして、それを元にそれぞれの PC 上で音源のカットまでできれば、目的が達成できる。

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

特定の CD からの音源の切り取り方を指定するフォーマット無いのかな。それさえあればあとは GitHub でなんとかなる。

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

Ruby で CD の取り込みができればいいのかな。エンコード済みの音源を入力とする場合、ファイル名フォーマットのズレを吸収するのがめんどい。

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

CD を読み込むプログラムを書く方法ちょっと調べてもわからなそうだったしエンコード済みの音源を入力にする方が楽かな。ファイル名でソートした順にトラック番号割り当てるルールで大体問題なさそう。

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

英語学習ほっぽりだした ffmpeg インストール始めた

— Yuya Takeyama (@yuya_takeyama) 2014, 2月 2

背景: TOEIC に初挑戦します

会社の同僚に誘われて、TOEIC 受けることにしました。
今回が初挑戦で、2014 年 3 月 16 日に行われる第 188 回を受験します。

どう勉強したもんかと思ったんですが、その同僚がこんな教材を薦めてくれました。

DUO 3.0 というのは英語の例文が 560 文掲載されていて、それをもとに重要な単語や熟語を覚えられるよ、みたいなヤツです。
語彙力が圧倒的に足りない私にとっては素晴らしい教材に思われます。
TOEIC 用に作られたものではありませんが、TOEIC 用としても十分実用的で、軽くググった限りではなかなか有名な教材のようです。

個人的には単語とか熟語だけを丸暗記するのは辛くて、むしろひとかたまりの例文の方が忘れにくいし応用もしやすい、と思ってます。
まぁ、大昔に読んだ「超」勉強法の受け売りなんですが。

そして、その DUO 3.0 の例文と訳文、さらにその中の単語・熟語の音読が聞けるのが DUO 3.0 / CD 基礎用です。

さっそく CD をリッピングして iPhone に入れてみたんですが、どうもトラック分けがイマイチ。
私としては 1 トラック 1 文に分かれていてほしいんですが、実際は 1 トラックに対して 2 文入ってたりします。
そしてそれらは前述の通り、英文、日本文、単語や熟語がごちゃ混ぜになってます。

これでは私がやりたい勉強法に使えません。

ぼくがかんがえたさいきょうの英文暗記法

早い話が i暗記 + 音声ですね。
そういったプログラムについても今のところ私自身で実装することになってるんですが、いいのがあれば教えてください。

まずは音声データを用意

オリジナルデータとしてはもちろん DUO 3.0 / CD 基礎用を使うとして、それをいい感じに切り分ける必要があります。
しかし 560 もの例文となるとあまりの量に目眩がしてしまいます。
それを、インターネット上のみんなと協同作業することで解決しよう、というのは自然な発想です。

ですが、独自に切り取った音声ファイルを勝手にアップロードしたりすると、当然著作権法上問題となります。
そこで、CD は各自購入した上で用意して、その「切り取り方」だけを共有できればいいんじゃないか、と考えました。
「切り取り方」は Ruby の言語内 DSL としてコード化し、GitHub のリポジトリ上で共有できれば、プルリクエストによるコラボレーションも可能となります。

音声教材ハックツール、AudioHacker のご紹介

そこで作られたのがこの AudioHacker です。
AudioHacker は以下のような機能・特徴を持っています。

単純に範囲指定で音声を切り出すだけなので、グリッチとかのアート的なヤツには使えません。

「切り取り方」を定義する DSL は以下のようなフォーマットです。

directory というのは、後に示す設定ファイル中の 1 番目のディレクトリから読み込むよ、という宣言です。
そして file はそのディレクトリ内で 1 番目のファイルを読み込むよ、という宣言。
なお、ここでいう「1 番目のファイル」というのは、ディレクトリ内のファイルを昇順でソートした順番を元にしています。
start は開始位置、duration は長さをそれぞれ秒で指定しています。
少数を使うこともできますし、文字列で 00:00:15.20 みたいなフォーマットで指定することもできます。
要は FFmpeg の -ss オプションや -t オプションに指定できるフォーマットが使えます。

そして設定ファイルは以下の通りです。
こちらは、利用者それぞれの環境によってディレクリ名もファイルフォーマットも異なるので、リポジトリ上では共有しないものです。

pattern というのは入力ファイルのファイルパターンを Ruby の Dir.glob で使えるフォーマットで指定します。
input_dir は入力ディレクトリのパスを指定します。
DUO 3.0 / CD 基礎用は 5 枚組なので、5 ディレクトリ指定しています。
なお、内部で利用している streamio-ffmpeg の制限上、ディレクトリ名もファイル名も ASCII にしておくのが無難です。
切り取られたファイルは output_dir で指定したディレクトリに書き出されます。

AudioHacker で DUO 3.0 / CD 基礎用を英文だけに切り取ろう

早速 DUO 3.0 / CD 基礎用を英文だけに切り取るための定義ファイルを用意しました。

DUO 3.0 / CD 基礎用 English Sentences for AudioHacker

...ただし、ひとりでは大変なのでまだ 10 文だけしか定義できてません。
Patches welcome ということで。

以下の手順で DUO 3.0 / CD 基礎用の切り取りが実行できます。

  1. DUO 3.0 / CD基礎用を用意する
  2. 適当なソフトで音声ファイルにリッピング (このとき、1 Disc 1 ディレクトリ、1 トラック 1 ファイルとし、ファイル名はソートできるよう先頭をトラック番号とすること)
  3. 以下の手順で AudioHacker を実行 (FFmpeg と Ruby 1.9 以上と Bundler 1.5 以上が必要)

FFmpeg は Mac を使っている人は brew install ffmpeg とかすれば入ると思います (各位頑張って入れてください)。

上手く行くと、以下のように出力されます。

[caption id="attachment_2426" align="aligncenter" width="480" caption="AudioHacker を実行した様子"]AudioHacker を実行した様子[/caption]

設定ファイルに output_dir として設定したディレクトリにはファイルが出力されます。

[caption id="attachment_2433" align="aligncenter" width="480" caption="AudioHacker が出力したファイル"]AudioHacker が出力したファイル[/caption]

終わりに

音声教材をハックしてコード化して共有するためのツール AudioHacker の紹介でした。

とりあえず Proof of Concept レベルの実装ではありますが、「GitHub 上でコラボレーションして音声教材をハックする」というアイディアは我ながらなかなか面白いんじゃないかと思ってます。
まぁ現状 Git や GitHub を当たり前に使えるエンジニアでないと使えないツールなので、このままでの普及は難しいとは思いますが...

さて、あとは自動出題用のプログラムを用意する必要がありますが、どう考えても TOEIC 受験時までに回収できない投資となりますし、とりあえずは本を読みながらアナログに勉強する予定だったりします。
続きはまたいつか。

文書校正支援 Web アプリ Torutsume を作った

2014-01-06 00:39:59

[caption id="attachment_2368" align="alignnone" width="300" caption="Torusume で赤入れっぽいことしてる様子"]Torutsume デモ[/caption]

いわゆるウェブ系で働いていると、外向きに、それなりにしっかりした文書を書くことが日々あると思います。
メルマガだったり、プレスリリースだったり。
そういうのを社内で周囲の人間がレビューしてなおしたりとかあると思うんですが、あるときはメールやチャットでここはこうした方がよくない? とか言ったり、またあるときは紙に印刷して赤入れしたり。
まぁそういうのダルいと思う訳です。

そこであるとき、こういうの GitHub の Pull Request を使ったコードレビューみたいな感じにできると楽しいんじゃないか、って思ったのを、この正月休みを利用して作ってみました。

Torutsume: Git-based proofreading tool on the Web

ウェブサービスとしての公開ではなくて、あくまでデモサイトなので、ある日突然消えるかもしれません。
企業等、特定の組織内でプライベートな環境での使用を想定しているので、イントラとかに各自インストールして使う感じになってます。
ウェブサービスになってるとそれはそれで面白いと思うんですが、そうなるとプライベート投稿機能とか、組織を管理する機能とか必要になってくると思うのですが、そこまで作り込むモチベーションは今のところ無いのでした。

Torutsume の機能・特徴

とりあえず最小限の機能となってます。
コミットログで修正履歴とかも追えるといいと思いますが、とりあえず後回し。
あとは一度見えなくなったコメントを表示する手段もないので、その辺もなんとかしたいところです。

技術的な話

言語・フレームワーク・ライブラリ

Ruby 2.0.0 で Rails4 を使って実装しています。

ライブラリとしては FriendlyId とか Devise とか Omniauth とか Figaro とか。

この辺は去年作った Web アプリでも使ったんですが、ほとんど似たような実装を行ったので、ボイラープレートみたいなのを用意しておくと、便利何じゃないかと思っています。

CSS フレームワークには Twitter Bootstrap 3 を使っています。
Bootstrap は大変便利ですが、Rails に組み込むためのライブラリはいろいろあり過ぎてどれ使っていいのかわからないですね。
今回は bootstrap-sass-rails というのを使っています。
Devise や scaffold で生成されたフォームに Bootstrap を適用していくのに、地味に時間かかってます。

あとは開発用のものとしては rspec-rails とか guard-rspec とか pry-rails とか better_errors とか factory_girl_rails とか database_rewinder とか。
guard-rspec はいつのまにか spring に対応してたので、サクサク動いてよかったです。
CI では Travis CI と Coveralls 使ってます。

Git の操作

Git の操作には Rugged という libgit2 の Ruby バインディングを利用しています。
ライブラリを使うといっても、Git の操作を行うには Git の仕組み自体をそれなりに知っている必要があるので、作っていく段階でいろいろ勉強になってよかったです。
ディレクトリはツリーオブジェクトで、そこにファイルとしての blgb オブジェクトやサブディレクトリとして別のツリーオブジェクトがひもづいていて... とか。

リポジトリについては、プロジェクトディレクトリ内の repo ディレクトリ内にポコポコできます。
リモートの Git サーバを参照できるようにした方がいいとは思うものの、イントラでちょこっと使いたい程度なのでとりあえず手抜き。
時間あれば Gitlab あたりの実装を参考にしようと思います。

DI コンテナ

そして、各種ライブラリの利用には、先日リリースした dee-rails を使っています。
Git の複雑な操作を抽象化すべく、細かく階層化してモジュール (アプリケーションサービス) 化しているため、オブジェクトの生成はそれなりに複雑になっていたんですが、DI コンテナを通して利用する限りにおいては、そういった複雑性を忘れられました。
モジュールの実装は、とりあえず動けばいいやの適当なものになっていますが、テストもそれなりに書いてるので追々直していければという感じです。

作ってみて、やはり Ruby/Rails でも DI コンテナは便利だという印象です。
これが最良の方法かどうかはわかりませんが、まぁ悪くない感じにはなってます。
今までだと ApplicationController に以下のようなメソッドをいくつも実装していたのを、サービスプロバイダとして整理することができるようになっています。

# 今まで Rails でやっていた、サービス的なクラスの生成
class ApplicationController < ActionController::Base
  def some_benri_service
    @some_benri_service ||= SomeBenriService.new
  end
end

デモサイトのデプロイ

デモサイトはフロントに Nginx、App サーバに Unicorn という構成で、EC2 の micro インスタンス 1 台に載せてます。
DB は RDS で MySQL です。
プロビジョニング・デプロイには Chef Solo を使ってます。
相変わらず伊藤直也さんの本にお世話になりました。

Chef 便利ですが、新しい環境を構築するとなると、僕にとってはまだまだ一日仕事になってしまいます。
経験値の問題が大きいとは思いますが。
特定のバージョンの Ruby のインストールには ruby_buildrbenv のクックブックを使うのが便利でした。
Unicorn の実行にも既存のクックブックを使えればよかったんですが、rbenv で入れた Ruby を使う方法がよくわからなかったので、冪等性的には微妙な感じのクックブックを手書きで済ませてます。
MySQL のユーザやデータベースの作成には database クックブックが便利でした。

まとめ

文書校正支援 Web アプリ Torutsume を紹介しました。
そのうち社内用にインストールして使ってみつつ、モチベーション続く限り機能追加等していこうと思います。

Ruby/Rails 用 DI コンテナ Dee をつくった、あるいは Ruby のカルチャーについて

2014-01-01 01:27:43

あけましておめでとうございます。
大晦日は実家でプログレ聞きながらコード書いてました。
今さらながら Heldon の Stand by とか聞いてたんですが、Tangerine Dream を思わせるミニマルなシンセサイザーの反復と、リシャール・ピナスによるロバート・フリップばりの暴力的なギターソロが絡みあっており、大変良いですね。

作ったもの

また説明長くなりそうなので、はじめに作ったものの紹介です。

この Dee というのが DI コンテナの本体です。
名前は Ozzy Osbourne ソロ 1st Blizzard of Ozz におけるランディ・ローズのギター曲からです。
50 秒と短く、メタルアルバムの中にあってクラシック風の静かなギター曲ですが、同時にアルバムから欠かせない存在感を放つ名曲です。

何が言いたいかというと、Dee はコンパクトな実装ながらも、Dependency Injection によるクリーンな依存性解決を行う上でなかなか便利なライブラリとなっています。
PHP の Pimple を意識した作りになってます。

Dee 自体は DI コンテナとして最小限の機能だけに留められていて、何らかのアプリケーションやフレームワークに組み込むには、そのための実装が必要となります。
Rails については dee-rails という形で gem にしていて、これはデフォルトのコンテナへのアクセス方法や、サービスプロバイダを記述するルール (ディレクトリの配置とか、命名とか) と、それを生成するためのジェネレータを含んでいます。

ライブラリとしての使い方についてはそれぞれの README.md にとりあえず書いてるので、そちらをご覧ください。

Dee を作った背景、あるいは Ruby と PHP のカルチャーの比較

今年の後半は、知人のために Rails 4 で Web サービスを作ったりしていました。
そちらについては諸々の事情でここには書けないんですが、Rails でまともな Web アプリを書くのは初めてだったので、いろいろ勉強になりました。

基本的には Rails way で行くべきだろうということでやってきたんですが、どうにもしっくり来ないこともいくつかあって、一番気になったのはオブジェクトの取り回しを行う方法が用意されてないところでした。
要するに DI コンテナとかが用意されてない。

PHP だとここ 5 年ぐらいで、各種 Web フレームワークは DI コンテナ付属してて当たり前みたいな雰囲気になっていて、PSR-0 によるオートローディングや、PSR-1 でのクラス定義における副作用の排除と組み合わせることによって、非常にクリーンな形でオブジェクトの取り回しが行えるようになったという印象があります。

Ruby で何かする度にそんなことを考えさせられていて、Twilog から「黒魔術」をキーワードに探したところ、以下のようなツイートが掘り起こされました。

Ruby は黒魔術ビリティが高いので複雑な問題をより複雑な黒魔術で解決する傾向があるように感じる。少なくとも他の言語に比べると。

— Yuya Takeyama (@yuya_takeyama) 2012, 12月 23

PHP は Ruby より黒魔術ビリティが低い分、黒魔術による解決だとすぐ頭打ちするので、やっぱりオブジェクト指向の原則は大事だよね、ということになって、やや面倒さは残るものの堅実なやり方を採用していこう、みたいな流れでここ数年来ていると思う。

— Yuya Takeyama (@yuya_takeyama) 2012, 12月 23

[ruby]クラスメソッドにするとテスタビリティ下がるんだけどなんかアリになってるのはモンキーパッチとかで何とかできてしまう黒魔術ビリティにあるのかなぁ / “Ruby中級入門” http://t.co/Dv5OxKWQOG

— Yuya Takeyama (@yuya_takeyama) 2013, 8月 5

数ヶ月から 1 年以上前のツイートですが、今でも特に Ruby とそのカルチャーに抱く感想は変わってません。

なお、DI コンテナは元々 Java 由来だろうとは思いますが、その辺の歴史については全く知らないので書きませんでした。

Ruby に DI コンテナは不要か

Ruby における DI コンテナの実装は、もちろん全く無いわけではないと思うんですが、ほとんど使われていない印象です。
アレコレ検索してみると、Ruby においては DI コンテナは不要である、みたいな記事もいくつか見つかります。
Matz も「DIってのは硬直した言語のための技術なんだ」と言っています。

その他に参照した記事は大体以下の通り。

その辺の意見をまとめると、大体「Ruby の動的な性質を利用すれば DI コンテナなんか無くても問題ない」みたいな感じだと思います。
より具体的には、Ruby だとクラス自体もオブジェクト (Class オブジェクト) なんだからそいつをファクトリオブジェクトとして渡せば良い、みたいな。
(ちょっと英語の記事なんかはちゃんと読み取れてない可能性があるので、その辺読み違えてるところあればご指摘いただきたいところではあります)

確かに Ruby の動的な性質を利用することで解決できることも結構あると思うんですが、大体の場合は規模が大きくなって来ると破綻するように思われます。
Class オブジェクトをファクトリオブジェクトとして利用する場合も、new メソッドの引数が同じでないと上手く差し替えができなかったりするので、困ったことになります。

これは言い換えると、コンストラクタは API であるか否か、とも言えます。
これに対する僕の答えは「No」です。
もちろん、コンストラクタも API として考えること自体はできなくはないですが、そういうものとして作られたライブラリはあんまり無いように思います。

Rack Middleware のコンストラクタ引数の辛さ

ですが、実を言うと Rack Middleware のコンストラクタは API のようなものが一応決まっていて、Rack::Builder でミドルウェアを積み上げる場合、ミドルウェアのコンストラクタ引数は以下のようにする必要があります。

class SomeRackMiddleware
  def initialize(app, *args)
    # ~~~
  end
end

Rack::Builder におけるミドルウェアはまさに Class オブジェクトをファクトリオブジェクト、コンストラクタを API として考えているような感じになっていて、このような実装を半分強制されています。
これの何が問題かというと、コンストラクタパラメータのチェックや、デフォルト値のセットを自分で書かないといけなくなることです。

なお、これは Rack の仕様外の決まりで、Rack::Builder を使用するとき特有の問題だと思われます。

この問題については、コード例を示したこともありました。

DCI と ActiveSupport::Concern と古き良き Service について

DI コンテナと直接関係はないものの、「ドメインロジックをどこに実装するか」という問題において考えると、DCI や ActiveSupport::Concern に触れる必要が出て来ると思います。

DCI は未だにちゃんと理解できてないですが、ドメインオブジェクトをそれ自体とコンテキスト (ロール) に分けて考えよう、みたいな理解でいます。
より実装に近い感じでいうと、ドメインオブジェクトの状態をロールとして切り出した形に用意して、どこかに実装していたロジックが、ロールに勝手にすげ変わるようになってるよ、という感じでしょうか。
これを実現するにはそれなりのフレームワークが必要になるので、具体的にどう書くか、みたいなところはそのフレームワークに依存することでしょう。
Module.extend で頑張ることもできそうだけどまぁ辛そうですし、なんというか DCI 自体めんどくさそうな印象です。
(やったことなくて言ってますが)

あと ActiveSupport::Concern は複数のモデルとかで共通の処理を切り出してるだけだと思うんですが、どうでしょうか。
module のミックスイン + ちょいとした拡張機能みたいな感じ?
Scala や PHP の trait なんかもそうですが、どういう単位で切り出すかが問題になるので、結構難しいと思ってます。
それで済ませられる範囲で言うと便利だと思うんですけど。
まぁこれもほとんど使ったこと無くて言ってますが。

ぶっちゃけ新しいこと覚えるのがめんどくさくて避けてるだけなんですが、実際のところ大きな問題だと思うのは、ビジネスロジックの実装が何かしらのフレームワークに依存してしまうということです。
ActiveSupport::Concern はもちろん ActiveSupport に依存しますし、DCI もそれを実現するための何らかのフレームワークに依存することになるでしょう。

その点、古き良き Service は別に何らかのフレームワークに依存することを強制されてはいません。
その生成に関しては何かしらの DI コンテナに任せることになったとしても、別に個々の Service 自体が DI コンテナのことを知ってるわけではありません。
(知っていたとすればそれは DI Container ではなく Service Locator, Dependency Injection でなく Dependency Lookup になっているはず)

まとめ

大分とっ散らかった感じになってますが、Ruby や Rails においても DI コンテナは便利なのではないか、という問題提起として、Dee を作ってみました。
まだそれで実際に何か作ったわけではないのですが、それはまた追々...

今年もよろしくお願いします。

2014-01-01 14:00:00 追記

一部ご意見いただいた点などについて、追記します。

「DCI や ActiveSupport::Concern は DI コンテナとは関係ないだろ」というご意見

はい、直接的には関係ありません!
でも、間接的には関係してくると思ってます。

DCI や ActiveSupport::Concern の比較対象とすべきは、DI コンテナではなくて Service ですね。
どれも「Rails でいうところの Model (ActiveRecord::Base 継承したヤツ) をはみ出るロジックをどこに記述するか」という点では競合して来ると思います。

DI コンテナは Service をクリーンに記述するのを支援するツールに過ぎません。
DI コンテナ無しで Service を記述することはできなくないですし、DCI フレームワークを DI な感じに実装することも当然考えられます (あぁややこしい)。
ここについては僕の書き方が誤解を招いていたと思います。

DI 不要論と DCI 便利そう論は別に前々関係無いところで起こっていたと思うので、「DCI でいいから DI 要らないよね」みたいな人は居なかったと思います。
ですが、DCI 不要論の中では「DCI とか難しいし Service でいいじゃん」という意見を 2013 年の前半頃によく見かけたと思います。

「なんで突然 DCI や ActiveSupport::Concern Dis ってるんだ」というご意見

この文脈で DCI や ActiveSupport::Concern を挙げた理由については、先に書いた通りです。

Dis ってる、という点については特にそういう風には思ってません。
開発規模とかによってどれがより便利か違ってくることはあっても、どれかが絶対的に優れているとかいうことはないと思います。
とはいえこの記事でいうと、DCI や ActiveSupport::Concern について否定的になっている感は確かにあると思います。
どちらかというと、どっちも自分には難しくて挫折しただけなんですが。

それぞれ比較して、どういうときに便利そうか、自分なりの考えをまとめておきます。

長くなったので先に結論。

DCI はやはり、それを実現するフレームワークで、コレというものが出てくるまでは手が出せないんじゃないかと思います。
確かに考え方としてはふむふむなるほどという感じがしますが、実装として考えてみると、どうしても複雑化してしまうように思います。
とはいえ、それが実現されたら、それが有効な問題領域に「DCI というレールが敷かれている」状態になるので、Rails の目指している方向性には合致しているように思えます。

レールとして考えると、やはり「大体これで解決できるようにしといた。それでできない残り少ない部分は各位なんとかしろ」みたいな感じになると思います。
例えば「複数の Model (ActiveRecord::Base 継承したヤツ) にまたがるロジック」はうまく解決できても、「そもそも ActiveRecord 一切関係無い何か (Web API 使った処理とか)」については解決できない、みたいな感じになりそうです。
そういった割り切りの無いレールというのは、それはそれで複雑で誰にも使われないことでしょう。

単純かつ頻出の問題がとにかくたくさんある、という場合には DCI は便利になりそうな気がします。

で、Rails は Model をはみ出るロジックの記述に ActiveSupport::Concern を採用しています。
これも単純にミックスインを使うのに比べたら、ディレクトリの配置とか記述のしかたとかがある程度規約化されているので、それなりに「ActiveSupport::Concern というレールが敷かれている」状態にはなっていると思います。
とはいえこれはかなり自由度が高いレールなので、レールっぽさは低いんじゃないかなーとも思います。
その分、広い範囲で使えそうではありますね。

自由度が高いと、本来それを使うべきでない状況での濫用が問題になりそうです。
使うのにセンスが求められると思います。
少数精鋭での開発であれば大いに役立ちそうです。
別に他の方法と排他的ではないと思うので、ちょこっとだけ使う、ということもアリでしょう。

これらと比較すると、Service はレールでもなんでもありません。
単に何らかの処理を、専用のクラスに分割して書くだけなんですから。
何のフレームワークやライブラリへの依存も前提としていません。
例えある Service が ActiveRecord に依存していたとしても、ActiveRecord をラップすることで、Service それ自体から ActiveRecord を見えなくすることもできます。

とはいえ本当に生の状態で Service を利用せよ、となるとそれはさすがに辛いので、DI コンテナと、それへのアクセス方法だけレールとして用意したのが Dee と dee-rails ということになります。

Service を使ったやり方は本当に自由なので、基本的にはどんな状況にも対応できます。
シンプルな問題を素朴に解決することも、複雑な問題を複雑に (でもインターフェイスはシンプルに) 解決することもできます。
似たようなたくさんの問題を効率よく解決する方法については、自分で考える必要があるでしょう。
大規模な開発でも適用可能だと思いますが、何人かは GoF とか PofEAA とか DDD とか読んでて欲しいところです。

以下、関連するツイートを並べます。

なんで DCI がさらっと Dis られてるのかちょっとわからなかった / “Ruby/Rails 用 DI コンテナ Dee をつくった、あるいは Ruby のカルチャーについて - Born Too Late” http://t.co/0lV9jfUb6A

— ハト (@rosylilly) 2013, 12月 31

@rosylilly もともと、ドメインロジックとか、DB 関係無いモデルをどこに書くか、というときに、いま流行の DCI とか使うといいのかなぁ、でもフツーに Service クラス書けばよくない? って思ったところが発端なので。間接的には同じ問題領域に触れると思います。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

@rosylilly DCI は、実装レベルでいうと、それを支援するフレームワークに依存すると思いますけど、デファクトっぽいのを見つけられなかったので手を出すこともしてません。Dicer は Railtie や Generator まわりを参考にさせてもらいました。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

@yuya_takeyama よくわからないのですが、 DCI は FW に依存するからダメで、 Service は FW に依存しないからよい、みたいな話なんですか?

— ハト (@rosylilly) 2014, 1月 1

@rosylilly それもひとつです。もっと単純に言うと「よりシンプルな方法で解決できるんならそっちでいいじゃん」ぐらいの感じです。開発規模とか開発者のカルチャーに依存して変わって来るものだと思いますし、どちらかが優れているとかは思ってないです。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

@yuya_takeyama シンプルな方法で解決できればベターなのは同意するのですが、DI の有用性からなんで DCI や ActiveSupport::Concern に飛んだのかがわかってません

— ハト (@rosylilly) 2014, 1月 1

@rosylilly どれも Rails が用意した Model をはみ出る処理をどこに書くか、という点で関係して来ると思います。比較対象としては DI コンテナでなく Service の方がより厳密ではありますね。DI コンテナはあくまでもそれを支援するツールでしかないので。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

@rosylilly @yuya_takeyama DIとserviceで十分に解決できる問題をなぜDIを否定した上でDCIを議論しているのか?という疑問だと感じた

— デブ (@kuzuha) 2014, 1月 1

@kuzuha はい、大体そんな感じです。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

DI 不要論の文脈と、DCI というのが凄いらしい、という文脈は全く別だと思ってるけど、DCI 不要論の人は結構「Service でよくね」って言ってたと思う。2013 年前半頃そういう人あちこちで見た覚えがある。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

@kuzuha 別に DI 否定した覚えはないんですが、いつから DCI が DI を否定したことになったんでしょう……

— ハト (@rosylilly) 2014, 1月 1

@rosylilly それは読み取り方が間違ってて、ruby界隈ではrubyが強力に動的であるからDIは必要ないと否定されているという本分の一節のことを指している。DCIとの関連性はない。

— デブ (@kuzuha) 2014, 1月 1

@kuzuha ああ DCI が DI 否定してますて話かと。そういう話なら納得です。

— ハト (@rosylilly) 2014, 1月 1

@yuya_takeyama Model をはみ出る処理の具体例がいまいちわかってないのですが、 Service と DCI を比較するという話なんだったらわかります。

— ハト (@rosylilly) 2014, 1月 1

@rosylilly Model をはみ出る処理の具体例はこれもそうです。 http://t.co/fDPk0Ss1xz 複数の Model に横断していてどっちに書くか悩ましいから切り出してしまおう、みたいなものも含みます。あとは Web API に依存した処理とか。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

@yuya_takeyama なるほどなるほど。確かにこれくらいの規模なら Service で十分というのはうなづけます。

— ハト (@rosylilly) 2014, 1月 1

あと、この記事に関して残る火種も紹介します。

新年早々ブログでボヤ起きてて楽しい感じになってきた。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

DI コンテナ作ったよ!とか言いながらそれ自体の実装が全然 DI じゃない点についてのツッコミ待ち。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1

Rack Middleware のコンストラクタ引数辛いよね、は割とあるあるネタだと思ってたけどいまのところだれも触れてくれてなくて寂しい。

— Yuya Takeyama (@yuya_takeyama) 2014, 1月 1