Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Humble Object Patternな話
Search
いも
February 21, 2019
Programming
2.3k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Humble Object Patternな話
Roppongi.unity #01の資料です
いも
February 21, 2019
More Decks by いも
See All by いも
UnityプログラミングバイブルR6号宣伝&Unity Logging小話
adarapata
0
640
Unityテスト活動のふりかえり
adarapata
1
670
Gather.townはいいぞ その後
adarapata
1
1.7k
Unityでの開発事例
adarapata
3
23k
どこのご家庭にもあるシーンマネージャーの話
adarapata
2
8.8k
Gather.townはいいぞ
adarapata
2
2.4k
宴はいいぞ
adarapata
0
2.2k
わかった気になるモブプログラミング
adarapata
1
180
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
1.3k
Other Decks in Programming
See All in Programming
act2-costs.pdf
sumedhbala
0
110
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
260
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
570
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
140
【やさしく解説 設計編 #1】「ドメイン駆動」と「実装駆動」ってなに? 〜設計の考え方を、たとえ話で学ぼう〜
panda728
PRO
1
110
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
510
OSINT for SRE: 学術論文とポストモーテムから探る システム障害の共通パターン / SRE NEXT 2026
tomoyk
1
3.4k
コーディングルールの鮮度を保ちたい for SRE NEXT 2026 / keep-fresh-go-internal-conventions-sre-next-2026
handlename
0
140
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
250
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
関数型プログラミングのメリットって何だろう?
wanko_it
0
160
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
310
Featured
See All Featured
Code Reviewing Like a Champion
maltzj
528
40k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
690
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Statistics for Hackers
jakevdp
799
230k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.2k
Mind Mapping
helmedeiros
PRO
1
280
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
Into the Great Unknown - MozCon
thekraken
41
2.6k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
360
Transcript
Humble Object Pattern な話 Roppongi.unity #1 2019/02/21 Roppongi.unity #1 2019/02/21
いもです いも(@adarapata) ゲー ムクライアントエンジニア adarapata.com Roppongi.unity #1 2019/02/21
ご注意 2019/1/23 にGotanda.unity #10 で発表した「 どこから始めるUnity Test」 の時間切れで話せなかった後半部分にフォー カスした内容です。 https://speakerdeck.com/adarapata/dokokarashi-meruunity-test
なので前回と若干被る話が多いのでご了承ください。 Roppongi.unity #1 2019/02/21
今日の話 Humble Object Pattern について Roppongi.unity #1 2019/02/21
前提 みんなテストが書きたくて手が震えている Roppongi.unity #1 2019/02/21
テストしにくさの元 密結合 static なインスタンス 入力イベントが絡む処理 UI が絡む処理 ファイル、DB などの外部リソー スが絡む処理
etc.. 実際問題、 どう綺麗に書いてもテストしにくい部分は出てくる Roppongi.unity #1 2019/02/21
テストピラミッド。 上位に行くほど難易度が高い Roppongi.unity #1 2019/02/21
コスト高いのでテスト避けたい わかる 時にはそういう判断も必要かもしれない 書かない ≠ 書けない 書けない理由は明らかにすべき。 ピラミッドの境界を跨ぐような処理を分割していく Roppongi.unity #1
2019/02/21
Humble Object Pattern とは テストしやすいものとしにくいものを住み分ける実装パター ン テストしにくいものの実装をHumble( 控え目) にする 多分初出は
xUnit Patterns http://xunitpatterns.com/Humble Object.html クリー ンアー キテクチャ本にも載ってたので有名かも Roppongi.unity #1 2019/02/21
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
書きにくさポイント 入力が絡むので書きにくい MonoBehavior の機能に依存しているので書きにくい SerializeField も同様 でも移動する部分は書きたい 書きやすいものと書きにくいものを切り分ける。 Unity における書きにくいものは大体MonoBehaviour
絡みなのでそこか ら切り出す。 Roppongi.unity #1 2019/02/21
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
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
変更点 移動処理の詳細と、Monobehavior が離れた 具体的な処理は PlayerUnitController に任せるようになった テストしやすいものとしにくいものに分かれた ピラミッドの境界が明確になった 切り分けられたので、 移動処理のテストも書ける。
入力のテストはやらない! 移動処理を行う側はインタフェー スだけ見ているので、 差し替えが楽。 Roppongi.unity #1 2019/02/21
IPlayerUnit は状況に応じて差し替えられる Roppongi.unity #1 2019/02/21
IPlayerUnit は状況に応じて差し替えられる Roppongi.unity #1 2019/02/21
テストコー ド 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
まとめ テストしにくい部分は発生する テストしにくいところとしやすいところを分けて、 書ける領域を増 やす Humble Object はそれらを切り分ける Roppongi.unity #1
2019/02/21