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

SUGARのアーキテクチャー / SUGAR ARCHITECTURE 20190425

SUGARのアーキテクチャー / SUGAR ARCHITECTURE 20190425

2019/4/25に行われた「突撃!!隣のアーキテクチャ」
https://totsugeki-architecture.connpass.com/event/125845/
での発表資料です

Avatar for sugitani

sugitani

April 25, 2019
Tweet

Other Decks in Technology

Transcript

  1. 46("3ͱ͸ʁ • ஶ໊ਓʹಛԽͨ͠ϥΠϒ഑৴Ξ ϓϦ • ొ࿥ͯ͠ΞʔςΟετΛϑΥϩʔ͠ ͓ͯ͘ͱి࿩ $BMM,JU ͕དྷΔ •

    Ұఆ਺͕ϐοΫΞοϓ͞Εબ୒ΤϦ ΞʹೖΔʢ௨শ͓ण࢘Ϩʔϯʣ • ΞʔςΟετ͕௨࿩ର৅ΛબͿͱ௨ ࿩͕Ͱ͖Δ ଞͷਓ͸ͦͷ༷ࢠΛ ோΊΔ • ഑৴ऀ͕εΰ͘ͳ͚Ε͹੒Γཱ ͨͳ͍ • ഑৴ऀ͕Ϡό͍
  2. ࠾༻ΞʔΩςΫνϟͱ঺հൣғ 4DBMBαʔό 4XJGUJ04 ,PUMJO"OESPJE ͥΜͿ΍Δ γεςϜΞʔΩςΫνϟ %*1Λ׆༻͢ΔҰ೿ʁ γεςϜΞʔΩςΫνϟ %*1Λ׆༻͢ΔҰ೿ʁ γεςϜΞʔΩςΫνϟ

    %*1Λ׆༻͢ΔҰ೿ʁ (6*ΞʔΩςΫνϟ ແ͠ +40/ग़͚ͩ͢ (6*ΞʔΩςΫνϟ .7$͔ͳ͊ʜʁ (6*ΞʔΩςΫνϟ .77.ͩͱࢥͬͯΔ
  3. 7JFX ͦͷଞʣ %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF 6*ͱίϯτϩʔϥ 6*7JFX$POUSPMMFS6*7JFX"DUJWJUZ'SB

    HNFOU QMBZͷ $POUSPMMFSͳͲݟͨ໨ ͱૢ࡞ͷ࢝·Γ͔ΒऴΘΓ·Ͱͷ੍ޚʹ ؔΘΔ࣮૷Λஔ͖·͢ɻ
  4. ಺ଆ͚ͩར༻Ͱ͖Δ %PNBJO "QQMJDBUJPO "EBQUFS 7JFX ͦͷଞ *OGSBTUSVDUVSF ґଘੑٯసͷݪଇΛ׆༻ %PNBJOr 7JFXɺ"EBQUFSɺ"QQMJDBUJPOΛར༻

    JNQPSU Ͱ͖ͳ͍ "QQMJDBUJPOr %PNBJOΛར༻Ͱ͖Δɻ 7JFXɺ"EBQUFSΛར༻Ͱ͖ͳ͍ "EBQUFSr"QQMJDBUJPOɺ%PNBJOΛར༻Ͱ͖Δɻ7JFXΛར༻Ͱ͖ͳ͍ 7JFXr "EBQUFSɺ"QQMJDBUJPOɺ%PNBJOΛར༻Ͱ͖Δ *OGSBTUSVDUVSFr ଞΛར༻Ͱ͖ͳ͍ɻଞ͔Βར༻͞ΕΔ
  5. %PNBJO૚ͷํ਑ • υϝΠϯۦಈઃܭͰϞσϦϯάΛߦ͏ • &SJDຊʹͰ͖Δ͚ͩ४ڌͯ͠ݕ౼͢Δ • ੠ʹग़ͯٞ͠࿦͢Δ • ݪଇఆٛ USBJUJOUFSGBDFQSPUPDPM

    Λஔ͘ • γϯϓϧͳ7BMVF0CKFDUʹ͸ྫ֎΋͋Δ • ط੒ͷ೔෇Ϋϥε΍63-ΫϥεΛ͔ͭͬͨΓ • UZQFBMJBT'PP4USJOH TXJGULPUMJO ΍"OZ7BM TDBMB Ͱදݱͨ͠Γ • &OVN࢖ͬͨΓ • ಉ͡ଘࡏʹରͯ͠αʔόͱΫϥΠΞϯτͰಉ͡ݴ༿΍ݟ͑ํʹ ͳΔͱ͸ݶΒͳ͍͜ͱʹؾΛ͚ͭΔ
  6. ʮΞΧ΢ϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4DBMB trait EntityId { /* … */ }

    trait Entity[T <: EntityId] { val id: T } trait UserId extends EntityId trait ImageResource { /* … */ } case class UserName(value: String) extends AnyVal trait RegisteredUser extends Entity[UserId]{ val name: UserName val icon: ImageResource val registeredDate: LocalDateTime }
  7. ʮΞΧ΢ϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4DBMB trait EntityId { /* … */ }

    trait Entity[T <: EntityId] { val id: T } trait UserId extends EntityId trait ImageResource { /* … */ } case class UserName(value: String) extends AnyVal trait RegisteredUser extends Entity[UserId]{ val name: UserName val icon: ImageResource val registeredDate: LocalDateTime } ొ࿥ࡁΈͰͳ͍Ϣʔβʔ͍ͩͬͯΔͷҙ
  8. trait Entity { type ID <: EntityId; val id: ID

    } case class User(id: UserId, …) extends Entity { type ID = UserId } 5JQTɿ&OUJUZͱ*% ར༻ྫ ͕ͧ͘͞Μᐌ͘ ҙຯ ৽نͰ࡞Δ৔߹͸ͪ͜Βʹ͓͖ͯ͠·͠ΐ͏ʂ https://twitter.com/gakuzzzz/status/1103240324120403968
  9. ʮΞΧ΢ϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4XJGU protocol EntityId { /* … */ }

    protocol Entity { var entityId: EntityId { get } } protocol UserId: EntityId { } typealias UserName = String protocol Profile: Entity { var userId: UserId { get } var name: UserName { get } var icon: URL? { get } } extension Profile { var entityId: EntityId { return userId } }
  10. ʮΞΧ΢ϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4XJGU protocol EntityId { /* … */ }

    protocol Entity { var entityId: EntityId { get } } protocol UserId: EntityId { } typealias UserName = String protocol Profile: Entity { var userId: UserId { get } var name: UserName { get } var icon: URL? { get } } extension Profile { var entityId: EntityId { return userId } } ΫϥΠΞϯτ͔Β͢Ε͹ਓ͡Όͳͯ͘ ϓϩϑΟʔϧ͔͠ڵຯͳ͍ΑͶɺ ͷҙΛࠐΊ໋໊ͨ
  11. ʮΞΧ΢ϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ 4XJGU protocol EntityId { /* … */ }

    protocol Entity { var entityId: EntityId { get } } protocol UserId: EntityId { } typealias UserName = String protocol Profile: Entity { var userId: UserId { get } var name: UserName { get } var icon: URL? { get } } extension Profile { var entityId: EntityId { return userId } } (FOFSJD1SPUPDPM͸໘౗͕ଟ͍ͷͰ খࡉ޻Ͱར༻Λආ͚Δ
  12. ʮΞΧ΢ϯτΛ࣋ͬͨར༻ऀʯͷ ఆٛΠϝʔδ ,PUMJO interface EntityId { /* ... */ }

    interface Entity<ID : EntityId> { val id: ID } interface UserId: EntityId typealias UserName = String interface Profile: Entity<UserId> { val name:UserName val icon: URI? }
  13. %%%తʹ͋΍͍͠Ϋϥεୡ΋ډΔ • ΫϥΠΞϯτଆʹ͍Δ • 8FC3UD˞ • 8FC3UD%FWJDF8FC3UD4JHOBMJOH8FC3UD4FUUJOHʜ • )UUQ-JWF4USFBNJOH˞ •

    "VEJP4PVSDF • 7JEFP4PVSDF • $BNFSB7JEFP4PVSDF4UJMM*NBHF7*EFP4PVSDF • %%%ͬΆ͘͸ͳ͍ʜ • ͔ͱ͍ͬͯݴ༿ͱͯ͠͸ઈର֎ͤͳ͍ʜ • Ͱ΋ศར ˞͜ΕΒ͸ࣗ෼ୡͷఆٛͨ͠΋ͷͰ ϥΠϒϥϦ౳ͷੜ0CKFDUΛࢦ͢΋ͷͰ͸͋Γ·ͤΜ
  14. উखʹ૿΍ͨ͠ఆٛୡ ΫϥΠΞϯτଆͰͷΈ%PNBJO૚ʹஔ͚ΔఆٛΛ૿΍͍ͯ͠Δ • -PDBM3FQPTJUPSZ • ϩʔΧϧͰ͔͠อଘ͠ͳ͍͔ΒͶʁ͍͍ͶʁΛڧௐͨ͠3FQPTJUPSZ • ओʹ$BDIF༻్Ͱ࢖͏ͷͰ$MFBS$MFBS"MMΛ͍࣋ͬͯΔ • %BUB4PVSDF

    • 3FQPTJUPSZͷѥछɻϩʔΧϧݶఆͷҰ࣌σʔλΛऔΓѻ͏ɻ • ߋ৽ݕग़ͷ EFMFHBUF  FWFOU-JTUFS ΛηοτͰ͖Δ • 7JFXʹηοτ͢Δ༻ • %BUB4UPSF • %BUB4PVSDFͷ্Ґ൛ɻ • σʔλͷ௥Ճߋ৽͕Ͱ͖Δɻ
  15. "QQMJDBUJPO૚ͷΠϝʔδ 'PP3FQPTJUPSZ ࠩ͠ࠐΈޱ #BB3FQPTJUPSZ ࠩ͠ࠐΈޱ #B['BDUPSZ ࠩ͠ࠐΈޱ "4QFDJBM"QQMJDBUJPO 'PP3FQPTJUPSZ *NQMFNFOU

    #BS3FQPTJUPSZ *NQMFNFOU #B['BDUPSZ *NQMFNFOU ར༻Մೳʂ ར༻Մೳʂ ͜͏ͳΔʂ ϝιου" ϝιου# ʜ
  16. ۩ମྫ r ܝࣔ൘ॻ͖ࠐΈΞϓϦ class CommentPoster(commentsRepository: CommentsRepository, commentFactory: CommentFactory){ def post(userId:UserId,

    body:String, timestamp:LocalDateTime): Future[Done] ={ val comment = commentFactory.build(userId, body, timestamp) commentsRepository.store(comment) } } ˞ͿͬͪΌ͚͜Ε͘Β͍ͷॲཧͳΒ"QQMJDBUJPOΛ࡞Βͣ $POUSPMMFSʹॻ͍ͯ͠·͏͜ͱ͕ଟ͍
  17. ۩ମྫ r $BDIF෇͖3FQPTJUPSZ protocol FooRepository { func get(id: FooId) ->

    Promise<Foo> func store(foo: Foo) -> Promise<Void> } protocol FooLocalRepository { func get(id: FooId) -> Promise<Foo> func store(foo: Foo) -> Promise<Void> func clear(id: FooId) func clearAll() } class CachedFooRepository: FooRepository {  ʜ  init(fooRepository: FooRepository, fooLocalRepository: FooLocalRepository) {  ʜ } func get(id: FooId) -> Promise<Foo> {  MPDBM3FQPTJUPSZ͔Βऔಘˠͳ͚Ε͹SFQPTJUPSZ͔Βऔಘ  } func store(foo: Foo) -> Promise<Void> {  SFQPTJUPSZʹอଘ͔ͯ͠Β MPDBM3FQPTJUPSZDMFBS   } } ˞1SPNJTFϥΠϒϥϦ͸ )ZESB Λ޷ΜͰ࢖͍ͬͯ·͢
  18. ۩ମྫ r $BDIF෇͖3FQPTJUPSZ interface FooRepository { suspend fun get(id: FooId):

    Foo suspend fun store(foo: Foo) } interface FooLocalRepository { suspend fun get(id: FooId): Foo suspend fun store(foo: Foo) fun clear(id:FooId) fun clearAll() } class CachedFooRepository( private val fooRepository: FooRepository, private val fooLocalRepository: FooLocalRepository ) : FooRepository { override suspend fun get(id: FooId): Foo { /* localRepositoryから取得→なければrepositoryから取得 */ } override suspend fun store(foo: Foo) { /* repositoryに保存してから localRepository.clear() */ } }
  19. ۩ମྫ r $BDIF$MFBOFS class CacheCleaner( private val fooLocalRepository: FooLocalRepository, private

    val barLocalRepository: BarLocalRepository, private val bazLocalRepository: BazLocalRepository ) { fun execute() { fooLocalRepository.clearAll() barLocalRepository.clearAll() bazLocalRepository.clearAll() } }
  20. ۩ମྫ r ϥΠϒ1MBZFSͷίΞ 1MBZFS6* EFMFHBUF ࠩ͠ࠐΈޱ Session ParticipantList DataStore ChatList

    DataStore ΍͍ͬͯΔۀ຿ • ঢ়گʹԠͯ͡)4-8FC35$ͷ઀ଓΛ࢖͍෼͚ΔΑ͏$POOFDUJPOʹࢦࣔΛग़͢ • 8FC4PDLFU&WFOU4PVSDF౳͔Βνϟοτ΍ࢀՃऀ৘ใΛड৴ͯ͠$IBU-JTU΍1BSUJDJQBOU-JTUʹ อଘ͢Δ • ϝιουΛ௨ͯ͠֎ଆʹ·ͱΊͨ৘ใΛฦͨ͠ΓɺࢦࣔΛड͚ͨΓ౳ Connection WebRtc Signaling Device WebSocket CommandFactory HLS EventSource (server sent event) QMBZFS4UBUVT DIBUૹ৴ DMPTF ʜ
  21. "EBQUFS૚ͷํ਑ • %PNBJO૚ͷఆٛ USBJUJOUFSGBDFQSPUPDPM Λܧঝ࣮ͯ͠૷͠ ͨΫϥεͷஔ͖৔ • &OUJUZ7BMVF 0CKFDUͰ͋Ε͹ DBTFDMBTTEBUBDMBTT

    TUSVDUͰ࡞ͬͨΓ౳ • +40/౳ͱͷ૬ޓม׵΋͜͜Ͱॻ͍ͯ͠·͏ • 3FQPTJUPSZͰ͋Ε͹%#΍"1*ͱ௨৴ͨ͠Γςετ༻ʹΦϯϝ ϞϦͷ࣮૷Λ࡞ͬͨΓɻ ͱ͘ʹ޻෉͸ͳ͍ͷͰ۩ମྫ͸লུ͠·͢
  22. 7JFX NJTD ૚ͷํ਑ • "QQMJDBUJPOΛΠϯελϯεԽͯ͠ը໘Λग़ྗߏங͢Δ • αʔόଆ͸+40/ు͚ͩ͘ͳͷͰγϯϓϧ • ΫϥΠΞϯτଆ͸ը໘ͷෳࡶ͞ʹԠͯ͡࿈ܞํ๏Λม͍͑ͯΔ •

    ओͳॅਓ • 6*7JFX$POUSPMMFS6*7JFX"DUJWJUZ'SBHNFOU QMBZͷ $POUSPMMFS ͳͲͷίϯτϩʔϥʔܥ • 4UPSZCPBSE9JCMBZPVUͷ9.- σΟϨΫτϦతʹ͸ผʣ "1*ͷҾ਺ ΍ฦ஋ͷ+40/ૢ࡞ • %*ίϯςφ΋͜ͷ૚
  23. J04ͷ7JFX࣮૷  ௒γϯϓϧͳը໘ • ௒؆୯ͳը໘Ͱ͋ΔͳΒͦͷ··7JFX$POUSPMMFSͱ4UPSZCPBSE͚ͬͭ͘Δ • 4UPSZCPBSE͸جຊը໘ຖʹ࡞੒ • Ұ࿈ͷը໘ʢΞϓϦىಈޙͷ͍Ζ͍Ζ঺հϑϩʔͳͲʣ͸ෳ਺ը໘Λ֨ೲ 閉じるボタン

    class FooViewController: UIViewController { @IBAction func onTouchUpInsideCloseBotton(_: Any) { navigationController?.popViewController(animated: true) } } 4UPSZCPBSE
  24. J04ͷ7JFX࣮૷  ΍΍ෳࡶͳը໘ • ଟগෳࡶͳΒ7JFXૢ࡞͸ΧελϜ7JFXʹԡ͠ࠐΊͯ͠·͏ • 7JFX$POUSPMMFS͸ΧελϜ7JFX΁ͷσʔληοτ SFQPTJUPSZΛݺͼग़͢౳ ͱɺ 7JFX͔Βͷૢ࡞΁ͷରԠ͕ओͳ࢓ࣄɻ

    Submit TextText TextTextTextTextText TextTextText TextText TextTextText 9JC ੜૢ࡞ !*#"DUJPO protocol FooViewDelegate: class { func onSubmit(value: String) } class FooView: UIView { /* ... */ weak var delegate: FooViewDelegate? var foo: Foo? { didSet { setNeedsLayout() } } override func layoutSubviews() { super.layoutSubviews() /* fooを描画 */ } } 'PP7JFX class FooViewController: UIViewController { @IBOutlet weak var fooView: FooView? { didSet { fooView?.delegate = self } } /* ... */ } extension FooViewController: FooViewDelegate { func onSubmit(value: String) { /* … */ } } 'PP7JFX$POUSPMMFS ᖤա͞Εͨ ૢ࡞ EFMFHBUF σʔλ ࢦࣔ QSPQFSUZTFU NFUIPEDBMM ඳը QSPQFSUZTFU
  25. J04ͷ7JFX࣮૷  ௒ෳࡶͳը໘ • 7JFX$POUSPMMFSͷ࢓ࣄ͕ଟ͍ͳΒ"QQMJDBUJPO૚ͷΫϥεʹ೚ ͤͯ͠·͏ Submit TextText TextTextTextTextText TextTextText

    TextText TextTextText 9JC ඳը QSPQFSUZTFU ੜૢ࡞ !*#"DUJPO σʔλ ࢦࣔ QSPQFSUZTFU NFUIPEDBMM ᖤա͞Εͨ ૢ࡞ EFMFHBUF class FooView: UIView { /* ... */ } 'PP7JFX class FooViewController : UIViewController, PlayerUI { /* ... */ } 'PP7JFX$POUSPMMFS 1MBZFS6* ΋ͬͱ ᖤա͞Εͨ ૢ࡞ NFUIPEDBMM Πϕϯτ EFMFHBUF 1MBZFS$PSF
  26. "OESPJEͷ7JFX࣮૷  ௒γϯϓϧͳը໘ • ௒؆୯ͳը໘Ͱ͋ΔͳΒ,PUMJO"OESPJE&YUFOTJPOTͰ"DUJWJUZ ͔Β6*ύʔπΛͦͷ··ૢ࡞ YNM 閉じるボタン import kotlinx.android.synthetic.main.fooview.*

    class FooActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.fooview) buttonView.setOnClickListener { /* … */ } } }
  27. "OESPJEͷ7JFX࣮૷  ΍΍ෳࡶͳը໘ • ෳࡶͳը໘ͳΒͰ"OESPJE"SDIJUFDUVSF$PNQPOFOUTͷ 7JFX.PEFM-JWF%BUBͱ%BUB#JOEJOHΛ׆༻ • J04ͱൺֱ͢Δͱɺߏ଄͸ಉ͡Ͱ΋ΧελϜ7JFXΛ࡞Βͳͯ͘ྑ͍৔໘͕ ຆͲʹͳΔΠϝʔδ YNM

    Submit TextText TextTextTextTextText TextTextText TextText TextTextText class FooViewModel : ViewModel() { interface Listener { fun onSubmit() } var listener: Listener? by weakVar() val foo = MutableLiveData<Foo>() fun onClickSubmitButton() { listener?.onSubmit() } } ૒ํ޲ #JOEJOH class FooActivity : FragmentActivity() { override fun onCreate( savedInstanceState: Bundle?) { /* BindingとViewModelの⽤意 */ model.listener = this } } } σʔλ QSPQFSUZTFU ᖤա͞Εͨ ૢ࡞ EFMFHBUF
  28. "OESPJEͷ7JFX࣮૷  ௒ෳࡶͳը໘ • "DUJWJUZ'SBHNFOUͷ࢓ࣄ͕ଟ͍ͳΒ"QQMJDBUJPO૚ͷΫϥεʹ ೚ͤͯ͠·͏ Submit TextText TextTextTextTextText TextTextText

    TextText TextTextText 9JC σʔλ ࢦࣔ QSPQFSUZTFU NFUIPEDBMM ᖤա͞Εͨ ૢ࡞ EFMFHBUF class FooViewModel: ViewModel() { /* ... */ } 'PP7JFX.PEFM 'PP"DUJWJUZ 1MBZFS6* ΋ͬͱ ᖤա͞Εͨ ૢ࡞ NFUIPEDBMM Πϕϯτ EFMFHBUF 1MBZFS$PSF class FooActivity : FragmentActivity(), PlayerUI { override fun onCreate() { /* … */ } } ૒ํ޲ #JOEJOH