テスト・設計研修【MIXI 25新卒技術研修】
by
MIXI ENGINEERS
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
©MIXI 2025/04/16 Vantageスタジオ Romi事業部 開発グループ サーバーチーム 加藤 修悟 2025 テスト‧設計研修
Slide 2
Slide 2 text
22 ©MIXI ● 加藤 修悟 (shugo.kato) a.k.a. ろぐみ ● 21新卒 ● Romi 事業部 開発グループ サーバーチーム ○ サーバ/フロント/インフラ ○ なんでもやさん(?) ● 好きなもの ○ キーボードづくり ○ チャーシューづくり ● 好きな分野 ○ 爆速化 ⾃⼰紹介
Slide 3
Slide 3 text
33 ©MIXI ⾃⼰紹介 ● 丸尾 ⼀真(kazuma.maruo) ● 19新卒 ○ ⼊社時はモンスト関連のオフラインイベント (XFLAG PARKなど)に従事 ● 所属 ○ ソーシャルベッティング事業本部 開発室 ■ バックエンドメイン ● 好きなもの ○ ダイビング ○ ドライブ
Slide 4
Slide 4 text
44 ©MIXI ⾃⼰紹介 ● 若松 丈⼈(taketo.wakamatsu) ● 23新卒 ● 事業部 開発グループ サーバーチーム ○ Webチームも兼務 ● 好きなもの ○ サウナ ○ 筋トレ(ベンチ100kgを⽬指してます) ○ 旅⾏(年15回弱くらい) ↑会社でいい感じに撮ってもらったやつ
Slide 5
Slide 5 text
55 ©MIXI 本⽇の流れ 1. 講義 2. 演習1 (ペアプログラミング) ○ 実装 ○ 各チーム同⼠でコードレビュー & 修正 3. 演習2、 3 … お昼は13:00頃〜を予定
Slide 6
Slide 6 text
©MIXI 講義
Slide 7
Slide 7 text
77 ©MIXI 本⽇の流れ ● テスト‧ソフトウェアテストとは ○ ソフトウェアの品質の話 ○ TDDの話 ○ テスタビリティの話 ○ テスト技法の話 ○ テストの7原則 ● ペアプログラミング ● コードレビューの仕⽅とされ⽅
Slide 8
Slide 8 text
©MIXI みなさん、テスト書いてますか?
Slide 9
Slide 9 text
©MIXI テストと聞いて、 どのようなことを思い浮かべますか?
Slide 10
Slide 10 text
10 10 ©MIXI テスト‧ソフトウェアテストとは テスト != デバッグ テスト:不具合があることを⽰すことができるだけ デバッグ:不具合を取り除くまでの⼀連の開発活動のこと
Slide 11
Slide 11 text
11 11 ©MIXI テスト‧ソフトウェアテストとは ソフトウェアテストは ソフトウェアが想定通りの動作をしているか評価‧検証し 運⽤時の不具合を低減するための 1 つの⼿段です
Slide 12
Slide 12 text
©MIXI ソフトウェアの品質の話
Slide 13
Slide 13 text
13 13 ©MIXI ソフトウェアの品質 ソフトウェア品質特性 ● 外部品質特性 ○ システムの利⽤者が触れる、⾒える部分の品質 ● 内部品質特性 ○ システムの利⽤者からは⾒えない内側の部分の品質
Slide 14
Slide 14 text
14 14 ©MIXI ソフトウェアの品質 引⽤: 『つながる世界のソフトウェア品質ガイド あたらしい価値提供のための品質モデル活⽤のすすめ 』 P30 図2.3-3 (https://www.ipa.go.jp/publish/qv6pgp0000000wkj-att/000055008.pdf)
Slide 15
Slide 15 text
©MIXI テスト駆動開発(TDD)
Slide 16
Slide 16 text
16 16 ©MIXI テスト駆動開発(Test-Driven Development / TDD)とは? TDDとは、プログラミングのワークフローのひとつ 以下のステップで開発を⾏う 1. テストリストを作成する a. 挙動の要件を書き出す 2. テストを書く (Red) a. 実装はないのでもちろんテストは落ちる 3. テストを通すために、実装をする (Green) a. まずはテストを通すことを考えてみる 4. リファクタリングする (Refactor) 5. テストリストが完了するまで2〜4を繰り返す Red Green Refactor 参考:Kent Beck 著 / 和田卓人 訳, テスト駆動開発, https://shop.ohmsha.co.jp/shopdetail/000000004967/ 和田卓人, 【翻訳】テスト駆動開発の定義, https://t-wada.hatenablog.jp/entry/canon-tdd-by-kent-beck
Slide 17
Slide 17 text
17 17 ©MIXI TDD に関するありがちな勘違い Q. テストコードを書くこと⾃体がTDD? A. それは⾃動テストです! ⾃動テストがあるだけでもとても⽣産性が上がりますが TDD とは別です。 Q. テストを先に書いていればTDD? A. それはテストファーストです! 全テストを先に書くと仕様が把握できるなどのメリットがあります。 ⼀⽅で後戻りのリスクが上がったりします。
Slide 18
Slide 18 text
18 18 ©MIXI TDDの実例|動物の鳴き声を返す関数を実装する 以下のお題で実装をするとします。 呼び出すと⽝の鳴き声を返す関数を実装してください 別の動物(⽜、猫)を指定したらその動物の鳴き声を返して欲しいです 複数の動物を渡したら鳴き声を連結させて返してください
Slide 19
Slide 19 text
19 19 ©MIXI TDDの実例|テストリストの作成 先程のリストから実現すべき挙動を列挙します。 ❏ 引数なしで呼び出した時に、⽝の鳴き声 ʻbowwow!’を返す ❏ 引数で猫(cat)を渡した時に、猫の鳴き声 ʻmeow!’を返す ❏ 引数で⽜(cow)を渡した時に、⽜の鳴き声 ʻmow!’を返す ❏ 複数の動物を渡した時、鳴き声を連結して返す
Slide 20
Slide 20 text
20 20 ©MIXI TDDの実例|1つめの要件のテストを実装 まずは以下のテストを実装 ❏ 引数なしで呼び出した時に、⽝の鳴き声 ʻbowwow!’を返す import pytest from app.bark import bark def test_bark(): assert bark() == 'bowwow!'
Slide 21
Slide 21 text
21 21 ©MIXI TDDの実例|1つめの要件のテストを実装 メソッドの本体がないのでテストが落ちる!! ImportError while importing test module '/app/tests/app/test_bark.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: ... from app.bark import bark E ImportError: cannot import name 'bark' from 'app.bark' (/app/app/bark.py)
Slide 22
Slide 22 text
22 22 ©MIXI TDDの実例|1件⽬のテストに対するメソッドを実装する テストが通る最低限のメソッドを実装 ❏ 引数なしで呼び出した時に、⽝の鳴き声 ʻbowwow!’を返す def bark() -> str: return 'bowwow!'
Slide 23
Slide 23 text
23 23 ©MIXI TDDの実例|1件⽬のテストが通る テストが通ったので1つ⽬完了! 引数なしで呼び出した時に、⽝の鳴き声 ʻbowwow!’を返す tests/app/test_bark.py . [100%] ===================================== 1 passed in 0.03s ====================================
Slide 24
Slide 24 text
24 24 ©MIXI TDDの実例|2つめの要件のテストを実装 以下のテスト assert を追加 ❏ 引数で猫(cat)を渡した時に、猫の鳴き声 ʻmeow!’を返す import pytest from app.bark import bark def test_bark(): assert bark() == 'bowwow!' assert bark('cat') == 'meow!' # 追加
Slide 25
Slide 25 text
25 25 ©MIXI TDDの実例|2つめの要件のテストを実⾏ 元々のメソッドは引数を取っていないのでテストが落ちる E TypeError: bark() takes 0 positional arguments but 1 was given tests/app/test_bark.py:6: TypeError ============================= short test summary info ======================================== FAILED tests/app/test_bark.py::test_bark - TypeError: bark() takes 0 positional arguments but 1 was given ============================== 1 failed in 0.05s =============================================
Slide 26
Slide 26 text
26 26 ©MIXI TDDの実例|2つめの要件のメソッドを実装 テストが通るよう、引数とそれによる分岐を追加 def bark(name: str = 'dog') -> str: if name == 'cat': return 'meow!' return 'bowwow!'
Slide 27
Slide 27 text
27 27 ©MIXI TDDの実例|2つめの要件のテストが通る 2つ⽬のタスクも完了! 引数で猫(cat)を渡した時に、猫の鳴き声 ʻmeow!’を返す tests/app/test_bark.py . [100%] =========================== 1 passed in 0.06s ================================
Slide 28
Slide 28 text
28 28 ©MIXI TDDの実例|3つめの要件のメソッドを実装 同じ形で実装し、3つ⽬の要件も完了! ❏ 引数で⽜(cow)を渡した時に、⽜の鳴き声 ʻmow!’を返す import pytest from app.bark import bark def test_bark(): assert bark() == 'bowwow!' assert bark('cat') == 'meow!' assert bark('cow') == 'mow!' # 追加
Slide 29
Slide 29 text
29 29 ©MIXI TDDの実例|3つめの要件のメソッドを実装 同じ形で実装し、3つ⽬の要件も完了! 引数で⽜(cow)を渡した時に、⽜の鳴き声 ʻmow!’を返す def bark(name: str = 'dog') -> str: if name == 'cat': return 'meow!' if name == 'cow': return 'mow!' return 'bowwow!'
Slide 30
Slide 30 text
30 30 ©MIXI TDDの実例|リファクタ出来そうな箇所を発⾒ 引数で⽜(cow)を渡した時に、⽜の鳴き声 ʻmow!’を返す def bark(name: str = 'dog') -> str: if name == 'cat': return 'meow!' if name == 'cow': return 'mow!' return 'bowwow!' 動物が増えたらifが連なって大変 もっと見通しがよく出来そう?
Slide 31
Slide 31 text
31 31 ©MIXI TDDの実例|鳴き声の持ち⽅をリファクタする 動物の名前と鳴き声を if で管理するのは微妙なので、辞書で管理するようにする テストがあるので、安全にリファクタできる! ANIMAL_SOUNDS = { 'dog': 'bowwow!', 'cat': 'meow!', 'cow': 'mow!', } def bark(name: str = 'dog') -> str: return ANIMAL_SOUNDS[name]
Slide 32
Slide 32 text
32 32 ©MIXI TDDの実例|鳴き声の持ち⽅をリファクタする 動物の名前と鳴き声を if で管理するのは微妙なので、辞書で管理するようにする テストがあるので、安全にリファクタできる! ANIMAL_SOUNDS = { 'dog': 'bowwow!', 'cat': 'meow!', 'cow': 'mow!', } def bark(name: str = 'dog') -> str: return ANIMAL_SOUNDS[name] 知らない動物が来た時の対応も必要で は?
Slide 33
Slide 33 text
33 33 ©MIXI TDDの実例|テストリストに例外時の挙動を追加 引数なしで呼び出した時に、⽝の鳴き声 ʻbowwow!’を返す 引数で猫(cat)を渡した時に、猫の鳴き声 ʻmeow!’を返す 引数で⽜(cow)を渡した時に、⽜の鳴き声 ʻmow!’を返す ❏ 複数の動物を渡した時、鳴き声を連結して返す ❏ 知らない動物が渡された時はエラーを返す New!
Slide 34
Slide 34 text
©MIXI 同じ流れで 1. テストを書く (Red) 2. テストを通すために、実装をする (Green) 3. 必要に応じてリファクタリングする (Refactor) をテストリストが全て完了するまで繰り返すと...
Slide 35
Slide 35 text
35 35 ©MIXI TDDの実例|テストリストが完了し、⽬的を達成 ANIMAL_SOUNDS = { 'dog': 'bowwow!', 'cat': 'meow!', 'cow': 'mow!', } class ArgumentError(Exception): pass def bark(names: list[str] = ['dog']) -> str: for name in names: if name not in ANIMAL_SOUNDS: raise ArgumentError('Invalid animal name') return ''.join([ANIMAL_SOUNDS[name] for name in names]) import pytest from app.bark import bark, ArgumentError def test_bark(): assert bark() == 'bowwow!' assert bark(['cat']) == 'meow!' assert bark(['cow']) == 'mow!' assert bark(['cow', 'cat']) == 'mow!meow!' with pytest.raises(ArgumentError) as e: bark('pig') assert str(e.value) == 'Invalid animal name' 本実装 テスト
Slide 36
Slide 36 text
36 36 ©MIXI TDDの実例|テストリストが完了し、⽬的を達成 引数なしで呼び出した時に、⽝の鳴き声 ʻbowwow!’を返す 引数で猫(cat)を渡した時に、猫の鳴き声 ʻmeow!’を返す 引数で⽜(cow)を渡した時に、⽜の鳴き声 ʻmow!’を返す 複数の動物を渡した時、鳴き声を連結して返す 知らない動物が渡された時はエラーを返す
Slide 37
Slide 37 text
37 37 ©MIXI TDDの注意点 ● 最初はリストのうちの1つを満たすテストからはじめる ○ 全部のテストを書くと、通すのにも、再設計にも時間がかかる。 ● テストを通すとき(Greenステップ)にリファクタリングはしない ○ 設計に関する判断はリファクタリングのステップで。⽬の前に集中。 ● ⼀度に必要以上のリファクタリングをしない ○ フローを回す速度が遅くなってしまう。
Slide 38
Slide 38 text
38 38 ©MIXI TDDのメリット TDDは⽬の前の⼩さいステップに取り組んで⾏くので 開発に対する不安をコントロールしやすい その時々に必要となる設計に向き合えるため、早すぎる抽象化が起きづらい 最初に全体を考えて実装‧設計などをするのは不確実性が⼤きい...
Slide 39
Slide 39 text
©MIXI テスト容易性 (テスタビリティ, Testability)
Slide 40
Slide 40 text
40 40 ©MIXI テストが書きづらい... def get_active_user_x_acounts (): from_time = datetime.now() - timedelta(days=3) # アクティブなユーザーを取ってくる処理 users = query(User).filter(user.updated_at > from_time).all() active_users = [] for user in users: # user が active かどうかのスコアを得る複雑な処理 active_score = # ... # 設定値を元にアクティブユーザーかどうかを判定 if active_score > Config.ACTIVE_USER_THRESHOLD: active_users.append(user) # ユーザーの X アカウント情報を取ってくる処理 result = [] for user in active_users: # 外部サイトへのリクエストをして X アカウント情報を取得 user_x_account = request( 'GET', 'https://x.com/users/~~~' ) result.append(user_x_account) return result
Slide 41
Slide 41 text
41 41 ©MIXI テストが書きづらい... def get_active_user_x_acounts (): from_time = datetime.now() - timedelta(days=3) # アクティブなユーザーを取ってくる処理 users = query(User).filter(user.updated_at > from_time).all() active_users = [] for user in users: # user が active かどうかのスコアを得る複雑な処理 active_score = # ... # 設定値を元にアクティブユーザーかどうかを判定 if active_score > Config.ACTIVE_USER_THRESHOLD: active_users.append(user) # ユーザーの X アカウント情報を取ってくる処理 result = [] for user in active_users: # 外部サイトへのリクエストをして X アカウント情報を取得 user_x_account = request( 'GET', 'https://x.com/users/~~~' ) result.append(user_x_account) return result 現在時刻、DBのレコードに依存 複雑なロジック 関数外の設定で挙動が変わる 外部リクエストに依存 テストパターン多くて重い、見づらい
Slide 42
Slide 42 text
42 42 ©MIXI テストを書きやすくするには?|テスタビリティを構成する特性 ● 実⾏円滑性(Operability) ○ テスト実⾏の際の⽀障のなさ。実⾏速度、バグの総数など。 ● 観測容易性(Observability) ○ テスト対象の出⼒、エラー、内部状態を確認しやすいか? ● 制御容易性(Controllability) ○ テスト対象はテストを⾏うための操作がしやすいか?(テスト⽤に内部の挙動を操作できるか?) ● 分解容易性(Decomposability) ○ 実⾏するテストの範囲を分離しやすいか?(依存をモックしたりして対象範囲のみテスト可能か?) ● 単純性(Simplicity) ○ テスト対象のコードや仕様はシンプルか? ● 安定性(Stability) ○ テスト対象はテスト負担を増やすような変更が少ないか?(仕様変更やそれによる影響が少ないか) ● 理解容易性(Understandability) ○ テストを⾏うための情報を得やすいか?(仕様書があるかなど)
Slide 43
Slide 43 text
43 43 ©MIXI テスタビリティの特性の観点で⾒てみる def get_active_user_x_acounts (): from_time = datetime.now() - timedelta(days=3) # アクティブなユーザーを取ってくる処理 users = query(User).filter(user.updated_at > from_time).all() active_users = [] for user in users: # user が active かどうかのスコアを得る複雑な処理 active_score = # ... # 設定値を元にアクティブユーザーかどうかを判定 if active_score > Config.ACTIVE_USER_THRESHOLD: active_users.append(user) # ユーザーの X アカウント情報を取ってくる処理 result = [] for user in active_users: # 外部サイトへのリクエストをして X アカウント情報を取得 user_x_account = request( 'GET', 'https://x.com/users/~~~' ) result.append(user_x_account) return result 現在時刻、DBのレコードに依存 → 内部挙動を制御しづらい (制御容易性が低い)
Slide 44
Slide 44 text
44 44 ©MIXI テスタビリティの特性の観点で⾒てみる def get_active_user_x_acounts (): from_time = datetime.now() - timedelta(days=3) # アクティブなユーザーを取ってくる処理 users = query(User).filter(user.updated_at > from_time).all() active_users = [] for user in users: # user が active かどうかのスコアを得る複雑な処理 active_score = # ... # 設定値を元にアクティブユーザーかどうかを判定 if active_score > Config.ACTIVE_USER_THRESHOLD: active_users.append(user) # ユーザーの X アカウント情報を取ってくる処理 result = [] for user in active_users: # 外部サイトへのリクエストをして X アカウント情報を取得 user_x_account = request( 'GET', 'https://x.com/users/~~~' ) result.append(user_x_account) return result 複雑なロジック → 仕様が難しい&変更があるとテストも 大幅に変わる... 処理ベタ書きでモックもできない... (分解容易性、単純性、安定性が低い)
Slide 45
Slide 45 text
45 45 ©MIXI テスタビリティが上がるようにリファクタしてみる def get_active_user_x_acounts (from_time): # アクティブなユーザーを取ってくる処理 users = get_users_recently_updated(from_time) active_users = select_active_users(users, Config.ACTIVE_USER_THRESHOLD) result = [] for user in active_users: user_x_account = get_user_x_acounts(user) result.append(user_x_account) return result def get_users_recently_updated (from_time): return query(User).filter(user.updated_at > from_time).all() def select_active_users (users, active_score_threshold ): return list(filter(None, [user for user in users if calc_active_score(user) > active_score_threshold else None])) def calc_active_score (user): # user が active かどうかのスコアを得る複雑な処理 return active_score def get_user_x_account (user): # 外部サイトへのリクエストをして X アカウント情報を取得 return request('GET', f'https://x.com/users/~~~' )
Slide 46
Slide 46 text
46 46 ©MIXI テスタビリティが上がるようにリファクタしてみる def get_active_user_x_acounts (from_time): # アクティブなユーザーを取ってくる処理 users = get_users_recently_updated(from_time) active_users = select_active_users(users, Config.ACTIVE_USER_THRESHOLD) result = [] for user in active_users: user_x_account = get_user_x_acounts(user) result.append(user_x_account) return result def get_users_recently_updated (from_time): return query(User).filter(user.updated_at > from_time).all() def select_active_users (users, active_score_threshold ): return list(filter(None, [user for user in users if calc_active_score(user) > active_score_threshold else None])) def calc_active_score (user): # user が active かどうかのスコアを得る複雑な処理 return active_score def get_user_x_account (user): # 外部サイトへのリクエストをして X アカウント情報を取得 return request('GET', f'https://x.com/users/~~~' ) 現在時刻を外部から指定できる! = 制御容易性 DBから取得する処理をモックしやすい! = 分解容易性
Slide 47
Slide 47 text
47 47 ©MIXI テスタビリティが上がるようにリファクタしてみる def get_active_user_x_acounts (from_time): # アクティブなユーザーを取ってくる処理 users = get_users_recently_updated(from_time) active_users = select_active_users(users, Config.ACTIVE_USER_THRESHOLD) result = [] for user in active_users: user_x_account = get_user_x_acounts(user) result.append(user_x_account) return result def get_users_recently_updated (from_time): return query(User).filter(user.updated_at > from_time).all() def select_active_users (users, active_score_threshold ): return list(filter(None, [user for user in users if calc_active_score(user) > active_score_threshold else None])) def calc_active_score (user): # user が active かどうかのスコアを得る複雑な処理 return active_score def get_user_x_account (user): # 外部サイトへのリクエストをして X アカウント情報を取得 return request('GET', f'https://x.com/users/~~~' ) 仕様が複雑な部分を個別テストできる! 本体のメソッドへの影響が減った! = 分解容易性, 単純性, 安定性
Slide 48
Slide 48 text
©MIXI テスト技法の話
Slide 49
Slide 49 text
©MIXI Q. どんなテストケースを設計するのが良いのか?
Slide 50
Slide 50 text
©MIXI A. ʻ最⼩の時間と労⼒でほとんどのエラーを 検出する可能性が最も⾼くなるように、 テストケースを設計しなければならない’ リー・コープランド 著 / 宗雅彦 訳, はじめて学ぶソフトウェアのテスト技法, https://bookplus.nikkei.com/atcl/catalog/05/P82510/
Slide 51
Slide 51 text
51 51 ©MIXI テスト技法 ● テストのレベル ○ 単体テスト (Unit testing) ■ もっとも⼩さなテスト ■ クラス、メソッド単位 (⾔語‧テストライブラリ等で異なる) ○ 統合テスト (Integration testing) ■ 単体テストよりも⼤きな範囲のテスト ○ システムテスト (System testing) ■ ソフトウェア全体のテスト ○ 受け⼊れテスト (User Acceptance Testing) ■ 顧客がソフトウェアを受け⼊れる時のテスト
Slide 52
Slide 52 text
52 52 ©MIXI テスト技法 ● テストの種別 ○ ブラックボックステスト ■ 仕様や要件に基づいてテストを実施するテスト ■ 実装レベルの知識は必要としない ○ ホワイトボックステスト ■ 実装レベルの知識に基づいて実施するテスト ■ ソフトウェアの内部パス、構造、実装 ... ○ グレーボックステスト ■ 実装をある程度調べた上で、ブラックボックステストのテストケースを効 率的に選択していく
Slide 53
Slide 53 text
53 53 ©MIXI テスト技法 ● ブラックボックステスト ○ 同値クラステスト ○ 境界値テスト ○ デシジョンテーブルテスト ○ ペア構成テスト ○ …. ● ホワイトボックステスト ○ 制御フローテスト ○ データフローテスト
Slide 54
Slide 54 text
54 54 ©MIXI テスト技法 同値クラステスト ○ 同値クラスに分け、代表値を選んでテストケースを作る ○ 例 ■ ⼊⼒値は0~100 ■ 0~19は未成年、20~100は成⼈ と返すプログラムを考える
Slide 55
Slide 55 text
55 55 ©MIXI テスト技法 境界値テスト ● 同値クラステストを元に、境界値に注⽬したテスト ● パーティションの最⼩値と最⼤値、または最初の値と最後の値を選んでテストする ● -1, 0, 19, 20, 100, 101
Slide 56
Slide 56 text
56 56 ©MIXI テストの7原則 1. テストは⽋陥があることは⽰せるが、⽋陥がないことは⽰せない 2. 全数テストは不可能 3. 早期テストで時間とコストを節約 4. ⽋陥の偏在 5. 殺⾍剤のパラドックスにご⽤⼼ 6. テストは状況次第 7. 「バグゼロ」の落とし⽳
Slide 57
Slide 57 text
57 57 ©MIXI その他テストに関するTIPS ● テストを書くのは⼤事だが、なるべく数を減らそう ○ 特に重いテストが多いと実⾏時間が伸びて⽣産性が下がる ● 確率的に落ちるテスト(Flaky Test)に対処していく ○ ⾃動テストの再実⾏が何度も必要だと、⽣産性は下がるし、CIのコストも上がる ○ テスト成功率などを監視して、よく落ちるものは早めに対処する ● QAエンジニアの⽅とはなるべく仕様設計の段階からコミュニケーションを取る ○ 早い段階で仕様の擦り合わせをすることで、擦り合わせのコストを減らしつつ、異常ケー スやQA実⾏の効率化について早めに対処ができる ● 重要なのは成果‧⽣産性が上がること ○ ⾃分が⼀⼈で頑張る以上に⽂化を作るのを頑張る ○ ⽅法論は重要だが、それに縛られず常に最善を⽬指すのが重要
Slide 58
Slide 58 text
©MIXI ペアプログラミング
Slide 59
Slide 59 text
59 59 ©MIXI ペアプログラミング ● ドライバー ○ 実際に操作する⼈ ● ナビゲーター ○ ドライバーの操作を眺めつつ、助ける⼈ ● 定期的に役割を⼊れ替えながら進める
Slide 60
Slide 60 text
60 60 ©MIXI ペアプログラミング うまくやるコツ ● ドライバー ○ 今、何をやろうとしているか、やっているかを明確にする (発⾔する) ● ナビゲーター ○ 良い⽅法を思いついたり、ミスに気づいたりしたときに、積極的に発⾔する ○ ドライバーが何をやろうとしていることが良くわからなくなったら、すぐに聞く commit & push してれば、役割交代はしやすいはず‧‧‧?
Slide 61
Slide 61 text
61 61 ©MIXI ペアプログラミング チーム分け(敬称略) A yamato.kato, ryotaro.tanaka B masayoshi.yamahira, satoshi.kanamori C kotaro.suto, shun.makino D kentaro.mizuki, shota.tanemura E junnosuke.kushibiki, takayuki.yamamoto F hayato.yamada, kaai.miyaki
Slide 62
Slide 62 text
©MIXI コードレビューをしよう
Slide 63
Slide 63 text
63 63 ©MIXI コードレビューをしよう ● チームごとにteam-A,B,...,F ブランチ向きにPRを作ってください ● レビューするチーム ● 演習1: A → B, B → C, C → D, D → E, E → F, F → A ● 演習2: A → C, B → D, C → E, D → F, E → A, F → B ● 時間が余ったら他のチームをレビューしてもOK
Slide 64
Slide 64 text
64 64 ©MIXI コードレビューをしよう ● コードレビューの⽬的 ○ コードの品質の保証 ○ コードの共有 ■ 設計や作戦の共有
Slide 65
Slide 65 text
65 65 ©MIXI コードレビューをしよう ● どうすれば、レビューが通りやすいかを考えよう ● PR の説明をしっかり書こう ○ どういう背景、理由で、どういうものを作った、など ○ 重点的にレビューして欲しいところや、実装していてよく分からなかったところ、など ○ ⾏単位でコメント/会話ができるのでそれも活⽤しよう ● JIRA のチケットや、関連 PR, issue など ○ 背景の詳細や、仕様などを追いやすい ○ 監査などのときに、追いやすい、など ● どういうタイミングでマージして欲しい、など (QA終わるまで待って、など)
Slide 66
Slide 66 text
66 66 ©MIXI コードレビューをしよう ● レビューは⼈格攻撃ではない (⼼理的安全性) ○ レビューする側もされる側も攻撃ではないことを意識する ● わからないところは聞こう ● 褒めよう! ● この⼈はこういうところをレビューしてくるだろうなぁと考えてみる
Slide 67
Slide 67 text
67 67 ©MIXI 参考⽂献 ● SQuBOK Guide V3 ● テスト駆動開発 ● 【翻訳】テスト駆動開発の定義 ● 保守しやすく変化に強いソフトウェアを⽀える柱 ⾃動テストとテスト駆動開 発 、その全体像 ● はじめて学ぶソフトウェアのテスト技法 ● ソフトウェアテスト技法 ● 「テスタビリティ」への投資で⽣産性向上!評価の指標と向上させるポイント
Slide 68
Slide 68 text
©MIXI