Slide 1

Slide 1 text

組織と技術の両輪で開発を加速させる kintoneチームの取り組み JJUG CCC 2022 Fall Nov 27, 2022 濵田 健

Slide 2

Slide 2 text

§ 濵田 健 / Ken Hamada (id:itchyny) § 2021/11 サイボウズ入社 § kintone開発チーム/ソフトウェアエンジニア § Java/TypeScript/Go/Rust/Haskell/Vim/jq § lightline.vim/gojq/bed/json2yaml (in Go) 自己紹介

Slide 3

Slide 3 text

業 務 シ ステ ム を 簡単 に 作成 ス ム ー ズな デ ー タ共 有 プ ロ セ ス管 理 ・ アク セ ス権 限 コ ミ ュ ニケ ー シ ョン 基 盤 国 内 2 5 , 5 0 0 社 ( 2 0 2 2 年 8 月 末 ) kintone

Slide 4

Slide 4 text

アジェンダ 意思決定コスト 認知負荷 逆コンウェイ戦略 領域専任チーム 探求時間 個人改善 自律的改善チーム 属人性の低減 モノリス オーナーシップ意識 クロスファンクショナル 機能毎にパッケージ分割 レビューコスト 大規模リファクタリング 開発の加速 開発体制の改革 組織面 プロジェクト制 技術面

Slide 5

Slide 5 text

開発体制の改革 〜領域専任のチーム体制へ〜

Slide 6

Slide 6 text

kintone開発チームの職種 プロダクト マネージャー (PdM) デザイナー リサーチャー テクニカルライター ローカライズ エンジニア (PG) QAエンジニア アクセシビリティ スクラムマスター 約90名の様々な職種のメンバーが所属

Slide 7

Slide 7 text

kintone開発チームの体制 PdM PdM PdM プロダクト バックログ サブチームA PG PG PG QA QA デザイナー デザイナー デザイナー ライター ライター ローカ ライズ ローカ ライズ スプリント プランニング レビュー ソースコード 全体振り返り 新規開発チーム React移行チーム DXチーム メンテチーム モバイルチーム AWS基盤チーム サブチームB PG PG PG QA QA サブチームC PG PG PG QA QA サブチームD PG PG PG QA QA

Slide 8

Slide 8 text

∎PdMがバックログを作成 § リファインメントでPBI共有、見積もり、優先順位付け ∎サブチームにPBIを割り振り § PG 3〜4人 + QA(兼務あり)のサブチーム × 3〜4 § デイリースクラム、モブプログラミング、振り返り ∎スプリントレビュー、全体振り返り § 1スプリント 1週間 スクラム開発 (LeSS) Large-Scale Scrum

Slide 9

Slide 9 text

2021年 ごろ から 開 発速 度 が顕 著に 低下 開発速度の低下 消化したストーリーポイントを kintoneに記録してグラフ描画

Slide 10

Slide 10 text

∎PdM・デザイナー・ライターはサブチームに所属しない § サブチームのデイリースクラムや振り返りにも不参加 § コミュニケーションコストが高い・心理的な距離感 ∎バックログ担当箇所が決まっていない § 実装箇所、見積もりの不確実性が高い ∎認知負荷が高い・オーナーシップ意識が希薄 チーム体制のモノリス性

Slide 11

Slide 11 text

∎モノリシックなアーキテクチャー・リポジトリ § サーバーサイド・フロントエンド共に § 一部は別リポジトリでパッケージ化(更新頻度低) § コードベースは肥大化、依存関係が複雑化 § 変更の影響範囲が広く、学習コストが高い § 新しいメンバーの育成に時間がかかる ∎認知負荷が高い・オーナーシップ意識が希薄 アーキテクチャーのモノリス性

Slide 12

Slide 12 text

∎マイクロサービス化の検証プロジェクト (2021/6-10) § 分離しやすそうな機能を一つ切り出す検証(組織・技術) § 認証・通知・DB分離・トランザクション・E2Eテストなど ∎検証プロジェクトの結果 § 分離しやすそうな機能だったが他の機能と密結合だった § 分離しやすそうな機能は開発の優先度もモチベも低い § 分離する工数、整合性担保など技術的困難もあり断念 § 小さいチームの意思決定の速さ・職種間の連携が密に マイクロサービス化の検討

Slide 13

Slide 13 text

『チームトポロジー: 価値あるソフトウェアを すばやく届ける適応型組織設計』 チームタイプと チーム間のインタラクションモードの分類 自チームが他のチームとどう関わるべきか ʰνʔϜτϙϩδʔʱษڧձ https://pub.jmam.co.jp/book/b593881.html

Slide 14

Slide 14 text

∎フィーチャーチーム § 担当領域 (機能) を明確化して、認知負荷を下げる § アプリ設定チームを発足 (2022/6-) ∎クロスファンクショナル § 各職種のメンバー・密にコミュニケーション ∎逆コンウェイ戦略 § チームの形 → システムアーキテクチャーの形 § チーム間のインタラクションモードを意識 領域専任のチーム体制へ

Slide 15

Slide 15 text

PG QA デザイナー ローカ ライズ スクラム イベント 領域Aチーム PdM PG ライター PBL 領域専任チームの発足 PdM PdM PdM プロダクト バックログ デザイナー デザイナー ライター ローカ ライズ 新規開発チーム ソースコード 全体振り返り スクラム イベント React移行チーム DXチーム メンテチーム モバイルチーム AWS基盤チーム サブチームA PG PG PG QA QA サブチームB PG PG PG QA QA サブチームC PG PG PG QA QA

Slide 16

Slide 16 text

チーム体制の未来図 PdM 新規開発チーム PG QA デザイナー ローカ ライズ スクラム イベント 領域Dチーム PdM PG ライター PBL PG QA デザイナー ローカ ライズ スクラム イベント 領域Cチーム PdM PG ライター PBL PG QA デザイナー ローカ ライズ スクラム イベント 領域Bチーム PdM PG ライター PBL PG QA デザイナー ローカ ライズ スクラム イベント 領域Aチーム PdM PG ライター PBL ソースコード・全体振り返り React移行チーム DXチーム メンテチーム モバイルチーム AWS基盤チーム

Slide 17

Slide 17 text

∎巨大でモノリシックなコードがここにあるんだが? § 逆コンウェイ戦略はすでにあるモノリスシステムには? ∎パッケージの分割:リスクもコストも低い § サーバーサイド・フロントエンド共に機能ごとに分割中 § ArchUnitで依存関係をテスト・Gradle multi-project化 § 依存関係をグラフ描画 → 変な依存は随時解消 § オーナーシップの明確化・認知負荷の低減 機能毎のパッケージ分割

Slide 18

Slide 18 text

∎領域専任のチーム体制へ移行に挑戦中 § 担当する領域(機能)を明確化 § 各職種が所属する小さなチームで自律性を向上 § 新規開発の活発なコアドメインから分割 ∎機能毎にパッケージを分割(モジュラーモノリスへ) § 依存関係を描画、修正、テスト → 境界と依存の統制 § Gradle multi-project化 ∎認知負荷、学習コストやモノリス性の低減 開発体制の改革(まとめ)

Slide 19

Slide 19 text

アジェンダ 意思決定コスト 認知負荷 逆コンウェイ戦略 領域専任チーム 探求時間 個人改善 自律的改善チーム 属人性の低減 モノリス オーナーシップ意識 クロスファンクショナル 機能毎にパッケージ分割 レビューコスト 大規模リファクタリング 開発の加速 開発体制の改革 組織面 プロジェクト制 技術面

Slide 20

Slide 20 text

プロジェクト制の発足 〜PG主導の改善プロジェクト〜

Slide 21

Slide 21 text

∎探求時間:バックログの開発以外に各自で「探求」 § リファクタリングなどの改善や個人学習など ∎一人で大きな改善を進めるのはつらい § その改善はいつ終わるの? § 見積もりの欠如、属人性が高い、停止判断を下す立場の不在 § レビューする側も大変 § 改善の背景の理解に時間がかかる § 工数を割く価値がPdMに伝わっていない 探求時間

Slide 22

Slide 22 text

∎プロジェクト制 (2022/1-) § 大きな改善やプロトタイピングを実施する枠組み § 目的やゴール、期限をチーム運営に説明して承認 § プロジェクト憲章のテンプレートがある § プロジェクトマネージャー・メンバー・スポンサー § スポンサー:プロジェクトの外から助言や停止判断を行う プロジェクト制の発足

Slide 23

Slide 23 text

§ JUnit 5へのアップデート § Joda-TimeからJSR-310への移行 § フロントエンドの改善 § 他多数 実施されたプロジェクト PGの改善が 活発に!

Slide 24

Slide 24 text

JUnit 5へのアップデート

Slide 25

Slide 25 text

∎JUnit:Javaのユニットテストのフレームワーク § JUnit 5は2017/9 Release → 時は流れ… ∎2022年になっても、JUnit 4を使っていた § テスト用なのでアップデートの必要性は? § 移行する工数とプロダクトの価値提供は? § 一万クラスのテストを書き換える手段は? § 並列実行の仕組みの移行方法は? JUnit 5へのアップデート

Slide 26

Slide 26 text

JUnit 5へのアップデート JUnit 4 JUnit 5 org.junit.Test org.junit.jupiter.api.Test @Before @BeforeEach @After @AfterEach @BeforeClass @BeforeAll @AfterClass @AfterAll @Ignore @Disabled @Theory @ParameterizedTest @Enclosed @Nested 置換してgit commitするスクリプトを準備 junit-vintage-engineで徐々に移行も可能だが 混在すると認知負荷が上がるので一気に移行

Slide 27

Slide 27 text

∎Maven Surefire Plugin の parallel=classes § runOrder=balanced でCI時間を短縮していた ∎JUnit 5.3から並列実行をサポート § junit.jupiter.execution.parallel.enabled=true § 並び替えは ClassOrderer を独自に実装 § 前回の実行時間のログを使い、遅いテストクラスから実行 JUnitテストの並列実行 並列実行とクラス並び替えの組み合わせで意図しない順序になるバグがある → The order of classes is not correct when parallel execution is enabled 詳しくは “kintone JUnit 5” で検索 🔍

Slide 28

Slide 28 text

Joda-TimeからJSR-310への移行

Slide 29

Slide 29 text

∎Joda-Time:Javaで日時を扱うライブラリ (2005-) § Java 8のJSR-310 Date and Time APIへの移行を推奨 § SpringのJoda-Timeインテグレーションも非推奨 § 移行を怠っているとライブラリ更新できなくなる危機 ∎全製品で移行を決定、プロジェクト化 § 週に三時間ほど集まり、機能ごとに移行 § IntelliJ IDEAのType migrationが便利 Joda-TimeからJSR-310への移行 おつかれさまでした!

Slide 30

Slide 30 text

Joda-Timeがパースできるもの § LocalDate.parse("12345-1-1"): 五桁年、0埋めなし § DateTime.parse("2022T10"): 年と時のみ § DateTime.parse("2022-03-04T"): Tあり時刻なし § LocalTime.parse("T12:13:14"): Tから始まる時刻 § LocalTime.parse("12:13:14,567"): 小数点が "," § LocalTime.parse("3.5555"): 小数点時の秒以下

Slide 31

Slide 31 text

JSR-310での日時のフォーマット ∎DateTimeFormatter.ofPatternが基本 § 西暦年はy (year-of-era) ではなくu (year) § yyyy は西暦0年が "1" に、紀元前の年に "-" がつかない § "令和4年" をパースする時はGGGGy (JapaneseChronology) § uuuuは10000年以上に "+" がつく (SignStyle.EXCEEDS_PAD) ∎DateTimeFormatterBuilder § パース時は ResolverStyle.STRICT を指定 § デフォルトはSMART: 11/31 → 11/30 (月末日)

Slide 32

Slide 32 text

タイムゾーンのformatterの違い output Joda-Time JSR-310 +0900 Z Z, xx +09:00 ZZ xxx +09 -- x JST z z Asia/Tokyo ZZZ VV Japan Standard Time zzzz zzzz GMT+09:00 -- ZZZZ, OOOO

Slide 33

Slide 33 text

Joda-TimeとJSR-310の夏時間 リマインダーの条件通知 Joda-Time JSR-310 org.joda.time.DateTimeZone java.time.zone.ZoneRules (java.time.ZoneId#getRules) isStandardOffset(long) isDaylightSavings(Instant) previousTransition(long) previousTransition(Instant) nextTransition(long) nextTransition(Instant) 夏時間と標準時の切り替わるぴったりの日時に注意 夏時間 (daylight saving time): 夏に時計を進める

Slide 34

Slide 34 text

Joda-TimeとJSR-310の夏時間 > var dt = OffsetDateTime.parse("2022-11-06T09:00:00Z"); > Instant.ofEpochMilli( org.joda.time.DateTimeZone.forID("America/Los_Angeles") .previousTransition(dt.toInstant().toEpochMilli())); 2022-11-06T08:59:59.999Z > java.time.ZoneId.of("America/Los_Angeles").getRules() .previousTransition(dt.toInstant()).getInstant(); 2022-03-13T10:00:00Z

Slide 35

Slide 35 text

Joda-TimeとJSR-310の夏時間 > var dt = OffsetDateTime.parse("2022-11-27T09:00:00Z"); > Instant.ofEpochMilli( org.joda.time.DateTimeZone.forID("America/Los_Angeles") .previousTransition(dt.toInstant().toEpochMilli())); 2022-11-06T08:59:59.999Z > java.time.ZoneId.of("America/Los_Angeles").getRules() .previousTransition(dt.toInstant()).getInstant(); 2022-11-06T09:00:00Z

Slide 36

Slide 36 text

フロントエンドの改善

Slide 37

Slide 37 text

∎Google Closure Tools § Google製・2009/11- § AngularJS 2010/10, TypeScript 2012/10, React 2013/05, Vue.js 2014/02 § JavaScriptトランスパイラ・ライブラリ群 § 変数名やクラスのフィールド名をminify § テンプレートエンジン・型システム Google Closure Tools https://developers.google.com/closure/library

Slide 38

Slide 38 text

∎Google Closure Toolsを採用 § 2009年末のフレームワーク選定により採用決定 § 社内の他製品ではjQueryとYUIを使っていた § 豊富なライブラリ群・DOM操作・イベントハンドリング ∎現在、JavaScript・テンプレート含め50万行以上 § フロントエンドエコシステムの潮流から乖離 § Google Closure Toolsに詳しい人が少ない、採用難 kintoneのフロントエンド

Slide 39

Slide 39 text

フロントエンドの刷新 ∎全てのページをReact化するプロジェクト § フロントエンドをリアーキテクチャするプロジェクト § 技術的にもチーム的にも分割し、スケールできる § クロスファンクショナルで自律性のある四つのチーム § フロントエンドのモノリスからの脱却 § 詳しくは “kintone フロリア” で検索🔍

Slide 40

Slide 40 text

∎既存のコードでの機能開発は継続中 § 現状はReact移行チームの機能実装が後追い ∎機能開発の速度を維持・改善するために § 不要な実装を削除する (IE対応など) § 古い記法を新しくする § prototype記法のclass構文移行 § React移行の際にも読みやすさは重要 既存のフロントエンドの改善

Slide 41

Slide 41 text

prototype記法のclass構文移行 var SampleComponent = function(items) { SampleComponent.base(this, 'constructor'); this.items_ = items; }; goog.inherits(SampleComponent, Component); SampleComponent.prototype.getItems = function () { return this.items_; }; SampleComponent.prototype.disposeInternal = function () { SampleComponent.base(this, 'disposeInternal'); }; class SampleComponent extends Component { constructor(items) { super(); this.items_ = items; } getItems() { return this.items_; } disposeInternal() { super.disposeInternal(); } } closure library独自の継承方法 メソッドの定義が冗長 基底クラスのメソッドを呼ぶのも長い ES2015準拠の継承方法 メソッドの定義も 呼び出しも完結 読むのもつらいし書くのも楽しくない

Slide 42

Slide 42 text

∎RubyスクリプトでJavaScriptのコードを変換 § 3時間で実装した200行程度のRubyスクリプト § 関数やメンバーの定義ごとにテキスト処理(構文木ではない) § 自動変換できないコードは先に手で修正から変換 § super(); の前に this にアクセスしているなど ∎プロジェクトをPGが提案し、現在も進行中 § 1000クラス以上が移行完了 prototype記法のclass構文移行

Slide 43

Slide 43 text

∎IDEの機能 § IntelliJ IDEAの構造検索と置換 ∎semgrep § OCaml製・各種言語に対応 ∎sed・awk・(git-)grep・Perl・IdeaVim § "/pattern1/{:l; /pattern2/!{N; bl}; ...}" "/.../{F; p}" ∎自前で実装 リファクタリングに使うツール 構文木・厳格・特化 行毎・寛容・汎用 厳格さをコントロール・実装コスト高 属人性高・メンテナンス難・特化型 インスペクションに設定可能 Vimのマクロも対応!

Slide 44

Slide 44 text

∎不要な実装や記法の混在を放置しない § 「このコードは使われていないので消すと良さそう」 § 「Javaの新しい記法を使うと良さそう」 § これらの放置は開発時の生産性の低下につながる ∎一人での改善は本人もレビュアーもチームもつらい § プロジェクト制、コード品質の改善を草の根活動に頼らない § 責任者を明確化、不確実性・属人性を低減、QAと連携 § 場面に応じた手法で大規模にリファクタリング 「〜すると良さそう」を「やる」には

Slide 45

Slide 45 text

まとめ 意思決定コスト 認知負荷 逆コンウェイ戦略 領域専任チーム 探求時間 個人改善 自律的改善チーム 属人性の低減 モノリス オーナーシップ意識 クロスファンクショナル 機能毎にパッケージ分割 レビューコスト 大規模リファクタリング 開発の加速 開発体制の改革 組織面 プロジェクト制 技術面

Slide 46

Slide 46 text

We are Hiring! kintone 採用情報 🔍