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

JavaでWebサービスを作り続けるための戦略と戦術

 JavaでWebサービスを作り続けるための戦略と戦術

Japan Java ユーザーグループ クロスコミュニティ カンファレンス 2018 Spring 登壇資料

Avatar for Yu Watanabe

Yu Watanabe

May 29, 2018
Tweet

More Decks by Yu Watanabe

Other Decks in Technology

Transcript

  1. #ccc_g1 published Who? • 渡辺 祐 • (株)ビズリーチ • SREグループ

    ◦ Site Reliability Engeneering • twitter: @nabedge 5
  2. #ccc_g1 published 仮想OS on 仮想OS 13 OracleVirtualBox CentOS Docker (MySQL)

    Docker (Redis) CentOS Docker (PgSQL) Docker (fakes3) Aサービス のコード Bサービス のコード 172.16.1.1 172.16.2.2 setup.sh setup.sh Mac OS
  3. #ccc_g1 published setup.shがやってること 1. vagrant up 1.1. 仮想OS(CentOS)起動 1.2. yum

    install docker-ce 2. vagrant ssh -c “docker-compose up -d” 2.1. mysql, solr, localstack, etc... 3. DBにテストデータをINSERTするスクリプト 15
  4. #ccc_g1 published Eclipse -> IntelliJ IDEA 1. ライブラリプロジェクト、アプリケーションプロジェクトの絶対数 が増 a.

    フラットなプロジェクトレイアウトが前提のEclipseだと何かと不都合 2. Python, TypeScript, Android Java... 3. Scalaのチームもいる 4. 全社の全エンジニアまとめてIntelliJ 18
  5. #ccc_g1 published Maven -> Gradle • ライブラリプロジェクト、アプリケーションプロジェクトの絶対数 の増加 • CPUのコア数に合わせて並列ビルドできるほうが有利

    • フロントエンドのビルドツールもろともgradleから制御したい • pom.xmlよりもbuild.gradleのほうが自由度が高いわりに読み やすい 19
  6. #ccc_g1 published Jenkins1から2へ。そしてJenkinsfileへ 20 • Maven -> Gradle移行の過程でjenkinsジョブの 調整コストが増 •

    全ソース, build.gradle, Jenkinsfile まで含め git管理するだけで楽勝。 • っていうのを見越してまず先にJenkins2に バージョンアップしていた
  7. #ccc_g1 published • “public static void main”ならIDEだろうと サーバ上のCLIだろうと、どうにでも動かせる 27 public

    class AppStarter { public static void main(String args[] argv) { Tomcat tomcat = new Tomcat(); tomcat.start();
  8. #ccc_g1 published JasperReportはオワコン • PDF出力ライブラリ • Java8だとデザインツールが事実上動かない ◦ (2016年当時です。今は知らない) •

    全体のJava8化を阻害する意外なボトルネックだった • flying-soucer-pdf でPDF関連機能を全部作り直し 30
  9. #ccc_g1 published “JSESSIONID”はオワコン • サブシステムAは http://localhost:8001/ • サブシステムBは http://localhost:8002/ •

    両方ともセッションCookie名が ”JSESSIONID” • ローカル開発環境でA, B同時に起動すると 片方でしかログイン状態を保てない • エンジニアの生産性低下 33
  10. #ccc_g1 published // JavaConfigの場合 @WebListener public class SessionTrackingListener implements ServletContextListener

    { @Override public void contextInitialized(ServletContextEvent event) { SessionCookieConfig config = event.getServletContext().getSessionCookieConfig(); config.setName("MY_HOGE_SESSIONID"); config.setHttpOnly(true); 35
  11. #ccc_g1 published sticky-session-cookieもオワコン • APサーバ2台の冗長構成だとして • リリースのときは1台ずつ止めてデプロイ • リリース中は片系統にアクセス集中 •

    リリース後も片系統にアクセス集中したまま (sticky-session-cookieとはそういうもの) • 同時利用ユーザー数が増えると... !! 38
  12. #ccc_g1 published おすすめの「JavaConfigはじめかた」 <beans xmlns:context="http://www.springframework.org/schema/context"> <context:component-scan base-package="jp.bizreach.foo"/> </beans> 44 package

    jp.bizreach.foo @Configuration public BarConfig { @Bean public HogeService hogeService() {...} } xmlファイルにほんの数行だけ残しておく
  13. #ccc_g1 published src/main/webappの存在がオワコン • クラスパスではないからJUnitから読み込めない ◦ 単体テスト自動化を妨げる元凶 • MVCフレームワークの機能が中途半端だった時代の遺跡 ◦

    ほとんどのMVC-FWは、”src/main/resources/static” に置 いた静的リソースをそのままレスポンスする機能が既にあ る。 ◦ TomcatのDefaultServletの出番はもはや無いのに、それ を使うためのディレクトリ構造を残すの? 49
  14. #ccc_g1 published ├ build.gradle └ src/ ├ main/ │ ├

    java/ │ ├ resources/ │ └ webapp/ │ └ WEB-INF/ └ test/ ├ java/ └ resources/ 普通のクラスパス テストのクラスパス ロストテクノロジー置き場 50
  15. #ccc_g1 published • IDEはもちろんIntelliJ IDEA ◦ Java, Scala, TypeScript, JavaScript,

    Python 全部対応 • npm + gulp/webpack から yarn + gradle へ 56
  16. #ccc_g1 published • わざわざgradleからyarnを呼ぶ理由 ◦ gradleのほうがなんでも書ける(groovy)わりに、bashより も読みやすい ◦ mavenではまず無理 ◦

    並列実行ですばやくビルドできる ◦ 並列実行対象タスクを任意に設定しやすい ◦ Jenkinsfileが短くなる 57
  17. #ccc_g1 published テストの理想と現実 • 自動化に倒すべきなのは確か ◦ JUnit, spring-test, Selenium... •

    「テスト項目表を書いての手動テスト」も 結局は存在し続けるだろう ◦ その良し悪しはともかく 63
  18. #ccc_g1 published • 良い兆候=ビズリーチシステムの現状 ◦ 若手のエンジニアが増、ソースコードの絶対量も増。 ◦ にも関わらずテストカバレッジ率は下がってない。 むしろジリジリと上がってる。 ◦

    “@Test”メソッドの数は明らかに増えている • よくある悪い兆候 ◦ テストが書いてあるのに実行されてない。 ◦ ソース規模やカバレッジ率が 毎日測定&周知されてない or 不正確。 66
  19. #ccc_g1 published • あるエンジニアのPC上でなら動く • 他のエンジニアのPCでも動くけど 準備に時間がかかる • 検証環境でも動くけど、いま別のチームが テストのために検証環境にデプロイしているのは

    別ブランチのコードなのでやっぱり動かない 「動くソフトウェアで進捗を確認せよ」 しかし、なぜ動かないのか?(再掲) だから手動テストが面倒くさくなる 70
  20. #ccc_g1 published 歴史を紐解いてみる • 2001年: アジャイルソフトウェア宣言 ◦ 「動くソフトウェアこそが最重要な進捗の尺度だ」 • 2004年:

    レガシーコード改善ガイド ◦ 「レガシーコードとはテストが無いコードのことだ」 • 2005年: JUnit4 71
  21. #ccc_g1 published 歴史を紐解いてみる • 2001年: アジャイルソフトウェア宣言 ◦ 「動くソフトウェアこそが最重要な進捗の尺度だ」 • 2004年:

    レガシーコード改善ガイド ◦ 「レガシーコードとはテストが無いコードのことだ」 • 2005年: JUnit4 • この頃無かったもの ◦ 分散VCS(git), AWS-EC2, IaaC, Docker 72
  22. #ccc_g1 published 分散VCS, コンテナ, IaaC時代の手動テスト(案) 1. プルリクエスト毎にそれ専用の検証環境が 自動構築される 2. pushされる都度mergedな状態のコードで

    1の環境にビルド&デプロイされる 3. そのプルリクに対するテストをいつでも誰でもできる a. エンジニア、デザイナー b. 社内の手すきの人員? c. クラウドソーシング? まだ出来てませんが、 目指すところです。 74
  23. #ccc_g1 published • AWS-S3のバケットがうっかりpublic設定 • パスワードを平文でログ出力 • 割賦販売法改正, PCI-DSS…? •

    AWSのシークレットキーを ソースコードに埋め込んだままn年変えてない • JRE/ライブラリ/フレームワークで 脆弱性報告からのバージョンアップ祭り 77
  24. #ccc_g1 published • ベストなのはOS環境変数 • キーを変えたくなってもソースコードを変更する必 要をなくす。 • OS環境変数を変更してアプリケーションを再起動 するだけ。

    • OS環境変数をどう管理するかは別途 ◦ Hashicorp Vault, AWSパラメータストア アプリケーションの外から差し替え可能にする 80
  25. #ccc_g1 published それ、Spring3.1 (2011年)から普通にできるよ! $ export FOO_KEY=HOGE $ java -jar

    application.jar @Component public class FooBean { @Value("${foo.key}") private String key; 1. FOO_KEY は foo.key プロパティに 当てられる 2. 変数 “key” に “HOGE” が入る See: SystemEnvironmentPropertySource.java 81
  26. #ccc_g1 published たとえばlogbackの脆弱性 • logback1.2.0未満にはシリアライゼーション機構に脆弱性が ある • SocketServer と ServerSocketReciever

    要するにソケット通 信でログを中継する機能を使ってる場合は危険 • 逆にいうとそれを使っていなければ大丈夫そうだね 85
  27. #ccc_g1 published たとえばTomcatの脆弱性 @WebServlet (name = "Root", urlPatterns = {

    "/" }) @ServletSecurity( value=@HttpConstraint(rolesAllowed={"admin"}) ) public class HelloServlet extends HttpServlet { 最後に自前でサーブレットクラスを書いたのは いつだっけ?(遠い目) 87
  28. #ccc_g1 published 1. 脆弱性Bはやばい!xxxライブラリを1.1.2まで バージョンアップしよう! 2. あれ?アプリケーションが 動かなくなった...だと?! 3. 1.1.0

    の段階で自分たちが使っている メソッドの仕様が変更されてました。 「リリースノートやChangeLogに 全てが書いてあるなんて誰が言った?」 4. 詰んだ!\(^o^)/ 90
  29. #ccc_g1 published ビズリーチシステムでは • Java6 -> Java8 • Spring 3.0

    -> 3.2 -> 4.0 -> 4.1 -> 4.2 -> 4.3 -> 5.0 • Tomcat6(インストール方式) -> tomcat-embed-8.5 • Maven -> Gradle ◦ Mavenの基本は「先勝ち」でjarが入ってくるため 意図せず古いor新しいjarが使われることがある ◦ Gradleではデフォルト”Newest” 95
  30. #ccc_g1 published 1. 開発環境とCI戦略 2. 老朽化した技術からの脱却 3. フロントエンドと仲良くする 4. 手動テストも、自動テストも。

    5. セキュリティ 6. バージョンアップする 98 おっ、すべて語りきれたかな? 1. 水を飲む 2. 時間を確認 あと何分?
  31. #ccc_g1 published 102 Mac Book Pro 3GHz Core i7 16GB

    memory 250GB SSD Jet Brains All Products Pack ビズリーチのエンジニアとデザイナーの基本装備
  32. #ccc_g1 published A. MacBook Pro + 外付けディスプレイ B. iMac Pro

    + MacBook (Proじゃないやつ) 106 好きなほうを選べ。ってことになってます
  33. #ccc_g1 published リファクタリングとは(若干のこじつけあり) • オワコンは乗り換えるしかない • ゴミは断捨離するしかない • 新しい息吹を吹き込む ◦

    フロントエンド技術、Python... • 遅くなってしまったものを速くする ◦ Maven -> Gradle • CIまで含めて管理しやすくする ◦ Jenkins2 と Jenkinsfile 111
  34. #ccc_g1 published リファクタリングを支えるもの • setup.sh 一発で準備できるローカル開発環境 • 基本FW/ライブラリのこまめなバージョンアップ • 自動テストコード

    • いつでも誰でも確実に手動テストできる環境 ◦ プルリクエストひとつに対して 検証環境ひとつ(を目指してます) 112
  35. #ccc_g1 published 目指す世界線のための布石は? • IaaCとコンテナ技術の知見を身につけておく ◦ ローカル開発環境でDockerを使ってみる ◦ vagrant, docker,

    setup.shの存在理由が “ローカル開発環境構築手順書” (A4 15枚) の代替だけだと思ってると、もったいない。 116
  36. #ccc_g1 published JJUG-CCC-2014 Fall 「JavaでやってみるThe Twelve Factor App」 Y.Watanabe JJUG-CCC-2015

    Fall 「Java8移行から始まる技術的負債との戦い」 Daisuke.Sei JJUG-CCC-2016 Spring 「テストゼロからイチに進むための戦略と戦術」 Y.Watanabe JJUG-CCC-2018 Spring 「JavaでWebサービスを作り続けるための戦略と戦術」 Y.Watanabe 117