Successfully reported this slideshow.
Your SlideShare is downloading. ×

Humble Object Patternな話

Ad

Humble Object Patternな話
Roppongi.unity #1 2019/02/21
Roppongi.unity #1 2019/02/21

Ad

いもです
いも(@adarapata)
ゲームクライアントエンジニア
adarapata.com
Roppongi.unity #1 2019/02/21

Ad

ご注意
2019/1/23にGotanda.unity #10で発表した「どこから始めるUnity
Test」の時間切れで話せなかった後半部分にフォーカスした内容です。
https://speakerdeck.com/adarapata/dok...

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Loading in …3
×

Check these out next

1 of 18 Ad
1 of 18 Ad

Humble Object Patternな話

Download to read offline

Roppongi.unity #01のLT資料です。
SpeakerDeckにアップロードできなかったのでSlideShareに上げています。
最新のスライドは以下から
https://speakerdeck.com/adarapata

Roppongi.unity #01のLT資料です。
SpeakerDeckにアップロードできなかったのでSlideShareに上げています。
最新のスライドは以下から
https://speakerdeck.com/adarapata

Advertisement
Advertisement

More Related Content

Advertisement

Humble Object Patternな話

  1. 1. Humble Object Patternな話 Roppongi.unity #1 2019/02/21 Roppongi.unity #1 2019/02/21
  2. 2. いもです いも(@adarapata) ゲームクライアントエンジニア adarapata.com Roppongi.unity #1 2019/02/21
  3. 3. ご注意 2019/1/23にGotanda.unity #10で発表した「どこから始めるUnity Test」の時間切れで話せなかった後半部分にフォーカスした内容です。 https://speakerdeck.com/adarapata/dokokarashi-meruunity-test なので前回と若干被る話が多いのでご了承ください。 Roppongi.unity #1 2019/02/21
  4. 4. 今日の話 Humble Object Pattern について Roppongi.unity #1 2019/02/21
  5. 5. 前提 みんなテストが書きたくて手が震えている Roppongi.unity #1 2019/02/21
  6. 6. テストしにくさの元 密結合 staticなインスタンス 入力イベントが絡む処理 UIが絡む処理 ファイル、DBなどの外部リソースが絡む処理 etc.. 実際問題、どう綺麗に書いてもテストしにくい部分は出てくる Roppongi.unity #1 2019/02/21
  7. 7. テストピラミッド。上位に行くほど難易度が高い Roppongi.unity #1 2019/02/21
  8. 8. コスト高いのでテスト避けたい わかる 時にはそういう判断も必要かもしれない 書かない≠ 書けない 書けない理由は明らかにすべき。 ピラミッドの境界を跨ぐような処理を分割していく Roppongi.unity #1 2019/02/21
  9. 9. Humble Object Pattern とは テストしやすいものとしにくいものを住み分ける実装パターン テストしにくいものの実装をHumble(控え目)にする 多分初出はxUnit Patterns http://xunitpatterns.com/Humble Object.html クリーンアーキテクチャ本にも載ってたので有名かも Roppongi.unity #1 2019/02/21
  10. 10. public class PlayerUnit : MonoBehaviour { [SerializeField] private float _speed = 1F; void Update() { var horizontal = Input.GetAxis("Horizontal"); var vertical = Input.GetAxis("Vertical"); Move(new Vector3(horizontal, vertical)); } private void Move(Vector3 direction) { transform.position += direction * _speed; } } きちんと任意の方向に動くかテストを実装したい Roppongi.unity #1 2019/02/21
  11. 11. 書きにくさポイント 入力が絡むので書きにくい MonoBehaviorの機能に依存しているので書きにくい SerializeFieldも同様 でも移動する部分は書きたい 書きやすいものと書きにくいものを切り分ける。 Unityにおける書きにくいものは大体MonoBehaviour絡みなのでそこか ら切り出す。 Roppongi.unity #1 2019/02/21
  12. 12. public interface IPlayerUnit { float Speed { get; } Vector3 Position { get; set; } } // MonoBehavior成分を0にしたけど、移動ロジックを持つクラス public class PlayerUnitController { private readonly IPlayerUnit _unit; public PlayerUnitController(IPlayerUnit unit) { _unit = unit; } public void Move(Vector3 direction) { _unit.Position += direction * _unit.Speed; } } テストを書きにくいMonobehaviorからロジックを抽出するRoppongi.unity #1 2019/02/21
  13. 13. public class PlayerUnitHumble : MonoBehaviour, IPlayerUnit { [SerializeField] private float _speed = 1F; private PlayerUnitController _controller; public float Speed => _speed; public Vector3 Position { get => transform.position; set => transform.position = value; } void Start() => _controller = new PlayerUnitController(this); void Update() { var horizontal = Input.GetAxis("Horizontal"); var vertical = Input.GetAxis("Vertical"); _controller.Move(new Vector3(horizontal, vertical)); } } Roppongi.unity #1 2019/02/21
  14. 14. 変更点 移動処理の詳細と、Monobehaviorが離れた 具体的な処理は PlayerUnitController に任せるようになった テストしやすいものとしにくいものに分かれた ピラミッドの境界が明確になった 切り分けられたので、移動処理のテストも書ける。 入力のテストはやらない! 移動処理を行う側はインタフェースだけ見ているので、差し替えが楽。 Roppongi.unity #1 2019/02/21
  15. 15. IPlayerUnitは状況に応じて差し替えられる Roppongi.unity #1 2019/02/21
  16. 16. IPlayerUnitは状況に応じて差し替えられる Roppongi.unity #1 2019/02/21
  17. 17. テストコード public class PlayerUnitTest { // テスト用のいい感じモック public class MockPlayerUnit : IPlayerUnit { public float Speed { get; set; } public Vector3 Position { get; set; } } [Test] public void PlayerUnitMove() { var unit = new MockPlayerUnit { Speed = 5, Position = Vector3.zero }; var controller = new PlayerUnitController(unit); controller.Move(Vector3.up); Assert.AreEqual(new Vector3(0,5F,0), unit.Position); } } Roppongi.unity #1 2019/02/21
  18. 18. まとめ テストしにくい部分は発生する テストしにくいところとしやすいところを分けて、書ける領域を増 やす Humble Objectはそれらを切り分ける Roppongi.unity #1 2019/02/21

×