<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/marin-simic/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Wed, 22 Apr 2026 11:24:34 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>42294https://infinum.com/uploads/2023/09/Koin-vs-kotlin-inject.webp</url>
				</image>
				<title>Koin vs. Kotlin-inject – Which to Choose and Why?</title>
				<link>https://infinum.com/blog/koin-vs-kotlin-inject-dependency-injection/</link>
				<pubDate>Thu, 14 Sep 2023 10:47:00 +0000</pubDate>
				<dc:creator>Marin Šimić</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=42294</guid>
				<description>
					<![CDATA[<p>We take a close look at Koin and Kotlin-inject, so you can choose the best dependency-injection library for your Kotlin Multiplatform project.</p>
<p>The post <a href="https://infinum.com/blog/koin-vs-kotlin-inject-dependency-injection/">Koin vs. Kotlin-inject – Which to Choose and Why?</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-117"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-36-text js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	<strong>In the fast-evolving world of cross-platform development with Kotlin Multiplatform, choosing the right dependency-injection library can have a great impact on your project. We reveal the strengths and weaknesses of Koin and Kotlin-inject, so you can find the best match for your KMP needs.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	As <a href="https://infinum.com/blog/kotlin-multiplatform-overview/" target="_blank" rel="noreferrer noopener">Kotlin Multiplatform</a> is becoming an increasingly popular choice for cross-platform development, developers face the task of selecting a suitable dependency-injection library for their KMP projects. We’re here to introduce <a href="https://github.com/InsertKoinIO/koin" target="_blank" rel="noreferrer noopener">Koin</a> and <a href="https://github.com/evant/kotlin-inject" target="_blank" rel="noreferrer noopener">Kotlin-inject</a>, two libraries that take different approaches to solving this problem. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	In this article we will present both libraries, exploring their features and implementation. We’ll do a head-to-head comparison, shedding light on their strengths and weaknesses. So let’s dive in and help you find the best fit for your KMP needs.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-102">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-103'
	>
	If you want to explore more Kotlin-based libraries, you can also check our blog post on<em> </em><a href="https://infinum.com/blog/a-kotlin-first-json-api-library-jsonapix/" target="_blank" rel="noreferrer noopener">JsonApiX</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-105">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-106'
	>
	Our example project </h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-108">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-109'
	>
	In order to better compare Koin and Kotlin-inject, we’ve come up with a simple example project. It includes a <code>WeatherApiService</code> responsible for providing <code>WeatherData</code>, along with domain components like Interactor, Repository, and UseCase, used for propagating and mapping data:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-112"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> WeatherApiService.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">WeatherApiService</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@G</span><span class="token" style="color: #d73a49;">E</span><span class="token">T(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">weather</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">suspend fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">getWeatherDa</span><span class="token" style="color: #6f42c1;">t</span><span class="token" style="color: #6f42c1;">a</span><span class="token">(</span><span class="token" style="color: #d73a49;">@Que</span><span class="token" style="color: #d73a49;">r</span><span class="token">y(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">city</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #e36209;">city</span><span class="token">: </span><span class="token" style="color: #e36209;">String</span><span class="token">)</span><span class="token">: WeatherData
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> GetWeatherDataInteractor.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">GetWeatherDataInteractor</span><span class="token">(</span><span class="token" style="color: #d73a49;">private</span><span class="token"> val weatherApiService: WeatherApiService) : Interactors.GetWeatherData </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">override suspend operator fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">invo</span><span class="token" style="color: #6f42c1;">k</span><span class="token" style="color: #6f42c1;">e</span><span class="token">(</span><span class="token" style="color: #e36209;">city</span><span class="token">: </span><span class="token" style="color: #e36209;">String</span><span class="token">)</span><span class="token">: WeatherData </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #24292e;">weatherApiService</span><span class="token" style="color: #6f42c1;">.getWeather</span><span class="token" style="color: #6f42c1;">D</span><span class="token" style="color: #6f42c1;">at</span><span class="token">a(</span><span class="token">city</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> WeatherRepository.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">WeatherRepository</span><span class="token">(</span><span class="token" style="color: #d73a49;">private</span><span class="token"> val getWeatherInteractor: Interactors.GetWeatherData) : Repositories.Weather </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">override suspend fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">fet</span><span class="token" style="color: #6f42c1;">c</span><span class="token" style="color: #6f42c1;">h</span><span class="token">(</span><span class="token" style="color: #e36209;">city</span><span class="token">: </span><span class="token" style="color: #e36209;">String</span><span class="token">)</span><span class="token">: Weather </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #6f42c1;">getWeatherIntera</span><span class="token" style="color: #6f42c1;">c</span><span class="token" style="color: #6f42c1;">tor</span><span class="token">(</span><span class="token">city</span><span class="token">)</span><span class="token" style="color: #6f42c1;">.mapToL</span><span class="token" style="color: #6f42c1;">o</span><span class="token" style="color: #6f42c1;">ca</span><span class="token">l(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> GetWeatherUseCase.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">GetWeatherUseCase</span><span class="token">(</span><span class="token" style="color: #d73a49;">private</span><span class="token"> val weatherRepository: Repositories.Weather) : UseCases.GetWeather </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">override suspend operator fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">invo</span><span class="token" style="color: #6f42c1;">k</span><span class="token" style="color: #6f42c1;">e</span><span class="token">(</span><span class="token" style="color: #e36209;">city</span><span class="token">: </span><span class="token" style="color: #e36209;">String</span><span class="token">)</span><span class="token">: Weather </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #24292e;">weatherRepository</span><span class="token" style="color: #6f42c1;">.f</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">tc</span><span class="token">h(</span><span class="token">city</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-113">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-114'
	>
	We want our example to cover the differences in implementation, so let’s say <code>WeatherApiService</code> and <code>WeatherRepository</code> are intended to be singletons. This is what our final dependency structure looks like:</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-120"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-118"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-119">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/09/chart-mobile.webp				media='(max-width: 699px)'
				type=image/webp								height="1425"
												width="1125"
				 />
												<img
					src="https://infinum.com/uploads/2023/09/chart-desktop.webp"
					class="image__img block-media__image-img"
					alt=""
										height="320"
															width="2400"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-280"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-121">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-124"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-122">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-123'
	>
	Koin</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-125">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-126'
	>
	Let&#8217;s start by diving into the Koin library. Here are some of its key features:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-128">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-129'
	>
	<li>Kotlin-based dependency injection library that offers a user-friendly experience through its easy-to-read Kotlin DSL</li><li>Suitable for any Kotlin application, including Android, Multiplatform, or Backend development</li><li>Easily integrates with the ViewModel, Ktor, and Compose, which adds to Koin’s appeal across diverse developer domains</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-133"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-131">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-132'
	>
	But let&#8217;s shift from theory to practice and test this library in action on our example project:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-135"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> ServicesModule.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val servicesModule </span><span class="token" style="color: #d73a49;">=</span><span class="token"> module </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  single </span><span class="token">{</span><span class="token"> 
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #24292e;">WeatherServiceProvider</span><span class="token" style="color: #6f42c1;">.pr</span><span class="token" style="color: #6f42c1;">o</span><span class="token" style="color: #6f42c1;">vid</span><span class="token">e(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> InteractorsModule.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val interactorsModule </span><span class="token" style="color: #d73a49;">=</span><span class="token"> module </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">includ</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">s</span><span class="token">(</span><span class="token">servicesModule</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  factory</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">Interactors</span><span class="token" style="color: #24292e;">.GetWeatherDat</span><span class="token">a</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token"> 
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #6f42c1;">GetWeatherDataInter</span><span class="token" style="color: #6f42c1;">a</span><span class="token" style="color: #6f42c1;">ctor</span><span class="token">(</span><span class="token" style="color: #6f42c1;">g</span><span class="token" style="color: #6f42c1;">et</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> RepositoriesModule.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val repositoriesModule </span><span class="token" style="color: #d73a49;">=</span><span class="token"> module </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">includ</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">s</span><span class="token">(</span><span class="token">interactorsModule</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  single</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">Repositories</span><span class="token" style="color: #24292e;">.Weathe</span><span class="token">r</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token"> 
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #6f42c1;">WeatherRepos</span><span class="token" style="color: #6f42c1;">i</span><span class="token" style="color: #6f42c1;">tory</span><span class="token">(</span><span class="token" style="color: #6f42c1;">g</span><span class="token" style="color: #6f42c1;">et</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> UseCasesModule.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val useCasesModule </span><span class="token" style="color: #d73a49;">=</span><span class="token"> module </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">includ</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">s</span><span class="token">(</span><span class="token">repositoriesModule</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  factory</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">UseCases</span><span class="token" style="color: #24292e;">.GetWeathe</span><span class="token">r</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token"> 
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #6f42c1;">GetWeatherUs</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">Case</span><span class="token">(</span><span class="token" style="color: #6f42c1;">g</span><span class="token" style="color: #6f42c1;">et</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-138"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-136">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-137'
	>
	Koin&#8217;s DSL, while remarkably straightforward, <strong>presents significant distinctions from Dagger or Hilt API</strong>. It primarily consists of <code>module</code> functions, which can be linked together using <code>includes</code> function:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-140"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">val repositoriesModule </span><span class="token" style="color: #d73a49;">=</span><span class="token"> module </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">includ</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">s</span><span class="token">(</span><span class="token">interactorsModule</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">val useCasesModule </span><span class="token" style="color: #d73a49;">=</span><span class="token"> module </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">includ</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">s</span><span class="token">(</span><span class="token">repositoriesModule</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-143"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-141">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-142'
	>
	This way, <code>useCasesModule</code> includes all of the dependencies provided inside the <code>repositoriesModule</code>, which includes all of the dependencies provided by <code>interactorsModule</code> and so on.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-146"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-144">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-145'
	>
	The <code>factory</code> function binds implementations to interfaces and the function <code>get()</code> helps Koin retrieve injected dependencies during runtime. In the code snippet below, we&#8217;re instructing Koin on how to build a <code>UseCases.GetWeather</code> instance. It uses the <code>get()</code> function to obtain the necessary <code>Repositories.Weather</code> dependency that <code>GetWeatherUseCase</code> requires:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">factory</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">UseCases</span><span class="token">.</span><span class="token" style="color: #24292e;">GetWeather</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">GetWeatherUseCa</span><span class="token" style="color: #6f42c1;">s</span><span class="token" style="color: #6f42c1;">e</span><span class="token">(</span><span class="token" style="color: #6f42c1;">g</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">t</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-151"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-149">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-150'
	>
	For <code>WeatherApiService</code> and <code>WeatherRepository</code> instances intended to be singletons, the <code>single</code> function is used:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">single</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">Repositories</span><span class="token">.</span><span class="token" style="color: #24292e;">Weather</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">WeatherReposito</span><span class="token" style="color: #6f42c1;">r</span><span class="token" style="color: #6f42c1;">y</span><span class="token">(</span><span class="token" style="color: #6f42c1;">g</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">t</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> 
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-156"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-154">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-155'
	>
	To use Koin, we first need to initialize it by calling the <code>startKoin</code> function and providing a parent module, in this case, the <code>useCasesModule</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-158"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">val exampleKoin </span><span class="token" style="color: #d73a49;">=</span><span class="token"> startKoin </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #6f42c1;">modules</span><span class="token">(</span><span class="token">useCasesModule</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">.</span><span class="token" style="color: #24292e;">koin</span><span class="token">
</span></span><span class="line"><span class="token">val weather </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">exampleKoin</span><span class="token">.</span><span class="token" style="color: #24292e;">get</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">UseCases</span><span class="token">.</span><span class="token" style="color: #24292e;">GetWeather</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token">(</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">invoke</span><span class="token">(</span><span class="token">cityName</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-161"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-159">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-160'
	>
	That’s it; Koin is initialized and ready for use.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-162">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-163'
	>
	Kotlin-inject</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-167"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-165">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-166'
	>
	Now that we have a clearer understanding of how Koin works, let’s see how Kotlin-inject compares. Some of its key features are:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-170"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-168">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-169'
	>
	<li>Relatively new and simple Kotlin-based dependency-injection library</li><li>Powered by Kotlin&#8217;s robust features like <a href="https://github.com/google/ksp" target="_blank" rel="noreferrer noopener">KSP</a> and lazy initialization, which simplify the process of providing dependencies</li><li>With the use of Kotlin typealias, it allows injecting multiple instances of the same type and even supports lambda injection</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-173"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-171">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-172'
	>
	Let&#8217;s roll up our sleeves again and put this library to work on our example project:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> ServicesComponent.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ServicesComponent</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@ExampleScop</span><span class="token">e</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@Provide</span><span class="token">s</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">protected</span><span class="token"> </span><span class="token">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">provideWeatherApiServi</span><span class="token" style="color: #6f42c1;">c</span><span class="token" style="color: #6f42c1;">e</span><span class="token">(</span><span class="token">)</span><span class="token">: WeatherApiService = 
</span></span><span class="line"><span class="token">    WeatherServiceProvider.</span><span class="token" style="color: #6f42c1;">pro</span><span class="token" style="color: #6f42c1;">v</span><span class="token" style="color: #6f42c1;">ide</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> InteractorsComponent.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">InteractorsComponent</span><span class="token"> : ServicesComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@Provide</span><span class="token">s</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">protected</span><span class="token"> fun GetWeatherDataInteractor.</span><span class="token" style="color: #6f42c1;">bi</span><span class="token" style="color: #6f42c1;">n</span><span class="token" style="color: #6f42c1;">d</span><span class="token">(</span><span class="token">)</span><span class="token">: Interactors.GetWeatherData = this
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> RepositoriesComponent.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">RepositoriesComponent</span><span class="token"> : InteractorsComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@ExampleScop</span><span class="token">e</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@Provide</span><span class="token">s</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">protected</span><span class="token"> fun WeatherRepository.</span><span class="token" style="color: #6f42c1;">bi</span><span class="token" style="color: #6f42c1;">n</span><span class="token" style="color: #6f42c1;">d</span><span class="token">(</span><span class="token">)</span><span class="token">: Repositories.Weather = this
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> UseCasesComponent.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UseCasesComponent</span><span class="token"> : RepositoriesComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">@Provide</span><span class="token">s</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">protected</span><span class="token"> fun GetWeatherUseCase.</span><span class="token" style="color: #6f42c1;">bi</span><span class="token" style="color: #6f42c1;">n</span><span class="token" style="color: #6f42c1;">d</span><span class="token">(</span><span class="token">)</span><span class="token">: UseCases.GetWeather = this
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> ExampleComponent.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">ExampleScope</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Component</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ExampleComponent</span><span class="token"> : UseCasesComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">abstract</span><span class="token"> val getWeatherUseCase</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">UseCases</span><span class="token" style="color: #24292e;">.GetWeathe</span><span class="token">r</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-176">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-177'
	>
	Kotlin-inject relies on annotations to define scopes and functions that contribute to the dependency graph. In the example above, we can notice a <strong>more Dagger-like API, unlike Koin DSL, which bears less resemblance.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-181"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-179">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-180'
	>
	Additionally, we can notice one major difference – <strong>there are no modules</strong>. Kotlin-inject operates using components, with the parent component <code>ExampleComponent</code> being an abstract class with <code>@Component</code> annotation and its own <code>@ExampleScope</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-183"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Scope</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Target</span><span class="token">(</span><span class="token">CLASS</span><span class="token">,</span><span class="token"> FUNCTION</span><span class="token">,</span><span class="token"> PROPERTY_GETTER</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">annotation </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ExampleScope</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-186"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-184">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-185'
	>
	The components rely on the interfaces they inherit to provide the necessary dependencies, which is called<strong> component inheritance</strong>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-188"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">RepositoriesComponent</span><span class="token"> : InteractorsComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> provide repository dependencies</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UseCasesComponent</span><span class="token"> : RepositoriesComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> provide usecase dependencies</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">ExampleScope</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Component</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ExampleComponent</span><span class="token"> : UseCasesComponent </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-191"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-189">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-190'
	>
	<code>ExampleComponent</code> implements <code>UseCasesComponent</code>, which provides the necessary dependencies while also relying on <code>RepositoriesComponent</code> for its dependencies and so on.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-194"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-192">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-193'
	>
	To bind implementations, a familiar <code>@Provides</code> annotation is used combined with the extension function <code>bind</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-196"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">ExampleScope</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Provides</span><span class="token">
</span></span><span class="line"><span class="token">fun </span><span class="token" style="color: #24292e;">WeatherRepository</span><span class="token">.</span><span class="token" style="color: #6f42c1;">bind</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">Repositories</span><span class="token">.</span><span class="token" style="color: #24292e;">Weather</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-199"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-197">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-198'
	>
	<code>WeatherRepository</code> and <code>WeatherApiService</code> are scoped as singletons using the already mentioned <code>@ExampleScope</code> annotation. The instance of these components will live as long as the <code>ExampleComponent</code> does.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-202"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-200">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-201'
	>
	Finally, <code>ExampleComponent</code> is crafted using the <code>create</code> extension function and is ready for use:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">val exampleComponent </span><span class="token" style="color: #d73a49;">=</span><span class="token"> ExampleComponent</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #24292e;">class</span><span class="token">.</span><span class="token" style="color: #6f42c1;">create</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">val weather </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">exampleComponent</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getWeatherUseCase</span><span class="token">(</span><span class="token">cityName</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-205">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-206'
	>
	With the differences in implementation covered, we can now compare the two libraries based on some common criteria.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-208">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-209'
	>
	Koin vs. Kotlin-inject – a head-to-head comparison</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-211">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-212'
	>
	Let&#8217;s size up these two libraries in some key categories that affect your development as well as the user experience. This will allow you to get a clearer picture of where each library shines and where its weaker points are.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-216"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-214">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-215'
	>
	Build time</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-219"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-217">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-218'
	>
	First, we&#8217;re going to take a look at how these two libraries stack up against each other when it comes to build time. A key difference between Koin and Kotlin-inject lies in their mechanics:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-223"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-220">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<h4	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-221'
	>
	<strong>The Koin approach</strong>:</h4><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-222'
	>
	Koin functions similarly to a service locator pattern, creating and providing the dependencies we want in runtime when they are needed. This translates to less boilerplate code generated during compile-time.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-224">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<h4	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-225'
	>
	<strong>The Kotlin-inject approach:</strong></h4><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-226'
	>
	Kotlin-inject acts as a code generator, creating the necessary boilerplate for effective dependency injection based on the setup and annotations you provide. Similarly to Dagger and Hilt, this results in a significant amount of code generated during compile-time.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-228">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-229'
	>
	Due to reduced compile-time code generation, <strong>using Koin typically leads to quicker builds</strong>. Notably, the difference in build time becomes more significant on larger projects, amplifying Koin&#8217;s advantage.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-233"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-231">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-232'
	>
	Runtime performance</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-236"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-234">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-235'
	>
	Moving on with our agenda, we’ll compare the startup and injection performance of the two libraries. The results presented are based on the median of 100 iterations in our example project setup:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-238"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Koin</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Startup time: 0.2475 ms</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val exampleKoin </span><span class="token" style="color: #d73a49;">=</span><span class="token"> startKoin </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #6f42c1;">modules</span><span class="token">(</span><span class="token">useCasesModule</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">.</span><span class="token" style="color: #24292e;">koin</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Injection time: 0.0137 ms</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val weatherUseCase </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">exampleKoin</span><span class="token">.</span><span class="token" style="color: #24292e;">get</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #24292e;">UseCases</span><span class="token">.</span><span class="token" style="color: #24292e;">GetWeather</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-240"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Kotlin-inject</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Startup time: 0.0005 ms</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val exampleComponent </span><span class="token" style="color: #d73a49;">=</span><span class="token"> ExampleComponent</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #24292e;">class</span><span class="token">.</span><span class="token" style="color: #6f42c1;">create</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Injection time: 0.0043 ms</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val weatherUseCase </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">exampleComponent</span><span class="token">.</span><span class="token" style="color: #24292e;">getWeatherUseCase</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-243"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-241">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-242'
	>
	In summary, while Koin offers quicker build times, it does come with a trade-off. The runtime dependency resolution impacts the overall performance, <strong>causing Koin to lag significantly behind Kotlin-inject in this regard</strong>. The difference is most noticeable during startup. Resolving the Koin dependency graph requires significantly more time compared to creating a Kotlin-inject component, which benefits from pre-generated boilerplate code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-246"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-244">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-245'
	>
	Debugging</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-249"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-247">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-248'
	>
	Now, let&#8217;s delve into the libraries’ debugging capabilities. Both libraries excel in providing clear and informative error descriptions. However, <strong>Kotlin-inject has the advantage of showing them at compile-time</strong>, which allows you to correct your mistakes without ever running the application. This is not only a more convenient but also a much safer approach. On the other hand, Koin addresses this with somewhat of a workaround – <strong>writing tests to validate your Koin setup</strong>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-251"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">CheckKoinModulesTest</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">@Tes</span><span class="token">t</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">checkUseCasesMo</span><span class="token" style="color: #6f42c1;">d</span><span class="token" style="color: #6f42c1;">ule</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">checkKoi</span><span class="token" style="color: #6f42c1;">n</span><span class="token" style="color: #6f42c1;">Modules</span><span class="token">(</span><span class="token" style="color: #6f42c1;">l</span><span class="token" style="color: #6f42c1;">istOf</span><span class="token">(</span><span class="token">useCasesModule</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-254"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-252">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-253'
	>
	Writing these tests does provide you with the verification of DI structure, but still requires you to run them quite often, which is less practical compared to Kotlin-inject compile-time error detection.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-257"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-255">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-256'
	>
	Community</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-260"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-258">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-259'
	>
	To wrap things up, we should mention the communities behind these two libraries, since they are the ones responsible for their respective future development.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-263"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-261">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-262'
	>
	<strong>Koin has an active community of contributors</strong> ensuring regular updates and enhancements. After all, they&#8217;ve paved the way for smooth integrations with Ktor, Compose, ViewModel, and KMP and will continue to provide support for future technologies. Alongside regular updates and initiatives, Koin’s engaged user community helps spot and resolve issues quickly.<br>On the other hand, <strong>Kotlin-inject is still establishing its presence</strong> with a smaller contributor base. However, it&#8217;s gaining traction within the Kotlin development scene, hinting at a bright future for the community.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-266"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-264">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-265'
	>
	Koin or Kotlin-inject? You choose.</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-269"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-267">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-268'
	>
	As would be expected, both Koin and Kotlin-inject come with their own set of strengths and weaknesses.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-272"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-270">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-271'
	>
	If you prefer a simpler DSL, want to benefit from faster build times, seek integration with various technologies like Ktor, Compose, Android, KMP, and value a strong community support, Koin is a solid choice.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-275"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-273">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-274'
	>
	On the other hand, if you prefer a Dagger-like API, prioritize compile-time safety and runtime performance, want to use Kotlin&#8217;s powerful features, and are comfortable with fewer integrations by a smaller, but growing community, Kotlin-inject is the library for you.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-278"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-276">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-277'
	>
	Clearly, there&#8217;s no universal answer when it comes to choosing between these two libraries. However, if you take a close look at the needs of your project and take into consideration your own skills and preferences, you’ll be able to decide which of the two is the best fit.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/koin-vs-kotlin-inject-dependency-injection/">Koin vs. Kotlin-inject – Which to Choose and Why?</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>29615https://infinum.com/uploads/2022/11/Remote-brewing.webp</url>
				</image>
				<title>Enabling Philips Coffee+ Users to Brew Drinks Remotely</title>
				<link>https://infinum.com/blog/how-we-enabled-coffee-users-brew-drinks-remotely/</link>
				<pubDate>Mon, 07 Nov 2022 13:23:39 +0000</pubDate>
				<dc:creator>Marin Šimić</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=29615</guid>
				<description>
					<![CDATA[<p>As part of the 2.0.0 release, we finally launched the most requested and most challenging feature so far – remote brewing.</p>
<p>The post <a href="https://infinum.com/blog/how-we-enabled-coffee-users-brew-drinks-remotely/">Enabling Philips Coffee+ Users to Brew Drinks Remotely</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-310"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-281">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-284"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-282">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-283'
	>
	Coffee+ is the accompanying application for Philips coffee machines that allows users to control certain functions of their machines remotely. The app provides a seamless user experience and offers various ways of interacting with the machine over WiFi. Users can turn their machine on and off, set a timer to turn it on at a specific time, adjust water hardness and standby time. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-287"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-285">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-286'
	>
	As part of the 2.0.0 release, we finally launched the most requested and most challenging feature so far – remote brewing.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-289"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-288'
	>
	This feature allows coffee machine users to choose a specific drink, customize it to their liking, start and track the brewing process without having to physically interact with the machine.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-292"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-290">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-291'
	>
	However, implementing the feature was no simple task. This blog post will discuss a problem we encountered on the way and how we solved it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-299"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-293"
	 target='_blank' rel='noopener noreferrer' href='https://infinum.com/iot-implementation/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<h2	class='typography typography--size-24-text js-typography card-simple__heading'
	data-id='es-294'
	>
	From strategy to deployment, we cover all aspects of IoT development lifecycle. <strong>Download our Guide to Successful IoT Implementation</strong>.</h2>		</div>

		<button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-296"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-297'
	>
	Learn more</div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-298'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-302"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-300">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-301'
	>
	The elusive brewing status</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-305"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-303">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-304'
	>
	The remote brewing flow is far from simple. It required adding new activities as well as updating some old ones. Apart from the standard happy flow, we had to implement an error-handling flow as well as various checks and handles throughout the brewing process.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-308"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-306">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-307'
	>
	The biggest challenge we encountered during implementation was keeping track of the brewing status in different activities and navigation graphs. Also, during the brewing process the machine couldn’t be a single source of truth for the current state of brewing due to the lack of emitted properties. This means that simply renewing the subscription and reading the properties wouldn’t suffice if we wanted to determine the latest state. If we wanted to show a snackbar at the bottom of <code>DashboardActivity</code> immediately after remote brewing is canceled, reading machine properties wouldn&#8217;t provide enough information for us to do it.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-311"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-312">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2022/11/the_problem_source-1400x1293.webp				media='(max-width: 699px)'
				type=image/webp								height="1293"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2022/11/the_problem_source.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1940"
															width="2100"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-385"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-314">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-317"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-315">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-316'
	>
	As you can see in the example above, once brewing is canceled by calling <code>CancelBrewingUseCase</code> and we close <code>BrewingActivity</code>, the machine state remains at <code>BREWING</code> for some time until the whole process is completed. So there is no real way of determining if the brewing process was canceled just by observing machine properties.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-320"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-318">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-319'
	>
	On top of that, we wanted our logic to be handled in one component for easier logging and testing, as well as reducing the amount of repetitive code. Since there is always a chance we will expand upon this feature sometime in the future, we also wanted our code to be clean and scalable.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-323"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-321">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-322'
	>
	Envisioning a solution</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-326"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-324">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-325'
	>
	We’ve defined the problem, and now we can start looking into potential solutions. There are several aspects we’ll need to consider.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-329"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-327">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-328'
	>
	Scope</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-332"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-330">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-331'
	>
	Because the brewing process spans multiple activities, we cannot use a shared <code>ViewModel</code>, meaning we need a separate component independent of any activity lifecycle. We can conclude that we need a component with a scope that lasts throughout the entire remote brewing flow.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-335"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-333">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-334'
	>
	States</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-338"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-336">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-337'
	>
	How do we present the state of the brewing process? The machine can go through various states during the process. For example, before brewing is started, the machine is considered to be in an <code>IdleState</code>. When it starts brewing, the machine switches to <code>ProgressState</code> and the updated progress value should be shown in the app UI. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-339'
	>
	If an error occurs during brewing, for example, someone pulls the drip tray out, the machine switches to <code>ErrorHandlingState</code>, and user action is expected. Some of the states can be observed directly from the values emitted by the machine, but some are more dependent on the user&#8217;s interaction with the app. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-341">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-342'
	>
	As mentioned, when a user decides to cancel brewing, we should switch to <code>CancelledState</code>, which cannot be determined from the machine properties. We can conclude that brewing should be reflected in various states. These states can change depending on the properties observed from the machine or from the user&#8217;s interaction with the application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-346"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-344">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-345'
	>
	State machine</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-349"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-347">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-348'
	>
	All of these requirements point towards the finite-state machine or FSM. FSM is a mathematical model of computation, an abstract machine that can be in exactly one of a finite number of states at once. FSM can then change states depending on the current state and input. These are called transitions and in our case, inputs that will trigger transitions can either come from the machine side (a change of value observed) or from a user’s interaction with the application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-352"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-350">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-351'
	>
	Therefore, to determine where the input came from, we want to make a lifecycle-independent state machine component with a single current state that will always reflect the state of remote brewing.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-355"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-353">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-354'
	>
	Implementation</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-358"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-356">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-357'
	>
	Now that we’ve defined what our solution requires, we can dive into the implementation in more detail.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-361"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-359">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-360'
	>
	State</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-364"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-362">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-363'
	>
	First let’s see how a state is defined through the <code>BaseState</code> interface:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-366"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">interface BaseState</span><span class="token" style="color: #6f42c1;">&lt;State : BaseState&lt;State, Output, Action&gt;, Output, Action&gt;</span><span class="token"> {
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">suspend</span><span class="token"> </span><span class="token">fun onAction</span><span class="token">(action</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Action</span><span class="token">): </span><span class="token" style="color: #6f42c1;">S</span><span class="token" style="color: #6f42c1;">tate</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">fun toOutput</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Output</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-369"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-367">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-368'
	>
	If we look at the definition of <code>BaseState</code>, we can notice two generic types, <code>Output</code> and <code>Action</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-372"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-370">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-371'
	>
	<li><code>Output</code> is a model that holds state properties. By emitting an <code>Output</code> rather than the whole <code>State</code> we protect state values and functions from other components.</li><li><code>Action</code> represents inputs that lead to transitions. Each state can handle a certain <code>Action</code> through the call of <code>onAction</code> function and return a new <code>State</code> (or itself). That way states perform transitions by handling actions.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-375"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-373">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-374'
	>
	Now let&#8217;s take a look at a simplified example of <code>ProgressState</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-377"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class ProgressState</span><span class="token">(
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">progress</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Int</span><span class="token"> = </span><span class="token" style="color: #6f42c1;">0</span><span class="token">
</span></span><span class="line"><span class="token">) </span><span class="token">: </span><span class="token" style="color: #6f42c1;">BaseBrewingState</span><span class="token"> </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun toOutput</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BrewingOutput</span><span class="token"> =
</span></span><span class="line"><span class="token">        BrewingOutput</span><span class="token">.ProgressState</span><span class="token">(
</span></span><span class="line"><span class="token">            progress </span><span class="token" style="color: #d73a49;">=</span><span class="token"> progress
</span></span><span class="line"><span class="token">        )
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token" style="color: #d73a49;">suspend</span><span class="token"> </span><span class="token">fun onAction</span><span class="token">(action</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BrewingAction</span><span class="token">): </span><span class="token" style="color: #6f42c1;">B</span><span class="token" style="color: #6f42c1;">aseBrewingState</span><span class="token"> =
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">when</span><span class="token"> (action) {
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">is</span><span class="token"> BrewingAction.UpdateProgress </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> action</span><span class="token">.handle</span><span class="token">()
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">is</span><span class="token"> BrewingAction.StartErrorHandling </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> action</span><span class="token">.handle</span><span class="token">()
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">is</span><span class="token"> BrewingAction.CancelBrewing </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> action</span><span class="token">.handle</span><span class="token">()
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token">
</span></span><span class="line"><span class="token">        }
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">fun BrewingAction.UpdateProgress</span><span class="token">.handle</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BaseBrewingState</span><span class="token"> = </span><span class="token" style="color: #6f42c1;">Pr</span><span class="token">ogressState</span><span class="token">(updatedProgress)
</span></span><span class="line"><span class="token">    
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">fun BrewingAction.StartErrorHandling</span><span class="token">.handle</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BaseBrewingState</span><span class="token"> = </span><span class="token" style="color: #6f42c1;">Er</span><span class="token">rorState</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">fun BrewingAction.CancelBrewing</span><span class="token">.handle</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BaseBrewingState</span><span class="token"> = </span><span class="token" style="color: #6f42c1;">Ca</span><span class="token">ncelledState</span><span class="token">()
</span></span><span class="line"><span class="token">}
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-380"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-378">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-379'
	>
	Function <code>toOutput</code> is implemented and returns <code>BrewingOutput.ProgressState</code> which holds the latest <code>progress</code> value. The other function <code>onAction</code> handles three types of <code>BrewingAction</code>, otherwise the same state is returned and no transitions are made. In case the <code>UpdateProgress</code> action is received, a new <code>ProgressState</code> is returned with updated <code>progress</code> value. Action <code>StartErrorHandling</code> will return <code>ErrorState</code> and the last handled action <code>CancelBrewing</code> will return <code>CancelledState</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-383"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-381">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-382'
	>
	If we wanted to visualize these state transitions with a diagram, they would look something like this:</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-388"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-386"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-387">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2022/11/Progress-state-diagram-1400x588.webp				media='(max-width: 699px)'
				type=image/webp								height="588"
												width="1400"
				 />
								
			<source
				srcset=https://infinum.com/uploads/2022/11/Progress-state-diagram-2400x1008.webp				media='(max-width: 1199px)'
				type=image/webp								height="1008"
												width="2400"
				 />
												<img
					src="https://infinum.com/uploads/2022/11/Progress-state-diagram.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1150"
															width="2738"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-442"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-389">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-392"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-390">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-391'
	>
	If our <code>ProgressState</code> receives the <code>CancelBrewing</code> action from a user’s interaction with the UI it will immediately transition to <code>CancelledState</code>. Otherwise, if the brewing progress property changes from the machine side, <code>ProgressState</code> will receive the <code>UpdateProgress</code> action and transition to a new <code>ProgressState</code> with updated <code>progress</code> value. Finally, if any errors are observed from the machine side, the <code>StartErrorHandling</code> action is received and <code>ProgressState</code> transitions to <code>ErrorState</code> where it will wait for the user to resolve the machine error.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-395"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-393">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-394'
	>
	State machine</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-398"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-396">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-397'
	>
	Now that we have a good understanding of how states and transitions work, the only thing left is to implement a state machine. Following is an example of <code>BaseStateMachine</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-400"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token">class BaseStateMachine</span><span class="token" style="color: #6f42c1;">&lt;State : BaseState&lt;State, Output, Action&gt;, Output, Action&gt;</span><span class="token"> {
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">protected</span><span class="token"> </span><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token">val </span><span class="token">scope</span><span class="token">: </span><span class="token" style="color: #6f42c1;">CoroutineScope</span><span class="token">
</span></span><span class="line"><span class="token">    
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token">val </span><span class="token">stateFlow</span><span class="token">: </span><span class="token" style="color: #6f42c1;">StateFlow</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">Output</span><span class="token">&gt;
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">protected</span><span class="token"> </span><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token">val </span><span class="token">currentState</span><span class="token">: </span><span class="token" style="color: #6f42c1;">State</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">abstract</span><span class="token"> </span><span class="token" style="color: #d73a49;">suspend</span><span class="token"> </span><span class="token">fun update</span><span class="token">(action</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Action</span><span class="token">)
</span></span><span class="line"><span class="token">}
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-403"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-401">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-402'
	>
	The first value to implement is the <code>scope</code>. As mentioned earlier, we want our state machine to have its own independent scope. In this example we are using <code>CoroutineScope</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-405"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">val </span><span class="token">scope </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">CoroutineScope</span><span class="token">(dispatcher </span><span class="token" style="color: #d73a49;">+</span><span class="token"> </span><span class="token">SupervisorJob</span><span class="token">())
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-408"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-406">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-407'
	>
	When initializing <code>CoroutineScope</code>, we are using an injected dispatcher combined with <code>SupervisorJob</code>. That way we can be sure that failing jobs will not cancel the whole state machine process. Inside the <code>scope</code> the state machine can observe machine properties, perform actions, and make state changes. If we wanted to observe the brewing progress flow and perform actions on each updated value, we would do it inside the mentioned <code>scope</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-410"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token"> </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">fun observeProgress</span><span class="token">() </span><span class="token" style="color: #d73a49;">=</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">observeBrewingProgress</span><span class="token">()</span><span class="token">.onEach </span><span class="token">{
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> update state</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> log tracked progress</span><span class="token">
</span></span><span class="line"><span class="token">    }</span><span class="token">.launchIn</span><span class="token">(scope)
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-413"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-411">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-412'
	>
	The second value implemented is the <code>stateFlow</code>, which is the output of the state machine. Other components can subscribe to <code>stateFlow</code> changes and observe the state of brewing. Here is an example of <code>stateFlow</code> used in the implementation with its initial value set to <code>BrewingOutput.IdleState</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-415"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token"> </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">mutableStateFlow </span><span class="token" style="color: #d73a49;">=</span><span class="token">
</span></span><span class="line"><span class="token">     </span><span class="token">MutableStat</span><span class="token">eFlow&lt;</span><span class="token" style="color: #6f42c1;">BrewingOutput</span><span class="token">&gt;</span><span class="token">(BrewingOutput.IdleState)
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token"> </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">val </span><span class="token">stateFlow</span><span class="token">: </span><span class="token" style="color: #6f42c1;">StateFlow</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">BrewingOutput</span><span class="token">&gt; =</span><span class="token"> mutableStateFlow
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-418"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-416">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-417'
	>
	The next value implemented is <code>currentState</code>, which holds the reference to the latest state the state machine was in:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-420"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">var </span><span class="token">currentState</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BaseBrewingState</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">IdleState</span><span class="token">()
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">set</span><span class="token">(</span><span class="token" style="color: #d73a49;">value</span><span class="token">) {`
</span></span><span class="line"><span class="token">         </span><span class="token" style="color: #d73a49;">field</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">value</span><span class="token">
</span></span><span class="line"><span class="token">         mutableStateFlow</span><span class="token">.tryEmit</span><span class="token">(</span><span class="token" style="color: #d73a49;">value</span><span class="token">.toOutput</span><span class="token">())
</span></span><span class="line"><span class="token">         </span><span class="token">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">New state set: </span><span class="token" style="color: #032f62;">${</span><span class="token" style="color: #d73a49;">value</span><span class="token" style="color: #032f62;">.toOutput</span><span class="token" style="color: #032f62;">()</span><span class="token" style="color: #032f62;">}</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)
</span></span><span class="line"><span class="token">     }
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-423"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-421">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-422'
	>
	Initially, the <code>currentState</code> is set to <code>IdleState</code>. The value setter is marked as <code>private</code> to ensure encapsulation and prevent other components from altering the state. Once a new state is set, the state output value is emitted to the <code>mutableStateFlow</code> to notify all of the observing components about the latest state change. This state change is also logged.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-426"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-424">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-425'
	>
	The last to implement was the <code>update</code> function, which acts as the only input to the state machine:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-428"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token"> </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token" style="color: #d73a49;">suspend</span><span class="token"> </span><span class="token">fun update</span><span class="token">(action</span><span class="token">: </span><span class="token" style="color: #6f42c1;">BrewingAction</span><span class="token">)</span><span class="token"> {
</span></span><span class="line"><span class="token">     currentState </span><span class="token" style="color: #d73a49;">=</span><span class="token"> currentState</span><span class="token">.onAction</span><span class="token">(action)
</span></span><span class="line"><span class="token"> }
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-431"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-429">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-430'
	>
	Certain app components can use this function to interact with the brewing process. Once this function is invoked with a specific <code>action</code>, the result of <code>currentState.onAction(action)</code> is going to be the next <code>currentState</code>. For example, if our <code>currentState</code> is <code>ProgressState</code> from the previous chapter, once <code>update(BrewingAction.CancelBrewing)</code> is called, the resulting <code>CancelledState</code> will be the new <code>currentState</code> and all of the observing components will be notified of the change through <code>stateFlow</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-434"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-432">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-433'
	>
	Architecture</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-435">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-436'
	>
	By now we should have a deeper understanding of the state machine. Now let&#8217;s see how it blends into our app’s architecture. As mentioned before, the state machine has its own scope, meaning it differs from any other domain component (UseCase, Repository, Interactor). On top of that, we would also like to use these components for performing actions inside the StateMachine. For that reason, StateMachine is like a bridge layer between the UI and the domain layers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-438">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-439'
	>
	Here’s an example of the way state machine interacts with the components from both UI and domain layers:</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-445"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-443"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-444">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2022/11/state_machine_architecture_source-1400x1537.webp				media='(max-width: 699px)'
				type=image/webp								height="1537"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2022/11/state_machine_architecture_source.webp"
					class="image__img block-media__image-img"
					alt=""
										height="2240"
															width="2040"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-454"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-446">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-449"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-447">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-448'
	>
	The example above shows a standard brewing navigation flow. First, when the drink parameters are defined, brewing is started inside <code>AdjustDrinkViewModel</code> by sending <code>BrewingAction.StartBrewing(drink)</code>. <code>BrewingStateMachine</code> handles this action by calling <code>StartBrewingUseCase</code> and performs state transition to <code>ProgressState</code>. This state is updated by observing <code>ObserveBrewingProgressUseCase</code>, with each progress change from the machine being emitted as <code>BrewingOutput.ProgressState(progress)</code>. The output is observed inside the <code>BrewingProgressViewModel</code> and the UI is updated accordingly. If the user decides to cancel brewing, <code>BrewingAction.CancelBrewing</code> is sent inside <code>CancelBrewingViewModel</code> and <code>BrewingActivity</code> is finished. Upon receiving this action, <code>BrewingStateMachine</code> cancels the brewing process by calling <code>CancelBrewingUseCase</code> and transitions to <code>CancelledState</code>. This new <code>BrewingOutput.CancelledState</code> is observed inside the <code>DashboardViewModel</code> and a snackbar is shown notifying the user that brewing was canceled.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-452"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-450">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-451'
	>
	State machine and onwards</h2></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-457"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-455"
	 data-media-type='video'>

	<div class="video__wrapper" data-id="es-456">
		<video
		class="video block-media__video js-video js-block-media-video video--cursor-takeover-use"
		 loop autoplay playsinline muted preload='metadata'>
		<source  src='https://infinum.com/uploads/2022/11/state_machine_flow.mp4' type='video/mp4' />	</video>
	</div></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-475"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-458">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-461"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-459">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-460'
	>
	We successfully added a much-anticipated feature for Coffee+ users. Enabling remote brewing was not a simple implementation, but we managed to tackle the challenges involved.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-464"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-462">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-463'
	>
	Working our way through the implementation, we got a very close look at the state machine. Let’s summarize some of its benefits:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-467"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-465">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-466'
	>
	<li>State machine acts as a single point of reference for controlling and observing the brewing process and can be used as such from any ViewModel inside the application.</li><li>State machine is a lifecycle-independent component that has its own scope, meaning it will persist regardless of activity changes like in the example above.</li><li>State machines are easily scalable by simply adding new states and actions, with states handling transitions without accumulating code inside the state machine.</li><li>Most of the logic is stored inside the state machine component, preventing us from writing repetitive code elsewhere and having to test it individually.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-470"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-468">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-469'
	>
	The remote brewing feature is now fully functional, and our clean and scalable code will allow us to build upon it even further in the future. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-473"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-471">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-472'
	>
	<em>To find out what else we can do in the Internet of Things realm, check out our <a href="https://infinum.com/custom-iot-solutions/" target="_blank" rel="noreferrer noopener">IoT solutions page</a>.</em></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/how-we-enabled-coffee-users-brew-drinks-remotely/">Enabling Philips Coffee+ Users to Brew Drinks Remotely</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>