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

LINE Androidアプリの基盤を支える OSSライブラリLich / Kotlin Lich

LINE Androidアプリの基盤を支える OSSライブラリLich / Kotlin Lich

LINE Androidアプリの基盤を支える OSSライブラリLich

セッションの動画はこちら
https://youtu.be/5PNIVPi_0-A

Avatar for LINE Developers

LINE Developers

February 18, 2021
Tweet

More Decks by LINE Developers

Other Decks in Technology

Transcript

  1. -JDI w "OESPJEΞϓϦ޲͚ͷMJCSBSZDPMMFDUJPO w ݱ࣌఺Ͱ͸lDPNQPOFOUz lWJFXNPEFMz lMJGFDZDMFz lPLIUUQz lUISJGUzͷ ͭͷϥΠϒϥϦ͕͋Δ

    w ͦΕͧΕͷϥΠϒϥϦ͸ಠཱ͍ͯ͠ΔͷͰඞཁͳ΋ͷ͚ͩར༻Մೳ w ຊ೔͸l-JDIDPNQPOFOUzʹ͍ͭͯ঺հ IUUQTHJUIVCDPNMJOFMJDI
  2. -JDI$PNQPOFOUͷಛ௃ w ࢖༻͢ΔͨΊʹ֮͑Δ͜ͱ͕গͳ͍ w (MPCBMͳঢ়ଶΛ࣋ͨͣɺ"QQMJDBUJPOPO$SFBUF ͳͲͰͷॳظԽ͕ෆཁ w MB[Z͕,PUMJOͷEFMFHBUFEQSPQFSUZͱͯ͠ॻ͚Δ w JOUFSGBDFͱ࣮૷Λ؆୯ʹ෼཭Ͱ͖Δ

    w -JCSBSZNPEVMF΍%ZOBNJDGFBUVSFNPEVMFͰ΋໰୊ͳ͘ಈ͘ w #VJMEUZQF΍qBWPSʹΑΔ࣮૷ͷ੾Γସ͕͑؆୯ʹͰ͖Δ w 6OJUUFTUͰϞοΫΦϒδΣΫτʹࠩ͠ସ͑Δͷ΋؆୯ w ίʔυੜ੒Λ͠ͳ͍ͷͰϏϧυ͕࣌ؒԆͼͳ͍
  3. جຊతͳ࢖͍ํ  w $PNQPOFOUΛఆٛ͢Δ class FooComponent { // snip... companion

    object : ComponentFactory<FooComponent>() { override fun createComponent(context: Context): FooComponent = FooComponent() } }
  4. جຊతͳ࢖͍ํ  w 'PP$PNQPOFOUͷΠϯελϯεΛऔಘ w 'PP$PNQPOFOUͷΠϯελϯεΛMB[Zʹऔಘ w 'SBHNFOUͰͷ࢖༻ྫ val fooComponent

    = context.getComponent(FooComponent) val fooComponent by context.component(FooComponent) class FooFragment : Fragment() { private val fooComponent by component(FooComponent) // snip... }
  5. JOUFSGBDFͱ࣮૷ͷ෼཭ w ࢖͏ଆ͔Β͸'PP$PNQPOFOUΠϯλʔϑΣʔε͚͕ͩݟ͑Ε͹Α͍ w 'PP$PNQPOFOU*NQM͸೚ҙͷϞδϡʔϧʹஔ͚Δ interface FooComponent { // snip...

    companion object : ComponentFactory<FooComponent>() { override fun createComponent(context: Context): FooComponent = delegateToServiceLoader(context) } } @AutoService(FooComponent::class) class FooComponentImpl : FooComponent { // snip... }
  6. ෳ਺ͷ࣮૷ΫϥεΛ੾Γସ͑Δ EFCVHϏϧυͰ͸%FCVH'PP$PNQPOFOU*NQM ͦΕҎ֎Ͱ͸'PP$PNQPOFOU*NQM͕༻͍ΒΕΔ // path: src/debug/java/DebugFooComponentImpl.kt @AutoService(FooComponent::class) class DebugFooComponentImpl :

    FooComponent, ServiceLoaderComponent { override val loadPriority: Int get() = 10 // snip... } // path: src/main/java/FooComponentImpl.kt @AutoService(FooComponent::class) class FooComponentImpl : FooComponent, ServiceLoaderComponent { override val loadPriority: Int get() = 0 // snip... }
  7. 6OJUUFTUͷॻ͖ํ  'PP6TF$BTFͷGPP3FQPTJUPSZΛϞοΫͯ͠ςετ͢Δʹ͸࣍ͷΑ͏ʹॻ͘ class FooRepository(context: Context) { suspend fun findFoo(key:

    String): Foo { /* TODO */ } companion object : ComponentFactory<FooRepository>() { override fun createComponent(context: Context): FooRepository = FooRepository(context) } } class FooUseCase(context: Context) { private val fooRepository by context.component(FooRepository) // snip… }
  8. 6OJUUFTUͷॻ͖ํ  @RunWith(AndroidJUnit4::class) class FooUseCaseTest { @Test fun testFooUseCase() {

    val expectedValue = Foo() // Set a mock of FooRepository. mockComponent(FooRepository) { onBlocking { findFoo(any()) } doReturn expectedValue } val context = ApplicationProvider.getApplicationContext() val fooUseCase = FooUseCase(context) // TODO: Write test cases for fooUseCase. } }
  9. '"2 w 4JOHMFUPOҎ֎ͷΦϒδΣΫτ͸ѻ͑ͳ͍ͷ  w 7JFX.PEFMͰ͋Ε͹-JDI7JFX.PEFM͕࢖͑Δ w -JDI$PNQPOFOUͱಉ༷ʹ࢖͑Δ΄͔ɺ4BWFE4UBUFΛEFMFHBUFE QSPQFSUJFTͱͯ͠ૢ࡞͢Δ͜ͱ΋Ͱ͖Δ w

    "DUJWJUZTDPQFE΍'SBHNFOUTDPQFEͳΦϒδΣΫτ͸Ϟμϯͳ "OESPJEΞϓϦͰ͸ෆཁͳ͸ͣ w ϏδωεϩδοΫ͸7JFX.PEFMҎԼͷ૚ʹ࣮૷͠ɺ"DUJWJUZ΍ 'SBHNFOU͸7JFX.PEFMͱ7JFXͷCJOEJOH͚ͩΛߦ͏΂͖