SlideShare a Scribd company logo
1 of 87
Download to read offline
Session 2 l Rainist
Efficient and Testable MVVM pattern
Session 2. Android archietecture
@omjoonkim
with using AAC, Rx, Koin
Android .
?
MVC
MVP
MVVM
MVI
VIPER
etc…
MVC
MVP
MVVM
MVI
VIPER
etc…
MVC
MVP
MVVM
MVI
VIPER
etc…
with CleanArchitecture
with RFP(rxJava2)
with AAC, Koin
with Spek
MVVM?
why MVVM?
?
Presenter code 1000Line 😨
😓
( ) 🤕
View Presenter 🤒
☝
Business Logic ☝
☝
☝
👇
👇
what MVVM?
MVVM….
- Model View ViewModel
- ViewModel View .
- View ViewModel n:m .
- View ViewModel bindable .
Model View ViewModel
VIEW
VIEW
MODEL
MODEL
DataBinding
Notification
Update
Notification
ViewModel View .
- ViewModel View .
- ViewModel View input output .
- input output .
- (input) (output) .
- .
- output View Route .
View ViewModel n:m .
- View ViewModel .
- ViewModel View .
- .
VIEW
VIEW
MODEL
MODEL
DataBinding
View ViewModel bindable .
Notification Notification
Update
View ViewModel bindable .
- View ViewModel .
- (View -> ViewModel)
- View (ViewModel -> View)
- PS. binding .
…
VIEW
VIEW
MODEL
MODEL
DataBinding
Databinding,
LiveData
RxJava
View 

ViewModel
.
binding input output
.
Databinding
.
How MVVM?
Efficiently
Testable
on Android? 🤔
VIEW
VIEW
MODEL
MODEL
DataBinding
Notification
Update
Notification
on Android! 🙌
VIEW
VIEW
MODEL
MODEL
DataBinding
LiveData
UseCase
Rx
VIEW
VIEW
MODEL
MODEL
DataBinding
LiveData
UseCase
Rx
XML
(databindingUtil)
Activity
or Fragment
or something
on Android! 🙌
VIEW
VIEW
MODEL
MODEL
DataBinding
LiveData
UseCase
Rx
XML
(databindingUtil)
Activity
or Fragment
or something
View
Router + ViewModel View binding
.
on Android! 🙌
✨
- CleanArchitecture
- Koin IOC(Inversion Of Control)
- Spek .
…
https://github.com/omjoonkim/GitHubBrowserApp
✨
package
package
App
Data
Domain
Remote
CleanArchitecture
UI
Data
Domain
Remote
Presentation
Koin!
Koin?
- Library.(DI x)
- Kotlin .
- !
- AAC ✨
- Service Locator .
- Runtime .
Koin!
val myModule: Module = module {
viewModel { (id: String) -> MainViewModel(id, get(), get()) }
viewModel { SearchViewModel(get()) }
//app
single { Logger() }
single { AppSchedulerProvider() as SchedulersProvider }
//domain
single { GetUserData(get(), get()) }
//data
single { GithubBrowserDataSource(get()) as GitHubBrowserRepository }
//remote
single { GithubBrowserRemoteImpl(get(), get(), get()) as GithubBrowserRemote }
single { RepoEntityMapper() }
single { UserEntityMapper() }
single {
GithubBrowserServiceFactory.makeGithubBrowserService(
BuildConfig.DEBUG,
"https://api.github.com"
)
}
}
Koin!
class App : Application() {
override fun onCreate() {
super.onCreate()
startKoin(
this,
listOf(myModule)
)
}
}
SearchActivity
SearchView - Input?
name
clickSearchButton
SearchView - Output?
STATE
enableSearchButton
Route
goResultActivity
SearchViewModel - constructor
class SearchViewModel(
logger: Logger
) : BaseViewModel()
BaseViewModel
abstract class BaseViewModel : ViewModel(){
protected val compositeDisposable : CompositeDisposable = CompositeDisposable()
override fun onCleared() {
super.onCleared()
compositeDisposable.clear()
}
}
SearchViewModel - input, output, state
interface SearchViewModelInPuts : Input {
fun name(name: String)
fun clickSearchButton()
}
interface SearchViewModelOutPuts : Output {
fun state(): LiveData<SearchViewState>
fun goResultActivity(): LiveData<String>
}
data class SearchViewState(
val enableSearchButton: Boolean
)
SearchViewModel - properties
private val name = PublishSubject.create<String>()
private val clickSearchButton = PublishSubject.create<Parameter>()
val input = object : SearchViewModelInPuts {
override fun name(name: String) =
this@SearchViewModel.name.onNext(name)
override fun clickSearchButton() =
this@SearchViewModel.clickSearchButton.onNext(Parameter.CLICK)
}
private val state = MutableLiveData<SearchViewState>()
private val goResultActivity = MutableLiveData<String>()
val output = object : SearchViewModelOutPuts {
override fun state() = state
override fun goResultActivity() = goResultActivity
}
SearchViewModel - logic
init {
compositeDisposable.addAll(
name.map { SearchViewState(it.isNotEmpty()) }
.subscribe(state::setValue, logger::d),
name.takeWhen(clickSearchButton) { _, t2 -> t2 }
.subscribe(goResultActivity::setValue, logger::d)
)
}
SearchViewModel - logic
init {
compositeDisposable.addAll(
name.map { SearchViewState(it.isNotEmpty()) }
.subscribe(state::setValue, logger::d),
name.takeWhen(clickSearchButton) { _, t2 -> t2 }
.subscribe(goResultActivity::setValue, logger::d)
)
}
SearchView
<data>
<import type="android.view.View"/>
<variable
name="viewModel"
type="com.omjoonkim.app.githubBrowserApp.viewmodel.SearchViewModel"
/>
</data>
SearchView - Databinding
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="48dp"
android:onTextChanged='@{(s,start,end,before) -> viewModel.input.name(s.toString ?? "")}'
/>
<Button
android:id="@+id/button_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="@{viewModel.output.state().enableSearchButton}"
android:onClick="@{(v) -> viewModel.input.clickSearchButton()}"
android:text="search"
/>
SearchView - Databinding
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="48dp"
android:onTextChanged='@{(s,start,end,before) -> viewModel.input.name(s.toString ?? "")}'
/>
<Button
android:id="@+id/button_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="@{viewModel.output.state().enableSearchButton}"
android:onClick="@{(v) -> viewModel.input.clickSearchButton()}"
android:text="search"
/>
SearchActivity
class SearchActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivitySearchBinding>(this,…)
binding.setLifecycleOwner(this)
val viewModel = getViewModel<SearchViewModel>()
binding.viewModel = viewModel
viewModel.output.goResultActivity()
.observe {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("githubbrowser://repos/$it")
)
)
}
}
}
SearchActivity - state binding
class SearchActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivitySearchBinding>(this,…)
binding.setLifecycleOwner(this)
val viewModel = getViewModel<SearchViewModel>()
binding.viewModel = viewModel
viewModel.output.goResultActivity()
.observe {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("githubbrowser://repos/$it")
)
)
}
}
}
SearchActivity - router binding
class SearchActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivitySearchBinding>(this,…)
binding.setLifecycleOwner(this)
val viewModel = getViewModel<SearchViewModel>()
binding.viewModel = viewModel
viewModel.output.goResultActivity()
.observe {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("githubbrowser://repos/$it")
)
)
}
}
}
ResultActivity
ResultView - Input?
clickHomeButton
clickUser
ResultView - Output?
STATE
title
showLoading
ROUTER
refreshListData
finish
showErrorToast
goProfileActivity
MainViewModel - constructor
class MainViewModel(
searchedUserName: String,
private val getUserData: GetUserData,
logger: Logger
) : BaseViewModel()
MainViewModel - input, output, state
interface MainViewModelInputs : Input {
fun clickUser(user: User)
fun clickHomeButton()
}
interface MainViewModelOutPuts : Output {
fun state(): LiveData<MainViewState>
fun refreshListData(): LiveData<Pair<User, List<Repo>>>
fun showErrorToast(): LiveData<String>
fun goProfileActivity(): LiveData<String>
fun finish(): LiveData<Unit>
}
data class MainViewState(
val showLoading: Boolean,
val title: String
)
MainViewModel - properties
private val clickUser = PublishSubject.create<User>()
private val clickHomeButton = PublishSubject.create<Parameter>()
val input: MainViewModelInputs = object : MainViewModelInputs {
override fun clickUser(user: User) = clickUser.onNext(user)
override fun clickHomeButton() = clickHomeButton.onNext(Parameter.CLICK)
}
private val state = MutableLiveData<MainViewState>()
private val refreshListData = MutableLiveData<Pair<User, List<Repo>>>()
private val showErrorToast = MutableLiveData<String>()
private val goProfileActivity = MutableLiveData<String>()
private val finish = MutableLiveData<Unit>()
val output = object : MainViewModelOutPuts {
override fun state() = state
override fun refreshListData() = refreshListData
override fun showErrorToast() = showErrorToast
override fun goProfileActivity() = goProfileActivity
override fun finish() = finish
}
MainViewModel - logic
init {
val error = PublishSubject.create<Throwable>()
val userName = Observable.just(searchedUserName).share()
val requestListData = userName.flatMapMaybe {
getUserData.get(it).neverError(error)
}.share()
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainViewModel - logic
val error = PublishSubject.create<Throwable>()
val userName = Observable.just(searchedUserName).share()
val requestListData = userName.flatMapMaybe {
getUserData.get(it).neverError(error)
}.share()
MainViewModel - logic
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainViewModel - logic
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainViewModel - logic
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainViewModel - logic
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainViewModel - logic
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainViewModel - logic
compositeDisposable.addAll(
Observables
.combineLatest(
Observable.merge(
requestListData.map { false },
error.map { false }
).startWith(true),
userName,
::MainViewState
).subscribe(state::setValue, logger::d),
requestListData.subscribe(refreshListData::setValue, logger::d),
error.map {
if (it is Error)
it.errorText
else UnExpected.errorText
}.subscribe(showErrorToast::setValue, logger::d),
clickUser.map { it.name }.subscribe(goProfileActivity::setValue, logger::d),
clickHomeButton.subscribe(finish::call, logger::d)
)
MainView
<data>
<import type="android.view.View"/>
<variable
name="viewModel"
type="com.omjoonkim.app.githubBrowserApp.viewmodel.MainViewModel"
/>
</data>
MainView - Databinding
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@{viewModel.output.state().title}"
/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="@{viewModel.output.state().showLoading ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBar"
>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</FrameLayout>
MainView - Databinding
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@{viewModel.output.state().title}"
/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="@{viewModel.output.state().showLoading ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBar"
>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</FrameLayout>
MainActivity
val binding = DataBindingUtil.setConten…..
binding.setLifecycleOwner(this)
val viewModel = getViewModel<MainViewModel> {
parametersOf(intent.data.path.substring(1))
}
binding.viewModel = viewModel
actionbarInit(binding.toolbar, onClickHomeButton = {
viewModel.input.clickHomeButton()
})
MainActivity
with(viewModel.output) {
refreshListData().observe { (user, repos) ->
binding.recyclerView.adapter = MainListAdapter(
user,
repos,
viewModel.input::clickUser
)
}
showErrorToast().observe { showToast(it) }
goProfileActivity().observe {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("githubbrowser://repos/$it")
)
)
}
finish().observe {
onBackPressed()
}
}
Test
HOW? 😎
-
- Test SchedulersProvider .
- Test DummyApiService .
- Spek + LiveData .
- Spek
- Feature
- Scenario
- Given
- When
- Then
TestSchedulerProvider
class TestSchedulerProvider : SchedulersProvider {
override fun io() = Schedulers.trampoline()
override fun ui() = Schedulers.trampoline()
}
TestDummyGithubBrowserService
class TestDummyGithubBrowserService : GithubBrowserService {
override fun getUserInfo(userName: String): Single<UserModel> =
Single.just(
UserModel("omjoonkim", "")
)
override fun getUserRepos(userName: String): Single<List<RepoModel>> =
Single.just(
listOf(
RepoModel("repo1", "repo1 description", "1"),
RepoModel("repo2", "repo2 description", "2"),
RepoModel("repo3", "repo3 description", "3")
)
)
}
DI for Test
val testModule = module {
single(override = true) {
TestSchedulerProvider() as SchedulersProvider
}
single(override = true) {
TestDummyGithubBrowserService() as GithubBrowserService
}
}
val test_module = listOf(myModule, testModule)
for Spek + LiveData
beforeEachTest {
ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) {
runnable.run()
}
override fun isMainThread(): Boolean {
return true
}
override fun postToMainThread(runnable: Runnable) {
runnable.run()
}
})
}
afterEachTest {
ArchTaskExecutor.getInstance().setDelegate(null)
}
MainViewModelSpec
object MainViewModelSpec : KoinSpek({
beforeEachTest {…}
afterEachTest {…}
lateinit var userName: String
val viewModel: MainViewModel by inject { parametersOf(userName) }
val getUserData: GetUserData by inject()
Feature("MainViewModel spec") {…}
})
Scenario1
Scenario(" , ") {
Given(" omjoonkim "){
userName = "omjoonkim"
}
Then(" ") {
assertEquals(
getUserData.get(userName).blockingGet(),
viewModel.output.refreshListData().value
)
}
}
Scenario2
Scenario(" ") {
When(" ") {
viewModel.input.clickUser(
viewModel.output.refreshListData().value?.first
?: throw IllegalStateException()
)
}
Then(" ") {
assertEquals(
viewModel.output.refreshListData().value?.first?.name
?: throw IllegalStateException(),
viewModel.output.goProfileActivity().value
)
}
}
Scenario3
Scenario(" .") {
When(" ") {
viewModel.input.clickHomeButton()
}
Then(" .") {
assertEquals(
Unit,
viewModel.output.finish().value
)
}
}
✨✨✨
More……. + TMI
Dagger2 vs Koin
- Heavy vs light
- Dependency Injection vs ServiceLocator
- CompileTime vs RunTime
https://twitter.com/jakewharton/status/908419644742098944
Spek Koin
- Spek + Koin .
- Spek Koin
https://github.com/InsertKoinIO/koin/pull/107
+
- Datbinding kotlin 100% .
- xml .
- Router
- Presentation module
Thank you✨✨ by @omjoonkim

More Related Content

What's hot

Introduction to React
Introduction to ReactIntroduction to React
Introduction to ReactRob Quick
 
FRONT-END WEB DEVELOPMENT-Intro.pptx
FRONT-END WEB DEVELOPMENT-Intro.pptxFRONT-END WEB DEVELOPMENT-Intro.pptx
FRONT-END WEB DEVELOPMENT-Intro.pptxRajeevKumar304148
 
Fundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-DevelopersFundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-DevelopersLemi Orhan Ergin
 
Ajax ppt - 32 slides
Ajax ppt - 32 slidesAjax ppt - 32 slides
Ajax ppt - 32 slidesSmithss25
 
Starting a Web Development Project
Starting a Web Development ProjectStarting a Web Development Project
Starting a Web Development ProjectTraversy Media
 
An Introduction to ReactJS
An Introduction to ReactJSAn Introduction to ReactJS
An Introduction to ReactJSAll Things Open
 
Introduction to react and redux
Introduction to react and reduxIntroduction to react and redux
Introduction to react and reduxCuong Ho
 
Laravel dokumentacja Restful API - swagger
Laravel dokumentacja Restful API - swaggerLaravel dokumentacja Restful API - swagger
Laravel dokumentacja Restful API - swaggerLaravel Poland MeetUp
 
ASP.NET MVC Presentation
ASP.NET MVC PresentationASP.NET MVC Presentation
ASP.NET MVC Presentationivpol
 
Introduction to mvc architecture
Introduction to mvc architectureIntroduction to mvc architecture
Introduction to mvc architectureravindraquicsolv
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJSHoang Long
 
An Introduction to Vuejs
An Introduction to VuejsAn Introduction to Vuejs
An Introduction to VuejsPaddy Lock
 
Basic Crud In Django
Basic Crud In DjangoBasic Crud In Django
Basic Crud In Djangomcantelon
 

What's hot (20)

Introduction to React
Introduction to ReactIntroduction to React
Introduction to React
 
FRONT-END WEB DEVELOPMENT-Intro.pptx
FRONT-END WEB DEVELOPMENT-Intro.pptxFRONT-END WEB DEVELOPMENT-Intro.pptx
FRONT-END WEB DEVELOPMENT-Intro.pptx
 
Fundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-DevelopersFundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-Developers
 
Ajax ppt - 32 slides
Ajax ppt - 32 slidesAjax ppt - 32 slides
Ajax ppt - 32 slides
 
jQuery
jQueryjQuery
jQuery
 
Php sessions & cookies
Php sessions & cookiesPhp sessions & cookies
Php sessions & cookies
 
API for Beginners
API for BeginnersAPI for Beginners
API for Beginners
 
Introduction to Angularjs
Introduction to AngularjsIntroduction to Angularjs
Introduction to Angularjs
 
Starting a Web Development Project
Starting a Web Development ProjectStarting a Web Development Project
Starting a Web Development Project
 
JSON WEB TOKEN
JSON WEB TOKENJSON WEB TOKEN
JSON WEB TOKEN
 
An Introduction to ReactJS
An Introduction to ReactJSAn Introduction to ReactJS
An Introduction to ReactJS
 
The WebKit project
The WebKit projectThe WebKit project
The WebKit project
 
Introduction to react and redux
Introduction to react and reduxIntroduction to react and redux
Introduction to react and redux
 
Laravel dokumentacja Restful API - swagger
Laravel dokumentacja Restful API - swaggerLaravel dokumentacja Restful API - swagger
Laravel dokumentacja Restful API - swagger
 
ASP.NET MVC Presentation
ASP.NET MVC PresentationASP.NET MVC Presentation
ASP.NET MVC Presentation
 
Introduction to mvc architecture
Introduction to mvc architectureIntroduction to mvc architecture
Introduction to mvc architecture
 
ReactJS presentation.pptx
ReactJS presentation.pptxReactJS presentation.pptx
ReactJS presentation.pptx
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJS
 
An Introduction to Vuejs
An Introduction to VuejsAn Introduction to Vuejs
An Introduction to Vuejs
 
Basic Crud In Django
Basic Crud In DjangoBasic Crud In Django
Basic Crud In Django
 

Similar to [22]Efficient and Testable MVVM pattern

Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)Natasha Murashev
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019UA Mobile
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Patterngoodfriday
 
Gutenberg sous le capot, modules réutilisables
Gutenberg sous le capot, modules réutilisablesGutenberg sous le capot, modules réutilisables
Gutenberg sous le capot, modules réutilisablesRiad Benguella
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsScott Gardner
 
Protocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupProtocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupNatasha Murashev
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Eyal Vardi
 
Android Jetpack: ViewModel and Testing
Android Jetpack: ViewModel and TestingAndroid Jetpack: ViewModel and Testing
Android Jetpack: ViewModel and TestingYongjun Kim
 
Functional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftFunctional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftRodrigo Leite
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Chris Alfano
 
Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014
Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014
Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014Fábio Pimentel
 
Knockoutjs databinding
Knockoutjs databindingKnockoutjs databinding
Knockoutjs databindingBoulos Dib
 
Functionnal view modelling
Functionnal view modelling Functionnal view modelling
Functionnal view modelling Hugo Saynac
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Coe-Legion
 
MVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayMVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayZeyad Gasser
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Mahmoud Hamed Mahmoud
 
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...Stanfy
 
We sport architecture_implementation
We sport architecture_implementationWe sport architecture_implementation
We sport architecture_implementationaurelianaur
 

Similar to [22]Efficient and Testable MVVM pattern (20)

Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Pattern
 
Gutenberg sous le capot, modules réutilisables
Gutenberg sous le capot, modules réutilisablesGutenberg sous le capot, modules réutilisables
Gutenberg sous le capot, modules réutilisables
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the Things
 
Protocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupProtocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS Meetup
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)
 
Android Jetpack: ViewModel and Testing
Android Jetpack: ViewModel and TestingAndroid Jetpack: ViewModel and Testing
Android Jetpack: ViewModel and Testing
 
Functional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftFunctional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwift
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014
Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014
Conceitos e prática no desenvolvimento iOS - Mobile Conf 2014
 
Knockoutjs databinding
Knockoutjs databindingKnockoutjs databinding
Knockoutjs databinding
 
Functionnal view modelling
Functionnal view modelling Functionnal view modelling
Functionnal view modelling
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
 
MVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayMVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin Way
 
Android development
Android developmentAndroid development
Android development
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
 
We sport architecture_implementation
We sport architecture_implementationWe sport architecture_implementation
We sport architecture_implementation
 

More from NAVER Engineering

디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIXNAVER Engineering
 
진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)NAVER Engineering
 
서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트NAVER Engineering
 
BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호NAVER Engineering
 
이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라NAVER Engineering
 
날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기NAVER Engineering
 
쏘카프레임 구축 배경과 과정
 쏘카프레임 구축 배경과 과정 쏘카프레임 구축 배경과 과정
쏘카프레임 구축 배경과 과정NAVER Engineering
 
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기NAVER Engineering
 
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)NAVER Engineering
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드NAVER Engineering
 
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기NAVER Engineering
 
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활NAVER Engineering
 
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출NAVER Engineering
 
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우NAVER Engineering
 
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...NAVER Engineering
 
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법NAVER Engineering
 
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며NAVER Engineering
 
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기NAVER Engineering
 
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기NAVER Engineering
 

More from NAVER Engineering (20)

React vac pattern
React vac patternReact vac pattern
React vac pattern
 
디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX
 
진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)
 
서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트
 
BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호
 
이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라
 
날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기
 
쏘카프레임 구축 배경과 과정
 쏘카프레임 구축 배경과 과정 쏘카프레임 구축 배경과 과정
쏘카프레임 구축 배경과 과정
 
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
 
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
 
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
 
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
 
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
 
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
 
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
 
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
 
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
 
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
 
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
 

Recently uploaded

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 

Recently uploaded (20)

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 

[22]Efficient and Testable MVVM pattern