Kotlin Fest 2018でサーバサイドKotlinのテストについて発表してきた #kotlinfest

昨日8/25(土)に、日本Kotlinユーザグループが運営するKotlin Fest 2018が東京コンファレンスセンター品川にて開催され、同僚の @suusan2go と二人で「How to Test Server-side Kotlin」というタイトルで発表してきました。セッションを聞きにきてくださったみなさん、運営のみなさん、ありがとうございました。

f:id:maeharin:20180826121505j:plain

沢山の方が参加するイベントとあって、発表直前までとても緊張していたのですが、随所にスピーカーに対する心遣いが散りばめられており、大変過ごしやすいイベントでした。ここではスピーカーとして感じたことを書いておこうと思います。(私が所属するエムスリーはスポンサーとしても参加したのですが、それはまた会社の方のブログで)

発表資料はこちらです

オープニングセッションでの「盛り上げよう!」

イベントの最初に日本Kotlinユーザグループ代表の長澤太郎さんと藤原聖さんによるオープニングセッションがあったのですが、その中で「スピーカーの方々は参加者のみなさんからのフィードバックを楽しみにしています。ぜひ皆さんで盛り上げましょう!拍手するところでは拍手、おおーというところではおおーと声に出してフィードバックしましょう」といった旨の呼びかけをされてました

f:id:maeharin:20180826122656j:plain

このオープニングの呼びかけもあってか、私達の発表の際にも参加者のみなさんから温かいフィードバックをいただくことができました。

ちょっとしたアイスブレイクとして「昨日発表資料を作ってる時、長澤太郎さんの写真をダウンロードしたら、なぜかMacがバグってデスクトップから消えなくなってしまいましたw」というエピソードをお話したのですが、ちゃんと笑っていただけて一安心でした

自己紹介で「はてなブックマーク1200超えたことが自慢です!」といったら大きな拍手がもらえたことも嬉しかったです(まさかここで拍手してもらえると思ってなかったw)

それと、セッションがはじまる前にフリースペースでお話をした方々が実際にセッションを聞きに来てくださったのがとても嬉しかった。懇親会の時にも話しかけていただけて、こういうフィードバックをいただけるのは本当に発表者冥利につきますね。

発表後の「Ask The Speaker」スペース

発表後にはスピーカーに自由に質問できる「Ask The Speaker」というスペースが用意されており、次のセッションまでの休憩時間に質問できるような仕組みになってました。スピーカーとしては「次のセッションの方の邪魔にならないように早く捌けなきゃなー」など気にしなくてよくなりますし、参加者の方も「そこに行けばスピーカーに質問できる」と明確に分かるので、いい仕組みだなと思いました。質問に来てくださった方々、ありがとうございます!

控室とかTシャツとか

それ以外にも、スピーカー用の控室からセッションのライブビューイングが見れるのが驚きでした。自分の発表がはじまるまで資料の修正をしたりしながら、他のセッションを見ることができるのは細かい配慮だなぁと感心しました。

控室がとても快適なので、最後のしらじさんのセッションもライブビューイングで見ようと思ったのですが、会場で見てください!とご本人から声をかけていただき、会場でみることにしました。当然ながら会場で見たほうが臨場感があってよかったですw(しらじさんのブログで神対応なんて言っていただいてますが、逆に声かけさせてしまってすみません!)

shiraji.hatenablog.com

あと、Kotlin Fest 2018のTシャツがもらえました。めっちゃかわいい

f:id:maeharin:20180826180641j:plain

Kotlin Fest 2018、楽しかった!

セッション聞きに来てくださったみなさん、ありがとうございます!そして運営のみなさん、本当にお疲れ様でした!

DBスキーマからKotlinのテストフィクスチャを自動生成するgradleプラグインを作った

サーバーサイドKotlinでDB接続テストする際、テストデータのセットアップにはDbSetup が便利です。DbSetupは「xmlなどの外部ファイル」ではなく「コード」でテストフィクスチャを生成できるJavaライブラリで、以下のようなKotlin用のDSLも提供してくれているので重宝しています。

    insertInto("users") {
        mappedValues(
                "id" to 1,
                "name" to "前原 秀徳",
                "job" to "engineer",
                "status" to "ACTIVE",
                ...
        )
    }

ただ、これだとカラム数が数十個になってくると記述が面倒だし(仕事だと100カラム近いテーブルもあるんですよね。。)、ちょっとだけ値が異なるパターンを色々作りたい、といった際にしんどいな感じてました。

DBスキーマからコードを自動生成してくれて、かつRubyのfactory_botのような使い心地だったら楽だなと思い、factlinというgradle pluginを作ったので紹介します。

github.com

  • 既存のDBスキーマを元にKotlinのコードを自動生成する(自動生成されたコードはDbSetupに依存)
  • 自動生成されたコードを使うとRubyのfactory_botのような使い心地でテストフィクスチャをセットアップできる
  • 自動生成されるコードのテンプレートやデフォルト値はカスタマイズ可能

といった代物です。例えば、postgresでこんなテーブル定義があった場合

 CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name VARCHAR(256) NOT NULL,
  job VARCHAR(256) NOT NULL DEFAULT 'engineer',
  status VARCHAR(256) NOT NULL DEFAULT 'ACTIVE',
  age INTEGER NOT NULL,
  score NUMERIC NOT NULL,
  is_admin BOOLEAN NOT NULL,
  birth_day DATE NOT NULL,
  nick_name VARCHAR(256),
  created_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  updated_timestamp TIMESTAMP WITHOUT TIME ZONE
);

COMMENT ON TABLE users IS 'user table';
COMMENT ON COLUMN users.id IS 'primary key';
COMMENT ON COLUMN users.name IS 'user name';
COMMENT ON COLUMN users.job IS 'job name';
COMMENT ON COLUMN users.status IS 'activate status';
COMMENT ON COLUMN users.age IS 'user age';
COMMENT ON COLUMN users.score IS 'game score';
COMMENT ON COLUMN users.is_admin IS 'user is admin user or not';
COMMENT ON COLUMN users.birth_day IS 'user birth day';
COMMENT ON COLUMN users.nick_name IS 'nick name';

このプラグインを実行すると、以下のようなKotlinのコードが自動生成されます。

data class UsersFixture (
    val id: Int = 0, // primary key
    val name: String = "", // user name
    val job: String = "", // job name
    val status: String = "", // activate status
    val age: Int = 0, // user age
    val score: BigDecimal = 0.toBigDecimal(), // game score
    val is_admin: Boolean = false, // user is admin user or not
    val birth_day: LocalDate = LocalDate.now(), // user birth day
    val nick_name: String? = null, // nick name
    val created_timestamp: LocalDateTime = LocalDateTime.now(), 
    val updated_timestamp: LocalDateTime? = null 
)

fun DbSetupBuilder.insertUsersFixture(f: UsersFixture) {
    insertInto("users") {
        mappedValues(
                "id" to f.id,
                "name" to f.name,
                "job" to f.job,
                "status" to f.status,
                "age" to f.age,
                "score" to f.score,
                "is_admin" to f.is_admin,
                "birth_day" to f.birth_day,
                "nick_name" to f.nick_name,
                "created_timestamp" to f.created_timestamp,
                "updated_timestamp" to f.updated_timestamp
        )
    }
}

生成されたコードは、

  1. テストフィクスチャを表すData Class
  2. DbSetupのinsertIntoメソッドをラップした拡張関数

で構成されてます。1.Data Classの各プロパティには、データベースのカラム型に応じたKotlinの型とデフォルト値が自動生成されます。デフォルト値はnullableなカラムならnull、nullableでない場合はカラムの型に応じた値(数値なら0、文字列なら空文字)といった具合に設定されますが、後述するカスタマイズ設定である程度カスタマイズ可能です。また、DBカラムにコメントがついている場合、コメントもつくようになっています。

上記の自動生成されたコードは、テストの中で以下のように使います。これによりDBにテストデータがinsertされ、そのデータを用いたテストを行うことができます。

dbSetup(dest) {
    deleteAllFrom(listOf("users")) 
    // DBにテストデータをセットアップする
    insertUsersFixture(UsersFixture(id = 1, name = "foo"))
    insertUsersFixture(UsersFixture(id = 2, name = "bar"))
}.launch()

...DBのデータを使ったテスト

自動生成されたFixtureクラスはData Classになっており、かつカラムの型に沿ったデフォルト値が設定されているので、「ちょっとだけ値が異なるテストフィクスチャ」を簡単に生成することができます。IDEで補完が効いてくれて、定義元にジャンプすればカラムのコメントも確認できて便利です(100個近くカラムがあるテーブルだと特に嬉しい)

f:id:maeharin:20180809082049g:plain

フィクスチャのパターンを作る

自動生成されたクラスがData Classになっているという点がポイントで、Data Classのcopyメソッドを使うことで、Rubyのfactory_botのように「フィクスチャのパターンに名前をつけて取り回せるようにしておく」ことが可能です。以下のようにKotlinの拡張関数とcopyを使います。ちなみに、メンテナンスしやすくするため(カラムが変更されコードを再生成する場合に備えて)、自動生成されたFixtureクラスには手を加えず、別のディレクトリとファイルを作って拡張関数を定義するのがオススメです。

fun UsersFixture.default() = this.copy(job = "エンジニア", age = 30)
fun UsersFixture.active() = this.default().copy(status = "ACTIVE")
fun UsersFixture.inActive() = this.default().copy(status = "IN_ACTIVE")

テストでこんな風に使います

insertUsersFixture(UsersFixture().active().copy(id = 1, name = "テスト1"))
insertUsersFixture(UsersFixture().inActive().copy(id = 2, name = "テスト2"))

カスタマイズ

自動生成されるコードはある程度カスタマイズ可能となっています。

設定 内容 デフォルト
fixtureOutputDir 自動生成されるコードの出力先ディレクト src/test/kotlin/com/maeharin/factlin/fixtures
fixturePackageName 自動生成されるコードのパッケージ名 com.maeharin.factlin.fixtures
fixtureTemplatePath 自動生成に使うテンプレート(FreeMarker) のパスです デフォルト
exclude table names 自動生成の対象外にするテーブルリスト なし
includeTables 自動生成の対象にするテーブルリスト すべて
cleanOutputDir trueにすると自動生成するまえに出力先ディレクトリを削除します(メンテナンス性のためにtrueにすることを推奨) false
customDefaultValues 特定のテーブルの特定のカラムのデフォルト値を上書き。形式: [tableName, columnName, defaultValue] なし
customTypeMapper データベースの型をKotlinの型に変換するルールを上書き。形式: [databaseColumnType, KotlinType] デフォルトルール

リポジトリのREADMEに設定例があるのでご参照ください。

ぜひ使ってみてください!

この仕組でこれまで1000ケース以上テストケースを書いてきましたが、とくに問題なく快適に使えています。もしよければ、ぜひ使ってみてください!

(宣伝)Kotlin Fest 2018に登壇します

2018年8月25日(土)に東京コンファレンスセンター品川にて開催されるKotlin Fest 2018に登壇します。サーバーサイドKotlinのテストに関して話す予定ですので、ぜひご来場ください!

kotlin-fest-2018.peatix.com

「どこでもKotlin #1 〜Kotlin実践導入体験談〜」を開催しました #m3kt

8/24(木)に私が所属しているエムスリー主催でKotlinのイベント「どこでもKotlin」を開催しました。エムスリーではAndroid開発言語としてはもちろんのこと、サーバーサイドでもKotlinを実践導入しています。第1回目となる今回は、日本Kotlinユーザグループ代表 長澤太郎をはじめとするエムスリーのKotlinエンジニアが、サーバーサイド、Kotlin/Native、AndroidアプリでKotlinを使った体験談を発表しました。

connpassイベントページ:どこでもKotlin #1 〜Kotlin実践導入体験談〜【増員!】 - connpass

f:id:maeharin:20170824192906j:plain

どこでもKotlinについて

ご存知のとおりKotlinはAndroid開発言語として有名です。しかし、その活躍の場はAndroidにかぎらず、サーバーサイド、Nativeなど多岐に渡ります。私は今年Kotlinと出会い、その素晴らしさに惚れ、システムリニューアルにサーバーサイドKotlinを導入することを決めました。Androidだろうとサーバーサイドだろうと、エムスリーだろうとそうでなかろうと、参加者の方と一緒にKotlinを盛り上げていきたいと思い、「どこでもKotlin」というタイトルでイベントを開催することにしました

f:id:maeharin:20170829105721j:plain

#m3kt

ハッシュタグは #m3kt。当日はみなさんに盛り上がっていただき、トレンド入りしました

エムスリー×長澤太郎グッズの数々

煽られる参加者の方々

発表内容

システムリニューアルと サーバーサイドKotlin

まずは私の発表。システムリニューアルにサーバーサイドKotlinを導入した事例をお話しました

APIサーバーをKotlin x Spring Bootで作成しています(フロントはrailsとvue.js使っています。ここら辺についても機を改めて発表したいと思ってます)

f:id:maeharin:20170824194013j:plain

Kotlin ✖︎ Spring Boot サーバーサイドkotlinは怖くない

私と同じチームでドイツ人のルーカスによる発表

サーバーサイドKotlinは怖くない!

f:id:maeharin:20170824200124j:plain

Starting Kotlin/Native おなじところ、ちがうところ

後半戦はちょっと怖い?Kotlinの話。エムスリー新卒のエンジニア星川さんによるKotlin/Nativeに関する話

f:id:maeharin:20170829105620j:plain

一歩進んだ拡張関数の活用とその濫用で後悔した話

トリはエムスリーのアイドル、長澤太郎による拡張関数の話し

f:id:maeharin:20170824203117j:plain

懇親会

最後は懇親会。みなさんKotlinの話題で盛り上がりました

f:id:maeharin:20170824210555j:plain

長澤太郎とKotlinポーズ!

f:id:maeharin:20170824210729j:plain

次回「どこでもKotlin #2 〜サーバーサイドKotlin特集〜」は9/28開催!

どこでもKotlinはシリーズ開催します。次回は9/28。テーマは「サーバーサイドKotlin」です! connpassページで募集しますので、是非m3-engineerグループのメンバーに登録ください(twitterの#m3ktでも告知します)

m3-engineer.connpass.com

長澤太郎の新刊、サーバーサイドKoltin本が9/29発売!

さらに!9/29に長澤太郎の新刊「Kotlin Webアプリケーション 新しいサーバサイドプログラミング」が発売予定です!(amazonで予約受付中です)

エムスリー love Kotlin!ジョイナス

エムスリーはKotlinを積極的に導入していきます!カジュアル面談なんかも随時しているので興味がある方は是非下のリンクからご応募ください!全国のKotoliner(ことりにゃ〜)のみなさん、ジョイナス

jobs.m3.com

have fun Kotlin!

f:id:maeharin:20170828161615j:plain

開発合宿行ってきた

いつも一緒に活動してるメンバー5人で、久々に開発合宿してきましたー

今回は「勉強したい技術を使って、何か作ってみる」をテーマとして、1泊2日。場所は伊東の山喜旅館。両日とも会議室を貸し切ることができたので、快適なネット環境の元、集中して開発できました

事前準備

場所と日時を決める

まずはメンバーの都合が合う日程を伝助とかで調整して、その後合宿会場を予約。今回は伊東の山喜旅館にしました。開発合宿では「チェックイン、チェックアウトの時間」が問題になりやすいのですが、山喜旅館は会議室があって1時間1000円くらいで予約できました。チェックインしてない時間は、この会議室を予約することで、開発の時間を多くとれました

www.ito-yamaki.jp

旅館のホームページ、いい感じです

テーマ・タイムテーブル決める

今回は「勉強したい技術を使って、何か作ってみる」をテーマにしました。また、タイムテーブルは事前に決めて共有しておくと、当日はかどる。ということで今回はこんな感じにしました。

1日目

時間 内容
10:00 - 12:00 開発
12:00 - 13:00 ランチ
13:00 - 15:00 開発
15:00 - 15:30 部屋へ移動
15:30 - 19:00 開発
19:00 - 20:30 夕飯
20:30 - フリータイム

開発時間:7.5h

2日目

時間 内容
8:00 - 10:00 起床、朝食 、チェックアウト
10:00 - 12:00 開発
12:00 - 13:00 ランチ
13:00 - 14:00 開発
14:00 - 15:00 成果発表!
15:00 - 解散!

開発時間:3h

技術調査をしておく

当日開発に集中するために、ある程度技術調査というか勉強はしておく。自分はswiftiosアプリを作りたかったので、以下のようなことをしておきました

当日の様子

f:id:maeharin:20150314103040j:plain

f:id:maeharin:20150314151224j:plain

f:id:maeharin:20150314124225j:plain

f:id:maeharin:20150314160928j:plain

f:id:maeharin:20150314191002j:plain

f:id:maeharin:20150315100600j:plain

f:id:maeharin:20150315124034j:plain

f:id:maeharin:20150315140608j:plain

f:id:maeharin:20150315140946j:plain

振り返り

  • よかった点
    • wifi完備の会議室を長い時間予約できたので、開発環境は問題なし
    • 成果物発表を目標にしたので、集中できた
    • 事前にタイムテーブル作っておいたので、スムーズ
  • 反省点
    • 旅館の部屋、隙間があって寒かった
    • 帰りの電車調べてなくて混乱した。(自由席がない特急が来て待ち時間無駄になった)
    • 個人的には、もう少し事前にiosチュートリアルやっておけばよかった

レガシーシステムを理解する方法

結構年季が入ったJavaのレガシーなwebアプリをRailsに移行するというプロジェクトを進めている。レガシーシステムは以下のような状態。

・オリジナルを作ったエンジニアは既に不在
ビジネスロジックに対するドキュメントは殆ど存在しない
単体テストは存在しない
・社内WAFで、ドキュメントなし
複数のシステムが連動している

このような状態は、年季の入ったシステムではわりとよくあることだと思うが、いかんせん「仕様がわからない」ということが色んな所でボトルネックになっていた。その対策方法について、メモしておく。

仕様を理解するための時間を確保する

「その内時間が経てば理解できるよ」という考えもあるだろうが、ある程度年季が入ったシステムをリプレースするなら、初期段階で多少コストをかけてでも、既存仕様を理解するための時間を作った方が効率的だと思う。既存仕様をよく理解しないまま移行開発を行っても、色々な抜け漏れが発生する。また、移行作業とは別に通常開発やテクニカルサポートも行うわけだが、既存システムへの理解が浅いままだと、毎回の調査時間が馬鹿にならない。チームの人数や仕様理解度にもよるが、初期段階で仕様理解の体制を整備してチーム内で共有する時間をとった方が、トータルでみた時間コストが少なくなるというケースは多そうだ。

レガシーコードといえば、「レガシーコード改善ガイド」が有名だが、この本にも以下のように書いてある。

多くの人は、自分にできる最も手近な方法でコードを理解しようとし、その他の方法を使いません。結局のところ、何かを理解しようとするために多くの時間を費やすのは、作業がはかどらず、正しくないやり方に思えるからです。理解する段階をさっさと終わらせることができたら、自分の稼ぎを得るための仕事に取りかかれるはずだと考えるのです。しかし、こうした考えは愚かではないでしょうか。

とはいえ、場当たり的に調査しても効率が悪い。レガシーコード改善ガイドには、レガシーコードを理解するための技法がいくつか解説されているが、自分はその中から以下の3つを好んで使っている。

・仕様化テスト
・ラフスケッチ
・試行リファクタリング

「仕様化テスト」でユーザーから見た仕様を理解する

ユーザーからみたアプリケーションの仕様(一番外側の仕様)を把握する際に効果的。レガシーコード改善ガイドによると、仕様化テストとは以下のようなテストをさす。

仕様化テストは、コードの実際の振る舞いを明らかにするテストです。「システムはこれをするべきだ」とか「こうしていると思う」ということを確認するテストではありません。仕様化テストは、システムの現在の振る舞いをそのまま文書化します。(略)実際のシステムの動きをそのまま文書化したものになります。システムの一部分の動作を理解できると、その知識と、システムに新しく期待する動作に関する知識とを使って、変更を行えるようになります。率直にいって、システムの実際の動作に関する知識はとても重要です。

このやり方の何がよいかというと、仕様理解とテストケース作成の両方が進むということ。(もちろん、テストを正式にやろうとなると、メンテナンスコストが発生するので、実際に運用にのせる際には、注意深く検討する必要がある。)

リプレースプロジェクトなら、単体テストではなく、E2Eテスト

自分のプロジェクトでは「ユーザーからみた仕様は殆ど変えずにリプレースする」という大前提がある。なので、既存のレガシーアプリに単体テストを書いても結局捨て去る事になり、殆ど意味がない。なのでE2Eの仕様化テストを書くようにしている。

ツールとしては、selenium ideが便利。見返しやすいし(slowモードで再生すれば、ああ、こういう動きねというのが分かる)、後々自動テストを整備する際の資産にもなる。もちろん、selenium ideはメンテナンスがちょっと。。というのがあればcapybaraなど使って書くのもあり。この辺は用途やチームの状況に合わせて好きなツールを選択したらよいと思う。


「ラフスケッチ」で主要テーブル・クラスを理解する

コードを読むだけでは混乱する場合、絵を描いたり、メモを取ったりすることが有効です。(略)これらのスケッチには、完全なUMLダイアグラムや、関数呼び出しを表現する特別な記法を使う必要はありません。

上記の通り、形式はラフでよい。テーブル・クラスについて理解を深める時に効果的と思う。ただ、全てのテーブル・クラスを網羅しようとすると大変なので、スケッチの対象は、ビジネス上最も重要なテーブルやクラスのみにする。

ER図もどき

テーブルの関連だけ書いたER図があると、何かと便利。エクセルだとマスター管理が微妙なので、google driveの図形描画を使って、主要なテーブルの関連を書いている(とはいえ、結局主要テーブル以外の関連も調べるケースがあるので、erdというrubyのgemでER図を作るのもあり)

クラス図もどき

ビジネス上非常に重要な役割を担っているクラスは、クラス構造のスケッチがあると便利。別にUMLで正確に書く必要はなくて、継承や集約をざっと書いて、主要なpublicメソッドだけ書いておくだけでも役に立つ。継承関係の矢印ひっぱったりするのが面倒なら、手書きで書いておくだけでもいい。

「試行リファクタリング」で細かいロジックを理解する

ロジックが複雑で、かつそのロジックを把握しておかないとまずい部分は、試行リファクタリングを行う。レガシーコード改善ガイドによると、試行リファクタリングとは以下のようなリファクタリングをさす

まず、バージョン管理システムからコードをチェックアウトしてください。テストを書く事は忘れましょう。メソッドの抽出でも、変数の移動でも、そのコードを理解しやすくするために、あらゆる方法を用いてリファクタリングしてください。ただし、そのコードは再びチェックインせずに破棄します。これは試行リファクタリング(scratch refactoring)と呼ばれる手法です

リファクタリングを自由に行って、徐々にロジックへの理解を深めて行く。深掘りするとどこまでもいけるので、理解すべきポイントを把握したらすぐに切り上げるようにする。終わったら別ブランチに保存しておくか、もしくは破棄する。(決して稼働中のアプリに影響を与えないようにする)

まとめ

上記の方針で少しずつレガシーコードの理解を進めていて、結構いい感じにワークしている。なお、Object-Oriented Reengineering Patternsという書籍はこのテーマについて突っ込んで書いているようなので、読んでいるところ。以下から無料のpdfがダウンロードできる
http://scg.unibe.ch/download/oorp/



レガシーコード改善ガイド (Object Oriented SELECTION)
マイケル・C・フェザーズ
翔泳社
売り上げランキング: 118,912

「Webアプリエンジニア養成読本」を献本してもらった!読んだ!

「Webアプリエンジニア養成読本」を献本してもらいました。あざす!


Webアプリエンジニア養成読本[しくみ、開発、環境構築・運用…全体像を最新知識で最初から! ] (Software Design plus)
和田 裕介 石田 絢一 (uzulla) すがわら まさのり 斎藤 祐一郎
技術評論社
売り上げランキング: 316

「点」ではなく「線」

私自身は「28歳の時に未経験からWebエンジニアに転職する」という無謀な試みをして、今年3年目になります。日々開発に勤しむ日々を過ごしておりますが、Webアプリを作るために必要な技術要素って広い!と日々痛感しております。

たまたま自分は本書の著者の1人であるゆーすけべーさんはじめ、先輩諸氏から色々教わることができましたが、教えてくれる人が身近にいて一番よかったのは

何を勉強すればよいのかが分かった

ことです。本書にはその「何を勉強すればよいのか」がコンパクトにまとまっていると思いました。技術書って「点」で書かれているものが多いと思います(PHPRubyMySQLみたいに特定技術ピンポイントで深堀されてる本)。一方、本書は「Webアプリを作るための技術要素」という「線」で書かれているように思いました。

この本をざっと読んで手を動かせば、脳内でWebアプリを作るために必要な技術要素という「点」が繋がって「線」になっていくように思います。Webアプリエンジニア先輩諸氏がconnecting the dotsしてくれた感じで素敵です。

未経験の人は「索引作り」に

まだWebアプリを作ったことが無い方は、きっと「Webアプリを作るために必要な技術的要素の索引」がまだ頭の中に出来上がっていない状態だと思うので、頭の中に索引を作るイメージで読み進めるとよいかと思います。

まずは、この本に書いてあることを、ざっと手を動かしてやってみる(全体を見失わないようにとにかく先に進める)。すると「何を勉強すればよいのか」当たりがつけられるようになる。その後は自分でアプリの企画を考えて実際に作ってみたり、より深く勉強したい技術的要素があればさらに勉強していくみたいな感じで進めるとよいかと。

あ、ただ本書ではクライアントサイドJavaScriptとデータベースについて本当にさらっとしか触れられていないので、その部分はちょい踏み込んで自分で調べる必要が出てくると思います。

2-3年の経験がある人は「穴埋め」に

自分のように2, 3年の経験がある人にとっては、「穴を埋める」という視点で読むとよいかと思いました。もちろん「この本に書かれていることは全て知り尽くしている」という方もいらっしゃるでしょうが、自分は結構穴がありました。例えば、自分は「開発」に携わることが多く「運用」の経験が浅いです。なので、やはりその「運用」を扱っている3章,4章は穴が多かったです。

また、PHPの章はいわゆる「モダン」な開発手法が用いられているので、「レガシーなPHPの保守に手一杯でモダンなPHPの学習が追いついていない」なんて方は結構新しい発見があるのではないでしょうか。具体的にはComposerでライブラリ管理して、WAFとしてSlim(RubySinatraライクなWAF)、テンプレートにTwig、ORMにEloquent(Laravelで使われているORM)を使ってサンプルアプリを開発していくという構成になっているので、その辺の経験がなければ新しい発見があるかと。

まとめ

未経験だった頃の自分には無条件でオススメしたい。今の自分にとっても穴が把握できてよかったです!

Backbone.jsでViewからModel・DOMを操作する時の流れ

自分の頭の中の整理のために。

はじめに

Backbone.jsガイドブックを読んでいたら、このような事が書いてあった。

Backbone流MVCでは、ビューとコントローラは両方ともViewが担当します。(略)これらはそれぞれViewのメソッドとして実装しますが、本書では区別のために前者をビューメソッド、後者をコントローラメソッドと呼ぶことにします。(略)重要な点は、DOMイベントに応じてコントローラメソッドが実行されることで処理が始まり、その中でmodelやcollectionを操作し、その結果生じるイベントがビューメソッドを呼ぶ、という流れを意識することです。そのためにも、コントローラメソッドには処理の起点になる以上の仕事を与えず、DOM操作はすべてビューメソッドに集めるよう明確に区別しましょう。

図にするとこんな感じになる(点線がイベントで実線が直操作)

しかし、なぜこのような書き方にするとよいのか?2つの疑問をもった

1. なぜコントローラメソッドとビューメソッドを切り分けるのか?
2. なぜコントローラメソッドがビューメソッドを直接呼び出さないのか?

以降、それぞれ整理してみる

1. なぜコントローラメソッドとビューメソッドを切り分けるのか?

まず、なぜわざわざコントローラメソッドとビューメソッドを切り分ける必要があるのか?逆に以下のように一緒にすると何が困るのか?

思うに、この書き方の問題は、DOMの更新を担当する部分のコードが再利用できないことにあると思う。例えば以下のように複数イベントハンドラが同じDOM更新を行う場合、上記の書き方だとコードが重複する。

DOM更新の部分を切り出して別メソッドにすれば再利用できる

役割が分離されているので、テストもしやすくなるし、理解もしやすくなる。

2. なぜコントローラメソッドがビューメソッドを直接呼び出さないのか?

では次に、なぜコントローラメソッドが直接ビューメソッドを呼び出さない方がよいのか?つまり以下のように書くと、なぜよくないのか?

恐らく、問題はModelとViewが1対多になった時に起こる。自分が作ったWebサービス音楽制作のためのWebサービス)でModelとViewが1対多になる部分が多くあったので例にあげる。例えばこんな部分。

この部分では音源を表す1つのModelに対して、再生ボタンを管理するPlayButtonViewと波形を管理するWaveformViewという2つのViewが存在している。例えば音源が停止している状態から再生ボタンと波形それぞれをクリックすると、以下のような動きをする。

・再生ボタンをクリック

  • > PlayButtonViewがModelを再生
  • > PlayButtonViewが再生ボタンを停止ボタンにする + WaveformViewが波形を動かす

・波形部分をクリック

  • > WaveformViewがModelを再生
  • > PlayButtonViewが再生ボタンを停止ボタンにする + WaveformViewが波形を動かす
ビューメソッドを直接呼び出すと

これをコントローラメソッドがビューメソッドを直接呼び出すように書くと、以下のようになる。

Modelに対してViewが2つであったとしても、既にかなり複雑になっている。これが3つ、4つとなってきたら確実に破綻する。

Modelのイベントを購読すると

では、これをビューメソッドがモデルのイベントを購読するように変更したらどうなるだろうか?図にすると以下のようになる。

Modelのイベントを介することによって、View1とView2が疎結合になった。DRYだし、理解しやすいし、テストもしやすい。

まとめ

もちろん、コントローラとなるViewのメソッドが必ずModelとDOMを更新するわけではない(ただDOMを更新するだけの時や、イベントを発火するだけの時など様々なケースがある)し、ViewとModelが複雑でイベント仲介者(Mediator)を置かないと厳しいこともあるが、「Model更新->DOM更新の基本的ケース」においては、上記のような書き方をするとだいたい幸せになれるように思った。