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
WACATE2019_summer_BPP
Search
Daiki Katayama
June 15, 2019
Programming
1
2.1k
WACATE2019_summer_BPP
WACATE2019 夏のBPPセッションスライドです。
Daiki Katayama
June 15, 2019
Tweet
Share
More Decks by Daiki Katayama
See All by Daiki Katayama
iOSアプリのパフォーマンス計測をおさらいする
kariad
1
8.5k
アプリのパフォーマンスを継続的に計測する
kariad
6
15k
Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?
kariad
3
4.1k
Viewのテストどうしてますか?
kariad
2
1.4k
コードカバレッジとの付き合い方を知ってテストを書く
kariad
2
2.3k
開発者として学ぶソフトウェアテスト
kariad
2
920
Other Decks in Programming
See All in Programming
最古の関数型言語「Lisp」ことはじめ / lisp_in_kamiyama
uhooi
1
190
今こそ始める、CDKコンストラクトライブラリ開発 ― 入門から実践まで
tmokmss
1
930
Advanced App Shrinking Techniques
cbeyls
2
150
SDCon2024: Enabling DevOps and Team Topologies thru architecture: architecting for fast flow
cer
PRO
0
780
CSC307 Lecture 09
javiergs
PRO
1
500
The rollercoaster of releasing an Android, iOS, and macOS app with Kotlin Multiplatform | droidcon Berlin
prof18
0
110
Trial
cairolibrary720
1
130
Rust.Nagoya #1
codemountains
0
170
Google's Recipe for Scaling (Web) Security – LocoMocoSec 2024
lweichselbaum
0
170
Clean Architecture by TypeScript & NestJS
ryounasso
0
150
社内 LT 会を発足し、アウトプット文化を醸成させるために考えたこと・やったこと / Starting internal LT meetings and fostering an output culture
mackey0225
3
120
CSC307 Lecture 10
javiergs
PRO
0
310
Featured
See All Featured
Done Done
chrislema
179
15k
Automating Front-end Workflow
addyosmani
1362
200k
Designing Experiences People Love
moore
136
23k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
121
18k
Robots, Beer and Maslow
schacon
PRO
157
8.1k
How STYLIGHT went responsive
nonsquared
93
5k
Typedesign – Prime Four
hannesfritz
37
2.2k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
129
32k
Faster Mobile Websites
deanohume
303
30k
Rails Girls Zürich Keynote
gr2m
93
13k
Adopting Sorbet at Scale
ufuk
71
8.8k
Building a Scalable Design System with Sketch
lauravandoore
458
32k
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