#技術書典13 に出典されたミクシィグループエンジニア有志による技術書です。
<< 目次 >>
1章:Service Worker を介した feature toggle 管理
2章:Haskell の静的サイトジェネレーター
3章:Clojure ではじめる仕様分析
4章:Rust の Axum を使った API サーバ開発
5章:学校提供ソフトウェアで問題解決
6章:BigQuery で GeoHash による高速な市区町村判定
7章:Android の動画再生アプリの作り方 2022
8章:Unity Transport 解析と軽量サーバー開発
<< TECH NOTE 一覧 >>
mixi tech note #01
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-01
mixi tech note #02
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-02
mixi tech note #03
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-03
mixi tech note #04
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-04
mixi tech note #05
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-05
mixi tech note #06
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-06
mixi tech note #07
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-07
MIXI TECH NOTE #08
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-08
XFLAG Tech Note Vol.01
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-01
XFLAG Tech Note vol.02
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-02
MIXI TECH NOTE #08
גࣜձࣾ MIXI ༗ࢤɹஶ
2022-09-10 ൛ גࣜձࣾ MIXI ൃߦ
·͕͖͑
ຊॻʮMIXI TECH NOTE #08ʯɺMIXIGROUP ʹॴଐ͢Δ༗ࢤୡʹΑͬͯࣥචɾ੍࡞͞Εٕͨ
ज़ॻͰ͢ɻ࣮ࡍͷϓϩμΫτ։ൃͷݱͰ༻͞Εٕͨज़ͷɺʑͷۀͷΒɺݸਓతʹௐ
ͨ͜ͱͳͲɺࢥ͍ࢥ͍ʹࣥච͍ͯ͠·͢ɻͦͷͨΊɺ֤ষͦΕͧΕͰ͍݁ͯ͠Δ༰ʹͳ͍ͬͯ·
͢ͷͰɺ͖ͳষ͔Β͖ͳॱ൪Ͱָ͓͠Έ͍ͩ͘͞ɻ
·ͨɺຊॻɺMIXIGROUP ʹ͋Δٕज़తݟΞΠσΞΛੵۃతʹڞ༗ɾެ։͍ͯ͘͜͠ͱͰɺ
ੈͷதʹΑΓྑ͍αʔϏε͕ҲΕग़͢͜ͱΛئͬͯץߦ͞Ε͍ͯ·͢ɻܝࡌ͞Ε͍ͯΔใɺࣥච
ऀࣗͷڥͰݕূࣥ͠ච͞ΕͨͷͰ͢ͷͰɺ͝ࢀߟʹ͞ΕΔࡍɺࣗ͝ͷͰஅ͠͝׆༻
͍ͩ͘͞ɻͳ͓ɺจষදݱʹ͖ͭ·ͯ͠ɺࣥචऀࣗͷݴ༿Ͱ͑ͨ͘ɺϑϥϯΫͳදݱͱͳͬͯ
͓Γ·͢͜ͱ͝ཧղ͍͚ͨͩΕͱࢥ͍·͢ɻ
σΟϕϩούʔϦϨʔγϣϯζνʔϜҰಉ
˗ຊॻʹؔ͢Δ͓͍߹Θͤઌ
ɹ https://twitter.com/mixi_engineers
˗ MIXIGROUP ʹ͍ͭͯ
ɹ https://mixi.co.jp/
˞ MIXI ͷ໊শɺ͜Εʹؔ࿈͢Δඪٴͼϩΰɺגࣜձࣾ MIXI ͷඪٴͼొඪͰ͢ɻ·ͨɺ
֤ࣾͷձ໊ࣾɺαʔϏεٴͼͷ໊শɺͦΕͧΕͷॴ༗͢Δඪ·ͨొඪͰ͢ɻ
iii
࣍
·͕͖͑ 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
࣍
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
ୈ 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
ୈ 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 ? new : old}
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
ୈ 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
ୈ 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
ୈ 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 => {
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 => {
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
ୈ 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(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
ୈ 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
ୈ 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 ? new : old}
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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 3 ষ
Clojure Ͱ࢝ΊΔ༷ੳ
3.1 ͡Ίʹ
Έͳ͞Μɺ༷ॻಡΜͰ͍·͔͢ʁ
ੈͷதʹ༷ॻΛಡΉ͜ͱઃܭ͢Δ͜ͱଟ͋͘Γ·͕͢ɺ࣌ʹ༷ॻͷͳ͍ശΛૢ࡞͢Δ
ඞཁʹഭΒΕΔ͜ͱ͕͋Γ·͢ɻࠓճͦΜͳ༷ॻͷͳ͍ശΛૢ࡞ͨ͠ͱ͖ʹ༷ॻΛ࿉ͨ͠ɺ
ͪΐͬͱมΘͬͨΤϯδχΞϦϯάʢʁʣΛհ͠·͢ɻ
͕͖ͨͩ͠
ຊষͰհ͢Δ༰ MIXI ࣾͰ࣮ࡍʹΘΕ͍ͯΔσʔλɺ༷ͱԿΒ͕ؔ͋Γ·ͤΜɻ
3.2 ঢ়گઃఆ
͋ͳͨɺͱ͋ΔλϫʔσΟϑΣϯεήʔϜͷσόοάΛ͍ͯ͠·͢ɻ
σόοά༰ͱͯ͠ɺࢿྉ 1 ͷΫΤετʹ͍ͭͯɺμϛʔͷσʔλΛ࡞ͬͯήʔϜͷڍಈʹᴥᴪ
͕ͳ͍͔ΛνΣοΫ͢Δɺͱ͍͏ͷͰ͢ɻ
ͳ͓ɺμϛʔͷσʔλʹ͍ͭͯɺࢿྉ 2 ͷαϯϓϧΛࢀߟʹదٓௐ͢Δඞཁ͕͋Γ·͢ɻ
17
ୈ 3 ষ Clojure Ͱ࢝ΊΔ༷ੳ 3.2 ঢ়گઃఆ
ࢿྉ 1
ਤ 3.1: ΫΤετͷྲྀΕਤ
18
ୈ 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ͭͷεςʔδͰ230ඵ
Ͱఢ͕ग़ݱ͠·͢ɻ 2ͭͷεςʔδͰதϘε͕5ମɺ3ͭͷεςʔδͰϘε͕1ମग़ݱ͠·͢ɻ
ͦΕͧΕͷϚελσʔλɺཧը໘͔Βೖߘ͢Δ͜ͱͰөͰ͖·͢ͷͰɺσόοάΑΖ͓͘͠ئ͍͠·͢ɻ
ಛʹݟͯཉ͍͠؍ͱͯ͠ɺఢͷλΠϓ͕Ϙε (type = 3) ͷͱ͖ʹϘεͷϚʔΫ͕֘ͷఢΩϟϥΫλʹ
༩͞ΕΔͱ͜ΖͰ͢ɻ
19
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 3 ষ Clojure Ͱ࢝ΊΔ༷ੳ 3.4 ऴΘΓʹ
3.4 ऴΘΓʹ
ࠓճ Clojure Λ༻͍ͯσʔλ͔Β༷Λੳ͍ͯ͘͠ɺͱ͍͏ͪΐͬͱมΘͬͨΤϯδχΞϦϯ
άΛհ͍͖ͯ͠·ͨ͠ɻݱ࣮Ͱ͋·Γى͜Βͳ͍γνϡΤʔγϣϯͱࢥ͍·͕͢ɺಈతʹܕΛ
͚͍ͯ͘͜ͱɺܕΛϦϑΝΫλ͍ͯ͘͜͠ͱɺͱ͍ͬͨಛʹ੩తܕ͖ݴޠͰΊͬͨʹܦݧͰ͖
ͳ͍ࣄʹ͍ͭͯݟฉΛΊ͍ͯͨͩ͘ҰॿʹͳΕͱࢥ͍·͢ɻ
·༷ͨʹ stringɺint ͱ͍ͬͨجຊσʔλܕใͷΈΛॻ͘ͷͰͳ͘ɺࠓճ Clojure Ͱੳ
ͨ͠Α͏ͳ໌֬ͳܗʹ·ͱΊΒΕΔͱɺੳख͕ؒল͚σόοάͳͲ͕ΑΓεϜʔζʹਐΉͷͰɺۃ
ྗஸೡͳهड़͕Ͱ͖ΔͱΑͦ͞͏Ͱ͢ɻ
(ཉΛݴ͑ ࠓճͷΑ͏ͳϓϩάϥϜͰ༷͕·Ε͍ͯΔͱɺσόοάͳͲ͕Γ͍͢ͷͰɺ
֤։ൃνʔϜͷٕज़ελοΫʹ߹ΘͤͯదͳݴޠɾπʔϧΛ࠾༻͢ΔͷΑ͍Ͱ͠ΐ͏)
27
ୈ 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
ୈ 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::()
.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
ୈ 4 ষ Rust ͷ Axum Λͬͨ API αʔό։ൃ 4.2 ToDo ΞϓϦͷ API Λ࡞Δ
fn app(app_state: Arc) -> 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>)
-> Response {
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::>(
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
ୈ 4 ষ Rust ͷ Axum Λͬͨ API αʔό։ൃ 4.2 ToDo ΞϓϦͷ API Λ࡞Δ
pub async fn post_todo(
Extension(state): Extension>,
Json(params): Json,
_: Auth,
) -> Response {
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
ୈ 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 {
let status = StatusCode::UNAUTHORIZED;
let body = json!({"error": "Unauthorized".to_string()}).to_string();
(status, body).into_response()
}
}
#[async_trait]
impl FromRequest for Auth
where
B: Send,
{
type Rejection = AuthError;
async fn from_request(req: &mut RequestParts) -> Result {
use std::env;
use axum::{
extract::TypedHeader,
headers::{authorization::Bearer, Authorization},
};
match TypedHeader::>::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
ୈ 4 ষ Rust ͷ Axum Λͬͨ API αʔό։ൃ 4.3 ͓ΘΓʹ
Extractor*5Λ࣮͢Δࣄ͕Ͱ͖·͢ɻ͜ͷ࣮Ͱ AuthorizationΛऔಘ͠ɺ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
ୈ 5 ষ
ֶߍఏڙιϑτΣΞͰղܾ
5.1 ຊষʹ͍ͭͯ
ࢲ͕औΓΉϓϩδΣΫτʹ͓͍ͯதֶߍͷιϑτΣΞఏڙֶशࢦಋΛଟ࣮͘ࢪͨ͠ɻͦ
ͷதͰ࣮ફͨ͠ੳݕূͱϑΟʔυόοΫΛऔΓೖΕͯͷվળʹ͍ͭͯৼΓฦͬͯཧ͠ɺι
ϑτΣΞ։ൃࣄྫͷҰͭͱͯ͠චऀؚΊͨಡऀͯ͢ͷํͷܞΘΔϏδωεʹ׆͔͞Ε͍ͨɻͳ
͓ઌʹݴ͓ͬͯ͘ͱɺຊষͰϓϩάϥϛϯάͱίʔυͷొ͠ͳ͍ɻ
චऀϓϩϑΟʔϧ
ήʔϜΛத৺ͱͨ͠ιϑτΣΞΤϯδχΞͱͯ͠׆ಈ͓ͯ͠ΓɺίϯγϡʔϚήʔϜϒϥ
βήʔϜͱεϚʔτϑΥϯΞϓϦͷ։ൃɺWeb αʔϏεήʔϜاըܞΘΔɻۙڭҭݱ
ʹ͚ͯɺ
ʮϓϩάϥϛϯάֶशʯΛਪਐ͢Δߨࢣͱͯͦ͠ͷֶशιϑτΣΞΧϦΩϡϥ
Ϝ։ൃͱซͤͯऔΓΜͰ͍Δɻ
LinkedIn: https://www.linkedin.com/in/akira-tanabe/
ͶΒ͍
ࢲ͕୲͍ͬͯΔۀͰ͋Δ͜ͷϢχʔΫͳऔΓΈͷཪଆΛ͔͋͠աఔΛৼΓฦΔ͜ͱͰɺٛͳ
ιϑτΣΞιϦϡʔγϣϯʹ͓͚Δղܾࣄྫͱͯ͠͠චऀͱಡऀͷֶͼʹͭͳ͛Δ͜ͱΛओ
ࢫͱ͢Δ
35
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.1 ຊষʹ͍ͭͯ
ཁ
• ݱࡏࢲͨͪதֶߍʹରͯ͠ϢχʔΫͳࢧԉ׆ಈΛൃݟ͠ͳ͕Βܧଓతʹ࣮ࢪ͍ͯ͠Δ
• ࣮ࢪઌ༰͋Β͔͡Ίܾ·͍ͬͯΔΘ͚Ͱͳ͘ɺΛฉ͖ঢ়گΛݟͯاըΛఏҊ͠ͳ͕
ΒίϯςϯπΛఏڙ͓ͯ͠Γɺ·ͨʑͦΕਐԽ͠ॆ࣮͖͍ͯͯ͠Δ
• ղܾͷࢹͰɺ͜Ε·Ͱࢧԉ͕࣮ݱͨ͠աఔͰͲΜͳతʹ͓͍ͯɺͲͷΑ͏ʹఏࣔ
͠ɺͲͷΑ͏ͳ४උΛ͠ɺͲΜͳબΛͨ͠ͷ͔Λྫࣔ͢Δ͜ͱͰɺ͍ͣΕ͔ͷϏδωεͷ֫
ಘ্ཱͪ͛ʹͱͬͯؔ৺͕͋ΔࣄྫͱͳΕͱࢥ͍ه͢
• ιϑτΣΞ։ൃͷࢹͰɺͦͷاըͷݟ௨͠ΛͲͷΑ͏ʹཱͯɺͲͷΑ͏ͳཪ͚Λ࣋ͪɺ
ͲͷΑ͏ʹߦ͔ͨ͠Λྫࣔ͢Δ͜ͱͰɺιϑτΣΞ੍࡞Ϗδωεͷ্ཱͪ͛ɺىۀʹ
ͱͬͯؔ৺͕͋ΔࣄྫͱͳΓ͏Δ
TOPICS
1. ࢲͨͪͷڭҭࢧԉ׆ಈʹ͍ͭͯ
2.
3. ͷղ
4. ඪઃఆͱߦಈࢦ
5. ίϯςϯπاըͱ͞·͟·ͳੳ
6. ΞΠσΞͷൃͱࢥߟ
7. ࠷ޙʹ
ࢀߟจݙɺҾ༻
•ʮϏδϣφϦʔΧϯύχʔʯδϜɾίϦϯζʢ˞γϦʔζʣ
•ʮGIVE ˍ TAKEʯΞμϜɾάϥϯτ
•ʮϦʔϯɾελʔτΞοϓʯΤϦοΫɾϦʔε
•ʮRunnnig LeanʯΞογϡɾϚϦϟ
•ʮϏδωεϞσϧδΣωϨʔγϣϯζʯΞϨοΫεɾΦελʔϫϧμʔɺΠϰɾϐχϡʔϧ
•ʮMeasure What Matters આͷϕϯνϟʔࢿՈ͕ Google ʹڭ͑ͨޭख๏ OKRʯδϣ
ϯɾυʔΞ
•ʮσβΠϯࢥߟ͕ੈքΛม͑Δ: ΠϊϕʔγϣϯΛಋ͘৽͍͠ߟ͑ํʯςΟϜɾϒϥϯ
•ʮܦӦઓུશ࢙ʯࡾ୩ ࣏
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
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.3
5.3
͔͜͜Βɺࢲ͕औΓΜͰ͍ͯࠓճৄ͘͠ղઆ͍ͨ͠ʮʯͷى͜ΓͱͦͷରԠʹ͍ͭͯࣄྫ
հͱͯ͠ৄ͍͠ܦҢΛهड़͍ͯ͘͠ɻͳ͓ɺهࡌ͢Δଞऀʹؔ͢Δഎܠҙࢥʹ͍ͭͯͷใݯ
ɺҰൠʹࠂࣔ͞Ε͍ͯΔͷͷ΄͔ҙਤΛټΜͰςΩετԽͨ͠෦ଟগ͋Δɻຊষͷझࢫ
ղܾख๏ʹ͓͚ΔղܾࣄྫΛɺҙతʹੳ͠͡ΔͷͰ͋Γɺ͍ͣΕ͔ͷ৫ʹ͓͚Δ
ʹ͍ͭͯࢦఠ͢Δҙਤͳ͍ɻ
ͷ্ཱ͕ͪΓ
• ओɹɹɿɹٛڭҭͷϓϩάϥϛϯάֶशࢧԉΛ͢Δ
• ґཔऀɹɿɹौ୩۠
• ൃɹੜɹɿɹ 2019 य़
a. എܠɹʙֶߍڭҭͰͷϓϩάϥϛϯάֶशͱ
ֳͷΊ͟͢ Society 5.0 ͷࣾձɻङྌɺߞɺۀɺใʹଓ͘ 5 ظͱͳΔࣾձ͕ࢦ͢
ͷαΠόʔۭؒͱϑΟδΧϧۭؒΛߴʹ༥߹ͤͨࣾ͞ձɻະདྷʹ͚ͯςΫϊϩδͱՊֶٕज़
ͱͷ༥߹ͳͲɺ૯߹తͳֶशʹऔΓΉ STEAM ڭҭΛਪਐ͢Δจ෦Պֶলɻֶߍʹ͓͚Δ ICT ׆
༻ʢใ௨৴ٕज़ʣͭ·ΓΠϯλʔωοτ PC ͷར༻Λ࣮ࢪ͢Δ֤࣏ࣗମɻ৽͍͠ػثιϑτ
ΣΞ͕ಋೖ͞ΕैདྷͷतۀҎ֎ͷࣝͱ׆༻͕ٻΊΒΕͯ͘Δڭһઌੜํɻ
ֶߍߦͷͶΒ͏࣮ࢪల։
࣮ࢪϞσϧʹ͓͍ͯɺICT ׆༻ͱϓϩάϥϛϯάֶशʹ͓͍ͯҬͱͷͭͳ͕ΓΛ׆͔ͨ͠औΓ
Έ͕༗ҙٛͱ͞ΕɺҬΫϥϒݩاۀେֶͳͲͱͷͭͳ͕ΓΛ׆͔ͯ͠ࢦಋ͍ͯ͘͜͠ͱ͕
ྫࣔ͞ΕΔͳͲɺɾຽɾֶͷ࿈ܞ͕ࠓޙٻΊΒΕ͍ͯ͘ͱ͍͏ɻ
ڭҭݱʹ͓͍ͯɺ৽ͱͯ͠ʮϓϩάϥϛϯάʯ͕ࢦಋͷൣғʹೖΔதͰֶश༰͕·ͩ
ࡧஈ֊ʹ͋Δɻϓϩάϥϛϯάӳޠͱಉ༷ʹશһֶ͕श͢ΔྖҬʹͳΔͱࣔ͞Ε͍ͯΔɻͦͷ࣌Ͳ
Μͳ՝͕ר͖ى͜Δͷ͔ɺ·ͩ༧ଌ͕͔ͭͳ͍ɻ
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
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.3
˙ิ 3 ͭ ্ͷ 5 ͚ͭͩͰ࣮ࡍʹ͞Βʹಥͬࠐ·Εͯ͑ΒΕͳ͍ͨΊɺ͜͜ʹৗ༻తʹΘ
ΕΔࣄ߲Λಠࣗʹ 3 ͓ͭͯ͘͠ɻଞྫʹ฿ͬͯӳޠදهʹ͢Δɻ
1. can ɹʢͰ͖Δ͜ͱʣ
2. should ɹʢΔ͖͜ͱʗͰͳ͍͜ͱʣ
3. resist ɹʢ߅ʣ
˙ରऀ ͏߲୭ͷࢹʹΑΔͷ͔Ͱੜ͢ΔͷͰ͋Γɺͨͱ͑ʮwhyʯͳͥΔ͔
ʹ͓͍͕ͯࣗΔཧ༝ͱґཔऀ͕Δཧ༝͓ͦΒ͘ผʹ͋ΔɻΑΓৄࡉʹݕ౼͍ͯ͘͠ͷͰ͋Ε
ɺํʹ৫άϧʔϓͷϨΠϠ͕͋ΓͦΕͧΕผͷҙࢤతΛ࣋ͪɺͦͷझࢫΛ౿ऻ͠߹ҙΛ
औΓ͚͍ͯ͘ඞཁ͕͋Δ͜ͱΛߟྀ͠ͳ͚ΕͳΒͳ͍ɻ
ࠓճओʹ߹ҙΛಘ͍ͨରͱͯ͠ҎԼࡾऀʹରͯ͠Ͱ͖Δ͚ͩ͘·ͳ͘ड़Δ͜ͱʹΊΔɻ
˙ݕ౼ࢹ
1. ґཔऀ
2. ࣗ৫
3. ࣗࣗ
ड͚खଆΛʮࣗ৫ʯͱʮࣗࣗʯʹ͚ͯఆٛͨ͠ͷ͜ͷऔΓΈಛ༗ͷଆ໘͕͋Δ͔͠
Εͳ͍ɻԾʹґཔऀ͕໌֬ͳϓϩμΫτʢಛఆͷιϦϡʔγϣϯαʔϏε·ͨʣΛٻΊͯ
Φʔμʔ͍ͯ͠ΔͷͰ͋Εɺํͷత͕໌֬Ͱ͋Γ͢ΔՕॴҟͳΔͩΖ͏ɻࠓճͷࣄྫ
ͷ߹ɺࣗࣾʮΔ͖͜ͱͰ͋ΕΔʯͱ͍͏ɺཱͪҐஔͱͯ͠தཱతͳ࢟Ͱ͋ͬͨɻ·ͨ
ʮࣗࣗʯͷ࢟ͱͯ͠ଟগҟͳΓɺ
ʮࠓޙ༗ҙٛʹͳΔݟࠐΈ͕͋Δ͜ͱΛݟग़ͯ͠Δ͖ʗ
Βͳ͍͖Λࣔ͢ʯͱ͍͏ཱʹ͋Δɻ͜Ε͔Βࣔ͢ࡾऀͷඍົͳͱظͷҧ͍ʹͯ͠
΄͍͠ɻ
ᶘ. ࠓճͷੳํ๏·ͱΊ
ղܾͷจ຺Ͱ 5W1H ʴЋΛ·ͱΊɺ࣍ͷͱ͓ΓͱͳΔɻ
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
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.4 ͷղ
5.4 ͷղ
લ߲Ͱڍ͛ͨ·ͱΊํʮ5W1HʯʴЋͰɺཁͭ·Γղܾ͍ͨ͠Λཧ͢Δɻࢹ·ͣ
ఏىΛ͢ΔʮґཔऀʯΛߟ͑ɺґཔऀͷཱʹͳͬͯڞײ͠ͳ͕ΒҙਤཧͳͲΛټΜͰ
͍͘ɻ
ґཔऀʹͱͬͯ
• ԿΛ͢Δ͜ͱͳͷ͔ what
– ٛڭҭͷϓϩάϥϛϯάֶशࢧԉΛ͢Δ
• ୭͕Δͷ͔ who
– ຽֶ࿈ܞʹ͓͚Δʮຽʯ
ɺຽؒͷઐՈ͕Δ͜ͱʹҙຯ͕͋Δ
• ͍ͭͷ͜ͱͳͷ͔ when
– ͦͷ࣌ͷ࣍ɻ20 ͔Βͷॱ࣍ඞमԽʹ͚Δ
• ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where
– ۠ͷٛڭҭɺ20 খֶੜͳͲ
• ͳͥΔͷ͔ why
– ֶߍڭһ͚ͩͰϓϩάϥϛϯάྖҬʹ͍ͭͯઐతࣝͷ४උ͕ͳ͍ͨΊऔΓΈ͕
͍ͨ
• Ͳ͏Δ͔ how
– ఏҊͯ͠΄͍͕͠΄͔ͷࣄྫࢀߟʹ͢Δ
• ࣗୡԿ͔Ͱ͖Δͷ͔ can
– ۠ͷ IT اۀͷίϛϡχςΟΛ׆͔ͯ͠اۀʹڠྗΛཁ͢Δ͜ͱ
• ࣗୡԿΛ͖͢Ͱɺ͖͢Ͱͳ͍͔ should
– ࣮ࢪͷબֶߍͷஅʹΏͩͶΔͨΊ࣮ࢪϝχϡʔͷఏࣔΛ͢Δʢ͖ʣ
– ֶशࢦಋཁྖʹ४ڌ͢Δʢ͖ʣ
• ͲΜͳ߅ͱো͕͋Δͷ͔ resist
– ར༻ڭࡐͷ੍͕͋Δ͔͠Εͳ͍
– ֶߍଆͷڠྗ͕ಘΒΕͳ͍͔͠Εͳ͍
– ࢠͲ͕ͨͪదԠͰ͖ͳ͍͔͠Εͳ͍
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
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.4 ͷղ
˙Ξϯϓϥάυϓϩάϥϛϯάֶश ICT ػثΛҰΘͣʹϓϩάϥϛϯάతࢥߟΛֶͿखஈɻ
ࣄྫͷଟ͘ͰΧʔυΛͬͯॲཧͷॱং༰Λߟ͑Δ͜ͱͰཧతࢥߟྗϓϩάϥϛϯάతͳ
ࢥߟͷֶͼͱ݁ͼ͚͍ͯΔɻֶशͰ͖Δ෯ਂ͞ϓϩάϥϛϯάΛ࣮ࡍʹڭ͑ͨ࣌΄Ͳʹ
࣋ͨͤͮΒ͘ɺػࡐ͕͋Γ͑ΔͷͰ͋Εͬͨํ͕ྑ͍Մೳੑ͕ߴ͍ɻ
˙ϓϩάϥϛϯάֶशతήʔϜ ίϯγϡʔϚػεϚʔτϑΥϯΞϓϦͳͲͰήʔϜͱͯ͠ϓϩά
ϥϛϯάΛϞνʔϑʹͨ͠ͷ͕͍͔ͭ͋͘ΓɺήʔϜͷߦಈͱͯ͠ϓϩάϥϛϯάతͳೖྗࢥ
ߟΛͤ͞Δͷ͕͋ΔɻϓϨΠϠʔ͕ʮਓʯΛϓϩάϥϛϯάͯ͠ࣄͷޮΛ্͛Δ͜ͱΛߟ͑Δ
ͱ͍͏ͷ͕Ұ෦Ͱྲྀߦͨ͠ɻ
ʮϚΠϯΫϥϑτʯͰίϚϯυͱݴΘΕΔΩʔೖྗͦΕΛ֨ೲ͠
໋ͨྩϒϩοΫΛΈ߹ΘͤͨҰ࿈ͷֻ͚ΛϓϩάϥϛϯάͰ͖Δɻ͜ΕΒମݧΠϕϯτͱͯ͠
ར༻͞ΕΔ͜ͱ͕ଟ͍͕ɺͦͷޙͷใͰʮϚΠϯΫϥϑτʯʹ͓͍ͯՃཁૉ͋ͬͯतۀͰͷ
ࣄྫ͋Δɻ
˙ςΩετϓϩάϥϛϯά Web αΠτ্ͳͲͰ JavaScript ͷεΫϦϓτݴޠΛจࣈೖྗͯ͠
νϡʔτϦΞϧతʹ՝Λղ͍͍ͯ͘λΠϓͷֶशڭࡐ͕͋Δɻқʹ෯͕͋ΓࢠͲ͚ͷ
ήʔϜ෩ͳͷ͔Βࣾձਓ͚৬ۀ܇࿅͚ͷ༗ྉڭࡐ·Ͱ͍͔ͭ͋͘Δɻ͜ͷπʔϧࣗମ͕νϡʔ
τϦΞϧҎ֎ͷԿ͔ʹͳ͍ͬͯΔέʔϧ͋·Γͳ͍ɻ͋Δ͍ Scratch ϕʔεͷػث੍ޚιϑτ
ΣΞʹ͓͍ͯ JavaScript Python ग़ྗมͰ͖Δ߹͕͋ΓɺεΫϦϓτΛॻ੍͍ͯޚ
Ͱ͖Δͱݴ͑Δ͕ػثͱηοτߪೖͷͷʹͳΔɻ
˙ʴЋʹΧϦΩϡϥϜͱࢦಋٕज़ ڭࡐͱֶशΧϦΩϡϥϜͱशख़ͨ͠ࢦಋऀ͕͍ͳ͚ΕͳΒͳ
͍ɻ͍ͭ͘ͷطଘڭࡐιϑτΣΞʹֶशΧϦΩϡϥϜ͕େྔʹ༻ҙ͞Ε͓ͯΓɺࣄۀऀͦΕ
ΛֹྉۚΛઃఆͯ͠ఏڙ͍ͯ͠Δɻ͋Δ͍ઌߦاۀ࣏ࣗମͷڠྗͷͱ੍࡞ͨ͠ΧϦΩϡϥϜ
͕͋Γઐ༻ιϑτΣΞͱͱʹ࣮ࢪͰ͖Δͷ͋Δɻ
b. ൃݟ ʢใऩू·ͱΊʣ
• ະࢀೖͰख͕ग़͕͍ͨ͠͏ཱ͑ͤ͞ΔͨΊʹڑײ͕͔ͳΓ͋Δ
• খֶੜͷࢦಋ͕Ͳ͏͍͏ͷ͔ͱ͍͏ݟ͕ͳ͍͜ͱʹࣗͨͪͷ͋͠͞Δ
• খֶੜ͚ϏδϡΞϧϓϩάϥϛϯάͱ࣮༻ϓϩάϥϛϯάͱʹဃ͕͋Δ
• तۀͷࢦ͔ΒʮϓϩάϥϛϯάతࢥߟʯΛͬͨԠ༻͕ٻΊΒΕ͓ͯΓط͔ͦΕʹมΘ
ΔϓϩμΫτʢֶशͰ͖Ԡ͕͋Δͷʣ͕ඞཁ
• طͰݻ༗ͷ੍ݶʹΑͬͯʹର͢ΔϓϩάϥϛϯάҎ֎ͷ܇࿅͕ඞཁʹͳΓʮϓϩά
ϥϛϯάֶशʯͷൣғΛ͑ͳ͚ΕͳΒͳ͍
44
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.4 ͷղ
c. Ծઆઃఆ
ใऩू͠ݱࡏͷ͕ݟ͑ͯ͘ΔͱࣗવͱԾઆཱ͕ͬͯ͘ΔɻԾઆͱɺཪ͚·ͩͳ͍
͕ͷঢ়گʹࢸΒ͠ΊΔཁૉΛநग़ͨ͠ΓղܾҊΛڍ͛ΔखॱΛࢦ͢ɻࠓճͷέʔεͰɺͲ͏ࢧ
ԉΛܭըͯ͠ఏࣔ͢Εґཔऀͱ͕ࣗࣾ Win-Win Ͱ͋Δ͔Λࡧ͢Δ͜ͱʹ͋ΔɻԾઆઃఆʹɺ
͍͔ͭ͘ͷํੑͰྻڍ͍͖ͯ͠࿙Ε͕ͳ͍Α͏ʹݕ౼ͯ͠Α͍͕ɺ͜͜ͰʮϩδοΫπϦʔʯ
Λҙࣝͯ͠Ͳ͏͋Δ͖͔Λಋ͖ग़ͨ͠ɻ্͔Βॱʹ͓͓Αͦରܗࣜʹͳ͍ͬͯΔɻ
ࢧԉ͖͢ࢪࡦͷԾઆ
• ͕ࣗͨͪͰ͖Δ͜ͱΛͨ͠ํ͕Α͍ͷͰ
• ڭһ͕ڭ͑ʹ͍͘қͷͷΛѻ͍ڭ͑ͨํ͕تΕΔͷͰ
• طͷࢦಋͦΕ͕Ͱ͖Δͱ͜Ζ͕͢ΔͷͰฐࣾͰෆཁͳͷͰ
• ΤϯδχΞͷܦݧଇతʹʮςΩετϓϩάϥϛϯάʯ͠ͳ͍ͱࣗ༝ʹͳΕͳ͍ͷͰ
• Ͱ͖Δ্͚ͩͷֶͰ͋ΕςΩετϓϩάϥϛϯάͰ͖ΔͷͰ
•ʮதֶੜʯʹςΩετϓϩάϥϛϯάΛڭ͑ΕΑ͍ͷͰ
• ຊۀʹݶΓͳ͍ۙ͘ͷͰशಘίετͳ͘ࢦಋͰ͖ίϯςϯπఏڙͰ͖ΔՄೳੑ͕ߴ͍ͷͰ
ରऀΛதֶੜʹͯ͠Α͍ͷͰ
ॳզʑʹࣔ͞Εݟ͍͑ͯͨظͱձٞମͷۭؾײͱͯ͠શʹখֶੜࢧԉͩͬͨɻͨͩখֶੜ
ʹରͯ͠ࢧԉΛ͢Δاۀ͕΄͔ʹ͍ͨ͜ͱ͔Βɺ୭खΛग़͞ͳ͍தֶੜʹ͢Δ͜ͱΛґཔऀʹ
͏ͱରʹೖ͍ͬͯΔͷͰ OK ͕ͰͨɻݟํʹΑͬͯɺओྲྀ͔Β֎Εͯͨ͠ͱͱΒΕ͔Ͷͳ
͍ɻґཔऀͱฐࣾҎ֎ɺͦΕͳ͍ͱ͍͏ۭؾͩͱײ͍͕ͯͨ͡ڧ͍৴೦ͰਐΉɻ
͜ͷ࣌Ͱࣗࣾͷݟղͷશମ૾͕ݟ͖͑ͯͨͨΊɺࢹΛʮࣗ৫ʯͱ͢Δʮ5W1HʯͰཧ͢Δɻ
ࣗ৫ʹͱͬͯ
• ԿΛ͢Δ͜ͱͳͷ͔ what
– ґཔऀͷΉࢧԉΛ࣮ࢪ͢Δ
– ֶशιϑτΣΞ։ൃ·ͨΧϦΩϡϥϜߏங
– ߨࢣͱॿखͷखͱ܇࿅
• ୭͕Δͷ͔ who
– ༧ࢉ͔͚ͳ͍ൣғͱͯ͠ࢲࣗ
45
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.4 ͷղ
• ͍ͭͷ͜ͱͳͷ͔ when
– தֶߍ͕ϓϩάϥϛϯάΛ࣮ࢪ͢Δ 2021 ·Ͱ
• ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where
– தֶߍͷओʹٕज़Պ
• ͳͥΔͷ͔ why
– IT اۀͱͯ͠ݟΛࢠͲͨͪͷֶशʹؐݩֶ͠ߍ͚ͩͰͰ͖ͳ͍ઐࣝΛఏڙ͢
Δ͜ͱͰҬؐݩ͢Δ
• Ͳ͏Δ͔ how
– ςΩετϓϩάϥϛϯάͷֶशΛԿΒ͔ͷίϯςϯπΛىͯ͜͠ఏڙ͢Δ
– ֶशίϯςϯπ͍Ζ͍Ζͳͱ͜ΖͰ͑ͦ͏ͳࣗࣾఏڙڭࡐͱ͍͏͜ͱͰݕ౼
• ࣗୡԿ͔Ͱ͖Δͷ͔ can
– ιϑτΣΞ։ൃαʔϏε։ൃͱϓϩάϥϛϯάͰ͋Δ
– தֶɺߴߍʹ͚ͯʮاۀ๚ड͚ೖΕʯͱ͍͏ֶߍ͔Βاۀͷ๚Λड͚Δίϯςϯ
πΛ࣮ࢪ͍ͯ͠ΔͨΊਓ૾͕ΠϝʔδͰ͖Δ
• ࣗୡԿΛ͖͢Ͱɺ͖͢Ͱͳ͍͔ should
– ϓϩάϥϛϯά͖͕ͩ͢طͷࢦಋ͓ͦΒ͖͘͢Ͱͳ͍
• ͲΜͳ߅ͱো͕͋Δͷ͔ resist
– தֶߍʹϓϩάϥϛϯάֶशͷࢧԉ͕ෆཁ͔͠Εͳ͍
– ίϯςϯπཱ͕͠ͳ͍͔͠Εͳ͍
– ੜెֶ͕शΛड͚ೖΕͳ͍͔͠Εͳ͍
d. ݕূ
Πϕϯτ։࠵ཁ͕͋Γίϯςϯπͷ্ཱͪ͛ͱ࣮ূࢼݧ·ͰਐΉʙ
ґཔऀͷҙʹΑͬͯɺऔΓΈશମͱ͍ͯͣ͠Ε͔Λֶߍʹ͍࣋ͬͯ͘લʹ·ͣاۀओ࠵ͷֶ
शΠϕϯτͰͷΞϐʔϧͱ࣮ͮ͘ΓΛ͢Δ͜ͱʹͳΔɻΠϕϯτͰରऀֶश༰ʹؔͯ͠σʔ
λ͕औΕΔɻલ߲Ͱڍ͛ͨԾઆΛ۩ମతʹͯ͠ݕূ͢ΔઈͷػձͷͨΊͲΜͳܗͰ͋Ε 21 ʢ2
ޙʣ࣮ࢪͷίϯςϯπҊΛࡦఆͯ͠ࢼݧʹྟΉɻ͜ͷͱ͖ 2019 5 ݄ͰՆͷΠϕϯτ։࠵·Ͱ
Γ 3 ϱ݄͕ͩͬͨ 20 ʹऔΓΉΞΫγϣϯͷํੑʹӨڹ͢Δͱߟ͑ΒΕͨɻڠྗऀΛ૿
ͭͭ͠ΠϕϯτࢀՃऀʹ͚ͨ։࠵֓ཁతͱ͍ͬͨاըࣗΒܝ͛ͳ͚ΕͳΒͳ͍ɻσόΠ
εʹ͍ͭͯɺ͜ͷ࣌ͰͷఆσόΠεΛ Android λϒϨοτͱઃఆͨͨ͠Ίͯ͢ͷૢ࡞λο
νը໘ೖྗόʔνϟϧΩʔϘʔυʹݶఆ͠ɺNexus5 λϒϨοτΛ 30 आΓ͖ͯͯ։࠵ʹྟΜͩɻ
46
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.4 ͷղ
˞ͷͪʹ۠ͷ PC ͱͯ͠ Windows λϒϨοτܕ͕ࢧڅ͞Ε͍ͯΔ͜ͱ͔Βޙऀ͕λʔήοτʹ
ͳΔ
୲ऀϨϕϧͷঢ়گͱඪ͕ݟ͖͑ͨͨΊɺࢹΛʮࣗࣗʯͱ͢Δʮ5W1HʯͰཧ͢Δɻ
ࣗࣗʹͱͬͯ
• ԿΛ͢Δ͜ͱͳͷ͔ what
– ֶߍͰ࣮ࢪֶ͍ͨ͠शࢧԉͷ࠷খߏʢMVPʣͱΧϦΩϡϥϜҊΛ࡞͢Δ
– ґཔऀ͕ΉֶशΠϕϯτΛ։࠵͠ࢧԉͷ࣮ݱࣗମΛ͢Δ
• ୭͕Δͷ͔ who
– ͪΖΜࣗࣗ
• ͍ͭͷ͜ͱͳͷ͔ when
– 2019 Նʢ3 ϱ݄ޙʣͷΠϕϯτ·Ͱʹୡ͢Δ
• ୭ʢͲ͜ʣʹର͢Δ͜ͱͳͷ͔ where
– ΠϕϯτԠื͖ͯͨ͠தֶੜ
• ͳͥΔͷ͔ why
– 20 ʢ࣍ʣ
ɺ21 ʢ࣍ʑʣʹֶߍΦϑΝʔ͢ΔͨΊͷσʔλऔಘͱલྫͮ
͘ΓͷͨΊ
• Ͳ͏Δ͔ how
–ʢ࠷ऴతʹʣήʔϜ੍࡞తεΫϦϓτͷԠ༻ͱήʔϛϑΟέʔγϣϯʢ՝ͷήʔϜԽʣʹ
ΑΔֶशίϯςϯπΛఏڙ
– ٕज़తʹʮήʔϜ੍࡞తεΫϦϓτʢΠϕϯτεΫϦϓτͱͯ͠ར༻͞Ε͍ͯΔݴޠʣ
ʯ͕
ͷϥϯλΠϜͰར༻Ͱ͖Δ͔ͷݕূ͕ඞཁ
• ࣗୡԿ͔Ͱ͖Δͷ͔ can
–ʢࢲʣήʔϜ͕ओ࣠ͷιϑτΣΞͷఏڙͱςΩετϓϩάϥϛϯάͷࢦಋ
– ࣍Ҏ߱Ͳ͏͍͏ల։ʹ͢Δ͔Λݟग़ࣔͤ͠Δਓ͔͍ؒࣗ͠ͳ͍ʢ։ൃͱࢦಋࢲ
ҰਓͳͷͰʣ
• ࣗୡԿΛ͖͢Ͱɺ͖͢Ͱͳ͍͔ should
– Α͍ػձΛಀͣ͞ΠϕϯτͰԾઆݕূʹد༩͢ΔσʔλΛͱΔʢ͖ʣ
– ४උظ͕ؒগͳ͍͔ΒͱػձΛಀ͖͢Ͱͳ͍
• ͲΜͳ߅ͱো͕͋Δͷ͔ resist
– ίϯςϯπ੍࡞͕ૂ͍௨ΓணͰ͖ͳ͍͔͠Εͳ͍
– ιϑτΣΞΠϕϯτࣗମ͕ظ௨Γ࣮ࢪͰ͖ͳ͍͔͠Εͳ͍
– ݕূ݁Ռͷσʔλ͕ෆຬΛ͔ࣔ͢͠Εͳ͍
ݕূ݁Ռ
४උʹ͓͍ͯ։ൃ 2 ϱ݄ͱςετ͓Αͼௐ 1 ϱ݄Λඅ͠ιϑτΣΞແࣄ։ൃʹޭͨ͠ɻ
ΠϕϯτࢀՃऀืूͷ࣌Ͱ༰ͷܝ͕ࣔඞཁͩͬͨͨΊهࡌ͢Δ༰Ͱ࣮֬ʹΰʔϧͰ͖Δͱ֬ఆ
47
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.4 ͷղ
Ͱ͖Δ·Ͱʹר͖ʹר͍ͯςετΛॏͶͨɻΠϕϯτʹ 25 ਓ΄Ͳͷࣾһ͔Βڠྗ͕ಘΒΕɺखް
͘େʹ։࠵Ͱ͖ɺ҆৺ͯ͠ΠϕϯτӡӦΛҕͶΔ͜ͱ͕Ͱ͖ͨɻऔಘσʔλͱͯ͠ɺதֶੜ͕ς
Ωετϓϩάϥϛϯά͕͋Δఔ·Ͱ࣮ફͰ͖ͨՌɺͭ·͖͍ͣ͢ՕॴɺΞϯέʔτʹΑΔڹ
ΛಘΔ͜ͱ͕Ͱ͖ͨɻͦΕ͔Β͍ͨΜҙຯਂ͍͜ͱͱͯ͠ɺϓϩάϥϛϯάʹڵຯ͕͋Δ͕औΓ
ΜͰ͍ͳ͍ະܦݧऀͷϖϧιφʢސ٬Ϟσϧɺఆଐੑͷਓ૾ͷҙຯʣ͕֫ಘͰ͖ͨ͜ͱ͕ڍ͛Β
ΕΔɻσʔλͱϖϧιφʹؔͯ͠ɺฐࣾશࠃ͔Βདྷࣾ͢Δʮֶߍ๚ड͚ೖΕʯΛߦ͍ͬͯͨ͜
ͱ͕͍͠ɺͦͷޙ΄΅ಉ݅ͷֶशΛ࣮ࢪͯ͠ܧଓతʹԠΛݟͯௐ͕ܧଓͰ͖ͨɻͬ͘͟
ΓԆ 100 ਓҎ্ࢼߦͰ͖ͨɻ
ਤ: αϚʔΩϟϯϓ 2019
ਤ: اۀ๚ϓϩάϥϜ
48
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.5 ඪઃఆͱߦಈࢦ
5.5 ඪઃఆͱߦಈࢦ
a. Πϕϯτޙͷܦա
ΠϕϯτΛ࣮ࢪͨ͜͠ͱͰۮવ͕Ұͭൃੜͨ͠ɻెาݍʹ͋Δۙྡͷެཱதֶߍͷੜె͕ਃ͠ࠐΜ
Ͱ͘Εͨ͜ͱ͔ΒىҼ͢Δɻ൴ϓϩάϥϛϯάͱΠϕϯτࢀՃʹର͍ͯͨ͠ΜҙͱرΛ࣋ͬ
͍ͯΔֶੜ͕ͩࣄʹΑΓࢭΉʹࢭ·Εͣܽ੮ͱͳͬͯ͠·ͬͨͱ͍͏ɻ͔͠͠൴Ѫ͖͢ਓ
ͩͬͨɻչ·ΕΔࣄଶʹΑΓ࣌ͷڭ৬һ͕ΘΓʹݟֶʹདྷࣾ͠ɺςΩετڭࡐΛ࣋ͪؼͬͯษ
ڧͤͯ͞Α͍͔ͱΘ͟Θ֬͟ೝΛٻΊ͖ͯͨͷͰ͋ΔɻͪΖΜঝͨ͠͏͑Ͱɺઌੜ͞Βʹ
90 ͷϫʔΫγϣοϓΛͯ͢ݟֶͯ͠ؼΒΕͨɻͦͷޙʹઌੜํͱݱঢ়ͷ͓͠Λฉ͍͍ͯ͘
ͱɺϓϩάϥϛϯάֶश ICT ׆༻ʢใ׆༻ʣʹࢦಋऀίϯςϯπͷ՝͕͋Γɺͦ͠
ͯੜెʹԿ͕࠷ద͔ͷॲཱ͕͍ͬͯͳ͍ঢ়گͰࡧ͍ͯ͠Δঢ়گ͕͏͔͕͍Εͨɻͦ͜Ͱಉߍ
ͷϓϩάϥϛϯάֶशࢧԉͱͯ͠ɺ͜ͷϫʔΫγϣοϓΠϕϯτΛϞσϧͱͨ͠ෳճֶशߨ࠲ͷ࣮
ݱΛࢦͯ͠ɺऔΓΈΛ۩ମԽ͍ͯ͘͜͠ͱʹ྆ऀ߹ҙͨ͠ɻ
ల։ͱͯ͠ґཔऀ͕ೋऀʹͳΔ͕ɺैདྷͷґཔऀͱͯ͠ॳΑΓแ͍ͯͨ͠ͱݴͬͯᴥᴪͳ
͘ɺ͋Δ͍ґཔऀͷޙΖଆʹҐஔ͢Δɻͭ·Γ૬खଆʹ͓͚Δʮࣗ৫ʯͱʮࣗࣗʯͷؔʹ
͋ͨΓɺґཔऀͰ͋Δ۠ͱֶߍʮ౷ׅ৫ʯͱʮ৫ʯͷؔʹ͋ͨΔɻΑΓ۩ମతͳͷऔ
ΓΈͱղܾΛҎͯ׆ಈͱՌΛࣔ͢΄͏͕ΑΓ༗ҙٛͰ͋Δͱߟ͑ɺैདྷͷґཔऀʢґཔऀᶃʣͷ
ҙࢥͷͱ۩ମతͳࢪࡦ࣮ࢪઌͱͳΔֶߍʢґཔऀᶄʣͷɺݸผͷࣄྫΛղܾ͢ΔऔΓΈʹ
ࢹΛམͱͨ͠ɻ
b. ࣋ଓతʹୡ͢Δߦಈࢦʹམͱ͠ࠐΉ
ґཔऀͷϫϯΞΫγϣϯ͘͠ 1 ϓϩμΫτͰͯ͢ղফ͠ͳ͍ɻϓϩδΣΫτ͕։࢝
͞ΕΔͱࣗͷඪࠓͷ՝͚ͩߟ͑ͯಥ͖ਐΜͰ͠·͍ɺ্৫ͷඪͱͦΕͯ͠·͏͜ͱ
͕ଟ͍ɻ
͜͜·Ͱݟ͖ͯͨࡾऀͷʮ5W1HʯΓޱΛม͑͞ΒʹผͷݟํΛͯ͠ݕ౼ΛਂΊΔɻࠓճͷ
έʔεʹ͓͚Δґཔऀͷͱɺओޠେ͖ͳ͘͘Γͷਓͷू·ΓͰ͋Γɺશମͷ࣋ଓత͔ͭॊ
ೈͳࢧԉΛඞཁͱ͢ΔͷͰ͋Δɻ͜ͷΑ͏ʹ࣌ؒ࣠ͷ͍՝ʹରͯ͠औΓΉͱ͖ʹ্ԼϨΠ
Ϡͷࢹ࠲Λߦ͖͠ɺ࣋ଓతʹୡ͠ଓ͚ΔʮߦಈࢦʯͱݸผͷʮඪઃఆʯΛͦͷ֬ೝͯ͠औ
ΓΉɻ
ܧଓͯ͠ʹऔΓΉதͰऴ࢝తΛݟࣦΘͣʹతΛߦ͢ΔͨΊʹ࣍ͷϑϨʔϜϫʔΫΛղ
આ͍ͨ͠ɻ
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
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.5 ඪઃఆͱߦಈࢦ
Πϕϯτ͔Β·Ͱͷ OKR
• ґཔऀᶄʹͱͬͯ
–ʢͲ͜Ͱʣࣗߍ 1ʙ2 ੜ
–ʢ͍ͭʣ࣮ݱͰ͖͏Δ࣌ظʹʢظඪʣ
–ʢͲ͏͖͢ʣ·ͣ์՝ޙֶशΫϥϒ׆ಈͳͲͷҙࢀՃͰ
–ʢͳʹΛʣΠϕϯτͰࣔ͞ΕͨΑ͏ͳϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔඪʣ
• ґཔऀᶃʹͱͬͯ
– ˞ มΘΒͣ
–ʢͲ͜Ͱʣ۠ͷٛڭҭɺ20 খֶੜͳͲ
–ʢ͍ͭʣͦͷ࣌ͷ࣍ɻ20 ͔Βͷॱ࣍ඞमԽʹ͚ʢظඪʣ
–ʢͲ͏͖͢ʣֶशࢦಋཁྖʹ४ڌ͢Δ࣮ࢪϝχϡʔͷఏࣔΛͯ͠
–ʢͳʹΛʣٛڭҭͷϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔඪʣ
• ࣗ৫ʹͱͬͯ
– ˞ มΘΒͣ
–ʢͲ͜Ͱʣதֶߍͷओʹٕज़Պ
–ʢ͍ͭʣதֶߍ͕ϓϩάϥϛϯάΛ࣮ࢪ͢Δ 2021 ·Ͱʢظඪʣ
–ʢͲ͏͖͢ʣຊདྷͷҙຯͷϓϩάϥϛϯάΛࢦಋ͠
–ʢͳʹΛʣґཔऀͷΉࢧԉΛ࣮ࢪ͢Δʢྔʹఆྔඪʣ
• ࣗࣗʹͱͬͯ
–ʢͲ͜ͰʣΦϑΟγϟϧʹରߍͷߍͰ
–ʢ͍ͭʣͭ·Γ 5 ϱ݄Ҏʹʢظඪʣ
–ʢͲ͏͖͢ʣΑ͍ػձΛಀͣ͞ɺԾઆݕূͱվળػձͱͯ͠ɺ͞Βʹࣄྫͮ͘Γͱͯ͠
–ʢͳʹΛʣֶߍͰ࣮ࢪ͖͢ߏͱΧϦΩϡϥϜΛߏֶ͠शࢧԉ͢Δʢఆྔඪʣ
ޙऀͷϦετͰɺֶߍͰ͋ΔʮґཔऀᶄʯࣗࣗͷରہͱͳΔΑ͏࠷্Ґʹܝࡌͨ͠ɻ͜Ε
ʹΑͬͯؒͷϨΠϠ৫ΛͲͷΑ͏ʹҙࣝ͢Δͷ͔͕มΘΓɺ࠷ԼҐඪୡͰ࠷্Ґඪ՝͕ղ
ܾͰ͖Δ͔ΛٻΊ͍ͯΔɺͱࣔ͢͜ͱʹͳΔɻ
d. ʮͲ͏ͬͯʯ෦ɺίϯςϯπͷߏஙʹ͚ͯ
ͦΕͰ࣍અ͔Βɺίϯςϯπͷاը։ൃʹΛ͚ͯղઆ͢ΔɻΠϕϯτͱͦͷޙʹ͓͍ͯͲͷ
Α͏ͳઓུҙਤΛͬͯൃɾاը͍͔ͯͬͨ͠ʹ͍ͭͯղઆͦ͠ͷख๏Λհ͍ͨ͠ɻ
51
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.6 ίϯςϯπاըͱ͞·͟·ͳੳ
5.6 ίϯςϯπاըͱ͞·͟·ͳੳ
ఏڙ͢ΔڭࡐͱΧϦΩϡϥϜʢҎԼίϯςϯπʣʹ͍ͭͯߟ͑Δɻ࣮ݱ͍ͨ͠ཁ݅ɺςΩετϓ
ϩάϥϛϯάͰήʔϛϑΟέʔγϣϯͱֶशͰ͋ΔɻมԽٿΛ͍͛ͨ༁Ͱͳ͍͕ɺطͱಉ͡
ͷΛ࡞ͬͯ·ͬͨ͘ҙຯ͕ͳ͍ɻطͱಉ͡Α͏ͳͱ͜Ζֶ͕शͰ͖Δͷͩͱ͢Δͱɺٸ͝
͠Β͑ͨͪ͜͠Βʹউ͕ͪͳ͍͏͑ɺΦϦδφϧΛར༻ͨ͠΄͏͕ϚγͱͳΔɻ·ͨڭҭۀքͰ
ɺڭࡐ։ൃձ͕ࣾઐੑΛ׆͔ͯ͠ൢച͍ͯ͠ΔΩοτ͕ͨ͘͞Μ͋Γɺ͢Ͱʹར༻͍ͯ͠Δ߹
͋ΔɻίϯγϡʔϚʔʢফඅऀʣʹ͚ͯɺήʔϛϑΟέʔγϣϯΛ׆ָ͔ͯ͠͠Έͳ͕Βֶश
Ͱ͖Δʢ·ֶͨशͱޛΒͤͳ͍ʣΞϓϦέʔγϣϯ͕ͨ͘͞Μ͋Δɻاըʹ͋ͨͬͯɺ
औΓΉ༨͕͋Δͷ͔Ͳ͏͔͔ΒௐΔඞཁ͕͋ΔͨΊɺࢢࣗΛ͔ͬ͠ΓݟΔ͜ͱ͔Β࢝
ΊΔɻ
a. STP ੳʢࢢλʔήοτϙδγϣϯʣ
৽نࣄۀΛల։͢Δ͏͑Ͱࢢʹ͓͚ΔཱͪҐஔΛ໌֬Խ͢ΔͨΊʹ༻͍ΔɺϑΟϦοϓɾίτ
ϥʔͷఏএͨ͠ϑϨʔϜϫʔΫͰ͋ΔɻSegmentationʢࢢࡉԽʣ - Targetingʢࢢબʣ -
PositioningʢཱͪҐஔʣɹͷ಄จࣈΛͱͬͯ STP ੳͱ͍͏ɻ୭ʹΉ͚Δͷ͕ద͔ɺڝ߹ͱͷ
Έ͚͕Ͱ͖Δ͔ʹ͍ͭͯࢹ֮తʹੳͰ͖Δɻ
ڝ߹ͱઃఆ͍͔ͨͭ͘͠ͷαʔϏε͓ΑͼΛհΩϟονίϐʔΛݩʹରྸΛྨ
͢Δɻ
ڝ߹ ༮ࣇ খֶੜʢʣ খֶੜʢதʣ খֶੜʢߴʣ தֶੜ ߴߍੜ Ұൠ
V ̋ ̋ - - - - -
P - ̋ ̋ - - - -
Q - ̋ ̋ ̋ - - -
S - ̋ ̋ ̋ - - -
H - ̋ ̋ ̋ ̋ ̋ ̋
N - - ̋ ̋ ̋ ̋ ̋
දͷྫͱ͔ͯ͠ΓͮΒ͍͕ɺ༗ྗͳ͕ौ͓ͯ͠Βͣಛ͕ଧͪग़͍͢͠ྖҬ͕
ʮதֶɾߴߍʯͱ͍͏λʔήοτԾઆ͕ݟ͑ͨɻಉ༷ͷηάϝϯτʹ͋Δ Hɾ N ͳͲͷڝ߹
ͱͷϙδγϣϯͰɺ
ʢॳʣAndroid λϒϨοτΛத৺ʹ͢Δ͜ͱͰϓϥοτϑΥʔϜʹΑΔࠩผ
ԽΛૂͬͨɻͦͷ΄ֶ͔शྖҬͷॅΈ͚ΛධՁ͠ͳ͕Βɺதֶֶशࢦಋཁྖ͕ࣔ͢ʮωοτϫʔ
Ϋʯͷར༻Λߟྀ͢Δ෦ྫ͕গͳ͍ɻ·ͨςΩετϓϩάϥϛϯάͷڝ߹ͰશମతʹυϦϧܗ
͕ࣜଟ͍ͨΊɺ׆༻ࣗݾ࣮ݱʹͭͳ͛ΔֶशͳͲɺֶशࣗମͷػೳΑΓʮԠ༻ʯʹࠩผԽ͢Δϙ
ΠϯτΛஔ͚Δɻ˞ϓϥοτϑΥʔϜʹ͍ͭͯผهͨ͠௨Γͦͷޙ Windows λϒϨοτ PC ͷ
ఏڙʹࢸΔ
52
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.6 ίϯςϯπاըͱ͞·͟·ͳੳ
b. VRIO ੳʢڝ߹༏Ґੑʣ
ܦӦࢿݯΛ 4 ͭͷࢹͰධՁ͠ੳ͢ΔͨΊͷɺδΣΠɾBɾόʔχʔ͕ఏএͨ͠ϑϨʔϜϫʔ
ΫͰ͋Δɻ4 ͭͷࢹɺValueʢܦࡁՁʣ- Rarityʢرগੑʣ- Inimitability ʢ฿ࠔੑʣ-
Organizationʢ৫ʣ
ɻ
• ܦࡁՁɹ ... ސ٬ࣾձʹͱͬͯՁ͕͋Δ͔
• رɹগɹੑ ... رগੑ͕͋ͬͯಛ͚ΒΕΔ͔
• ฿ࠔੑ ... ྨࣅ͕؆୯ʹग़ճͬͯ͠·͏͔
• ɹɹ৫ɹ ... ׆༻Ͱ͖Δ৫ʹͳ͍ͬͯΔ͔
ֶࣗࣾशίϯςϯπͷ VRIO ੳ
• ܦࡁՁ
– ؆୯ͰςΩετϓϩάϥϛϯάͰͪΐ͏ͲΑ͍ͷ͕গͳ͍தͰόϦΤʔγϣϯΛ࣋ͨͤ
ֶͨͼ͕֫ಘͰ͖ΔͨΊࢦಋؚΉύοέʔδʹର͢ΔՁͱͯ͠ଧͪग़ͤΔ
• رগੑ
– ςΩετϓϩάϥϛϯάίϯςϯπɺήʔϛϑΟέʔγϣϯ՝ֶशɺςΩετϓϩάϥ
ϛϯάͷࣗ༝͕࣋ͭόϥΤςΟɺࣾһ͕ࢦಋɺͷֻ͚ࢉʹرগੑ͕͋Δ
• ฿ࠔੑ
– ιϑτΣΞɾΧϦΩϡϥϜɾࢦಋɾԠ༻ͷཁૉ͕͋Γ࣮ݱίετ͕ൺֱతߴ͍
– ฐࣾͷεϚʔτϑΥϯΞϓϦʮϞϯελʔετϥΠΫʯʹొ͢ΔਓؾΩϟϥΫλʔʮΦ
ϥΰϯʯ͕׆༻͞Ε͓ͯΓɺֶशʹର͢ΔোนΛݮΒ͠ಠࣗੑɾݸੑ͕ߴ·͍ͬͯΔ
• ৫
– ͜ͷྖҬʹ͓͍͔ͯͳΓͷࡋྔΛͬͯ΄ͱΜͲࣗ༝ʹͤͯ͞Β͍͑ͯΔͨΊɺ࡞ͬͨ
ίϯςϯπΛ׆༻͠ల։͢ΔͨΊʹ·ͨ׆ಈͦ͠ΕͧΕΛ݁ͼ͚Δ͜ͱ͕Ͱ͖Δɻ
ʢࠓ
ճͷࣥචͦͷҰͰ͋Δʣ
ΑΓΑ͍ੳͱ݁ՌΛ׆͔͢৫ʹ
VRIO ੳΛཧղͨ͠͏͑ͰϓϩδΣΫτߦ͍ͯ͠ΔͷͰ͋ΕɺͦͷϓϩμΫτʢͱαʔ
ϏεΛؚΉʣ͕༗ҙٛͰ͋Δͷ͔ɺ͋Δ͍ΑΓྑ͘ΑΓ͍҆ͷ͕͢Ͱʹଘࡏͨ͠Γ͙͢ग़ճͬͯ
͠·͏ͷ͔ΛݟΔ͜ͱ͕Ͱ͖Δɻڝ߹༏Ґੑݸੑʢྑ͞ʣΛཧղͨ͠͏͑Ͱίϯςϯπ։ൃ͔Βఏ
ࣔ·Ͱ͕ߦ͑ΔͷͰ͋Εɺ୯ʹ͍͔͠ΒɺײҠೖ͍ͯ͠Δ͔Βɺͱ͍ͬͨओ؍తͳηʔϧε
ϙΠϯτʹྗΛೖΕͯޡͬͨૌٻΛͯ͠͠·͏Մೳੑ͕ݮΔͩΖ͏ɻ
݁Λม͑ΒΕͳ͍৫͕ੳΛ͢Δ͜ͱҎ্ʹແՁͳͷͳ͍ɻաڈܦݧͨ͠ଟ͘ͷϓϩμ
ΫτͰϏδωεϩδοΫखஈͷબఆ͕ઌʹ͋ΓͦͷؒΛίϯςϯπاըͰຒΊ͍ͯΔɻVRIO
ੳͷ؍ͦͷ΄͔ͷ༗ޮͳੳͰ༏ҐੑՁ͕ࣔͤͳ͍ͷͰ͋ΕɺͰ͖Δ͚ͩૣ͍λΠϛϯά
ͰͷʮϐϘοτʯΛɺͭ·ΓยΛͣΒ͢มֵ͕·ΕΔɻ
53
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.7 ΞΠσΞͷൃͱࢥߟ
5.7 ΞΠσΞͷൃͱࢥߟ
a. ϑϨʔϜϫʔΫʮϦʔϯΩϟϯόεʯͰߟ͑Δ
ىۀɾࣄۀΞΠσΞΛՄࢹԽͯ͠ɺݕূ͠վળ͢Δ͏͑Ͱʹཱͭߟ͑ํͷҰͭɻͦͷத͔Βɺί
ετऩӹɺ΄΅֬ఆ͍ͯ͠Δྲྀ௨νϟϯωϧͳͲΛল͖ͳ͕ΒԼهʹݶఆ͢ΔͱࠓճධՁ߲ͱ
ͯ͠ར༻͍͢͠ɻ
1. ސ٬ͷ՝
2. ސ٬ηάϝϯτ
3. Ձ
4. ιϦϡʔγϣϯ
5. ༏Ґੑ
ʮϦʔϯΩϟϯόεʯͦͷલͰ͋ΔʮϏδωϧϞσϧδΣωϨʔγϣϯϚοϓʯͰɺ͜ΕΒ
ΛؚΉ 9 ߲΄ͲΛϚτϦοΫεతͳදʹͯ͠Ծઆݕূ͠ෳҊ͔Β༗ޮͳͷΛऔࣺબ͍ͯ͠Δɻ
ਤʹͤͣͱ͜ͷπʔϧػೳ͠ߟ͑ํͷπʔϧͱͯ͠·͞ʹʮղܾʯͷΞϓϩʔνͦͷͷͱ
ͯ͠ݟΔ͜ͱ͕Ͱ͖Δɻ
ਤ: Ωϟϯόεͷྫ
ڭҭࢧԉͷՁͱιϦϡʔγϣϯ
ࣗࣾίϯςϯπΛͯΊͯߏ͢Δͱ...
• ސ٬ͷ՝
–ʢͲ͜Ͱʣ۠ͷٛڭҭɺ20 খֶੜͳͲ
–ʢ͍ͭʣͦͷ࣌ͷ࣍ɻ20 ͔ΒͷඞमԽʹ͚ʢظඪʣ
–ʢͲ͏͖͢ʣֶशࢦಋཁྖʹ४ڌ͢Δ࣮ࢪϝχϡʔͷఏࣔΛͯ͠
–ʢͳʹΛʣٛڭҭͷϓϩάϥϛϯάֶशࢧԉΛ͢Δɹʢఆྔඪʣ
• ސ٬ηάϝϯτ
–ʢͲ͜Ͱʣதֶߍͷओʹٕज़Պ
54
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.7 ΞΠσΞͷൃͱࢥߟ
• Ձ
– ະܦݧऀ͕ςΩετϓϩάϥϛϯάΛ͍͖ͳΓମݧͰ͖Δ
– ΤϯδχΞ͕ߨࢣʹདྷΔ
– ϢχʔΫͳڭࡐͰָ͠Έͳ͕ΒֶशͰ͖Δ
• ιϦϡʔγϣϯ
– ςΩετϓϩάϥϛϯάΛଧͪࠐΜͰࢼͤΔ
– ଧͪࠐ·ͳͯ͘ςΩετϓϩάϥϛϯάֶ͕Δ
– ϓϩάϥϛϯάͷυϦϧֶश͕Ͱ͖Δ
– ࡞੍࡞ڭՊͷԠ༻ʹΑͬͯϓϩάϥϛϯάࣗମ͕πʔϧʹͳΔ
• ༏Ґੑ
– ॳΊ͔ΒதֶΛϝΠϯλʔήοτʹ͍ͯ͠ΔͨΊҰఆͷద߹ੑ͕͋Δ
– ήʔϜͱαʔϏεͷձࣾΒָ͍͠͠·ͤํ͕͋Δ
– ֶशͷόϦΤʔγϣϯδϟϯϧ෯͕ͱΕΔ
• ظݶ͕͋ΔதͰιϑτΣΞʹԿΛඋ͑ఏڙͰ͖Δ͔ͷج४...
– ϦʔϯελʔτΞοϓͷ MVPʢՁఏڙ࠷খʣΛ࣠ʹඞཁͳͷ͔Β࣌ؒͷݶΓʹ
࣮ݱ͢Δ
∗ Կ͕ MVP ͱͳΔ͔ 5W1H OKR ͷ্͔ΒԼ·Ͱͷͭͳ͕Γ͔Β͔ͭΉ
– UVPʢಠࣗͷՁఏҊʣ։ൃ͕࣮ݱͰ͖ͨ͜ͱͰ࣮֬ʹιϑτΣΞ͕ఏڙͰ͖Δཪ
͚ʹͳΔ
∗ पΓͷػೳͳΜͱͰͳΓɺ࠷Ͱඋ͑ͯͳͯ͘తࣗମୡͰ͖Δ
ਖ਼͍͠ݕ౼ͷॱংͰߏ͢Δ
ҙ͓ͯ͘͠෦ͱͯ͠ʮιϦϡʔγϣϯʯͭ·Γ͕࣮ݱ͢ΔػೳΛ͔ͬͯͳ͑Δ෦ 9
߲ͷ͏ͪͷ 1 ͭͰ͔͠ͳ͘ɺ
ʮΞΠσΞʹറΒΕ͗͢Δͳʯͱ͍͏ϝοηʔδ͕ͦ͜ʹ͋Δͱ
͍͏͜ͱͩͦ͏ͩɻՁιϦϡʔγϣϯʹϦʔϯελʔτΞοϓͷ MVPʢՁఏڙ࠷খʣ
͔Β࣮ݱͯ͠ݕূ͢Δ͜ͱ͕ॏཁͰ͋Δͱड़ΒΕ͍ͯΔɻ·ͨ MVP ͷ৺ଁ෦ɺͭ·Γ UVPʢಠ
ࣗͷՁఏҊʣ͕ڝ߹༏Ґੑʹͭͳ͕ΓͦͷαʔϏεΛಛ͚ͮΔͱ͍͏ɻ
ΩϟϯόεʹͯΊͳ͕ΒߏͱݕূΛߦ͖དྷ͢Εɺม͑Δ͖Օॴ͕ɺૌٻ͢ΔʮՁʯͦ
ͷͷͳͷ͔۩ݱԽ͢ΔʮιϦϡʔγϣϯʯͳͷ͔͕໌֬ʹѲͰ͖Δɻߟ͕͑ٴͣʹ͋Ε͜Εม
͍͑ͯΔͱ͖ͦΕʮιϦϡʔγϣϯʯͭ·Γ۩ମతͳखஈΛม͍͑ͯΔ͚ͩͰՁ͕มΘ͍ͬͯͳ
͍Մೳੑ͕͋ΔͩΖ͏ɻਖ਼͍͠ೝࣝͷʮ՝ʯͱʮސ٬ʯͷؒʹͦͷʮՁʯ͕ఆٛͰ͖͍ͯΔ͔ɺ
ݕ౼ͷॱং·ͨॏཁͳҙຯΛ࣋ͭɻ
55
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.7 ΞΠσΞͷൃͱࢥߟ
b. ղܾΞϓϩʔνͱͯ͠ͷʮσβΠϯࢥߟʯ
σβΠϯࢥߟղܾͷϑϨʔϜϫʔΫͷҰͭͰɺͱͱσβΠφʔͰ༻͍ΒΕΔࢥߟ๏ͰԾ
આͱݕূʹΑͬͯݚຏ͍ͯ͘͠औΓΈํʹϏδωεͷ՝ղܾͱͷڞ௨͕͋Δɻࢥߟͷํ๏࣍
ͷͱ͓Γɻ
• ڞɹײɹɹɹ ... ใऩूֶशɺϢʔβʔͱڞײ͢Δ
• ఆɹٛɹɹɹ ... Ϣʔβʔͷؾ࣋ͪͰʹؾ͘ɺੳ͠ఆٛ͢Δ
• ɹɹɹɹ ... ΛղܾͰ͖ΔΞΠσΞΛ͍͔ͭ͘͠ڍ͛Δ
• ϓϩτλΠϓ ... ΞΠσΞ͕࣮ࡍʹࢼͤΔΑ͏ʹࢼ࡞͢Δ
• ςετɹɹɹ ... ࢼ࡞ͨ͠Λ࣮ࡍʹςετ͠ධՁ͢Δ
։ൃͷϑΣʔζ͕σβΠϯࢥߟΛదԠ͍͢͠ɻڭࡐιϑτΣΞ։ൃ࣌ʹ͜ͷࢥߟΛͯ
ΊͨྫΛڍ͛Δɻ
• ڞײ
– ίϯϐϡʔλૢ࡞ͦͷͷॳ৺ऀֶ͕ͩशͷຊ࣭Ͱͳ͘ϓϩάϥϛϯάΛֶͼ͍ͨ
• ఆٛ
– ॳ৺ऀͳͷͰΩʔϘʔυೖྗͳΜͯͯͨ͠Β͕Εͯ͠·͏͠໘ʹͳΔ
•
– จࣈೖྗΛͤͣೖྗ͢ΔԿΒ͔ͷػೳ͕͋ΕମݧͱֶशʹूதͰ͖Δ
• ϓϩτλΠϓ
– ίʔυૠೖϘλϯͷ࡞
• ςετ
– ݕূͰλΠϐϯάෆಘखͰίʔυૠೖػೳͰετϨεͳ͘Γ͖Εͨʢߠఆʣ
– ߦͱΠϯσϯτϒϩοΫʹ͍ͭͯͷཧղෆʹΑΓೖྗϛε͕ى͜Δʢվળʣ
͜ͷݕূͱͦͷޙͷ࣮ݱʹΑͬͯதֶ 1 ͳͲλΠϐϯάෆಘखͷֶੜͪΖΜͷ͜ͱখֶੜ
Ͱ͋ͬͯར༻Ͱ͖Δɻґཔऀ͔ΒখֶߍͰͷར༻Λͯ͠Α͍Μ͡Όͳ͍͔ͱظ͕͕͋ͬͨɺ
ݱ࣌Ͱখֶੜͷࢦಋͦͷͷͷ͕͋͠͞ΔͨΊԕྀ͍ͯ͠Δঢ়گͰ͋Δɻͳ͓զ͕Ոͷখ 1
ʢ࣌ʣͷ່͕ͳΜͱ͔ΫϦΞ͍ͯͨ͠ɻ
56
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.7 ΞΠσΞͷൃͱࢥߟ
ਤ: ϓϩάϥϛϯάମݧߨ࠲
57
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.7 ΞΠσΞͷൃͱࢥߟ
c. ৽͍͠ΞϓϩʔνʮετʔϦʔࢥߟʯͰΓ։͘
ͦ͏͜͏ΞϓϩʔνΛߟ͑ͳ͕ΒऔΓΜͰ͍Δ͏ͪղܾͷاըͱͷ௨͠ํʹίπ͕͔ͭ
Ίͯ͘Δɻ͓·͚ͱͯۙ͠گͰࢲ͕࣮ફ͍ͯ͠Δߟ͑ํͷҰͭʮετʔϦʔࢥߟʯͳΔͷΛհ͠
͓͖͍ͯͨɻࢥߟΦϦδφϧͰ͋Γݺশ͜͜Ͱͷղઆ༻ʹ͚͍ͯΔ͚ͩͰจ͕͋ΔͷͰ
ͳ͍͕ɺ༗ޮͳہ໘͕͔ͳΓଟ͋͘Δͱߟ͍͑ͯΔɻ
• ސ٬ͷཧΛݟΔ
– ސ٬ͷΛฉ͖ใΛऩू࣮͠ݱ͍ͨ͠ͶΒ͍ͱͦͷഎܠΛݟΔ
∗ʢ࣮ྫʣ์՝ޙֶशΑΓٕज़Պͷतۀࢧԉ͕ཉ͍͠ɺΑΓೝͷ͋ΔݴޠΛֶͤͨ
͍ɺPTA ͷҙݟټΈ͍ͨɺཧڭҭͰઌߦ͍ͨ͠ɺઐڭ་͕গͳ͘ରԠͰ͖ͳ͍
• ϓϩοτΛ࡞Δ
– ےಓʹ߅͑ͳ͍τϐοΫͱΩʔϫʔυͰετʔϦʔΛଧཱͪͯΔ
∗ʢ࣮ྫʣٕज़Պใͱͯ͠ɾߴߍͰ͞ΒʹߴԽ͢Δใֶशʹඋ͑ͯɾ৬ۀʹͰ͖
ͯ͜Ε͔Βֶͼ͍ͨςΩετϓϩάϥϛϯάݴޠ No1 ͷ Python ݴޠΛɾ४උͱૢ
࡞ͷख͕͔͔ؒΒͳ͍ΦϦδφϧΞϓϦΛ͔ͭͬͯɾઐߨࢣ͔ΒखʹڭΘΓɾϓ
ϩάϥϛϯάͰ࡞੍࡞͕Ͱ͖ΔΑ͏ʹͳΔ·Ͱͷઌߦֶͨ͠शΛɾਪਐֶ͍ͨ͠ߍ
ͷڭ་ʹΈ͍͍ͯͨͩͯतۀઃܭ࣮͠ࢪ͢Δͱɾٕज़Պڭ་͕औΓΜͩͷͰ࣮ࢪ
ྫ͕͋ΔͨΊ۠શߍͷల։͕ಉ͔ʹͰ͖Δɻ
• ࣮ʹ GIVE ͢Δ
–ʮGIVEʯॻ੶ʮGIVE ˍ TAKEʯʹొ͢ΔߦಈಛੑͰଞऀ༩͑ΔߦಈΛࣔ͢
– ϓϩοτҎ্ͷڻ͖Λ༩͑Δ࡞ʢʣΛ࣮ʹࣔ͠ސ٬ GIVE Λି͚ͭ͠ Funʢຯ
ํʣʹม͑Δ
∗ʢ࣮ྫʣεέδϡʔϧతʹΏͱΓΛ࣋ͬͯܦաͷ༰Λ։ࣔͯ͠ɺ֬ೝऀ໔Ӹ͕ͳ
͍Ώ͑ιϑτΣΞෆ۩߹θϩͰ͋Γଓ͚ɺ͔Ώ͍ͱ͜Ζʹख͕ಧ͖؆୯͕͞ࡍཱ
ͭΑ͏ʹ͠ɺࢹ֮తʹڻ͖͕͋ΔίϯςϯπΛؚΈɺͱ༰ͷઐՈͰ͋Δ͜ͱ
Λࣔ͠ɺސ٬ͷݸਓతͳతح৺ʹ͔͑ͬ͞͠Γ͖߹͏ɻ
• ΈंʹΔ
–ʮΈंʯॻ੶ʮϏδϣφϦʔΧϯύχʔʯʹొ͢Δ
– ࢿݯͱ࣌ؒ༗ݶͳͷͰߦಈඞͣೋ࣍ࡾ࣍ར༻Λલఏʹաڈͱະདྷʹͭͳ͛Δετʔ
ϦʔΛඳ͘
– ෳͷސ٬ͷղܾΛ 1 ΞΫγϣϯͰຬͨͦ͠ͷઐՈʹͳΔ
∗ʢ࣮ྫʣ
ʮֶशΠϕϯτʯͰಋೖͨ͠ϏΪφʔ͚ςΩετϓϩάϥϛϯάମݧιϑτ
ʢLua ݴޠʣΛస༻͠ʮٕज़Պʯͷ Python ֶशʹਐԽɻͦͷޙͱΧϦΩϡϥϜ
స༻͠ʮ෦׆ʯͷΑΓߴͳ࣮ફʹ׆͔͓ͤͯΓ૬ޮՌͰͱͱͷίϯςϯ
πͱͱʹൃలͨ͠ɻࠓޙ͞Βʹผतۀͷίϯςϯπʹస༻͠׆͔͘͢४උ͠
͍ͯΔɻ
58
ୈ 5 ষ ֶߍఏڙιϑτΣΞͰղܾ 5.7 ΞΠσΞͷൃͱࢥߟ
ਤ: Python ֶशը໘
59
ୈ 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
ୈ 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
ୈ 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
ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴͳࢢ۠ொଜఆ 6.1 ͡Ίʹ
ਤ 6.1: 1 จࣈͷ GeoHash
63
ୈ 6 ষ BigQuery Ͱ GeoHash ʹΑΔߴͳࢢ۠ொଜఆ 6.1 ͡Ίʹ
ਤ 6.2: 2 จࣈͷ GeoHash
64
ୈ 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
ୈ 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
ୈ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
ୈ 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
ୈ 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
ୈ 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
ୈ 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(
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
) 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
) = 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
ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ
super.onDestroy()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = mediaSession
}
AndroidManifest.xml
android:name=".PlayerService"
android:exported="false"
android:foregroundServiceType="mediaPlayback">
αʔϏε্Ͱ 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({
// MediaControllerExoPlayerͱಉ͘͡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
ୈ 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
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
ୈ 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
ୈ 7 ষ Android ͷಈը࠶ੜΞϓϦͷ࡞Γํ 2022 7.3 ಈը࠶ੜΞϓϦͷ࡞Γํ
Λඇදࣔʹ͍ͨ͠߹ɺҎԼͷΑ͏ʹ addOnPictureInPictureModeChangedListener() Λ࣮ߦ
ͯ͠ PiP ϞʔυͷΓସ͑Λࢹ͠·͢ɻ
PlayerActivity.kt
class PlayerActivity : AppCompatActivity() {
private val pipListener = Consumer { 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
ୈ 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()
.firstOrNull()
}
.collect { foldingFeature ->
// TODO ંΓͨͨΈͷঢ়ଶʹΑͬͯUIΛߋ৽͢Δ
foldingFeature.state // ંΓͨͨΜͰ͍Δ͔Ͳ͏͔
foldingFeature.orientation // ંΓͷ͖
92
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 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
ୈ 8 ষ Unity Transport ղੳͱܰྔαʔό։ൃ 8.5 ऴΘΓʹ
ࠓճऔΓ্͛ΒΕͳ͔ͬͨ Pipeline ػߏΛ༻͍ͨ RUDP ௨৴ΑΓ࣮ફతͳαʔό։ൃʹ͍ͭͯ
ɺػձΛ͋ΒͨΊͯ·ͱΊΒΕͨΒͱࢥ͍·͢ɻ
101
ஶऀհ
٢ ༐ଠ (ୈ 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
ஶऀհ
ౡ ޔ (ୈ 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
MIXI TECH NOTE #08
2022 9 ݄ 10 ɹॳ൛ୈ 1 ɹൃߦ
ஶɹऀ גࣜձࣾ MIXI ༗ࢤ
ൃߦॴ גࣜձࣾ MIXI
ҹॴ άϥϑΟοΫ
ɹ
MIXI