大規模映像配信サービスの
Java8による全面リニューアルの裏側
Hello!
氏名 秋穂 賢(あきほ すぐる)
所属 株式会社U-NEXT システム開発部
リリース管理や開発用ミドルウェア管理
DBFlute & Java8でのAPI開発 など
見習いスクラムマスターとして精進中
仕事
このページ以降、U-NEXTは
サービス名称を表します
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction
2015/10/8
全面リニューアルを実施!
◉ 12万本以上の映像コンテ
ンツ
◉ 20万冊以上の電子書籍
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction/device
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction/family
そもそもU-NEXT?
最新情報はWebで http://video.unext.jp/introduction/fee
そもそもU-NEXT?
2015年2月〜
2015年10月〜
そもそもU-NEXT?
◉ 動画配信サービスを軸として、書籍・音楽コンテンツのサービスも
提供
◉ 多種多様なデバイス・複数アカウント
◉ 見放題・ポイント
◉ 各社とアライアンスを提携
◉ FHD配信・アダプティブストリーミング配信
◉ コンテンツホルダーに応じた最高ビットレートのフレキシブルな制御
◉ などなど....
細やかな制御
第1章
リニューアルの背景
U-NEXTの歴史
Pay per
View開始
GyaONEXT
サービス開始
マルチ
デバイス
2007年6月
1デバイス1顧客
デバイス認証
見放題のみ
2008年11月
都度課金の仕組み
コンテンツDB
顧客・課金DB
2010年6月
TVデバイス対応
オンライン認証
の仕組み
新
顧客課金DB
新
顧客課金DB
PlayStati
on Vita
U-NEXT
TV
PC
スマホ
タブレット
2012年 2014年
増える対応デバイス
● 様々な環境と異なるバージョンで動いていたPHP
● 様々なPHPアプリケーションから直接リクエストされる
DB
● 各テーブルが触るな危険状態に
● 新しいサービスを開始する際には同じようなテーブル
が次々と拡張されていく
2007年から拡張し続けた複雑怪奇
なシステム
アニメ放題サービス提携の決定
これ以上の拡張は不可能
アニメ放題の先を見据えて
既存システムを捨て
U-NEXTサービスサイトの
リニューアルを決断
U-NEXT
大幅
リニューアル
2015年10月
アニメ放題
サービス開始
2015年2月
リニューアルで目指す姿
性能にこだわるシステム
よりよいユーザ体験の為に性能にこだわる
アプリケーションだけでなく
システムアーキテクチャとして高い性能を出せるような
設計に
メンテナンス性の高いシステム
DBの集中管理
● どのDBがどのアプリケーションからアクセスさ
れているか、管理したい
● DB毎に管理するAPIを実装する方針に
アーキテクチャの最適化を測った結果
自然とマイクロサービスアーキテクチャ
よりの思想に
(実際はミディアムサービスくらい)
FW選定
FW選定で重視したポイント
● 強力なORM
○ 生のSQLは書かなくてもよいように
■ 人によって書くSQLが違うとか...
○ DB Migration機能
● 静的型付け言語
○ 規模の大きな開発
○ IDEによるサポート
○ コンパイルによるエラー検知
● PlayFramework
● (NodeJS + TypeScript)
● DBFlute
いくつかの選択肢があった
縁があってDBFluteメインコミッターのjfluteさん
にDBFluteを紹介してもらえることに
● DBFluteの強力なORM
● DB Migrationツール
● コードとドキュメント自動生成
● Javaによる静的型付けとコンパイル
● IDEのサポート
● 豊富な公式ドキュメント
● (24時間戦えるjfluteさんが開発してる)
DBFluteとの出会い
何より
DBFlute / SAFluteはサービス開発のためのFW
サービス開発で便利な機能が豊富
(詳細は後ほど)
DBFluteとの出会い
これらのメリットからORMはDBFluteに決定
WebFWは一緒に紹介してもらったDBFluteとの
親和性が高いSAFluteに
DBFluteとの出会い
Java8
+
DBFlute / SAFlute
第2章
アニメ放題サービスの開始
◉ 迫り来る決まったリリース日
◉ 決まらない要求仕様
◉ この期間でサーバ構成を検討
◉ そして開発メンバーがDBFluteの習得
○ jfluteさんが勉強会をひらいてくれた
○ DBFluteハンズオン(チュートリアル)をしっかり実施
アニメ放題
http://dbflute.seasar.org/ja/tutorial/handson/
DBFluteハンズオン?
DBFluteハンズオン = DBFluteのチュートリアル
セクション1 〜 セクション11で構成されている
DBFluteハンズオンで修行する
=
業務で出てくる技術の習得
http://dbflute.seasar.org/ja/tutorial/handson/
DBFlute Live Demo
そんなDBFluteを生で見てもらいます
サーバ構成
クライアントむけの
API
永続層は持たない
リバースプロキシ
のキャッシュ
コンテンツDBを
管理するAPI
コンテンツDB
Slaveに全文検索エ
ンジンのMroonga
MySQL Atlas
中国企業のOSS
SB認証基盤
コンテンツと紐付
いたユーザ情報
のDB
アーキテクチャ課題
クライアントむけの
API
永続層は持たない
リバースプロキシ
のキャッシュ
コンテンツDBを
管理するAPI
コンテンツDB
Slaveに全文検索エ
ンジンのMroonga
MySQL Atlas
中国企業のOSS
SB認証基盤
コンテンツと紐付
いたユーザ情報
のDB
① ②
③
課題1 Redisへのアクセス
大きく2種類の使い方
◉ データキャッシュとしてのRedis
○ マスタデータはDBに格納
○ キャッシュとしてRedis上にも保存
○ ユーザDBのデータはキャッシュへ
◉ データストアとしてのRedis
○ マスタデータをRedisに格納
キャッシュを意識しないデータのCRUD
構造を意識したデータのCRUD
キャッシュとしてのRedis
◉ 対象テーブル毎にCRUDのI/Fを持ったLogicクラスを実装
○ キャッシュを意識したくないテーブルを作るタイミングでLogicクラ
スも一緒に実装
◉ RedisへのアクセスはFacadeを使って統一で使い回し
○ insert or update時には内部でキャッシュを削除
○ delete時は一緒にキャッシュを削除
○ select時はキャッシュがあればキャッシュから、なければDBから
のデータをキャッシュに
◉ 内部ではJedisを利用
キャッシュを意識しないデータのCRUD
キャッシュとしてのRedis
@Resource
protected ViewingHistoryCacheLogic viewingHistoryCacheLogic;
…
UsrViewingHistory viewingHistory = new UsrViewingHistory();
viewingHistory.setUserId(userId);
…
viewingHistoryCacheLogic.insertOrUpdate(viewingHistory);
ViewingHistoryParam param = new ViewingHistoryParam();
param.setUserId(userId);
param.addOrderByList(ViewingHistoryDbm.getInstance().
columnUpdateDatetime());
…
return viewingHistoryCacheLogic.getList(param);
データストアとしてのRedis
◉ Logic / Facadeクラスは変わらず実装
◉ もう一歩発展
◉ jsonでスキーマ定義
◉ それを元に共通して使えるクラスについてテンプレート化
○ Velocityテンプレートを利用
○ DBFluteの自動生成の仕組みに乗せて、Redisにスキーマ定義を
もたせて自動生成!!
◉ IDEのコード補完の恩恵を存分に受けられるように
構造を意識したデータのCRUD
データストアとしてのRedis
EVALUATION: {
$comment : "評価点",
$type : "table",
PLATFORM_CODE : {
type: "varchar",
comment: "プラットフォームコード",
kvsKey: true ,
notNull: true },
SAKUHIN_CODE : {
type: "varchar",
comment: "作品コード",
kvsKey: true,
notNull: true },
EVALUATION_POINT : {
type: "varchar",
comment: "評価点",
notNull: true },
TTL : {
type: "java.time.LocalDateTime",
comment: "有効期限",
notNull: true
}
}
public class EvaluationMeta
implements KvsStoreMeta {
…(Meta data. name, column, ...)
}
public class BsEvaluation
implements KvsStoreEntity,
Serializable {
…(getter / setter / util methods)
}
public class Evaluation extends
BsEvaluation {
… (extends local methods)
}
自
動
生
成
◉ 本当は専用の検索エンジン(Solr/Elasticsearch)を使いたかっ
た
◉ 時間の都合上、手軽に全文検索ができるMroongaを選択
◉ 一部Slaveの全文検索したいテーブルだけのEngineを
Mroongaにして利用
○ 初めて利用するため、何かあった場合の影響を最小限に
課題2 Mroongaへの対応
Mroonga?
Groongaをベースとした全文検索エンジン。MySQLのストレー
ジエンジンの1つとしてMySQLに全文検索機能を提供
課題2 Mroongaへの対応
Mroongaを使うとSQLで手軽に全文検索が出来る
DBFluteはmatch構文をサポート
mysql> SELECT * FROM diaries WHERE MATCH(content) AGAINST("fine");
+----+-----------------------------------------+
| id | content |
+----+-----------------------------------------+
| 1 | It'll be fine tomorrow. |
+----+-----------------------------------------+
1 row in set (0.00 sec)
課題2 Mroongaへの対応
Engine
Innodb
Engine
Innodb
Engine
Innodb
Mroonga
Mroongaへの検索かど
うかで向け先を変える
課題2 Mroongaへの対応
Engine
Innodb
Engine
Innodb
Engine
Innodb
Mroonga
Mroongaへの検索かど
うかで向け先を変える
SelectableDataSource
SelectableDataSource
◉ Seasar2が提供しているMaster/Slaveを切り替える仕組
みを利用
// e.g. SelectableDataSource のベタな実装方法 @Java
protected MemberBhv memberBhv;
protected DataSourceFactory dataSourceFactory; // injected
public void fooAndBar() {
dataSourceFactory.setSelectableDataSourceName("master");
Member member = ...
...
memberBhv.update(member); // master の会員を更新
dataSourceFactory.setSelectableDataSourceName("slave");
MemberCB cb = ...
...
... = memberBhv.select(cb); // slave の会員を検索
}
http://dbflute.seasar.org/ja/manual/reference/diway/seasar/selectabledatasource.html
SelectableDataSource
◉ SAFluteの機能を使ってSelectableDataSourceをベー
スに汎用性を持たせて使いやすいようにして利用
PagingResultBean<Sakuhin> sakuhinPage =
slaveDBAccessor.accessIfNeeds(() -> {
return sakuhinBhv.selectPage(cb -> {
cb.specify()....
cb.query()....
});
}, isNotEmpty(searchWord));
http://dbflute.seasar.org/ja/manual/reference/diway/seasar/selectabledatasource.html
検索ワードがあれば強制的にSlave
へ
Slaveのhost設定をMroongaな
MySQLへ向くように設定
◉ MySQL Atlasはトランザ
クションを更新処理とみ
なしてmasterへ
◉ SAFlute(SAStruts)はリク
エストでトランザクション
◉ 各API毎に自前でトラン
ザクションをかけるのは
つらい
課題3 MySQLとAtlas
ここのLBは
MySQL Atlas
にお任せ
LazyTransaction
◉ 更新系処理が開始した時点で初めてトランザクションを開始す
るように
◉ DBFluteでBehavior(SQL実行)の処理前後にHookができる
LazyTransaction?
protected BehaviorCommandHook createLazyTransactionHook() {
return new BehaviorCommandHook() {
public void hookBefore(BehaviorCommandMeta meta) {
if (!meta.isSelect() || meta.isProcedure()) {
LazyHookedUserTransaction.beginRealTransactionLazily();
}
}
public void hookFinally(BehaviorCommandMeta meta, RuntimeException
cause) {
}
@Override
public boolean inheritsExistingHook() {
return true;
}
};
}
SAFluteのリクエ
スト開始時点の
Hookへ登録
◉ 課題1 Redisへのアクセス
○ キャッシュ / ストアとしての使い方
○ FacadeやLogicで処理をまとめたり、DBFluteの自動
生成機能に乗せて独自の自動生成機能を作った
◉ 課題2 Mroongaへの対応
○ DBFluteのSelectableDataSourceを使ってMaster
/ Slaveの切り替えを汎用的に実装
◉ 課題3 MySQLとAtlas
○ BehaviorCommandHookを使って全てのBehavior
の実行前にHookを入れることでLazyTransaction機
能を実現
アーキテクチャ課題への対応
Special Thanks
アーキテクチャ周りはDBFluteコアユーザの
@p1us2er0 さん
に多大なるご協力を頂きました
その他
日々のサービス開発で
便利なこと
工夫してること
などなど
一挙にご紹介!!6連発
DB変更を行うとき、どのようにしていますか?
DBFluteの場合、こんな感じです
1. ERDドリブン開発
1. ERDドリブン開発
1. EclipseプラグインのERMasterでER図を変更
1. ERDドリブン開発
2. ERMasterからDDLを出力
1. ERDドリブン開発
3. manage.shのrenewalを実行
renewalはDB定義から
Javaのエンティティクラスな
どを自動生成する機能
1. ERDドリブン開発
4. DB変更した内容のJavaが自動生成
1. ERDドリブン開発
4. DB変更した内容のJavaが自動生成
DB変更完了!
U-NEXTではDBFluteの流儀に沿って
DB変更する場合はまずERDを修正する
というフローで実施
ER図と実態が一致しない、はありえない
2. ReplaceSchema
テストデータを追加
開発メンバーと共有 & 最新化
みなさんどのようにやってますか?
DBFluteの場合、こんな感じです
2. ReplaceSchema
1. テストデータの修正と出力
1. まず、MySQLへテストデータ
を追加
2. manage.shでload data
reverse実行!
3. DBに入っているテストデータ
がxlsやtsv形式で出力
4. git commit & push
http://dbflute.seasar.org/ja/manual/function/generator/task/doc/loaddatareverse.html
2. ReplaceSchema
2. データ共有 & Load
1. git pull
2. sh manage.sh
3. 0
4. Enter!
http://dbflute.seasar.org/ja/manual/function/generator/task/doc/loaddatareverse.html
drop table
create table
insert into
2. ReplaceSchema
2. データ共有 & Load
1. git pull
2. sh manage.sh
3. 0
4. Enter!
http://dbflute.seasar.org/ja/manual/function/generator/task/doc/loaddatareverse.html
drop table
create table
insert into
修正したデータをgit経由で簡単に共有
開発前にReplaceSchemaをしておけば
テストデータの共有漏れは起こらない
3. AlterCheck (DB Migration)
ローカルと開発と本番のDBスキーマが違う!
なんてことが起こらないようにするための
DB Migrationツール
DBFluteの場合、こんな感じです
DB変更後にmanage.shの8
◉ 前回のDBの状態で
ReplaceSchema
◉ 最新のDBの状態で
ReplaceSchema
◉ 前回と今回の差分を提示し
てFailure
3. AlterCheck (DB Migration)
3. AlterCheck (DB Migration)
差分を確認
alterSQLを定義
今回の場合は
create table hoge
再度AlterCheckで
Success!
後は各環境へ差分を
反映させるだけ
3. AlterCheck (DB Migration)
差分を確認
alterSQLを定義
今回の場合は
create table hoge
再度AlterCheckで
Success!
AlterCheckを運用として実施していくことで
各環境でのDBスキーマで差分が出ないように
4. Schemaドキュメント
ER図だけでなく、DBFluteはHTML形式のドキュメントも自動
生成してくれる
4. Schemaドキュメント
ER図だけでなく、DBFluteはHTML形式のドキュメントも自動
生成してくれる
U-NEXTでは
人によってER図とSchema.htmlを
使い分けて開発作業を行っている
5. 見やすいログ
開発やテスト時は何度もデバッグを行うため、ログが見やすい
ことは重要
今回は一部のログをご紹介
http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html
5. 見やすいログ
Requestの開始と終了
http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html
...-DEBUG (...#before():268) - * * * * * * * * * * {BEGIN}: /member/list/
Request class=org.seasar.framework.container.hotdeploy.HotdeployHttpSer...
, REQUEST_URI=/dockside/member/list/, SERVLET_PATH=/member/list/, Chara...
, ContentType=application/x-www-form-urlencoded, Locale=ja, Locales=ja,...
...
...
Response class=org.mortbay.jetty.Response, ContentType=text/html; chars...
, toString()=HTTP/1.1 200 Content-Type: text/html; charset=utf-8 Expir...
[session] javax.servlet.jsp.jstl.fmt.request.charset=UTF-8
[session] member_memberListForm=org.dbflute.maihama.app.web.member.
Memb...
[session] org.apache.struts.action.LOCALE=ja
[session] org.dbflute.maihama.domainfw.action.DocksideUserBean={userId=...
* * * * * * * * * * {END}: /member/list/ [00m00s247ms]
5. 見やすいログ
SQLの実行時間と結果概要
http://dbflute.seasar.org/ja/manual/function/helper/saflute/friendlylogging.html
2016-05-20 17:28:22,346 [main]-DEBUG (XLog#log():43) -
SakuhinListActionTest.testname():131 -> ...
2016-05-20 17:28:22,693 [main]-DEBUG (QLog#log():43) -
select dfloc.SAKUHIN_ID as SAKUHIN_ID, dfloc.DISPLAY_NAME as
DISPLAY_NAME
from SAKUHIN dfloc
where dfloc.SAKUHIN_ID = 1
2016-05-20 17:28:22,694 [main]-DEBUG (XLog#log():43) - ===========/
[00m00s348ms (1) result={1, null, ほげ作品, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null}@729c021d]
5. 見やすいログ
その他、色々とログが見やすく工夫されています
詳細は公式ページで!
http://dbflute.seasar.
org/ja/manual/function/helper/saflute/friendlylogg
ing.html
6. 書きやすいUT
みなさん、テストは書いていますか?
UTFluteを使えば楽々テスト
UTFluteはDBFluteファミリーのJUnit拡張ライブラリ
UTFlute は、自分で new したものにDIできる JUnit
拡張 です。
http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html
6. 書きやすいUT
ActionクラスのisHogeメソッドを実行してbooleanを
Assert
public void test_isHoge_hogeはhogeだったらtrue() throws Exception {
// ## Arrange ##
SakuhinListAction action = new SakuhinListAction();
inject(action);
// ## Act ##
boolean isHoge = action.isHoge("hoge");
// ## Assert ##
assertTrue("hogeはtrueだ", isHoge);
}
http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html
6. 書きやすいUT
http://dbflute.seasar.org/ja/manual/function/helper/utflute/index.html
UTFluteのおかげで単体テストの自動化は結構して
いる
◉ JenkinsでのCIも実施
○ エラーが出たらHipChatに通知
◉ UTで事前に不具合を検知できた
コード品質が向上!
その他、UTFluteでの便利機能が提供されています
詳細は公式ページで!
http://dbflute.seasar.
org/ja/manual/function/helper/utflute/index.html
6. 書きやすいUT
アニメ放題
無事に予定通りリリース!!
振り返ってみると
◉ 最初にDBFluteハンズオンをみっちりと実施した効果は
大
○ 業務アプリ実装時に役立つTipsがたくさん
◉ 困った時の拡張ポイントがしっかりしてる
○ アーキテクチャ課題は無事にクリア
◉ その他諸々サービス開発で役立つ機能
○ 細かいけどあったらとても役立つ機能がたくさん
第3章
U-NEXTサービスサイト
リニューアル
◉ アニメ放題と比較すると遥かに複雑な業務
○ アニメ放題はアニメのみ、U-NEXTは洋画・邦画・ドラマなど、ジャン
ルの多さ
○ アニメ放題はiOS/Android/PC、U-NEXTはTV、ゲーム機、STBなど、
対応デバイスの多さ
○ アニメ放題は見放題のみ、U-NEXTは見放題と単品でのレンタル作
品も
○ U-NEXTはユーザへの見せ方がよりきめ細やか
◉ 複雑な業務 = 開発が大変
◉ 複雑な業務 = 複雑なDB
U-NEXTリニューアルでの難関
API数
10倍程度のAPI
テーブル数
125テーブル から253テーブルに
(区分値除く 29 => 89)
激しいDB変更の嵐
DBFlute採用から約1年半、DB変更の回数は 186 回
=> 単純計算すると 約 3 日に 1 回はDB変更してる
毎日のようにER図を変更して
AlterCheckして
本番へDDL実行!をしていた日々もあった
怒涛のDB変更ラッシュもDBFluteで乗り越えた
検索のインクリメンタルサーチを目指していた
=> Mroongaでは性能で不利
ElasticsearchとSolrが候補に
「検索」の実績から Solr を選択
Demo:http://video.unext.jp
詳細:http://www.slideshare.net/SuguruAkiho/20151028-17-solr-unext
MroongaからSolrへ
solrjをそのまま使うとタイプセーフではない...
MroongaからSolrへ
try (HttpSolrClient httpSolrClient = new HttpSolrClient(“http://localhost:
8983/solr/schema”)) {
httpSolrClient.setParser(new XMLResponseParser());
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "あの日");
params.add("defType", "dismax");
params.add("qf", "name kana^10");
QueryResponse response = httpSolrClient.query(params);
SolrDocumentList results = response.getResults();
}
…
Schema.xmlから各種クラスを自動生成
全文検索システムFessで使っていたSolr用CBを拡張
MroongaからSolrへ
SolrPagingResultBean<General> list = generalBhv.selectPage(cb -> {
cb.query().dismax("あの日", queryField -> {
queryField.put(GeneralMeta.Name, null);
queryField.put(GeneralMeta.Kana, 10);
queryField.put(GeneralMeta.NameGeneral, 20);
queryField.put(GeneralMeta.Synonym, null);
});
cb.specify().fieldUid();
cb.paging(10, 2);
});
LOG.debug("list={}", list);
DBFluteの機能で
ページング検索が
出来る
dismax検索出来る対象
のフィールドがタイプ
セーフに指定可能
specifyでflをタイプセー
フに指定可能
MroongaからSolrへ
とある1日のフリーワード検索の平均レスポンス:39ms
2016年9月26日、Seasar2のサポートが終了
SAFluteはSAStrutsの拡張FW
リニューアルが終わってないのにFW移行の危機...
そんな時、jfluteさん
「Seasar2フォークしてJava8で書き換えてLastaFlute
作っちゃった」
SAFluteからLastaFluteへ
2016年9月26日、Seasar2のサポートが終了
SAFluteはSAStrutsの拡張FW
リニューアルが終わってないのにFW移行の危機...
そんな時、jfluteさん
「Seasar2フォークしてJava8で書き換えてLastaFlute
作っちゃった」
SAFluteからLastaFluteへ
使うしかないでしょう
LastaFluteのいいところ
◉ 起動が圧倒的に早い
○ SAFluteは7〜8秒程度、Lastaは2〜3秒程度
◉ ログが見やすい
○ DBFluteイズムで見やすいログ
◉ よりシンプルに書けるコード
○ formが引数, formで型定義、Hibernate Validatorが使え
る、などなど
APIドキュメント自動生成
API開発をしている場合、クライアントへI/F定義を提示
する必要がある
=> 自動生成
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
膨大な開発
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
2015年 8月へ延期
 開発..開発..開発..開発..開発..開発..
膨大な開発
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
2015年 8月へ延期
 開発..開発..開発..開発..開発..開発..
2015年 9月へ延期
 開発..開発..開発..開発..開発..開発..開発..開発..開発..
膨大な開発
膨大な開発
2015年 6月U-NEXTリニューアルリリース予定
 リニューアルに向けて開発..開発..開発..
2015年 8月へ延期
 開発..開発..開発..開発..開発..開発..
2015年 9月へ延期
 開発..開発..開発..開発..開発..開発..開発..開発..開発..
2015年 10月9日へ延期
 開発..開発..開発.. リリース!!
ボリューム満点の開発
SAFlute / LastaFlute / DBFluteの軽快さ
実装 => リリース => 修正 => リリース => …
のサイクルをとても軽快に回すことが出来る
リニューアルを乗り越えられたのは
この軽快さのおかげ
膨大な開発
第4章
更なる高みへ
リニューアルで全力疾走を続けた結果
◉ 個々のソロプレーを足しあわせて何とかなっていた
○ チーム力・組織力が全くない状況
◉ ソースコードがちぐはぐ
○ とにかく動くコードを早くリリースするのが正義
○ その結果、ちぐはぐなコードが生まれる
○ それでもテストコードは書いてCIはしていたし、DBFlute部分の
コードは問題なし
■ これはDBFluteハンズオンのおかげ
約1年半の開発である程度の技術的負債が生まれた
スクラム開発
◉ 今まで
○ 複数人のディレクターやQAからの要望を各分野に精通している人
が個々の判断で優先度を決定し、開発
◉ これから
○ スクラム開発を導入
○ 優先度はプロダクトオーナーが決定
○ 開発タスクは開発チームで決定
○ 2週間のスプリント
○ スプリント計画ミーティングで実装タスクを決定
○ デイリースクラムで日々の状況や問題点を洗い出し
○ スプリントレビューで成果物の検査
○ スプリント振り返りでよりよいやり方に改善
○ ビジネス開発:アーキテクチャ改善・リファクタリング=7:3
より働きやすい環境
◉ ハイスペックな開発マシン
○ メモリ32GB、250GB SSD、インテル® Core™i7-
5930k
◉ 高級なイス(予定)
○ 候補:アーロンチェアなど
◉ 自由に買える書籍
○ 申請して5分後に電子書籍が届くとか
◉ 定期的に開催される勉強会
○ スクラム読書会
○ 機械学習の勉強会
○ データベースの勉強会 etc...
コードの品質
◉ これまで
○ コードを書いた人以外の目に触れずに本番へリリースされる
コードがたくさん
◉ これから
○ コーディングガイドラインを整備
■ 規約は文章化せず、自動で判別できるものに
○ プルリクベースでのコードレビューを導入
○ 対面でのコードレビュー会を導入
チーム内でよりよいコードを書く
という意識が芽生え始める
より良いアーキテクチャへ
◉ 当初目指していたDB単位のAPI
○ これは実現出来た
○ DB変更は比較的簡単に出来る
◉ リポジトリはそれなりにでかい
○ 分割出来るプロジェクトが同じリポジトリに存在している
■ 時間の都合上
◉ もっと最適に分割出来る
マイクロサービスアーキテクチャの思想で
アーキテクチャをリファクタリグ
(やりすぎないようにミニマムサービスくらいを目指して)
◉ まだまだたくさんある開発案件
○ これからはチームでよりよいものをより楽しく開発出来るように
○ そして競合に負けないように
◉ 個々の技術力
○ コードレビュー・勉強会などを通じてメンバーそれぞれがお互いを
高め合える環境・そして文化に
◉ より最適なアーキテクチャに
○ 既存の技術的負債を放置せず、少しずつ返却していく
○ 2年後、3年後も楽しく開発出来るように
今後
U-NEXTでは人材を募集しています
映画やアニメが好きなひと
エンターテイメントが好きなひと
配信プラットフォームに興味のあるひと
技術的なことが好きなひと
一緒に仕事をしましょう
http://unext.co.jp/recruit/
Thank you for your attention

20160521 大規模映像配信サービスの Java8による全面リニューアルの裏側