Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
WACATE2019_summer_BPP
Search
Daiki Katayama
June 15, 2019
Programming
2.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
WACATE2019_summer_BPP
WACATE2019 夏のBPPセッションスライドです。
Daiki Katayama
June 15, 2019
More Decks by Daiki Katayama
See All by Daiki Katayama
iOSアプリのパフォーマンス計測をおさらいする
kariad
2
9.9k
アプリのパフォーマンスを継続的に計測する
kariad
7
18k
Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?
kariad
3
5.2k
Viewのテストどうしてますか?
kariad
2
1.6k
コードカバレッジとの付き合い方を知ってテストを書く
kariad
2
2.6k
開発者として学ぶソフトウェアテスト
kariad
2
1.1k
Other Decks in Programming
See All in Programming
気持ちぃ〜角丸 Squircle
ryu1013
0
220
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.8k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
540
パーソナライズPodcastを作った話
repunit11
0
130
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
280
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
1
2.3k
When benchmarks go bad - what I learned from measuring performance wrong
hollycummins
0
200
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
610
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
200
APNsからLive Activityを開始する話
yumnumm
0
160
プロダクトコードからライブラリの境界を見つける
elmetal
PRO
0
110
Domain-Driven Transformation
hschwentner
2
2.3k
Featured
See All Featured
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Building an army of robots
kneath
307
47k
Git: the NoSQL Database
bkeepers
PRO
433
67k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.7k
Visualization
eitanlees
153
17k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
530
Odyssey Design
rkendrick25
PRO
2
870
Designing Experiences People Love
moore
143
24k
Docker and Python
trallard
47
4.2k
How STYLIGHT went responsive
nonsquared
100
6.3k
Transcript
։ൃऀ͔ΒݟΔςετ 2019/06/15~16 WACATE2019 Ն BPPηογϣϯ kariad/͔Γ͋Ͳ(@kariad_uu) 1
ࣗݾհ • kariad / @kariad_uu • ยࢁ େथ • ΦΠγοΫεɾϥɾେ
iOS App Developer • / / V / ςετ / ઃܭ / ྉཧ / ήʔϜ 2
ςετͱͷؔΘΓ • ৽ଔ: SIer ͻͨ͢ΒؤுΔखಈςετɺऴΘΒͳ͍ɺؼΕͳ͍ɺਏ͍…. • ҟಈ: ΞδϟΠϧɺTDDɺςετָ͍͠ • స৬:
ΞδϟΠϧɺUnitςετಋೖɺςετ͍͖ͬͯ • QAΤϯδχΞɺςετΤϯδχΞͱݺΕΔํͱҰॹʹࣄΛͨ͜͠ ͱͳ͍Ͱ͢ 3
ࠓ͢͜ͱ • લճͷࢲͷϙδγϣϯϖʔύʔৼΓฦΓ • ։ൃऀ(ࢲ)͜͏͍͏෩ʹςετʹ͖߹ͬͯ·͢ͱ͍͏ - ςετͷϞνϕʔγϣϯ - ։ൃऀ͕ςετΛ͠ͳ͍(Ͱ͖ͳ͍)ཧ༝ 4
ҙʂ • ͋͘·Ͱࢲͷओ؍Ͱ͢ɻશͯͷ։ൃऀ͕͜͏Ͱ͋Δʂͱ͍ ͏Ͱͳ͍ͷͰྃ͝ঝ͍ͩ͘͞
લճ(WACATE2018 ౙ)ͷ ࢲͷϙδγϣϯϖʔύʔ 6
7
վΊͯݟͨ࣌ͷࢲͷײ • ΈΜͳͱൺͯϑΥϯτ͕Ͱ͔͍ • †ͱ͔ͬͯதೋප • ͳΜ͔ΤϞ͍͚ͩ • ਖ਼ͪΐͬͱஏ͔͔ͣͬͨ͠… 8
ͭ·ΓԿ͕ݴ͍͔ͨͬͨͷ͔ • ։ൃऀ͔ΒࢹͰͷςετͷ͍ ςετ͕͋Δ͜ͱͰ৺ཧత҆શੑͷ͋Δ։ൃ͕Ͱ͖Δ ͰΔ͔ΒʹޮతʹΓ͍ͨ • ςετ͕͖͔ͩΒྑͯ͘͠Ͷ ςετք۾ͷίϛϡχςΟॳࢀՃͩͬͨ 9
• ࠓճΓ߹͍ͱ͔΄΅͍ͳ͍ͷͰؾܰʹ͔͚ͯ͘͠ ΕΔͱخ͍͠Ͱ͢ 10
։ൃऀͷςετͷ͖߹͍ํ
ςετͷϞνϕʔγϣϯ (ࢲͳΓʹ) 12
• ࢲͨͪͷϛογϣϯϢʔβʔʹͱͬͯՁ͋Δ αʔϏεΛఏڙ͢Δ͜ͱ • Ձ͕͋Δ = ͓٬༷(Ϣʔβʔ)͕خ͍͔͠ 13
• Ͱ࠷ॳ͔Β࠷େԽ͞ΕͨՁΛఏڙ͢Δͷ͍͠ • ߟ͑ͨ͜ͱ͕ਖ਼͍͠(Ձ͕͋Δ)ͱݶΒͳ͍ ϦʔϯɾελʔτΞοϓ 14
ϦʔϯɾελʔτΞοϓ 15
ϦʔϯɾελʔτΞοϓ • ݁ہͲΜͳʹ͍͍ͷΛߟ͑ͨͱ͜ΖͰͦΕࢥ͍ࠐΈԾ આʹ͗͢ͳ͍ • MVP(Minimum Valuable Product)Ͱݕূ͢Δ • Ծઆ
→ Ծઆݕূ → ֶͼ →ҙࢥܾఆͷαΠΫϧΛճ͢ 16
࠷ۙͷτϨϯυʁ (σʔλੳΛݩʹͨ͠։ൃ) • ԾઆΛݩʹ࣮ͯ͠ϦϦʔε • σʔλΛऔಘͯ͠ੳ • ੳ݁ՌΛݩʹվળͯ͠ϦϦʔε
• ͲͪΒͱʹ͔͘ૣ͘αΠΫϧΛճ͍ͨ͠ • ͱ͍͑όά͕͋Γਖ਼ৗʹ͑ͳ͚ΕԾઆݕূͰ͖ͳ ͍ ࠷ݶCheckingߦ͍͍ͨ 18
• ΞδϟΠϧ։ൃऀͱͯ͠ૣ͘Ձͷ͋ΔαʔϏεΛఏ ڙ͢ΔͨΊʹCheckingΛ͍ͨ͠ ʢ࣭͕͔ͦͦͬͨΒՁԼ͕Δ…ʣ 19
͡Ό͋ͳΜͰChecking(ࠓճUnitςετ) Βͳ͍ͷʁ 20
• ΊΜͲ͍͘͞ • ςετʹڵຯ͕ͳ͍ • Γํ͕Θ͔Βͳ͍ • CheckingͷॏཁੑΛཧղ͍ͯ͠ͳ͍
• ΊΜͲ͍͘͞ • ςετʹڵຯ͕ͳ͍ • Γํ͕Θ͔Βͳ͍ • CheckingͷॏཁੑΛཧղ͍ͯ͠ͳ͍ ͬͱݴ͏ͱɺ Γͨͯ͘Ͱ͖ͳ͍
• ΊΜͲ͍͘͞ • ςετʹڵຯ͕ͳ͍ • Γํ͕Θ͔Βͳ͍ • CheckingͷॏཁੑΛཧղ͍ͯ͠ͳ͍ ͬͱݴ͏ͱɺ Γͨͯ͘Ͱ͖ͳ͍
ࢲ͕ߟ͑ΔUnitςετΛ Βͳ͍ཧ༝ͷେ͖ͳҰͭ
Unitςετ࣮ͬͯͦΜͳʹ ؆୯Ͱͳ͍ 24
ςετΛॻ͘ͷ͕͍͠ཧ༝ • ςετ͕ॻ͖͍͢ઃܭ(Testable)ʹͳ͍ͬͯͳ͍ͱॻ͘͜ ͱ͕͍͠ • (ແཧཧ)ॻ͚ͯځ۶Ͱมߋʹऑ͘ͳΔ • ޙ͔Βઃܭมߋຊʹେม…(ςετ͕ͳ͍ͱঘߋ) 25
• ଟ͘ͷ߹ઃܭʹ͕͋Δ • ͪΖΜϑϩʔతͳͷ߹͋Δ UnitςετΛॻ͘ϑϩʔʹͳ͍ͬͯͳ͍ɻ͕࣌ؒͳ͍ɻ 26
ͦͦઃܭͱ ”ؔ৺ͷʹΑͬͯ ෳࡶͳΛ୯७ͳͷ܈ͱͯ͠Γ͚Δ͜ͱ” -iOSΞϓϦઃܭύλʔϯೖ P23 ΑΓ 27
• ࠷ۙυϝΠϯతʹٕज़తʹෳࡶԽ͍ͯ͠Δ • ͦͷͨΊʹઃܭΛߦ͍ෳࡶ͞ʹཱ͔ͪ͏ • ͖ͪΜͱઃܭ͞Ε͍ͯΔ = ͕୯७Խ͞Ε͍ͯΔ TestableͷୈҰา
28
ઃܭύλʔϯ(ΞʔΩςΫνϟ) • MVC / MVP / MVVM / Clean Architecture
/ Flux… • ઃܭํͱͯ͠ͷϕετϓϥΫςΟεू • ͜ΕΒͷଟ͘Testableಉ࣌ʹߟ͑ΒΕ͍ͯΔ 29
ςετ͕ॻ͖͍͢ઃܭͱ • ͕୯७Խ͞Ε͍ͯΔ Ϟδϡʔϧ͝ͱʹςετ͍͕ͨ͠γϯϓϧͰ໌֬ • Ϟδϡʔϧؒͷґଘੑ͕ͳ͍ ςετ͍͕ͨ͠ଞϞδϡʔϧͷӨڹΛड͚ͳ͍ 30
ෳࡶͳΛ࣋ͬͨϞδϡʔϧ • xxઍߦΈ͍ͨͳΫϥε • ͗ͯ͢ԿΛ͍ͬͯΔͷ͔Θ͔Βͳ͍ϝιου • ͨΒͱίϝϯτͰઆ໌ͯ͋͠Δ(ݸਓతҙݟ) 31
աଟΛͲ͏ݟ͚Δ͔ʁ 32
“ίʔυͷΛௌ͘” 33
• ςετ͕ॻ͖ͮΒ͍… • ॲཧ͕ෳࡶԽ͖͍ͯͯ͠Δ… • ඞͣͦ͜ʹࠟ͋Δ • ίʔυͷष͍ͱ 34
ઃܭͷݪଇ • ༗໊ͳͷͰSOLIDݪଇ • ୯Ұݪଇɺ։์ดݪଇɺϦείϑͷஔݪଇɺΠϯ λʔϑΣʔεͷݪଇɺґଘؔٯసͷݪଇ • ઃܭͷݪଇΛ༻͍ͯίʔυͷष͍ΛऔΓআ͘
Ϟδϡʔϧؒͷґଘੑ͕͋Δ • ଞϞδϡʔϧͷ࣮͕มΘΔ͜ͱͰͪ͜Βͷॲཧ͕ӨڹΛड ͚ͯ͠·͏͜ͱ 36
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } 37
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } ͜͜ͷॲཧΛςετ͍ͨ͠ 38
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } SearchModelͷ࣮ʹ ґଘ͍ͯ͠Δ 39
func didTapSearchButton(text: String?) { ~~~ লུ ~~~ SearchModel().search(searchWord: searchWord) {
result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } SearchModelͷ࣮͕มΘΔͱ ͪ͜Βͷ݁ՌมΘͬͯ͠·͏ 40
func didTapSearchButton(text: String?, model: SearchModel) { ~~~ লུ ~~~ model.search(searchWord:
searchWord) { result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } ֎ଆ͔ΒΦϒδΣΫτΛ ͢Α͏ʹ 41
func didTapSearchButton(text: String?, model: SearchModelProtocol) { ~~~ লུ ~~~ model.search(searchWord:
searchWord) { result in switch result { case .success(let events): ~~ লུ ~~ case .failure: ~~ লུ ~~ } } } ͢ܕΛநԽ͞Εͨ ܕʹ͢Δ 42
43 protocol SearchEventModelProtocol { func search(searchWord: String, completion: @escaping ((Result<[ConnpassEvent]>)
-> ())) } Protocol
class FakeSearchEventModel: SearchEventModelProtocol { var search_successValue = [ConnpassEvent]() func search(searchWord:
String, completion: @escaping ((Result<[ConnpassEvent]>) -> ())) { search_callCount += 1 search_arguments = searchWord completion(.success(search_successValue)) } } class FakeFailureSearchEventModel: SearchEventModelProtocol { func search(searchWord: String, completion: @escaping ((Result<[ConnpassEvent]>) -> ())) { search_arguments = searchWord completion(.failure) } } ελϒ ґଘ͢ΔΦϒδΣΫτͷ݁ՌΛ ίϯτϩʔϧͰ͖Δ
• ͜ͷґଘ͢ΔΦϒδΣΫτΛ֎ଆ͔Β্ͯ͛͠Δ͜ͱ ΛDI(Dependency Injection)ͱ͍͏ • ͢ΦϒδΣΫτநԽ͞Ε͍ͯΔͷͰɺςετίʔ υ͔ΒελϒΛ͢͜ͱ͕Ͱ͖Δ • Modelͷ࣮ʹґଘͤͣޭɺࣦഊͦΕͧΕͷςετ͕ ՄೳͱͳΔ
45
• ࣮ࡍʹJavaͰ͋ΕMockitoΛ͑͏গָ͠ʹͳͬ ͨΓ͋Δ • ͕ɺSwiftͰϥΠϒϥϦΛ༻͍ͳ͍͜ͷύλʔϯ͕ൺֱ తଟ͍ • ͜ΕΒͷ͕ࣝͳ͍ͱॻ͘͜ͱ͕͍͠ 46
ઃܭҎ֎ͷཁૉ • ςεςΟϯάϑϨʔϜϫʔΫͷ͍ํ(XCTest, Quick/Nimble) • ඇಉظॲཧͷςετ • ಛʹඇಉظ׳Εͳ͍ͱ͍͠ iOSͰReactiveX(RxSwift)͕ελϯμʔυ(Combine) 47
ReactiveX • FRP(Functional Reactive Programming) • ͬ͘͟Γ͍͏ͱStreamͱ͍͏࣌ؒͷྲྀΕΛ༻͍ͯඇಉظॲཧΛ؆ ܿʹॻ͚ΔΑ͏ʹͨ͠ख๏ • บ͕͋ΔͷͰ׳Εͳ͍ͱগ͍͠͠
• ςετͰಉظతʹѻͬͯ͋͛ͨΓɺςετ༻ͷStreamͰཧͨ͠Γ 48
ςετΛॻͨ͘ΊʹΒͳ͖Ό ͍͚ͳ͍͜ͱଟ͍ 49
• Βͳ͍ͷͰͳ͘ΔεΩϧ͕ແ͔ͬͨ • Γͨͯ͘αΫοͱͰ͖ΔઃܭͰແ͔ͬͨ • Ͱ͜ͷลͷࣝɺͲ͜Ͱֶ͍͍ͷ…ʁ
ֶͿͨΊͷ໌Δ͍ஹ͠ 51
ίϛϡχςΟͷಇ͖ • ςετʹؔ͢Δษڧձ (TestNight) • ΫϥυϑΝϯσΟϯά(PEAKS)ʹΑΔ Android / iOSςετશॻץߦ(iOS8݄༧ఆ) 52
ٕज़ॻయ લճࢲ͜Μͳͷग़͠·ͨ͠
·ͱΊ • গͳ͘ͱϞόΠϧΞϓϦ։ൃऀͰςετʹର͢Δҙࣝ ؒҧ͍ͳ͘ߴ·͍ͬͯΔ(ͱࢥ͏) • αʔόɺϑϩϯτͳͲϑϨʔϜϫʔΫͷൃలΞδϟΠϧ ͷਁಁͱͱʹҙࣝߴ·͍ͬͯΔΑ͏ʹݟ͑Δ 54
• ؍ଌൣғͰςετΛͲ͏ʹ͔͍ͨ͠ͱࢥ͍ͬͯΔ։ൃ ऀ͕ଟ͍ • Ձ͋ΔαʔϏεΛಧ͚͍ͨͱ͍͏ࢥ͍୭͠ಉ͡ͳ ͣ • ։ൃऀ/ςετΤϯδχΞ͕ڠྗͯ͠ςετʹର͢Δݟ ΛਂΊ͍͚ͯͨΒخ͍͠ 55
• iOSΞϓϦઃܭύλʔϯೖ ؔ ོٛɾদؗ େًɾླ େوɾਿ্ ༸ฏɾ࢙ ᠳ৽ɾాத ݡ ࣏ɾՃ౻
ਓ ஶ https://peaks.cc/books/iOS_architecture • Clean Architecture ୡਓʹֶͿιϑτΣΞͷߏͱઃܭ Robert.C.Martinஶ ֯ యɾߴ ਖ਼߂ ༁ ࢀߟॻ੶
• Test Night https://testnight.connpass.com/ • Androidςετશॻ https://peaks.cc/books/android_testing • iOSςετશॻ https://peaks.cc/iOS_testing
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ 58