Slide 1

Slide 1 text

10年前のレガシーシステムを サーバーサイドKotlinで フルリニューアルしている話 #jjug_ccc #ccc_g2 2017/11/18 JJUG CCC 2017 FALL エムスリー株式会社 前原 @maeharin

Slide 2

Slide 2 text

● 前原 秀徳 ● @maeharin(まえはりん) ● エムスリー株式会社 ● エンジニアチームリーダー、グループ会社取締役等を歴任 ● 好きな言語等:Kotlin、Ruby、Vue.js ● 好きな漫画:ベルセルク(心の支え。悩んだら読む) ● 自慢:ブログ記事が、はてぶ1200超えた ○http://maeharin.hatenablog.com/ 自己紹介

Slide 3

Slide 3 text

・医療に関するWebサービスを多数展開 ・全世界で約400万人の医師会員 ・日本で約25万人の医師会員 エムスリーって何の会社?

Slide 4

Slide 4 text

今回のゴールド・コーヒースポンサーです!

Slide 5

Slide 5 text

Kotlin本、好評発売中! 日本Kotlinユーザグループ代表、長澤太郎が在籍

Slide 6

Slide 6 text

1. リニューアルの背景・概要 2. 経営会議承認までの道 3. 技術選定の理由 4. Kotlin APIサーバーの作り方 5. イベント「どこでもKotlin」の紹介 アジェンダ

Slide 7

Slide 7 text

1. リニューアルの背景・概要

Slide 8

Slide 8 text

今、私たちは10年に一度の システムリニューアルをしてます!

Slide 9

Slide 9 text

医師のキャリア支援事業 (年間売上、数十億規模) システムリニューアルの対象システム

Slide 10

Slide 10 text

とある事業の今期開発予定だけで 約600人日(2年半) という見積りが! 開発スピードの低下が課題

Slide 11

Slide 11 text

● 複数のサブシステムが存在。データとロジックが重複 ● 長年の改修でアーキテクチャが限界 データ重複 200テーブル・2000カラムのう ち、半分くらい重複 ※DB以外に生Luceneも ロジック重複 複雑な依存関係 原因1: 複雑なアーキテクチャ

Slide 12

Slide 12 text

● 複数のサブシステムが存在。データとロジックが重複 ● 長年の改修でアーキテクチャが限界 データ重複 規模感: 200テーブル・2000カラム ※DB以外に生Luceneも ロジック重複 複雑な依存関係 かなり簡素化してこれ...(^ω^) 原因1: 複雑なアーキテクチャ

Slide 13

Slide 13 text

主要システム Ruby on Rails ● ビジネス上優先度の高いシステムはRuby on Rails ● 優先度低いシステムは10年前のシステム ○ → だが、この部分の優先度が高まってきた 10年前の Javaシステム 7年前の Javaシステム 原因2: 10年前のシステムが... Javaの独自FW viewの部分はXSLT!

Slide 14

Slide 14 text

補足:XSLTとは

Slide 15

Slide 15 text

補足:XSLTとは

Slide 16

Slide 16 text

2001〜2002年頃の技術...(^ω^) 補足:XSLTとは

Slide 17

Slide 17 text

つらい_(:3」∠)_

Slide 18

Slide 18 text

リニューアルだ!

Slide 19

Slide 19 text

重複DBや重複ロ ジックを廃止し、API に一元化! リニューアル後のアーキテクチャ

Slide 20

Slide 20 text

控えめに見積もって 生産性2倍以上! WEBアプリ APIサーバー リニューアル後の技術スタック

Slide 21

Slide 21 text

5月 6月 7月 8月 9月 10月 11月 12月 1月 2月 3月 12月上旬に 10年前の部分の リニューアルを リリース! 今の進捗 開発 ▲プロトタイプ作成 ▲経営会議承認 ▲リリース1 開発 ▲リリース2 ▼NOW ※ エンジニア3名で頑張ってます

Slide 22

Slide 22 text

2. 経営会議承認までの道

Slide 23

Slide 23 text

少し触ると障害が起きる 何をやるにも時間がかか りすぎる DBの設計にアンチパ ターンが... アーキテクチャが複雑す ぎる 100テーブルくらい 重複してる... プロジェクト提案前の私の悩み... _(:3」∠)_

Slide 24

Slide 24 text

12人月以上 必要だよな... やるべきだけど、 どこまでスコープにする べきか.. プロジェクト提案前の私の悩み... ビジネスメンバーを どうやって 説得するか... 経営陣をどうやって 説得するか... _(:3」∠)_

Slide 25

Slide 25 text

色々悩んだが、経営会議でプレゼンし、承認! \承認/

Slide 26

Slide 26 text

1. 最優先イシューを、粘り強く見極めた ● 一気に何もかもやろうとすると、終わらない ● とはいえ、局所的な改善では意味がない ● 周りの人に何度も相談し、イシューを定めていく 踠き 挑み 足掻く!! それこそが死と対峙する者の唯一の剣!! ゆめゆめ忘れぬことだ!! by ベルセルク

Slide 27

Slide 27 text

2. 複数案検討し、可能な限り数値化した ● 経営陣を説得する際、数値化は必須と考えた ● 複数案考え、各案のコストやメリットを数値化した ○ 1案だと自分の視野も狭くなるし、経営陣も決められない ● 開発効率化だけでなく、エンドユーザーへの提供価値も織り込 めると話は進みやすい 言葉にすることだけが 気持ちを伝えるすべてではなくてよ ファルネーゼさん by ベルセルク

Slide 28

Slide 28 text

● 私がRuby on Railsで全部で作った ● UIにはVue.jsやmaterial-components-webを使用 ● 早期にリスクを発見できることも ● 自分への自信 → 経営陣への説得力 3. プロトタイプで不確実性をコントロールした 言葉は無粋!!押し通れ!! by ベルセルク

Slide 29

Slide 29 text

3. 技術選定

Slide 30

Slide 30 text

● APIサーバー ○ 重複ロジック・DBを一元化したい ○ 型を用いてカッチリとやりたい ● フロントサーバー ○ 複数のサービスがある 1. メインサイト(Rails、1年前にリプレイス済) 2. サテライトサイト(Java、7年もの...) 3. 管理画面:3種類(Java、10年もの...) ○ 頻繁に改修が入る ○ リッチなUIへのニーズが強い 技術選定のポイント

Slide 31

Slide 31 text

postgresql ElasticSearch メインサイト サテライトサイト postgresql 管理画面(3種) 10年もの 7年もの 生Lucene 生Lucene リニューアル前の技術スタック

Slide 32

Slide 32 text

postgresql ElasticSearch メインサイト サテライトサイト postgresql 管理画面(3種) 10年もの 7年もの 生Lucene 生Lucene リニューアル前の技術スタック 廃止 フルリプレイス

Slide 33

Slide 33 text

postgresql ElasticSearch メインサイト サテライトサイト 管理画面(3種) APIサーバー リニューアル後の技術スタック

Slide 34

Slide 34 text

なぜAPIサーバーにKotlin? Kotlin

Slide 35

Slide 35 text

Kotlinとは Kotlin ● 静的型付けオブジェクト指向言語 ● いわゆる「JVM言語」 ● 開発元:JetBrains ● 2016年2月に正式リリース ○ 2017/11/18 現在、ver1.1.60 ● Apache License ver2.0 ● 特に、Google I/O 2017以降、爆発的な広がり

Slide 36

Slide 36 text

Google I/O 2017 https://twitter.com/Jayroo5245/status/926120722539282432

Slide 37

Slide 37 text

Kotlin ※長澤太郎さんの発表資料より抜粋 スリムなコードベース

Slide 38

Slide 38 text

Kotlin Null安全

Slide 39

Slide 39 text

Kotlin 型推論

Slide 40

Slide 40 text

● 背景: ● チームのRubyエンジニア7-8名(Javaもたまに触る) ● 対象システムの規模感 ○200テーブル、2000カラム(100テーブルがサブシステム重複) ○ソースコード行数:数十万行 ● フロントはゆるく。コアはカッチリやりたい ○型が欲しいという声がメンバーから噴出したことも ○通称:型一揆 Kotlin選択理由

Slide 41

Slide 41 text

● 型:あり(型推論、null safetyも嬉しい) ● エムスリーにはたろう (@ngsw_taro) がいる! ● フレームワーク:Spring Boot(問題なし) ● Java製の社内ライブラリは使えるか:使える ● IDE:IntelliJ IDEA ● 学習コスト:RubyENGは親しみやすい構文(後述) Kotlin選択理由 Kotlin Webアプリケーション 新しいサーバサイドプログラミング 絶賛発売中! エムスリー株式会社 日本Kotlinユーザーグループ代表 長澤 太郎 たろう(@ngsw_taro) ● 言語の将来性:きっとある(Google I/O 2017)

Slide 42

Slide 42 text

Ruby Kotlin a.map {i -> i * 10} a.reduce {sum,n -> sum + n} a.groupBy {i -> i % 2} a.filter {i -> i % 2 == 0} a.map {|i| i * 10} a.reduce {|sum,n| sum + n} a.group_by {|i| i % 2} a.select {|i| i % 2 == 0} (参考)Rubyエンジニアに親しみやすい構文

Slide 43

Slide 43 text

● SpringはオフィシャルにKotlinサポートを宣言 Spring Boot

Slide 44

Slide 44 text

Spring Boot

Slide 45

Slide 45 text

● JavaのDBアクセスフレームワーク ● 2Way-SQL(SQLを外出しできる) ● 社内のJavaプロジェクトでも利用多い ● 「Domaの開発で大切にしている10のこと」に共感 ○ https://qiita.com/nakamura-to/items/099cf72f5465d0323521 Doma2

Slide 46

Slide 46 text

Doma2

Slide 47

Slide 47 text

● Rails5.1でwebpackerが導入された ○ Vue.js等のjsライブラリを用いた開発が楽 ● メインサイトはRuby on Railsで書かれており、リニューアル後も 流用する Ruby on Rails

Slide 48

Slide 48 text

● 仮想DOMを活用したリアクティブなjsライブラリ ● 学習しやすい(チームメンバーからの評価) ● リッチなUIニーズに対応しやすい Vue.js

Slide 49

Slide 49 text

Vue.js

Slide 50

Slide 50 text

● Vue.jsのフレームワーク ● フォームなどのパーツが大量に用意されている ● 管理画面に導入 Element

Slide 51

Slide 51 text

Element

Slide 52

Slide 52 text

● サーバーサイドKotlinは自分のチームでは正解 ○Kotlinの特徴はチームにフィット ○Kotlin x Spring Bootは問題なく動く ○Kotlin自体の学習コストは問題にならなかった ● Kotlinかわいい(^ω^)ペロペロ 技術選定の所感

Slide 53

Slide 53 text

4. Kotlin APIサーバーの作り方

Slide 54

Slide 54 text

githubにあげてます サンプルプロジェクト https://github.com/maeharin/kotlin-dvd-rental-dev

Slide 55

Slide 55 text

postgresql ElasticSearch customer-front admin-front api APIクライアントgem swagger-codegenで自動生 成 サンプルプロジェクトの構成 Kotlin: 1.1.60 Spring Boot: 1.5.8 spring-security-oauth2: 2.2.0 doma: 2.18.0 rails: 5.1.4 vue: 2.5.3 element-ui: 2.0.4 typescript: 2.6.1 rails: 5.1.4

Slide 56

Slide 56 text

DBスキーマ http://www.postgresqltutorial.com/postgresql-sample-database/

Slide 57

Slide 57 text

hello world

Slide 58

Slide 58 text

● hello worldはたった3ステップ 1) SPRING INITIALIZRからDLしたzipを解凍 2) KotlinでRestControllerを作成 3) 起動 hello world

Slide 59

Slide 59 text

Kotlinを選ぶ https://start.spring.io hello world 1) SPRING INITIALIZRからDLしたzipを解凍

Slide 60

Slide 60 text

package com.example.demo.controller import org.springframework.web.bind.annotation.* @RestController class HelloController { @GetMapping fun index():String = "hello!" } Kotlinで書く hello world 2) KotlinでRestControllerを作成

Slide 61

Slide 61 text

$ ./gradlew bootRun hello world 3) 起動

Slide 62

Slide 62 text

hello world 以上!

Slide 63

Slide 63 text

Springの各種機能

Slide 64

Slide 64 text

@RestController @RequestMapping("/api/v1/films") class FilmRestController( private val filmRepository: FilmRepository ) { @GetMapping fun index(): List = ... @PostMapping fun create( @RequestBody @Validated filmParam: FilmParam Springのアノテーション ● 問題なく使える

Slide 65

Slide 65 text

@Configuration @EnableAuthorizationServer class Oauth2AuthorizationServerConfig( private val authManager: AuthenticationManager, private val dataSource: DataSource ) : AuthorizationServerConfigurerAdapter() { @Bean fun passwordEncoder(): BCryptPasswordEncoder = BCryptPasswordEncoder() spring-security-oauth2 ● 問題なく使える

Slide 66

Slide 66 text

SpringFox ● 問題なく使える

Slide 67

Slide 67 text

@RestController @RequestMapping("/api/v1/films") open class FilmRestController( 都度openするの大変。。。 kotlin-springプラグイン ● Kotlinのクラスはデフォルトでfinal ● 普通ならopenが必要だが...

Slide 68

Slide 68 text

classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") apply plugin: 'kotlin' apply plugin: 'kotlin-spring' compileKotlin { kotlinOptions.jvmTarget = "1.8" } compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } ※Spring Initializr経由で作成す るとデフォルトで入る ↑Spring Initializr経由で作成したbuild.gradle(抜粋) kotlin-springプラグイン ● kotlin-springプラグインでopen不要に

Slide 69

Slide 69 text

jackson-module-kotlin ● Kotlinでのjsonの扱いをしやすくする

Slide 70

Slide 70 text

data class FilmResource( var name: String = "", var isAdmin: Boolean = false, var companyId: Int = 0 ) Jacksonは デフォルト値ありの コンストラクタを要 求 デフォルト値は使い たくないのに。。 jackson-module-kotlin ● APIリクエスト(JSON)をKotlinへマッピング

Slide 71

Slide 71 text

data class FilmResource( val name: String, val isAdmin: Boolean, val companyId: Int ) jackson-module-kotlin ● こうしたい

Slide 72

Slide 72 text

compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.0" ※Spring4.3より依存ライブラリに入れれば自動的に registerされるようになった https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin#jackson-kotlin-module jackson-module-kotlin ● jackson-module-kotlinを入れるだけ

Slide 73

Slide 73 text

Doma 2

Slide 74

Slide 74 text

● JavaのDBアクセスフレームワーク ● 2Way-SQL(SQLを外出しできる) https://qiita.com/nakamura-to/items/099cf72f5465d0323521 Doma 2

Slide 75

Slide 75 text

● Spring BootでDoma 2を使うためのstarterあり ● doma-spring-boot-starter Doma 2

Slide 76

Slide 76 text

http://doma.readthedocs.io/ja/stable/kotlin-support/ Doma 2 ● Doma 2はKotlin 1.1.2を実験的にサポート

Slide 77

Slide 77 text

http://doma.readthedocs.io/ja/stable/kotlin-support/ Doma 2 ● EntityをKotlinで書ける

Slide 78

Slide 78 text

http://doma.readthedocs.io/ja/stable/kotlin-support/ Doma 2 ● とはいえ、バージョンアップ時にハマるリスクを少なく したい ● Domaの層は全てJavaで書く。という選択肢

Slide 79

Slide 79 text

● 私達の選択・・・DomaはJava。それ以外はKotlin ○よく触るのはDomaの層ではなく、それを「使う層」 ○「使う層」を全てKotlinにすれば、ほとんどKotlin ○Domaのコード(Java)はdoma-genで自動生成も可能 ■生成されるコードをconfigでカスタマイズ可能 ■さらに細かく制御したければ、テンプレートのカスタマイズも可能 Doma 2

Slide 80

Slide 80 text

@Entity(naming = NamingType.SNAKE_LOWER_CASE) @Table(name = "film") public class FilmEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @SequenceGenerator(sequence = "film_film_id_seq") public Integer filmId; public String title; public String description; SQL実行結果のマッピ ングと捉え、ロジックを 書かないようにした Doma 2 ● Doma 2のEntity(Java)

Slide 81

Slide 81 text

@ConfigAutowireable @Dao public interface FilmEntityDao { @Select FilmEntity selectById(Integer filmId); @Select List selectAll(); @Insert int insert(FilmEntity entity); Doma 2 ● Doma 2のDao(Java)

Slide 82

Slide 82 text

レイヤー構造 application domain infrastructure RestController ApplicationService Model, ValueObject Repository(interface) Repository(impl) Doma(Dao, Entity) doma-genでDBスキーマから 自動生成も可能 Kotlin Java Doma 2 よく触る部分は 全部Kotlin!

Slide 83

Slide 83 text

swagger-codegen

Slide 84

Slide 84 text

postgres ElasticSearch customer-front admin-front api APIクライアント gem swagger-codegen で自動生成 swagger-codegen ● APIクライアントを手動で作るのは中々しんどい ● swagger-codegenで自動生成できる

Slide 85

Slide 85 text

Spring Boot (APIサーバー) API定義ファイル(json) Swagger UI (WEB GUI) SpringFoxで API定義ファイル生成 API定義ファイルを利用 swagger-codegen コマンド Rubyクライアント 自動生成 swagger-codegen ● SpringFoxでswagger definition(json)を生成 ● そのjsonをswagger-codegenに食わせる

Slide 86

Slide 86 text

Rails側コードイメージ

Slide 87

Slide 87 text

● 詳しくはこちらのスライドをご参照ください 少しだけハマりどころ(回避可能)がある https://speakerdeck.com/juntaki/swagger-codegende-apikuraiantogem-zi-dong-sheng-cheng-number-m3kt

Slide 88

Slide 88 text

● Kotlin x Spring BootでAPIサーバーは問題なく作れる ● kotlin-springプラグインでopen不要 ● jackson-module-kotlinでjsonの扱いが楽に ● 私達はDoma 2の層をJavaにした ○→ よく触る部分はKotlin ● Kotlinかわいい(^ω^)ペロペロ Kotlin APIサーバーの所感

Slide 89

Slide 89 text

5. 「どこでもKotlin」の紹介

Slide 90

Slide 90 text

エムスリー主催のKotlinのイベント「どこでもKotlin」を開催 どこでもKotlin イベント発足の想い

Slide 91

Slide 91 text

今年の8月からはじめて、計3回開催 どこでもKotlin フリー素材と化す たろうさん...

Slide 92

Slide 92 text

Kotlinに関する様々な話題を取り上げる どこでもKotlin Deeplerning4jの作者 Adamさんが突然参 加 サーバーサイドKotlin Android Kotlin/Native 機械学習 sendgrid 拡張関数 Spring Boot Ktor etc...

Slide 93

Slide 93 text

第3回目のLT大会では社外の方々がご登壇 どこでもKotlin Retty 石田 憲幸さん Kotlinで型安全なSQLを書こう サイバーエージェント 木村 正弘さん 運用中のJavaプロジェクトにKotlinを導入した話 構造計画研究所 菊田 洋一さん Kotlin x SendGridでメール送信してみた FiNC Matthew Vernさん Android Things me to Sleep

Slide 94

Slide 94 text

11/22(水)19:30〜 どこでもKotlin#4 〜秋のLT大会 その弐〜 @クラウドワークス(恵比寿) どこでもKotlin connpassにて 参加受付中!

Slide 95

Slide 95 text

● Kotlinいいですよ! ● リニューアルがきっかけでKotlinerの輪が広がった ● 社内の別プロジェクトもサーバーサイドKotlin導入決定! まとめ

Slide 96

Slide 96 text

ご清聴 ありがとうございました Have a nice Kotlin!