Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Micro Frontends の理論と実践 -価値提供を高速化する真のマイクロサービスのあ...
Search
nobuhikosawai
November 02, 2018
Technology
17
40k
Micro Frontends の理論と実践 -価値提供を高速化する真のマイクロサービスのあり方- / The Theory and Practice of Micro Frontends
AWS Dev Day Tokyo 2018でMicro Frontendsについて話したスライドです。
#MicroFrontends #マイクロフロントエンド
nobuhikosawai
November 02, 2018
Tweet
Share
More Decks by nobuhikosawai
See All by nobuhikosawai
GraphQLを用いたサイトに おけるパフォーマンス改善 (ECサイトを題材に)/ Improving online shopping site performance which using the GraphQL
nobuhikosawai
3
5.9k
Micro Frontends (example from micro-frontends.org)
nobuhikosawai
0
970
Railsのタイムゾーン
nobuhikosawai
4
2.4k
Other Decks in Technology
See All in Technology
LLMで構造化出力の成功率をグンと上げる方法
keisuketakiguchi
0
230
JAWS AI/ML #30 AI コーディング IDE "Kiro" を触ってみよう
inariku
3
260
【CEDEC2025】ブランド力アップのためのコンテンツマーケティング~ゲーム会社における情報資産の活かし方~
cygames
PRO
0
230
マルチプロダクト×マルチテナントを支えるモジュラモノリスを中心としたアソビューのアーキテクチャ
disc99
0
250
生成AI時代におけるAI・機械学習技術を用いたプロダクト開発の深化と進化 #BetAIDay
layerx
PRO
1
1k
Lambda management with ecspresso and Terraform
ijin
2
120
データ基盤の管理者からGoogle Cloud全体の管理者になっていた話
zozotech
PRO
0
320
【CEDEC2025】『Shadowverse: Worlds Beyond』二度目のDCG開発でゲームをリデザインする~遊びやすさと競技性の両立~
cygames
PRO
1
290
Mambaで物体検出 完全に理解した
shirarei24
2
210
マルチモーダル基盤モデルに基づく動画と音の解析技術
lycorptech_jp
PRO
4
490
家族の思い出を形にする 〜 1秒動画の生成を支えるインフラアーキテクチャ
ojima_h
1
190
20250728 MCP, A2A and Multi-Agents in the future
yoshidashingo
1
210
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.9k
Writing Fast Ruby
sferik
628
62k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
The Cost Of JavaScript in 2023
addyosmani
51
8.7k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
139
34k
Faster Mobile Websites
deanohume
308
31k
A better future with KSS
kneath
238
17k
Become a Pro
speakerdeck
PRO
29
5.5k
Rails Girls Zürich Keynote
gr2m
95
14k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.8k
Transcript
.JDSP'SPOUFOETͷཧͱ࣮ફ ՁఏڙΛߴԽ͢ΔਅͷϚΠΫϩαʔϏεͷ͋Γํ ᖒҪએ !OPCVIJLPTBXBJ גࣜձࣾ'J/$5FDIOPMPHJFT "84%FW%BZ5PLZP
ࠓશ͘͜Ε·Ͱͱҧ͏ ϚΠΫϩαʔϏεͷΛ͠·͢
"HFOEB !3 • ୈᶗ෦.JDSP'SPOUFOETͷཧ • ୈᶘ෦.JDSP'SPOUFOETͷ࣮ફ • ߟ • ·ͱΊ
"HFOEB !4 • ୈᶗ෦.JDSP'SPOUFOETͷཧ • ୈᶘ෦.JDSP'SPOUFOETͷ࣮ફ • ߟ • ·ͱΊ
.JDSP'SPOUFOET͕ղܾ͍ͨ͠ ͦͷͨΊͷٕज़
"HFOEB !5 • ୈᶗ෦.JDSP'SPOUFOETͷཧ • ୈᶘ෦.JDSP'SPOUFOETͷ࣮ફ • ߟ • ·ͱΊ
࣮ફ্ͨ͠Ͱͷݟ՝Λڞ༗͠·͢ ຊ൪ೖͷࢀߟʹͳΕʂ
Έͳ͞ΜϚΠΫϩαʔϏε͝ଘͰ͔͢ʁ
ϚΠΫϩαʔϏεͷϝϦοτ͏͚ͯ·͔͢ʁ
Α͋͘ΔϚΠΫϩαʔϏε !8 4FSWFS 4FSWFS $MJFOU 4FSWFS αʔόʔ গਓɾಠཱͨ͠ νʔϜ J04
"OESPJE 8FC
Α͋͘ΔϚΠΫϩαʔϏε !9 4FSWFS 4FSWFS $MJFOU 4FSWFS গਓ ಠཱͨ͠νʔϜ ϚΠΫϩαʔϏε ࠷ߴʂ
J04 "OESPJE 8FC
Α͋͘ΔϚΠΫϩαʔϏε !10 4FSWFS 4FSWFS $MJFOU 4FSWFS গਓ ಠཱͨ͠νʔϜ ϚΠΫϩαʔϏε ࠷ߴʂ
͋Εʁ ϚΠΫϩʁ
ΫϥΠΞϯταΠυ ϚΠΫϩαʔϏεͷϝϦοτ͏͚ͯ·͔͢ʁ
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !12 ͱ͋ΔϚΠΫϩαʔϏεͷ։ൃݱ ʢαʔόʔαΠυʣ
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !13 ࠷ߴͷاըΛࢥ͍͍ͭͨʂઈରͨΔʂ
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !14 ࠷ߴͷاըΛࢥ͍͍ͭͨʂઈରͨΔʂ ͓Ζ͍ʂ͑͑Μʂ͍͖ͬͯʂ
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !15 ͍ʂԶ࠷ߴͷاըΛࢥ͍͍ͭͨʂ Զఱ࠽ʂઈରͨΔʂ ͠Βͯ͘͠
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !16 ࠷ߴͷاըΛࢥ͍͍ͭͯ͠·ͬͨΜ͚Ͳʂ
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !17 ࠷ߴͷاըΛࢥ͍͍ͭͯ͠·ͬͨΜ͚Ͳʂ ͋ɺͦΕ͚ͬͪͩ͜Ͱ݁͠·͢Ͷʂ Γ·͢ʂ
ͱ͋Δ։ൃݱʢαʔόʔαΠυʣ !18 ͋ɺͦΕ͚ͬͪͩ͜Ͱ݁͠·͢Ͷʂ Γ·͢ʂ ʢϚΠΫϩαʔϏε࠷ߴɻɻɻʣ ࠷ߴͷاըΛࢥ͍͍ͭͯ͠·ͬͨΜ͚Ͳʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !19 ΫϥΠΞϯταΠυͷ߹
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !20 ࠷ߴͷاըΛࢥ͍͍ͭͨʂઈରͨΔʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !21 ࠷ߴͷاըΛࢥ͍͍ͭͨʂઈରͨΔʂ ͍ʂ ͍͖ͬͯʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !22 ͍ʂԶ࠷ߴͷاըΛࢥ͍͍ͭͨʂ Զఱ࠽ʂઈରͨΔʂ ͠Βͯ͘͠
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !23 ࠷ߴͷاըΛࢥ͍͍ͭͯ͠·ͬͨΜ͚Ͳʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !24 ΜʔɺӨڹൣғେৎ͔ͳʁ ؾΛ͚ͭͳ͕ΒΓ·͢ʂ ࠷ߴͷاըΛࢥ͍͍ͭͯ͠·ͬͨΜ͚Ͳʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !25 ΜʔɺӨڹൣғେৎ͔ͳʁ ؾΛ͚ͭͳ͕ΒΓ·͢ʂ ͋ΕʁϓϧϦΫΊͬͪΌίϯϑϦΫτ ͯ͠Δʁʁ ࠷ߴͷاըΛࢥ͍͍ͭͯ͠·ͬͨΜ͚Ͳʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !26 ίϯϑϦΫτ͍ͬ͢ʂʂ ༏ઌॱҐͱQAௐ͠·͢ʂ
ͱ͋Δ։ൃݱʢΫϥΠΞϯταΠυʣ !27 ίϯϑϦΫτ͍ͬ͢ʂʂ ༏ઌॱҐͱQAௐ͠·͢ʂ ͋Εʁ ϢʔβʔʹϦϦʔεͰ͖ͳ͍
ϚΠΫϩαʔϏεͷϝϦοτΛ ेʹ׆͔ͤͯͳ͍ʂ
ΫϥΠΞϯταΠυʹ ϚΠΫϩαʔϏεਫ਼ਆΛʂʂ
ͦ͜Ͱ.JDSP'SPOUFOETʂʂ
ୈᶗ෦.JDSP'SPOUFOETͷཧ
ϚΠΫϩαʔϏεͷ֓ཁ !32 • ʮϚΠΫϩαʔϏεɺڠௐͯ͠ಈ࡞͢Δখ نͰࣗతͳαʔϏεͰ͢ɻʯ • ϏδωεͷڥքͱαʔϏεͷڥքΛἧ͑Δ͜ ͱͰιϑτΣΞͷਝͳఏڙΛ࣮ݱ͠Ϗδ ωεΛՃ͢Δ
ϚΠΫϩαʔϏεͷϝϦοτ !33 • σϓϩΠͷಠཱ • αʔϏε͕͔Ε͍ͯΔͷͰσϓϩΠ͕ࣗ༝ʹͰ͖Δ • ٕज़ҟ࣭ੑ • αʔϏεಛੑ͝ͱʹ࠷దͳٕज़બ͕Մೳ
• ٕज़తෛ࠴ΛҾ͖ͣΓʹ͍͘ • ߹Մೳੑ • αʔϏε͝ͱʹదͳཻͷ"1*͕ެ։͞Ε͍ͯΔͨΊɺ࠶ར༻ੑ͕ߴ·Δ • ৫ͷࣗੑ • ίϛϡχέʔγϣϯύεΛݮΒ͠ɺҙࢥܾఆΛ͘͢͢Δ
ϚΠΫϩαʔϏεͷϝϦοτ !34 • ϙΠϯτߴڽूͱૄ݁߹ •ڽूͷߴ͍αʔϏε͕ૄ݁߹Ͱ͋Δ͜ͱʹΑΓߴ͍ࣗ༝ɾࣗੑ ͕ಘΒΕΔ •ٯʹαʔϏε͕ີ݁߹ʹͳΔͱϚΠΫϩαʔϏεͷྑ͞ফ͑Δ
ϚΠΫϩαʔϏεͷϝϦοτ !35 • ϙΠϯτߴڽूͱૄ݁߹ •ڽूͷߴ͍αʔϏε͕ૄ݁߹Ͱ͋Δ͜ͱʹΑΓߴ͍ࣗ༝ɾࣗੑ ͕ಘΒΕΔ •ٯʹαʔϏε͕ີ݁߹ʹͳΔͱϚΠΫϩαʔϏεͷྑ͞ফ͑Δ ͋ɺͦΕͬͪ͜ͷαʔϏεͰ͢ʂ Γ·͢ʂ ʢϚΠΫϩαʔϏε࠷ߴɻɻɻʣ
ϚΠΫϩαʔϏεͷϝϦοτ !36 • ϙΠϯτߴڽूͱૄ݁߹ •ڽूͷߴ͍αʔϏε͕ૄ݁߹Ͱ͋Δ͜ͱʹΑΓߴ͍ࣗ༝ɾࣗੑ ͕ಘΒΕΔ •ٯʹαʔϏε͕ີ݁߹ʹͳΔͱϚΠΫϩαʔϏεͷྑ͞ফ͑Δ ίϯϑϦΫτ͍ͬ͢ʂʂ
݁߹Λ͍͔ʹԼ͛Δ͔͕ ϚΠΫϩαʔϏεͷ՝
ϚΠΫϩαʔϏεʹ͓͚ΔϑϩϯτΤϯυ !38 • ϚΠΫϩαʔϏεͷ౷߹ϨΠϠʔ •Ϣʔβʔ͕ݟΔͷͭͷ8FCը໘ •6*Ϣʔβʔͷମݧ౷߹͞Ε͍ͯΔ ඞཁ͕͋Δ •݁߹͍͢͠ Side Bar
Contents Header Footer
ϑϩϯτΤϯυϞϊϦε !39 • ϑϩϯτΤϯυϞϊϦε • όοΫΤϯυϚΠΫϩαʔϏεԽͯ͠ ͍ΔͷʹϑϩϯτΤϯυϞϊϦγοΫ ͳঢ়ଶ • ݁߹͕ߴ͘ϚΠΫϩαʔϏεͷྑ͞Λ
ফͯ͠͠·͏
ϑϩϯτΤϯυͷ݁߹Λ Լ͛ΔʹͲ͏͢ΕΑ͍͔ʁ
֤ϚΠΫϩαʔϏε͕ ϑϩϯτΤϯυ·ͰఏڙͰ͖ΕΑ͍
.JDSP'SPOUFOETʂʂ
.JDSP'SPOUFOET !43 • ϑϩϯτΤϯυ·Ͱఏڙ͢ΔϚΠΫϩαʔϏε •֤όοΫΤϯυ+40/ͳͲͷσʔλͰͳ͘6*·ͰҰؾ௨؏ͯ͠ฦ͢
.JDSP'SPOUFOET !44 • ϑϩϯτΤϯυͰαʔϏενʔϜ͝ͱͷ։ൃΛՄೳʹ͢Δ
ͨͱ͑ʁ
.JDSP'SPOUFOETͷྫ !46 • &$αΠτΛྫʹ αϯϓϧNJDSPGSPOUFOETPSHΛ͓आΓ͍ͯ͠·͢ʣ
.JDSP'SPOUFOETͷྫ !47 • .JDSPTFSWJDFTΛಋೖ͍ͯ͠Δ •ϓϩμΫτνʔϜʢҰཡػೳʣ •νΣοΫΞτνʔϜ ߪೖػೳʣ •ϨίϝϯυνʔϜʢ͓͢͢Ίʣ
.JDSP'SPOUFOETͷྫ !48 • ֤νʔϜҟͳΔ,1*Λୡ͍ͨ͠ •ͷΫϦοΫʢϓϩμΫτνʔϜʣ •ߪೖྃʢνΣοΫΞτνʔϜʣ •Ϩίϝϯσʔγϣϯਫ਼ ʢϨίϝϯυνʔϜʣ
.JDSP'SPOUFOETͷྫ !49 • ϑϩϯτΤϯυϞϊϦεͰى͖Δ •σϓϩΠ͕ґଘ͢Δ •ҟͳΔٕज़ͷಋೖ͕ࠔ •৫͕ґଘ͢Δ
.JDSP'SPOUFOETͷྫ !50 • .JDSP'SPOUFOETͷ߹ •֤νʔϜ͕ͦΕͧΕͷίϯϙʔωϯτ·Ͱฦ͢ https://noti.st/naltatis/HxcUfZ/micro-frontends-think-smaller-avoid-the-monolith-love-the-backend#sRI5XtT
.JDSP'SPOUFOETͷྫ !51 • ͭͷը໘ʹରͯ͠ϚΠΫϩαʔϏε͝ͱʹෳίϯϙʔωϯτΛஔ ͢Δ • ౷߹ϨΠϠʔ͕औΓ·ͱΊΔ https://noti.st/naltatis/HxcUfZ/micro-frontends-think-smaller-avoid-the-monolith-love-the-backend#sRI5XtT
.JDSP'SPOUFOETͷྫ !52 • ϝϦοτ •σϓϩΠ͕༰қʹͳΔ •ҟͳΔٕज़࠾༻Մೳ •֤νʔϜͷࣗੑ͕ߴ·Δ
औΓΈͷࣄྫ !53 • औΓΜͰ͍Δاۀ •*,&" •4QPUJGZ •ͳͲ IKEA Spotify https://www.youtube.com/watch?v=4KVOuQDIfmw
https://www.slideshare.net/kevingoldsmith/how-spotify-builds-products-organization-architecture-autonomy-accountability
͑͑Μ
ͰͲ͏࣮ͬͯݱ͢Δͷ͔ʁ
.JDSP'SPOUFOETΛߏ͢Δٕज़ελοΫ !56 • ಉ͡ը໘ʹ֤ϚΠΫϩαʔϏε͕ίϯϙʔωϯτΛஔ͢Δ • JGSBNF •ੲͳ͕Βͷख๏ •Βͳ͍͏ͪʹ͜ΕΛಋೖͯ͠.JDSP'SPOUFOETΛ͍ͬͯΔ Մೳੑ͕͋Δ •
8FC$PNQPOFOUT •৽͍͠8FCͷ༷
8FC$PNQPOFOUTͱ !57 • ʮ8FC$PNQPOFOUTɺ࠶ར༻ՄೳͳΧελϜཁૉΛ࡞͠ɺΣϒ ΞϓϦͷதͰར༻͢ΔͨΊͷɺҰ࿈ͷςΫϊϩδʔͰ͢ɻίʔυͷଞͷ ෦͔Βಠཱͨ͠ɺΧϓηϧԽ͞ΕͨػೳΛ࣮ͬͯݱ͠·͢ɻʯ • $VTUPN&MFNFOUT • $VTUPN&WFOUT
$VTUPN&MFNFOUTͷྫ !58 • ։ൃऀ͕৽͍͠)5.-λάΛ࡞ͨ͠Γɺطଘଞͷσϕϩούʔ͕࡞ ͨ͠ίϯϙʔωϯτΛ֦ுͨ͠Γ͢Δ͜ͱ͕Ͱ͖Δ"1* • ྫ(JU)VC •K2VFSZͰ͍ͭͬͯͨ͘$PNQPOFOUΛ$VTUPN&MFNFOUTͰஔ <relative-time datetime="2018-08-21T21:44:05Z"
title="Aug 22, 2018, 6:44 AM GMT+9"> on Aug 22 </relative-time> https://githubengineering.com/removing-jquery-from-github-frontend/
• ߪങϘλϯΛग़͢ྫ $VTUPN&MFNFOUTͷྫ !59 class BlueBuy extends HTMLElement { constructor()
{ super(); this.innerHTML = ɹɹɹ`<button type="button">buy for 66,00 €</button>`; } disconnectedCallback() { ... } } window.customElements.define('blue-buy', BlueBuy); <blue-buy></blue-buy>
.JDSP'SPOUFOETͷ࣮ݱํ๏ !60 { "id": 1, "name": "foobar", "title": “hooray!” }
JSON { "id": 1, "name": "foobar", "title": “hooray!” } JSON { "id": 1, "name": "foobar", "title": “hooray!” } JSON { "id": 1, "name": "foobar", "title": “hooray!” } JSON • ैདྷόοΫΤϯυ ֤.JDSPTFSWJDFT ͕σʔλΛฦ͢
.JDSP'SPOUFOETͷ࣮ݱํ๏ !61 <div> <h1>hooray!</h1> <p>foobar</p> </div> <div> <h1>hooray!</h1> <p>foobar</p> </div>
<div> <h1>hooray!</h1> <p>foobar</p> </div> <div> <h1>hooray!</h1> <p>foobar</p> </div> HTML • ϑϩϯτΤϯυ ͭͷ6*ʹมͯ͠ ͍ͨ
.JDSP'SPOUFOETͷ࣮ݱํ๏ !62 class BlueBuy extends HTMLElement { constructor() { super();
this.innerHTML = `<button ></button>`; } disconnectedCallback() { ... } } window.customElements.define('b lue-buy', BlueBuy); JavaScript <blue-buy></blue-buy> HTML • 8FC$PNQPOFOUTͷఆٛʢ+4 Λฦ͢ • ౷߹ϨΠϠʔͦΕΛஔ͢Δ͚ͩ
None
.JDSP'SPOUFOETͷཧ·ͱΊ !64 • ϑϩϯτΤϯυϞϊϦεͷ՝Λղܾ͢Δ •σϓϩΠ͕ಠཱͰ͖ͳ͍ •ҟͳΔٕज़ΛબͰ͖ͳ͍ •৫ͷґଘ
.JDSP'SPOUFOETͷཧ·ͱΊ !65 • .JDSP'SPOUFOETϑϩϯτΤϯυ·Ͱఏڙ͢ΔϚΠΫϩαʔϏε
.JDSP'SPOUFOETͷཧ·ͱΊ !66 • ٕज़తʹJGSBNF8FC$PNQPOFOUTΛ࣮ͬͯݱ class BlueBuy extends HTMLElement { constructor()
{ super(); this.innerHTML = `<button ></button>`; } disconnectedCallback() { ... } } window.customElements.define('b lue-buy', BlueBuy); JavaScript <blue-buy></blue-buy> HTML
.JDSP'SPOUFOET ϑϩϯτΤϯυͷ݁߹ΛԼ͛ ϚΠΫϩαʔϏεͷϝϦοτΛ׆͔͢ʂ
.JDSPTFSWJDFT.JDSP'SPOUFOET
None
ձࣾհ !70 •'J/$5FDIOPMPHJFTϔϧεέΞͷϓϥοτϑΥʔϜΛӡӦ͍ͯ͠Δ •'J/$ΞϓϦɺ&$ɺاۀ͚ͷ݈߁ιϦϡʔγϣϯͳͲΛఏڙ •ϔϧεέΞΞϓϦϥϯΩϯά/P
ձࣾհ !71 •ϓϥοτϑΥʔϜΛ࠷Ͱఏڙ͢ΔͨΊʹϚΠΫϩαʔϏεΛऔΓೖΕ ͍ͯΔ •ࠓճ.JDSP'SPOUFOETΛ࣮ફͯ͠ΈͨͷͰݟΛڞ༗͠·͢
ୈᶘ෦.JDSP'SPOUFOETͷ࣮ફ
ϏδωεͷഎܠGJODBQQXFC !73 • 'J/$ʹੲ͔ΒGJODBQQXFCͱ͍͏ΞϓϦͷXFC൛͕͋Δ •4JOHMF1BHF"QQMJDBUJPO 41" Ͱ3FBDUKT •͙Β͍લ͔Β͋ΔׂͱϨΨγʔͳϑϩϯτΤϯυ
ϏδωεͷഎܠϐΞɾϘʔφεػೳ !74 • ࣾһʹࠒͷײँΛ͑Δ͓ྱϙΠϯτ༩ػೳΛࣾπʔϧͱͯ͠࡞ ͢Δ͜ͱͱͳͬͨ
ϏδωεͷഎܠϐΞɾϘʔφεػೳ !75 • ϔϧεέΞͷϓϥοτϑΥʔϜΛࢦ͢'J/$ͱͯࣾ͠πʔϧ ͱ͍͑ɺϐΞɾϘʔφεػೳGJODBQQXFC্ʹͷ͓͖͍ͤͯͨ • ී௨ʹ3FBDUΛ࣮͢Δ͜ͱߟ͑ΒΕΔ͕ɺ.JDSP'SPOUFOETΛ࠾༻ ͨ͠
ͳͥ.JDSP'SPOUFOETΛ࠾༻͔ͨ͠ !76 • ී௨ʹ3FBDUͰ͍͍ͷͰʁ •όοΫΤϯυ3BJMTͰ৽্ཱͪ͛͘͠Δ •νʔϜͷٕज़ελοΫతͱͯ͠3FBDUPO3BJMTͷϊϋ͕ཷ·ͬͯ ͍ͨ •ϨΨγʔͳGJODBQQXFCͷίʔυϕʔεΛ͋·Γେ͖ͨ͘͘͠ͳ͔ͬͨ •ͭ·Γ৽چ3FBDUͱ͍͏ٕज़ҟ࣭ੑ͕͋Δঢ়ଶ
ͳͥ.JDSP'SPOUFOETΛ࠾༻͔ͨ͠ !77 • Ұ.JDSP'SPOUFOETͷج൫͕͑ •ࠓޙ͍ΖΜͳαʔϏε͕ίϯϙʔωϯτΛఏڙͰ͖Δ •ඞཁʹԠͯ͡কདྷ؆୯ʹSFQMBDF͢Δ͜ͱͰ͖Δ •֤αʔϏε͝ͱʹಠཱͯ͠վम͕Ͱ͖Δ • ٕज़ҟ࣭ੑ߹Մೳੑ͕͋Δͱ͜ΖʹϝϦοτ͕͋Δ .JDSP'SPOUFOETΛ࠾༻
։ൃதͷը໘ !78 • ։ൃதͷ࣮ࡍͷը໘ͱαϯϓϧίʔυ
ίʔυΠϝʔδ !79 • ϐΞɾϘʔφεଆ class TimelineComponents extends HTMLElement { async
connectedCallback() { const mountPoint = document.createElement('span'); const shadow = this.attachShadow({ mode: 'open' }); shadow.appendChild(mountPoint); const currentUser = await UserRepository.fetch(); render( <React.Fragment> <link rel="stylesheet" type="text/css" href="http://localhost:3020/main.css"/> <Timeline currentUser={currentUser}/> </React.Fragment>, mountPoint, ); retargetEvents(shadow); } } customElements.define(‘peerbonus—timeline’, TimelineComponents);
ίʔυΠϝʔδ !80 • GJODBQQXFCଆ import React from 'react'; class PeerBonus
extends React.Component { render() { return ( <div className="l-main_contents_area"> <peerbonus-timeline></peerbonus-timeline> </div> ); } } export default PeerBonus;
࣮ફʹ͓͍ͯ໘ͨ͠՝ !81 • ࣮ࡍʹͲͷΑ͏ͳʹ͍ͭͯऔΓΜͩͷ͔Λհ͠·͢ • Ϗϧυͷ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝
• άϩʔόϧͳঢ়ଶͷڞ༗ • ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ • ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
DBDIFCVTUJOHͷ !82 • Ϗϧυͷ •DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝ • άϩʔόϧͳঢ়ଶͷڞ༗ •
ը໘ભҠ • ঢ়ଶཧ • ϥΠϒϥϦͷ • ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
എܠ !83 • 41"Ϗϧυ͕ඞཁ • ผͷϑΝΠϧΛJNQPSU͢Δ༷͕࠷ۙ·Ͱͳ͔ͬͨͷͰɺϥΠϒϥϦ Ͱ͕ΜͬͯCVOEMFͯ͠ຕʹ͍ͯ͠Δ •Ұ൪࢝ΊʹಡΈࠐ·ΕΔIUNM JOEFYIUNM
ͰϏϧυͨ͠ϑΝΠϧΛࢦఆ ͯ͠ಡΈࠐΉΑ͏ʹ͢Δ ϒϥβ HTML JS index.html bundle.js JS JS JS Ϗϧυ styleλά
എܠ !84 • Ϗϧυ͢Δͨͼʹҧ͏ϑΝΠϧ໊Ͱఏڙ͢Δඞཁ͕͋Δɻ •ಉҰϑΝΠϧ໊ͩͱϒϥβͷΩϟογϡ͕ޮ͍ͯมߋ͕ө͞Εͳ͍ ͜ͱ͕͋Δ •ϦϦʔε࣌ʹࠔΔ ϒϥβ HTML JS
index.html new bundle.js JS JS JS Ϗϧυ styleλά JS cached bundle.js ΩϟογϡΛࢀর
എܠ !85 • ௨ৗϑΝΠϧ໊ʹϥϯμϜͳจࣈྻʢDIVOLIBTI Λ͚ͭͯɺϏϧυ͝ͱ ʹҟͳΔϑΝΠϧ໊ʹͳΔΑ͏ʹ͢Δ ϒϥβ HTML JS index.html
new bundle-ac2c5.js JS JS JS Ϗϧυ styleλά JS cached bundle-c1df8.js ࢀর͞Εͳ͍
՝ !86 • ͭͷαʔϏεͰϏϧυJOEFYIUNMͷఏڙ͍ͯ͠Δͱ͖ͳ͍ •DIVOLIBTI͕Θ͔ΔͷͰɺJOEFYIUNMଆͰͦΕΛࢦఆͯ͠Δ͚ͩ HTML JS index.html bundle-ac2c5.js <script
src=“./bundle- ac2c5.js”></script>
՝ !87 • .JDSP'SPOUFOETͷ߹ •αʔϏε͕6*ఏڙଆʢJOEFYIUNMଆ ͱϏϧυଆͰΘ͔Ε͍ͯΔ •Ϗϧυ͝ͱʹDIVOLIBTI͖ͷϑΝΠϧ໊Λڞ༗͢Δͷ͕͍͠ HTML JS index.html
bundle-ac2c5.js <script src=“./bundle-?????.js”> </script>
ݕ౼ !88 • NBOJGFTUKTPOΛ͑औಘͰ͖Δ •ϑΝΠϧ໊ͱDIVOLIBTI͖ϑΝΠϧ໊ͷؔ࿈Λද͢KTPOϑΝΠϧ •ϑΝΠϧ໊ΛLFZͱ࣮ͯ͠ࡍͷDIVOLIBTI͖ͷϑΝΠϧ໊ΛͨͲΔ͜ ͱ͕Ͱ͖Δ HTML JS index.html
bundle-ac2c5.js { "bundle.js": "bundle-ac2c5.js" } <script src=“./bundle-ac2c5.js”> </script> manifest.json
ରԠ !89 • NBOJGFTUKTPOΛͬͯGJMF໊Λऔಘ͢Δ • औಘͷλΠϛϯάJOEFYIUNMΛฦ͢લʹαʔόʔαΠυͰߦ͏ •TDSJQUλάΛຒΊࠐΜͩঢ়ଶͰϒϥβʹฦ͢
άϩʔόϧͳঢ়ଶͷڞ༗ !90 • Ϗϧυͷ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝ •άϩʔόϧͳঢ়ଶͷڞ༗ •
ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ • ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
എܠ !91 • άϩʔόϧʹڞ༗͍ͨ͠ঢ়ଶ͕ଘࡏ͢Δ • ೝূͷঢ়ଶ • Ϣʔβʔجຊใ • FUD
՝ !92 • αʔϏεͷૄ݁߹Λอͬͨ··Ͳ͏ڞ༗͢Δ͔ • Ξϯνύλʔϯڞ༗σʔλετΞ • ڊେͳڞ༗"1*ʹͳΔ • มߋ͕ࠔ
ೝূ Micro Frontends Micro Frontends localStorage Write Read Ξϯνύλʔϯ: ڞ༗σʔλετΞ
ݕ౼௨ৗͷ41"ͷ߹ 'MVY !93 ೝূ Component Component Store Dispatcher notify state
change change state Action (loggedIn)
ରԠ.JDSP'SPOUFOETͷ߹ !94 ೝূ Micro Frontends Micro Frontends Store Dispatcher change
state ౷߹ϨΠϠʔ Micro Frontends Custom Events (globalStateChanged) Custom Events (loggedIn)
ରԠ.JDSP'SPOUFOETͷ߹ !95 ೝূ Micro Frontends Micro Frontends Store Dispatcher change
state ౷߹ϨΠϠʔ Micro Frontends Custom Events (globalStateChanged) Custom Events (loggedIn) 'MVYͷΞφϩδʔͰղܾͰ͖Δʂ
ը໘ભҠ !96 • Ϗϧυͷ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝ • άϩʔόϧͳঢ়ଶͷڞ༗
•ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ • ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
എܠ !97 • ϐΞɾϘʔφεը໘͔ΒͦΕҎ֎ͷը໘ʹભҠ͍ͨ͠ •۩ମతʹϢʔβʔͷϓϩϑΟʔϧͳͲΛطଘͷը໘ʹભҠ͍ͤͨ͞
՝ !98 • ී௨ʹBλάͰભҠͯ͠͠·͏ͱ41"ͱͯ͠ͷભҠ͕Ͱ͖ͳ͘ͳͬͯ ͠·͏ •IJTUPSZBQJͰભҠͤ͞Δඞཁ͕͋Δ
՝ !99 • ֤αʔϏε͕ࣗ༝ʹભҠͤ͞ΔͱΧΦε •XJOEPXMPDBUJPOͱ͔XJOEPXIJTUPSZͱ͔͏ͱࣗ༝ʹը໘ભҠͰ͖Δ •ΞϓϦέʔγϣϯ֎෦ભҠ͢Δ͜ͱͰ͖ΔΑ͏ʹͳΔ • ը໘ભҠ౷߹ϨΠϠʔͷͱͯ͠ཧͨ͠΄͏͕͍͍
ཹҙ !100 • 8FCͷମݧͱἧ͑Δ •BλάΛ͏ •ӈΫϦοΫͰλϒ͕։͚Δඞཁ͕͋Δ •CVUUPOλάΛ͏ͱ8FCͷମݧͱ߹͠ͳ͍ʂ
ରԠ !101 • ී௨ʹBλάΛ͏ • IJTUPSZBQJͰભҠ͢ΔͨΊʹ౷߹ϨΠϠʔʹભҠઌΛFWFOUΛ͛Δ • ౷߹ϨΠϠʔFWFOU͔ΒભҠઌͷใΛड͚औͬͯը໘ભҠ͢Δ
ରԠ !102 • ࣮ΠϝʔδϦϯΫ༻ͷίϯϙʔωϯτ class FawLink extends Component { handleClick
= (e) => { const { to } = this.props; e.preventDefault(); const event = new CustomEvent('transition', { detail: { to, }, }); window.dispatchEvent(event); }; render() { const { to, children } = this.props; return ( <a href={to} onClick={this.handleClick}> {children} </a> ); } } export default FawLink;
ରԠ !103 • ࣮ΠϝʔδϦϯΫ༻ͷίϯϙʔωϯτ class FawLink extends Component { handleClick
= (e) => { const { to } = this.props; e.preventDefault(); const event = new CustomEvent('transition', { detail: { to, }, }); window.dispatchEvent(event); }; render() { const { to, children } = this.props; return ( <a href={to} onClick={this.handleClick}> {children} </a> ); } } export default FawLink; BλάͰఆٛ
ରԠ !104 • ࣮ΠϝʔδϦϯΫ༻ͷίϯϙʔωϯτ class FawLink extends Component { handleClick
= (e) => { const { to } = this.props; e.preventDefault(); const event = new CustomEvent('transition', { detail: { to, }, }); window.dispatchEvent(event); }; render() { const { to, children } = this.props; return ( <a href={to} onClick={this.handleClick}> {children} </a> ); } } export default FawLink; $VTUPN&WFOUΛఆٛ͠ ͯ͛Δ
ରԠ !105 • ࣮Πϝʔδ౷߹ϨΠϠʔଆ import React from 'react'; import {
browserHistory } from 'react-router'; class Peerbonus extends React.Component{ componentDidMount() { window.addEventListener('transition', (e) => { browserHistory.push(e.detail.to); }); } render() { return ( <div className="l-main_contents_area"> <peerbonus-timeline></peerbonus-timeline> </div> ); } } export default Peerbonus; &WFOU͔ΒભҠઌΛ ड͚औͬͯભҠ
ঢ়ଶཧ !106 • Ϗϧυͷ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝ • άϩʔόϧͳঢ়ଶͷڞ༗
• ը໘ભҠ •ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ • ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
എܠ !107 • ࿈ಈ͢Δͭͷίϯϙʔωϯτ͕͋Δ ߘϘλϯΛԡ͢ͱมߋ͕ө͞ΕΔ
എܠ !108 • ௨ৗͷ41"ͷઃܭύλʔϯͩͱຕͷΦϒδΣΫτΛ4JOHMFTPVSDFPG USVUIͱͯ͠ঢ়ଶཧ͢Δ 3FEVYͷHMPCBM4UBUFͳͲ { givenPoints: 200, sendablePoints:
400, }
ݕ౼ !109 • .JDSP'SPOUFOETʹ͓͚Δίϯϙʔωϯτؒͷ࿈ܞύλʔϯ •ύλʔϯαʔϏεͷͱ͖ •ύλʔϯෳαʔϏεΛ·͕ͨΔͱ͖
ݕ౼αʔϏεͷͱ͖ !110 • ͭͷαʔϏε͕ෳͷ$PNQPOFOUTΛฦ͢ • ͦΕΒ͕࿈ಈͯ͠ಈ͘
ݕ౼αʔϏεͷͱ͖ !111 • ಉҰαʔϏεͳͷͰͭͷHMPCBM4UBUFʹͭͳ͕ͬͨܗͰఏڙ͢Δ͜ͱ͕ Մೳ Component1 Component2 { state1: 1,
state2: 2, }
ݕ౼ෳαʔϏεΛ·͕ͨΔͱ͖ !112 • $VTUPN&WFOUTΛ͏ •ίϯϙʔωϯτFWFOUΛͳ͛Δ •౷߹ϨΠϠʔΠϕϯτΛ͛͢ •ଞͷίϯϙʔωϯτʹ௨͞ΕΔ Component1 Component2 CustomEvents
ରԠ !113 • ಉҰαʔϏεͳͷͰͭͷHMPCBM4UBUFʹͭͳ͕ͬͨܗͰఏڙ͢Δ const store = configureStore(); class XCountButton
extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); const shadow = this.attachShadow({ mode: 'open' }) shadow.appendChild(mountPoint); render( <Provider store={store}> <CountButton /> </Provider>, mountPoint ); retargetEvents(shadow) } } customElements.define('x-count-button', XCountButton); class XCountDisplay extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); this.attachShadow({ mode: 'open' }).appendChild(mountPoint); render( <Provider store={store}> <CountDisplay /> </Provider>, mountPoint ); } } customElements.define('x-count-display', XCountDisplay);
ରԠ !114 • ڞ௨ͷTUPSFΛఆٛ͠QSPWJEFSʹ͢ const store = configureStore(); class XCountButton
extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); const shadow = this.attachShadow({ mode: 'open' }) shadow.appendChild(mountPoint); render( <Provider store={store}> <CountButton /> </Provider>, mountPoint ); retargetEvents(shadow) } } customElements.define('x-count-button', XCountButton); class XCountDisplay extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); this.attachShadow({ mode: 'open' }).appendChild(mountPoint); render( <Provider store={store}> <CountDisplay /> </Provider>, mountPoint ); } } customElements.define('x-count-display', XCountDisplay);
ϒϥβؒͷࠩͷղফ QPMZGJMM !115 • Ϗϧυͷ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝ •
άϩʔόϧͳঢ়ଶͷڞ༗ • ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ •ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
എܠ !116 • 8FCαʔϏεͱͯ͠ఏڙ͢ΔͷͰɺͰ͖Δ͚ͩଟ͘ͷϒϥβʹରԠ͠ ͍ͨ designed by Pixel perfect from
Flaticon https://www.flaticon.com/packs/browsers
!117 • 8FC$PNQPOFOUTͷϒϥβͷରԠঢ়گʹ͕ࠩ͋Δ • *&ͳͲҰ෦ͷݹ͍ϒϥβαϙʔτ͍ͯ͠ͳ͍ •๏ਓͷ͓٬༷ʹॏཁ https://www.webcomponents.org/
ରԠ !118 • QPMZGJMMΛ͍Εͨ •IUUQTHJUIVCDPNXFCDPNQPOFOUTXFCDPNQPOFOUTKT • QPMZGJMMͱɺ࠷ۙͷػೳΛαϙʔτ͍ͯ͠ͳ͍ݹ͍ϒϥβʔͰɺͦ ͷػೳΛ͑ΔΑ͏ʹ͢ΔͨΊͷίʔυͰ͢ɻେΣϒ্ͷ +BWB4DSJQUͰ͢ɻ
• $VTUPN&MFNFOUTಛʹͳ͘ಈ͘ •ͨͩ͠4IBEPX%0.͚ͩҰ෦ະରԠ
3FBDUͰTIBEPX%0.Λ͔ͭ͏ !119 • Ϗϧυͷ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝ • άϩʔόϧͳঢ়ଶͷڞ༗
• ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ • ϒϥβؒͷࠩͷղফ QPMZGJMM • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍
എܠ !120 • 4IBEPX%0. •%0.ͷΧϓηϧԽΛߦ͏͜ͱ͕Ͱ͖Δ8FC$PNQPOFOUTͷ༷ͷͭ •$44͕֎෦͔ΒִͰ͖ͨΓͯ͠ศར • 3FBDUͱಉ࣌ʹ͑ͳ͍
!121 • 3FBDUΛ4IBEPX%0.ͰXSBQͨ͠ͱ͖ʹ$MJDLFWFOU͕Ԡ͠ͳ͘ͳΔ
ݕ౼ !122 • 3FBDUͷFWFOUͷϋϯυϦϯάํ๏ʹෛ࠴͕͋Δ • *TTVFཱ͍ͬͯΔɺ3FBDU'JSFͱ͍͏ෛ࠴ղফϓϩδΣΫτʹ Ҋͱͯ͠ొ͞Ε͍ͯΔ
ରԠ !123 • ϥΠϒϥϦͰճආՄೳ •SFBDUTIBEPXEPNSFUBSHFUFWFOUT • 3FBDUຊମͷվम·ͪʣ • 1PMZGJMMͷ͜ͱߟ͑Δͱ·ͩૣͦ͏ •
ଞʹIUUQTHJUIVCDPNTLBUFKTWBMͳͲ͕͋ΔΑ͏ͳͷͰৄ͍͠ํ ͍ͨΒڭ͍͑ͯͩ͘͞ʂ
None
ߟ !125 • .JDSP'SPOUFOET࣮ઓೖՄೳ •αʔϏεόοΫΤϯυ͔Β6*·Ͱ୲Ͱ͖ΔͷͰαʔϏεͷϩδοΫ ͕ࢄ͠ͳ͍ •վળ͕༰қ •࠶ར༻ੑ͕ߴ·Δ • ։ൃಠཱͯ͠ϦϦʔεͰ͖ΔͷͰνʔϜͷࣗੑ͕ߴ·Δ
ߟ !126 • #''ͱͷҧ͍ •ू͍ͯ͠ΔϨΠϠʔ͕ҧ͏
ߟ !127 4FSWFS Backend Frontend αʔόʔͰ)5.-Ϩϯμ Ϧϯά͍ͯͨ͠
ߟ !128 Backend Frontend $MJFOU 4FSWFS ΫϥΠΞϯτ͕Ϧονʹ ͳΓ
ߟ !129 Backend Frontend $MJFOU 4FSWFS 4FSWFS 4FSWFS αʔϏε͕ෳࡶԽ͠ɺ ϚΠΫϩʔαʔϏεʹ
ߟ !130 Backend Frontend $MJFOU 4FSWFS 4FSWFS 4FSWFS ϦΫΤετ͕૿͑Δ αʔϏε͝ͱʹҟͳΔΦϒ
δΣΫτ #''
ߟ !131 Backend Frontend $MJFOU 4FSWFS 4FSWFS 4FSWFS #'' ϦΫΤετ͕૿͑Δ
αʔϏε͝ͱʹҟͳΔΦϒ δΣΫτ #''
ߟ !132 Backend Frontend 4FSWFS 4FSWFS 4FSWFS ϑϩϯτΤϯυͷෳࡶ͞ʹ ରॲ.JDSP'SPOUFOET
ߟࠓޙͷ !133 • ύϑΥʔϚϯε͕Γͦ͏ •443 4FSWFSTJEFSFOEFSJOH ͋ͬͨ΄͏͕͍͍ •͜Ε·Ͱͷ8FCͷݟͰഓΘΕͨύϑΥʔϚϯεɾνϡʔχϯά ඞཁ •
6*ͷ౷Ұ • ςετ •%0.#BTFE$%$ $POTVNFSESJWFODPOUSBDU UFTUJOH
·ͱΊ !134 • .JDSP'SPOUFOET.JDSPTFSWJDFTͷຊདྷͷྑ͞Λൃش͠ɺϑϩϯτΤϯ υͷ݁߹ੑΛԼ͛Δ • Ұॹʹݚڀͯ͘͠ΕΔؒΛ୳ͯ͠·͢ •ҰॹʹϚΠΫϩϑϩϯτΤϯυΛΓ͍ͨํʢࣾһɾۀҕୗɾ෭ۀ Մʣɺ%.͍ͩ͘͞ʂ5XJUUFS!OPCVIJLPTBXBJ
ࣗݾհ !135 • ໊લ: ᖒҪ એ ʢ͞Θ͍ ͷͿͻ͜ʣ • twitter/github:
nobuhikosawai • αʔόʔαΠυ(Rails) • ϑϩϯτΤϯυ(React.js)
ࣗݾհ !136 • .JDSPTFSWJDFT.FFUVQ7PMͱ7PMͰ .JDSP'SPOUFOETΛςʔϚʹ͠· ͨ͠ • Α͚ΕฐࣾͷCMPHΈ͍ͯͩ͘͞ https://medium.com/finc-engineering/microservices-meetup-vol-7-bbceaf1b860c https://medium.com/finc-engineering/microservices-meetup-vol-9-44b7664756ee
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠
ࢀߟจݙ !138 • ϚΠΫϩαʔϏεΞʔΩςΫνϟʢ 4BN/FXNBOஶɺࠤ౻ੜमɺԼ༁ʣ • NJDSPGSPOFOETPSH • $PQZSJHIU $
OFVMBOE#ÛSPGÛS*OGPSNBUJL #SFNFO (FSNBOZ IUUQTHJUIVCDPNOFVMBOENJDSPGSPOUFOETMJDFOTF • 3FBDUJTTVFT • IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT • IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT • IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT