ϞόΠϧΞϓϦ։ൃͷඪ४Λ୳Δ$PPLQBE5FDI$POG SE+BO'6+*(PSPHPSPGVKJ!DPPLQBEDPN
View Slide
͡Ίʹ• ໊લ• FUJI Goro (GitHub: gfx, Twitter: @__gfx__)• ෦ॺ• ٕज़෦ ϞόΠϧ։ൃج൫• ۙگ• Ϛάωοτגࣜձࣾʹग़தʢ20159݄~ʣ
͜ͷτʔΫͷഎܠ• 20161݄ݱࡏɺΫοΫύουεϚϗλϒϨοτͳͲɺϞόΠϧͰͷΞΫηε͕աΛ͍͑ͯΔ• ͦΕΏ͑ʹϞόΠϧΞϓϦ։ൃͷن͕େ͖͘ͳͬͨ• ୯ҰͷAndroidΞϓϦɺiOSΞϓϦʹͷΈؔΘΔΤϯδχΞ૬ରతʹগͳ͘ͳͬͨ• ҰํͰʮΫοΫύουʯαʔϏεͷण໋͕҆͘ఆͯ͠։ൃɾӡ༻Ͱ͖Δ͜ͱ͕ٻΊΒΕΔ
ϞόΠϧ͔ΒͷΞΫηεͷ༁• PC vs εϚϗ• ΞΧϯτ࣋ͪϢʔβʮεϚϗͷΈʯ͕8ׂ• ήετϢʔβͷ͏ͪʮεϚϗʯ7ׂ• ΞϓϦ vs Σϒ• ΞΧϯτ࣋ͪϢʔβʮΞϓϦͷΈʯ͕6ׂ• ήετϢʔβͷ͏ͪʮΞϓϦʯ1ׂ
։ൃʹ͓͚Δʮඪ४ʯͱʁ• ʮඪ४తͳ։ൃʯΛʮޮՌͱίετͷόϥϯε͕Α͘ೲಘײͷ͋Δ։ൃʯͱߟ͑Δ• ͭ·Γʮඪ४తͰͳ͍։ൃʯͱʮௐͯΘ͔Βͳ͍ൿͷλϨ͕ଟ͘ɺཧෆਚʹײ͡Δ։ൃʯͱͳΔ• ʮރΕٕͨज़ʯͷ͜ͱͱݶΒͳ͍ɻڥͷมԽʹ͍͍ͭͯ͘͜ͱେࣄɻ
ΫοΫύουͷߟ͑Δඪ४తͳϞόΠϧΞϓϦ։ൃw ৽ٕज़ͷಋೖw $* 5FTU 2"w '54
৽ٕज़ͷಋೖ
͜͜Ͱ͍͏ʮ৽ٕज़ʯͱ• ϓϩάϥϛϯάݴޠʢe.g. Swiftʣ• ϑϨʔϜϫʔΫϥΠϒϥϦʢe.g. RxJavaʣ• ϓϩτίϧʢe.g. HTTP/2ʣ• σʔλϑΥʔϚοτʢe.g. WebPʣ• ΞʔΩςΫνϟʢe.g. MVVM, Clean Architectureʣ• ͦͷଞιϑτΣΞɾαʔϏε
৽ٕज़Λಋೖ͢Δͱ͍͏͜ͱ• جຊతʹੵۃతʹ࠾༻͢Δํ• ͦΕ͕Ͳ͏͍͏Λղܾ͢Δͷ͔Λ͖ͪΜͱ໌Β͔ʹ͢Δ͜ͱ• ʮ͏ਓಋೖऀ͚ͩʯආ͚Δ͖ࣄଶ• ৽ٕज़ಋೖͷࡍࣾษڧձϒϩάͳͲͰੵۃతʹܒ׆ಈΛߦͳ͍ͬͯΔ• cf. Android։ൃͰRxJavaΛνʔϜʹಋೖͨ͠
ಋೖࡁΈɾݕ౼தͷٕज़• ಋೖࡁΈ• WebP, Shared Web Credentials, Smart Lock forPasswords, Retrolambda, Dokumi, Pull-RequestBuilder• ݕ౼த• Swift, Kotlin, fastlane, Issue Tracking System, CIas a Service (Travis, CircleCI)
ྫ4XJGU• 201512݄ʹOSSԽ͞ΕͨiOS༻ͷϓϩάϥϛϯάݴޠ• ৽نͰSwiftΛͬͨΞϓϦ͋Γ• طଘͷObjective-CΛॻ͖͑ΔͷҰྫ͚ͩ͋Γ• Global Cookpad iOS app• SwiftͷӨڹͰ࣮͞ΕͨObjective-Cͷ৽ػೳੵۃతʹ͍ͬͯ͘ํʢͨͱ͑δΣωϦΫεʣ• AppleʹΑΓະདྷ͕ଋ͞Ε͍ͯΔ
ྫ,PUMJO• JetBrainsࣾͷ։ൃ͢ΔJVM༻ͷϓϩάϥϛϯάݴޠ• Android༻ͷϓϩάϥϛϯάݴޠͱͯ͠͞Ε͍ͯΔ• ߏจ (Java + Swift) / 2 ͱ͍ͬͨͱ͜Ζ• ݴޠ༷͔ͳΓΑ͘IDEͷαϙʔτे• ϥΠϯλΠϜͷϑοτϓϦϯτ1MBఔͱখ͞Ί• Javaͷࢿ࢈Λͦͷ··͑ͯίʔυྔJavaΑΓগͳ͍• ͨͩ͜ΕʹΑͬͯʮԿΛղܾ͢Δͷ͔ʯ͖ͬΓͱ͠ͳ͍
$* 5FTU 2"
ϞόΠϧΞϓϦͷಛʢʣ• Ϣʔβʔ͕͏όʔδϣϯΛ੍ޚͰ͖ͳ͍• Ϣʔβʔ͕ΞϓϦͷΞοϓσʔτΛ͢ΔͱݶΒͳ͍͠ɺ࣮ࡍΞοϓσʔτΛ͠ͳ͍Ϣʔβ͍Δ• ʮΞοϓσʔτͷڧ੍ʯ͠ͳ͍ํͰ͖͍ͯΔ• Android৽͍͠ύʔϛογϣϯΛՃ͢ΔͱݦஶʹΞοϓσʔτ͕͕͞Δ• ύʔϛογϣϯΛՃ͢ΔͱࣗಈΞοϓσʔτ͕ޮ͔ͳ͘ͳΔͨΊɻAndroid 6.0Ͱվળ͞Ε͕ͨະීٴ
ϞόΠϧΞϓϦͷಛʢʣ• ࣮ߦڥΛ੍ޚ͢Δ͜ͱͰ͖ͳ͍• ͷεϖοΫ / OSͷόʔδϣϯ / ௨৴ڥ·ͪ·ͪ• ΣϒΞϓϦΑΓࣦഊ͕ॏ͘ςετ͍͠• ςετίʔυΣϒΞϓϦΑΓॻ͘ͷ͕͍͠• ίʔυϨϏϡʔɾCIɾQAͳͲͷ࣭ཧ͕ॏཁ
$*+FOLJOT NVMUJTMBWFT• AndroidLinux/EC2• iOSMac࣮ػ• Travis CI, Circle CIͳͲݕ౼͕ͨ͠ະಋೖ• ίετʹରͯͦ͜͠·Ͱར͕ͳ͍ͱ͍͏அ• ڥΛ੍ޚ͍͢͠ͱ͍͏རΛͱ͍ͬͯΔ
"OESPJE$*ϚγϯςετσόΠεͷมભ1. EC2 + emulator2. Macbook ProʢiOS CIͱಉ͡Ϛγϯʣ + ࣮ػ3. ϋΠεϖοΫLinuxϚγϯ + ࣮ػ• εέʔϧΞοϓͰͦͦ͜͜շద4. EC2 + emulator• ؆୯ʹεέʔϧΞτͰ͖ΔΑ͏ʹͨ͠• ϨΠςϯγΑΓεϧʔϓοτΛͱͬͨ݁Ռ
1VMM3FRVFTU#VJMEFS• JenkinsͷpluginͰɺPR͝ͱʹCIΛىಈ͢Δ• master branchʹcommit / push͢Δͷېࢭ• Ϗϧυʴςετ͕ύε͠ɺϨϏϡʔΛ௨ͬͨΒϚʔδՄ
1VMM3FRVFTU#VJMEFS͕ߦ͏͜ͱ• Pull-Request Builder (+Dokumi)• ςετΛ࣮ߦͯ͠PRʹࣦഊϝοηʔδΛϙετ• ੩తղੳΛ࣮ߦͯ͠PRͷ֘ՕॴʹϝοηʔδΛϙετ• ػցʹίʔυϨϏϡʔͤͯ͞ਓͷෛ୲ΛݮΒ͢• ΞϓϦύοέʔδΛϏϧυʢapk, ipaʣ• ΞϓϦύοέʔδΛDeployGateʹΞοϓϩʔυ• ΤϯδχΞҎ֎Ͱ։ൃதͷ৽ػೳΛࢼ͘͢͠
6OJU5FTU2"• ςετΤϯδχΞ2ਓମ੍• 2ਓڞίʔυΛॻ͚Δ• ςετίʔυϓϥοτϑΥʔϜ͝ͱͷඪ४ςετϑϨʔϜϫʔΫʢAndroid JUnit4, XCTestʣ• ։ൃऀॻ͘͠ɺςετΤϯδχΞॻ͘• AppiumπʔϧʹΑΔࣗಈԽ͞Εͨςετɺख࡞ۀʹΑΔςετ࣮ࢪ
'BJMVSF5FBDIFT4VDDFTT
'BJMVSF5FBDIFT4VDDFTT• োϨϙʔτͷϑΥʔϚοτɿ• ʹ͍ͭͯνʔϜͰ͠߹͏͜ͱ• ͳͥͦͷΛൃੜͤͯͨ͞ͷ͔Λهࡌ͢Δ͜ͱ• ࠶ൃࢭࡦͱͦͷ࣮ࢪΛهࡌ͢Δ͜ͱ• ʮؾΛ͚Δʯʮҙ͢Δʯͱ͍ͬͨओ؍తͳࢭࡦೝΊͳ͍
'54ࢥߟͷϑϨʔϜϫʔΫ• ͕͋Εࠜຊతʹղܾ͖͢ͱ͍͏Ձ؍• ʮͳͥ͜ͷ͕ى͖ͨͷ͔ʯΛੳٕͯ͠ज़తͳղܾࡦʹམͱ͜͠Ή• ։ൃʹ͓͚Δʮඪ४ʯΛ࡞͍ͬͯ͘աఔͰ͋Δ
࣮ࡍͷ'54͔Β͍͔ͭ͘ϐοΫΞοϓ
"OESPJEΞϓϦͰ8JEHFU͕͋Δͱ͖ʹΞοϓσʔτ͢ΔͱϩάΞτ
$PPLQBE"QQ8JEHFU• AndroidͷϗʔϜʹஔ͚Δখ͍͞ΞϓϦ• ىಈϑϩʔ͕ී௨ͷΞϓϦͱҧ͏ʢ͜ͱ͕͋Δʣ
8JEHFU͕͋Δͱ͖ʹΞοϓσʔτ͢ΔͱϩάΞτ• WidgetΛؚΊͯز͔ͭͷύλʔϯͰىಈϑϩʔ͕গ͚ͩ͠ҧ͏• ΞϓϦέʔγϣϯͷىಈ࣌ʢApplication#onCreate()ʣʹͯ͢ͷॳظԽΛߦ͏ͱ͗͢ΔͷͰɺผͷͱ͜ΖʹΓ͚͍ͯͨ• ݁Ռɺ௨ৗͱҧ͏ىಈϑϩʔΛऔΔ߹ʹͯ͢ͷॳظԽ͕Βͳ͍ঢ়ଶͩͬͨ
ղܾํ๏• ॳظԽΛ Application#onCreate() Ͱߦ͏Α͏ʹͨ͠• ͦͷࡍɺॳظԽϓϩηεΛݟͳ͓ͯ͠ߴԽͨ͠• ͜ͷॳظԽεϓϥογϡεΫϦʔϯ͕ग़Δલͷ͜ͱͳͷͰɺͦΕͳΓʹ࣌ؒΛͬͯߴԽ͢ΔՁ͕͋Δ• ʮؾΛ͚࣮ͭͯ͢Δʯোͷͱ
/Ͱ"1*ΞΫηεͯ͠αʔόʔͷෛՙ্͕ঢ
/• ͋ΔϦιʔεʢͨͱ͑RecipeʣΛNݸऔಘͨ͋͠ͱɺͦͷϦιʔεʹඥͮ͘ผͷϦιʔεʢͨͱ͑UserʣΛऔಘ͠Α͏ͱͯ͠͞ΒʹNճͷAPIΛൃߦͯ͠͠·͍ύϑΥʔϚϯε͕ྼԽ͢Δ• RailsͰΑ͋͘Δ͜ͱͰɺbulletͱ͍͏N+1Λൃݟ͢Δઐ༻ͷgem·Ͱ͋Δ
J04ΞϓϦͰ/ʹؾͮ͘• ίʔυϨϏϡʔQA Λ௨աͯ͠ɺϦϦʔεޙʹAPIαʔόͷෛՙ͕ߴ·ͬͯൃ֮• αʔόʔαΠυͷ࣮Α͘ͳ͔ͬͨͷͰͦͷվળͰ͋Δఔ͠ͷ͛ͨ• ΞϓϦͷڍಈͦͷͷਖ਼ৗ͕ͩো͕͓͖Δͱ͍͏ঢ়گͩͬͨ
ղܾࡦɿνΣοΫϦετʹ߲ΛՃ• pull-requestʹಛఆͷϥϕϧΛ͚ͭΔͱɺͦΕʹԠͨ͡νΣοΫϦετ͕షΒΕΔΈ͕͋Δ• ͦΕΛ֦ுͯ͠νΣοΫͰ͖ΔΑ͏ʹͨ͠• ߋʹΞϓϦ͔ΒͷϦΫΤετΛΩϟϓνϟͯ͠νΣοΫ͢ΔΈΛςετʹΈࠐΜͩ
1SP(VBSEͱͷઓ͍
1SP(VBSE• JavaͷόΠτίʔυͷͨΊͷminifyπʔϧ• γϯϘϧ໊ͷॖɺόΠτίʔυ࠷దԽɺϝλσʔλͷআɺσουίʔυআɺಡԽͳͲΛߦ͏• γϯϘϧ໊ͷॖͱσουίʔυআͰAPKαΠζΛখ͘͢͞ΔޮՌΛظ• ProGuardͦͷ্༷ɺΞϓϦͷػೳෆશΛඇৗʹى͍͜͢͠• ͔͠͠APKαΠζͷॖখޮՌϝΨόΠτʹٴͿͷͰΘͳ͍Θ͚ʹ͍͔ͳ͍
BTTVNFOPTJEFF⒎FDUT• σουίʔυআʹ͓͍ͯɺಛఆͷϝιου͕෭࡞༻Λ࣋ͨͳ͍ͱ͍͏ώϯτΛ༩͑ΔΦϓγϣϯ• ϩΨʔͷϝιουΛ "no side-effects" ͱ͢Δ͜ͱͰɺLog.d()ͷݺͼग़͠ΛόΠτίʔυ͔ΒআͰ͖Δ• ΫοΫύουΞϓϦͰ͜ΕͰϩάग़ྗΛ͍͕ͬͯͨ…
ϦϦʔεϏϧυͰϩάग़ྗ• ͋Δόʔδϣϯ͔Βϩάग़ྗ͕ແޮԽ͞Εͳ͍ঢ়ଶʹͳ͍ͬͯͨ• ͦ͜Ͱ -assumenosideeffects Ͱ Log.d() Λআ͢Δ͜ͱʹͨ͠ɿBTTVNFOPTJEFF⒎FDUTaDMBTTBOESPJEVUJM-PH\NFUIPET^
"1*αʔόͷෛՙ૿େ• ΄Ͳͳͯ͘͠APIαʔόͷෛՙ͕ߴ·͖ͬͯͨ• ೝূϦΫΤετ͕աʹൃߦ͞Ε͍ͯΔΒ͍͠• ΫοΫύουΞϓϦىಈ࣌ʹೝূΛߦ͏Α͏ʹͳ͍ͬͯΔ• ೝূ͕͍ྃͯ͠ͳ͍ͱ͖ʹൃߦ͞ΕͨͦͷଞͷAPIίʔϧೝূ͕௨Δ·ͰͭΑ͏ʹͳ͍ͬͯΔw w
"1*ίʔϧೝূ͕௨Δ·Ͱͭw w• ͜ͷͪ߹Θͤʹ Object#wait() Λ͍ͬͯͨ• -assumenosideeffects class Log { ; } Ϋϥε֊ΛḪͬͯద༻͞ΕΔ• LogΫϥεͷεʔύʔΫϥεͰ͋ΔObjectΫϥεͷશϝιου͕෭࡞༻ͳ͠ͱղऍ͞ΕΔʂ• ͜ͷΑ͏ͳܦҢͰ Object#wait() ͷݺͼग़͕͠όΠτίʔυ͔Βআ͞Ε͍ͯͨ…
ͳͥϦϦʔε·Ͱؾ͔ͳ͔͔ͬͨ• APIίʔϧͷೝূ͕ͪյΕͨ݁Ռɺೝূ͕ͱ͓ΒͣʹAPIίʔϧ͕͞ΕͯΤϥʔʹͳ͍ͬͯͨ• ͔͠͠ɺAPIΫϥΠΞϯτʹ࣮͞ΕͨࣗಈϦτϥΠػߏ͕͏·͘ಈ͍ͯ͠·͍ɺϦτϥΠ͢Δؒʹೝূ͕ͱ͓ͬͯଓ͘APIίʔϧ͕ޭͯ͠͠·͏• ·ͨΞϓϦͷڍಈͦͷͷਖ਼ৗ͕ͩো͕͓͖Δͱ͍͏ঢ়گ
"1*ݺͼग़͠ଟ͗͢ͷࠜຊղܾ• ΞϓϦ্ͰΦʔόʔϨΠදࣔ͢ΔϩΨʔΛͭ͘Γɺstatus 4xx, 5xxͷAPIݺͼग़͠ΛͦͷϩΨʔͰه͢ΔΑ͏ʹͨ͠ʢAndroid, σόοάϏϧυͰͷΈ༗ޮʣ• ͦͷޙɺ௨৴पΓͷτϥϒϧΦʔόʔϨΠϩΨʔͷ͓͔͛Ͱ͍ͩͿॿ͔ͬͨ• ·ͨ௨৴ྔΛଌఆ͢ΔπʔϧΛͭ͘ΓɺQAʹऔΓೖΕͨ
͓ΘΓ