Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MIXI TECH NOTE #08

MIXI TECH NOTE #08

MIXI ENGINEERS

October 03, 2022
Tweet

More Decks by MIXI ENGINEERS

Other Decks in Technology

Transcript

  1. ·͕͖͑ ຊॻʮMIXI TECH NOTE #08ʯ͸ɺMIXIGROUP ʹॴଐ͢Δ༗ࢤୡʹΑͬͯࣥචɾ੍࡞͞Εٕͨ ज़ॻͰ͢ɻ࣮ࡍͷϓϩμΫτ։ൃͷݱ৔Ͱ࢖༻͞Εٕͨज़ͷ࿩΍ɺ೔ʑͷۀ຿ͷ๣Βɺݸਓతʹௐ΂ ͨ͜ͱͳͲɺࢥ͍ࢥ͍ʹࣥච͍ͯ͠·͢ɻͦͷͨΊɺ֤ষͦΕͧΕͰ׬͍݁ͯ͠Δ಺༰ʹͳ͍ͬͯ· ͢ͷͰɺ޷͖ͳষ͔Β޷͖ͳॱ൪Ͱָ͓͠Έ͍ͩ͘͞ɻ ·ͨɺຊॻ͸ɺMIXIGROUP

    ʹ͋Δٕज़త஌ݟ΍ΞΠσΞΛੵۃతʹڞ༗ɾެ։͍ͯ͘͜͠ͱͰɺ ੈͷதʹΑΓྑ͍αʔϏε͕ҲΕग़͢͜ͱΛئͬͯץߦ͞Ε͍ͯ·͢ɻܝࡌ͞Ε͍ͯΔ৘ใ͸ɺࣥච ऀࣗ਎ͷ؀ڥͰݕূࣥ͠ච͞Εͨ΋ͷͰ͢ͷͰɺ͝ࢀߟʹ͞ΕΔࡍ͸ɺࣗ͝਎ͷ੹೚Ͱ൑அ͠͝׆༻ ͍ͩ͘͞ɻͳ͓ɺจষදݱʹ͖ͭ·ͯ͠΋ɺࣥචऀࣗ਎ͷݴ༿Ͱ఻͑ͨ͘ɺϑϥϯΫͳදݱͱͳͬͯ ͓Γ·͢͜ͱ͝ཧղ͍͚ͨͩΕ͹ͱࢥ͍·͢ɻ σΟϕϩούʔϦϨʔγϣϯζνʔϜҰಉ ˗ຊॻʹؔ͢Δ͓໰͍߹Θͤઌ ɹ https://twitter.com/mixi_engineers ˗ MIXIGROUP ʹ͍ͭͯ ɹ https://mixi.co.jp/ ˞ MIXI ͷ໊শɺ͜Εʹؔ࿈͢Δ঎ඪٴͼϩΰ͸ɺגࣜձࣾ MIXI ͷ঎ඪٴͼొ࿥঎ඪͰ͢ɻ·ͨɺ ֤ࣾͷձ໊ࣾɺαʔϏεٴͼ੡඼ͷ໊শ͸ɺͦΕͧΕͷॴ༗͢Δ঎ඪ·ͨ͸ొ࿥঎ඪͰ͢ɻ iii
  2. ໨࣍ ·͕͖͑ iii ୈ 1 ষ Service Worker Λհͨ͠ feature

    toggle ؅ཧ 1 1.1 SSR ࣌ͷ feature toggle Ͱͷ෼ذ . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Service Worker ͱ͸ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 HTTP ϦΫΤετΛϓϩΩγ͢Δ . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.4 feature toggle ؅ཧ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.5 feature toggle ͷ SSR ରԠ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.6 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 ୈ 2 ষ Haskell ͷ੩తαΠτδΣωϨʔλʔ 11 2.1 Hakyll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.2 Slick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.3 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 17 3.1 ͸͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.2 ঢ়گઃఆ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.4 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό։ൃ 29 4.1 ͸͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4.2 ToDo ΞϓϦͷ API Λ࡞Δ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.3 ͓ΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 35 5.1 ຊষʹ͍ͭͯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 5.2 ࢲͨͪͷڭҭࢧԉ׆ಈʹ͍ͭͯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 5.3 ໰୊ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 5.4 ໰୊ͷ෼ղ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 v
  3. ໨࣍ 5.5 ໨ඪઃఆͱߦಈࢦ਑ . . . . . . .

    . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.6 ίϯςϯπاըͱ͞·͟·ͳ෼ੳ . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.7 ΞΠσΞͷൃ૝ͱࢥߟ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 5.8 ࠷ޙʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 61 6.1 ͸͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 6.2 ڥքσʔλͷऔΓࠐΈ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.4 ύϑΥʔϚϯεଌఆ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.5 ͓ΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 81 7.1 2022 ೥Ҏલͷྺ࢙ΛৼΓฦΔ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.2 ExoPlayer ͱ Jetpack Media3 ʹ͍ͭͯ . . . . . . . . . . . . . . . . . . . . . . . 84 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.4 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 95 8.1 ͸͡Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.2 Unity Transport ͷηοτΞοϓ . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.3 Unity Transport ͷ௨৴ϓϩτίϧ . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.4 ܰྔαʔό։ൃ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.5 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 ஶऀ঺հ 103 vi
  4. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ feature

    toggle ͱ͸ ։ൃ͢Δػೳͷಈ࡞Λ༗ޮԽ͢Δ͔ແޮԽ͢Δ͔Λ੍ޚ͢ΔͨΊͷख๏Ͱ͢ɻ ৄ͘͠͸ɺલճͷٕज़ॻయ 12*1Ͱॻ͍ͨ ʮUnleash Λ࢖ͬͨ feature toggle ؅ཧʯ Ͱ feature toggle Λ࢖͏ϝϦοτ΍͜ΕΛ׆༻͢ΔτϥϯΫϕʔε։ൃʹ͍ͭͯͷ঺հΛ͍ͯ͠·͕͢ɺຊষͰ ͸ɺ΋͏গ͠ൃలͯ͠ Web (Next.js) ʹ͓͚Δ SSR ࣌ͷ feature toggle ͷΫϥΠΞϯτ؅ཧʹ͍ͭ ͯɺ Service Worker Λ׆༻ͨ͠ख๏Λ঺հ͍ͨ͠ͱࢥ͍·͢ɻ 1.1 SSR ࣌ͷ feature toggle Ͱͷ෼ذ SSR ͱ͸ Server Side Rendering ͷུͰ SPA*2 Λϖʔδ͝ͱʹαʔόͰ HTML ͱͯ͠ϨϯμϦ ϯάͯ͠ΫϥΠΞϯτʹฦ٫͢Δख๏Ͱ͢ɻ ΫϥΠΞϯτ͸αʔό͔Βड͚औͬͨϨϯμϦϯά݁ՌΛύʔεͯ͠ඳըͨ͠ޙɺΫϥΠΞϯτଆ ͰͷεΫϦϓτ࣮ߦΛ͠·͢ɻ ͜ΕΛ hydration ͱ͍͏ͷͰ͕͢ɺύϑΥʔϚϯε্ͷཧ༝͔ΒαʔόαΠυͰͷϨϯμϦϯά ݁ՌͱΫϥΠΞϯταΠυͰͷॳճϨϯμϦϯά݁Ռ͸ඞͣҰகͤ͞Δඞཁ͕͋Δͱ͍͏ಛ௃͕͋Γ ·͢ɻ feature toggle ʹ͓͍ͯ͸ɺϑϥάͷεςʔλεʹΑͬͯϨϯμϦϯά݁ՌΛ෼ذ͍ͤͨ͞ͷͰ৔ ߹ʹΑͬͯ͸ SSR ͨ͠ޙͷ hydration ͰϨϯμϦϯά݁ՌͷෆҰகʹΑΔΤϥʔ͕ൃੜ͢Δ͜ͱ͕ ͋Γ·͢ɻ ͨͱ͑͹ɺfeature toggle ΛΫϥΠΞϯτͰ؅ཧͨ͠৔߹ *1 ٕज़ॻయ 12: https://techbookfest.org/product/5148888694521856?productVariantID=6546902914957312 *2 Single Page Application 1
  5. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.2

    Service Worker ͱ͸ Ϧετ 1.1: featureToggle.ts 1: const getFeatureToggle = () => { 2: const featureToggle = localStorage.getItem("featureToggle"); 3: 4: return featureToggle === "true" 5: } 6: 7: const ExampleComponent = () => { 8: const enabled = getFeatureToggle() 9: 10: return ( 11: <> 12: {enabled ? <h1>new</h1> : <h1>old</h1>} 13: </> 14: ) 15: } local storage ΍ session storage ͳͲͷΫϥΠΞϯτͷετϨʔδͰ؅ཧͨ͠ feature flag Λݺͼग़ͯ͠ɺϨϯμϦϯά݁ՌΛ෼ذͯͦ͠ͷ·· SSR ͠Α͏ͱ͢ΔͱɺαʔόϓϩηεͰ͸Ϋ ϥΠΞϯτͷετϨʔδʹอଘ͞Ε͍ͯΔϑϥάΛࢀরͰ͖ͳ͍ͨΊɺCSR*3 ࣌ͱͷϨϯμϦϯά ݁Ռʹࠩ෼͕ੜ͡·͢ɻ CSR ࣌ͷΈ SSR ࣌ͱϨϯμϦϯά݁ՌΛͲ͏ͯ͠΋ม͍͑ͨ৔߹͸ɺॳճͰ null (ۭ) ΛϨϯμ Ϧϯάͯ͠ɺͦͷ࣍ʹຊདྷඳը͍ͨ͠ίϯςϯπΛϨϯμϦϯά͢Δख๏͕͋Γ·͢ɻ ͔͠͠ɺ͜ͷख๏͸ null ΛϨϯμϦϯάͨ͠Օॴʹ͍ͭͯ SSR ͷҙຯ͕ͳ͘ͳͬͯ͠·ͬͨΓɺ ϨϯμϦϯάճ਺͕࠷దԽ͞Ε͍ͯͳ͍ͨΊύϑΥʔϚϯεΛྼԽͤ͞ΔཁҼͱͳΔɺͰ͖Ε͹ආ͚ Δ΂͖ hucky ͳख๏ʹͳΓ·͢ɻ Unleash ͳͲͷ֎෦αʔϏεͷ DB Ͱ feature flag Λ؅ཧ͢Ε͹ SSR ࣌ʹ΋εςʔλεΛऔಘͰ ͖ΔͨΊ͜ͷ໰୊͸ղফ͞Ε·͕͢ɺ։ൃ؀ڥʹ͓͍ͯσόοά΍ QA ࡞ۀΛߦ͏৔߹ʹ feature Flag Λ࣮ߦ؀ڥ͝ͱʹ੾Γସ͍͑ͨέʔεͳͲɺΫϥΠΞϯτͰ΋ feature Flag Λ؅ཧ͍ͨ͠έʔ ε͕͋Γ·͢ɻ ΫϥΠΞϯτͷετϨʔδͰ feature flag ͷঢ়ଶΛ؅ཧͭͭ͠໰୊ͳ͘ SSR Ͱ͖ΔΑ͏ʹ͢Δͨ Ίʹɺࠓճ͸ Service Worker Λ׆༻͢Δ͜ͱͰղܾΛࢼΈ·͢ɻ 1.2 Service Worker ͱ͸ Service Worker ͱ͸ωοτϫʔΫϓϩΩγͷΑ͏ͳৼΔ෣͍Λ͢Δϒϥ΢β্Ͱಈ࡞͢ΔϫʔΧ Ͱ͢ɻ ΫϥΠΞϯτ͔Βͷ HTTP ϦΫΤετͳͲΛτϦΨͱͨ͠Πϕϯτ͕ൃߦ͞ΕɺϦΫΤετʹର ͯ͠ϦιʔεͷΩϟογϡΛฦ٫ͨ͠ΓͳͲͷॲཧ͕ϝΠϯϓϩηεͱ͸ผͷεϨουͰฒྻͰߦ͑ *3 Client Side Rendering ͷུ 2
  6. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.2

    Service Worker ͱ͸ ·͢ɻ Service Worker Λ࢖༻͢Δʹ͸ɺ Service Worker ಺ͰͷॲཧΛهड़ͨ͠ JavaScript ϑΝΠϧΛ ϗεςΟϯάͯ͠ɺnavigator.serviceWorker.register("path/to/serviceWorker.js") Λ ࣮ߦ͢Δ͜ͱͰϒϥ΢βʹ Service Worker Λొ࿥Ͱ͖·͢ɻ React ʹ͓͍ͯ͸ొ࿥༻ͷ JavaScript Λ༻ҙͯ͠εΫϦϓτλάΛ index.html ʹهࡌ͢Δ͜ͱ Ͱ Service Worker Λొ࿥͢Δ͔ɺ Service Worker Λొ࿥͢Δ custom hook Λ༻ҙ͠·͢ɻ Ϧετ 1.2: serviceWorkerHooks.ts 1: const useRegisterServiceWorker = () => { 2: useEffect(() => { 3: const register = async () => { 4: if (!("serviceWorker" in navigator)) { 5: return; 6: } 7: 8: const registration = await navigator.serviceWorker 9: // Next.js ͷ public σΟϨΫτϦʹεΫϦϓτϑΝΠϧΛ഑ஔ 10: .register("/serviceWorker.js") 11: .catch((error) => { 12: if (error instanceof Error) { 13: return error; 14: } 15: 16: throw Promise.reject(error); 17: }); 18: 19: if (registration instanceof Error) { 20: console.log("Service Worker registration failed: ", registration); 21: return; 22: } 23: 24: console.log( 25: "Service Worker registration successful with scope: ", 26: registration.scope 27: ); 28: }; 29: 30: register(); 31: }, []); 32: }; Service Worker Λొ࿥͢Δ custom hook Λ༻ҙͨ͠৔߹͸άϩʔόϧͰ࣮ߦ͞ΕΔՕॴʹϚ΢ ϯτ͢ΔΑ͏ʹ͠·͢ɻ register ϝιου͸ɺ͢Ͱʹಉ͡ Service Worker Λొ࿥͍ͯ͠Δ৔߹͸Α͠ͳʹΠϯετʔϧॲ ཧΛεΩοϓ͠·͢ɻ 3
  7. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.3

    HTTP ϦΫΤετΛϓϩΩγ͢Δ 1.3 HTTP ϦΫΤετΛϓϩΩγ͢Δ Service Worker Ͱ͸ΫϥΠΞϯτ͔Βͷ HTTP ϦΫΤετΛϓϩΩγ͢Δػೳ͕͋Γ·͢ɻ ϖʔδͷ SSR ݁ՌΛαʔό͔Βऔಘ͢Δࡍʹ΋ HTTP ϦΫΤετ͕૸ΔͷͰɺ Service Worker Ͱ༗ޮԽ͢Δ feature toggle ͷϑϥά໊ΛϦΫΤετͷϔομʹ෇༩͠·͢ɻ ϦΫΤετϔομʹ feature flag ͷ৘ใΛؚ·ͤΔ͜ͱͰɺΫϥΠΞϯτͰϑϥάΛ؅ཧ͠ͳ͕Β SSR ࣌ʹ feature flag Λϔομ͔ΒऔΓग़͢͜ͱ͕Ͱ͖ΔΑ͏ʹ͠·͢ɻ Ϧετ 1.3: serviceWorker.js 1: self.addEventListener("fetch", (event) => { 2: if (process.env.NODE_ENV === "production") { 3: return; 4: } 5: 6: const callback = async () => { 7: const baseRequest = event.request.clone(); 8: 9: // ϔομʔʹ feature toggle ͷ৘ใΛ෇༩ͨ͠ HTTP ϦΫΤετΛੜ੒ 10: const request = await appendFeatureToggleRequest(baseRequest); 11: 12: return fetch(request); 13: }; 14: 15: event.respondWith(callback()); 16: }); FetchEvent ͷ respondWith ϝιουΛ࢖༻͢Δ͜ͱͰɺΠϕϯτΛൃߦ͢ΔτϦΨͱͳͬͨ HTTP ϦΫΤετΛϓϩΩγͰ͖·͢ɻ ·ͨɺ ຊ൪؀ڥͰ͸ HTTP ϦΫΤετΛϓϩΩγ͠ͳ͍Α͏ʹ؀ڥม਺Λݟͯ֘౰؀ڥͷ৔߹ʹ ॲཧΛΩϟϯηϧ͠·͢ɻ 1.4 feature toggle ؅ཧ Service Worker ͸ඇಉظʹಈ࡞͢ΔͨΊɺಉظॲཧΛඞཁͱ͢Δ session storage ΍ local s torage ͸࢖͏͜ͱ͕Ͱ͖·ͤΜɻ ϒϥ΢βʹ͸ indexedDB ͱ͍͏ඇಉظʹ௨৴Ͱ͖Δܰྔͳ DB ͕༻ҙ͞Ε͍ͯΔͨΊɺ feature toggle ͷ؅ཧʹ͸͜ΕΛ࢖༻͠·͢ɻ Ϧετ 1.4: featureToggleDb.ts 1: const DB = { 4
  8. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.4

    feature toggle ؅ཧ 2: featureToggle: { 3: name: "featureToggle", 4: version: 1, 5: storeNames: ["featureToggles"], 6: }, 7: } as const; 8: 9: const openDb = async (db: keyof typeof DB): Promise<IDBDatabase> => { 10: return new Promise((resolve, reject) => { 11: const requst = indexedDB.open(DB[db].name, DB[db].version); 12: 13: requst.onupgradeneeded = async () => { 14: switch (db) { 15: case "featureToggle": { 16: await migrationFeatureToggles(requst.result); 17: return; 18: } 19: } 20: }; 21: 22: requst.onsuccess = () => { 23: resolve(requst.result); 24: }; 25: 26: requst.onerror = () => { 27: reject(requst.error); 28: }; 29: 30: requst.onblocked = () => { 31: reject(requst.error); 32: }; 33: }); 34: }; 35: 36: const initialFeatureToggles = { 37: test: true, 38: }; 39: 40: const migrationFeatureToggles = (db: IDBDatabase): Promise<void> => { 41: return new Promise(async (resolve, reject) => { 42: const objectStore = db.createObjectStore(DB.featureToggle.storeNames[0], { 43: keyPath: "name", 44: }); 45: 46: objectStore.transaction.oncomplete = () => { 47: const transaction = db.transaction( 48: DB.featureToggle.storeNames[0], 49: "readwrite" 50: ); 51: 52: const featureToggleStore = transaction.objectStore( 53: DB.featureToggle.storeNames[0] 54: ); 55: 5
  9. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.5

    feature toggle ͷ SSR ରԠ 56: Object.entries(initialFeatureToggles).map(([flagName, enabled]) => { 57: featureToggleStore.add({ name: flagName, enabled }); 58: }); 59: 60: resolve(); 61: }; 62: 63: objectStore.transaction.onerror = () => { 64: reject(objectStore.transaction.error); 65: }; 66: }); 67: }; indexedDB Λ࢖༻͢Δʹ͸ɺ window.indexedDB.open ϝιουΛ࢖༻͠·͢ɻ indexedDB ͷ open ϝιουΛ࣮ߦ͢Δࡍʹ͸ DB ໊ͱ 0 ΑΓେ͖͍ͷ೚ҙͷ version Λࢦఆ͠ ·͢ɻ ࢦఆͨ͠ version ͷ DB ͕·ͩ࡞੒͞Ε͍ͯͳ͚Ε͹ onupgradeneeded event ͕ൃߦ͞ΕΔͷ Ͱɺ͜ͷΠϕϯτൃߦ࣌ʹ feature flag Λ؅ཧ͢Δ ObjectStore Λ࡞੒͠·͢ɻ ObjectStore ͱ͸ɺ RDB Ͱ͍͏ςʔϒϧͷΑ͏ͳ΋ͷͰɺ ObjectStore ࡞੒࣌ʹ keyPath ͱ͍ ͏ index Λ࡞੒͠·͢ɻ ObjectStore ͷσʔλૢ࡞͸͢΂ͯτϥϯβΫγϣϯ಺Ͱߦ͍·͢ɻ 1.5 feature toggle ͷ SSR ରԠ SSR ݁ՌΛϦΫΤετ͢Δࡍʹ Service Worker ͰϦΫΤετϔομ಺ʹ feature toggle ৘ใΛ ࡌͤͯɺαʔόϓϩηεͰ֘౰ϔομͷ৘ใΛऔΓग़͠·͢ɻ Ϧετ 1.5: featureToggleDb.ts 1: export const getFeatureToggles = async () => { 2: return new Promise<featureToggle[]>(async (resolve, reject) => { 3: const db = await openDb("featureToggle").catch((error) => { 4: if (error instanceof DOMException) { 5: return error; 6: } 7: 8: return Promise.reject(error); 9: }); 10: 11: if (db instanceof Error) { 12: console.log(db); 13: return; 14: } 15: 16: const transaction = db.transaction( 6
  10. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.5

    feature toggle ͷ SSR ରԠ 17: DB.featureToggle.storeNames[0], 18: "readonly" 19: ); 20: 21: const featureToggleStore = transaction.objectStore( 22: DB.featureToggle.storeNames[0] 23: ); 24: 25: const request = featureToggleStore.getAll(); 26: 27: request.onsuccess = () => { 28: resolve(request.result); 29: db.close(); 30: }; 31: 32: request.onerror = () => { 33: reject(request.error); 34: db.close(); 35: }; 36: }); 37: }; Ϧετ 1.6: serviceWorker.js 1: const appendFeatureToggleRequest = async (request: Request) => { 2: const defaultHeaders = Object.fromEntries(request.headers.entries()); 3: 4: const featureToggles = await getFeatureToggles(); 5: 6: const enabledToggleNames = featureToggles 7: .filter(({ enabled }) => enabled) 8: .map(({ name }) => name) 9: .join(","); 10: 11: const appendFeatureToggleRequest = new Request(request, { 12: headers: { 13: ...defaultHeaders, 14: ["Dev-Feature-Toggle"]: enabledToggleNames, 15: }, 16: }); 17: 18: return appendFeatureToggleRequest; 19: }; 20: 21: self.addEventListener("fetch", (event) => { 22: if (process.env.NODE_ENV === "production") { 23: return; 24: } 25: 26: const callback = async () => { 7
  11. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.5

    feature toggle ͷ SSR ରԠ 27: const baseRequest = event.request.clone(); 28: 29: // ϔομʹ feature toggle ͷ৘ใΛ෇༩ͨ͠ HTTP ϦΫΤετΛੜ੒ 30: const request = await appendFeatureToggleRequest(baseRequest); 31: 32: return fetch(request); 33: }; 34: 35: event.respondWith(callback()); 36: }); Ϧετ 1.7: index.tsx 1: const Home = ({ featureToggle }) => { 2: return ( 3: <> 4: {featureToggle?.test ? <h1>new</h1> : <h1>old</h1>} 5: </> 6: ); 7: }; 8: 9: export default Home; 10: 11: const httpHeadersToEnabledToggleNames = ( 12: httpHeaders: IncomingHttpHeaders 13: ) => { 14: const toggleHeader = httpHeaders["Dev-Feature-Toggle".toLowerCase()]; 15: 16: const value = Array.isArray(toggleHeader) ? toggleHeader[0] : toggleHeader; 17: 18: const enabledToggleNames = value?.split(","); 19: 20: return enabledToggleNames; 21: }; 22: 23: const generateFeatureFlags = (enabledToggleNames?: string[]) => { 24: if (process.env.NODE_ENV === "production") { 25: return initialFeatureToggles; 26: } 27: 28: const enabledToggleEntries = enabledToggleNames?.map( 29: (flagName) => [flagName, true] as const 30: ); 31: 32: const toggles = { 33: ...initialFeatureToggles, 34: ...Object.fromEntries(enabledToggleEntries ?? []), 35: }; 36: 37: return toggles; 8
  12. ୈ 1 ষ Service Worker Λհͨ͠ feature toggle ؅ཧ 1.6

    ऴΘΓʹ 38: }; 39: 40: export const getServerSideProps = async ( 41: context 42: ) => { 43: const enabledToggleNames = httpHeadersToEnabledToggleNames( 44: context.req.headers 45: ); 46: const toggles = generateFeatureFlags(enabledToggleNames); 47: 48: return { 49: props: { 50: featureToggle: toggles, 51: }, 52: }; 53: }; ϦΫΤετϔομʹࡌͤͨ feature toggle ͸ getServersideProps ಺Ͱऔಘ͠ Page ͷ props ʹઃ ఆ͠·͢ɻ ϖʔδ͝ͱʹϔομΛऔಘ͢Δ͜ͱͰɺ feature toggle Λඞཁͱ͠ͳ͍ϖʔδ͸੩తੜ੒͢ΔͳͲ ࠷దԽ͞ΕΔΑ͏ʹ͠·͢ɻ 1.6 ऴΘΓʹ ͜ͷΑ͏ʹͯ͠ΫϥΠΞϯτͰ feature toggle Λ؅ཧ͠ͳ͕Β SSR ʹରԠͰ͖·͢ɻ ϖʔδͷԼҐ૚ͰϚ΢ϯτ͞ΕΔίϯϙʔωϯτͰ feature toggle Λ࢖༻ͯ͠ϨϯμϦϯάΛ෼ ذͤ͞Δͱ͖ʹ͸ React.Context Λ࢖༻͢Δ͜ͱΛݕ౼ͯ͠΋ྑͦ͞͏Ͱ͢ɻ ࠓճͷ͜ͷ Service Worker Λ༻͍ͨ feature toggle ͷ؅ཧํ๏͸ API ϞοΫΛ͢ΔͨΊͷπʔ ϧ ʮMock Service Worker*4ʯ ʹண૝ΛಘͯԠ༻ͨ͠ྫʹͳΓ·͢ɻ Service Worker Λ׆༻͢Δ͜ͱͰ΋ͬͱ͓΋͠Ζ͍͜ͱ͕Ͱ͖ͦ͏ͳؾ͕͢ΔͷͰҾ͖ଓ͖ݚڀ ͍͖ͯ͠·͢ɻ *4 MSW: https://mswjs.io/ 9
  13. ୈ 2 ষ Haskell ͷ੩తαΠτδΣωϨʔλʔ ଟ͘ͷϓϩάϥϛϯάݴޠʹ͸੩తͳ Web ϖʔδΛੜ੒͢ΔͨΊͷΞϓϦέʔγϣϯͰ͋Δ ʮ੩తαΠτδΣωϨʔλʔʯ͕ଘࡏ͠·͢ɻͨͱ͑͹༗໊ͳ΋ͷͰɺRuby ͷ

    Jekyll*1 ΍ Go ͷ Hugo*2 ͳͲ͕͋Γ·͢Ͷɻࠓճ͸ϓϩάϥϛϯάݴޠ Haskell ͷ੩తαΠτδΣωϨʔλʔΛ঺հ ͠·͢ɻ Haskell Haskell ͸࣍ͷΑ͏ͳಛ௃Λ࣋ͭϓϩάϥϛϯάݴޠͰ͢ɻ • ڧྗͳ੩తܕ෇͚ʢܕϨϕϧϓϩάϥϛϯάͳͲ΋Մೳʣ • ڧྗͳϝλϓϩάϥϛϯάʢTemplate Haskell ͳͲʣ • ஗ԆධՁʢࣜ͸ར༻͢ΔλΠϛϯά·ͰධՁ͞Εͳ͍ʣ • ڧྗͳฒߦॲཧʢܰྔεϨου΍ιϑτ΢ΣΞτϥϯβΫγϣϯϝϞϦͳͲʣ Haskell Ͱ͸ɺখͯ͘͞γϯϓϧͳؔ਺Λ༻ҙ͠ɺͦΕΒΛؔ਺߹੒͢ΔܗͰϓϩάϥϜΛ૊Έཱ ͯΔͷ͕جຊʹͳ͍ͬͯ·͢ɻ·ͨɺϞφυͱ Do ه๏ͱ͍͏ػೳΛར༻ͯ͠ɺ͋Δछͷ಺෦ DSL ͷΑ͏ͳॻ͖ํΛ࣮ݱͨ͠Γ͠·͢ɻࠓճ͸͋Δҙຯɺ੩తαΠτδΣωϨʔλʔΛ૊ΈཱͯΔͨΊ ͷ಺෦ DSL ͷΑ͏ͳه๏Λར༻͠·͢ɻ 2.1 Hakyll Haskell ͷ੩తαΠτδΣωϨʔλʔͷ͏ͪɺ࠷΋༗໊ͳͷ͕ Hakyll*3 Ͱ͢ɻHakyll ͷόʔδϣ ϯ 1.0 ͕ग़ͨͷ͕ 2010 ೥*4Ͱ͢ͷͰɺൺֱతྺ࢙ͷ௕͍ϓϩδΣΫτͰ͢Ͷɻଞͷϓϩάϥϛϯά ݴޠͷ੩తαΠτδΣωϨʔλʔͱͷେ͖ͳҧ͍͸ɺ੩తαΠτδΣωϨʔλʔࣗ਎Λϓϩάϥϛϯ ά͢Δ఺ʹ͋Γ·͢ɻ *1 https://jekyllrb.com *2 https://gohugo.io *3 https://jaspervdj.be/hakyll/ *4 https://github.com/jaspervdj/hakyll/tree/hakyll-1.0 11
  14. ୈ 2 ষ Haskell ͷ੩తαΠτδΣωϨʔλʔ 2.1 Hakyll ଞͷϓϩάϥϛϯάݴޠͷ੩తαΠτδΣωϨʔλʔͷ৔߹ɺ༻ҙ͞Εͨ CLI πʔϧ΁ҎԼͷ

    ϑΝΠϧ܈Λ༩͑ͯ੩తͳ Web αΠτͷϑΝΠϧ܈Λੜ੒͠·͢ɿ • YAML ΍ JSON Ͱॻ͔ΕͨઃఆϑΝΠϧ • ֤ϓϩάϥϛϯάݴޠʹͷͬͱͬͨςϯϓϨʔτه๏ΛؚΉ HTML ϑΝΠϧͳͲ • ϚʔΫμ΢ϯͳͲͰهड़ͨ͠هࣄ༻ͷจॻ Hakyll ͷ৔߹ɺͦ΋ͦ΋༻ҙ͞Εͨ CLI πʔϧ͕͋Γ·ͤΜɻࣗ਎Ͱϓϩάϥϛϯάͯ͠ CLI πʔϧΛ༻ҙ͠ɺ্هͷΑ͏ͳϑΝΠϧ܈Λ࢖ͬͨπʔϧΛ࡞੒͠·͢ɻ ੩తαΠτδΣωϨʔλʔΛ࡞Δ Hakyll ͷެࣜαΠτ͔ΒαϯϓϧίʔυΛҾ༻͖ͯ͠·ͨ͠ɻ main :: IO () main = hakyll $ do -- Static files match "images/*" $ do route idRoute compile copyFileCompiler -- Pages match "post/*.md" $ do route $ setExtention "html" compile $ pandocCompiler >>= loadAndApplyTemplate "templates/post.html" defaultContext ͬ͘͟Γ 2 ͭͷϒϩοΫʹ෼͔Ε͍ͯΔͷ͕Θ͔Δ͸ͣͰ͢ɻલ൒͸੩తͳϑΝΠϧΛͦͷ·· ίϐʔ͍ͯ͠Δ͚ͩͰ͢ɻޙ൒͸ϚʔΫμ΢ϯͰهड़ͨ͠จॻΛ Pandoc*5 Λར༻ͯ͠ HTML ʹ ม׵͍ͯ͠·͢ɻPandoc ͸ Haskell ੡ͷΞϓϦέʔγϣϯͰɺϚʔΫμ΢ϯͱ HTML ͷ΄͔ʹɺ LaTeX ΍ reStructuredText ͳͲ͞·͟·ͳϚʔΫΞοϓݴޠΛ૬ޓม׵ͯ͘͠Ε·͢ɻ͜ͷ࣌ʹ ࢖͏ HTML ςϯϓϨʔτΛ loadAndApplyTemplate ؔ਺Ͱࢦఆ͍ͯ͠·͢ɻ ֤ϒϩοΫʹ͸ 3 ͭͷϑΣʔζ͕͋Γ·͢ɿ • match : ೖྗͱͯ͠࢖͏ϑΝΠϧͷબ୒ • route : ग़ྗઌͷϑΝΠϧͷࢦఆʢ֦ுࢠ΍ύεΛॻ͖׵͑Δʣ • compile : ೖྗϑΝΠϧͷத਎Λॻ͖׵͑Δ લ൒Ͱ࢖͍ͬͯΔ idRoute ͷ id ͸ identity ͷུশͰɺ߃౳ࣸ૾ʢ\x -> xʣͷ͜ͱΛࢦ͍ͯ͠ ·͢ɻͭ·Γɺग़ྗઌͷϑΝΠϧ໊͸ೖྗͱಉ͡ͱ͍͏͜ͱͰ͢ͶɻloadAndApplyTemplate ͷ࠷ ޙʹ౉͍ͯ͠Δ defaultContext ͸ςϯϓϨʔτ಺Ͱར༻Ͱ͖Δม਺܈ͰɺContext ܕʹͳ͍ͬͯ *5 https://pandoc.org 12
  15. ୈ 2 ষ Haskell ͷ੩తαΠτδΣωϨʔλʔ 2.1 Hakyll ·͢ɻͨͱ͑͹ɺλά΍೔෇ͳͲΛςϯϓϨʔτͰهड़͍ͨ͠৔߹͸ɺdefaultContext Ͱ͸ͳࣗ͘ ਎ͰΧελϚΠζͨ͠΋ͷΛ࢖͍·͢ɻ

    ྫɿΞʔΧΠϒϖʔδʹϖʔδωʔγϣϯΛೖΕΔ ࣗ਎Ͱ੩తαΠτδΣωϨʔλʔΛΧελϚΠζͰ͖ΔྫΛ঺հ͠·͢ɻ·ͣ͸ɺաڈʹ౤ߘͨ͠ هࣄͷҰཡϖʔδʢΞʔΧΠϒϖʔδʣΛੜ੒͢Δ Rule Λॻ͍ͯΈ·͢ɿ create ["archive.html"] $ do route idRoute compile $ do posts <- loadAll "posts/*" let archiveCtx = mconcat [ listField "posts" defaultContext (pure posts) , defaultContext ] makeItem "" >>= loadAndApplyTemplate "templates/archive.html" archiveCtx ΞʔΧΠϒϖʔδ͸ɺࠓ·ͰͷͱҟͳΓݩʹͳΔهࣄ΍σʔλ͕ͳ͘ɺθϩ͔Β HTML ϑΝΠϧ Λੜ੒͢ΔͷͰ match ؔ਺ͷ୅ΘΓʹɹ create ؔ਺Λ࢖͍·͢ɻΞʔΧΠϒϖʔδͷςϯϓϨʔ τͰ͸هࣄͷҰཡʢλΠτϧͱϦϯΫʣΛ౉ͯ͠ϧʔϓͰॲཧ͢Δ͜ͱΛߟ͑·͢ɻͦͷ৘ใΛ౉͢ ͨΊʹɺઐ༻ͷ Context Λ archiveCtx ͱͯ͠࡞͍ͬͯ·͢ɻ ͜ͷ··ͩͱɺ͢΂ͯͷهࣄ͕ 1 ϖʔδʹζϥʔͬͱฒͿͷͰϖʔδ෼͚ʢϖʔδωʔγϣϯʣΛ ͠·͢ɻHakyll Ͱϖʔδωʔγϣϯ͢Δʹ͸ buildPaginateWith ؔ਺ͱ paginateRules ؔ਺Λ ࢖͍·͢ɿ archive <- buildPaginateWith (return . paginateEvery 10) -- 10هࣄͣͭʹ۠੾Δ "posts/*" (\pageNum -> fromFilePath ("archive/" ++ show pageNum <.> "html")) paginateRules archive $ \pageNum pat -> do route idRoute compile $ do posts <- loadAll pat let archiveCtx = mconcat [ listField "posts" defaultContext (return posts) , paginateContext archive pageNum , defaultContext ] makeItem "" >>= loadAndApplyTemplate "templates/archive.html" archiveCtx 13
  16. ୈ 2 ষ Haskell ͷ੩తαΠτδΣωϨʔλʔ 2.2 Slick ϖʔδωʔγϣϯͷೖྗઌͱग़ྗઌͷઃఆΛ buildPaginateWith ؔ਺Ͱ༻ҙͯ͠

    paginateRul es ؔ਺Ͱग़ྗํ๏Λنఆ͍ͯ͠·͢ɻϖʔδωʔγϣϯ͞ΕͨςϯϓϨʔτʹ͸ɺલޙͷϖʔδ൪ ߸ͱϦϯΫͳͲͷ৘ใ͕ඞཁͰ͢ΑͶʁ ͦΕΛ૊ΈཱͯΔͷ͕ paginateContext ؔ਺Ͱ͢ɻଞ͸ جຊɺલͷঢ়ଶͱಉ͡Ͱ͢Ͷɻ 2.2 Slick Haskell ͷ੩తαΠτδΣωϨʔλʔ͸ఆظతʹ৽͍͠ίϯηϓτͷ΋ͷ͕ग़͖ͯ·͢ɻࠓճ͸ Hakyll ͷ΄͔ʹࢲ͕ར༻͍ͯ͠Δ Slick*6 ΋঺հ͠·͢ɻ Slick ΋ Hakyll ͱಉ͡Α͏ʹɺ੩తαΠτδΣωϨʔλʔࣗମΛϓϩάϥϛϯά͠·͢ɻSlick ͷ README ʹ͸ Hakyll ͷܽ఺ͱͯ͠ɺHakyll ༻ͷಠࣗϞφυͷ෦෼ʹ͍ΖΜͳίϯςΩετ͕Ӆ ณ͞Ε͓ͯΓɺશମ૾Λ೺Ѳ͢Δͷ͕ඇৗʹࠔ೉ͳ఺͕͋͛ΒΕ͍ͯ·͢ɻͦͷͨΊɺΑΓγϯϓϧ Ͱѻ͍΍͍͢΋ͷΛ໨ࢦ͍ͯ͠ΔΑ͏Ͱ͢ɻSlick ͷಛ௃ͱͯ͠ɺ಺෦తͳॲཧΛ΄͔ͷ͘͠Έʹҕ Ͷ͍ͯΔ఺͕͋͛ΒΕ·͢ɿ • ϏϧυγεςϜʹ͸ Shake*7 Λར༻͍ͯ͠Δʢఏڙ͢ΔαϒίϚϯυ΍Ϗϧυ݁ՌͷΩϟο γϡͳͲʣ • Markdown ͔Β HTML ΁ͷม׵͸ Pandoc Λར༻͍ͯ͠ΔʢHakyll ͱಉ͡ʣ • ςϯϓϨʔτͷϨϯμϦϯάʹ͸ Mustache*8 Λར༻͍ͯ͠Δ Shake ͸ Make ͷ୅ସΛ໨ࢦͨ͠ Haskell Ͱهड़Ͱ͖ΔϏϧυγεςϜͰ͢ɻHaskell ͷσϑΝΫ τελϯμʔτͳॲཧܥͰ͋Δ GHC Ͱ΋ར༻͞Ε͍ͯ·͢*9ɻMustache ͸ಛఆͷϓϩάϥϛϯά ݴޠʹґଘ͠ͳ͍൚༻ͷςϯϓϨʔτΤϯδϯͰ͢ɻHaskell ࣮૷΋ଘࡏ͠ɺͦΕΛར༻͍ͯ͠·͢ɻ ྫɿهࣄͷϖʔδੜ੒ ྫͱͯ͠ɺϚʔΫμ΢ϯͰهड़͞ΕͨهࣄΛ HTML ʹม׵͢Δ෦෼Λࣔ͠·͢*10ɿ data Post = Post { title :: String , author :: String , date :: String , image :: Maybe String , content :: String } *6 https://github.com/ChrisPenner/slick *7 https://shakebuild.com *8 https://mustache.github.io/ *9 ΑΓਖ਼֬ʹ͸ɺShake Λϕʔεʹͯ͠ GHC ༻ʹ։ൃ͞Ε͍ͯΔ Hadrian ͱ͍͏ϏϧυγεςϜͰ͢ɻhttps: //gitlab.haskell.org/ghc/ghc/-/wikis/building/hadrian *10 https://github.com/ChrisPenner/slick-template ΑΓൈਮ 14
  17. ୈ 2 ষ Haskell ͷ੩తαΠτδΣωϨʔλʔ 2.3 ऴΘΓʹ deriving (Generic, Eq,

    Ord, Show, FromJSON, ToJSON, Binary) buildPosts :: Action [Post] buildPosts = do paths <- getDirectoryFiles "." ["site/posts//*.md"] forP paths buildPost buildPost :: FilePath -> Action Post buildPost srcPath = cacheAction ("build" :: T.Text, srcPath) $ do content <- readFile’ srcPath postData <- mmarkdownToHTML’ @Post (T.pack content) template <- compileTemplate’ "templates/post.html" writeFile’ (outputFolder </> dropDirectory1 (srcPath -<.> "html")) $ T.unpack (substitute template postData) convert postData ΍͍ͬͯΔ͜ͱ͸ Hakyll ͷͱ͖ͱ΄ͱΜͲಉ͡Ͱ͢ɻ৑௕ʹͳͬͯ·͕͢ɺ୅ΘΓʹશମ૾͕ͭ ͔Έ΍͍͢͸ͣͰ͢ɻ Slick ͷ৔߹ɺHakyll ͷ Context ܕͷΑ͏ͳςϯϓϨʔτʹ౉͢৘ใΛɺͦΕͧΕͷܕͰಠࣗʹ ఆٛ͢Δ͜ͱΛ૝ఆ͞Ε͓ͯΓɺPost ܕ͕ͦΕʹ͋ͨΓ·͢ɻmmarkdownToHTML’ ؔ਺͕ Pandoc Λར༻ͯ͠ϚʔΫμ΢ϯΛ HTML ΁ม׵͍ͯ͠·͢ɻͦͷࡍʹɺFront Matter ͷ৘ใΛ Post ܕ ΁ม׵͍ͯ͠·͢ɻcontent ϑΟʔϧυͷ෦෼͚ͩ͸ɺFront Matter Ͱ͸ͳ͘ຊจͰ͢ɻcompile Template’ ͸ Mustache ͷςϯϓϨʔτϑΝΠϧΛಡΈࠐΈɺsubstitute ؔ਺ͰςϯϓϨʔτ಺ ͷม਺Λ Post ܕͷ஋Λݩʹஔ͖׵͍͑ͯ·͢ɻcacheAction ؔ਺͸ Shake ͷؔ਺ͰɺϑΝΠϧͷ มߋΛݕ஌͠มߋ͕͋ͬͨ৔߹ʹ͚ͩੜ੒͠௚͢෦෼ͷఆٛΛ͍ͯ͠·͢ɻ 2.3 ऴΘΓʹ ࠓճ͸ Haskell ͷ੩తαΠτδΣωϨʔλʔͱͯ͠ݹ͔͘Β࢖ΘΕ͍ͯΔ Hakyll ͱɺൺֱత৽ ͍͠ Slick Λ঺հ͠·ͨ͠ɻͨͩ୯ʹϚʔΫμ΢ϯͰهࣄΛॻ͖ɺ੩తαΠτΛ࡞Δ͚ͩͰ͋Ε͹ Jekyll ΍ Hugo Ͱ΋ྑ͍ͱࢥ͍·͢ɻͨͩɺJekyll ΍ Hugo Λ࢖ͬͨ͜ͱΛɺRuby ΍ Go Ͱϓϩ άϥϛϯάͨ͠ͱ͸ݴ͍͕͍ͨͰ͢ΑͶʁ ͔͠͠ɺHakyll ΍ Slick Ͱ͋Ε͹ɺHaskell Ͱϓϩάϥ ϛϯάͨ͠ͱݴͬͯ΋աݴͰ͸ͳ͍͸ͣͰ͢ɻͰ͢ͷͰɺHaskell Λ࢖ͬͯΈ͍͚ͨͲಛʹॻ͖͍ͨ ΞϓϦέʔγϣϯ͕ͳ͍ͱ͍͏ਓ͸ɺࢼ͠ʹ࢖ͬͯΈͯ͸Ͳ͏Ͱ͠ΐ͏͔ɻ 15
  18. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.1 ͸͡Ίʹ Έͳ͞Μɺ࢓༷ॻಡΜͰ͍·͔͢ʁ ੈͷதʹ͸࢓༷ॻΛಡΉ͜ͱ΍ઃܭ͢Δ͜ͱ͸ଟ͋͘Γ·͕͢ɺ࣌ʹ࢓༷ॻͷͳ͍ശΛૢ࡞͢Δ ඞཁʹഭΒΕΔ͜ͱ͕͋Γ·͢ɻࠓճ͸ͦΜͳ࢓༷ॻͷͳ͍ശΛૢ࡞ͨ͠ͱ͖ʹ࢓༷ॻΛ࿉੒ͨ͠ɺ

    ͪΐͬͱมΘͬͨΤϯδχΞϦϯάʢʁʣΛ঺հ͠·͢ɻ ͕͖ͨͩ͠ ຊষͰ঺հ͢Δ಺༰͸ MIXI ࣾͰ࣮ࡍʹ࢖ΘΕ͍ͯΔσʔλɺ࢓༷ͱ͸ԿΒؔ܎͕͋Γ·ͤΜɻ 3.2 ঢ়گઃఆ ͋ͳͨ͸ɺͱ͋ΔλϫʔσΟϑΣϯεήʔϜͷσόοάΛ͍ͯ͠·͢ɻ σόοά಺༰ͱͯ͠͸ɺࢿྉ 1 ͷΫΤετʹ͍ͭͯɺμϛʔͷσʔλΛ࡞ͬͯήʔϜͷڍಈʹᴥᴪ ͕ͳ͍͔ΛνΣοΫ͢Δɺͱ͍͏΋ͷͰ͢ɻ ͳ͓ɺμϛʔͷσʔλʹ͍ͭͯ͸ɺࢿྉ 2 ͷαϯϓϧΛࢀߟʹదٓௐ੔͢Δඞཁ͕͋Γ·͢ɻ 17
  19. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.2 ঢ়گઃఆ ࢿྉ 2 ։ൃνʔϜ͔Βڞ༗͞Εͨαϯϓϧσʔλͱͦͷઆ໌

    event_quest_sample.json { "dataId": "event_quest", "eventQuestId": "20220801", "title": "εϖγϟϧΫΤετ1", "updatedAt": "20220715133011", "stages": [ { "teki_count": 25, "teki": [ {"id": 1, "level": 60, "count": 15, "type": 1}, {"id": 2, "level": 55, "count": 10, "type": 1} ], "teki_syutugen": "0000", }, { "teki_count": 40, "teki": [ {"id": 1, "level": 60, "count": 15, "type": 1}, {"id": 3, "level": 75, "count": 5, "type": 3}, {"id": 5, "level": 40, "count": 20, "type": 1} ], "teki_syutugen": "0100", }, { "teki_count": 15, "teki": [ {"id": 1, "level": 60, "count": 10, "type": 1}, {"id": 3, "level": 75, "count": 4, "type": 3}, {"id": 7, "level": 90, "count": 1, "type": 2} ], "teki_syutugen": "0230", } ] } ։ൃνʔϜ͔Βڞ༗͞Εͨϝοηʔδ.txt ఴ෇ͨ͠Ϛελσʔλͷ event_quest_sample.json ΛϕʔεʹΫΤετΛ࡞Ε·͢ɻ εςʔδͷઃఆͱͯ͠͸ɺ1ͭ໨ͷεςʔδͰ͸0෼ɺ2ͭ໨ͷεςʔδͰ͸1෼ɺ3ͭ໨ͷεςʔδͰ͸2෼30ඵ Ͱఢ͕ग़ݱ͠·͢ɻ 2ͭ໨ͷεςʔδͰதϘε͕5ମɺ3ͭ໨ͷεςʔδͰϘε͕1ମग़ݱ͠·͢ɻ ͦΕͧΕͷϚελσʔλ͸ɺ؅ཧը໘͔Βೖߘ͢Δ͜ͱͰ൓өͰ͖·͢ͷͰɺσόοάΑΖ͓͘͠ئ͍͠·͢ɻ ಛʹݟͯཉ͍͠؍఺ͱͯ͠͸ɺఢͷλΠϓ͕Ϙε (type = 3) ͷͱ͖ʹϘεͷϚʔΫ͕֘౰ͷఢΩϟϥΫλʹ ෇༩͞ΕΔͱ͜ΖͰ͢ɻ 19
  20. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ ͜͜·Ͱདྷͯ໰୊ͱͳΔͷ͕ɺ

    event_quest_sample.json ʹ͍ͭͯ ๻Β͸Ұ੾ͷ࢓༷Λ஌Βͳ ͍ ɺͱ͍͏఺Ͱ͢ɻ ៛ີͳ࢓༷Λ༻ҙͯ͠΋Β͏ʹ͸ίετ͕͔͔Γ·͢͠ɺखݩͰ͋Δఔ౓ͷ࢓༷ͷ͋ͨΓΛ͚ͭ ͯɺ͍͔ͭ͘ͷٙ໰఺͸։ൃνʔϜ΁దٓڞ༗ͭͭ͠σόοάΛ׬ྃͤ͞ͳ͚Ε͹ͳΓ·ͤΜɻ ্ઃఆʹ͓͍ͯద༻Ͱ͖ΔΞϓϩʔν͸͍͔ͭ͋͘Δͱࢥ͍·͕͢ɺࠓճ͸ ࠓ͋ΔσʔλΛύʔ εͯ͠ܕʹམͱ͠ࠐΈɺٯʹੜ੒Ͱ͖ΔΑ͏ͳπʔϧΛ࡞Δ ͜ͱͰରԠͯ͠Έ·͢ɻ Clojure ͱܕ Clojure ͱ͍͏ͷ͸ಈతϓϩάϥϛϯάݴޠͷҰͭͰɺ͔ͳΓಠಛͷܕʹ͍ͭͯͷߟ͑Λ͍࣋ͬͯ ·͢ɻͦͯ͜͠ͷಠಛͳܕ΁ͷߟ͑ํ͕ɺࠓճͷΑ͏ͳಾͳσʔλͷ෼ੳʹඇৗʹ༗ྗͳπʔϧͱͳ Γ·͢ɻ ࠓճ͸ Clojure Ͱ༗ྗͳܕͷఆٛΛิॿ͢ΔϥΠϒϥϦͱͯ͠ malli *1 Λར༻͖ͯ͠·͢ɻ ·ͣ͸ Level ͱ͍͏ 1 ͔Β 100 ͷ int ͷ஋ ͷܕΛఆٛͯ͠Έ·͢ɻ small_sample1.clj (ns domain.sample (:require [malli.core :as m])) (def Level [:and :int [:> 0] [:<= 100]]) ; int Ͱ 0 ΑΓେ͖͘ 100 ҎԼͰ͋Δ ;; ΠϯλϓϦλςετ (m/validate Level 0) ; => false (m/validate Level 1) ; => true (m/validate Level 100) ; => true (m/validate Level 101) ; => false ͜ͷΑ͏ʹɺ type Level int (golang) ͷΑ͏ͳܕఆٛΑΓ΋ৄࡉʹσʔλͷܕΛఆٛɾνΣο ΫͰ͖·͢ɻಈతܕ෇͖ݴޠͳΒͰ͸ͷܳ౰Ͱ͕͢ɺ ্ͷྫͷΑ͏ʹ Clojure ͸ɺJavaScript ͷΑ ͏ͳ΄͔ͷಈతܕ෇͖ݴޠΑΓ΋ɺσʔλͷܕʹ͍ͭͯஸೡʹѻ͑Δͷ͕ັྗͷҰͭͰ͢ɻ ·ͨ͜ͷಈతͳੑ࣭Λར༻ͯ͠ɺ࣍ͷΑ͏ͳؔ਺Λ࡞Δ͜ͱͰɺσʔλͷαϯϓϦϯά͕Ͱ͖·͢ *2ɻ *1 https://github.com/metosin/malli *2 malli ͷػೳΛ࢖͑͹αϯϓϦϯάؔ਺͸ࣗಈੜ੒Ͱ͖ΔͷͰ͕͢ɺنଇੑΛ΋ͨͤͨαϯϓϦϯάͳͲ͕೉͍ͨ͠Ίɺ ຊষΛॻ͍ͨਓ͸ಠࣗͰؔ਺Λ࡞ΔํΛ͓קΊ͍ͯ͠·͢ 20
  21. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ small_sample2.clj (ns domain.sample

    (:require [malli.core :as m])) (def Level [:and :int [:> 0] [:<= 100]]) ; int Ͱ 0 ΑΓେ͖͘ 100 ҎԼͰ͋Δ (defn my-validate [spec value] (or ;; ࢓༷Λຬ͍ͨͯ͠Ε͹ true (m/validate spec value) ;; ࢓༷Λຬ͍ͨͯ͠ͳ͚Ε͹ΤϥʔΛ౤͛Δ (throw (ex-info "invalid spec" {:spec spec :value value})))) (defn generate-level [] ;; αϯϓϦϯάͨ͠ฦΓ஋͕࢓༷Λຬ͍ͨͯ͠ͳ͚Ε͹ΤϥʔΛ౤͛Δ {:post [(my-validate Level %)]} (inc (rand-int 100))) ;; ΠϯλϓϦλςετ (generate-level) ; => 54 etc. ·ͨ Clojure ͷ͜ͷख๏ͷ΋͏ҰͭͷڧΈͱͯ͠ɺ σʔλؒͷؔ܎Λܕʹམͱ͠ࠐΊΔ ͱ͍͏΋ ͷ͕͋Γ·͢ɻ۩ମతͳαϯϓϧͱͯ͠ɺ ఢͷϦετ teki ͱఢͷ਺Λද͢ teki_count Λ࣋ͭ teki_setting ͱ͍͏஋ ͷܕΛఆٛͯ͠Έ·͢ɻ small_sample3.clj (ns domain.sample (:require [malli.core :as m])) (def Level [:and :int [:> 0] [:<= 100]]) ; int Ͱ 0 ΑΓେ͖͘ 100 ҎԼͰ͋Δ (def Teki [:map [:id [:int]] [:level Level] ; લʹఆٛͨ͠ Level ܕ [:count [:and :int [:> 0]]] [:type [:enum 1 2 3]]]) (def TekiSetting [:and [:map ; ҎԼͷΩʔΛ࣋ͭࣙॻߏ଄ [:teki-count [:and :int [:> 0]]] ; teki-count ͸ 0 Ҏ্ [:teki [:vector {:min 1} Teki]]] [:fn (fn [{:keys [teki-count teki]}] ;; teki-count ͸ (-> teki :count) ͷ߹ܭͱҰக͢Δ (= teki-count (apply + (map :count teki))))]]) ;; ΠϯλϓϦλςετ 21
  22. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ (m/validate TekiSetting {:teki-count

    30 :teki [{:id 1 :level 2 :count 10 :type 1} {:id 2 :level 3 :count 20 :type 1}]}) ; => true (m/validate TekiSetting {:teki-count 30 :teki [{:id 1 :level 2 :count 10 :type 1} {:id 2 :level 3 :count 30 :type 1}]}) ; => false Clojure Λ࢖ͬͯϓϩάϨογϒʹ࢓༷Λ෼ੳͯ͠ΈΔ ͜ͷઅͰ͸͍Α͍Αݩͷ event_quest_stages.json Λ෼ੳ͍͖ͯ͠·͢ɻ ෼ੳखॱ͸ҎԼͷ 2 εςοϓ͔ΒͳΓ·͢ɻ 1. Ͱ͖Δ͚ͩݻఆ஋ͷܕ (= ཁૉ 1 ͷ Enum) Λ෇͚͍ͯ͘ 2. ৄࡉͳ࢓༷͕Θ͔ͬͨͱ͜ΖͷܕͷղऍΛ޿͍͛ͯ͘ 22
  23. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ 1. Ͱ͖Δ͚ͩݻఆ஋ͷܕΛ෇͚͍ͯ͘ ·ͣ๻Β͕Ͱ͖ΔҰ൪খ͞ͳ͜ͱͱͯ͠͸ɺ༩͑ΒΕͨσʔλͷΈ͕ਖ਼͍͠ܕ

    Λ࡞Δ͜ͱͰ͢ɻ ͦͷதͰɺσόοάʹΑΓৄࡉͳ࢓༷͕ඞཁͳ஋ΛϦετΞοϓ͍͖ͯ͠·͢ɻ event_quest.clj (ns domain.event_quest (:require [malli.core :as m])) ;; ࢓༷ (def Level [:and :int [:> 0] [:<= 100]]) ; int Ͱ 0 ΑΓେ͖͘ 100 ҎԼͰ͋Δ (def Teki [:map [:id [:int]] [:level Level] ; લʹఆٛͨ͠ Level ܕ [:count [:and :int [:> 0]]] [:type [:enum 1 2 3]]]) ; type ͸ 1 ~ 3 ͚ͩʁ (def EventQuestStage [:and [:map [:teki-count [:and :int [:> 0]]] [:teki [:vector {:min 1} Teki]]] [:teki-syutugen [:and :string [:fn is-valid-time?]]] [:fn (fn [{:keys [teki-count teki]}] ;; teki-count ͸ (-> teki :count) ͷ߹ܭͱҰக͢Δ (= teki-count (apply + (map :count teki))))]]) (def EventQuest [:map [:data-id [:= "event_quest"]] ; ͜Ε͸ݻఆʁ [:event-quest-id [:= "20220801"]] ; ೔෇ʁ [:title [:= "εϖγϟϧΫΤετ1"]] ; ΫΤετλΠτϧ? จࣈྻ௕͸Ͳ͏ͩΖ͏ [:updated-at [:= "20220715133011"]] ; yyyyMMddHHmmss ͬΆͦ͏ [:stages [:vector {:min 3 :max 3} EventQuestStage]]]) ; stage ͸ 3 ͭݻఆʁ ;; ΠϯλϓϦλςετ (m/validate EventQuest {:data-id "event_quest" :event-quest-id "20220801" :title "εϖγϟϧΫΤετ1" :updated-at "20220715133011" :stages [{:teki-count 25 :teki [{:id 1 :level 60 :count 15 :type 1} {:id 2 :level 55 :count 10 :type 1}] :teki-syutugen "0000"} {:teki-count 40 23
  24. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ :teki [{:id 1

    :level 60 :count 15 :type 1} {:id 3 :level 75 :count 5 :type 3} {:id 5 :level 40 :count 20 :type 1}] :teki-syutugen "0100"} {:teki-count 15 :teki [{:id 1 :level 60 :count 10 :type 1} {:id 3 :level 75 :count 4 :type 3} {:id 7 :level 90 :count 1 :type 2}] :teki-syutugen "0230"}]}) ; => true ;; utils (defn is-valid-time? [t] (if (not= (count t) 4) false (let [[min sec] (->> t (partition-all 2) (map (partial apply str)))] (and (= min (re-matches #"\d{2}" min)) (= sec (re-matches #"[0-5][0-9]" sec)))))) 24
  25. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ 2. ৄࡉͳ࢓༷͕Θ͔ͬͨͱ͜ΖͷܕͷղऍΛ޿͍͛ͯ͘ 1.

    ͷεςοϓͰݻఆ஋ͷαϯϓϧ͕Ͱ͖ͨͱ͜ΖͰɺ࣍ʹ a) αϯϓϧσʔλΛ΋͏গ͠΋Β͏ b) ։ൃνʔϜ͔Βٙ໰఺ʹ্͕ͬͨσʔλ߲໨ͷ࢓༷ΛώΞϦϯά͢ΔɺͳͲͯ͠ɺσόοάʹඞ ཁͳσʔλੜ੒͕Ͱ͖Δͱ͜Ζ·ͰܕͷղऍΛ޿͍͖͛ͯ·͢ɻ ͨͱ͑͹ҎԼͷΑ͏ͳܕఆٛʹͳΔ͜ͱ͕ߟ͑ΒΕ·͢ɻ event_quest.clj (ns domain.event_quest (:require [malli.core :as m])) ;; ࢓༷ (def Level [:and :int [:> 0] [:<= 100]]) ; int Ͱ 0 ΑΓେ͖͘ 100 ҎԼͰ͋Δ (def Teki [:map [:id [:int]] [:level Level] ; લʹఆٛͨ͠ Level ܕ [:count [:and :int [:> 0]]] [:type [:enum 1 2 3 4 5]]]) ; type ͸ 1 ~ 5 (def EventQuestStage [:and [:map [:teki-count [:and :int [:> 0]]] ; teki-count ͸ 0 Ҏ্ [:teki [:vector {:min 1 :max 10} Teki]] ; teki ͸ 10 छྨ·Ͱ [:teki-syutugen [:and :string [:fn is-valid-time?]]]] [:fn (fn [{:keys [teki-count teki]}] ;; teki-count ͸ (-> teki :count) ͷ߹ܭͱҰக͢Δ (= teki-count (apply + (map :count teki))))]]) (def EventQuest [:map [:data-id [:= "event_quest"]] [:event-quest-id [:and :string [:fn is-valid-date?]]] ; ೔෇ [:title [:string {:min 1 :max 20}]] ; λΠτϧ͸ 20 จࣈҎ಺ [:updated-at [:and :string [:fn is-valid-datetime?]]] ; yyyyMMddHHmmss [:stages [:vector {:min 3 :max 5} EventQuestStage]]]) ; stage ͸ 3 ~ 5 ;; ΠϯλϓϦλςετ (m/validate EventQuest {:data-id "event_quest" :event-quest-id "20220801" :title "εϖγϟϧΫΤετ1" :updated-at "20220715133011" :stages [{:teki-count 25 :teki [{:id 1 :level 60 :count 15 :type 1} {:id 2 :level 55 :count 10 :type 1}] :teki-syutugen "0000"} 25
  26. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.3 ࢓༷ͷ෼ੳΛ͠Α͏ {:teki-count 40 :teki

    [{:id 1 :level 60 :count 15 :type 1} {:id 3 :level 75 :count 5 :type 3} {:id 5 :level 40 :count 20 :type 1}] :teki-syutugen "0100"} {:teki-count 15 :teki [{:id 1 :level 60 :count 10 :type 1} {:id 3 :level 75 :count 4 :type 3} {:id 7 :level 90 :count 1 :type 2}] :teki-syutugen "0230"}]}) ;; utils (defn is-valid-time? [t] (if (not= (count t) 4) false (let [[min sec] (->> t (partition-all 2) (map (partial apply str)))] (and (= min (re-matches #"\d{2}" min)) (= sec (re-matches #"[0-5][0-9]" sec)))))) (defn is-valid-date? [t] (try (java.time.LocalDate/parse t (java.time.format.DateTimeFormatter/ofPattern "uuuuMMdd")) true (catch java.time.format.DateTimeParseException e false))) (defn is-valid-datetime? [t] (try (java.time.LocalDate/parse t (java.time.format.DateTimeFormatter/ofPattern "uuuuMMddHHmmss")) true (catch java.time.format.DateTimeParseException e false))) 26
  27. ୈ 3 ষ Clojure Ͱ࢝ΊΔ࢓༷෼ੳ 3.4 ऴΘΓʹ 3.4 ऴΘΓʹ ࠓճ͸

    Clojure Λ༻͍ͯσʔλ͔Β࢓༷Λ෼ੳ͍ͯ͘͠ɺͱ͍͏ͪΐͬͱมΘͬͨΤϯδχΞϦϯ άΛ঺հ͍͖ͯ͠·ͨ͠ɻݱ࣮Ͱ͸͋·Γى͜Βͳ͍γνϡΤʔγϣϯͱ͸ࢥ͍·͕͢ɺಈతʹܕΛ ෇͚͍ͯ͘͜ͱɺܕΛϦϑΝΫλ͍ͯ͘͜͠ͱɺͱ͍ͬͨಛʹ੩తܕ෇͖ݴޠͰ͸ΊͬͨʹܦݧͰ͖ ͳ͍ࣄ৅ʹ͍ͭͯݟฉΛ޿Ί͍ͯͨͩ͘ҰॿʹͳΕ͹ͱࢥ͍·͢ɻ ·ͨ࢓༷ʹ͸ stringɺint ͱ͍ͬͨجຊσʔλܕ৘ใͷΈΛॻ͘ͷͰ͸ͳ͘ɺࠓճ Clojure Ͱ෼ੳ ͨ͠Α͏ͳ໌֬ͳܗʹ·ͱΊΒΕΔͱɺ෼ੳख͕ؒল͚σόοάͳͲ͕ΑΓεϜʔζʹਐΉͷͰɺۃ ྗஸೡͳهड़͕Ͱ͖ΔͱΑͦ͞͏Ͱ͢ɻ (ཉΛݴ͑͹ ࠓճͷΑ͏ͳϓϩάϥϜͰ࢓༷͕૊·Ε͍ͯΔͱɺσόοάͳͲ͕΍Γ΍͍͢ͷͰɺ ֤։ൃνʔϜͷٕज़ελοΫʹ߹Θͤͯద੾ͳݴޠɾπʔϧΛ࠾༻͢Δͷ΋Α͍Ͱ͠ΐ͏) 27
  28. ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό ։ൃ

    4.1 ͸͡Ίʹ ฐࣾͰ͸ XFLAG PARK ͱ͍͏ήʔϜɾΞχϝɾԻָͳͲ͞·͟·ͳδϟϯϧͷ֞ࠜΛ௒͑ͨະ ମݧͷ LIVE ΤϯλʔςΠϝϯτγϣʔΛ։࠵͍ͯ͠·͢ɻࠓ೥ͷ XFLAG PARK 2022 Ͱ͸ɺγ εςϜͷҰ෦Ͱ Rust Λ༻͍ͨ։ൃΛ͠·ͨ͠ɻຊষͰ͸ɺRust Ͱ API αʔόΛ։ൃ͢ΔͨΊͷϑ ϨʔϜϫʔΫͰ͋Δ Axum ʹ͍ͭͯ঺հ͠·͢ɻ ຊষͷର৅ऀ • Rust Ͱ API αʔόΛ࡞ͬͯΈ͍ͨਓ • Actix Web ΍ Rocket ͳͲͷ΄͔ͷ Rust ͷ Web ϑϨʔϜϫʔΫΛ࢖ͬͨࣄ͕͋Δਓ Axum Axum*1͸ Rust ͷඇಉظϥϯλΠϜΛ࡞͍ͬͯΔ Tokio ͷνʔϜ͕։ൃ͍ͯ͠Δ Web ϑϨʔϜ ϫʔΫͰ͢ɻTokio ͷΤίγεςϜΛϑϧͰѻ͑Δͱ͜Ζ΍ tower ΍ hyper ͳͲͷڧྗͳϥΠϒϥ Ϧͱͷ࿈ܞ͕Ͱ͖Δ఺͕ಛ௃Ͱ͢ɻ SeaORM SeaORM*2͸ async ରԠͷ O/R ϚούͰόοΫΤϯυʹ sqlx Λ࠾༻͍ͯ͠·͢ɻ·ͨɺActixɺ Tokioɺasync-std ͷ 3 ͭͷඇಉظϥϯλΠϜʹରԠ͍ͯ͠·͢ɻΑΓݹ͔͘Β Rust ͷ O/R Ϛού ͱͯ͠࢖ΘΕ͍ͯΔ Diesel ͱൺֱ͢ΔͱɺDiesel ͸ίϯύΠϧ࣌ʹܕ͕֬ఆ͢Δͷʹର͠ SeaORM *1 Axumɿ https://github.com/tokio-rs/axum *2 SeaORMɿ https://www.sea-ql.org/SeaORM/ 29
  29. ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό։ൃ 4.2

    ToDo ΞϓϦͷ API Λ࡞Δ ͸࣮ߦ࣌ʹܕཱ͕֬͢ΔΑ͏ͳڍಈΛ͠·͢ɻ 4.2 ToDo ΞϓϦͷ API Λ࡞Δ Axum Ͱͷ API αʔό։ൃʹ͍ͭͯ؆୯ʹ஌ΕΔΑ͏ ToDo ΞϓϦͷ API Λ࡞ΔαϯϓϧΛࣔ ͠·͢ɻ *3 Router ͷ࡞Γํ Axum ͷ Router ͸ҎԼͷΑ͏ͳܗͰ࣮૷Ͱ͖·͢ɻ src/main.rs pub struct AppState { pub db: DatabaseConnection, } #[tokio::main] async fn main() { let mut opt = ConnectOptions::new(env::var("DB_HOST") .expect("DB_HOST is not defined")); opt.max_connections(10000) .min_connections(5) .connect_timeout(Duration::from_secs(8)) .idle_timeout(Duration::from_secs(8)) .sqlx_logging(true); let db: DatabaseConnection = Database::connect(opt) .await .expect("Database connection failed"); let app_state = Arc::new(AppState { db }); let addr = SocketAddr::from(( [0, 0, 0, 0], env::var("PORT") .expect("PORT is not defined") .parse::<u16>() .unwrap(), )); if let Err(e) = axum::Server::bind(&addr) .serve(app(app_state).into_make_service()) .await { panic!("{:?}", e) } } *3 ղઆ͢Δ࣮૷ͷίʔυຊମɿ https://github.com/Taillook/axum-seaorm-todo 30
  30. ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό։ൃ 4.2

    ToDo ΞϓϦͷ API Λ࡞Δ fn app(app_state: Arc<AppState>) -> Router { Router::new() .route( "/todo", get(handler::todo::get_todo_list).post(handler::todo::post_todo), ) .layer(AddExtensionLayer::new(app_state)) } ·ͣɺapp ؔ਺Ͱ Router Λ࡞Γ·͢ɻroute ͱ͍͏ؔ਺ͰύεͱϋϯυϥΛ Router ʹఆٛ͢Δࣄ ͕Ͱ͖·͢ɻ͜ͷϋϯυϥ͸ϝιουνΣΠϯͷܗͰ౉͢ܗࣜʹͳΓ·͢ɻ·ͨɺlayer ͱ͍͏ؔ਺ Ͱ͸ AddExtensionLayer ͱ͍͏ߏ଄ମͱ߹Θͤͯঢ়ଶΛ࣋ͭࣄ͕Ͱ͖·͢ɻ͜ͷྫͰ͸ AppState ͱ͍͏ DB ΁ͷ઀ଓ৘ใΛ࣋ͬͨߏ଄ମΛঢ়ଶͱͯ͠อ͍࣋ͯ͠·͢ɻ͜͜Ͱ layer ͱͯ͠ఆٛͨ͠ ஋͸֤ϋϯυϥͰҾ਺ͱͯ͠ݺͼग़ͯ͠ѻ͍·͢ɻ main ؔ਺Ͱ͸ AppState ͷ৘ใͱαʔόͷ PORT ৘ใΛఆٛ͠ Router Λ࣮ࡍʹಈ͔͍ͯ͠ ·͢ɻ Handler ͷ࡞Γํ Handler ͸ҎԼͷΑ͏ʹ࣮૷͠·͢ɻ src/handler/todo.rs pub async fn get_todo_list(Extension(state): Extension<Arc<crate::AppState>>) -> Response<BoxBody> { let todo_list = Todos::find().all(&state.db).await; match todo_list { Ok(todo_list) => ( StatusCode::OK, Json(TodoResponse { todo_list: serde_json::from_str::<Vec<Todo>>( json!(todo_list).to_string().as_str() ).unwrap(), }), ) .into_response(), Err(err) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { status: i32::from(StatusCode::BAD_REQUEST.as_u16()), title: format!("{:?}", err), }), ) .into_response(), } } 31
  31. ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό։ൃ 4.2

    ToDo ΞϓϦͷ API Λ࡞Δ pub async fn post_todo( Extension(state): Extension<Arc<crate::AppState>>, Json(params): Json<PostTodoRequest>, _: Auth, ) -> Response<BoxBody> { let todo = todos::ActiveModel { todo: Set(params.todo), ..Default::default() }; let result = Todos::insert(todo).exec(&state.db).await; match result { Ok(result) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(PostTodoResponse { last_insert_id: result.last_insert_id as i32, }), ) .into_response(), Err(err) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { status: i32::from(StatusCode::BAD_REQUEST.as_u16()), title: format!("{:?}", err), }), ) .into_response(), } } ·ͣɺAxum ͷϋϯυϥ͸ axum::response::IntoResponse ͱ͍͏τϨΠτΛ࣮૷ͨ͠΋ͷΛ Ϩεϙϯεͱͯ͠ฦ͘͢͠Έͱͳ͍ͬͯ·͢ɻ͍͔ͭ͘ܗ͕ࣜ͋Γ·͕͢ྫͰ࣮૷͢Δϋϯυϥ͸ ( http::status::StatusCode, axum::Json) ͱ͍ͬͨܗࣜͰϨεϙϯεΛฦ͠·͢ɻ DB ͱͷ࿈ܞ͸ઌड़ͷ AppState ͷίωΫγϣϯΛ࢖͍ɺTodos ͳͲͷ֤ςʔϒϧ͝ͱʹ࣮૷͞ Εͨؔ਺Λ࢖͍·͢ɻ͜ͷؔ਺ͷ࣮૷͸ࣗಈੜ੒ͰߦΘΕ͍ͯͯ SeaORM ͕ఏڙ͢Δ sea-orm-cli Λ༻͍·͢ɻ·ͨɺAppState Λऔಘ͍ͯ͠Δ Extension(state) ΍ Json(params) ͳͲͷҾ਺͸ Extractor ͱݺ͹ΕɺϦΫΤετͷσʔλΛநग़͢Δ͘͠ΈͰ͢ɻ OpenAPI ͱͷ࿈ܞ OpenAPI ͱͷ࿈ܞʹ͍ͭͯ͸ݱঢ় Axum ଆͷରԠ͕͞Ε͍ͯ·ͤΜɻPoC ͱͯ͠ͷ࣮૷͸Կ౓ ͔ٞ࿦͞Ε͍ͯ·͢*4͕௚ۙͰ͸ࣗಈੜ੒౳Ͱ࿈ܞ༻ͷίʔυΛੜ੒͢ΔΑ͏ͳܗͰରԠ͢Δ΄͔ͳ ͍Ͱ͢ɻ ຊষͰͷྫͰ͸ openapitools/openapi-generator-cli ͷ rust ΦϓγϣϯΛ༻͍ͯ Rust ͷߏ଄ମͷ *4 axum Ͱͷ OpenAPI ରԠͷ PoCɿ https://github.com/tokio-rs/axum/pull/459 32
  32. ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό։ൃ 4.2

    ToDo ΞϓϦͷ API Λ࡞Δ ΈΛαʔό࣮૷಺Ͱѻ͏ରԠΛऔ͍ͬͯ·͢ɻ ೝূ Bearer ೝূͳͲ͸ҎԼͷΑ͏ʹ࣮૷͠·͢ɻ src/handler/auth.rs pub struct Auth; pub struct AuthError; impl IntoResponse for AuthError { fn into_response(self) -> Response<BoxBody> { let status = StatusCode::UNAUTHORIZED; let body = json!({"error": "Unauthorized".to_string()}).to_string(); (status, body).into_response() } } #[async_trait] impl<B> FromRequest<B> for Auth where B: Send, { type Rejection = AuthError; async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> { use std::env; use axum::{ extract::TypedHeader, headers::{authorization::Bearer, Authorization}, }; match TypedHeader::<Authorization<Bearer>>::from_request(req).await { Ok(TypedHeader(Authorization(bearer))) => { match bearer.token() == env::var("API_KEY") .expect("API_KEY is not defined") { true => Ok(Auth {}), false => Err(Self::Rejection {}), } } Err(_) => Err(Self::Rejection {}), } } } FromRequest ͱ͍͏τϨΠτΛ࣮૷͢ΔࣄͰϋϯυϥͷҾ਺ʹ͋Δ Extension ΍ Json ͳͲͷ 33
  33. ୈ 4 ষ Rust ͷ Axum Λ࢖ͬͨ API αʔό։ൃ 4.3

    ͓ΘΓʹ Extractor*5Λ࣮૷͢Δࣄ͕Ͱ͖·͢ɻ͜ͷ࣮૷Ͱ͸ Authorization<Bearer>Λऔಘ͠ɺbearer .token() ͱ API_KEY ؀ڥม਺ͷϚονΛऔΔࣄͰೝূΛߦ͍ͬͯ·͢ɻJWT ͷݕূͷΑ͏ͳ Extractor Λ࡞Γ͍ͨ৔߹ʹ͓͍ͯ΋ from_request ؔ਺಺ͷॲཧΛมߋ͢ΔࣄͰ༰қʹ࣮૷Ͱ͖ ·͢ɻ 4.3 ͓ΘΓʹ ຊষͰ͸ Rust ͷ Axum Λ࢖ͬͨ API ͷ࣮૷ʹ͍ͭͯ঺հ͠·ͨ͠ɻRust Ͱ API αʔόΛ࡞Δ ํ΁ͷࢀߟʹͳΕ͹ͱࢥ͍·͢ɻ ͨͩ͠ɺൃల్্ͳϑϨʔϜϫʔΫͱ͍͏ͷ΋͋ΓόʔδϣϯΞοϓʹ͍͍ͭͯ͘ؾ߹͍΋ඞཁͰ ͸͋Γ·͢ɻ *5 axum ͷ Custom Extractorɿ https://docs.rs/axum/0.1.1/axum/extract/index.html#defining-custom- extractors 34
  34. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.1 ຊষʹ͍ͭͯ ࢲ͕औΓ૊ΉϓϩδΣΫτʹ͓͍ͯதֶߍ΁ͷιϑτ΢ΣΞఏڙ΍ֶशࢦಋΛ਺ଟ࣮͘ࢪͨ͠ɻͦ ͷதͰ࣮ફͨ͠໰୊෼ੳ΍ݕূͱϑΟʔυόοΫΛऔΓೖΕͯͷվળʹ͍ͭͯৼΓฦͬͯ੔ཧ͠ɺι ϑτ΢ΣΞ։ൃࣄྫͷҰͭͱͯ͠චऀ΋ؚΊͨಡऀ͢΂ͯͷํͷܞΘΔϏδωεʹ׆͔͞Ε͍ͨɻͳ ͓ઌʹݴ͓ͬͯ͘ͱɺຊষͰ͸ϓϩάϥϛϯάͱίʔυͷ࿩͸ొ৔͠ͳ͍ɻ

      චऀϓϩϑΟʔϧ ήʔϜΛத৺ͱͨ͠ιϑτ΢ΣΞΤϯδχΞͱͯ͠׆ಈ͓ͯ͠ΓɺίϯγϡʔϚήʔϜ΍ϒϥ΢ βήʔϜͱεϚʔτϑΥϯΞϓϦͷ։ൃɺWeb αʔϏε΍ήʔϜاը΋ܞΘΔɻۙ೥͸ڭҭݱ ৔ʹ޲͚ͯɺ ʮϓϩάϥϛϯάֶशʯΛਪਐ͢Δߨࢣͱͯͦ͠ͷֶशιϑτ΢ΣΞ΍ΧϦΩϡϥ Ϝ։ൃͱซͤͯऔΓ૊ΜͰ͍Δɻ LinkedIn: https://www.linkedin.com/in/akira-tanabe/   ͶΒ͍ ࢲ͕୲͍ͬͯΔۀ຿Ͱ͋Δ͜ͷϢχʔΫͳऔΓ૊ΈͷཪଆΛ͔͋͠աఔΛৼΓฦΔ͜ͱͰɺ޿ٛͳ ιϑτ΢ΣΞιϦϡʔγϣϯʹ͓͚Δ໰୊ղܾࣄྫͱͯ͠࢒͠චऀͱಡऀͷֶͼʹͭͳ͛Δ͜ͱΛओ ࢫͱ͢Δ 35
  35. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.1 ຊষʹ͍ͭͯ ཁ໿ • ݱࡏࢲͨͪ͸தֶߍʹରͯ͠ϢχʔΫͳࢧԉ׆ಈΛൃݟ͠ͳ͕Βܧଓతʹ࣮ࢪ͍ͯ͠Δ •

    ࣮ࢪઌ΍಺༰͸͋Β͔͡Ίܾ·͍ͬͯΔΘ͚Ͱ͸ͳ͘ɺ੠Λฉ͖ঢ়گΛݟͯاըΛఏҊ͠ͳ͕ ΒίϯςϯπΛఏڙ͓ͯ͠Γɺ·ͨ೔ʑͦΕ͸ਐԽ͠ॆ࣮͖͍ͯͯ͠Δ • ໰୊ղܾͷࢹ఺Ͱɺ͜Ε·Ͱࢧԉ͕࣮ݱͨ͠աఔͰ͸ͲΜͳ໨తʹ͓͍ͯɺͲͷΑ͏ʹఏࣔ ͠ɺͲͷΑ͏ͳ४උΛ͠ɺͲΜͳબ୒Λͨ͠ͷ͔Λྫࣔ͢Δ͜ͱͰɺ͍ͣΕ͔ͷϏδωεͷ֫ ಘ΍্ཱͪ͛ʹͱͬͯؔ৺͕͋ΔࣄྫͱͳΕ͹ͱࢥ͍ه͢ • ιϑτ΢ΣΞ։ൃͷࢹ఺Ͱɺͦͷاըͷݟ௨͠ΛͲͷΑ͏ʹཱͯɺͲͷΑ͏ͳཪ෇͚Λ࣋ͪɺ ͲͷΑ͏ʹ਱ߦ͔ͨ͠Λྫࣔ͢Δ͜ͱͰɺιϑτ΢ΣΞ੍࡞΍Ϗδωεͷ্ཱͪ͛ɺىۀʹ ͱͬͯؔ৺͕͋ΔࣄྫͱͳΓ͏Δ TOPICS 1. ࢲͨͪͷڭҭࢧԉ׆ಈʹ͍ͭͯ 2. ໰୊ 3. ໰୊ͷ෼ղ 4. ໨ඪઃఆͱߦಈࢦ਑ 5. ίϯςϯπاըͱ͞·͟·ͳ෼ੳ 6. ΞΠσΞͷൃ૝ͱࢥߟ 7. ࠷ޙʹ ࢀߟจݙɺҾ༻ •ʮϏδϣφϦʔΧϯύχʔʯδϜɾίϦϯζʢ˞γϦʔζʣ •ʮGIVE ˍ TAKEʯΞμϜɾάϥϯτ •ʮϦʔϯɾελʔτΞοϓʯΤϦοΫɾϦʔε •ʮRunnnig LeanʯΞογϡɾϚ΢Ϧϟ •ʮϏδωεϞσϧδΣωϨʔγϣϯζʯΞϨοΫεɾΦελʔϫϧμʔɺΠϰɾϐχϡʔϧ •ʮMeasure What Matters ఻આͷϕϯνϟʔ౤ࢿՈ͕ Google ʹڭ͑ͨ੒ޭख๏ OKRʯδϣ ϯɾυʔΞ •ʮσβΠϯࢥߟ͕ੈքΛม͑Δ: ΠϊϕʔγϣϯΛಋ͘৽͍͠ߟ͑ํʯςΟϜɾϒϥ΢ϯ •ʮܦӦઓུશ࢙ʯࡾ୩ ޺࣏ 36
  36. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.2 ࢲͨͪͷڭҭࢧԉ׆ಈʹ͍ͭͯ 5.2 ࢲͨͪͷڭҭࢧԉ׆ಈʹ͍ͭͯ ओͳίϯςϯπ࣮੷͓ΑͼΧϦΩϡϥϜαΠζ •

    ौ୩۠಺ͷެཱɾࢲཱதֶߍतۀࢧԉ͓ΑͼίϯςϯπͱΧϦΩϡϥϜ –ʮதֶ૯߹తͳֶशͷ࣌ؒʯ޲͚ςΩεϓϩάϥϛϯάɹ 3 ίϚ૬౰ʢڭࢣ࣮ࢪՄʣ –ʮதֶ਺ֶʯ޲͚ίϯύεΛ࢖ͬͨ਺ֶ՝୊ɹ 1 ίϚ૬౰ʢڭࢣ࣮ࢪՄʣ –ʮதֶٕज़Պ D ৘ใʯ޲͚ςΩεϓϩάϥϛϯάɹ 8 ίϚ૬౰ʢڭࢣ࣮ࢪՄʣ –ʮதֶٕज़Պ D ৘ใʯ޲͚ Python ݴޠϓϩάϥϛϯάɹ 1ʙ4 ίϚ૬౰ • ಉ۠಺ͷެཱɾࢲཱதֶߍ޲͚ͷύιίϯ෦ܥࢦಋ͓ΑͼίϯςϯπͱΧϦΩϡϥϜ –ʮதֶύιίϯ෦׆ಈʯ޲͚ LuaɾPython ϓϩάϥϛϯάɹ 2 ࣌ؒ x7 ೔෼૬౰ –ʮதֶύιίϯ෦׆ಈʯ޲͚ Unity ήʔϜ੍࡞ϓϩάϥϛϯάɹ 2 ࣌ؒ x4 ೔෼૬౰ • ΩϟϦΞڭҭɾϓϩάϥϛϯάϫʔΫγϣοϓ – தֶੜ޲͚ϓϩάϥϛϯάߨ࠲ɹ 1.5 ࣌ؒ૬౰ – தֶੜ޲͚ήʔϜ։ൃ Unity ߨ࠲ɹ 3 ࣌ؒ૬౰ – ΤϯδχΞ৬ߨԋ ਤ: ٕज़Պ Python तۀ 37
  37. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.3 ໰୊ 5.3 ໰୊ ͔͜͜Β͸ɺࢲ͕औΓ૊ΜͰ͍ͯࠓճৄ͘͠ղઆ͍ͨ͠ʮ໰୊ʯͷى͜ΓͱͦͷରԠʹ͍ͭͯࣄྫ ঺հͱͯ͠ৄ͍͠ܦҢΛهड़͍ͯ͘͠ɻͳ͓ɺهࡌ͢Δଞऀʹؔ͢Δഎܠ΍ҙࢥʹ͍ͭͯͷ৘ใݯ

    ͸ɺҰൠʹࠂࣔ͞Ε͍ͯΔ΋ͷͷ΄͔ҙਤΛټΜͰςΩετԽͨ͠෦෼΋ଟগ͋Δɻຊষͷझࢫ͸໰ ୊ղܾख๏ʹ͓͚ΔղܾࣄྫΛɺ޷ҙతʹ෼ੳ͠࿦͡Δ΋ͷͰ͋Γɺ͍ͣΕ͔ͷ૊৫ʹ͓͚Δ಺৘΍ ໰୊఺ʹ͍ͭͯࢦఠ͢Δҙਤ͸ͳ͍ɻ ໰୊ͷ্ཱ͕ͪΓ • ओɹ୊ɹɿɹٛ຿ڭҭ΁ͷϓϩάϥϛϯάֶशࢧԉΛ͢Δ • ґཔऀɹɿɹौ୩۠ • ൃɹੜɹɿɹ 2019 ೥౓य़ a. എܠɹʙֶߍڭҭͰͷϓϩάϥϛϯάֶशͱ͸ ಺ֳ෎ͷΊ͟͢ Society 5.0 ͷࣾձɻङྌɺ೶ߞɺ޻ۀɺ৘ใʹଓ͘ 5 ظ໨ͱͳΔࣾձ͕໨ࢦ͢΋ ͷ͸αΠόʔۭؒͱϑΟδΧϧۭؒΛߴ౓ʹ༥߹ͤͨࣾ͞ձɻະདྷʹ޲͚ͯςΫϊϩδͱՊֶٕज़ ͱͷ༥߹ͳͲɺ૯߹తͳֶशʹऔΓ૊Ή STEAM ڭҭΛਪਐ͢Δจ෦Պֶলɻֶߍʹ͓͚Δ ICT ׆ ༻ʢ৘ใ௨৴ٕज़ʣͭ·ΓΠϯλʔωοτ΍ PC ͷར༻Λ࣮ࢪ͢Δ֤஍࣏ࣗମɻ৽͍͠ػث΍ιϑτ ΢ΣΞ͕ಋೖ͞ΕैདྷͷतۀҎ֎ͷ஌ࣝͱ׆༻͕ٻΊΒΕͯ͘Δڭһઌੜํɻ ֶߍ΍ߦ੓ͷͶΒ͏࣮ࢪల։ ࣮ࢪϞσϧʹ͓͍ͯ͸ɺICT ׆༻ͱϓϩάϥϛϯάֶशʹ͓͍ͯ஍Ҭͱͷͭͳ͕ΓΛ׆͔ͨ͠औΓ ૊Έ͕༗ҙٛͱ͞Εɺ஍ҬΫϥϒ΍஍ݩاۀ΍େֶͳͲͱͷͭͳ͕ΓΛ׆͔ͯ͠ࢦಋ͍ͯ͘͜͠ͱ͕ ྫࣔ͞ΕΔͳͲɺ׭ɾຽɾֶͷ࿈ܞ͕ࠓޙٻΊΒΕ͍ͯ͘ͱ͍͏ɻ ڭҭݱ৔ʹ͓͍ͯ͸ɺ৽෼໺ͱͯ͠ʮϓϩάϥϛϯάʯ͕ࢦಋͷൣғʹೖΔதͰֶश಺༰͕·ͩ໛ ࡧஈ֊ʹ͋Δɻϓϩάϥϛϯά͸ӳޠͱಉ༷ʹશһֶ͕श͢ΔྖҬʹͳΔͱࣔ͞Ε͍ͯΔɻͦͷ࣌Ͳ Μͳ՝୊͕ר͖ى͜Δͷ͔ɺ·ͩ༧ଌ͕͔ͭͳ͍ɻ 38
  38. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.3 ໰୊ b. େ·͔ͳཁ๬͔Βํ਑΁ͷམͱ͠ࠐΈ·Ͱ ࢲ͕ͨͪ໰୊ʹऔΓ૊Έͩͨ͠ͷ͸ 2019

    ೥౓य़ɻґཔ͍ͯ͠Δͷ͸ौ୩۠ɻऔΓ૊Ή໰୊͸ɺٛ ຿ڭҭͰ͜Ε͔Β࢝·Δʮϓϩάϥϛϯάڭҭʯʹֶ͍ͭͯߍΛࢧԉ͢Δͱ͍͏ौ୩۠୲౰෦ॺ͔Β ґཔͷ΋ͷɻ࣌ྲྀతʹ࿩୊ʹͳ͍ͬͯΔશࠃతͳ՝୊Ͱ͋Δʮϓϩάϥϛϯάڭҭʯ͕ٛ຿ڭҭͰ΋ ࣮ࢪ͞ΕΔ͜ͱͱͳΓɺ࣍೥౓Ͱ͋Δ 2020 ೥౓͔ΒখֶߍɺҎ߱Ͱ͸தֶߍɺߴߍͱ࣮ࢪ͞Ε͍ͯ ͘ͱ͍͏ɻґཔ͖ͯͨ۠͠ͷখதֶੜ΁͸ͦΕΑΓ 2 ೥લͷฏ੒ 29 ೥ 9 ݄ʢ2017ʣ͔ΒλϒϨοτ PC ͕ࢧڅ͞Ε͍ͯΔɻ׆༻͸࢝·͍ͬͯΔ͕΋ͬͱ͜Ε͔Β৳͹͍ͨ͠ͱ͍͏ঢ়گͰ΋͋Δɻ ղܾ͢΂͖໰୊ͷൃݟͱେํ਑ͷܾఆɺ୭ʹԿΛఏڙ͢Δͷ͔ ໰୊ղܾ΁ͷऔΓ૊Έʹ͋ͨͬͯ͸ҙࢥܾఆऀ͕ܾఆΛԼΖͯ͘͠ΕΔ΋ͷͰ͸ͳ͍ɻऔΓ૊Έʹ ͋ͨΔࣗ෼ࣗ਎͕Ͳ͏͢Δ͔Λ෼ੳͯ͠ࡦఆ͠ɺऔΓ૊Έ૬खͱࣗΒͷ૊৫ʹ্͛ೝ஌ͱ߹ҙΛಘ ΔɻऔΓ૊Έ૬खͱࣗ૊৫૒ํͷظ଴ʹԠ͑Δ͜ͱ͕ٻΊΒΕΔɻ ௕ظతͳऔΓ૊ΈΛߦ͏૬ख΍ؔ܎اۀͱͷ࠲૊Έʢొ৔ਓ෺ͱͦͷؔ܎ੑʣΛ૊Ή࣌఺Ͱɺґཔ ऀ΁ࣗ෼ͨͪͷ໾ׂͱظ଴ΛͲͷΑ͏ʹҐஔ෇͚Δ͔Λࣔ͞ͳ͚Ε͹ͳΒͳ͍ɻ೤ྔɺݴ͍׵͑Ε͹ ফඅΧϩϦʔΛͲͷΑ͏ʹઃఆ͢Δ͔΋ॏཁͰ͋Δɻ·ͬͨ͘౿Έࠐ·ͳ͍ख΋͋Ε͹͔ͬ͠Γ΍Δ ख΋͋Δɻطଘιϑτ΢ΣΞΛ୳͢ख΋͋Ε͹ࢴͱϖϯΛ࢖͏ख΋͋Δɻ ໰୊΁ͷΞϯαʔͱॳಈΛܾΊΔ͜ͱ͔Β໰୊ղܾ͸࢝·Δɻকདྷతʹ࣮ࢪ͞ΕΔͰ͋Ζ͏ࢧԉͷ த਎͸Ͳ͏͍͏΋ͷ͔ɺݱঢ়ͩͱͲ͏໰୊͕͋Δͷ͔ɺ ʮࢧԉ͢Δʯͱ͸ԿΛͲ͏͢Δ͜ͱ͔ɻৄ͠ ͍ௐࠪͱ෼ੳ͕ඞཁʹͳΔɻ c. ෼ੳํ๏ ͔͜͜Βड़΂Δʮ໰୊ղܾʯͷʮ໰୊ʯͱ͸ཁٻཁ๬ͷҰͭͰ͋Γɺ ʮ͋Δ౰ࣄऀͷ՝୊ʯͱಉٛͩ ͱࢥͬͯಡΜͰ΄͍͠ɻ ᶗ. 5W1H ෼ੳ ෼ղʹ͋ͨͬͯ࿙Εͳ͘ݕ౼Λߦ͏ͷʹศརͩͱͯ͠ࠓճબ୒ͨ͠ख๏͸ΦʔιυοΫεʹ ʮ5W1Hʯ ɻେੲ͔Β͋ΔجຊͰ͋ͬͯ෠Δਓ΋ଟ͍ͩΖ͏͕͜ͷ࿦఺ͰͷಥͬࠐΈ͕Ͱ͖Δاը͸ ಴࠳͢Δɻ෼ੳπʔϧ͕͍·Ͳ͖͔Ͳ͏͔͸໰୊Ͱ͸ͳ͘ɺ࿙Εͳ͘μϒΓͳ͘෼ੳ͢ΔʮMECE ʢϛʔγʔʣ ʯͷϓϩηε͕ͱΕ͍ͯΔ͔ͱ͍͏͜ͱ͕ϙΠϯτͰ͋Δɻ 1. what ɹԿΛ 2. who ɹ୭͕ 3. when ɹ͍ͭ 4. where ɹͲ͜Ͱ 5. why ɹͳͥ 6. how ɹͲ͏΍ͬͯ 39
  39. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.3 ໰୊ ˙ิ଍ 3 ͭ ্ͷ

    5 ͚ͭͩͰ͸࣮ࡍʹ͸͞Βʹಥͬࠐ·Εͯ౴͑ΒΕͳ͍ͨΊɺ͜͜ʹৗ༻తʹ໰Θ ΕΔࣄ߲Λಠࣗʹ 3 ͭ଍͓ͯ͘͠ɻଞྫʹ฿ͬͯӳޠදهʹ͢Δɻ 1. can ɹʢͰ͖Δ͜ͱʣ 2. should ɹʢ΍Δ΂͖͜ͱʗͰͳ͍͜ͱʣ 3. resist ɹʢ఍߅ʣ ˙ର৅ऀ ໰͏߲໨͸୭ͷࢹ఺ʹΑΔ΋ͷ͔Ͱ΋೿ੜ͢Δ΋ͷͰ͋Γɺͨͱ͑͹ʮwhyʯͳͥ΍Δ͔ ʹ͓͍ͯࣗ෼͕΍Δཧ༝ͱґཔऀ͕΍Δཧ༝͸͓ͦΒ͘ผʹ͋ΔɻΑΓৄࡉʹݕ౼͍ͯ͘͠ͷͰ͋Ε ͹ɺ૒ํʹ૊৫΍άϧʔϓͷϨΠϠ͕͋ΓͦΕͧΕผͷҙࢤ΍໨తΛ࣋ͪɺͦͷझࢫΛ౿ऻ͠߹ҙΛ औΓ෇͚͍ͯ͘ඞཁ͕͋Δ͜ͱΛߟྀ͠ͳ͚Ε͹ͳΒͳ͍ɻ ࠓճ͸ओʹ߹ҙΛಘ͍ͨର৅ͱͯ͠ҎԼࡾऀʹରͯ͠Ͱ͖Δ͚ͩ͘·ͳ͘ड़΂Δ͜ͱʹ౒ΊΔɻ ˙ݕ౼ࢹ఺ 1. ґཔऀ 2. ࣗ૊৫ 3. ࣗ෼ࣗ਎ ड͚खଆΛʮࣗ૊৫ʯͱʮࣗ෼ࣗ਎ʯʹ෼͚ͯఆٛͨ͠ͷ͸͜ͷऔΓ૊Έಛ༗ͷଆ໘͕͋Δ͔΋͠ Εͳ͍ɻԾʹґཔऀ͕໌֬ͳϓϩμΫτʢಛఆͷιϦϡʔγϣϯ΍αʔϏε·ͨ͸੡඼ʣΛٻΊͯ Φʔμʔ͍ͯ͠ΔͷͰ͋Ε͹ɺ૒ํͷ໨త͕໌֬Ͱ͋Γ஫໨͢ΔՕॴ͸ҟͳΔͩΖ͏ɻࠓճͷࣄྫ ͷ৔߹ɺࣗࣾ͸ʮ΍Δ΂͖͜ͱͰ͋Ε͹΍Δʯͱ͍͏ɺཱͪҐஔͱͯ͠தཱతͳ࢟੎Ͱ͋ͬͨɻ·ͨ ʮࣗ෼ࣗ਎ʯͷ࢟੎ͱͯ͠΋ଟগҟͳΓɺ ʮࠓޙ༗ҙٛʹͳΔݟࠐΈ͕͋Δ͜ͱΛݟग़ͯ͠΍Δ΂͖ʗ ΍Βͳ͍΂͖Λࣔ͢ʯͱ͍͏ཱ৔ʹ͋Δɻ͜Ε͔Βࣔ͢ࡾऀͷඍົͳ࿦఺ͱظ଴஋ͷҧ͍ʹ஫໨ͯ͠ ΄͍͠ɻ ᶘ. ࠓճͷ෼ੳํ๏·ͱΊ ໰୊ղܾͷจ຺Ͱ 5W1H ʴЋΛ·ͱΊɺ࣍ͷͱ͓ΓͱͳΔɻ 40
  40. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.3 ໰୊ ˙ͲΜͳ໰୊͔ 1. ԿΛ͢Δ͜ͱͳͷ͔ what

    2. ୭͕΍Δͷ͔ who 3. ͍ͭͷ͜ͱͳͷ͔ when 4. ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where 5. ͳͥ΍Δͷ͔ why 6. Ͳ͏΍Δ͔ how 7. ࣗ෼ୡ͸Կ͔Ͱ͖Δͷ͔ can 8. ࣗ෼ୡ͸ԿΛ͢΂͖Ͱɺ͢΂͖Ͱͳ͍͔ should 9. ͲΜͳ఍߅ͱো֐͕͋Δͷ͔ resist ˙୭ͷࢹ఺͔ 1. ґཔऀ 2. ࣗ૊৫ 3. ࣗ෼ࣗ਎ ͜ΕΒΛςϯϓϨʔτͱͯ͜͠Ε͔Βड़΂Δ෼ੳͰ໰͍͍ͯ͘ɻ ᶙ. 5W1H Ͱղઆ͢Δࢹ఺ͷॱং ͢΂ͯͷ࣌఺Ͱʮґཔऀʯͱʮࣗ૊৫ʯͱʮࣗ෼ࣗ਎ʯͷࢹ఺Ͱͷఆ͕ٛ͋Δ͸ͣͰ͋ΔɻͦΕͧ Εͷҙࢥ͕ৗʹಉ࣌ʹଘࡏ͍ͯ͠ΔͨΊͰ͋Γɺಈ͖͕͋Δͱ͖ͦͷ྆ऀؒͷʮ5W1Hʯ͕ඞཁͰ͋ Δɻͦͷ͢΂ͯΛड़΂Δʹ͸৑௕Ͱ͋Γ·ͨຊষͰ͸ղܾ͍ͨ͠໰୊ͱͦͷղܾํ๏ʹؔ͢ΔྲྀΕΛ ղઆ͍ͨͨ͠ΊɺͦΕͧΕͷஈ֊Ͱͷओ໾ʹ͋ͨΔ 1 ͭͷࢹ఺ͣͭͰड़΂Δ͜ͱʹ͢Δɻ 41
  41. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ 5.4 ໰୊ͷ෼ղ લ߲Ͱڍ͛ͨ·ͱΊํʮ5W1HʯʴЋͰɺཁ๬ͭ·Γղܾ͍ͨ͠໰୊Λ੔ཧ͢Δɻࢹ఺͸·ͣ໰୊ ఏىΛ͢ΔʮґཔऀʯΛߟ͑ɺґཔऀͷཱ৔ʹͳͬͯڞײ͠ͳ͕Β໰୊΍ҙਤ΍ཧ૝ͳͲΛټΜͰ

    ͍͘ɻ ґཔऀʹͱͬͯ • ԿΛ͢Δ͜ͱͳͷ͔ what – ٛ຿ڭҭ΁ͷϓϩάϥϛϯάֶशࢧԉΛ͢Δ • ୭͕΍Δͷ͔ who – ׭ຽֶ࿈ܞʹ͓͚Δʮຽʯ ɺຽؒͷઐ໳Ո͕΍Δ͜ͱʹҙຯ͕͋Δ • ͍ͭͷ͜ͱͳͷ͔ when – ͦͷ࣌఺ͷ࣍೥౓ɻ20 ೥౓͔Βͷॱ࣍ඞमԽʹ޲͚Δ • ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where – ۠಺ͷٛ຿ڭҭɺ20 ೥౓খֶੜͳͲ • ͳͥ΍Δͷ͔ why – ֶߍڭһ͚ͩͰ͸ϓϩάϥϛϯάྖҬʹ͍ͭͯઐ໳త஌ࣝͷ४උ͕ͳ͍ͨΊऔΓ૊Έ͕ ͍ͨ • Ͳ͏΍Δ͔ how – ఏҊͯ͠΄͍͕͠΄͔ͷࣄྫ΋ࢀߟʹ͢Δ • ࣗ෼ୡ͸Կ͔Ͱ͖Δͷ͔ can – ۠ͷ IT اۀͷίϛϡχςΟΛ׆͔ͯ͠اۀʹڠྗΛཁ੥͢Δ͜ͱ • ࣗ෼ୡ͸ԿΛ͢΂͖Ͱɺ͢΂͖Ͱͳ͍͔ should – ࣮ࢪͷબ୒͸ֶߍͷ൑அʹΏͩͶΔͨΊ࣮ࢪϝχϡʔͷఏࣔΛ͢Δʢ΂͖ʣ – ֶशࢦಋཁྖʹ४ڌ͢Δʢ΂͖ʣ • ͲΜͳ఍߅ͱো֐͕͋Δͷ͔ resist – ར༻ڭࡐͷ੍໿͕͋Δ͔΋͠Εͳ͍ – ֶߍଆͷڠྗ͕ಘΒΕͳ͍͔΋͠Εͳ͍ – ࢠͲ΋͕ͨͪదԠͰ͖ͳ͍͔΋͠Εͳ͍ 42
  42. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ a. ৘ใऩू จ෦Պֶলͷࢦ਑ͱઌߦࣄྫ ICT

    ػثʢ৘ใ୺຤ʣͷѻ͍΍ϓϩάϥϛϯάʹؔ͢Δֶश͕৽ͨʹ௥Ճ͞ΕΔখֶߍɺϓϩ άϥϛϯά΍৘ใʹؔ͢Δֶश಺༰Λ͞Βʹॆ࣮ͤ͞Δதֶߍɻֶशࢦಋཁྖͷվగ͸ฏ੒ 29 ೥ ʢ2017.3ʣʹެࣔ͞Εɺখֶߍ͸ྩ࿨ 2 ೥౓ʢ2020.4ʣ ɺதֶߍ͸ྩ࿨ 3 ೥౓ʢ2021.4ʣ͔Βશ໘࣮ࢪ ͞ΕΔɻ௨ৗɺֶशࢦಋཁྖʹ४ڌͨ͠ڭՊॻ͕ڭՊॻग़൛ձ͔ࣾΒ͍͔ͭ͘࡞੒͞Εɺ֤࣏ࣗମ͝ ͱʹબఆ࠾୒Λܦͯɺڭһ͕ڭՊॻΛ΋ͱʹतۀҊΛ࡞੒͠ࢦಋ͢Δɻ2019 ೥౰࣌ɺڭՊॻ͸·ͩ ͳ͔ͬͨɻ খֶߍϓϩάϥϛϯάʹؔͯ͠͸ɺࢦఆڭՊͱͯ͠ͷֶश୯ݩ͸ͳ͘ɺطଘͷֶशʹ͞Βʹ ICT ڭࡐ΍ϓϩάϥϛϯάΛԠ༻͍ͯ͘͜͠ͱ͕ࣔ͞Ε͍ͯΔɻྫࣔ͞ΕԠ༻͠΍͍͢෦෼ͱͯ͠͸ʮࢉ ਺ʯ ʮཧՊʯ ʮ૯߹తͳֶशͷ࣌ؒʯͱͳΔɻͦͷޙ࣍ୈʹ͖͋Β͔ʹͳ͍ͬͯ͘ཁૉͱͯ͠ʮΞϧΰ ϦζϜʯʹؔΘΔ΋ͷ͕৽ͨʹڭՊॻʹࡌͬͨɻ தֶߍֶशࢦಋཁྖͰ͸͢Ͱʹϓϩάϥϛϯάʹؔͯ͠ଟগ͸ʮٕज़Պʯʹࡌ͍ͬͯͨɻ಺༰͕Α Γ૿͑ͯॆ࣮͠ɺηϯαͷଌఆɺΞΫνϡΤʔλʢϞʔλʣͷར༻ɺ૒ํ޲௨৴ͱ͍ͬͨࢦ਑͕ࣔ͞ Ε͍ͯΔɻͦͷޙ࣍ୈʹ໌Β͔ʹͳ͍ͬͯ͘ཁૉͱͯ͠ɺ೔ຊޠϓϩάϥϛϯάݴޠΛ͔ͭͬͨղઆ Ͱʮ৘ใҊ಺ʯͱʮνϟοτιϑτʯΛ࡞Δͱ͍͏ͷ͕ڭՊॻʹࡌͬͨɻ طଘͷख๏ ˙ϏδϡΞϧϓϩάϥϛϯά ւ֎༗໊ιϑτ΢ΣΞͷʮScratchʯ *1ͳͲΛ࢖ͬͨʮϏδϡΞϧϓϩ άϥϛϯάʯͰ͸֓೦ֶ͕शͰ͖ήʔϜͳͲͷ࡞඼͕࡞ΕΔɻੈքతʹখֶߍఔ౓ͷϓϩάϥϛϯά ֶशखஈͱͯ͠ελϯμʔτͱݴ͑ΔɻϞʔλ΍ηϯαͳͲͱ૊Έ߹ΘͤͨΩοτ͕ڭࡐձ͔ࣾΒ΋ ൢച͞Ε͓ͯΓ Scratch ͸؆୯ͳػց੍ޚʹ΋༻͍ΒΕ͍ͯΔɻϩϘοτ؝۩ʹ͓͚Δʮϓϩάϥ ϛϯάʯͷπʔϧͱͯ͠ఏڙ͞Ε͍ͯΔ͜ͱ΋͋Δɻ·ͨผͷ΋ͷͱͯ͠͸ɺՈఉ༻ήʔϜػͰ΋ஈ Ϙʔϧ޻࡞ͱ߹ΘͤͨΩοτʹ͓͍ͯಠࣗͷϏδϡΞϧϓϩάϥϛϯά͕Ͱ͖ɺίϯτϩʔϥೖྗ΍ ޫηϯαΛ࢖ͬͨ࡞඼͕࡞Εͨɻ ʮϚΠϯΫϥϑτʯ *2Ͱ͸ɺಛఆͷΤσΟγϣϯʢʙ൛ʣʹ͓͍ͯ֎ ෦ػೳΛ࢖͏͜ͱͰຊ֨తͳϓϩάϥϛϯά΍ϏδϡΞϧϓϩάϥϛϯά͕Ͱ͖Δ΋ͷ͕͋Δɻͨͩ ϏδϡΞϧπʔϧશମͰݴ͑Δ໰୊ʹɺҰఆن໛Ҏ্ͷ࡞඼ʹͳΔͱঢ়ଶ΍શମ͕ݟͮΒ͘ͳΓ࡞੒ ೉қ౓্͕͕Γෆศ͕͞૿͢ɻ *1 Scratch https://scratch.mit.edu/ *2 Minecraft https://www.minecraft.net/ 43
  43. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ ˙Ξϯϓϥάυϓϩάϥϛϯάֶश ICT ػثΛҰ੾࢖ΘͣʹϓϩάϥϛϯάతࢥߟΛֶͿखஈɻ ࣄྫͷଟ͘Ͱ͸ΧʔυΛ࢖ͬͯॲཧͷॱং΍಺༰Λߟ͑Δ͜ͱͰ࿦ཧతࢥߟྗ΍ϓϩάϥϛϯάతͳ

    ࢥߟ΁ͷֶͼ΁ͱ݁ͼ෇͚͍ͯΔɻֶशͰ͖Δ෯΍ਂ͞͸ϓϩάϥϛϯάΛ࣮ࡍʹڭ͑ͨ࣌΄Ͳʹ͸ ࣋ͨͤͮΒ͘ɺػࡐ͕͋Γ࢖͑ΔͷͰ͋Ε͹࢖ͬͨํ͕ྑ͍Մೳੑ͕ߴ͍ɻ ˙ϓϩάϥϛϯάֶशతήʔϜ ίϯγϡʔϚػ΍εϚʔτϑΥϯΞϓϦͳͲͰήʔϜͱͯ͠ϓϩά ϥϛϯάΛϞνʔϑʹͨ͠΋ͷ͕͍͔ͭ͋͘ΓɺήʔϜ಺ͷߦಈͱͯ͠ϓϩάϥϛϯάతͳೖྗ΍ࢥ ߟΛͤ͞Δ΋ͷ͕͋ΔɻϓϨΠϠʔ͕ʮਓʯΛϓϩάϥϛϯάͯ͠࢓ࣄͷޮ཰Λ্͛Δ͜ͱΛߟ͑Δ ͱ͍͏΋ͷ͕Ұ෦Ͱྲྀߦͨ͠ɻ ʮϚΠϯΫϥϑτʯͰ͸ίϚϯυͱݴΘΕΔΩʔೖྗ΍ͦΕΛ֨ೲ͠ ໋ͨྩϒϩοΫΛ૊Έ߹ΘͤͨҰ࿈ͷ࢓ֻ͚ΛϓϩάϥϛϯάͰ͖Δɻ͜ΕΒ͸ମݧΠϕϯτͱͯ͠ ར༻͞ΕΔ͜ͱ͕ଟ͍͕ɺͦͷޙͷ৘ใͰʮϚΠϯΫϥϑτʯʹ͓͍ͯ͸෇Ճཁૉ΋͋ͬͯतۀͰͷ ࣄྫ΋͋Δɻ ˙ςΩετϓϩάϥϛϯά Web αΠτ্ͳͲͰ JavaScript ౳ͷεΫϦϓτݴޠΛจࣈೖྗͯ͠ νϡʔτϦΞϧతʹ՝୊Λղ͍͍ͯ͘λΠϓͷֶशڭࡐ͕͋Δɻ೉қ౓ʹ΋෯͕͋ΓࢠͲ΋޲͚ͷ ήʔϜ෩ͳ΋ͷ͔Βࣾձਓ޲͚৬ۀ܇࿅޲͚ͷ༗ྉڭࡐ·Ͱ͍͔ͭ͋͘Δɻ͜ͷπʔϧࣗମ͕νϡʔ τϦΞϧҎ֎ͷԿ͔ʹͳ͍ͬͯΔέʔϧ͸͋·Γͳ͍ɻ͋Δ͍͸ Scratch ϕʔεͷػث੍ޚιϑτ ΢ΣΞʹ͓͍ͯ JavaScript ΍ Python ΁ग़ྗม׵Ͱ͖Δ৔߹͕͋ΓɺεΫϦϓτΛॻ͍ͯ௚઀੍ޚ Ͱ͖Δͱݴ͑Δ͕ػثͱηοτߪೖͷ΋ͷʹͳΔɻ ˙ʴЋʹΧϦΩϡϥϜͱࢦಋٕज़ ڭࡐͱֶशΧϦΩϡϥϜͱशख़ͨ͠ࢦಋऀ͕͍ͳ͚Ε͹ͳΒͳ ͍ɻ͍ͭ͘΋ͷطଘڭࡐιϑτ΢ΣΞʹ͸ֶशΧϦΩϡϥϜ͕େྔʹ༻ҙ͞Ε͓ͯΓɺࣄۀऀ͸ͦΕ Λ೥ֹྉۚΛઃఆͯ͠ఏڙ͍ͯ͠Δɻ͋Δ͍͸ઌߦاۀ͸࣏ࣗମͷڠྗͷ΋ͱ੍࡞ͨ͠ΧϦΩϡϥϜ ͕͋Γઐ༻ιϑτ΢ΣΞͱͱ΋ʹ࣮ࢪͰ͖Δ΋ͷ΋͋Δɻ b. ໰୊ൃݟ ʢ৘ใऩू·ͱΊʣ • ະࢀೖͰ͸ख͕ग़͕͍ͨ͠͏͑੒ཱͤ͞ΔͨΊʹ͸ڑ཭ײ͕͔ͳΓ͋Δ • খֶੜ΁ͷࢦಋ͕Ͳ͏͍͏΋ͷ͔ͱ͍͏஌ݟ͕ͳ͍͜ͱʹࣗ෼ͨͪͷ೉͠͞΋͋Δ • খֶੜ޲͚ϏδϡΞϧϓϩάϥϛϯάͱ࣮༻ϓϩάϥϛϯάͱʹဃ཭͕͋Δ • तۀͷࢦ਑͔ΒʮϓϩάϥϛϯάతࢥߟʯΛ࢖ͬͨԠ༻͕ٻΊΒΕ͓ͯΓط੡඼͔ͦΕʹมΘ ΔϓϩμΫτʢֶशͰ͖൓Ԡ͕͋Δ΋ͷʣ͕ඞཁ • ط੡඼Ͱ͸ݻ༗ͷ੍ݶʹΑͬͯ੡඼ʹର͢ΔϓϩάϥϛϯάҎ֎ͷ܇࿅͕ඞཁʹͳΓʮϓϩά ϥϛϯάֶशʯͷൣғΛ௒͑ͳ͚Ε͹ͳΒͳ͍ 44
  44. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ c. Ծઆઃఆ ৘ใऩू͠ݱࡏͷ໰୊͕ݟ͑ͯ͘Δͱ൒͹ࣗવͱԾઆཱ͕ͬͯ͘ΔɻԾઆͱ͸ɺཪ෇͚͸·ͩͳ͍ ͕໰୊ͷঢ়گʹࢸΒ͠ΊΔཁૉΛநग़ͨ͠ΓղܾҊΛڍ͛ΔखॱΛࢦ͢ɻࠓճͷέʔεͰ͸ɺͲ͏ࢧ

    ԉΛܭըͯ͠ఏࣔ͢Ε͹ґཔऀͱ͕ࣗࣾ Win-Win Ͱ͋Δ͔Λ໛ࡧ͢Δ͜ͱʹ͋ΔɻԾઆઃఆʹ͸ɺ ͍͔ͭ͘ͷํ޲ੑͰྻڍ͍͖ͯ͠࿙Ε͕ͳ͍Α͏ʹݕ౼ͯ͠΋Α͍͕ɺ͜͜Ͱ͸ʮϩδοΫπϦʔʯ Λҙࣝͯ͠Ͳ͏͋Δ΂͖͔Λಋ͖ग़ͨ͠ɻ্͔Βॱʹ͓͓Αͦର࿩ܗࣜʹͳ͍ͬͯΔɻ ࢧԉ͢΂͖ࢪࡦͷԾઆ • ࣗ෼͕ͨͪͰ͖Δ͜ͱΛͨ͠ํ͕Α͍ͷͰ͸ • ڭһ͕ڭ͑ʹ͍͘೉қ౓ͷ΋ͷΛѻ͍ڭ͑ͨํ͕ت͹ΕΔͷͰ͸ • ط੡඼ͷࢦಋ͸ͦΕ͕Ͱ͖Δͱ͜Ζ͕͢ΔͷͰฐࣾͰ͸ෆཁͳͷͰ͸ • ΤϯδχΞͷܦݧଇతʹ͸ʮςΩετϓϩάϥϛϯάʯ͠ͳ͍ͱࣗ༝ʹͳΕͳ͍ͷͰ͸ • Ͱ͖Δ্͚ͩͷֶ೥Ͱ͋Ε͹ςΩετϓϩάϥϛϯάͰ͖ΔͷͰ͸ •ʮதֶੜʯʹςΩετϓϩάϥϛϯάΛڭ͑Ε͹Α͍ͷͰ͸ • ຊۀʹݶΓͳ͍ۙ͘ͷͰशಘίετͳ͘ࢦಋͰ͖ίϯςϯπఏڙͰ͖ΔՄೳੑ͕ߴ͍ͷͰ͸ ର৅ऀΛதֶੜʹͯ͠΋Α͍ͷͰ͸ ౰ॳզʑʹࣔ͞Εݟ͍͑ͯͨظ଴ͱձٞମͷۭؾײͱͯ͠͸׬શʹখֶੜࢧԉͩͬͨɻͨͩখֶੜ ʹରͯ͠ࢧԉΛ͢Δاۀ͕΄͔ʹ΋͍ͨ͜ͱ͔Βɺ୭΋खΛग़͞ͳ͍தֶੜʹ͢Δ͜ͱΛґཔऀʹ࢕ ͏ͱର৅ʹೖ͍ͬͯΔͷͰ OK ͕ͰͨɻݟํʹΑͬͯ͸ɺओྲྀ͔Β֎Εͯ཭୤ͨ͠ͱͱΒΕ͔Ͷͳ ͍ɻґཔऀͱฐࣾҎ֎ɺͦΕ͸ͳ͍ͱ͍͏ۭؾͩͱײ͍͕ͯͨ͡ڧ͍৴೦ͰਐΉɻ ͜ͷ࣌఺Ͱࣗࣾͷݟղͷશମ૾͕ݟ͖͑ͯͨͨΊɺࢹ఺Λʮࣗ૊৫ʯͱ͢Δʮ5W1HʯͰ੔ཧ͢Δɻ ࣗ૊৫ʹͱͬͯ • ԿΛ͢Δ͜ͱͳͷ͔ what – ґཔऀͷ๬ΉࢧԉΛ࣮ࢪ͢Δ – ֶशιϑτ΢ΣΞ։ൃ·ͨ͸ΧϦΩϡϥϜߏங – ߨࢣͱॿखͷख഑ͱ܇࿅ • ୭͕΍Δͷ͔ who – ༧ࢉ͔͚ͳ͍ൣғͱͯ͠ࢲࣗ਎ 45
  45. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ • ͍ͭͷ͜ͱͳͷ͔ when –

    தֶߍ͕ϓϩάϥϛϯάΛ࣮ࢪ͢Δ 2021 ೥౓·Ͱ • ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where – தֶߍͷओʹٕज़Պ • ͳͥ΍Δͷ͔ why – IT اۀͱͯ͠஌ݟΛࢠͲ΋ͨͪͷֶशʹؐݩֶ͠ߍ͚ͩͰ͸Ͱ͖ͳ͍ઐ໳஌ࣝΛఏڙ͢ Δ͜ͱͰ஍Ҭؐݩ͢Δ • Ͳ͏΍Δ͔ how – ςΩετϓϩάϥϛϯάͷֶशΛԿΒ͔ͷίϯςϯπΛىͯ͜͠ఏڙ͢Δ – ֶशίϯςϯπ͸͍Ζ͍Ζͳͱ͜ΖͰ࢖͑ͦ͏ͳࣗࣾఏڙڭࡐͱ͍͏͜ͱͰݕ౼ • ࣗ෼ୡ͸Կ͔Ͱ͖Δͷ͔ can – ιϑτ΢ΣΞ։ൃ΍αʔϏε։ൃͱϓϩάϥϛϯάͰ͋Δ – தֶɺߴߍʹ޲͚ͯʮاۀ๚໰ड͚ೖΕʯͱ͍͏ֶߍ͔Βاۀ΁ͷ๚໰Λड͚Δίϯςϯ πΛ࣮ࢪ͍ͯ͠ΔͨΊਓ෺૾͕ΠϝʔδͰ͖Δ • ࣗ෼ୡ͸ԿΛ͢΂͖Ͱɺ͢΂͖Ͱͳ͍͔ should – ϓϩάϥϛϯά͸͢΂͖͕ͩط੡඼ͷࢦಋ͸͓ͦΒ͘͢΂͖Ͱ͸ͳ͍ • ͲΜͳ఍߅ͱো֐͕͋Δͷ͔ resist – தֶߍʹϓϩάϥϛϯάֶशͷࢧԉ͕ෆཁ͔΋͠Εͳ͍ – ίϯςϯπ͕੒ཱ͠ͳ͍͔΋͠Εͳ͍ – ੜెֶ͕शΛड͚ೖΕͳ͍͔΋͠Εͳ͍ d. ݕূ Πϕϯτ։࠵ཁ๬͕͋Γίϯςϯπͷ্ཱͪ͛ͱ࣮ূࢼݧ·ͰਐΉʙ ґཔऀͷҙ޲ʹΑͬͯɺऔΓ૊Έશମͱ͍ͯͣ͠Ε͔Λֶߍʹ͍࣋ͬͯ͘લʹ·ͣ͸اۀओ࠵ͷֶ शΠϕϯτͰͷΞϐʔϧͱ࣮੷ͮ͘ΓΛ͢Δ͜ͱʹͳΔɻΠϕϯτͰର৅ऀ΍ֶश಺༰ʹؔͯ͠σʔ λ͕औΕΔɻલ߲Ͱڍ͛ͨԾઆΛ۩ମతʹͯ͠ݕূ͢Δઈ޷ͷػձͷͨΊͲΜͳܗͰ͋Ε 21 ೥౓ʢ2 ೥ޙʣ࣮ࢪͷίϯςϯπҊΛࡦఆͯ͠ࢼݧʹྟΉɻ͜ͷͱ͖ 2019 ೥౓ 5 ݄ͰՆͷΠϕϯτ։࠵·Ͱ ࢒Γ 3 ϱ݄͕ͩͬͨ 20 ೥౓ʹऔΓ૊ΉΞΫγϣϯͷํ޲ੑʹӨڹ͢Δͱߟ͑ΒΕͨɻڠྗऀΛ૿΍ ͭͭ͠ΠϕϯτࢀՃऀʹ޲͚ͨ։࠵֓ཁ΍໨తͱ͍ͬͨاը΋ࣗΒܝ͛ͳ͚Ε͹ͳΒͳ͍ɻσόΠ εʹ͍ͭͯɺ͜ͷ࣌఺Ͱͷ૝ఆσόΠεΛ Android λϒϨοτͱઃఆͨͨ͠Ί͢΂ͯͷૢ࡞͸λο νը໘ೖྗ΍όʔνϟϧΩʔϘʔυʹݶఆ͠ɺNexus5 λϒϨοτΛ 30 ୆आΓ͖ͯͯ։࠵ʹྟΜͩɻ 46
  46. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ ˞ͷͪʹ۠ͷ PC ͱͯ͠ Windows

    λϒϨοτܕ͕ࢧڅ͞Ε͍ͯΔ͜ͱ͔Βޙऀ͕λʔήοτ୺຤ʹ ͳΔ ୲౰ऀϨϕϧͷঢ়گͱ໨ඪ͕ݟ͖͑ͨͨΊɺࢹ఺Λʮࣗ෼ࣗ਎ʯͱ͢Δʮ5W1HʯͰ੔ཧ͢Δɻ ࣗ෼ࣗ਎ʹͱͬͯ • ԿΛ͢Δ͜ͱͳͷ͔ what – ֶߍͰ࣮ࢪֶ͍ͨ͠शࢧԉͷ࠷খ੡඼ߏ੒ʢMVPʣͱΧϦΩϡϥϜҊΛ࡞੒͢Δ – ґཔऀ͕๬ΉֶशΠϕϯτΛ։࠵͠ࢧԉͷ࣮ݱࣗମΛ͢Δ • ୭͕΍Δͷ͔ who – ΋ͪΖΜࣗ෼ࣗ਎ • ͍ͭͷ͜ͱͳͷ͔ when – 2019 ೥౓Նʢ3 ϱ݄ޙʣͷΠϕϯτ·Ͱʹୡ੒͢Δ • ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where – ΠϕϯτԠื͖ͯͨ͠தֶੜ • ͳͥ΍Δͷ͔ why – 20 ೥౓ʢ࣍೥౓ʣ ɺ21 ೥౓ʢ࣍ʑ೥౓ʣʹֶߍ΁ΦϑΝʔ͢ΔͨΊͷσʔλऔಘͱલྫͮ ͘ΓͷͨΊ • Ͳ͏΍Δ͔ how –ʢ࠷ऴతʹʣήʔϜ੍࡞తεΫϦϓτͷԠ༻ͱήʔϛϑΟέʔγϣϯʢ՝୊ͷήʔϜԽʣʹ ΑΔֶशίϯςϯπΛఏڙ – ٕज़తʹʮήʔϜ੍࡞తεΫϦϓτʢΠϕϯτεΫϦϓτͱͯ͠ར༻͞Ε͍ͯΔݴޠʣ ʯ͕ ഑෍෺ͷϥϯλΠϜͰར༻Ͱ͖Δ͔ͷݕূ͕ඞཁ • ࣗ෼ୡ͸Կ͔Ͱ͖Δͷ͔ can –ʢࢲ͸ʣήʔϜ͕ओ࣠ͷιϑτ΢ΣΞͷఏڙͱςΩετϓϩάϥϛϯάͷࢦಋ – ࣍೥౓Ҏ߱Ͳ͏͍͏ల։ʹ͢Δ͔Λݟग़ࣔͤ͠Δਓؒ͸ࣗ෼͔͍͠ͳ͍ʢ։ൃͱࢦಋ͸ࢲ ҰਓͳͷͰʣ • ࣗ෼ୡ͸ԿΛ͢΂͖Ͱɺ͢΂͖Ͱͳ͍͔ should – Α͍ػձΛಀͣ͞ΠϕϯτͰԾઆݕূʹد༩͢ΔσʔλΛͱΔʢ΂͖ʣ – ४උظ͕ؒগͳ͍͔ΒͱػձΛಀ͢΂͖Ͱͳ͍ • ͲΜͳ఍߅ͱো֐͕͋Δͷ͔ resist – ίϯςϯπ੍࡞͕ૂ͍௨Γண஍Ͱ͖ͳ͍͔΋͠Εͳ͍ – ιϑτ΢ΣΞ΍Πϕϯτࣗମ͕ظ଴௨Γ࣮ࢪͰ͖ͳ͍͔΋͠Εͳ͍ – ݕূ݁Ռͷσʔλ͕ෆຬΛ͔ࣔ͢΋͠Εͳ͍ ݕূ݁Ռ ४උʹ͓͍ͯ։ൃ 2 ϱ݄ͱςετ͓Αͼௐ੔ 1 ϱ݄Λඅ΍͠ιϑτ΢ΣΞ͸ແࣄ։ൃʹ੒ޭͨ͠ɻ ΠϕϯτࢀՃऀืूͷ࣌఺Ͱ಺༰ͷܝ͕ࣔඞཁͩͬͨͨΊهࡌ͢Δ಺༰Ͱ࣮֬ʹΰʔϧͰ͖Δͱ֬ఆ 47
  47. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.4 ໰୊ͷ෼ղ Ͱ͖Δ·Ͱʹר͖ʹר͍ͯςετΛॏͶͨɻΠϕϯτʹ͸ 25 ਓ΄Ͳͷࣾһ͔Βڠྗ͕ಘΒΕɺखް ͘੝େʹ։࠵Ͱ͖ɺ҆৺ͯ͠ΠϕϯτӡӦΛҕͶΔ͜ͱ͕Ͱ͖ͨɻऔಘσʔλͱͯ͠͸ɺதֶੜ͕ς

    Ωετϓϩάϥϛϯά͕͋Δఔ౓·Ͱ࣮ફͰ͖ͨ੒Ռɺͭ·͖ͣ΍͍͢ՕॴɺΞϯέʔτʹΑΔ൓ڹ ΛಘΔ͜ͱ͕Ͱ͖ͨɻͦΕ͔Β͍ͨ΁Μҙຯਂ͍͜ͱͱͯ͠ɺϓϩάϥϛϯάʹڵຯ͕͋Δ͕औΓ૊ ΜͰ͍ͳ͍ະܦݧऀͷϖϧιφʢސ٬Ϟσϧɺ૝ఆଐੑͷਓ෺૾ͷҙຯʣ͕֫ಘͰ͖ͨ͜ͱ͕ڍ͛Β ΕΔɻσʔλͱϖϧιφʹؔͯ͠͸ɺฐࣾ͸શࠃ͔Βདྷࣾ͢Δʮֶߍ๚໰ड͚ೖΕʯΛߦ͍ͬͯͨ͜ ͱ͕޾͍͠ɺͦͷޙ΋΄΅ಉ৚݅ͷֶशΛ࣮ࢪͯ͠ܧଓతʹ൓ԠΛݟͯ͸ௐ੔͕ܧଓͰ͖ͨɻͬ͘͟ ΓԆ΂ 100 ਓҎ্ࢼߦͰ͖ͨɻ ਤ: αϚʔΩϟϯϓ 2019 ਤ: اۀ๚໰ϓϩάϥϜ 48
  48. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.5 ໨ඪઃఆͱߦಈࢦ਑ 5.5 ໨ඪઃఆͱߦಈࢦ਑ a. Πϕϯτޙͷܦա

    ΠϕϯτΛ࣮ࢪͨ͜͠ͱͰۮવ͕Ұͭൃੜͨ͠ɻెาݍʹ͋Δۙྡͷެཱதֶߍͷੜె͕ਃ͠ࠐΜ Ͱ͘Εͨ͜ͱ͔ΒىҼ͢Δɻ൴͸ϓϩάϥϛϯάͱΠϕϯτࢀՃʹର͍ͯͨ͠΁Μ೤ҙͱر๬Λ࣋ͬ ͍ͯΔֶੜ͕ͩࣄ৘ʹΑΓࢭΉʹࢭ·Εͣܽ੮ͱͳͬͯ͠·ͬͨͱ͍͏ɻ͔͠͠൴͸Ѫ͢΂͖ਓ෺ ͩͬͨɻչ΍·ΕΔࣄଶʹΑΓ౰࣌ͷڭ৬һ͕୅ΘΓʹݟֶʹདྷࣾ͠ɺςΩετڭࡐΛ࣋ͪؼͬͯษ ڧͤͯ͞΋Α͍͔ͱΘ͟Θ֬͟ೝΛٻΊ͖ͯͨͷͰ͋Δɻ΋ͪΖΜঝ୚ͨ͠͏͑Ͱɺઌੜ͸͞Βʹ 90 ෼ͷϫʔΫγϣοϓΛ͢΂ͯݟֶͯ͠ؼΒΕͨɻͦͷޙ೔ʹઌੜํͱݱঢ়ͷ͓࿩͠Λฉ͍͍ͯ͘ ͱɺϓϩάϥϛϯάֶश΍ ICT ׆༻ʢ৘ใ୺຤׆༻ʣʹ͸ࢦಋऀ΍ίϯςϯπͷ՝୊͕͋Γɺͦ͠ ͯੜెʹԿ͕࠷ద͔ͷ໨ॲཱ͕͍ͬͯͳ͍ঢ়گͰ໛ࡧ͍ͯ͠Δঢ়گ͕͏͔͕͍஌Εͨɻͦ͜Ͱಉߍ΁ ͷϓϩάϥϛϯάֶशࢧԉͱͯ͠ɺ͜ͷϫʔΫγϣοϓΠϕϯτΛϞσϧͱͨ͠ෳ਺ճֶशߨ࠲ͷ࣮ ݱΛ໨ࢦͯ͠ɺऔΓ૊ΈΛ۩ମԽ͍ͯ͘͜͠ͱʹ྆ऀ߹ҙͨ͠ɻ ల։ͱͯ͠͸ґཔऀ͕ೋऀʹͳΔ͕ɺैདྷͷґཔऀͱͯ͠౰ॳΑΓ಺แ͍ͯͨ͠ͱݴͬͯᴥᴪ͸ͳ ͘ɺ͋Δ͍͸ґཔऀͷޙΖଆʹҐஔ͢Δɻͭ·Γ૬खଆʹ͓͚Δʮࣗ૊৫ʯͱʮࣗ෼ࣗ਎ʯͷؔ܎ʹ ͋ͨΓɺґཔऀͰ͋Δ۠ͱֶߍ͸ʮ౷ׅ૊৫ʯͱʮ૊৫ʯͷؔ܎ʹ͋ͨΔɻΑΓ۩ମతͳ໰୊΁ͷऔ Γ૊ΈͱղܾΛҎͯ׆ಈͱ੒ՌΛࣔ͢΄͏͕ΑΓ༗ҙٛͰ͋Δͱߟ͑ɺैདྷͷґཔऀʢґཔऀᶃʣͷ ҙࢥͷ΋ͱ۩ମతͳࢪࡦ࣮ࢪઌͱͳΔֶߍʢґཔऀᶄʣ΁ͷɺݸผͷ໰୊ࣄྫΛղܾ͢ΔऔΓ૊Έʹ ࢹ఺Λམͱͨ͠ɻ b. ࣋ଓతʹୡ੒͢Δߦಈࢦ਑ʹམͱ͠ࠐΉ ґཔऀͷ໰୊͸ϫϯΞΫγϣϯ΋͘͠͸ 1 ϓϩμΫτͰ͢΂ͯ͸ղফ͠ͳ͍ɻϓϩδΣΫτ͕։࢝ ͞ΕΔͱࣗ෼ͷ໨ඪ΍ࠓͷ՝୊͚ͩߟ͑ͯಥ͖ਐΜͰ͠·͍ɺ্௕΍૊৫ͷ໨ඪͱͦΕͯ͠·͏͜ͱ ͕ଟ͍ɻ ͜͜·Ͱݟ͖ͯͨࡾऀͷʮ5W1Hʯ͸੾ΓޱΛม͑͞ΒʹผͷݟํΛͯ͠ݕ౼ΛਂΊΔɻࠓճͷ έʔεʹ͓͚Δґཔऀͷ໰୊ͱ͸ɺओޠ͸େ͖ͳ͘͘Γͷਓͷू·ΓͰ͋Γɺશମ΁ͷ࣋ଓత͔ͭॊ ೈͳࢧԉΛඞཁͱ͢Δ΋ͷͰ͋Δɻ͜ͷΑ͏ʹ࣌ؒ࣠ͷ௕͍՝୊ʹରͯ͠औΓ૊Ήͱ͖ʹ͸্ԼϨΠ Ϡͷࢹ࠲Λߦ͖͠ɺ࣋ଓతʹୡ੒͠ଓ͚Δʮߦಈࢦ਑ʯͱݸผͷʮ໨ඪઃఆʯΛͦͷ౎౓֬ೝͯ͠औ Γ૊Ήɻ ܧଓͯ͠໰୊ʹऔΓ૊ΉதͰऴ࢝໨తΛݟࣦΘͣʹ໨తΛ਱ߦ͢ΔͨΊʹ࣍ͷϑϨʔϜϫʔΫΛղ આ͍ͨ͠ɻ 49
  49. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.5 ໨ඪઃఆͱߦಈࢦ਑ c. ߦಈࢦ਑ͱ໨ඪઃఆʹʮOKRʯ ໨ඪઃఆʹ͍ͭͯ͸ Google

    ࣾͳͲͰ΋ಋೖ͞Εͨ OKR ͱ͍͏ϑϨʔϜϫʔΫ͕͋Δɻղઆ͢Δ ͱɺObjectives and Key Results ɹͷུͰɺ໨ඪʢObjectivesʣ ɺओཁࢦ਑ʢKey Resultsʣͷҙຯ͕ ͋ΔɻO ͱ KR ͷ 2 ఺Λɺ૊৫શମͰɺϓϩδΣΫτ୯ҐͰɺ୲౰ऀͰɺͱ෼ղͯ͠۩ମతʹ͍ͯ͠ ͘ɻ֤ϨΠϠͰܭଌՄೳͳ໨ඪͱͯ͠۩ମతʹऔΓ૊Ίͯ࠷ऴ໨ඪ͕ୡ੒Ͱ͖Δͱ͢Δ΋ͷɻ͜ͷ໨ ඪͷԠ༻͸ɺ૊৫΍্௕͔ΒԼͣ͞ͱ΋ࣗ෼Ͱࢹ࠲Λมཻ͑౓Λ্͛Լ͛ͯ͠໨ඪઃఆ͢ΔͱશମΛ ၆ᛌ͠ͳ͕Β۩ମతʹऔΓ૊ΊΔɻྨࣅͷϑϨʔϜϫʔΫʹ͸ʮSMARTʯ΍ʮMBOʯͱ͍ͬͨख ๏͕͋Δ͕ɺ͍ͣΕͷ৔߹Ͱ΋্Ґ໨ඪ͔ΒԼҐ໨ඪ΁ͷΑ͏ͳ۩ମԽ΍ KPIʢධՁࢦඪʣ͕ॏཁͱ ͞Ε͍ͯΔɻ ͜Ε·Ͱड़΂͖ͯͨʮ5W1HʯͷϦετ͸໨ඪʹݴ͍׵͑ͯू໿͢ΔͱԼهͷΑ͏ʹͱ·ͱΊΔ͜ ͱ͕Ͱ͖Δɻ Πϕϯτ·Ͱͷ OKR • ґཔऀʹͱͬͯ –ʢͲ͜Ͱʣ۠಺ͷٛ຿ڭҭɺ20 ೥౓খֶੜͳͲ΁ –ʢ͍ͭʣͦͷ࣌఺ͷ࣍೥౓ɻ20 ೥౓͔Βͷॱ࣍ඞमԽʹ޲͚ʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣֶशࢦಋཁྖʹ४ڌ͢Δ࣮ࢪϝχϡʔͷఏࣔΛͯ͠ –ʢͳʹΛʣٛ຿ڭҭ΁ͷϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔ໨ඪʣ • ࣗ૊৫ʹͱͬͯ –ʢͲ͜Ͱʣதֶߍͷओʹٕज़Պ –ʢ͍ͭʣதֶߍ͕ϓϩάϥϛϯάΛ࣮ࢪ͢Δ 2021 ೥౓·Ͱʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣຊདྷͷҙຯͷϓϩάϥϛϯάΛࢦಋ͠ –ʢͳʹΛʣґཔऀͷ๬ΉࢧԉΛ࣮ࢪ͢Δʢ਺ྔʹఆྔ໨ඪʣ • ࣗ෼ࣗ਎ʹͱͬͯ –ʢͲ͜ͰʣΠϕϯτԠื͖ͯͨ͠தֶੜ –ʢ͍ͭʣ3 ϱ݄ޙͷΠϕϯτ·Ͱʹʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣΑ͍ػձΛಀͣ͞ɺΠϕϯτͰԾઆݕূʹد༩͢ΔσʔλΛͱΓ –ʢͳʹΛʣֶߍͰ࣮ࢪֶ͍ͨ͠शࢧԉͷ࠷খ੡඼ߏ੒ʢMVPʣͱΧϦΩϡϥϜҊΛ࡞੒͠ ֶशΠϕϯτͰσʔλΛͱΔʢఆྔ໨ඪʣ ͜ͷΑ͏ʹ্ԼϨΠϠͲ͏͠Ͱͭͳ͕Γͷ͋Δےͷ௨ͬͨ໨ඪͱͳ͍ͬͯΔ͜ͱ͕ಡΈऔΓ΍͢ ͍ɻ ʮ5W1HʯʴЋͰॻ͖ى߲ͨ͜͠໨Ͱ͋Δ͜ͱΛ׆͔ͯ͠ whereɾwhenɾshouldɾwhat Λ࢒͠ ͓͍ͯͨɻͳ͓ࢹ఺͝ͱʹݟΔ࣌ؒ࣠ʹҧ͍͕͋Γʮࣗ෼ࣗ਎ʯͰ͸Πϕϯτ·Ͱ͕ 1 αΠΫϧͱͳ Γɺ౸ୡ஍఺͸࠷ऴཁ݅ୡ੒ʹ·͍͍ͩͨͬͯͳ͍ɻͦͷϑΣʔζ͝ͱʹ࣮ݱ͢Δ͜ͱΛݟग़্͠ͷ ͭͳ͕ΓΛอ͍ͬͯΔ͜ͱΛҙࣝ͠ͳ͕Βߦಈ͢Δɻ ʮࣗ෼ࣗ਎ʯʹ͓͚Δ୲౰Ϩϕϧͷ໨ඪ͕ 1 ͭ ୡ੒͞Εͨޙ͸Ұ্ͭͷϨΠϠ͕ࣔ͢ࢦ਑ͷதʹ͋Δ࣍ͳΔߦಈΛʮࣗ෼ࣗ਎ʯʹ՝͢ɻ 50
  50. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.5 ໨ඪઃఆͱߦಈࢦ਑ Πϕϯτ͔Β೥౓຤·Ͱͷ OKR • ґཔऀᶄʹͱͬͯ

    –ʢͲ͜Ͱʣࣗߍ 1ʙ2 ೥ੜ΁ –ʢ͍ͭʣ࣮ݱͰ͖͏Δ࣌ظʹʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣ·ͣ͸์՝ޙֶश΍Ϋϥϒ׆ಈͳͲͷ೚ҙࢀՃͰ –ʢͳʹΛʣΠϕϯτͰࣔ͞ΕͨΑ͏ͳϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔ໨ඪʣ • ґཔऀᶃʹͱͬͯ – ˞ มΘΒͣ –ʢͲ͜Ͱʣ۠಺ͷٛ຿ڭҭɺ20 ೥౓খֶੜͳͲ΁ –ʢ͍ͭʣͦͷ࣌఺ͷ࣍೥౓ɻ20 ೥౓͔Βͷॱ࣍ඞमԽʹ޲͚ʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣֶशࢦಋཁྖʹ४ڌ͢Δ࣮ࢪϝχϡʔͷఏࣔΛͯ͠ –ʢͳʹΛʣٛ຿ڭҭ΁ͷϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔ໨ඪʣ • ࣗ૊৫ʹͱͬͯ – ˞ มΘΒͣ –ʢͲ͜Ͱʣதֶߍͷओʹٕज़Պ –ʢ͍ͭʣதֶߍ͕ϓϩάϥϛϯάΛ࣮ࢪ͢Δ 2021 ೥౓·Ͱʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣຊདྷͷҙຯͷϓϩάϥϛϯάΛࢦಋ͠ –ʢͳʹΛʣґཔऀͷ๬ΉࢧԉΛ࣮ࢪ͢Δʢ਺ྔʹఆྔ໨ඪʣ • ࣗ෼ࣗ਎ʹͱͬͯ –ʢͲ͜ͰʣΦϑΟγϟϧʹର৅ߍͷߍ಺Ͱ –ʢ͍ͭʣ೥౓಺ͭ·Γ 5 ϱ݄Ҏ಺ʹʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣΑ͍ػձΛಀͣ͞ɺԾઆݕূͱվળػձͱͯ͠ɺ͞Βʹࣄྫͮ͘Γͱͯ͠ –ʢͳʹΛʣֶߍͰ࣮ࢪ͢΂͖੡඼ߏ੒ͱΧϦΩϡϥϜΛߏ੒ֶ͠शࢧԉ͢Δʢఆྔ໨ඪʣ ޙऀͷϦετͰ͸ɺֶߍͰ͋Δʮґཔऀᶄʯ͸ࣗ෼ࣗ਎ͷରہͱͳΔΑ͏࠷্Ґʹܝࡌͨ͠ɻ͜Ε ʹΑͬͯؒͷϨΠϠ૊৫ΛͲͷΑ͏ʹҙࣝ͢Δͷ͔͕มΘΓɺ࠷ԼҐ໨ඪୡ੒Ͱ࠷্Ґ໨ඪ՝୊͕ղ ܾͰ͖Δ͔ΛٻΊ͍ͯΔɺͱࣔ͢͜ͱʹͳΔɻ d. ʮͲ͏΍ͬͯʯ෦෼ɺίϯςϯπͷߏஙʹ޲͚ͯ ͦΕͰ͸࣍અ͔Βɺίϯςϯπͷاը։ൃʹ໨Λ޲͚ͯղઆ͢ΔɻΠϕϯτͱͦͷޙʹ͓͍ͯͲͷ Α͏ͳઓུ΍ҙਤΛ΋ͬͯൃ૝ɾاը͍͔ͯͬͨ͠ʹ͍ͭͯղઆͦ͠ͷख๏Λ঺հ͍ͨ͠ɻ 51
  51. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.6 ίϯςϯπاըͱ͞·͟·ͳ෼ੳ 5.6 ίϯςϯπاըͱ͞·͟·ͳ෼ੳ ఏڙ͢ΔڭࡐͱΧϦΩϡϥϜʢҎԼίϯςϯπʣʹ͍ͭͯߟ͑Δɻ࣮ݱ͍ͨ͠ཁ݅͸ɺςΩετϓ ϩάϥϛϯάͰήʔϛϑΟέʔγϣϯͱֶशͰ͋ΔɻมԽٿΛ౤͍͛ͨ༁Ͱ͸ͳ͍͕ɺط੡඼ͱಉ͡

    ΋ͷΛ࡞ͬͯ΋·ͬͨ͘ҙຯ͕ͳ͍ɻط੡඼ͱಉ͡Α͏ͳͱ͜Ζֶ͕शͰ͖Δ΋ͷͩͱ͢Δͱɺٸ͝ ͠Β͑ͨͪ͜͠Βʹউͪ໨͕ͳ͍͏͑ɺΦϦδφϧΛར༻ͨ͠΄͏͕ϚγͱͳΔɻ·ͨڭҭۀքͰ ͸ɺڭࡐ։ൃձ͕ࣾઐ໳ੑΛ׆͔ͯ͠ൢച͍ͯ͠ΔΩοτ͕ͨ͘͞Μ͋Γɺ͢Ͱʹར༻͍ͯ͠Δ৔߹ ΋͋ΔɻίϯγϡʔϚʔʢফඅऀʣʹ޲͚ͯ͸ɺήʔϛϑΟέʔγϣϯΛ׆ָ͔ͯ͠͠Έͳ͕Βֶश Ͱ͖Δʢ·ͨ͸ֶशͱ͸ޛΒͤͳ͍ʣΞϓϦέʔγϣϯ΍੡඼͕ͨ͘͞Μ͋Δɻاըʹ͋ͨͬͯ͸ɺ औΓ૊Ή༨஍͕͋Δͷ͔Ͳ͏͔͔Βௐ΂Δඞཁ͕͋ΔͨΊɺࢢ৔΍ࣗ਎Λ͔ͬ͠ΓݟΔ͜ͱ͔Β࢝ ΊΔɻ a. STP ෼ੳʢࢢ৔λʔήοτϙδγϣϯʣ ৽نࣄۀΛల։͢Δ͏͑Ͱࢢ৔ʹ͓͚ΔཱͪҐஔΛ໌֬Խ͢ΔͨΊʹ༻͍ΔɺϑΟϦοϓɾίτ ϥʔͷఏএͨ͠ϑϨʔϜϫʔΫͰ͋ΔɻSegmentationʢࢢ৔ࡉ෼Խʣ - Targetingʢࢢ৔બ୒ʣ - PositioningʢཱͪҐஔʣɹͷ಄จࣈΛͱͬͯ STP ෼ੳͱ͍͏ɻ୭ʹΉ͚Δͷ͕ద੾͔ɺڝ߹ͱͷ੗ Έ෼͚͕Ͱ͖Δ͔ʹ͍ͭͯࢹ֮తʹ΋෼ੳͰ͖Δɻ ڝ߹ͱઃఆ͍͔ͨͭ͘͠ͷαʔϏε͓Αͼ੡඼Λ੡඼঺հΩϟονίϐʔΛݩʹର৅೥ྸΛ෼ྨ ͢Δɻ ڝ߹ ༮ࣇ খֶੜʢ௿ʣ খֶੜʢதʣ খֶੜʢߴʣ தֶੜ ߴߍੜ Ұൠ ੡඼ V ̋ ̋ - - - - - ੡඼ P - ̋ ̋ - - - - ੡඼ Q - ̋ ̋ ̋ - - - ੡඼ S - ̋ ̋ ̋ - - - ੡඼ H - ̋ ̋ ̋ ̋ ̋ ̋ ੡඼ N - - ̋ ̋ ̋ ̋ ̋ දͷ੡඼ྫͱͯ͠͸෼͔ΓͮΒ͍͕ɺ༗ྗͳ੡඼͕ौ଺͓ͯ͠Βͣಛ௃͕ଧͪग़͠΍͍͢ྖҬ͕ ʮதֶɾߴߍʯͱ͍͏λʔήοτԾઆ͕ݟ͑ͨɻಉ༷ͷηάϝϯτʹ͋Δ੡඼ Hɾ੡඼ N ͳͲͷڝ߹ ͱͷϙδγϣϯͰ͸ɺ ʢ౰ॳʣAndroid λϒϨοτΛத৺ʹ͢Δ͜ͱͰϓϥοτϑΥʔϜʹΑΔࠩผ ԽΛૂͬͨɻͦͷ΄ֶ͔शྖҬͷॅΈ෼͚ΛධՁ͠ͳ͕Βɺதֶֶशࢦಋཁྖ͕ࣔ͢ʮωοτϫʔ Ϋʯͷར༻Λߟྀ͢Δ෦෼͸ྫ͕গͳ͍ɻ·ͨςΩετϓϩάϥϛϯάͷڝ߹Ͱ͸શମతʹυϦϧܗ ͕ࣜଟ͍ͨΊɺ׆༻΍ࣗݾ࣮ݱʹͭͳ͛ΔֶशͳͲɺֶशࣗମͷػೳΑΓʮԠ༻ʯʹ΋ࠩผԽ͢Δϙ ΠϯτΛஔ͚Δɻ˞ϓϥοτϑΥʔϜʹ͍ͭͯ͸ผهͨ͠௨Γͦͷޙ Windows λϒϨοτ PC ΁ͷ ఏڙʹࢸΔ 52
  52. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.6 ίϯςϯπاըͱ͞·͟·ͳ෼ੳ b. VRIO ෼ੳʢڝ߹༏Ґੑʣ ܦӦࢿݯΛ

    4 ͭͷࢹ఺ͰධՁ͠෼ੳ͢ΔͨΊͷɺδΣΠɾBɾόʔχʔ͕ఏএͨ͠ϑϨʔϜϫʔ ΫͰ͋Δɻ4 ͭͷࢹ఺͸ɺValueʢܦࡁՁ஋ʣ- Rarityʢرগੑʣ- Inimitability ʢ໛฿ࠔ೉ੑʣ- Organizationʢ૊৫ʣ ɻ • ܦࡁՁ஋ɹ ... ސ٬΍ࣾձʹͱͬͯՁ஋͕͋Δ͔ • رɹগɹੑ ... رগੑ͕͋ͬͯಛ௃෇͚ΒΕΔ͔ • ໛฿ࠔ೉ੑ ... ྨࣅ඼͕؆୯ʹग़ճͬͯ͠·͏͔ • ૊ɹɹ৫ɹ ... ׆༻Ͱ͖Δ૊৫ʹͳ͍ͬͯΔ͔ ֶࣗࣾशίϯςϯπͷ VRIO ෼ੳ • ܦࡁՁ஋ – ؆୯ͰςΩετϓϩάϥϛϯάͰͪΐ͏ͲΑ͍΋ͷ͕গͳ͍தͰόϦΤʔγϣϯΛ࣋ͨͤ ֶͨͼ͕֫ಘͰ͖ΔͨΊࢦಋ΋ؚΉύοέʔδʹର͢ΔՁ஋ͱͯ͠ଧͪग़ͤΔ • رগੑ – ςΩετϓϩάϥϛϯάίϯςϯπɺήʔϛϑΟέʔγϣϯ՝୊ֶशɺςΩετϓϩάϥ ϛϯάͷࣗ༝౓͕࣋ͭόϥΤςΟɺࣾһ͕௚઀ࢦಋɺͷֻ͚ࢉʹرগੑ͕͋Δ • ໛฿ࠔ೉ੑ – ιϑτ΢ΣΞɾΧϦΩϡϥϜɾࢦಋɾԠ༻ͷཁૉ͕͋Γ࣮ݱίετ͕ൺֱతߴ͍ – ฐࣾͷεϚʔτϑΥϯΞϓϦʮϞϯελʔετϥΠΫʯʹొ৔͢ΔਓؾΩϟϥΫλʔʮΦ ϥΰϯʯ͕׆༻͞Ε͓ͯΓɺֶशʹର͢ΔোนΛݮΒ͠ಠࣗੑɾݸੑ͕ߴ·͍ͬͯΔ • ૊৫ – ͜ͷྖҬʹ͓͍͔ͯͳΓͷࡋྔΛ΋ͬͯ΄ͱΜͲࣗ༝ʹͤͯ͞΋Β͍͑ͯΔͨΊɺ࡞ͬͨ ίϯςϯπΛ׆༻͠ల։͢ΔͨΊʹ·ͨ׆ಈͦ͠ΕͧΕΛ݁ͼ෇͚Δ͜ͱ͕Ͱ͖Δɻ ʢࠓ ճͷࣥච΋ͦͷҰ؀Ͱ͋Δʣ ΑΓΑ͍෼ੳͱ݁ՌΛ׆͔͢૊৫ʹ VRIO ෼ੳΛཧղͨ͠͏͑ͰϓϩδΣΫτ਱ߦ͍ͯ͠ΔͷͰ͋Ε͹ɺͦͷϓϩμΫτʢ੡඼ͱαʔ ϏεΛؚΉʣ͕༗ҙٛͰ͋Δͷ͔ɺ͋Δ͍͸ΑΓྑ͘ΑΓ͍҆΋ͷ͕͢Ͱʹଘࡏͨ͠Γ͙͢ग़ճͬͯ ͠·͏ͷ͔ΛݟΔ͜ͱ͕Ͱ͖Δɻڝ߹༏Ґੑ΍ݸੑʢྑ͞ʣΛཧղͨ͠͏͑Ͱίϯςϯπ։ൃ͔Βఏ ࣔ·Ͱ͕ߦ͑ΔͷͰ͋Ε͹ɺ୯ʹ෺௝͍͔͠Βɺײ৘Ҡೖ͍ͯ͠Δ͔Βɺͱ͍ͬͨओ؍తͳηʔϧε ϙΠϯτʹྗΛೖΕͯޡͬͨૌٻΛͯ͠͠·͏Մೳੑ͕ݮΔͩΖ͏ɻ ݁࿦Λม͑ΒΕͳ͍૊৫͕෼ੳΛ͢Δ͜ͱҎ্ʹແՁ஋ͳ΋ͷ͸ͳ͍ɻաڈܦݧͨ͠ଟ͘ͷϓϩμ ΫτͰ͸ϏδωεϩδοΫ΍खஈͷબఆ͕ઌʹ͋ΓͦͷؒΛίϯςϯπاըͰຒΊ͍ͯΔɻVRIO ෼ ੳͷ؍఺΍ͦͷ΄͔ͷ༗ޮͳ෼ੳͰ༏Ґੑ΍Ձ஋͕ࣔͤͳ͍ͷͰ͋Ε͹ɺͰ͖Δ͚ͩૣ͍λΠϛϯά ͰͷʮϐϘοτʯΛɺͭ·Γย଍ΛͣΒ͢มֵ͕๬·ΕΔɻ 53
  53. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.7 ΞΠσΞͷൃ૝ͱࢥߟ 5.7 ΞΠσΞͷൃ૝ͱࢥߟ a. ϑϨʔϜϫʔΫʮϦʔϯΩϟϯόεʯͰߟ͑Δ

    ىۀɾࣄۀΞΠσΞΛՄࢹԽͯ͠ɺݕূ͠վળ͢Δ͏͑Ͱ໾ʹཱͭߟ͑ํͷҰͭɻͦͷத͔Βɺί ετ΍ऩӹɺ΄΅֬ఆ͍ͯ͠Δྲྀ௨νϟϯωϧͳͲΛল͖ͳ͕ΒԼهʹݶఆ͢Δͱࠓճ͸ධՁ߲໨ͱ ͯ͠ར༻͠΍͍͢ɻ 1. ސ٬ͷ՝୊ 2. ސ٬ηάϝϯτ 3. Ձ஋ 4. ιϦϡʔγϣϯ 5. ༏Ґੑ ʮϦʔϯΩϟϯόεʯ΍ͦͷલ਎Ͱ͋ΔʮϏδωϧϞσϧδΣωϨʔγϣϯϚοϓʯͰ͸ɺ͜ΕΒ ΛؚΉ 9 ߲΄ͲΛϚτϦοΫεతͳදʹͯ͠Ծઆݕূ͠ෳ਺Ҋ͔Β༗ޮͳ΋ͷΛऔࣺબ୒͍ͯ͠Δɻ ਤʹͤͣͱ΋͜ͷπʔϧ͸ػೳ͠ߟ͑ํͷπʔϧͱͯ͠·͞ʹʮ໰୊ղܾʯͷΞϓϩʔνͦͷ΋ͷͱ ͯ͠ݟΔ͜ͱ͕Ͱ͖Δɻ ਤ: Ωϟϯόεͷྫ ڭҭࢧԉͷՁ஋ͱιϦϡʔγϣϯ ࣗࣾίϯςϯπΛ౰ͯ͸Ίͯߏ૝͢Δͱ... • ސ٬ͷ՝୊ –ʢͲ͜Ͱʣ۠಺ͷٛ຿ڭҭɺ20 ೥౓খֶੜͳͲ΁ –ʢ͍ͭʣͦͷ࣌఺ͷ࣍೥౓ɻ20 ೥౓͔ΒͷඞमԽʹ޲͚ʢظ೔໨ඪʣ –ʢͲ͏͢΂͖ʣֶशࢦಋཁྖʹ४ڌ͢Δ࣮ࢪϝχϡʔͷఏࣔΛͯ͠ –ʢͳʹΛʣٛ຿ڭҭ΁ͷϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔ໨ඪʣ • ސ٬ηάϝϯτ –ʢͲ͜Ͱʣதֶߍͷओʹٕज़Պ 54
  54. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.7 ΞΠσΞͷൃ૝ͱࢥߟ • Ձ஋ – ະܦݧऀ͕ςΩετϓϩάϥϛϯάΛ͍͖ͳΓମݧͰ͖Δ

    – ΤϯδχΞ͕ߨࢣʹདྷΔ – ϢχʔΫͳڭࡐͰָ͠Έͳ͕ΒֶशͰ͖Δ • ιϦϡʔγϣϯ – ςΩετϓϩάϥϛϯάΛଧͪࠐΜͰࢼͤΔ – ଧͪࠐ·ͳͯ͘΋ςΩετϓϩάϥϛϯάֶ͕΂Δ – ϓϩάϥϛϯάͷυϦϧֶश͕Ͱ͖Δ – ࡞඼੍࡞΍ڭՊ΁ͷԠ༻ʹΑͬͯϓϩάϥϛϯάࣗମ͕πʔϧʹͳΔ • ༏Ґੑ – ॳΊ͔ΒதֶΛϝΠϯλʔήοτʹ͍ͯ͠ΔͨΊҰఆͷద߹ੑ͕͋Δ – ήʔϜͱαʔϏεͷձࣾΒָ͍͠͠·ͤํ͕͋Δ – ֶशͷόϦΤʔγϣϯ΍δϟϯϧ෯͕ͱΕΔ • ظݶ͕͋ΔதͰιϑτ΢ΣΞʹԿΛඋ͑ఏڙͰ͖Δ͔ͷج४͸... – ϦʔϯελʔτΞοϓͷ MVPʢՁ஋ఏڙ࠷খ੡඼ʣΛ࣠ʹඞཁͳ΋ͷ͔Β࣌ؒͷݶΓʹ ࣮ݱ͢Δ ∗ Կ͕ MVP ͱͳΔ͔͸ 5W1H ΍ OKR ͷ্͔ΒԼ·Ͱͷͭͳ͕Γ͔Β͔ͭΉ – UVPʢಠࣗͷՁ஋ఏҊʣ։ൃ͕࣮ݱͰ͖ͨ͜ͱͰ࣮֬ʹιϑτ΢ΣΞ͕ఏڙͰ͖Δཪ෇ ͚ʹͳΔ ∗ पΓͷػೳ͸ͳΜͱͰ΋ͳΓɺ࠷௿Ͱ΋උ͑ͯͳͯ͘΋໨తࣗମ͸ୡ੒Ͱ͖Δ ਖ਼͍͠ݕ౼ͷॱংͰߏ૝͢Δ ஫ҙ͓ͯ͘͠෦෼ͱͯ͠ʮιϦϡʔγϣϯʯͭ·Γ੡඼͕࣮ݱ͢ΔػೳΛ΋͔ͬͯͳ͑Δ෦෼͸ 9 ߲໨ͷ͏ͪͷ 1 ͭͰ͔͠ͳ͘ɺ ʮ੡඼ΞΠσΞʹറΒΕ͗͢Δͳʯͱ͍͏ϝοηʔδ͕ͦ͜ʹ͋Δͱ ͍͏͜ͱͩͦ͏ͩɻՁ஋΍ιϦϡʔγϣϯʹ͸ϦʔϯελʔτΞοϓͷ MVPʢՁ஋ఏڙ࠷খ੡඼ʣ ͔Β࣮ݱͯ͠ݕূ͢Δ͜ͱ͕ॏཁͰ͋Δͱड़΂ΒΕ͍ͯΔɻ·ͨ MVP ͷ৺ଁ෦ɺͭ·Γ UVPʢಠ ࣗͷՁ஋ఏҊʣ͕ڝ߹༏Ґੑʹͭͳ͕ΓͦͷαʔϏεΛಛ௃͚ͮΔͱ͍͏ɻ Ωϟϯόεʹ౰ͯ͸Ίͳ͕Βߏ૝ͱݕূΛߦ͖དྷ͢Ε͹ɺม͑Δ΂͖Օॴ͕ɺૌٻ͢ΔʮՁ஋ʯͦ ͷ΋ͷͳͷ͔۩ݱԽ͢ΔʮιϦϡʔγϣϯʯͳͷ͔͕໌֬ʹ೺ѲͰ͖Δɻߟ͕͑ٴ͹ͣʹ͋Ε͜Εม ͍͑ͯΔͱ͖ͦΕ͸ʮιϦϡʔγϣϯʯͭ·Γ۩ମతͳखஈΛม͍͑ͯΔ͚ͩͰՁ஋͕มΘ͍ͬͯͳ ͍Մೳੑ͕͋ΔͩΖ͏ɻਖ਼͍͠ೝࣝͷʮ՝୊ʯͱʮސ٬ʯͷؒʹͦͷʮՁ஋ʯ͕ఆٛͰ͖͍ͯΔ͔ɺ ݕ౼ͷॱং͸·ͨॏཁͳҙຯΛ࣋ͭɻ 55
  55. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.7 ΞΠσΞͷൃ૝ͱࢥߟ b. ໰୊ղܾΞϓϩʔνͱͯ͠ͷʮσβΠϯࢥߟʯ σβΠϯࢥߟ͸໰୊ղܾͷϑϨʔϜϫʔΫͷҰͭͰɺ΋ͱ΋ͱσβΠφʔͰ༻͍ΒΕΔࢥߟ๏ͰԾ આͱݕূʹΑͬͯݚຏ͍ͯ͘͠औΓ૊ΈํʹϏδωεͷ՝୊ղܾͱͷڞ௨఺͕͋Δɻࢥߟͷํ๏͸࣍

    ͷͱ͓Γɻ • ڞɹײɹɹɹ ... ৘ใऩू΍ֶशɺϢʔβʔͱڞײ͢Δ • ఆɹٛɹɹɹ ... Ϣʔβʔͷؾ࣋ͪͰ໰୊ʹؾ෇͘ɺ෼ੳ͠໰୊ఆٛ͢Δ • ૑ɹ଄ɹɹɹ ... ໰୊ΛղܾͰ͖ΔΞΠσΞΛ͍͔ͭ͘૑଄͠ڍ͛Δ • ϓϩτλΠϓ ... ΞΠσΞ͕࣮ࡍʹࢼͤΔΑ͏ʹࢼ࡞͢Δ • ςετɹɹɹ ... ࢼ࡞ͨ͠੡඼Λ࣮ࡍʹςετ͠ධՁ͢Δ ੡඼։ൃͷϑΣʔζ͕σβΠϯࢥߟΛదԠ͠΍͍͢ɻڭࡐιϑτ΢ΣΞ։ൃ࣌ʹ͜ͷࢥߟΛ౰ͯ͸ ΊͨྫΛڍ͛Δɻ • ڞײ – ίϯϐϡʔλૢ࡞ͦͷ΋ͷ΋ॳ৺ऀֶ͕ͩशͷຊ࣭Ͱ͸ͳ͘ϓϩάϥϛϯάΛֶͼ͍ͨ • ఆٛ – ॳ৺ऀͳͷͰΩʔϘʔυೖྗͳΜͯͯͨ͠Β೔͕฻Εͯ͠·͏͠໘౗ʹͳΔ • ૑଄ – จࣈೖྗΛͤͣೖྗ͢ΔԿΒ͔ͷػೳ͕͋Ε͹ମݧͱֶशʹूதͰ͖Δ • ϓϩτλΠϓ – ίʔυૠೖϘλϯͷ࡞੒ • ςετ – ݕূͰλΠϐϯάෆಘखͰ΋ίʔυૠೖػೳͰετϨεͳ͘΍Γ͖Εͨʢߠఆʣ – ߦͱΠϯσϯτ΍ϒϩοΫʹ͍ͭͯͷཧղෆ଍ʹΑΓೖྗϛε͕ى͜Δʢվળʣ ͜ͷݕূͱͦͷޙͷ࣮ݱʹΑͬͯதֶ 1 ೥ͳͲλΠϐϯάෆಘखͷֶੜ΁͸΋ͪΖΜͷ͜ͱখֶੜ Ͱ͋ͬͯ΋ར༻Ͱ͖Δɻґཔऀ͔Β΋খֶߍͰͷར༻Λͯ͠΋Α͍Μ͡Όͳ͍͔ͱظ଴͕͕͋ͬͨɺ ݱ࣌఺Ͱ͸খֶੜ΁ͷࢦಋͦͷ΋ͷͷ೉͕͋͠͞ΔͨΊԕྀ͍ͯ͠Δঢ়گͰ͋Δɻͳ͓զ͕Ոͷখ 1 ʢ౰࣌ʣͷ່͕ͳΜͱ͔ΫϦΞ͍ͯͨ͠ɻ 56
  56. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.7 ΞΠσΞͷൃ૝ͱࢥߟ c. ৽͍͠ΞϓϩʔνʮετʔϦʔࢥߟʯͰ੾Γ։͘ ͦ͏͜͏ΞϓϩʔνΛߟ͑ͳ͕ΒऔΓ૊ΜͰ͍Δ͏ͪ໰୊ղܾͷاըͱ࿩ͷ௨͠ํʹ΋ίπ͕͔ͭ Ίͯ͘Δɻ͓·͚ͱͯۙ͠گͰࢲ͕࣮ફ͍ͯ͠Δߟ͑ํͷҰͭʮετʔϦʔࢥߟʯͳΔ΋ͷΛ঺հ͠

    ͓͖͍ͯͨɻࢥߟ͸ΦϦδφϧͰ͋Γݺশ͸͜͜Ͱͷղઆ༻ʹ෇͚͍ͯΔ͚ͩͰ࿦จ͕͋Δ΋ͷͰ͸ ͳ͍͕ɺ༗ޮͳہ໘͕͔ͳΓଟ͋͘Δͱߟ͍͑ͯΔɻ • ސ٬ͷཧ૝ΛݟΔ – ސ٬ͷ੠Λฉ͖৘ใΛऩू࣮͠ݱ͍ͨ͠ͶΒ͍ͱͦͷഎܠΛݟΔ ∗ʢ࣮ྫʣ์՝ޙֶशΑΓٕज़Պͷतۀࢧԉ͕ཉ͍͠ɺΑΓೝ஌ͷ͋ΔݴޠΛֶ͹ͤͨ ͍ɺPTA ͷҙݟ΋ټΈ͍ͨɺཧ਺ڭҭͰઌߦ͍ͨ͠ɺઐ໳ڭ་͕গͳ͘ରԠͰ͖ͳ͍ • ϓϩοτΛ࡞Δ – ےಓʹ߅͑ͳ͍τϐοΫͱΩʔϫʔυͰετʔϦʔΛଧཱͪͯΔ ∗ʢ࣮ྫʣٕज़Պ৘ใͱͯ͠ɾߴߍͰ͞Βʹߴ౓Խ͢Δ৘ใֶशʹඋ͑ͯɾ৬ۀʹͰ͖ ͯ͜Ε͔Βֶͼ͍ͨςΩετϓϩάϥϛϯάݴޠ No1 ͷ Python ݴޠΛɾ४උͱૢ ࡞ͷख͕͔͔ؒΒͳ͍ΦϦδφϧΞϓϦΛ͔ͭͬͯɾઐ໳ߨࢣ͔Βख୹ʹڭΘΓɾϓ ϩάϥϛϯάͰ࡞඼੍࡞͕Ͱ͖ΔΑ͏ʹͳΔ·Ͱͷઌߦֶͨ͠शΛɾਪਐֶ͍ͨ͠ߍ ͷڭ་ʹΈ͍͍ͯͨͩͯतۀઃܭ࣮͠ࢪ͢Δͱɾٕज़Պڭ་͕औΓ૊Μͩ΋ͷͰ࣮ࢪ ྫ͕͋ΔͨΊ۠಺શߍ΁ͷల։͕ಉ೥଎΍͔ʹͰ͖Δɻ • ੣࣮ʹ GIVE ͢Δ –ʮGIVEʯ͸ॻ੶ʮGIVE ˍ TAKEʯʹ΋ొ৔͢ΔߦಈಛੑͰଞऀ΁༩͑ΔߦಈΛࣔ͢ – ϓϩοτҎ্ͷڻ͖Λ༩͑Δ࡞඼ʢ੡඼ʣΛ੣࣮ʹࣔ͠ސ٬΁ GIVE Λି͚ͭ͠ Funʢຯ ํʣʹม͑Δ ∗ʢ࣮ྫʣεέδϡʔϧతʹΏͱΓΛ࣋ͬͯܦաͷ಺༰Λ։ࣔͯ͠ɺ֬ೝऀ͸໔Ӹ͕ͳ ͍Ώ͑ιϑτ΢ΣΞෆ۩߹͸θϩͰ͋Γଓ͚ɺ͔Ώ͍ͱ͜Ζʹख͕ಧ͖؆୯͕͞ࡍཱ ͭΑ͏ʹ͠ɺࢹ֮తʹڻ͖͕͋ΔίϯςϯπΛؚΈɺ੡඼ͱ಺༰ͷઐ໳ՈͰ͋Δ͜ͱ Λࣔ͠ɺސ٬ͷݸਓతͳ஌త޷ح৺ʹ͔͑ͬ͞͠Γ޲͖߹͏ɻ • ஄Έंʹ৐Δ –ʮ஄Έंʯ͸ॻ੶ʮϏδϣφϦʔΧϯύχʔʯʹ΋ొ৔͢Δ – ࢿݯͱ࣌ؒ͸༗ݶͳͷͰߦಈ͸ඞͣೋ࣍ࡾ࣍ར༻Λલఏʹաڈͱະདྷʹͭͳ͛Δετʔ ϦʔΛඳ͘ – ෳ਺ͷސ٬ͷ໰୊ղܾΛ 1 ΞΫγϣϯͰຬͨͦ͠ͷઐ໳ՈʹͳΔ ∗ʢ࣮ྫʣ ʮֶशΠϕϯτʯͰಋೖͨ͠ϏΪφʔ޲͚ςΩετϓϩάϥϛϯάମݧιϑτ ʢLua ݴޠʣΛస༻͠ʮٕज़Պʯͷ Python ֶशʹਐԽɻͦͷޙ੡඼ͱΧϦΩϡϥϜ ͸స༻͠ʮ෦׆ʯͷΑΓߴ౓ͳ࣮ફʹ΋׆͔͓ͤͯΓ૬৐ޮՌͰ΋ͱ΋ͱͷίϯςϯ πͱͱ΋ʹൃలͨ͠ɻࠓޙ͞Βʹผतۀͷ஫໨ίϯςϯπʹస༻͠׆͔͢΂͘४උ͠ ͍ͯΔɻ 58
  57. ୈ 5 ষ ֶߍఏڙιϑτ΢ΣΞͰ໰୊ղܾ 5.8 ࠷ޙʹ 5.8 ࠷ޙʹ ϑϨʔϜϫʔΫ΍πʔϧ͸ڍ͛ͨҎ֎΋ͨ͘͞Μ͋Δ͕ɺࠓճͷ΋ͷ͚ͩͰ΋ଟ͘ײ͡ɺͳ͓͔ͭ ؔ࿈͢ΔͲ͏͠͸ͲΕ΋ڞ௨఺͕͋Δɻ΋͸΍Ұॹʹࢥ͖͑ͯͨͷ͸͖ͬͱࢲ͚ͩͰ͸ͳ͍͕ɺٯʹ

    ͦ͏͍͏΋ͷͩͱࢥ͍ͬͯΔɻ఻͍͑ͨͷ͸ɺ͜ΕΒΛ͍͘Β஌͍ͬͯͯ΋ɺීஈ͔Βࣗવʹ׆༻Ͱ ͖͍ͯΔࢥߟ͕਎ʹ͍͍ͭͯͳ͚Ε͹ҙຯ͸ͳ͍ɻϓϨΠϠʔʢݱ৔ʣ͸ࣗ෼ͷྖҬͰ࠷େݶ׆༂͠ ࣗݾ࣮ݱͨ͘͠ͳΔͷ͸ੑʢ͕͞ʣͰ͋ΓͦΕ͸߅͑ͳ͍ɻ௕͘ଟ͘ͷΤωϧΪʔΛ஫͍Ͱ͜ͱʹऔ Γ૊Ήͱ͖ɺͦͷʮιϦϡʔγϣϯʯͷपΓΛΑ͘ݟఆΊΔ͜ͱ͕େ੾Ͱ͋Γ͢΂ͯͷࢿݯ͸༗ݶͳ ͷͩɻޘָ΋ɺੜ׆΋ɺڭҭ΋ɺ໰୊ͱղܾͷ͍ͣΕ͔ͷதʹ͋Δɻͦ͜ʹ͸ɺ໰୊ղܾʹࢸΒ͠Ί Δ࿦ཧతͳશମܭը͸͋Δͷ͔ɺͦͷιϦϡʔγϣϯ͸ MVP ͔ͦΕҎ֎͔ɺ՝୊ͱސ٬Ձ஋·ͨ͸ ໰୊ఆٛͱԾઆઃఆ͞Ε͍ͯΔ͔ɺͦͷԾઆ͸ݕূͰ͖͍ͯΔͷ͔ʔɻ Appendix ᶗ. ՝୊ղܾܕֶशʙPBLʢProject-Based-Leaningʣ ষ຤ʹɺ໰୊ղܾʹྨࣅؔ͠࿈ͨ͠ςʔϚͰ͋Δʮ՝୊ղܾܕֶशʯ *3ͱ͍͏ֶशख๏͕ڭҭքͰ ೐Θ͍ͬͯΔͨΊ঺հ͢Δɻӳޠදه͸ PBLʢProject-Based-Leaningʣͱݴ͍ۙ೥஫໨͞Εॏࢹ͞ Εͭͭ͋Δɻֶੜ͕ͨͪ՝୊Λղܾ͢ΔͨΊͷྗΛཆ͏ͨΊͷֶशํ๏ʹΑΓɺॊೈͳࢥߟྗ΍Ԡ༻ ྗΛ਎ʹ͚ͭ׆༂Ͱ͖Δਓ෺Λ͸͙͘Ήૂ͍͕͋Δɻֶੜ͕՝୊ΛࣗΒൃݟ͠ඞཁͳ͜ͱΛࣗΒֶͿ ͜ͱͰɺΧϦΩϡϥϜܕͷֶशʹൺ΂ΑΓॊೈͳࢥߟ͕਎ʹ͖ͭೳྗ͕৳͹ͤΔͱ͍͏΋ͷɻւ֎Ͱ ͸ΧϦΩϡϥϜͳ͘͢΂ͯ PBL ʹͳ͍ͬͯΔֶߍ΋͋Δͱ͍͏͕ɺࠃ಺Ͱ΋ڭՊΧϦΩϡϥϜͱ͸ ผʹฒߦͯ͠೥ؒΛ௨ͯ͠ܧଓతʹऔΓ૊ΜͰ͍Δֶߍͷࣄྫ΋͋ΔɻPBL Ͱ͸άϧʔϓϫʔΫͰ औΓ૊ΈɺνʔϜ֎΁ͷൃද·Ͱ͕ඞؚͣ·ΕΔɻऔΓ૊Έํ๏͸ओʹ࣍ͷ௨Γɻ • ৘ใऩू ... ओ୊ʹؔ࿈͢Δ৘ใΛऩू͢Δ • ໰୊ൃݟ ... ໰୊఺Λݟग़͢ • Ծઆઃఆ ... ݪҼͱղܾํ๏ͷԾઆΛཱͯΔ • ݕɹূɹ ... ԾઆΛݕূ͠༗ޮͳରࡦΛൃݟ͢Δ • ൃɹදɹ ... ௐࠪͨ͠಺༰ͱ݁ՌΛൃද͢Δ ᶘ. MIXI ͷॻ੶ߪೖࢧԉ ΤϯδχΞͰ΋Ϗδωε৬Ͱ΋όοΫΦϑΟεͰ΋ɺϚʔέςΟϯάͱϏδωεͷجૅ஌ࣝ͸ಇ͘ ࣾձਓʹͱͬͯॏཁͳཁૉͩɻMIXI ͷࣾһʹ͸ɺձ͔ࣾΒ͋Γ͕͍ͨࢧԉ͕͋Γʮॻ੶ߪೖࢧԉʯ ੍౓ͳΔ΋ͷʹΑͬͯۀ຿΍ࣗݾֶशʹͭͳ͕Δॻ੶ͷߪೖͷඅ༻Λຖ݄ 5500 ԁʢ੫ࠐʣ·Ͱิॿ ͯ͘͠ΕΔɻචऀ͸தݹॻ੶Λத৺ʹ೥ؒ 7~80 ࡭ۙ͘ࢧԉͯ͠΋Β͓ͬͯΓɺීஈͷંি΍اըʹ ௚઀ؐݩ͍ͯ͠Δɻॻ੶ߪೖࢧԉʹ͍ͭͯ͸Ұ౓͸Ξ΢τϓοτ͍ͨ͠ͱࢥ͍ͬͯͨɻ *3 ʮ՝୊ղܾܕʯͷ΄͔ɺઃఆͷҧ͍ʹΑΓʮ໰୊ղܾܕʯ ɺ ʮ՝୊ୡ੒ܕʯͱ΋͍͏ 60
  58. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳ ࢢ۠ொଜ൑ఆ ຊߘͰ͸ɺҢ౓ɾܦ౓Ͱදݱ͞Εͨ࠲ඪ͕ɺͲͷ౎ಓ෎ݝɾࢢ۠ொଜʹଘࡏ͢Δͷ͔ɺBigQuery ্

    Ͱ൑ఆ͢Δ͜ͱΛ໨తͱ͍ͯ͠·͢ɻ௨ৗ͸ PostGIS ޓ׵ͷ GIS ؔ਺Ͱ͋Δ ST_CONTAINS ؔ਺*1 Λ༻͍·͕͢ɺҐஔ৘ใΛӳ਺ࣈͰදݱͨ͠ GeoHash Λ༻͍ͯ୯७ͳจࣈྻҰகͰ൑ఆ͠ɺߴ଎Խ ΛਤΓ·͢ɻࠃ౔ަ௨লͷڥքσʔλΛऔಘɾ੔ܗͯ͠ BigQuery ʹऔΓࠐΈɺͲͷΑ͏ʹ GeoHash දݱʹม׵͢Δ͔ΛɺຊߘͰ͸ओ୊ͱͯ͠ѻ͍·͢ɻ౎ಓ෎ݝɾࢢ۠ொଜʹݶΒͣɺڥքσʔλ͞ ͑͋Ε͹ద༻ՄೳͰ͢ɻ1 ԯߦͷσʔλʹର͢Δ࣮ݧͰ͸ɺ௨ৗͷํ๏Ͱ͸ 1 ෼ఔ౓͔͔Δͱ͜Ζɺ GeoHash Λ༻͍Δͱ໿ 98% ͷਫ਼౓Λอͪ਺ඵͰ׬ྃ͢Δ͜ͱΛࣔ͠·ͨ͠ɻ GeoHash ͱࢢ۠ொଜͷରԠΛࣔ͢ςʔϒϧ͸ɺޙड़͢Δ query_1_3.sqlɺquery_2_3.sqlɺ query_3_3.sql Λ݁߹͢ΔͱಘΒΕ·͢ɻ࣮ࡍͷ࢖͍ํ͸ʮGeoHash Λ༻͍ͨํ๏.sqlʯΛࢀߟʹ ͯ͠Έ͍ͯͩ͘͞ɻ 6.1 ͸͡Ίʹ εϚʔτϑΥϯͷීٴʹΑΓҐஔ৘ใͷऔಘ͕਎ۙʹͳ͍ͬͯ·͢ɻҐஔ৘ใΛऩू͢Δࡍɺଟ͘ ͷ৔߹͸Ң౓ͱܦ౓͕஝ੵ͞Ε·͕͢ɺΘ͔Γ΍͍͢΋ͷͰ͸͋Γ·ͤΜɻೃછΈͷ͋Δʮ౎ಓ෎ ݝɾࢢ۠ொଜʯ͝ͱʹେࡶ೺ʹͰ΋೺ѲͰ͖Ε͹ɺͱࢥͬͨ͜ͱ͕ଟ͍ͷͰ͸ͳ͍ͷͰ͠ΐ͏͔ɻຊ ߘͰ঺հ͢Δख๏͸ɺBigQuery ʹ஝ੵ͞Εͨେྔͷσʔλʹରͯ͠ɺ͋Δఔ౓ͷਫ਼౓Ͱߴ଎ʹࢢ۠ ொଜ͝ͱͷ෼ྨΛࢼΈΔͨΊͷख๏Ͱ͢ɻ ຊઅͰ͸ɺجຊతͳ஌ࣝʹ͍ͭͯղઆ͠·͢ɻ *1 BigQuery ஍ ཧ ؔ ਺ ͷ Ϧ ϑ Ν Ϩ ϯ ε: https://cloud.google.com/bigquery/docs/reference/standard- sql/geography_functions?hl=ja#st_contains 61
  59. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.1 ͸͡Ίʹ δΦίʔσΟϯάͱ͸

    δΦίʔσΟϯάͱ͸ɺ ʮ౦ژ౎ौ୩۠ 2 ஸ໨ 24-12ʯͷΑ͏ͳॅॴΛ஍ཧ࠲ඪʢҢ౓ܦ౓ͳͲʣʹ ม׵͢Δ͜ͱΛࢦ͠·͢ɻҢ౓ܦ౓͚ͩͰ͸ͳ͘ɺ͞·͟·ͳද͠ํ͕͋Γ·͢ɻ·ͨɺҢ౓ܦ౓ͷ Α͏ͳҰ఺Λද͢͜ͱ΋͋Ε͹ɺ௕ํܗͳͲͷྖҬΛද͢͜ͱ΋͋Γ·͢ɻ ද 6.1: ͍Ζ͍ΖͳδΦίʔσΟϯά छྨ ༻ྫ ौ୩εΫϥϯϒϧεΫΤΞ ʢ1m ఔ౓ͷਫ਼౓ʣ ौ୩εΫϥϯϒϧεΫΤΞ ʢ1km ఔ౓ͷਫ਼౓ʣ Ң౓ɾܦ౓ Ұൠʹ޿͘༻͍ΒΕΔ 35.65840 N,139.70219 E 35.65 N,139.70 E GeoHash ଟ͘ͷ Web αʔϏεͳͲ xn76g52j0z xn76g5 MGRS ཮্ࣗӴୂͳͲ 54SUE8252546836 54SUE8246 ஍Ҭϝογϡ ੓෎౷ܭͳͲ 5339-3596-1-1-2(125m ਫ਼౓) 5339-3596 PlusCode*2 Google Maps ͳͲ 8Q7XMP52+9V82 8Q7XMP52+(300m ਫ਼౓) QuadKey Azure ͳͲ 133002112303102222000001 13300211230310 S2 ϙέϞϯ Go ͳͲ 6924437637984796672 6924437654335389696 GeoHex υϥΫΤ΢ΥʔΫͳͲ XM488542752402 XM4885427 GeoHash GeoHash ͸Ң౓ɾܦ౓Λ Base32 Ͱදݱͨ͠δΦίʔσΟϯάͰ͢ɻgeohash.org ͱ͍͏ Web αʔϏεͰߟҊ͞ΕɺύϒϦοΫυϝΠϯͱͳ͍ͬͯ·͢ɻGeoHash ͸Ң౓ͱܦ౓ͷϏοτΛަޓ ʹ഑ஔͯ͠Τϯίʔυ͠·͢ɻͦͷͨΊɺ୯७ʹ຤ඌΛ࡟Δ͚ͩͰਫ਼౓͕མͪΔੑ࣭͕͋Γ·͢ɻ· ͨɺGeoHash ͸఺Ͱ͸ͳ͘ྖҬΛදݱ͠·͢ɻ 1 จࣈͷ GeoHash Ͱ͸஍ٿن໛Ͱͷେࡶ೺ͳൣғ͔͠දݱͰ͖·ͤΜɻ2 จࣈͷ GeoHash Ͱ͸ ࠃϨϕϧɺ3 จࣈͷ GeoHash Ͱ͍͍ͩͨ౎ಓ෎ݝϨϕϧͷൣғΛදݱͰ͖·͢ɻ௚ײతͳཧղΛ͢ Δʹ͸ GeoHash Explorer*3͕͓͢͢ΊͰ͢ɻ *2 PlusCode ͸ Open Location Code ʹΑΓੜ੒͞ΕΔ *3 https://geohash.softeng.co/ 62
  60. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.1 ͸͡Ίʹ ਤ

    6.3: 3 จࣈͷ GeoHash GeoHash ͷΤϯίʔυ ͍͍ͨͯ͸طଘͷϥΠϒϥϦΛ࢖͏ͱࢥ͍·͕͢ɺҢ౓ܦ౓͔Β GeoHash ΁ͷม׵͸࣍ͷΑ͏ʹ ߦ͍·͢ɻौ୩εΫϥϯϒϧεΫΤΞͷ͋Δʮ๺Ң 35.65840 ౓ɺ౦ܦ 139.70219 ౓ʯͷม׵Λ௨͠ ͯઆ໌͠·͢ɻ·ͣɺҢ౓͸ʮೆҢ 90 ౓ˠ๺Ң 90 ౓ʯ ɺܦ౓͸ʮ੢ܦ 180 ౓ˠ౦ܦ 180 ౓ʯΛʮ0 ˠ 1ʯʹม׵͠·͢ɻҢ౓ΛПɺܦ౓ΛЕͱ͢Δͱ࣍ͷΑ͏ͳࣜʹͳΓ·͢ɻ ϕ′ = (ϕ + 90)/180 λ′ = (λ + 180)/360 ͜ΕΛ࣮ࡍʹ౰ͯ͸ΊΔͱ࣍ͷΑ͏ʹͳΓ·͢ɻ (35.65840 + 90)/180 = 0.69810222222... (139.70219 + 180)/360 = 0.88806163888... 65
  61. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.1 ͸͡Ίʹ ࣍ʹɺ͜ΕΒΛ

    2 ਐ਺ʹม׵͠·͢ɻখ਺ͷ 2 ਐ਺දه͕؆୯ʹಘΒΕͳ͍؀ڥͰ͸ɺඞཁͳܻ ਺͚ͩϏοτγϑτΛͨ͠ΓɺϧʔϓΛճ͢ͱྑ͍Ͱ͠ΐ͏ɻJavaScript Ͱ͸ 0.768.toString(2) ͳͲͱॻ͘ͱ؆୯ʹ 2 ਐ਺දه͕ಘΒΕ·͢ɻ લड़ͷ࠲ඪ͸ 2 ਐ਺Ͱදه͢Δͱ࣍ͷΑ͏ʹͳΓ·͢ɻ Ң౓: 0.69810222222... ˠ 0.1011001010110110110100111100010110110101100110010011... ܦ౓: 0.88806163888... ˠ 0.1110001101011000000000011110111111011100001001001111... ͜ΕΒͷখ਺఺ҎԼΛަޓʹฒ΂͍͖ͯ·͢ɻ2 ਐ਺ͷখ਺఺ҎԼΛ্Ґͷܻ͔Βॱʹɺܦ౓͸ح ਺ྻɺҢ౓͸ۮ਺ྻͱ͍ͬͨ۩߹ʹɺަޓʹฒ΂͍͖ͯ·͢ɻ Ң౓ ˠ .1.0.1.1.0.0.1.0.1.0.1.1.0.1.1.0.1.1.0.1.0.0.1.1.1 ܦ౓ ˠ 1.1.1.0.0.0.1.1.0.1.0.1.1.0.0.0.0.0.0.0.0.0.0.1.1. -------------------------------------------------- ߹੒ ˠ 11101101000011100110011110010100010100010000011111 ࠷ޙʹ͜ͷόΠφϦྻΛ BASE32 ม׵͠·͢ɻઌ಄͔Β 5 Ϗοτͣͭ۠੾Γɺද 6.2 ʹΑͬͯม ׵͠·͢ɻ ද 6.2: BASE32 ม׵ද 2 ਐ਺ BASE32 2 ਐ਺ BASE32 2 ਐ਺ BASE32 2 ਐ਺ BASE32 00000 0 01000 8 10000 h 11000 s 00001 1 01001 9 10001 j 11001 t 00010 2 01010 b 10010 k 11010 u 00011 3 01011 c 10011 m 11011 v 00100 4 01100 d 10100 n 11100 w 00101 5 01101 e 10101 p 11101 x 00110 6 01110 f 10110 q 11110 y 00111 7 01111 g 10111 r 11111 z ͖͞΄ͲಘΒΕͨόΠφϦྻ 11101101000011100110011110010100010100010000011111 ΋ 5 Ϗοτͣͭ۠੾Γɺද 6.3 ͷΑ͏ʹม׵Ͱ͖·͢ɻ 66
  62. ୈ6ষ BigQueryͰGeoHashʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.2 ڥքσʔλͷऔΓࠐΈ ද 6.3: BASE32 ม׵݁Ռ 2 ਐ਺

    BASE32 11101 x 10100 n 00111 7 00110 6 01111 g 00101 5 00010 2 10001 j 00000 0 11111 z ʮxn76g52j0zʯ͕ม׵݁ՌͰ͢ɻ͜ͷ GeoHash ͸ɺ๺Ң໿ 35.65839707 ౓ʙ35.65840244 ౓ɺ౦ ܦ໿ 139.70218062 ౓ʙ139.70219135 ౓ͷྖҬΛ͍ࣔͯ͠·͢ɻ 6.2 ڥքσʔλͷऔΓࠐΈ ࠃ౔ަ௨লͷڥքσʔλΛऔಘɾ੔ܗͯ͠ BigQuery ʹऔΓࠐΈɺGeoHash දݱʹม׵͢Δʹ͋ ͨΓɺ࣍ͷखॱͰߦ͍·͢ɻ 1.ʢԼ४උʣࠃ౔ަ௨ল͔ΒڥքσʔλΛऔಘ͠ɺBigQuery ʹऔΓࠐΉɻ 2.ʢຊ୊ʣBigQuery ্Ͱࢢ۠ொଜͱڥքσʔλͷରԠΛ΋ͱʹɺGeoHash ͱࢢ۠ொଜͷରԠΛ ࡞੒͢Δɻ ຊઅͰ͸ɺڥքσʔλΛ BigQuery ʹऔΓࠐΉͱ͜Ζ·Ͱղઆ͠·͢ɻGIS Ͱ༻͍ΒΕΔϕΫλ σʔλ͸ɺϙΠϯτʢ఺ʣ ɺϥΠϯʢઢʣ ɺϙϦΰϯʢଟ֯ܗʣͷ 3 छྨ͕͋Γ·͢ɻࠓճ͸ڥքσʔ λͰ͢ͷͰɺϙϦΰϯΛऔΓѻ͍·͢ɻ ࢢ۠ொଜͷڥքσʔλͱͯ͠ɺࠃ౔ަ௨ল͕ެ։͍ͯ͠Δࠃ౔਺஋৘ใͷߦ੓۠ҬσʔλΛ༻͍· ͢*4ɻ͜ͷαΠτͰ͸΄͔ʹ΋தֶߍ۠ͳͲ͞·͟·ͳσʔλ͕ެ։͞Ε͍ͯ·͢ɻར༻ن໿͸ͦΕ ͧΕʹ͓͍ͯ֬ೝΛ͓ئ͍͠·͢ɻ μ΢ϯϩʔυͨ͠σʔλ͸ jq ίϚϯυ*5Ͱ GeoJSON ͔Β TSV ʹม׵͠ɺbq ίϚϯυ*6Ͱ BigQuery ʹऔΓࠐΈ·͢ɻ *4 ࠃ౔਺஋৘ใͷߦ੓۠Ҭσʔλ:ɹ https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_0.html *5 jq ίϚϯυ: JSON Λ੔ܗ͢ΔͨΊͷπʔϧ https://stedolan.github.io/jq/ *6 bq ίϚϯυ: BigQuery Λૢ࡞͢ΔͨΊͷπʔϧ https://cloud.google.com/bigquery/docs/bq-command-line- tool?hl=ja 67
  63. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.2 ڥքσʔλͷऔΓࠐΈ #

    σʔλΛμ΢ϯϩʔυʢ೔ຊશࠃͷ2021೥࣌఺ͷσʔλʣ $ wget https://nlftp.mlit.go.jp/ksj/gml/data/N03/N03-2021/N03-20210101_GML.zip # ZIPΛղౚ͢Δ $ unzip N03-20210101_GML.zip # GeoJSONΛTSVʹม׵͢Δʢ؀ڥʹΑΓ·͕͢1෼ఔ౓͔͔Γ·͢ʣ $ jq -r ’.features | to_entries | map([ .key, .value.properties.N03_001, .value.properties.N03_002, .value.properties.N03_003, .value.properties.N03_004, .value.properties.N03_007, .value.geometry | tostring ])[] | @tsv’ N03-20210101_GML/N03-21_210101.geojson > japan.geo.tsv # BigQueryʹҰ୴औΓࠐΉ $ bq load --source_format=CSV \ --field_delimiter=tab geo_dataset.japan_pre \ ./japan.geo.tsv \ polygon_id:INT64,city_name_1:STRING,city_name_2:STRING,city_name_3:STRING,\ city_name_4:STRING,city_id:STRING,city_polygon:GEOGRAPHY TSV Λ͍ͬͨΜͦͷ·· BigQuery ʹऔΓࠐΜͩޙɺBigQuery ্Ͱ੔ܗͯ͠औΓࠐΈ௚͠·͢ɻ CREATE OR REPLACE TABLE geo_dataset.japan CLUSTER BY polygon_id AS WITH pref_number AS ( SELECT DISTINCT city_name_1, LEFT(city_id, 2) || "000" pref_city_id FROM geo_dataset.japan_pre WHERE city_name_1 != "null" AND city_id != "null" ) SELECT polygon_id, -- null͕จࣈྻͰऔΓࠐ·Ε͍ͯΔͨΊNULLʹ௚͓ͯ͘͠ NULLIF(city_name_1,"null") city_name_1, NULLIF(city_name_2,"null") city_name_2, NULLIF(city_name_3,"null") city_name_3, NULLIF(city_name_4,"null") city_name_4, CASE WHEN city_id != "null" THEN city_id WHEN city_name_1 != "null" THEN pref_city_id -- ॴଐະఆ஍ ELSE NULL END city_id, city_polygon FROM geo_dataset.japan_pre 68
  64. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ LEFT

    JOIN pref_number USING (city_name_1) ࠷ऴతʹ࣍ͷΑ͏ͳςʔϒϧ͕ BigQuery ʹ࡞ΒΕ·͢ɻ ද 6.4: ֤ࢢ۠ொଜͷڥքσʔλ ྻ໊ ܕ ಺༰ polygon_id INT64 ֤ϙϦΰϯʹ෇༩͢Δ ID city_name_1 STRING ౎ಓ෎ݝ city_name_2 STRING ࢧிɾৼڵہ໊ʢ๺ւಓͷΈɾͦͷ΄͔ͷ৔߹͸ NULLʣ city_name_3 STRING ܊ɾ੓ྩ౎ࢢ໊ city_name_4 STRING ࢢ۠ொଜ໊ city_id STRING ߦ੓۠Ҭίʔυɹ૯຿ল͕ઃఆ͍ͯ͠Δࢢ۠ொଜͷ੔਺ 5 ܻͷ ID city_polygon GEOGRAPHY ڥքΛද͢ϙϦΰϯ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ ຊߘͰ͸ GeoHash ΛΩʔͱͯ͠ɺͦͷൣғʹରԠ͢Δࢢ۠ொଜΛฦ͢ςʔϒϧΛ࡞੒͠·͢ɻ GeoHash Ͱද͞ΕΔ௕ํܗ͕Ͳͷࢢ۠ொଜʹඃ͍ͬͯΔ͔Λߟ͑·͢ɻ ʮxn5jeʯʹରͯ͠͸ɺ ʮ౦ژ ౎େౡொʯ͕ฦͬͯ͘Ε͹Α͍Θ͚Ͱ͢ɻ͜ͷςʔϒϧΛ࡞Δʹ͸ɺ͢΂ͯͷ 5 ܻͷ GeoHash λΠ ϧɺ ʮ00000ʯ͔Βʮzzzzzʯͷ໿ 3355 ສݸʹରͯ͠ɺࢢ۠ொଜͷϙϦΰϯ໿ 12 ສݸʹڞ௨෦෼͕͋ Δ͔൑ఆΛߦ͑͹Α͍Θ͚Ͱ͕͢ɺ౰વ΋ͬͱޮ཰ͷྑ͍ํ๏͕͋Γ·͢ɻ 69
  65. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ ਤ

    6.4: ҏ౾େౡ෇ۙͷ 5 ܻͷ GeoHash ೔ຊͷࠃ౔͸ GeoHashʮwv,wy,wu,ws,x5,xh,xj,xk,xn,xp,xr,z0,z2ʯͰ෴͍ਚͤ͘Δ͜ͱ͕஍ਤ͔ ΒΘ͔Γ·͢ɻͦΕͧΕͷࢢ۠ொଜͷϙϦΰϯ͕ɺ͜ͷ 2 จࣈͷ GeoHash ͷͲΕʢҰͭ΋͘͠͸ෳ ਺ʣʹؚ·ΕΔ͔Λ൑ఆ͠·͢ɻ͞ΒʹͦͷதͰಉ༷ͷ͜ͱΛɺ࠶ؼతʹ 3 จࣈɺ4 จࣈͱଓ͚͍ͯ ͚͹ɺޮ཰Α͘൑ఆ͕Ͱ͖·͢ɻ ຊߘͰ͸ɺ೔ຊશࠃͱ͍͏޿͍ൣғͱਫ਼౓ͷόϥϯεΛߟྀͯ͠ 7 จࣈͷ GeoHash Λ༻͍Δ͜ͱ ͱ͠·͢ɻ7 จࣈͷ৔߹ɺ࠷ऴతʹ࡞੒͞ΕΔςʔϒϧͷαΠζ͸ 1.25GBɺϨίʔυ਺͸໿ 2069 ສ ͱɺൺֱతऔΓѻ͍΍͍͢αΠζʹͳΓ·͢ɻ GeoHash ʹࢢ۠ொଜؚ͕·Ε͍ͯΔ͔൑ఆ͢Δ ·ͣɺGeoHash ͷจࣈྻ͔ΒɺGeoHash ͷྖҬΛද͢ϙϦΰϯΛ࡞Δؔ਺Λ࡞Γ·͢ɻ 70
  66. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ query_1_3.sql

    -- geohash_bboxؔ਺ͷࢠؔ਺ -- lจࣈͷGeoHash͸ɺܦ౓෯͸360 * 2^(-CEIL(l*2.5)), Ң౓෯͸180 * 2^(-FLOOR(l*2.5))ͱͳΔͷ Ͱɺ -- த৺఺͔Βͦͷ൒෼ΛՃݮ͢Ε͹bounding box͕Ͱ͖Δɻ CREATE TEMP FUNCTION geohash_bbox_inner(p GEOGRAPHY, l INT64) AS ( STRUCT<xmin FLOAT64, ymin FLOAT64, xmax FLOAT64, ymax FLOAT64>( ST_X(p) - 180 * POW(2,-CEIL(l*2.5)), ST_Y(p) - 90 * POW(2,-FLOOR(l*2.5)), ST_X(p) + 180 * POW(2,-CEIL(l*2.5)), ST_Y(p) + 90 * POW(2,-FLOOR(l*2.5)) ) ); -- GeoHashͷbounding boxΛऔಘɻST_GEOGPOINTFROMGEOHASHؔ਺ͰGeoHashͷத৺఺͕औಘͰ͖Δɻ CREATE TEMP FUNCTION geohash2bbox(geohash STRING) AS ( geohash_bbox_inner(ST_GEOGPOINTFROMGEOHASH(geohash), LENGTH(geohash)) ); -- bboxΛϙϦΰϯԽ͢Δ CREATE TEMP FUNCTION bbox2polygon( bbox STRUCT<xmin FLOAT64, ymin FLOAT64, xmax FLOAT64, ymax FLOAT64> ) AS ( ST_MAKEPOLYGON(ST_MAKELINE([ ST_GEOGPOINT(bbox.xmin, bbox.ymin), ST_GEOGPOINT(bbox.xmin, bbox.ymax), ST_GEOGPOINT(bbox.xmax, bbox.ymax), ST_GEOGPOINT(bbox.xmax, bbox.ymin) ])) ); ࣥච࣌఺ʢ2022 ೥ 8 ݄ʣͰ GeoHash ͱϙϦΰϯ͕ަࠩ͢Δʢڞ௨෦෼Λ΋ͭʣ͔൑ఆ͢Δؔ਺͸ BigQuery ʹ͸͋Γ·ͤΜɻ͔͠͠ɺϙϦΰϯͱ఺ͷަࠩΛ൑ఆͰ͖Δ ST_INTERSECTS ؔ਺͸͋Δ ͨΊɺͪ͜ΒΛ༻͍ͯ൑ఆ͠·͢ɻ্Ͱ࡞ͬͨ GeoHash ͷϙϦΰϯΛ࡞Δؔ਺Λ࢖͍͖ͬͯ·͢ɻ 2 จࣈͷ GeoHash ʹؚ·ΕΔࢢ۠ொଜͱࢢ۠ொଜຖͷϙϦΰϯ਺Λ֬ೝͯ͠Έ·͠ΐ͏ɻ -- (Ϣʔβʔఆٛؔ਺ʹଓ͚ͯ) WITH geohash_polygons AS ( SELECT geohash, bbox2polygon(geohash2bbox(geohash)) polygon FROM UNNEST([ "wv","wy","wu","ws","x5","xh","xj","xk","xn","xp","xr","z0","z2" ]) AS geohash ) SELECT geohash_polygons.geohash, city_name_1 || city_name_4 city_name, COUNT(1) polygon_count 71
  67. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ FROM

    geo_dataset.japan as j JOIN geohash_polygons ON ST_INTERSECTS(geohash_polygons.polygon, j.city_polygon) GROUP BY 1,2 ORDER BY 1,2 LIMIT 5 ද 6.5 ͷΑ͏ʹฦ͖ͬͯ·ͨ͠ɻ͏·͘ಈ࡞͍ͯͦ͠͏Ͱ͢ɻͨͩ͜ͷ··Ͱ͸ɺ ʮwsʯʹରͯ͠ ʮ༩ಹࠃொʯ ʮੴ֞ࢢʯ ʮ஛෋ொʯͷͲΕΛฦͤ͹Α͍ͷ͔෼͔Γ·ͤΜɻ࣮ࡍͷͱ͜Ζʮwsʯʹର͠ ͯ͸ͲΕ΋ਖ਼ղͰ͢ɻҢ౓ܦ౓Ͱදݱ͞ΕΔ࠲ඪʹରͯ͠ࢢ۠ொଜΛฦ͍ͨ͠ͱ͍͏ݩͷ໰୊ʹཱͪ ฦΔͱɺGeoHash ͷܻ਺Λ૿΍͍ͯ͘͠ͱྑͦ͞͏Ͱ͢ɻͦΕͰ΋͍͋·͍ͳ෦෼͸࢒Γ·͢ͷͰɺ ࠷ޙʹॲཧ͠·͢ɻ ද 6.5: ಈ࡞֬ೝͷԠ౴ geohash city_name polygon_count ws ԭೄݝ༩ಹࠃொ 428 ws ԭೄݝੴ֞ࢢ 256 ws ԭೄݝ஛෋ொ 35 wu ԭೄݝ͏Δ·ࢢ 920 wu ԭೄݝ༩ಹݪொ 1 GeoHash ͷจࣈ਺Λ૿΍͍ͯ͘͠ 2 จࣈͷ GeoHash ʹରͯ͠͸ɺ ࣍ͷΑ͏ʹ GeoHash ͱͦΕʹଐ͢ΔϙϦΰϯ ID ΛऔಘͰ͖·͢ɻ -- (Ϣʔβʔఆٛؔ਺ʹଓ͚ͯ) WITH g AS ( SELECT geohash, bbox_polygon(geohash_bbox(geohash)) polygon FROM UNNEST([ "wv","wy","wu","ws","x5","xh","xj","xk","xn","xp","xr","z0","z2" ]) AS geohash ), c2 AS ( SELECT g.geohash, polygon_id FROM geo_dataset.japan as j LEFT JOIN g ON ST_INTERSECTS(g.polygon, j.city_polygon) ) SELECT * FROM c2 ORDER BY 1,2 LIMIT 10 3 จࣈʹରԠ͢Δʹ͸͜ͷΑ͏ʹ͠·͢ɻ2 จࣈͷ GeoHash ʹશ௨ΓͷจࣈΛ຤ඌʹ௥Ճ͠ɺ3 จ 72
  68. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ ࣈͷ

    GeoHash Λ࡞Γ·͢ɻͦͷޙɺ3 จࣈͷ GeoHash ͱަࠩ͢ΔϙϦΰϯʹߜΓࠐΈ·͢ɻ -- (Ϣʔβʔఆٛؔ਺ʹଓ͚ͯ) WITH g AS ( SELECT geohash, bbox_polygon(geohash_bbox(geohash)) polygon FROM UNNEST([ "wv","wy","wu","ws","x5","xh","xj","xk","xn","xp","xr","z0","z2" ]) AS geohash ), c2 AS ( SELECT g.geohash, polygon_id FROM geo_dataset.japan as j LEFT JOIN g ON ST_INTERSECTS(g.polygon, j.city_polygon) ), c3 as ( SELECT cp.geohash || last_letter AS geohash, j.polygon_id FROM c2 AS cp, UNNEST(SPLIT("0123456789bcdefghjkmnpqrstuvwxyz", "")) AS last_letter JOIN geo_dataset.japan AS j USING (polygon_id) WHERE ST_INTERSECTS( bbox_polygon(geohash_bbox(cp.geohash || last_letter )), j.city_polygon ) ) SELECT * FROM c3 ORDER BY 1,2 LIMIT 10 ಉ༷ʹςʔϒϧ໊ͷ਺ࣈΛม͑ͯίϐʔ&ϖʔετ͍͚ͯ͠͹จࣈ਺ΛͲΜͲΜ૿΍ͤ·͢ɻ7 จ ࣈ·Ͱ૿΍͠ɺҰ࣌ςʔϒϧʹอଘ͠·͢ɻ7 จࣈͷ GeoHash ͷൣғ͸໿ 120m ʷ໿ 150m ͱͳΓ ·͢ɻ 73
  69. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ ਤ

    6.5: 7 ܻͷ GeoHash άϦου query_2_3.sql -- (Ϣʔβʔఆٛؔ਺ʹଓ͚ͯ) CREATE TEMP TABLE c7 CLUSTER BY polygon_id, geohash AS WITH g AS ( SELECT geohash, bbox_polygon(geohash_bbox(geohash)) polygon FROM UNNEST([ "wv","wy","wu","ws","x5","xh","xj","xk","xn","xp","xr","z0","z2" ]) AS geohash ), c2 AS ( SELECT g.geohash, 74
  70. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ polygon_id

    FROM geo_dataset.japan as j LEFT JOIN g ON ST_INTERSECTS(g.polygon, j.city_polygon) ), c3 as ( SELECT cp.geohash || last_letter AS geohash, j.polygon_id FROM c2 AS cp, UNNEST(SPLIT("0123456789bcdefghjkmnpqrstuvwxyz", "")) AS last_letter JOIN geo_dataset.japan AS j USING (polygon_id) WHERE ST_INTERSECTS( bbox_polygon(geohash_bbox(cp.geohash || last_letter )), j.city_polygon ) ), c4 as (লུ), c5 as (লུ), c6 as ( SELECT cp.geohash || last_letter AS geohash, j.polygon_id FROM c5 AS cp, UNNEST(SPLIT("0123456789bcdefghjkmnpqrstuvwxyz", "")) AS last_letter JOIN geo_dataset.japan AS j USING (polygon_id) WHERE ST_INTERSECTS( bbox_polygon(geohash_bbox(cp.geohash || last_letter )), j.city_polygon ) ), c7 as ( SELECT cp.geohash || last_letter AS geohash, j.polygon_id, city_id, city_name_1, city_name_2, city_name_3, city_name_4 -- ࠷ޙ͚ͩࢢ۠ொଜ໊ͷ৘ใ ΛೖΕ͓ͯ͘ FROM c6 AS cp, UNNEST(SPLIT("0123456789bcdefghjkmnpqrstuvwxyz", "")) AS last_letter JOIN geo_dataset.japan AS j USING (polygon_id) WHERE ST_INTERSECTS( bbox_polygon(geohash_bbox(cp.geohash || last_letter )), j.city_polygon ) ) SELECT * FROM c7; ෳ਺ͷࢢ۠ொଜ͕ 1 ͭͷ GeoHash ʹؚ·ΕΔ৔߹ ෳ਺ͷࢢ۠ொଜ͕ 1 ͭͷ GeoHash ʹؚ·ΕΔ৔߹͸ɺҰ൪ؚ·ΕΔ໘ੵͷ޿͍ࢢ۠ொଜΛ࠾༻͢ ΔΑ͏ʹ͠·ͨ͠ɻͨͩਖ਼֬ʹܭࢉ͢Δʹ͸ɺަࠩ͢ΔྖҬΛܭࢉ͢Δ ST_INTERSECTION ؔ਺ͱɺ 75
  71. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ ͦͷ໘ੵΛܭࢉ͢Δ

    ST_AREA ؔ਺Λ૊Έ߹Θͤͯܭࢉ͠·͕͢ɺST_AREA ؔ਺͸ BigQuery Ͱ͸ͳ ͔ͥۃ୺ʹ͕͔͔࣌ؒΓ·͢ɻߴ଎ʹҰ൪޿͍ࢢ۠ொଜΛۙࣅ͢Δํ๏ͱͯ͠ɺ΋͏Ұจࣈ૿΍ͨ͠ 8 จࣈͷ GeoHash ΛඞཁͳൣғͰͷΈ༻ҙ͠ɺࢢ۠ொଜؚ͕·Ε͍ͯΔ਺Ͱ໘ੵΛۙࣅ͢Δํ๏͕ ൺֱతߴ଎ʹಈ࡞͠·ͨ͠ɻ͋Δఔ౓ߦ਺ͷ͋Δ SQL ΫΤϦͰ͕͢ɺ1 ෼൒ఔ౓Ͱ׬ྃ͠·͢ɻ query_3_3.sql -- (Ұ࣌ςʔϒϧఆٛ c7ʹଓ͚ͯ) CREATE OR REPLACE TABLE geo_dataset.japan_geohash7 cluster by geohash as WITH city_count_by_geohash AS ( -- 7ܻGeoHashʹؚ·ΕΔࢢ۠ொଜΛ਺͑Δ SELECT geohash, COUNT(DISTINCT city_name_1 || city_name_4) city_count FROM c7 GROUP BY 1 ), city_area_by_geohash AS ( -- 7ܻGeoHashʹෳ਺ͷࢢ۠ொଜΛؚΉ৔߹͸ɺ8ܻͰ͸͍ͭ͘ͷλΠϧΛऔ ΕΔ͔਺͑Δ SELECT geohash, city_id, city_name_1, city_name_2, city_name_3, city_name_4, COUNT(distinct c) cnt, -- 8ܻͷGeoHashͷ਺ ARRAY_AGG(distinct polygon_id) polygon_ids -- ࢢ۠ொଜͷϙϦΰϯͷҰཡ FROM ( SELECT cp.geohash, c, j.city_id, j.polygon_id, cp.city_name_1, cp.city_name_2, cp.city_name_3, cp.city_name_4 FROM c7 AS cp, UNNEST(SPLIT("0123456789bcdefghjkmnpqrstuvwxyz", "")) AS c JOIN (SELECT geohash FROM city_count_by_geohash WHERE city_count >= 2) USING (geohash) JOIN geo_dataset.japan AS j USING (polygon_id) WHERE ST_INTERSECTS(bbox_polygon(geohash_bbox(cp.geohash||c )), j.city_polygon) ) GROUP BY 1,2,3,4,5,6 ) -- ؚ·ΕΔࢢ۠ொଜ͕Ұͭͷ৔߹ SELECT geohash, c7.city_id, city_name_1, city_name_2, city_name_3, city_name_4, ARRAY_AGG(distinct polygon_id) polygon_ids, ARRAY_AGG(distinct c7.city_id) city_ids FROM c7 JOIN city_count_by_geohash USING (geohash) WHERE city_count = 1 GROUP BY 1,2,3,4,5,6 UNION ALL -- ؚ·ΕΔࢢ۠ொଜ͕2ͭҎ্ͷ৔߹ SELECT geohash, city_id, city_name_1, city_name_2, city_name_3, city_name_4, 76
  72. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ polygon_ids,

    city_ids FROM ( SELECT geohash, city_id, city_name_1, city_name_2, city_name_3, city_name_4 FROM city_area_by_geohash -- Ұ൪਺ͷଟ͍ࢢ۠ொଜΛબͿɻಉ཰ͷ৔߹͸IDͷए͍ॱ QUALIFY ROW_NUMBER() OVER (PARTITION BY geohash ORDER BY cnt DESC, city_id) = 1 ) JOIN( -- Ͳͷࢢ۠ொଜΛؚΉ͔ SELECT geohash, ARRAY_CONCAT_AGG(polygon_ids) polygon_ids, ARRAY_AGG(city_id) city_ids FROM city_area_by_geohash GROUP BY 1 ) USING (geohash) ͜ͷΑ͏ʹੜ੒ͨ͠ 7 ܻͷ GeoHash ʹΑΔڥքʢࠇઢʣͱ࣮ࡍͷڥքʢ੺ઢʣΛॏͶΔͱਤ 6.6 ͷΑ͏ʹͳΓ·͢ɻਫ਼౓Λ GeoHash ʹΑΔਪఆ͕ਖ਼͘͠ڥք಺Ͱ͋Δׂ߹ͱఆٛ͢Δͱɺࢢ۠ொଜ ͷ໘ੵ͕޿͍஍ҬͰ͸ඞવతʹߴ͘ͳΓɺւԊ͍ͷ஍ҬͰ͸௿͘ͳΓ·͢ɻ౦ژ౎ଟຎ஍ҬͰ͸ 96 ʙ99 ˋఔ౓ɺ೔ຊશମͷฏۉ͸໿ 98.6 ˋʹͳΓ·ͨ͠ɻ 77
  73. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.3 GeoHash-ࢢ۠ொଜςʔϒϧ ਤ

    6.6: ौ୩۠෇ۙͷ GeoHash ʹΑΔ۠ڥ ˙ίϥϜ: GIS ιϑτΛ༻͍ͨ஍ਤͷ࡞੒ ຊষͰ͸͍͔ͭ͘ͷ஍ਤΛࢀߟը૾ͱͯ͠ૠೖ͍ͯ͠·͢ɻ͜ΕΒ͸ QGIS ͱ͍͏ϑϦʔͷ GIS ιϑτͰ࡞੒͍ͯ͠·͢ɻBigQuery Ͱ஍ཧ৘ใΛදݱ͢Δ GEOGRAPHY ܕΛ CSV ͳ ͲͰग़ྗ͢ΔͱɺWell-known text(WKT) ܗࣜͰग़ྗ͞Ε·͢ɻ BigQuery Ͱूܭͨ݁͠ՌΛ CSV Ͱग़ྗ͠ QGIS ʹऔΓࠐΉ͜ͱͰɺਤ 6.6 ͳͲ͸࡞੒ͯ͠ ͍·͢ɻ·ͨ WKT ܗࣜ͸୯७ͳςΩετͰ͢ͷͰɺϧʔϓΛճͯ͠ॎઢͱԣઢΛ WKT Ͱه ड़͠ɺਤ 6.3 ͳͲ͸࡞੒͍ͯ͠·͢ɻ ·ͨɺഎܠͷ஍ਤλΠϧ͸ OpenStreetMap*7Λ༻͍͍ͯ·͢ɻ 78
  74. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.4 ύϑΥʔϚϯεଌఆ 6.4

    ύϑΥʔϚϯεଌఆ Ң౓ɾܦ౓Ͱදݱ͞Εͨ࠲ඪ͕ɺͲͷ౎ಓ෎ݝɾࢢ۠ொଜʹଘࡏ͢Δͷ͔ɺBigQuery ্Ͱ൑ఆ͢ Δ͜ͱʹཱͪ໭Γ·͢ɻ ௨ৗ͸ɺϙϦΰϯʹରͯ͠ ST_CONTAINS ؔ਺Λ༻͍ͨ಺෦൑ఆΛߦ͍ɺ͜͏͍ͬͨ൑ఆΛߦ͍· ͢ɻGeoHash Λ༻͍Δͱɺਫ਼౓Λएׯ٘ਜ਼ʹ͢Δ͜ͱͰύϑΥʔϚϯε͕ྑ͘ͳΓ·͢ɻ ೔ຊࠃ಺ͷ࠲ඪΛҰ༷ʹϥϯμϜʹੜ੒͠ɺύϑΥʔϚϯεܭଌΛߦ͍·͢ɻ࣍ͷΑ͏ͳूܭΛ ߦ͍ɺ࣮ߦ࣌ؒͱεϩοτফඅ࣌ؒΛൺֱ͠·͢ɻද 6.6 ʹࣔͨ݁͠Ռ͸ 3 ճͷࢼߦͷதԝ஋Ͱ͢ɻ 100 ສߦ·Ͱ͸͋·ΓύϑΥʔϚϯεʹ͕ࠩ͋Γ·ͤΜ͕ɺ1000 ສߦҎ্Ͱ͸໌Β͔ͳ͕ࠩੜ·Ε ·ͨ͠ɻ BigQuery ͷ࣮ߦ࣌ؒ͸࣮ࡍʹֻ͔ͬͨ࣌ؒͰ͢ɻεϩοτফඅ࣌ؒ͸ʮফඅͨ͠εϩοτ਺ʷ࣌ ؒʯͰ͢ɻσϑΥϧτͷΦϯσϚϯυྉۚϞσϧͷ৔߹͸ BigQuery ͷΫΤϦͷ࣮ߦྉۚ͸σʔλε Ωϟϯྔʹൺྫ͢ΔͨΊɺεϩοτΛେྔʹ࢖ͬͨͱ͜ΖͰྉۚͷ৺഑͸͋Γ·ͤΜ͕ɺϓϩδΣΫ τ͋ͨΓͷεϩοτͷׂΓ౰ͯ͸ܾ·͍ͬͯ·͢ɻεϩοτΛେྔʹফඅ͢ΔΫΤϦΛ͍ͭ͘΋ฒྻ Ͱ࣮ߦ͢Δͱ஗͘ͳΓ·͢ɻ GeoHash Λ༻͍ͨํ๏.sql SELECT city_name_1, city_name_2, city_name_3, city_name_4, COUNT(1) c FROM geo_dataset.japan_random_places JOIN geo_dataset.geohash g ON ST_GEOHASH(ST_GEOGPOINT(lng, lat), 7) = g.geohash WHERE id BETWEEN 1 AND 4000000000 GROUP BY 1,2,3,4 ORDER BY 5 DESC; ௨ৗͷํ๏.sql SELECT city_name_1, city_name_2, city_name_3, city_name_4, COUNT(1) c FROM geo_dataset.japan_random_places JOIN geo_dataset.japan j ON ST_CONTAINS(j.city_polygon, ST_GEOGPOINT(lng,lat)) WHERE id BETWEEN 1 AND 4000000000 GROUP BY 1,2,3,4 ORDER BY 5 DESC; *8 ˜ OpenStreetMap ϥΠηϯε: https://www.openstreetmap.org/copyright/ja 79
  75. ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴ଎ͳࢢ۠ொଜ൑ఆ 6.5 ͓ΘΓʹ ද

    6.6: ࢢ۠ொଜ͝ͱͷ݅਺Λ਺͑ͨ৔߹ͷ࣮ߦ࣌ؒʢׅހ͸εϩοτফඅ࣌ؒʣ ର৅ͷߦ਺ GeoHash ST_CONTAINS 10 ສߦ 1s ະຬ (1s) 3s(5s) 100 ສߦ 3s(10s) 14s(17s) 1000 ສߦ 1s(38s) 1m5s(36m) 1 ԯߦ 2s(3m12s) 1m9s(2h10m) 5 ԯߦ 6s(16m) 1m33s(9h30m) 10 ԯߦ 14s(43m) 1m50s(20h10m) 40 ԯߦ 9s(4h21m) 4m29s(3d18h) 6.5 ͓ΘΓʹ BigQuery ্Ͱ GeoHash Λ༻͍ͯ఺͕ڥք಺ʹଘࡏ͢Δ͔Ͳ͏͔ͷ൑ఆΛɺେྔͷσʔλʹର͠ ͯߴ଎ʹߦ͏ํ๏Λࣔ͠·ͨ͠ɻࢢ۠ொଜҎ֎ͷσʔλʹରͯ͠΋ద༻Ͱ͖·͕͢ɺൣғͱඞཁͳਫ਼ ౓ʹԠͯ͡ GeoHash ͷܻ਺Λదٓௐઅ͢Δͱྑ͍Ͱ͠ΐ͏ɻ 80
  76. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 Android Λ౥ࡌ͢ΔσόΠεͷܗଶ͸ϓϥοτϑΥʔϜͷਐԽͱͱ΋ʹଟ༷Խ͍ͯ͠·͢ɻۙ೥ Ͱ͸ɺෳ਺ͷը໘Λ౥ࡌ͢ΔંΓͨͨΈࣜσόΠε΍ Chromebook

    ͷΑ͏ͳେը໘σόΠεͳͲʹ ࠷దԽ͞Εͨ UX Λఏڙ͢Δ͜ͱ͕ߴ඼࣭ͳΞϓϦͷࢦඪͷҰͭͱͳ͍ͬͯ·͢*1ɻ ͜ͷΑ͏ͳσόΠεͷଟ༷Խͱͱ΋ʹɺಈը࠶ੜΞϓϦΛ։ൃ͢ΔࡍͷϕετϓϥΫςΟε͸ࠁʑ ͱมԽ͖ͯ͠·ͨ͠ɻ ฐ͕ࣾఏڙ͍ͯ͠ΔΧϥΦέಈըίϛϡχςΟʮKARASTAʯ *2Ͱ͸ɺϢʔβʔ͕౤ߘͨ͠ಈը΍ ϥΠϒ഑৴Λշదʹࢹௌ͢ΔͨΊͷ඼࣭޲্ʹ஫ྗ͖ͯ͠·ͨ͠ɻຊষͰ͸ɺ2022 ೥ʹಈը࠶ੜΞ ϓϦΛ࡞Δͱͨ͠ΒͲͷΑ͏ʹ࣮૷͢Ε͹Α͍ͷ͔ɺ۩ମతͳϢʔεέʔεͱͱ΋ʹղઆ͠·͢ɻ 7.1 2022 ೥Ҏલͷྺ࢙ΛৼΓฦΔ Android ͷϝδϟʔόʔδϣϯ্͕͕ΔͱɺͦΕʹରԠͨ͠ API Level ͷ Android SDK ͕ϦϦʔ ε͞Ε·͢ɻݱ࣌఺Ͱ͸ Android 13 ʹରԠͨ͠ API Level 33 ͷ SDK ͕ར༻ՄೳͰ͢ɻ ԼҐޓ׵ੑΛอͪͳ͕Β࠷৽ͷ SDK ͷػೳΛ׆༻͢ΔͨΊʹɺJetpack ͱݺ͹ΕΔϥΠϒϥϦ܈ ͕ެࣜʹఏڙ͞Ε͍ͯ·͢ɻ2022 ೥ݱࡏͰ͸ Jetpack Λ׆༻ͯ͠ΞϓϦΛ։ൃ͢Δํ๏͕Ұൠతʹ ͳ͍ͬͯ·͢ɻ ຊઅͰ͸ Android SDK ͱ Jetpack ͷྺ࢙ΛৼΓฦΓɺಈը࠶ੜΞϓϦͷ࣮૷ํ๏͕ͲͷΑ͏ͳม ભΛͨͲ͖ͬͯͨͷ͔Λղઆ͠·͢ɻ 2008 ೥: MediaPlayer Android SDK ʹ͸ϦϦʔε౰ॳ͔Βಈը΍Ի੠Λ࠶ੜ͢ΔͨΊͷΫϥε (MediaPlayer) ͕ଘࡏ ͠·͢ɻ·ͨɺMediaPlayer Ͱ࠶ੜ͍ͯ͠ΔಈըΛ View ͱͯ͠දࣔ͢ΔͨΊͷ UI ίϯϙʔωϯτ *1 https://developer.android.com/quality *2 https://karasta.net/ 81
  77. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.1 2022 ೥Ҏલͷྺ࢙ΛৼΓฦΔ (VideoView)

    ΋ؚ·Ε͍ͯ·͢ɻ ͜ΕΒ͸ API Level 33 ͱͳͬͨݱࡏͰ΋ར༻Ͱ͖·͢ɻ͔͠͠ͳ͕ΒɺݱࡏͰ͸ MediaPlayer ΍ VideoView Λ࢖ͬͯಈըϓϨΠϠʔΛ࣮૷͢Δέʔε͸গͳ͘ͳΓ·ͨ͠ɻ୅ΘΓʹ ExoPlayer ͱ ͍͏ϥΠϒϥϦΛ༻͍࣮ͨ૷ํ๏͕Ұൠతʹͳ͍ͬͯ·͢ɻ͜Εʹ͍ͭͯ͸࣍ͷઅͰৄ͘͠ղઆ͠ ·͢ɻ 2014 ೥: MediaSession ͜ͷ೥ʹ͸΢ΣΞϥϒϧσόΠε޲͚ͷ Android Wear ΍ंࡌσόΠε޲͚ͷ Android Auto ͕ ൃද͞Ε·ͨ͠ɻͦΕʹ൐͍ɺεϚʔτϑΥϯͱ֎෦σόΠε͕࿈ܞͯ͠ಈ࡞͢ΔΞϓϦ͕׆ൃʹ։ ൃ͞ΕΔΑ͏ʹͳΓ·ͨ͠ɻAndroid 5.0 (API Level 21) Ͱ͸ɺ͜ͷ࿈ܞΛ࣮ݱ͢ΔͨΊͷ৽͍͠ ͘͠Έͱͯ͠ MediaSession ͕ಋೖ͞Ε·ͨ͠*3ɻ ΞϓϦ͸ϝσΟΞͷ࠶ੜঢ়ଶ (λΠτϧɺΞʔτϫʔΫɺ࠶ੜҐஔͳͲ) Λ MediaSession Λ௨͡ ͯ OS ʹެ։͠·͢ɻOS ͸ϝσΟΞͷঢ়ଶΛ֎෦σόΠεͳͲʹදࣔ͠·͢ɻٯʹɺ֎෦͔Βͷϝ σΟΞίϯτϩʔϧίϚϯυ (࠶ੜɺఀࢭɺγʔΫͳͲ) ͕ MediaSession Λ௨ͯ͡ΞϓϦʹ௨஌͞ Ε·͢ɻ ਤ 7.1: MediaSession MediaSession ͸ Jetpack Media ϥΠϒϥϦͱͯ͠΋ఏڙ͞Ε͓ͯΓɺ͜ΕΛ࢖͏ͱ؆୯ʹ MediaSession Λ࣮૷Ͱ͖ΔΑ͏ʹͳ͍ͬͯ·͢ɻৄ͘͠͸࣍ͷઅͰղઆ͠·͢ɻ *3 Android 4.0 ͷ࣌఺ͰϩοΫը໘ͳͲ͔ΒϝσΟΞΛίϯτϩʔϧ͢ΔͨΊͷ API (RemoteControlClient) ͕௥Ճ ͞Ε͍ͯ·͕ͨ͠ɺMediaSession ͷొ৔ͱͱ΋ʹඇਪ঑ʹͳΓ·ͨ͠ɻ 82
  78. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.1 2022 ೥Ҏલͷྺ࢙ΛৼΓฦΔ 2017

    ೥: Picture-in-Picture Android 8.0 (API Level 26) Ͱ͸ Picture-in-Picture (PiP) ͷػೳ͕௥Ճ͞Ε·ͨ͠*4ɻPiP ͸ ΞϓϦͷը໘Λখ͞ͳ΢Οϯυ΢ͱͯ͠දࣔ͢ΔػೳͰ͢ɻ͜ΕʹΑͬͯɺϢʔβʔ͸ಈըΛࢹௌ͠ ͳ͕Β΄͔ͷλεΫΛ͜ͳ͢͜ͱ͕Ͱ͖ΔΑ͏ʹͳΓ·ͨ͠ɻ͜ͷ͋ͨΓ͔ΒΞϓϦ։ൃͷைྲྀ͸γ ϯάϧ΢Οϯυ΢ͷ࣌୅͔ΒϚϧν΢Οϯυ΢ͷ࣌୅ʹҠΓมΘ͍͖ͬͯ·͢ɻ ਤ 7.2: Picture-in-Picture*5 2020 ೥: Jetpack WindowManager Android 10 (API Level 29) Ͱ͸Ϛϧν΢Οϯυ΢ͷαϙʔτ͕͞ΒʹڧԽ͞ΕɺંΓͨͨΈࣜσ όΠε΍େը໘σόΠεʹ࠷దԽ͞Εͨ UI Λఏڙ͢ΔͨΊͷ API ͕௥Ճ͞Ε·ͨ͠ɻ·ͨɺ΢Οϯ υ΢ͷঢ়ଶݕ஌ͷͨΊͷϥΠϒϥϦͱͯ͠ Jetpack WindowManager ͕৽ͨʹϦϦʔε͞Ε·ͨ͠ɻ 2022 ೥ݱࡏͰ͸ϚςϦΞϧσβΠϯͷΨΠυϥΠϯͰંΓͨͨΈࣜσόΠε΍େը໘σόΠε޲ ͚ͷ UI Λߏங͢Δํ๏͕ࣔ͞Ε͍ͯ·͢*6ɻಈը࠶ੜΞϓϦʹ͓͍ͯ͸ɺંΓͨͨΈͷঢ়ଶʹԠ͡ ͯಈըϓϨΠϠʔͷϨΠΞ΢τΛมߋ͢Δ͜ͱʹΑΔ UX ͷ޲্͕ظ଴Ͱ͖·͢ɻ ਤ 7.3: ંΓͨͨΈࣜσόΠε *4 Android 7.0 ͷ࣌఺ͰΞϓϦΛ෼ׂදࣔ͢ΔϚϧν΢Οϯυ΢Ϟʔυ͕αϙʔτ͞Ε͍ͯ·͕ͨ͠ɺPiP ͸ Android TV ͷΈͰར༻Ͱ͖ΔػೳͰͨ͠ɻ *5 Big Buck Bunny, ˜ 2008, Blender Foundation / www.bigbuckbunny.org *6 https://m3.material.io/foundations/adaptive-design/overview 83
  79. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.2 ExoPlayer ͱ Jetpack

    Media3 ʹ͍ͭͯ ͜͜·Ͱड़΂ͨΑ͏ʹɺಈը࠶ੜΞϓϦΛ։ൃ͢ΔࡍʹٻΊΒΕΔػೳཁ݅͸ Android ͷਐาͱ ͱ΋ʹଟ༷Խ͍ͯ͠·͢ɻ࣍ͷઅͰ͸ɺ͜Ε·Ͱʹ঺հͨ͠ػೳΛ࣮૷͢ΔͨΊʹ༻͍ΔϥΠϒϥϦ ʹ͍ͭͯ঺հ͠·͢ɻ 7.2 ExoPlayer ͱ Jetpack Media3 ʹ͍ͭͯ ExoPlayer ͸ Google ͕։ൃ͍ͯ͠ΔϝσΟΞ࠶ੜϥΠϒϥϦͰ͢ɻετϦʔϛϯάܗࣜͷϝσΟ Ξͷ࠶ੜ΍޿ࠂͷૠೖͳͲɺMediaPlayer ʹ͸ͳ͍ଟ͘ͷػೳΛඋ͍͑ͯ·͢ɻ ҰํɺJetpack ϥΠϒϥϦͷҰͭͰ͋Δ Jetpack Media2 ʹ΋ϝσΟΞ࠶ੜػೳ͕͋Γɺॏෳͨ͠ ػೳΛ࣋ͭ 2 ͭͷϥΠϒϥϦ͕ڞଘ͍ͯ͠·ͨ͠ɻ͞ΒʹɺJetpack Media2 ͷ MesiaSession ͷػ ೳͱ ExoPlayer Λ࿈ܞͤ͞ΔͨΊͷ ExoPlayer Extension ΋ެ։͞Ε͓ͯΓɺMediaSession ͷ࣮ ૷ํ๏͕ෳࡶԽ͍ͯ͠·ͨ͠ɻ ਤ 7.4: Jetpack Media2 ͱ ExoPlayer 2021 ೥ 10 ݄ɺ͜ΕΒͷ໰୊Λղܾͨ͠৽͍͠ Jetpack ϥΠϒϥϦͰ͋Δ Jetpack Media3*7͕ൃ ද͞Ε·ͨ͠ɻMedia3 ʹ͸ ExoPlayer ͕౷߹͞Ε͓ͯΓɺϝσΟΞ࠶ੜʹؔ͢Δ͞·͟·ͳϢʔε έʔεΛ୯ҰͷϥΠϒϥϦʹΑͬͯ؆୯ʹ࣮ݱͰ͖ΔΑ͏ʹͳΓ·ͨ͠ɻ ౰໘ͷؒ͸ैདྷͷ ExoPlayer ͱ Media3 ͕ฒߦͯ͠ϦϦʔε͞Ε·͕͢ɺैདྷͷ ExoPlayer ͸ক དྷతʹඇਪ঑ʹͳΔͨΊɺMedia3 ΁ͷҠߦ͕ਪ঑͞Ε͍ͯ·͢ɻ࠷৽ͷόʔδϣϯͷ ExoPlayer Λ ར༻͍ͯ͠Δ৔߹ɺجຊతʹ͸ύοέʔδ໊΍Ұ෦ͷΫϥε໊Λஔ׵͢Δ͚ͩͰ Media3 ΁ͷҠߦ͕ ׬ྃ͠·͢ɻ͞Βʹɺ͜ͷҠߦ࡞ۀΛࣗಈԽ͢ΔͨΊͷεΫϦϓτ΋ެ։͞Ε͍ͯ·͢*8ɻ Ҏ߱ͷ಺༰Ͱ͸ɺ͜ͷ Media3 Λ༻͍ͯಈը࠶ੜΞϓϦΛ࡞੒͢Δํ๏Λ঺հ͠·͢ɻ *7 https://developer.android.com/jetpack/androidx/releases/media3 *8 https://developer.android.com/guide/topics/media/media3/getting-started/migration-guide 84
  80. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ

    ຊઅͰ͸ɺ·ͣ࢝Ίʹ Jetpack Media3 Λ༻͍ͯγϯϓϧͳಈը࠶ੜΞϓϦΛ࡞੒͠ɺ࣍ʹ MediaSession ΍ PiP ͳͲͷߴ౓ͳػೳΛ௥Ճ͢Δํ๏Λ঺հ͠·͢ɻ γϯϓϧͳಈը࠶ੜΞϓϦ ·ͣ͸࠷΋؆୯ͳಈը࠶ੜΞϓϦΛߟ͑·͢ɻ͜ͷΞϓϦͷΞʔΩςΫνϟͱ࣮૷ྫΛ࣍ʹࣔ͠ ·͢ɻ ਤ 7.5: γϯϓϧͳಈը࠶ੜΞϓϦͷΞʔΩςΫνϟ PlayerActivity.kt class PlayerActivity : AppCompatActivity() { private lateinit var player: ExoPlayer override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // PlayerViewΛදࣔ͢Δ val playerView = PlayerView(this) setContentView(playerView) // PlayerΛ࡞੒ͯ͠PlayerViewʹηοτ͢Δ player = ExoPlayer.Builder(this).build() playerView.player = player // ϩʔΧϧ·ͨ͸ωοτϫʔΫ্ͷಈըͷUriΛࢦఆ͢Δ val mediaItem = MediaItem.fromUri(...) player.setMediaItem(mediaItem) } override fun onStart() { super.onStart() // ϑΥΞάϥ΢ϯυʹͳͬͨΒ࠶ੜΛ࢝ΊΔ player.prepare() 85
  81. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ player.play() }

    override fun onStop() { super.onStop() // όοΫάϥ΢ϯυʹͳͬͨΒ࠶ੜΛࢭΊΔ player.stop() } override fun onDestroy() { super.onDestroy() // PlayerͷϦιʔεΛղ์͢Δ player.release() } } ͜ͷྫͰ͸ΞϓϦ͕όοΫάϥ΢ϯυʹͳ͍ͬͯΔؒ͸࠶ੜΛఀࢭ͢ΔΑ͏ʹ͍ͯ͠·͢ɻPlayer ͷΠϯελϯε͸ෆཁʹͳͬͨλΠϛϯάͰղ์͢Δඞཁ͕͋ΔͨΊɺΞΫςΟϏςΟͷ onDestro y() Ͱղ์͍ͯ͠·͢ɻ ϩʔΧϧ·ͨ͸ωοτϫʔΫ্ͷಈըʹΞΫηε͢Δʹ͸దٓύʔϛογϣϯΛઃఆ͢Δඞཁ͕͋ Γ·͕͢ɺຊষͷείʔϓ͔Β͸গ͠֎ΕΔͨΊઆ໌ΛׂѪ͠·͢ɻ MediaSessionService Λ༻͍ͨόοΫάϥ΢ϯυ࠶ੜ લड़ͷ࣮૷Ͱ͸ΞΫςΟϏςΟ͕ Player Λอ͍࣋ͯ͠ΔͨΊɺը໘ճసͳͲʹΑͬͯΞΫςΟϏ ςΟ͕ഁغ͞ΕΔͱ Player ΋ղ์͞Εͯ͠·͍·͢ɻ͜ΕΛ๷͙ͨΊʹ͸ϑΥΞάϥ΢ϯυαʔϏ ε*9Λ࢖༻͠·͢ɻPlayer ͷΠϯελϯεΛΞΫςΟϏςΟͰ͸ͳ͘ϑΥΞάϥ΢ϯυαʔϏεʹ อ࣋ͤ͞Δ͜ͱͰɺΞΫςΟϏςΟ͕ഁغ͞Εͯ΋ϝσΟΞͷ࠶ੜΛଓߦͤ͞Δ͜ͱ͕Ͱ͖·͢ɻ Media3 ʹ͸͜ΕΛ؆୯ʹ࣮ݱ͢ΔͨΊͷΫϥεͰ͋Δ MediaSessionService ؚ͕·Ε͍ͯ·͢ɻ MediaSessionService ͸࣍ͷ͜ͱΛࣗಈతʹߦ͍·͢ɻ • ϑΥΞάϥ΢ϯυαʔϏεΛ࣮ߦ͢Δ • ௨஌ྖҬʹϝσΟΞΛίϯτϩʔϧ͢Δ UI Λදࣔ͢Δ • MediaSession Λ֎෦ʹެ։͢Δ ϝσΟΞͷίϯτϩʔϧ͸͢΂ͯ MediaSession Λհͯ͠ߦΘΕΔͨΊɺBluetooth ϔουηο τ΍ Wear OS ͳͲΛ࢖ͬͯಈըΛ࠶ੜ/ఀࢭ͢Δ͜ͱ΋ՄೳʹͳΓ·͢ɻ͜ͷΞϓϦͷΞʔΩςΫ νϟ͸࣍ͷΑ͏ʹͳΓ·͢ɻ *9 https://developer.android.com/guide/components/foreground-services 86
  82. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ ਤ 7.6:

    MediaSessionService Λ༻͍ͨಈը࠶ੜΞϓϦͷΞʔΩςΫνϟ MediaSessionService Λ࢖༻͢Δʹ͸ɺҎԼͷΑ͏ʹ MediaSessionService Λܧঝͨ͠αʔϏεΛ ࡞੒͠ɺAndroidManifest ʹ௥Ճ͠·͢ɻ PlayerService.kt class PlayerService : MediaSessionService() { private lateinit var player: ExoPlayer private lateinit var mediaSession: MediaSession private val mediaSessionCallback = object : MediaSession.Callback { override fun onAddMediaItems( mediaSession: MediaSession, controller: MediaSession.ControllerInfo, mediaItems: MutableList<MediaItem> ) = Futures.immediateFuture(mediaItems.map { mediaItem -> // MediaController͔Β౉͞ΕͨUriΛ࠶ੜ͢ΔͨΊʹඞཁͳॲཧ mediaItem.buildUpon() .setUri(mediaItem.requestMetadata.mediaUri) .build() }) } override fun onCreate() { super.onCreate() player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player) .setCallback(mediaSessionCallback) .build() } override fun onDestroy() { player.release() mediaSession.release() 87
  83. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ super.onDestroy() }

    override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = mediaSession } AndroidManifest.xml <service android:name=".PlayerService" android:exported="false" android:foregroundServiceType="mediaPlayback"> <intent-filter> <action android:name="androidx.media3.session.MediaSessionService" /> </intent-filter> </service> αʔϏε্Ͱ MediaSession ͱ ExoPlayer ͷΠϯελϯεΛ࡞੒͠ɺ onGetSession() ΛΦʔόʔ ϥΠυͯ͠ MediaSession Λฦ͠·͢ɻ͜͜Ͱ࡞੒ͨ͠ ExoPlayer ͸αʔϏεͷ֎෦͔Β௚઀ΞΫ ηε͞ΕΔ͜ͱ͸͋Γ·ͤΜɻ֎෦͔ΒͷϝσΟΞίϯτϩʔϧ͸͢΂ͯ MediaSession Λհͯ͠ߦ ΘΕ·͢ɻ ΞΫςΟϏςΟ͔ΒϝσΟΞΛίϯτϩʔϧ͢ΔྫΛҎԼʹࣔ͠·͢ɻ PlayerActivity.kt val sessionToken = SessionToken(this, ComponentName(this, PlayerService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener({ // MediaController͸ExoPlayerͱಉ͘͡PlayerΠϯλϑΣʔεΛ࣮૷͍ͯ͠Δ val mediaController = controllerFuture.get() playerView.player = mediaController // ಈըιʔεΛࢦఆ val requestMetadata = MediaItem.RequestMetadata.Builder() .setMediaUri(...) .build() val mediaItem = MediaItem.Builder() .setRequestMetadata(requestMetadata) .build() mediaController.setMediaItem(mediaItem) // ࠶ੜ։࢝ mediaController.prepare() mediaController.play() 88
  84. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ }, MoreExecutors.directExecutor())

    SessionToken Λ࢖͏ͱ MediaSession ͔Β MediaController ΛऔಘͰ͖·͢ɻMediaController ͸ Player ΠϯλϑΣʔεΛ࣮૷͍ͯ͠·͢ɻ·ͨɺαʔϏε্ʹ͋Δ ExoPlayer ΋ಉ༷ʹ Player ΠϯλϑΣʔεΛ࣮૷͍ͯ͠·͢ɻ͢ͳΘͪɺMediaController Λऔಘ͢Δͱ ExoPlayer ͱಉ͡Π ϯλϑΣʔεΛ༻͍ͯϝσΟΞΛίϯτϩʔϧͰ͖·͢ɻ Picture-in-Picture ΞϓϦʹ PiP ͷػೳΛ௥Ճ͢Δεςοϓ͸ҎԼͷ 3 ͭͰ͢ɻ 1. AndroidManifest ͰΞΫςΟϏςΟͷઃఆΛมߋ͢Δ 2. ΞΫςΟϏςΟΛ PiP Ϟʔυʹ੾Γସ͑ΔॲཧΛ௥Ճ͢Δ 3. ΞΫςΟϏςΟ͕ PiP Ϟʔυʹͳͬͨͱ͖ʹ UI Λߋ৽͢Δ 1. AndroidManifest ͰΞΫςΟϏςΟͷઃఆΛมߋ͢Δ AndroidManifest.xml <activity android:name=".PlayerActivity" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:supportsPictureInPicture="true" /> AndroidManifest Ͱ android:supportsPictureInPicture Λ true ʹ͢ΔͱɺΞΫςΟϏςΟ ͕ PiP ϞʔυʹରԠ͍ͯ͠Δ͜ͱΛએݴͰ͖·͢ɻPiP ϞʔυʹભҠͨ͠ͱ͖ʹΞΫςΟϏςΟ͕ ࠶ੜ੒͞ΕΔͷΛ๷͙ͨΊɺandroid:configChanges ͷઃఆ΋௥Ճ͠·͢ɻ 2. ΞΫςΟϏςΟΛ PiP Ϟʔυʹ੾Γସ͑ΔॲཧΛ௥Ճ͢Δ Activity.enterPictureInPictureMode() Λ࣮ߦ͢ΔͱɺΞΫςΟϏςΟ͕ PiP Ϟʔυʹ੾Γ ସΘΓ·͢ɻUI ্ͷϘλϯΛλοϓͨ͠ͱ͖ʹ PiP Ϟʔυʹ੾Γସ͍͑ͨ৔߹͸ɺϘλϯͷ onCl ickListener Ͱ͜ΕΛ࣮ߦ͠·͢ɻϢʔβʔ͕ϗʔϜը໘ʹ໭Ζ͏ͱͨ͠ͱ͖ʹࣗಈతʹ PiP Ϟʔ υʹ੾Γସ͍͑ͨ৔߹͸ɺҎԼͷΑ͏ʹ Activity.onUserLeaveHint() ΛΦʔόʔϥΠυ͠·͢ɻ PlayerActivity.kt // ϗʔϜը໘ʹ໭Δͱ͖ʹݺ͹ΕΔ override fun onUserLeaveHint() { if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) { 89
  85. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ try {

    val params = PictureInPictureParams.Builder().build() enterPictureInPictureMode(params) } catch (e: IllegalStateException) { // Ұ෦ͷσόΠεͰ͸FEATURE_PICTURE_IN_PICTURE͕༗ޮͰ΋ // PiPʹભҠ͢ΔͱΫϥογϡ͢Δ } } } PiP ͸ Android 8.0 Ͱ௥Ճ͞ΕͨػೳͰ͕͢ɺҰ෦ͷσόΠεͰ͸ Android 8.0 Ҏ߱Ͱ΋ར༻Ͱ͖ ͳ͍৔߹͕͋Γ·͢ɻFEATURE_PICTURE_IN_PICTURE ͷϑϥάΛࢀর͢ΔͱɺσόΠε͕ PiP Λα ϙʔτ͍ͯ͠Δ͔Ͳ͏͔Λ൑ผͰ͖·͢ɻ͔͠͠ͳ͕ΒɺFEATURE_PICTURE_IN_PICTURE ͕༗ޮͰ ͋Δʹ΋͔͔ΘΒͣ PiP Ϟʔυʹ͠Α͏ͱ͢ΔͱΫϥογϡ͢ΔσόΠε΋ଘࡏ͠·͢ɻϨΞέʔ εͰ͸͋Γ·͕͢ɺIllegalStateException ΛΩϟον͢Δ͜ͱʹΑͬͯΫϥογϡΛճආͰ͖·͢ɻ enterPictureInPictureMode() ͷҾ਺ͱͯ͠౉͢ PictureInPictureParams Ͱ͸ɺPiP Ϟʔυ ʹͳͬͨͱ͖ͷ΢Οϯυ΢ͷΞεϖΫτൺ΍දࣔ͢ΔϘλϯͷछྨͳͲΛઃఆͰ͖·͢ɻActivity .setPictureInPictureParams() Λ࣮ߦ͢ΔͱɺΞΫςΟϏςΟ͕ PiP Ϟʔυ͔Ͳ͏͔ʹؔ܎ͳ ͘ PictureInPictureParams Λߋ৽Ͱ͖·͢ɻಈը࠶ੜΞϓϦͷ৔߹͸ɺಈըͷΞεϖΫτൺʹԠ͡ ͯ PiP ͷ΢Οϯυ΢ͷΞεϖΫτൺΛมߋ͢Δͱྑ͍Ͱ͠ΐ͏ɻ PlayerActivity.kt mediaController.addListener(object : Player.Listener { override fun onVideoSizeChanged(videoSize: VideoSize) { if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) { try { // ಈըͷΞεϖΫτൺͱPiPͷ΢Οϯυ΢ͷΞεϖΫτൺΛҰகͤ͞Δ val params = PictureInPictureParams.Builder() .setAspectRatio(Rational(videoSize.width, videoSize.height)) .build() setPictureInPictureParams(params) } catch (e: IllegalStateException) { e.printStackTrace() } } } }) 3. ΞΫςΟϏςΟ͕ PiP Ϟʔυʹͳͬͨͱ͖ʹ UI Λߋ৽͢Δ PiP ϞʔυͰ͸ΞΫςΟϏςΟ͕খ͞ͳ΢Οϯυ΢Ͱදࣔ͞ΕΔͨΊɺΞΫςΟϏςΟʹ഑ஔͨ͠ ϘλϯͳͲ͸λοϓͰ͖ͳ͘ͳΓ·͢ɻΞΫςΟϏςΟ͕ PiP Ϟʔυʹͳͬͨͱ͖ʹಈըҎ֎ͷ UI 90
  86. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ Λඇදࣔʹ͍ͨ͠৔߹ɺҎԼͷΑ͏ʹ addOnPictureInPictureModeChangedListener()

    Λ࣮ߦ ͯ͠ PiP Ϟʔυͷ੾Γସ͑Λ؂ࢹ͠·͢ɻ PlayerActivity.kt class PlayerActivity : AppCompatActivity() { private val pipListener = Consumer<PictureInPictureModeChangedInfo> { info -> if (info.isInPictureInPictureMode) { // PlayerViewҎ֎ͷUIΛඇදࣔʹ͢Δ } else { // PlayerViewҎ֎ͷUIΛදࣔ͢Δ } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) addOnPictureInPictureModeChangedListener(pipListener) ... } override fun onDestroy() { removeOnPictureInPictureModeChangedListener(pipListener) super.onDestroy() } } addOnPictureInPictureModeChangedListener() ͸ Jetpack ͷ ComponentActivity Λܧঝ͠ ͨΞΫςΟϏςΟͰར༻Ͱ͖·͢ɻJetpack Λར༻͍ͯ͠ͳ͍৔߹͸ΞΫςΟϏςΟͷ onPictureI nPictureModeChanged() ΛΦʔόʔϥΠυͯ͠ PiP ϞʔυΛ؂ࢹ͠·͢ɻ PlayerActivity.kt override fun onPictureInPictureModeChanged( isInPictureInPictureMode: Boolean, newConfig: Configuration ) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) if (isInPictureInPictureMode) { // PlayerViewҎ֎ͷUIΛඇදࣔʹ͢Δ } else { // PlayerViewҎ֎ͷUIΛදࣔ͢Δ } } 91
  87. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ Jetpack Compose

    Ͱ PlayerView Λදࣔ͢Δ ࠷ۙͰ͸ View Ͱ͸ͳ͘ Jetpack Compose Λ༻͍ͯ UI Λߏங͢Δέʔε͕ଟ͘ͳ͍ͬͯ·͢ɻ ͔͠͠ͳ͕Β Media3 ͷϓϨΠϠʔ UI ͸ View ͱ࣮ͯ͠૷͞Ε͓ͯΓɺCompose ޲͚ͷ API ͸ࠓ ͷͱ͜Ζఏڙ͞Ε͍ͯ·ͤΜɻ Compose Ͱߏஙͨ͠ UI ্Ͱ PlayerView Λද͍ࣔͨ͠৔߹ɺҎԼͷΑ͏ʹ Compose ͱ View ͷ ૬ޓӡ༻ API Λ࢖༻͠·͢ɻ val playerView = remember { PlayerView(context) } DisposableEffect( AndroidView(factory = { playerView }) ) { // ը໘Λดͨ͡ͱ͖ʹݺ͹ΕΔ onDispose { mediaController.release() } } AndroidView Λ࢖༻͢ΔͱɺComposable ͷதͰ View ΛදࣔͰ͖·͢ɻ·ͨɺը໘Λดͨ͡ͱ ͖ʹߦ͏Ϧιʔεͷղ์ॲཧ͸ DisposableEffect Λ࢖࣮ͬͯݱͰ͖·͢ɻ ંΓͨͨΈࣜσόΠε΁ͷରԠ Jetpack WindowManager Λ࢖༻͢ΔͱɺҎԼͷΑ͏ʹͯ͠ંΓͨͨΈࣜσόΠεͷঢ়ଶΛ؂ࢹ Ͱ͖·͢ɻ PlayerActivity.kt lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { WindowInfoTracker.getOrCreate(this@PlayerActivity) .windowLayoutInfo(this@PlayerActivity) .mapNotNull { layoutInfo -> layoutInfo.displayFeatures .filterIsInstance<FoldingFeature>() .firstOrNull() } .collect { foldingFeature -> // TODO ંΓͨͨΈͷঢ়ଶʹΑͬͯUIΛߋ৽͢Δ foldingFeature.state // ંΓͨͨΜͰ͍Δ͔Ͳ͏͔ foldingFeature.orientation // ંΓ໨ͷ޲͖ 92
  88. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ foldingFeature.occlusionType //

    ંΓ໨͕ը໘ΛӅ͍ͯ͠Δ͔Ͳ͏͔ foldingFeature.isSeparating // ը໘ͷྖҬ͕ંΓ໨Ͱ෼ׂ͞Ε͍ͯΔ͔Ͳ͏͔ } } } WindowInfoTracker.windowLayoutInfo() ͸ WindowLayoutInfo ͷ Flow Λฦ͠·͢ɻWin- dowLayoutInfo ʹ͸σόΠεͷંΓͨͨΈঢ়ଶΛද͢ FoldingFeature ͕֨ೲ͞Ε͍ͯ·͢ɻFold- ingFeature Λ࢖ͬͯ View ·ͨ͸ Composable ͷϨΠΞ΢τΛߋ৽͢Δ͜ͱͰɺΞϓϦͷ UI ΛંΓ ͨͨΈࣜσόΠε޲͚ʹ࠷దԽͰ͖·͢ɻ ͜͜Ͱ͸ɺCompose Ͱද͍ࣔͯ͠Δ PlayerView ΛંΓ໨ʹॏͳΒͳ͍Α͏ʹ഑ஔͤ͞Δ࣮૷ྫ Λ঺հ͠·͢ɻ PlayerScreen.kt @Composable fun PlayerScreen( foldingFeature: FoldingFeature?, modifier: Modifier = Modifier ) { val playerModifier = if (foldingFeature == null || foldingFeature.state == FoldingFeature.State.FLAT ) { // ંΓͨͨΜͰ͍ͳ͍ͷͰશը໘දࣔ͢Δ Modifier.fillMaxSize() } else { if (foldingFeature.orientation == FoldingFeature.Orientation.HORIZONTAL) { // ંΓ໨ͷ্ଆʹϓϨΠϠʔΛ഑ஔ͢Δ val playerHeight = with(LocalDensity.current) { (foldingFeature.bounds.top - WindowInsets.systemBars.getTop(this)).toDp() } Modifier .fillMaxWidth() .height(playerHeight) } else { // VERTICAL // ંΓ໨ͷࠨଆʹϓϨΠϠʔΛ഑ஔ͢Δ val playerWidth = with(LocalDensity.current) { foldingFeature.bounds.left.toDp() } Modifier .width(playerWidth) .fillMaxHeight() } } Box( modifier = modifier .fillMaxSize() .systemBarsPadding() ) { 93
  89. ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.4 ऴΘΓʹ // PlayerViewΛදࣔ͢ΔComposable

    (લͷ߲Λࢀর) VideoPlayer(modifier = playerModifier) } } ંΓ໨ͷ޲͖͕ HORIZONTAL ͷ৔߹ɺը໘͸্Լʹ෼ׂ͞Ε·͢ɻfoldingFeature.bounds Ͱ ώϯδͷը໘্ͷҐஔ͕औಘͰ͖ΔͷͰɺ͜ΕΛ࢖ͬͯ PlayerView ͷߴ͞Λܭࢉ͠·͢ɻંΓ໨ͷ ޲͖͕ VERTICAL ͷ৔߹͸ը໘͕ࠨӈʹ෼ׂ͞ΕΔͷͰɺಉ༷ʹͯ͠ PlayerView ͷ෯Λܭࢉ͠· ͢ɻ͜ͷ Composable Λදࣔ͢Δͱਤ 7.3 ͷΑ͏ʹͳΓ·͢ɻ Compose Λ༻͍ͨެࣜͷ࣮૷αϯϓϧͱͯ͠͸ Jetcaster*10͕ࢀߟʹͳΓ·͢ɻ͜ͷαϯϓϧͰ ͸্هͷྫͱಉ༷ʹંΓͨͨΈͷঢ়ଶΛ؂ࢹ͠ɺΑΓෳࡶͳϨΠΞ΢τΛߏங͍ͯ͠·͢ɻ ·ͨɺView Ͱ UI Λߏங͍ͯ͠Δ৔߹͸ ConstraintLayout Λ༻͍ͯಉ༷ͷ͜ͱ͕࣮ݱͰ͖·͢ɻ ConstraintLayout Ͱͷ࣮૷ํ๏ʹ͍ͭͯ͸ެࣜͷσϕϩούʔΨΠυ*11Λࢀর͍ͯͩ͘͠͞ɻ 7.4 ऴΘΓʹ ຊষͰ͸ 2022 ೥ 8 ݄࣌఺Ͱͷ࠷৽ͷ API Λ༻͍ͯಈը࠶ੜΞϓϦΛ։ൃ͢Δख๏ʹ͍ͭͯղઆ ͠·ͨ͠ɻࠓޙ΋৽ͨͳϑΥʔϜϑΝΫλΛ࣋ͭσόΠε͕ొ৔͠ɺͦΕʹ൐ͬͯ৽ͨͳ API ͕௥ Ճ͞ΕΔՄೳੑ͕͋Γ·͢ɻ·ͨɺݱࡏ͸ Android View γεςϜ͔Β Compose ΁ͱҠߦ͢Δա౉ ظͰ͋ΔͨΊɺಈը࠶ੜͷ UI ίϯϙʔωϯτʹؔͯ͠΋ࠓޙେ͖ͳΞοϓσʔτ͕ߦΘΕΔՄೳੑ ͕͋Γ·͢ɻ KARASTA Ͱ͸ 2022 ೥ 8 ݄ʹ Media3 Λಋೖ͠ɺMediaSession ʹΑΔϝσΟΞίϯτϩʔϧʹ ରԠ͠·ͨ͠ɻ·ͨɺݱࡏ͸৽نʹ௥Ճ͢Δը໘ͷ΄ͱΜͲΛ Jetpack Compose Ͱ࣮૷͍ͯ͠·͢ɻ ࠓޙ΋ Android ϓϥοτϑΥʔϜͷมԽʹॊೈʹదԠͰ͖ΔΑ͏ɺΞϓϦͷ඼࣭վળʹ౒Ί͍͖ͯ ͍ͨͱࢥ͍·͢ɻ *10 https://github.com/android/compose-samples/tree/main/Jetcaster *11 https://developer.android.com/training/constraint-layout/foldables 94
  90. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό ։ൃ 8.1 ͸͡Ίʹ Unity

    Transport ͸ɺ௿ਫ४ͳωοτϫʔΫ௨৴ૢ࡞Λఏڙ͍ͯ͠ΔϥΠϒϥϦͰ͢ɻ௨৴ϓϩτ ίϧΛಠࣗʹ֦ு͢Δ͜ͱ΋Ͱ͖ɺPipeline ػߏΛ༻͍ͯ RUDP ௨৴΁ΧελϚΠζ͢Δ͜ͱ΋Մ ೳͰ͢ɻ·ͨɺNetcode for GameObjects Λ༻͍Δ͜ͱͰϚϧνϓϨΠϠʔήʔϜͷ։ൃޮ཰Λߴ ΊΔ͜ͱ͕Ͱ͖·͢ɻ2022 ೥ 6 ݄ʹ͸ϚϧνϓϨΠϠʔήʔϜͷ੍࡞ج൫ͱͳΔ Unity ήʔϛϯ άαʔϏε͕ਖ਼ࣜϦϦʔε͞Ε͓ͯΓɺϚϧνϓϨΠϠʔήʔϜͷ։ൃ͕ΑΓ؆୯ʹͳ͖͍ͬͯͯ ·͢ɻ ͔͠͠ɺ࣮ࡍʹϚϧνϓϨΠϠʔήʔϜͷ։ൃΛߦͬͯΈΔͱɺUnity Editor Λෳ਺্ཱͪ͛ͯ ಈ࡞֬ೝΛߦ͏ඞཁ͕͋ΓɺߴεϖοΫͳ։ൃ୺຤Λ༻ҙͰ͖ͳ͍ͱಈ࡞֬ೝࣗମ͕೉͍͠ͱ͍͏໰ ୊ʹ௚໘͢Δ͜ͱ͕͋Γ·͢ɻຊষͰ͸ɺ͜͏͍ͬͨ՝୊Λղܾ͢ΔͨΊɺUnity Transport ͷ௨৴ ϓϩτίϧΛֶͼ Unity Editor Λ༻͍ͣʹ௨৴Λߦ͏αʔόΛ։ൃͯ͠Έ·͢ɻ 8.2 Unity Transport ͷηοτΞοϓ Unity Transport ΛऔΓࠐΉखॱ͸ҎԼͷ௨ΓͰ͢ɻ 1. Unity Editor ͰϓϩδΣΫτΛಡΈࠐΉ 2. ϝχϡʔ͔ΒʮWindowʯˠʮPackage ManagerʯΛબ୒͢Δ 3. Package Manager ΢Οϯυ΢ͷࠨ্෇ۙʹ͋Δ ʮʴʯ ΛΫϦοΫ͠ɺ ʮadd by package name...ʯ Λબ୒͢Δ 4.ʮNameʯʹʮcom.unity.transportʯͱೖྗͯ͠ʮADDʯΛΫϦοΫ͢Δ ͜ΕʹΑΓ Unity Transport Λར༻Ͱ͖Δ͚ͩͰ͸ͳ͘ɺUnity Transport ͷιʔεΛ֬ೝ͢Δ ͜ͱ΋Ͱ͖·͢ɻιʔε͸ Library/PackageCache/[email protected] ҎԼʹ֨ೲ͞Εͯ ͓Γɺͪ͜ΒΛࢀরͭͭ͠௨৴ϓϩτίϧΛ֬ೝ͍͖ͯ͠·͢ɻͳ͓ɺ@Ҏ߱͸ Unity Transport ͷ 95
  91. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.3 Unity Transport ͷ௨৴ϓϩτίϧ

    όʔδϣϯΛ͓ࣔͯ͠Γɺࣥච࣌఺Ͱͷόʔδϣϯ͸ 1.2.0 ͱͳ͍ͬͯ·͢ɻ ࣮ࡍͷ௨৴಺༰Λ֬ೝ͢Δ৔߹͸ɺWireshark ͳͲͷύέοτΩϟϓνϟΛ༻͍Δͱ؆୯ʹ֬ೝͰ ͖·͢ɻຊষͰऔΓ্͛Δ಺༰ͷൣғ಺Ͱ͋Ε͹ɺૹड৴ͨ͠σʔλΛஞҰग़ྗ͢ΔΑ͏ͳ؆୯ͳϓ ϩάϥϜΛ༻ҙ͢Δ͚ͩͰ΋े෼Ͱ͢ɻ fmt.Println(receivedBytes) // ग़ྗྫ: [99 68 48 180 135 41 189 178 213 181] for _, b := range receivedBytes { fmt.Printf("%X ", b) } // ग़ྗྫ: 63 44 30 B4 87 29 BD B2 D5 B5 8.3 Unity Transport ͷ௨৴ϓϩτίϧ Unity Transport Ͱ௨৴Λߦ͏αϯϓϧϓϩάϥϜ͸ެࣜαΠτʹαʔό*1ͱΫϥΠΞϯτ*2ͱ΋ ʹެ։͞Ε͍ͯ·͢ɻ αϯϓϧϓϩάϥϜͷಈ࡞Λ؆୯ʹ·ͱΊΔͱɺҎԼͷΑ͏ʹͳΓ·͢ɻ 1. αʔό͕ UDP ϙʔτΛ։͘ 2. ΫϥΠΞϯτ͕઀ଓཁٻΛૹ৴͢Δ 3. αʔό͕઀ଓཁٻΛड৴͠ɺडཧͨ͜͠ͱΛ௨஌͢Δ 4. ઀ଓཱ֬ޙʹɺΫϥΠΞϯτ͕ήʔϜσʔλΛૹ৴͢Δ 5. αʔό͕ήʔϜσʔλΛड͚औΓɺՃ޻ͯ͠ૹ৴͢Δ 6. ΫϥΠΞϯτ͕ήʔϜσʔλΛड৴͢Δ ·ͨɺαϯϓϧϓϩάϥϜʹ͸ॻ͔Ε͍ͯ·ͤΜ͕ɺUnity Transport ͷ಺෦Ͱ ping ͱ pong Λ ૹड৴͍͋ͬͯ͠·͢ɻ Ҏ্ͷաఔͰొ৔͢Δ௨৴಺༰͸઀ଓཁٻɺ઀ଓडཧɺήʔϜσʔλɺpingɺpong ͷ 5 छྨͱͳ Γ·͢ɻͦΕͧΕ௨৴಺༰͸ڞ௨ͷϔομ෦Λ͓࣋ͬͯΓɺ಺༰ʹԠͨ͡ϘσΟ෦͕ޙʹଓ͖·͢ɻ ϔομ෦ͷ௕͞͸ 10 όΠτͰɺ௨৴ͷछผʢ1 όΠτʣ ɺϑϥάʢ1 όΠτʣ ɺηογϣϯτʔΫϯ ʢ8 όΠτʣؚ͕·Ε͍ͯ·͢ɻϘσΟ෦ʹ͍ͭͯ͸ɺ઀ଓडཧʹ͸৽ͨͳηογϣϯτʔΫϯʢ8 ό Πτʣؚ͕·ΕɺήʔϜσʔλʹ͸ήʔϜଆͰ٧ΊࠐΜͩόΠτྻؚ͕·Ε͓ͯΓɺαϯϓϧϓϩά ϥϜͰ͸ූ߸ͳ͠ 4 όΠτ੔਺ܕͷ਺஋͕ೖ͍ͬͯ·͢ɻͳ͓ɺ઀ଓཁٻɺpingɺpong ͷ 3 छྨ͸ ϔομͷΈͷ௨৴ͱͳ͓ͬͯΓɺϘσΟ෦͸͋Γ·ͤΜɻ ҎԼͰ͸ɺϔομ෦ͷ಺༰ʹ͍ͭͯৄࡉʹݟ͍͖ͯ·͢ɻ *1 αʔόαϯϓϧ https://docs-multiplayer.unity3d.com/transport/current/samples/serverbehaviour *2 ΫϥΠΞϯταϯϓϧ https://docs-multiplayer.unity3d.com/transport/current/samples/clientbehaviour 96
  92. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.4 ܰྔαʔό։ൃ ·ͣɺ௨৴ͷछผʹ͍ͭͯ͸શ෦Ͱ 6

    छྨ͋ΓɺҎԼͷΑ͏ͳ஋͕ઃఆ͞Ε·͢ɻ • ઀ଓཁٻʢ0ʣ • ઀ଓڋ൱ʢ1ʣ • ઀ଓडཧʢ2ʣ • ੾அʢ3ʣ • ήʔϜσʔλʢ4ʣ • pingʢ5ʣ • pongʢ6ʣ ͳ͓ࠓճ͸ɺ઀ଓڋ൱΍੾அʹ͍ͭͯ͸ಛʹऔΓ্͛·ͤΜɻ ࣍ʹɺϑϥάʹ͍ͭͯ͸ɺ ʮηογϣϯτʔΫϯ͕෇༩͞Ε͍ͯΔ͔ʯ͕ 1 Ϗοτ໨ɺ ʮPipeline Λ ࢖༻͍ͯ͠Δ͔ʯ͕ 2 Ϗοτ໨ͱͳΔϏοτϑϥάͱͯ͠ߏ੒͞Ε͍ͯ·͢ɻࠓճऔΓ্͛Δ௨৴಺ ༰ͷதͰ͸ɺ઀ଓडཧ͕௥ՃͷηογϣϯτʔΫϯΛ͍࣋ͬͯΔͨΊϑϥά͸ 1 ͱͳΓ·͢ɻ ࠷ޙʹɺηογϣϯτʔΫϯʹ͍ͭͯղઆ͠·͢ɻηογϣϯτʔΫϯ͸ϥϯμϜͳ 8 όΠτͷό Πτྻͱͳ͍ͬͯ·͢ɻαʔόͱΫϥΠΞϯτͰηογϣϯτʔΫϯΛڞ༗ͤͣɺ઀ଓཁٻʹೖͬͯ ͍ΔηογϣϯτʔΫϯΛαʔό͔Βͷૹ৴ʹ࢖༻͠ɺ઀ଓडཧʹؚ·ΕΔ৽͍͠ηογϣϯτʔΫ ϯΛΫϥΠΞϯτ͔Βͷૹ৴ʹ࢖༻͠·͢ɻ Ҏ্ͷ௨৴಺༰ͱྲྀΕΛ࣮૷͢Δ͜ͱͰɺUnity ͔Βಠཱͨ͠ܗͰ௨৴Λߦ͏ϓϩάϥϜΛ࡞੒Ͱ ͖·͢ɻ 8.4 ܰྔαʔό։ൃ αϯϓϧαʔόΛ࠶ൃ໌͢Δͷʹඞཁͳཁૉ͸ͦΖͬͨͷͰ Go Ͱಉ͡Α͏ͳಈ࡞Λ͢ΔαʔόΛ ࡞੒͍͖ͯ͠·͢ɻ ·ͣɺ௨৴ͷछผΛҎԼͷΑ͏ʹఆٛ͠·͢ɻ const ( ConnectionRequestType = iota ConnectionRejectType ConnectionAcceptType DisconnectType DataType PingType PongType ) ϑϥάͷऔΓѻ͍ʹ͍ͭͯ͸ɺࠓճ͸઀ଓडཧͰͷΈඞཁͳͨΊ઀ଓडཧΛૹ৴͢Δࡍʹ 1 Λઃఆ ͢Δ͜ͱʹ͠·͢ɻ ηογϣϯτʔΫϯʹ͍ͭͯ͸ rand.Uint64() Ͱੜ੒͠·͢ɻ 97
  93. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.4 ܰྔαʔό։ൃ ௨৴಺༰Λද͢ߏ଄ମ͸ɺϔομ෦ͷΈʢ઀ଓཁٻɺpingɺpongʣ ɺ઀ଓडཧɺήʔϜσʔλͷ

    3 ͭΛఆٛ͠·͢ɻ type TransportHeader struct { Type byte Flags byte Token uint64 } type ConnectAccept struct { TransportHeader NewToken uint64 } type UdpData struct { TransportHeader Num uint32 } αʔόຊମͷ࣮૷Ͱ͸؆୯ͷͨΊΫϥΠΞϯτ͸Ұ͚ͭͩѻ͏΋ͷͱ͠ɺඞཁ࠷௿ݶͷಈ࡞ͷΈఆ ٛͯ͠Έ·͢ɻڍಈͱͯ͠͸ɺUDP ϙʔτΛ։͖ɺԿ͔Λड৴ͯ͠͸ฦ౴Λߦ͏ͱ͍͏୯७ͳ΋ͷ ͱͳΓ·͢ɻΫϥΠΞϯτͷੜଘ֬ೝ΋ඞਢͰ͸ͳ͍ͨΊলུ͠ɺping Λૹ৴͢Δॲཧ΋ল͖·͢ɻ type toyServer struct { conn *net.UDPConn addr *net.UDPAddr // ઀ଓͨ͠ΫϥΠΞϯτ৘ใ recvToken uint64 } func (server *toyServer) run() { serverAddr := &net.UDPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 9000, } conn, err := net.ListenUDP("udp", serverAddr) if err != nil { panic(err) } server.conn = conn buf := make([]byte, 32) for { n, addr, err := conn.ReadFromUDP(buf) if err != nil { panic(err) 98
  94. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.4 ܰྔαʔό։ൃ } server.addr

    = addr switch buf[0] { case ConnectionRequestType: server.sendAccept(buf[:n]) case DataType: server.sendData(buf[:n]) case PingType: server.sendPong() } } } Ͱ͸ɺฦ౴ͷத਎Ͱ͋Δ઀ଓडཧ sendAcceptɺήʔϜσʔλૹ৴ sendDataɺpong ฦ౴ sendPo ng ʹ͍ͭͯݟ͍͖ͯ·͢ɻ ઀ଓडཧ sendAccept Ͱ͸ɺ઀ଓཁٻ͔ΒηογϣϯτʔΫϯΛൈ͖ग़͠ɺ৽ͨͳηογϣϯτʔ ΫϯΛੜ੒ͯ͠ฦ౴͍ͯ͠·͢ɻෳ਺ͷ઀ଓΛ؅ཧ͢Δ৔߹͸ɺ͜͜Ͱੜ੒ͨ͠৽͍͠ηογϣϯ τʔΫϯΛه࿥͓ͯ͘͠ඞཁ͕͋Δ఺ʹ஫ҙ͍ͯͩ͘͠͞ɻ func (server *toyServer) sendAccept(bs []byte) { var request TransportHeader binary.Read(bytes.NewBuffer(bs), binary.LittleEndian, &request) server.recvToken = request.Token var accept ConnectAccept accept.Type = ConnectionAcceptType accept.Flags = 1 accept.Token = server.recvToken accept.NewToken = rand.Uint64() buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, accept) _, err := server.conn.WriteTo(buf.Bytes(), server.addr) if err != nil { panic(err) } } ήʔϜσʔλૹ৴ sendData Ͱ͸ɺ઀ଓडཧͱಉ༷ʹड৴಺༰Λύʔε͠ɺฦ౴಺༰Λੜ੒ͯ͠ૹ ৴͠·͢ɻ͜͜Ͱ͸ Unity Transport ͷαϯϓϧͱಉ༷ʹɺड৴ͨ͠ήʔϜσʔλʹ +2 Λߦͬͯฦ ౴͍ͯ͠·͢ɻ 99
  95. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.5 ऴΘΓʹ func (server

    *toyServer) sendData(bs []byte) { var udpData UdpData binary.Read(bytes.NewBuffer(bs), binary.LittleEndian, &udpData) var response UdpData response.Type = DataType response.Flags = 0 response.Token = server.recvToken // αϯϓϧαʔόͷڍಈʹ߹Θͤͯ +2 Λ͢Δ͚ͩ response.Num = udpData.Num + 2 buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, response) _, err := server.conn.WriteTo(buf.Bytes(), server.addr) if err != nil { panic(err) } } ࠷ޙʹ pong ฦ౴ sendPong Ͱ͸ɺड৴಺༰͸ಛʹඞཁͳ͍ͨΊ pong Λੜ੒ͯ͠ૹ৴͢ΔͷΈͱ ͳ͍ͬͯ·͢ɻ func (server *toyServer) sendPong() { var pong TransportHeader pong.Type = PongType pong.Flags = 0 pong.Token = server.recvToken buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, pong) _, err := server.conn.WriteTo(buf.Bytes(), server.addr) if err != nil { panic(err) } } Ҏ্͕αʔό࣮૷ͷৄࡉͱͳΓ·͢ɻ͜ͷαʔόΛىಈ͠ɺUnity Editor ʹͯΫϥΠΞϯταϯ ϓϧΛ࣮ߦ͢Δͱ઀ଓ͔ΒήʔϜσʔλͷૹड৴·ͰߦΘΕΔ͜ͱ͕֬ೝͰ͖·͢ɻ 8.5 ऴΘΓʹ Unity Transport Λղੳ͠ɺαϯϓϧαʔόͱࣅͨಈ࡞Λ͢ΔϓϩάϥϜΛ࡞੒ͯ͠Έ·ͨ͠ɻα ϯϓϧϓϩάϥϜΛΤϛϡϨʔτ͢Δ͚ͩͰ͋Ε͹ɺ਺छྨͷ௨৴಺༰Λԡ͑͞Δ͚ͩͰ࣮૷Ͱ͖· ͨ͠ɻ 100
  96. ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.5 ऴΘΓʹ ࠓճऔΓ্͛ΒΕͳ͔ͬͨ Pipeline

    ػߏΛ༻͍ͨ RUDP ௨৴΍ΑΓ࣮ફతͳαʔό։ൃʹ͍ͭͯ ͸ɺػձΛ͋ΒͨΊͯ·ͱΊΒΕͨΒͱࢥ͍·͢ɻ 101
  97. ஶऀ঺հ ٢઒ ༐ଠ࿠ (ୈ 1 ষ୲౰, GitHub: yutaroyoshikawa) 2021 ৽ଔɻTIPSTAR

    ࣄۀ෦ͰΤϯδχΞΛ͍ͯ͠·͢ɻWebGL ͱ ΞΫηγϏϦςΟʹͭ ͍ͯߟ͑Δͷ͕޷͖Ͱ͢ɻ ɹ দݪ ৴஧ (ୈ 2 ষ୲౰) ॴଐ͸ϞϯεταʔόνʔϜͰ Ruby ΍ Go Λॻ͍ͯΔɻϓϩάϥϛϯά͕޷͖Ͱɺීஈ͸ਪ ͠ݴޠͷ Haskell Ͱ༡ΜͩΓɺ৽͍͠ϓϩάϥϛϯάݴޠΛษڧͨ͠Γ͍ͯ͠ΔɻHaskell-jp ΍ Elm-jp Ͱͪΐͪ͜ΐ͜׆ಈ΋͍ͯ͠Δɻ ɹ ߐാ ୓࠸ (ୈ 3 ষ୲౰, Twitter: @MeguruMokke) 2021 ৽ଔɻTIPSTAR ࣄۀ෦Ͱ൚༻తʹ׆ಈ͍ͯ͠·͢ɻझຯ͸͓ֆඳ͖ͱ Clojure ͱ͔ɻ ɹ ؙඌ Ұਅ (ୈ 4 ষ୲౰, Twitter: @Taillook) 2019 ৽ଔɻ഑ଐ࣌ΑΓΦϑϥΠϯΠϕϯτͷγεςϜपΓͷ։ൃʹैࣄɻ2022 ೥ 8 ݄͔Β͸ ԣஅతͳٕज़ࢧԉʹैࣄɻझຯ͸μΠϏϯάͱϥʔϝϯ԰८Γɻ ɹ ాಹล ً (ୈ 5 ষ୲౰) ։ൃຊ෦ CTO ࣨॴଐɻιϑτ΢ΣΞΤϯδχΞͱͯ͠ήʔϜ։ൃͱӡӦɺͦΕ͔Βऩӹੑ΍ ήʔϜੑͱ UX ໘౳ʑΫϦΤΠςΟϒʹ΋ܞΘ͖ͬͯ·ͨ͠ɻϓϩάϥϛϯάڭҭʹ͍ͭͯ ͷֶशιϑτͱΧϦΩϡϥϜΛࣗࣾ಺Ͱ࡞Γɺதɾߴߍੜʹ޲͚ͯϓϩάϥϛϯάߨ࠲ͷߨࢣ Ͱ΋׆ಈதɻ΄͔ࣾ಺ R&D ۀ຿΋ࢀՃɻ 103
  98. ෇࿥ ஶऀ঺հ ๺ౡ ঵ޔ (ୈ 6 ষ୲౰) 2019 ৽ଔɻϞϯετͳͲͷ෼ੳ༻σʔλج൫ߏஙΛओʹ୲౰͍ͯ͠·͢ɻBigQuery ͕޷͖ɻ

    ɹ ௥ా ହ޺ (ୈ 7 ষ୲౰) KARASTA ͷ Android/iOS ΞϓϦΛ࡞Δ࢓ࣄΛ͍ͯ͠·͢ɻKARASTA Ͱ͸ௌ͖ઐͱͯ͠ ೔ʑ׆ಈ͍ͯ͠·͢ɻ ɹ ࡾ্ ൏ਓ (ୈ 8 ষ୲౰, Twitter: @kawakami_o3) ϞϯετεϐϯΦϑԣஅਪਐάϧʔϓͰαʔόʔ։ൃͷαϙʔτΛ͍ͯ͠·͢ɻଟछଟ༷ͳ ϓϩδΣΫτ΍࠾༻ٕज़ʹ࢛ۤീۤͭͭ͠ɺ೔ʑษڧ͠ͳ͕Β͓ख఻͍͍͍͍ͤͯͨͩͯ͞ ·͢ɻ ɹ ܀ྛ խਓ (Graphic designer) σβΠϯຊ෦ϓϩμΫτਪਐάϧʔϓॴଐɻΞΠίϯΠϥετɾදࢴσβΠϯΛ୲౰͠·͠ ͨɻUI σβΠϯ΋खֻ͚·͢ɻͱΜ͔͕ͭ޷͖Ͱ͢ɻ ɹ تଟ ޭ࣍ (੍࡞ਐߦ, Twitter: @kojikita) CTO ࣨ DevRel άϧʔϓͰษڧձ΍Πϕϯτɺ৽ଔٕज़ݚमͳͲͷӡӦΛ͍ͯ͠·͢ɻ࠷ۙ ͷ஫ྗࣄۀ͸ࢠҭͯͰ͢ɻ ɹ ӹࢁ ઍय़ (੍࡞ਐߦ, Twitter: @charlielog_ggg) CTO ࣨ DevRel άϧʔϓͰɺΤϯδχΞͷΠϯλϏϡʔهࣄΛॻ͍ͨΓɺΠϕϯτڠࢍؔ࿈ ͷ΍ΓͱΓΛͨ͠Γ͍ͯ͠·͢ɻࣾ಺ͷʮϚʔϒϧϫʔΫελΠϧ੍౓ʯͷԸܙʹ༬͔ͬͯɺ ۙʑ஍ํҠॅ༧ఆͰ͢ʂ 104
  99. MIXI TECH NOTE #08 2022 ೥ 9 ݄ 10 ೔ɹॳ൛ୈ

    1 ࡮ɹൃߦ ஶɹऀ גࣜձࣾ MIXI ༗ࢤ ൃߦॴ גࣜձࣾ MIXI ҹ࡮ॴ άϥϑΟοΫ ɹ ˜ MIXI