GMOインターネット株式会社
⽥中 ⾼進
新卒3年⽬が⽴ち向かった
お名前.comでの
超巨⼤レガシーシステム脱却の事例
JJUG CCC 2019 Fall #ccc_a6a
レガシーなシステムとは︖
3
レガシーコードとは
意図した通りには動作するが、
内部のコードが複雑化し、
拡張や修正が必要な場合に
保守コストが⾼くなるコードです。
参考⽂献: https://www.oreilly.co.jp/books/9784873118864/
レガシーコードの定義
レガシーなシステムとは︖
4
レガシーなシステムとは
レガシーコードで出来ているシステム
・内部のコードが複雑化している
・拡張や修正時の保守コストが⾼い
レガシーなシステムとは︖
レガシーなシステムの定義
このシステムを参考に開発お願いします
確認します︕
ドキュメントが存在しない・・・
独⾃実装でわかりづらい・・・
単体テストがない。正しさが分からない︕
これがうわさのレガシーなシステム︖
⾊々問題がありそう︕
レガシーなシステムから
脱却をしよう︕︕
9
アジェンダ
l お名前.comの紹介
l 今回のプロジェクトの概要と課題
l 問題点ごとの解決策(仕様・実装・テスト)
l 結果どうなったのか
10
アジェンダ
l お名前.comの紹介
l 今回のプロジェクトの概要と課題
l 問題点ごとの解決策(仕様・実装・テスト)
l 結果どうなったのか
11
お名前.comの紹介
国内最⼤級のドメイン公式登録サービスです
サービス開始から20年となります
バックエンドは、Javaで動いています
12
アジェンダ
l お名前.comの紹介
l 今回のプロジェクトの概要と課題
l 問題点ごとの解決策(仕様・実装・テスト)
l 結果どうなったのか
13
今回のプロジェクト概要と課題
新卒3年⽬の⾃分に
RDAPの開発を任されました
14
RDAPとは︖
今回のプロジェクト概要と課題
WHOIS RDAP後継プロトコル
ドメイン
新規
15
WHOISとRDAPの違い
今回のプロジェクト概要と課題
Ø ⼤きな違いとしては、データフォーマットが違う
Ø RDAPでは、ユーザー⽬線となっている
フォーマットの統⼀化
TEXT
WHOIS
JSON
RDAP
16
締切&仕様
ICANNの指⽰に従う必要がある
上位機関 レジストラ
締切と仕様は決められている
今回のプロジェクト概要と課題
17
ドメインとは︖
ドメインとは
今回のプロジェクト概要と課題
インターネット上の住所
150.95.237.28
www.onamae.com
18
WHOISとは︖
今回のプロジェクト概要と課題
ドメインは誰が保有しているか公開しなければならない
WHOIS
ドメインの所有者は運⽤、管理などでトラブルが起きない
ように情報を公開する義務がある
19
ドメイン情報
20
コンタクト情報
21
WHOISとRDAP
今回のプロジェクト概要と課題
WHOIS RDAP後継プロトコル
TEXTからJSONへ(RESTful)
問い合わせ結果フォーマットが統⼀
22
RDAPサンプル
今回のプロジェクト概要と課題
https://rdap.gmo-onamae.com/rdap/v1/domain/onamae.com
ブラウザなどで、下記のリンクにアクセス
23
24
今回のプロジェクト概要と課題
WHOISの実装を参考に
RDAPを開発していく予定だった
25
今回のプロジェクト概要と課題
しかし実装を確認すると
レガシーな状態にあった
26
アジェンダ
l お名前.comの紹介
l 今回のプロジェクト概要と課題
l 問題点ごとの解決策(仕様・実装・テスト)
l 結果どうなったのか
27
問題点を確認してみた
28
l 流⽤元の仕様に関するドキュメントなどがない
l 複雑化している箇所があり、修正が困難
l 単体テストのテストコードが存在しない
現状の問題点
問題点ごとの解決策(仕様・実装・テスト)
29
問題点ごとの解決策
(仕様編)
30
Ø 流⽤元の仕様に関するドキュメントなどがない
Ø ソースを⾒ても、意図がわからない
Ø 微妙な実装があったとき、ソースが仕様通りな
のか、バグなのか、わからない
問題点
問題点ごとの解決策(仕様)
31
Ø 実装を始める前に
Wikiにまとめて共有
問題点ごとの解決策(仕様)
Wiki作成
共有
32
GitLabでマージリクエスト時に
コードの詳細な説明を加えている
Gitに実装の詳細な情報を残す
問題点ごとの解決策(仕様)
マージリクエストを送る
リポジトリ
33
問題点ごとの解決策
(実装編)
34
実装を確認したところ
問題がありました
問題点ごとの解決策(実装)
35
安易に修正ができなくなっている
ピュアJava実装(フレームワーク未使⽤)
問題点ごとの解決策(実装)
36
解決するために
問題点ごとの解決策(実装)
37
採⽤アーキテクチャ選定
問題点ごとの解決策(実装)
38
l JDKの選定
l フレームワークの選定
l Web API アーキテクチャの選定
採⽤アーキテクチャの選定
問題点ごとの解決策(実装)
39
l JDKの選定
l フレームワークの選定
l Web API アーキテクチャの選定
JDKの選定
問題点ごとの解決策(実装)
40
Ø JDKの選定基準
Ø LTSで最新versionな物
Ø AdoptOpenJDK LTS 11
Ø 選定理由
Ø 既存で動いているシステムで実績
JDKの選定
問題点ごとの解決策(実装)
41
l JDKの選定
l フレームワークの選定
l Web API アーキテクチャの選定
フレームワークの選定
問題点ごとの解決策(実装)
42
Ø フレームワークの選定
Ø 欲しい要件
Ø 組込Tomcat内蔵 & 標準的な実装にしたい
Ø Play Framework OR Spring Boot
フレームワークの選定
問題点ごとの解決策(実装)
43
フレームワークの選定
問題点ごとの解決策(実装)
⾃社での導⼊実積があった事と
フレームワークの
ライブラリが充実していた為
44
l JDKの選定
l フレームワークの選定
l Web API アーキテクチャの選定
Web API アーキテクチャの選定
問題点ごとの解決策(実装)
45
Ø Web API アーキテクチャ
Ø 選定要件
Ø 参考にできるガイドラインがあること
Ø 疎結合な実装にできること
Ø テストコードが書きやすいこと
Web API アーキテクチャの選定
問題点ごとの解決策(実装)
46
Ø 最終的に決まったのが
Web API アーキテクチャの選定
問題点ごとの解決策(実装)
3層アーキテクチャ
参考:https://terasolunaorg.github.io/guideline/public_review/Overview/ApplicationLayering.html
参考:https://qiita.com/YutaKase6/items/7d88fa23f81366905270
47
Ø 他のアーキテクチャは、検討しなかったのか
Web API アーキテクチャの選定
問題点ごとの解決策(実装)
ØMVC
ØMVCより、強度なアーキテクチャにしたかったため
ØClean Architecture
Ø学習コストが⾼いので、⼯数の関係上断念
48
Application Layer
• Controller
• Resource
Infrastructure Layer
• Repository Impl
• Entity (JPA)
Domain Layer
• Domain Object
• Service
• Repository Interface
3層アーキテクチャ
ビジネスロジック
です
問題点ごとの解決策(実装)
Web API アーキテクチャの選定
49
Application Layer
• Controller
• Resource
Infrastructure Layer
• Repository Impl
• Entity (JPA)
Domain Layer
• Domain Object
• Service
• Repository Interface
3層アーキテクチャ
依存依存
Web APIのアーキテクチャの選定
問題点ごとの解決策(実装)
Web API アーキテクチャの選定
50
Application Layer
• Controller
• Resource
Infrastructure Layer
• Repository Impl
• Entity (JPA)
Domain Layer
• Domain Object
• Service
• Repository Interface
3層アーキテクチャ
依存しない
問題点ごとの解決策(実装)
Web API アーキテクチャの選定
依存しない
51
Application Layer
• Controller
• Resource
Infrastructure Layer
• Repository Impl
• Entity (JPA)
Domain Layer
• Domain Object
• Service
• Repository Interface
3層アーキテクチャ
各レイヤーごとに処理が分かれている
Web API アーキテクチャの選定
問題点ごとの解決策(実装)
52
Ø 疎結合な実装になること OK
Ø テストが書きやすいこと OK
Web API アーキテクチャの選定
問題点ごとの解決策(実装)
53
問題点ごとの解決策(実装)
個別の実装上の問題点
54
問題点ごとの解決策(実装)
l 意図が分かり難い実装
l ⽣のクエリが定義
l 設定情報が⼀部、ベタ書き
l クラスの責任
55
問題点ごとの解決策(実装)
l 意図が分かり難い実装
l ⽣のクエリが定義
l 設定情報が⼀部、ベタ書き
l クラスの責任
56
意図が分かり難い実装
問題点ごとの解決策(実装)
意図が分かり難い実装
多重継承
class HogeA extends BaseA implements IBaseA
abstract class BaseA extends BaseB implements Ifb
abstract class BaseB {
//なにもしない
}
BaseB baseB = (BaseB) hogeA
if(baseB instancOf BaseA){
}
意味がわからない
57
if(str.equals("success")){
//なにかの処理
if(name != null){
for(条件A && 条件B){ // なにかの処理
if(条件A || (条件B && 条件C)){
}else if(条件(B) && 条件(B)){
} else {
}
}
}
}
意図が分かり難い実装深いネスト
問題点ごとの解決策(実装)
意図が分かり難い実装
読みづらい
58
Ø フレームワークに従った標準的な実装
Ø コードレビューの実施による属⼈化防⽌
Ø コード品質向上
意図が分かり難い実装(解決策)
問題点ごとの解決策(実装)
意図が分かり難い実装 解決策
59
問題点ごとの解決策(実装)
l 意図が分かり難い実装
l ⽣のクエリが定義
l 設定情報が⼀部、ベタ書き
l クラスの責任
60
⽣のクエリが定義
問題点ごとの解決策(実装)
// EXAMPLEテーブルのIDで検索
String EXAMPLE_SERCHID_QUERY = “SELECT * FROM EXAMPLE WHERE 〜“;
⽣のクエリが書かれている
61
O/Rマッピングフレームワークの導⼊
問題点ごとの解決策(実装)
⽣のクエリが定義(解決策)
62
問題点ごとの解決策(実装)
l 意図が分かり難い実装
l ⽣のクエリが定義
l 設定情報が⼀部、ベタ書き
l クラスの責任
63
設定情報が⼀部、ベタ書き
問題点ごとの解決策(実装)
ENV_JA = “値1”
ENV_US = “値2”
設定情報がプログラムにベタ書き、
外部ファイル化できていない
64
設定情報が⼀部、ベタ書き(解決策)
YAML
設定情報は、YAMLに統⼀
問題点ごとの解決策(実装)
65
問題点ごとの解決策(実装)
l 意図が分かり難い実装
l ⽣のクエリが定義
l 設定情報が⼀部、ベタ書き
l クラスの責任
67
クラス
給料計算 レポート作成
所定労働時間
問題点ごとの解決策(実装)
クラスの責任
68
クラス
給料計算 レポート作成
所定労働時間
問題点ごとの解決策(実装)
クラスの責任
修正
69
クラス
給料計算 レポート作成
所定労働時間
問題点ごとの解決策(実装)
クラスの責任
修正 バグ
70
クラス
給料計算 レポート作成
所定労働時間
問題点ごとの解決策(実装)
クラスの責任
修正 バグ
⼀つのメソッドを
修正すると
他にも影響する
71
各レイヤー毎に
責任を明確化し他モジュールに
影響しない作りにしました
問題点ごとの解決策(実装)
クラスの責任(解決策)
72
クラス
給料計算 レポート作成
社員Data
問題点ごとの解決策(実装)
クラスの責任(解決策)
データ情報
73
問題点ごとの解決策
(テスト編)
74
Ø 修正を⾏っても、何を持って正しいとするのか分
からない
Ø デグレ確認がすぐにできない
問題点
問題点ごとの解決策(テスト)
単体テストがなく、正しい結果が分らない
75
Ø 今回使⽤したのは
Ø Junit
Ø Mockito
解決策
問題点ごとの解決策(テスト)
76
アジェンダ
l お名前.comの紹介
l 流⽤元として渡されたシステムがレガシーだった
l 問題点ごとの解決策(仕様・実装・テスト)
l 結果どうなったのか
77
結果どうなったのか
l 仕様(ドキュメント化)
l 実装(アーキテクチャの採⽤)
l テスト(単体テストの改善)
78
結果どうなったのか
l 仕様(ドキュメント化)
l 実装(アーキテクチャの採⽤)
l テスト(単体テストの改善)
79
Ø ドキュメント化
Ø Wikiにドキュメント
Ø 仕様が変更になったらUpdateする
仕様(ドキュメント化)
結果どうなったのか
• チームで仕様を把握できるようになった
• Wikiもメンテナンスが必要である
80
結果どうなったのか
l 仕様(ドキュメント化)
l 実装(アーキテクチャの採⽤)
l テスト(単体テストの改善)
81
Ø 三層アーキテクチャ
Ø 実装の修正をルール明確化
実装(アーキテクチャの採⽤)
結果どうなったのか
独⾃実装になりにくい
82
Ø 三層アーキテクチャ
Ø ⼀番は、テストが書きやすいこと
実装(アーキテクチャの採⽤)
結果どうなったのか
テスタブルな実装になる
83
結果どうなったのか
l 仕様(ドキュメント化)
l 実装(アーキテクチャの採⽤)
l テスト(単体テストの改善)
84
テスト(単体テストの改善)
結果どうなったのか
• 開発に集中でき、テスト時間を削減
• 誰が実⾏しても、同じ粒度で検証可能
同じ粒度のテストを
実施できるのか︖
時間が掛かる︕
単体テストを書いたら
85
テスト(単体テストの改善)
結果どうなったのか
テストは、
どこまでできたのか︖
86
Ø実際にテストできたのは
Ø Controller & Service
Ø Repository & Entity
テスト(単体テストの改善)
結果どうなったのか
⼯数の関係上、
⼆つのテストしか書けなかった。
残りは結合テストで確認。
87
88
しかし・・・
89
Øルールの遵守やメンテナンスをしないと
Øレガシー化してしまいます
ルールの遵守や定期的な
メンテナンスを
していくことが⼤切
今後に向けて
結果どうなったのか
90
今後もレガシーなコードを
⽣まないようにします︕
92
[12/11(⽔)19時]渋⾕フクラス開業記念
GMO Developers Night
Date: 12/11(wed) 19:30-22:00
URL: https://gmo.connpass.com/event/156321/
Takamichi Tanaka
FaceBook https://www.facebook.com/takamichita
Twitter @ttakamichi1

Example of exiting legacy system