<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Vasilis Charalampakis on Medium]]></title>
        <description><![CDATA[Stories by Vasilis Charalampakis on Medium]]></description>
        <link>https://medium.com/@charbgr?source=rss-f985d4ea8dce------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*WCfBS-GJ_nh7D3p7eT0pWg.jpeg</url>
            <title>Stories by Vasilis Charalampakis on Medium</title>
            <link>https://medium.com/@charbgr?source=rss-f985d4ea8dce------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 08 Apr 2026 10:09:36 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@charbgr/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Bye bye Dagger ]]></title>
            <link>https://medium.com/@charbgr/bye-bye-dagger-1494118dcd41?source=rss-f985d4ea8dce------2</link>
            <guid isPermaLink="false">https://medium.com/p/1494118dcd41</guid>
            <category><![CDATA[koin]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[dagger]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[dependency-injection]]></category>
            <dc:creator><![CDATA[Vasilis Charalampakis]]></dc:creator>
            <pubDate>Mon, 13 Aug 2018 11:08:12 GMT</pubDate>
            <atom:updated>2018-08-23T08:39:03.898Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bsLqbAAElwKOeHABfd7c5A.jpeg" /></figure><p>When writing an Android application there comes a time, where you need to pick libraries. You always have in mind that these libraries should be scaleable, will help you achieve your goal and make your developer experience easier. That’s why we pick libraries that all big companies have in their toolset and have proved to work perfectly.</p><p>Such decisions I had to take when I scaffolded the Workable Android app. One of the libraries I chose was <a href="https://github.com/google/dagger">Dagger</a>. Dagger is a dependency injection framework that generates the dependencies at compile time. Well.. Guess what.</p><blockquote>Dagger didn’t work well for us.</blockquote><p>Dagger is stable and powerful and I can’t argue on that. One problem is that it is too complex, both the examples and the documentation and requires a lot of boilerplate code. I can’t remember how many times I looked over the Thermosiphon example in order to understand what exactly is happening. But complexity wasn’t the reason that Dagger didn’t work well for us despite it being a significant reason.</p><p>The biggest and most annoying problem, was the accompanied code generation by (k)apt. In our app, we also use Databinding heavily which is also based on code generation (note that for later). There was a moment when I needed to change the configuration of Dagger. After finishing with the changes and hitting compile, there were over 100 errors flooding the console. There wasn’t a clear indication what went wrong.</p><p>After a lot of continuous changes, retries and refactors over the already refactored configuration, I opened this <a href="https://github.com/google/dagger/issues/306">issue</a> on Dagger because I couldn’t reproduce it on small projects. After a couple of days of debugging with a colleague, we found that the annotation processors of Dagger and Databinding were messing around and when one failed, it caused the other processor to fail as well. As a result, I had several errors that I didn’t know how they were produced. Several days ahead struggling with the issue, we discovered that javac outputs only the first 100 errors, by default. That meant that our actual error was hidden somewhere above those 100 errors. After increasing the max errors javac produces, I found the “hidden” error and didn’t touch the Dagger setup again for <strong>2</strong> <strong>years</strong>, fearing similar situations.</p><p>Another issue our team faced with Dagger and probably the biggest one, was compile times. When your codebase is growing, compile times are increasing along with it. Our build takes on average 5–7mins and the incremental one is ~2.00–2.30mins. This is because kapt was breaking incremental compilation resulting in a full rebuild. Even tests are taking a long time to compile. Things can go sideways if you also add another library with code generation. Our team decided that this isn’t a “healthy” development environment to be working on and had to do something to make our build more reliable.</p><blockquote>What did we do?</blockquote><p>We ditched Dagger.</p><p>We decided to replace it with <a href="https://github.com/InsertKoinIO/koin">Koin</a> and couldn’t be more happy with that. Koin provides almost the same feature set as Dagger without a proxy, code generation, or reflection. It has scopes, multibindings and it is much easier to understand. Also, the documentation and examples are way more simple and straightforward. There is a tiny overhead at runtime, because it creates the dependency graph, but the cost is negligible.</p><p>Its easy and fluent API, saved us a lot of time with the migration. We started the migration by rebuilding the dependency graph exactly the way it is build with Dagger but in a <em>Koinish</em> way. In the meantime, we retained the dependency of Dagger in our project. Each time, we created a new module, we ran in a Unit-test the dryRun function that Koin provides. This function goes through all your modules and checks if the dependency graph is set up correctly. In addition, this helpful function, guarantees us that we will not break at runtime when we are pulling dependencies.</p><p>Once we finished the dependency graph, it was time to replace Dagger’s inject call sites with Koin ones. This was a piece of cake, since Koin offers custom <a href="https://kotlinlang.org/docs/reference/delegated-properties.html">delegated properties</a> to inject dependencies. The final result looked like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/88a5b4906281840008e8a576c75d0877/href">https://medium.com/media/88a5b4906281840008e8a576c75d0877/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e09e72e84e56d33ca117199de29d0751/href">https://medium.com/media/e09e72e84e56d33ca117199de29d0751/href</a></iframe><p>What we did on tests, was to replace modules or some parts of them with fake ones. For example, if we want to mock the above Storage, we just replaced the module with the mocked one.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2b5e7809630a2641b583b5c2add64880/href">https://medium.com/media/2b5e7809630a2641b583b5c2add64880/href</a></iframe><p>One of the powerful features of Koin is the ability to declare scopes. At Workable, we have a feature that allows a user to be logged-in in multiple accounts. This functionality is backed up by a specific module. When the user switches account, we release that module and let the user-scoped module/graph pull a new instance.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7d6933040f043aba2013b007a3ba5921/href">https://medium.com/media/7d6933040f043aba2013b007a3ba5921/href</a></iframe><blockquote><em>But what happened with Java files? Koin also works with Java. You can see more in the official </em><a href="https://beta.insert-koin.io/docs/1.0/quick-references/koin-java/"><em>documentation</em></a><em>. You can also find several techniques on </em><a href="https://github.com/InsertKoinIO/koin/issues/81"><em>this</em></a><em> Github issue.</em></blockquote><p>Once finished replacing all the call sites, we deleted every Dagger class annotated with Module, Component etc, resulting in <strong>93 </strong>additions and <strong>1803</strong> deletions. Quite a lot huh?</p><p>After doing that, we also saw several seconds down on compile time. This is because we removed some heavy work from kapt. Here is a sample benchmark :</p><pre>| Modules \ Compile time | Dagger  | Koin<br>|------------------------|---------|---------|<br>| :app                   | 41.610s | 28.374s |<br>| :module1               | 26.563s | 19.745s |<br>| :module2               | 14.345s | 11.325s |<br>| :module3               | 7.241s  | 3.950s  |<br>| :module4               | 22.828s | 5.866s  |<br>| :module5               | 4.976s  | 2.505s  |<br>| :module6               | 5.631s  | 4.684s  |<br>| :module7               | 1.988s  | 3.178s  |<br>| SUM                    | 125.15s | 79.59s  |<br>|------------------------|---------|---------|</pre><h4>Final thoughts</h4><p>What I suggest you to do, is look what works best for your team. There are several dependency injection and service locators libraries out there. We decided to use Koin. But that is our choice. Maybe your choice is to create your own, which could also be a perfect solution, because it would be simpler to understand how it actually works, since it is written by you. What won us in Koin, was its simple DSL, non verbose configuration and the ability to declare scopes and multibindings.</p><p>I am not a big fan of code generation. While sometimes it makes life easier, others it drains a lot of energy from you. I don’t like the trend of a code generation tool for every single tiny problem/thing on Android but that’s my Preference(Context.<em>MODE_PRIVATE</em>) 😛.</p><p>At least, one could argue about the differences between dependency injection and service locator pattern. I dοn’t want to dwell on this. You can find long and contradictory articles on the definition of these things with ease. My point is to, see what suits best for your team. Just because big companies use a library, it doesn’t mean it will work for you. Evaluate it and then go for it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1494118dcd41" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reproducible history on Android]]></title>
            <link>https://medium.com/@charbgr/reproducible-history-on-android-3b4a93d92236?source=rss-f985d4ea8dce------2</link>
            <guid isPermaLink="false">https://medium.com/p/3b4a93d92236</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[architecture]]></category>
            <category><![CDATA[reactive-programming]]></category>
            <dc:creator><![CDATA[Vasilis Charalampakis]]></dc:creator>
            <pubDate>Wed, 21 Jun 2017 15:49:20 GMT</pubDate>
            <atom:updated>2017-06-24T00:35:41.815Z</atom:updated>
            <content:encoded><![CDATA[<p>Have you ever wondered how you can write your app in a way that you know, at anytime, which was the previous state? Being able to undo an action, a user has previously done, is always a challenging thing and requires conscious effort from the developer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*TY4-Km82PmnOkRHMSRi7_g.gif" /><figcaption>Gmail Undo action</figcaption></figure><p>Applications like Gmail or Google’s Keep support undo action.</p><p>“Traditional” app architectures, like MVC or MVP, support these actions but they don’t manage state elegantly. The main reason is that they have an implicit data flow, which means that you can possible end up in invalid states. In this article, we will see how you can avoid these states and define a state machine in your app.</p><p>What we really need is to represent state in such a way that will be trackable, immutable and serializable. This state should be our source of truth for the UI at any certain point of time. Every user interaction should render a new different state. Every new state that is produced is our way to: go back, undo and generally reproduce history.</p><p>Architectures that enforce this pattern and eliminate the previously mentioned limitations of the “traditional” architectures, are MVI (Model-View-Intent), Redux and generally reactive architectures. For the sake of simplicity, I will analyze the MVI architecture.</p><h3>Model-View-Intent</h3><p>Model-View-Intent architecture might seem very strange at first glance! By referring to Intent we don’t mean <a href="https://developer.android.com/reference/android/content/Intent.html">Android’s Intent</a>, rather than a <strong>user’s</strong> interaction with our UI. Model is an object that processes information and keeps our state. View is the representation of the UI and cannot be rendered if Model is not present.</p><p>This architecture is heavily based on streams. If you use RxJava, every intent should be expressed as an Observable stream of events. For example, when a user clicks a button, you need to “translate” this to an Observable. Lucky for you, there is <a href="https://github.com/JakeWharton/RxBinding">RxBinding</a> that handles all of these translations.</p><p>MVI enforces unidirectional data flow. In a few words, unidirectional data flow provides predictable application state. This means, that a change on the UI layer will trigger an action on the data layer and the changes, that might occur, will transform the UI. This does not necessarily mean that the view directly affects storages etc. In particular View behaves as a pure function in which the same Model has the same output on the UI, without any side effects. As a result, when a bug occurs on the app, you can pinpoint it easier because data follows a “sequence” and the views are loosely coupled from the app data.</p><h3>Ok, but how can I reproduce history?</h3><p>Let’s say we have an app that does one thing: let’s you search GitHub users. The viewmodel for this simple app has 3 predefined states: <strong>Loading</strong>, <strong>Error</strong> and <strong>Success</strong>. Whenever user searches, we render the predictable state of Loading. If user found on GitHub, we render the Success state, otherwise something went wrong and we end up with Error state.</p><p>On the sample project, I use a cache that saves all these viewmodels and by using a slider, you can “time travel” over them.</p><p>So, we have the following <strong>View</strong>:</p><pre><strong>interface </strong>MainScreenView {<br>  <strong>fun </strong>searchIntent(): <strong>Observable</strong>&lt;<strong>String</strong>&gt;<br>  <strong>fun </strong>historyIntent(): <strong>Observable</strong>&lt;<strong>Int</strong>&gt;<br><br>  <strong>fun </strong>render(viewModel: <strong>MainScreenViewModel</strong>)<br>  <strong>fun </strong>renderFromHistory(viewModel: <strong>MainScreenViewModel</strong>)<br>}</pre><p>Nothing difficult here. The searchIntent() is the Observable stream that gives us emissions of the search terms. The historyIntent() is the Observable stream from the Seekbar’s progress, which “travels” us back to previous/next states.</p><p>Our <strong>Model</strong> is the following:</p><pre><strong>data class MainScreenViewModel</strong>(<br>    <strong>val </strong>searchTerm: <strong>String</strong>,<strong><br>    val </strong>showLoading: <strong>Boolean</strong>,<br>    <strong>val </strong>showFields: <strong>Boolean</strong>,<br>    <strong>val </strong>showError: <strong>Boolean</strong>,<br>    <strong>val </strong>gitHubUser: <strong>GitHubUser</strong>? = <strong>null</strong>,<br>    <strong>val </strong>errorMessage: <strong>String</strong>? = <strong>null<br></strong>) {<br><br>  <strong>val </strong>createdAt: <strong>Long </strong>= <strong>System</strong>.currentTimeMillis()<br><br>  <strong>companion object </strong>{<br>    <strong>fun </strong>inProgress(searchTerm: <strong>String</strong>): <strong>MainScreenViewModel </strong>=    MainScreenViewModel(searchTerm, <strong>true</strong>, <strong>false</strong>, <strong>false</strong>)</pre><pre><strong>    fun </strong>success(searchTerm: <strong>String</strong>, gitHubUser: <strong>GitHubUser</strong>) =    MainScreenViewModel(searchTerm, <strong>false</strong>, <strong>true</strong>, <strong>false</strong>, gitHubUser)</pre><pre><strong>    fun </strong>error(searchTerm: <strong>String</strong>): <strong>MainScreenViewModel </strong>= MainScreenViewModel(searchTerm, <strong>false</strong>, <strong>false</strong>, <strong>true</strong>, <strong>null</strong>,<br>    &quot;Houston we have a problem&quot;)<br>  }<br>}</pre><p>In our example, viewmodel is a data class because we want immutability! We actually don’t want someone else touching our state! The <strong><em>createdAt</em></strong> property exists in case we want to sort these viewmodels by time.</p><p>Finally, our <strong>Presenter</strong> is nothing special as well. I removed most of the lines, in order to focus on the most significant method: <strong><em>render()</em></strong>. Whenever the response is success, we map its result with the following factory method: <strong><em>success(it)</em></strong>. Whenever the response is failure (mostly 404 Http status code- user not found), we use the <strong><em>error()</em></strong> factory method. Before that we emit an item that the request is in flight, using the <strong><em>inProgress()</em></strong> factory method. We save its state on <strong><em>dispatchRender()</em></strong>. The method doOnNext() is actually very helpful for side effects like logging, so we log our render events. <em>Note: I could use the </em><a href="http://reactivex.io/documentation/operators/scan.html"><em>scan()</em></a><em> operator, but I wanted to keep it simple.</em></p><pre><strong>class MainScreenPresenter </strong>{<br><br>...<br><br>  <strong>fun </strong>bindIntents() {<br>    <strong>val </strong>searchIntent = viewRef.get()?.searchIntent()?.share() ?: <strong>Observable</strong>.empty()<br><br>    searchIntent<br>        .debounce(400, MILLISECONDS, <strong>AndroidSchedulers</strong>.mainThread())<br>        .doOnNext <strong>{ Log</strong>.d(&quot;Intent&quot;, &quot;Received Search Intent&quot;) <strong>}</strong><br>        .switchMap <strong>{<br>          </strong>gitHubApi.githubDAO<br>              .searchUser(<strong>it</strong>)<br>              .map <strong>{ MainScreenViewModel</strong>.success(<strong>it</strong>) <strong>}<br>              </strong>.onErrorReturn <strong>{ MainScreenViewModel</strong>.error() <strong>}<br>              </strong>.startWith(<strong>MainScreenViewModel</strong>.inProgress())<br>        <strong>}<br>        </strong>.doOnNext <strong>{ Log</strong>.d(&quot;Render&quot;, <strong>it</strong>.toString()) <strong>}<br>        </strong>.observeOn(<strong>AndroidSchedulers</strong>.mainThread())<br>        .subscribeWith(<strong>object </strong>: DisposableObserver&lt;<strong>MainScreenViewModel</strong>&gt;() {</pre><pre>          <strong>override fun </strong>onNext(viewModel: <strong>MainScreenViewModel</strong>) {<br>            dispatchRender(viewModel)<br>          }<br><br>          <strong>override fun </strong>onError(e: <strong>Throwable</strong>) {<br>            <strong>Log</strong>.wtf(&quot;ragment&quot;, e.message)<br>          }<br><br>          <strong>override fun </strong>onComplete() {<br>          }<br><br>        })<br>        .<em>addTo</em>(compositeDisposable)<br>  }</pre><pre><strong>private fun </strong>dispatchRender(viewModel: <strong>MainScreenViewModel</strong>) {<br>  <strong>ViewModelCache</strong>.append(viewModel)<br>  viewRef.get()?.render(viewModel)<br>}</pre><pre>...</pre><pre>}</pre><p>The View’s implementation is like this:</p><pre>progressbar.<em>showOrHideInvisible</em>(viewModel.showLoading)<br>userName.<em>showOrHideInvisible</em>(viewModel.showFields)<br>userLogin.<em>showOrHideInvisible</em>(viewModel.showFields)<br>gitHubUrl.<em>showOrHideInvisible</em>(viewModel.showFields)<br><br>userName.text = viewModel.gitHubUser?.name<br>userLogin.<em>text </em>= viewModel.gitHubUser?.login<br>gitHubUrl.<em>text </em>= viewModel.gitHubUser?.url<br><br><strong>if </strong>(viewModel.showError) {<br>  <strong>Toast</strong>.makeText(<strong>this</strong>, viewModel.errorMessage, <strong>Toast</strong>.<em>LENGTH_LONG</em>).show()<br>}</pre><p>Actually this is the only pain-point of this pattern. You somehow need to smartly and effectively invalidate Android’s views without worrying about how many layout passes our ViewGroup has executed. In an upcoming Medium post we will discuss on how to fix these issues.</p><p>Actually that’s all! You see? Nothing too hard. The result of the above looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*Ua7POUoUhSW7n4JuVWN38g.gif" /><figcaption>Time travel on Sample app</figcaption></figure><p>Debugging and testing with these reactive architectures seems to me very straightforward. By using Kotlin’s data classes or Google’s AutoValue or even your own custom implementation, you can <strong>compare</strong> these states and due to the fact that state must be immutable, you know that no one is going to change it! Also this is your single source of truth.</p><p>So, the only thing you have to emulate in unit tests are Intents. You can achieve this by mocking them with PublishSubjects. Now you can use those to “fake” user interactions and then just assert the output of your equivalent render method. Unidirectional data flow and pure functions help you a lot on this field.</p><p>As a bonus, you can have a stack of the last <strong><em>n</em></strong> rendered viewmodels. This is going to help you when reporting bugs e.g. on your Crashlytics, Bugsnag etc platform. It’s like a time travel. By feeding these last <strong><em>n</em></strong> viewmodels on the render() method you can see what led to your app crashing. That’s because you know the <strong><em>n-1</em></strong> viewmodel and what is really going on the screen. Do you remember the doOnNext method? You can always add more info on your Observable streams, for example an Intent for infinite scroll or pull to refresh.</p><p>In more complicated apps, you can make your app’s logic look very simple. By plug-and-playing with Observable streams and with all these various Rx operators, you have the ability to achieve the most extreme scenarios. That’s very convenient because you can almost see all of the edge cases that can happen and fix them before you release your app in production. Moreover, your data flow becomes explicit. That’s because you know the exact state your screen is currently in and how a user’s action will affect its current state.</p><p>Redux works somehow on the same style. Redux introduces Reducers, Actions, Dispatchers and Store. In a nutshell, Reducers work as pure functions from previous state to the new one, Actions are what a user has done(pretty much like our Intents), Dispatchers are like an event bus for all those Actions and Store manages the state and acts like an orchestrator. Finally, there are Middlewares which let you extend Store with some additional functionality, (e.g. like what we did on doOnNext() with logging)</p><p>You can find the sample GitHub project <a href="https://github.com/charbgr/ReproducibleHistory">here</a>.</p><p><em>Thanks to </em><a href="https://medium.com/u/d2295c5f4208"><em>Pavlos-Petros Tournaris</em></a><em>, </em><a href="https://medium.com/u/16a020408304"><em>Kostas Kremizas</em></a><em> and </em><a href="https://medium.com/u/4c26857274da"><em>Stratos Pavlakis</em></a><em> for providing me feedback for this article.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3b4a93d92236" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>