Upgrade to Pro — share decks privately, control downloads, hide ads and more …

10年前のレガシーシステムをサーバーサイドKotlinでフルリニューアルしている話 #jjug_ccc #ccc_g2

10年前のレガシーシステムをサーバーサイドKotlinでフルリニューアルしている話 #jjug_ccc #ccc_g2

JJUG CCC 2017 Fall での発表資料です
◆githubにサンプルプロジェクトあげてます
https://github.com/maeharin/kotlin-dvd-rental-dev

◆Kotlinのイベント「どこでもKotlin」を開催してます!
https://m3-engineer.connpass.com/event/70561/

Hidenori Maehara

November 18, 2017
Tweet

More Decks by Hidenori Maehara

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. 補足:XSLTとは

    View Slide

  15. 補足:XSLTとは

    View Slide

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

    View Slide

  17. つらい_(:3」∠)_

    View Slide

  18. リニューアルだ!

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  29. 3. 技術選定

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  34. なぜAPIサーバーにKotlin?
    Kotlin

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  38. Kotlin
    Null安全

    View Slide

  39. Kotlin
    型推論

    View Slide

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

    View Slide

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

    View Slide

  42. 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エンジニアに親しみやすい構文

    View Slide

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

    View Slide

  44. Spring Boot

    View Slide

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

    View Slide

  46. Doma2

    View Slide

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

    View Slide

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

    View Slide

  49. Vue.js

    View Slide

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

    View Slide

  51. Element

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  55. 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

    View Slide

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

    View Slide

  57. hello world

    View Slide

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

    View Slide

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

    View Slide

  60. 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を作成

    View Slide

  61. $ ./gradlew bootRun
    hello world
    3) 起動

    View Slide

  62. hello world
    以上!

    View Slide

  63. Springの各種機能

    View Slide

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

    View Slide

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

    View Slide

  66. SpringFox
    ● 問題なく使える

    View Slide

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

    View Slide

  68. 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不要に

    View Slide

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

    View Slide

  70. data class FilmResource(
    var name: String = "",
    var isAdmin: Boolean = false,
    var companyId: Int = 0
    )
    Jacksonは
    デフォルト値ありの
    コンストラクタを要

    デフォルト値は使い
    たくないのに。。
    jackson-module-kotlin
    ● APIリクエスト(JSON)をKotlinへマッピング

    View Slide

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

    View Slide

  72. 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を入れるだけ

    View Slide

  73. Doma 2

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  80. @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)

    View Slide

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

    View Slide

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

    View Slide

  83. swagger-codegen

    View Slide

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

    View Slide

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

    View Slide

  86. Rails側コードイメージ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  92. Kotlinに関する様々な話題を取り上げる
    どこでもKotlin
    Deeplerning4jの作者
    Adamさんが突然参

    サーバーサイドKotlin
    Android
    Kotlin/Native
    機械学習
    sendgrid
    拡張関数 Spring Boot
    Ktor
    etc...

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide