『駅すぱあと』新しい開発基盤の研究

49
『駅すぱあと』 新しい開発基盤の研究 株式会社ヴァル研究所 R&D Centre ソフトウェアエンジニア プロダクトチーフ 佐藤昭彦

description

「駅すぱあと」を支える開発 〜9262の可能性を繋げ!〜DevLOVE 2014/05/16 での発表資料です。

Transcript of 『駅すぱあと』新しい開発基盤の研究

Page 1: 『駅すぱあと』新しい開発基盤の研究

『駅すぱあと』新しい開発基盤の研究

株式会社ヴァル研究所 R&D Centre ソフトウェアエンジニア プロダクトチーフ 佐藤昭彦

Page 2: 『駅すぱあと』新しい開発基盤の研究

※注意 この発表では現在研究中のものを紹介しています。『駅すぱあと』には”まだ”導入されていません。

Page 3: 『駅すぱあと』新しい開発基盤の研究

自己紹介• 佐藤昭彦(さとうあきひこ)

• 2005年 株式会社ヴァル研究所入社

• モバイル系のJavaエンジニアを経て現在C++でお仕事してます

• プログラム言語大好き

Page 4: 『駅すぱあと』新しい開発基盤の研究

もくじ• C/C++開発環境の改善

• 調査したツール類の紹介

• 運賃計算とDSL

• 『駅すぱあと』が戦う運賃計算について

• DSLのススメ

Page 5: 『駅すぱあと』新しい開発基盤の研究

開発環境の改善

Page 6: 『駅すぱあと』新しい開発基盤の研究

開発環境の改善• 自動化(CI環境の整備)

• GitHubとJenkinsを連携させてPull Request単位でビルド&テスト

• デイリーでカバレッジ計測。gcovのレポートをJenkins上で管理

• その他ツール類の調査

• 便利ツールの導入検討

Page 7: 『駅すぱあと』新しい開発基盤の研究

GitHub/Jenkins連携

pull request

(polling)

pullbuild/test

結果通知

GitHub Jenkins+ “GitHub pull request builder plugin”

開発者

Page 8: 『駅すぱあと』新しい開発基盤の研究

GitHub/Jenkins連携

!右下の赤丸のように、ビルド・テストの成否をGitHub上に表示してくれます。

Page 9: 『駅すぱあと』新しい開発基盤の研究

導入による効果

• pull request対応コスト減

• pull requestされた内容について、ビルド・テストが通ることを手動で確認しなくてもよくなった

• 設計やロジックに注力してレビューが出来る

Page 10: 『駅すぱあと』新しい開発基盤の研究

カバレッジ計測

• Jenkins上で計測

• 毎日 AM8:00に1回レポート生成

• 計測にはgcovを使用

• gcovr + Cobertura Pluginで可視化

Page 11: 『駅すぱあと』新しい開発基盤の研究

!カバレッジの推移や現在の詳細な集計結果がレポートとして表示されます。

Page 12: 『駅すぱあと』新しい開発基盤の研究

その他ツール• ビルド構成管理

• CMake

• ユニットテスト

• Google Test

• 静的解析(lint)

• cpplink.py

• cppcheck

• メトリクス計測

• metrix++

• ドキュメント生成

• Doxygen

• コード整形/コンパート

• clang-format

• clang-modernize『駅すぱあと』には未導入のもの、導入しないものもありますが、自分のプロジェクトではこれらを使って開発をしています。

Page 13: 『駅すぱあと』新しい開発基盤の研究

clang-modernize

• C++は2011年に大きな改定があった(C++11)

• C++のコードを「C++11らしい」コードに変換

• 内部的にC++コンパイラ(clang)の技術を使っているので高精度

Page 14: 『駅すぱあと』新しい開発基盤の研究

class Person { std::string name; ! public: explicit Person(std::string name) : name(std::move(name)) { } void greet(const Person &person) const; void greet(const std::vector<const Person *> &friends) const { for (const auto & friends_i : friends) { if (friends_i != nullptr) { greet(*friends_i); } } } };

AFTER

class Person { std::string name; ! public: explicit Person(const std::string &name) : name(name) { } void greet(const Person &person) const; void greet(const std::vector<const Person *> &friends) const { for (std::vector<const Person *>::const_iterator i = friends.begin(); i != friends.end(); ++i) { if (*i != NULL) { greet(**i); } } } };

BEFORE

!ムーブセマンティクス、型推論、range-based for、新キーワード(nullptr)など、C++11の新機能を使ってくれます。

Page 15: 『駅すぱあと』新しい開発基盤の研究

開発環境まとめ・雑感• 自動化の効果は高い

• 単純にコストが減るし、何より単純作業のストレスがなくなるのがうれしいですね。

• もっとツールを使おう

• 手元で実行出来るだけでも楽しいし便利。

Page 16: 『駅すぱあと』新しい開発基盤の研究

運賃計算とDSL

Page 17: 『駅すぱあと』新しい開発基盤の研究

運賃計算?• 基本1

• 乗車した距離に応じて金額が決まる

• →「営業キロ」を求めて運賃表を引く

• 基本2

• 「複乗の禁止」

• → 同じ所を2度通ってはダメ

Page 18: 『駅すぱあと』新しい開発基盤の研究

https://www.jr-odekake.net/railroad/ticket/guide/02.html

Page 19: 『駅すぱあと』新しい開発基盤の研究

!運賃計算の実例を見てみます。高円寺から川崎まで、立川を経由する経路です。

Page 20: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km

本州3社内の幹線の普通運賃表

!高円寺→立川→川崎で通算56.9キロ。運賃表で引くと970円。 通算 56.9km

Page 21: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km高円寺→川崎は 970円…?

本州3社内の幹線の普通運賃表

通算 56.9km

Page 22: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km高円寺→川崎は 970円…?

本州3社内の幹線の普通運賃表

通算 56.9km!実はこの結果は間違い。

Page 23: 『駅すぱあと』新しい開発基盤の研究

●東京・大阪の電車特定区間の普通運賃表 東京・大阪の電車特定区間(次の図の範囲)のみをご利用になる場合は、「電車特定区間の普通運賃表」をご覧ください。

https://www.jr-odekake.net/railroad/ticket/guide/02.html

!この図にある区間は、よく使われる路線のためもう少し割安の運賃表が設定されています。

Page 24: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km電車特定区間の普通運賃表

本州3社内の幹線の普通運賃表

通算 56.9km!通算距離56.9キロを「電車特定区間の普通運賃表」で引くと920円。

Page 25: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km電車特定区間の普通運賃表

高円寺→川崎は 920円…?

本州3社内の幹線の普通運賃表

通算 56.9km

Page 26: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km電車特定区間の普通運賃表

高円寺→川崎は 920円…?

本州3社内の幹線の普通運賃表

通算 56.9km!実はこの結果もまだ不十分。

Page 27: 『駅すぱあと』新しい開発基盤の研究

●大都市近郊区間内のみをご利用になる場合の特例 下図のそれぞれの大都市近郊区間内のみを普通乗車券または回数乗車券でご利用になる場合は、実際にご乗車になる経路にかかわらず、最も安くなる経路で計算した運賃で乗車することができます。

https://www.jr-odekake.net/railroad/ticket/guide/02b.html

!この図にある区間は路線が入り組んでいて目的地までの経路が複数存在するため、常に最安になる経路で計算して良いという特例があります。

Page 28: 『駅すぱあと』新しい開発基盤の研究

!乗車した「高円寺→立川→川崎」よりも「高円寺→新宿→品川→川崎」の経路のほうが安く計算できます。

Page 29: 『駅すぱあと』新しい開発基盤の研究

高円寺

立川

川崎

21.4km

35.5km

高円寺

新宿

品川

5.8km

8.6km

通算 27.8km川崎

11.4km

高円寺→川崎は 470円!

通算 56.9km!ようやく正しい運賃が求まりました。

Page 30: 『駅すぱあと』新しい開発基盤の研究

!紹介した以外にも、運賃計算の特例は無数にあります。

Page 31: 『駅すぱあと』新しい開発基盤の研究

運賃計算

非常に特例が多い

Page 32: 『駅すぱあと』新しい開発基盤の研究

今は?• プログラムで頑張っている

• 運賃計算を行うC言語関数群の中に特例の数だけif文があるイメージ

• →関数設計を工夫しても保守性に限界がある

• →そこでDSL!

Page 33: 『駅すぱあと』新しい開発基盤の研究

DSL?

• Domain Specific Language:ドメイン特化言語

• ある特定領域(ドメイン)の問題を解決するのに特化した言語のこと(⇔汎用言語)

• 例)HTML, CSS, 正規表現, RSpec

Page 34: 『駅すぱあと』新しい開発基盤の研究

ドメイン特化言語 パターンで学ぶDSLのベストプラクティス46項目 http://www.amazon.co.jp/dp/4864010471

!この本がDSLのバイブルです。非常にオススメです。

Page 35: 『駅すぱあと』新しい開発基盤の研究

DSLをなぜ使うのか• 開発者の生産性の向上

• ビジネスロジックをより抽象度の高い言語で表現

• ドメインエキスパートとのコミュニケーション改善

• 問題の文脈に特化した言語なら、開発者以外でも理解しやすい

Page 36: 『駅すぱあと』新しい開発基盤の研究

DSLをいつ使わないのか• プロジェクトで使用する言語が増える

• エンジニアの習得コストが上がる

• →但し、汎用言語の習得コストとは比べ物にならないほど低い

• DSL自体のメンテナンスコスト

• 独自言語を作れば、それをメンテナンスする人が必要

• →表現力を限定することが重要 (チューリング完全になんてしてはいけない!)

!「チューリング完全なDSL」はDSLのよくあるアンチパターンです。それは既に汎用言語です。解決したいドメインに集中し、小さい言語に保たれているのがいいDSLだと思います。

Page 37: 『駅すぱあと』新しい開発基盤の研究

DSLの導入

• まずやること

• かっこいい文法を考える • セマンティックモデルを作成する

• → 問題解決方法を「モデル化」する

Page 38: 『駅すぱあと』新しい開発基盤の研究

モデルの例

if then

main.c util.c

main.h util.h

app

if then

if then

Y Y 20Y N 10N Y 5N N 0

プロダクションルールシステム 依存ネットワーク デシジョンテーブル

!これら以外にも、マーチン・ファウラーの本に様々な例が詳しく紹介されています。

Page 39: 『駅すぱあと』新しい開発基盤の研究

運賃計算のモデル化

「東京近郊区間」のみの利用である

最も安くなる経路で計算

「電車特定区間」のみの利用である

運賃表に「電車特定区間の普通運賃表」を使う

東京で折り返し、神田を通過する列車に乗る

「東京→神田→東京」 区間を除外

「if-then」で表現される一連のルールとして表現できる →今回はこれをクラスで実装してみる

!試しに「プロダクションルールシステム」で表現してみました。実際には、複雑な運賃計算を一つの単純なモデルで表現するのは難しいので、地域やルールの特性で再分割が必要でしょう。

Page 40: 『駅すぱあと』新しい開発基盤の研究

モデルの実装

ConcreteCondition

Rule

<<abstract>> Condition

ConcreteAction<<abstract>> Action

ConcreteCondition

ConcreteAction

ConcreteCondition

ConcreteAction

1件の「ルール」は 「条件」と「アクション」の 組み合わせとして表現

!クラス化したものです。条件とアクションは種類が沢山あるのでabstractクラスを挟んで解決しています。

Page 41: 『駅すぱあと』新しい開発基盤の研究

モデルの実装

ConcreteCondition

Rule

<<abstract>> Condition

ConcreteAction<<abstract>> Action

ConcreteCondition

ConcreteAction

ConcreteCondition

ConcreteAction

具体的な条件 “電車特定区間のみの乗車” ”区間A-Bを通っている”

具体的なアクション ”運賃表Xを使う”

“区間A-Bを除外する” …

Page 42: 『駅すぱあと』新しい開発基盤の研究

言語としてのDSLの作成

• 「モデル」が適切にクラス化出来ていれば、言語としてのDSLは薄いファサード(窓口)としての役割しか持っていない

• 今回の場合、DSLの仕事は条件とアクションのインスタンスを記述に従って組み上げ、ルールのインスタンスを生成することのみ

!この後もスライド中に何度か出てきますが、問題のモデル化がDSL作りの中心です。モデルが しっかりしていれば、その上に用途に応じた複数のDSL言語を作るなんてことも可能です。

Page 43: 『駅すぱあと』新しい開発基盤の研究

DSLの実装方法• 内部DSL:コア言語内に作るDSL

• 例)関数のネストでモデル構造を表現

• rule(condition(…), action(…))

• 例)メソッドチェーンでモデル構造を表現

• rule().condition(…).action(…).end()

Page 44: 『駅すぱあと』新しい開発基盤の研究

DSLの作成rule “電車特定区間の普通運賃表(東京)” do condition “経路全体マッチ” do sections “電車特定区間(東京)” end action “運賃表変更” do pricetable “電車特定区間の普通運賃表” end end !rule “大都市近郊区間内のみをご利用になる場合の特例(東京)” do … end !…

!Rubyで内部DSLを定義した場合のイメージです。Rubyならメタプログラミングな手法を使えばもっとスマートに書けると思います。

Page 45: 『駅すぱあと』新しい開発基盤の研究

DSLの実装方法• 外部DSL:コア言語外に作るDSL

• 例)コア言語でパーサーを用意する

• 独自言語, JSON, YAML, XML, Lua, mruby, …

• 例)コア言語のコードを生成する

• $ ruby codegen.rb > generated.c

Page 46: 『駅すぱあと』新しい開発基盤の研究

DSL作成の注意点• 表現力を限定する

• 「このDSLで何でも書けるように・・・」はNG

• 一般的な作法に倣う

• 開発者がJavaに慣れているなら、コメントは「//」で始まるべき

• 専門用語を使うことを恐れない

• 専門用語があることでドメイン内のコミュニケーションは豊かになる

Page 47: 『駅すぱあと』新しい開発基盤の研究

運賃計算とDSLまとめ・雑感

• 運賃計算は難しい

• 特例のかたまりです。

• DSLで大事なのは問題のモデル化と表現力の限定

• 解決したい問題を明確にしましょう。間違っても何でも書けるDSLを作っちゃダメです。

Page 48: 『駅すぱあと』新しい開発基盤の研究

参考文献/URL• ドメイン特化言語 パターンで学ぶDSLのベストプラクティス46項目 • http://www.amazon.co.jp/dp/4864010471

• 進化するアーキテクチャーと新方式の設計: DSL の使用 - IBM • https://www.ibm.com/developerworks/jp/java/library/j-eaed13/

• きっぷのルール:JRおでかけネット • https://www.jr-odekake.net/railroad/ticket/guide/01.html

Page 49: 『駅すぱあと』新しい開発基盤の研究

ご清聴ありがとうございました