SlideShare a Scribd company logo
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

Spring boot
Spring bootSpring boot
Spring boot
Bhagwat Kumar
 
Angular - Chapter 5 - Directives
 Angular - Chapter 5 - Directives Angular - Chapter 5 - Directives
Angular - Chapter 5 - Directives
WebStackAcademy
 
안드로이드 윈도우 마스터 되기
안드로이드 윈도우 마스터 되기안드로이드 윈도우 마스터 되기
안드로이드 윈도우 마스터 되기
Myungwook Ahn
 
Angular 8
Angular 8 Angular 8
Angular 8
Sunil OS
 
The Point of Vue - Intro to Vue.js
The Point of Vue - Intro to Vue.jsThe Point of Vue - Intro to Vue.js
The Point of Vue - Intro to Vue.js
Holly Schinsky
 
Introduction to Spring's Dependency Injection
Introduction to Spring's Dependency InjectionIntroduction to Spring's Dependency Injection
Introduction to Spring's Dependency Injection
Richard Paul
 
Introduction to angular with a simple but complete project
Introduction to angular with a simple but complete projectIntroduction to angular with a simple but complete project
Introduction to angular with a simple but complete project
Jadson Santos
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
Eyal Vardi
 
Introduction to Spring Framework
Introduction to Spring FrameworkIntroduction to Spring Framework
Introduction to Spring Framework
Hùng Nguyễn Huy
 
Spring boot - an introduction
Spring boot - an introductionSpring boot - an introduction
Spring boot - an introduction
Jonathan Holloway
 
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Steve Pember
 
mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교Woo Yeong Choi
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
Dzmitry Naskou
 
JPA and Hibernate
JPA and HibernateJPA and Hibernate
JPA and Hibernate
elliando dias
 
개발자 이승우 이력서 (2016)
개발자 이승우 이력서 (2016)개발자 이승우 이력서 (2016)
개발자 이승우 이력서 (2016)
SeungWoo Lee
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans
Hitesh-Java
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
Purbarun Chakrabarti
 
Introduction Django
Introduction DjangoIntroduction Django
Introduction Django
Wade Austin
 
[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는 어떻게 재활용하는가
[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는  어떻게  재활용하는가[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는  어떻게  재활용하는가
[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는 어떻게 재활용하는가
CONNECT FOUNDATION
 
Jetpack Compose beginner.pdf
Jetpack Compose beginner.pdfJetpack Compose beginner.pdf
Jetpack Compose beginner.pdf
AayushmaAgrawal
 

What's hot (20)

Spring boot
Spring bootSpring boot
Spring boot
 
Angular - Chapter 5 - Directives
 Angular - Chapter 5 - Directives Angular - Chapter 5 - Directives
Angular - Chapter 5 - Directives
 
안드로이드 윈도우 마스터 되기
안드로이드 윈도우 마스터 되기안드로이드 윈도우 마스터 되기
안드로이드 윈도우 마스터 되기
 
Angular 8
Angular 8 Angular 8
Angular 8
 
The Point of Vue - Intro to Vue.js
The Point of Vue - Intro to Vue.jsThe Point of Vue - Intro to Vue.js
The Point of Vue - Intro to Vue.js
 
Introduction to Spring's Dependency Injection
Introduction to Spring's Dependency InjectionIntroduction to Spring's Dependency Injection
Introduction to Spring's Dependency Injection
 
Introduction to angular with a simple but complete project
Introduction to angular with a simple but complete projectIntroduction to angular with a simple but complete project
Introduction to angular with a simple but complete project
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
Introduction to Spring Framework
Introduction to Spring FrameworkIntroduction to Spring Framework
Introduction to Spring Framework
 
Spring boot - an introduction
Spring boot - an introductionSpring boot - an introduction
Spring boot - an introduction
 
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
 
mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
JPA and Hibernate
JPA and HibernateJPA and Hibernate
JPA and Hibernate
 
개발자 이승우 이력서 (2016)
개발자 이승우 이력서 (2016)개발자 이승우 이력서 (2016)
개발자 이승우 이력서 (2016)
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
 
Introduction Django
Introduction DjangoIntroduction Django
Introduction Django
 
[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는 어떻게 재활용하는가
[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는  어떻게  재활용하는가[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는  어떻게  재활용하는가
[부스트캠프 웹・모바일 7기 Tech Talk]박명범_RecyclerView는 어떻게 재활용하는가
 
Jetpack Compose beginner.pdf
Jetpack Compose beginner.pdfJetpack Compose beginner.pdf
Jetpack Compose beginner.pdf
 

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 MVC
pootsbook
 
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
UA 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 Pattern
goodfriday
 
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
Riad Benguella
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the Things
Scott Gardner
 
Protocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupProtocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS Meetup
Natasha 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 Testing
Yongjun Kim
 
Functional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftFunctional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwift
Rodrigo Leite
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
Chris 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 2014
Fábio Pimentel
 
Knockoutjs databinding
Knockoutjs databindingKnockoutjs databinding
Knockoutjs databinding
Boulos 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&Co
e-Legion
 
MVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayMVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin Way
Zeyad Gasser
 
Android development
Android developmentAndroid development
Android development
Gregoire BARRET
 
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_implementation
aurelianaur
 

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

React vac pattern
React vac patternReact vac pattern
React vac pattern
NAVER Engineering
 
디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX
NAVER 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

Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Nexer Digital
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
danishmna97
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Vladimir Iglovikov, Ph.D.
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
SOFTTECHHUB
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
Pushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 daysPushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 days
Adtran
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
DianaGray10
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
Pierluigi Pugliese
 

Recently uploaded (20)

Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
Pushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 daysPushing the limits of ePRTC: 100ns holdover for 100 days
Pushing the limits of ePRTC: 100ns holdover for 100 days
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
 

[22]Efficient and Testable MVVM pattern