On the 2nd of August, I promised to document my progress during these two months. Hereās a report of my past two weeks of learning and building in public.
In the last time, honestly, I didnāt have much desire to be active in this digital world of developers. Thatās because my higher education has started, and there are so many new connections out there that itās actually too much for me. š
However, I need to summarise what Iāve done to feel the progress towards the end goal and be motivated, purposive, and consistent. While I'm delighted to return to my comfort zone and savor this exceptional phase of my life, it's important that I remain engaged in all its facets.
About two weeks ago, I was struggling with balancing learning and building. Thatās because I wanted to build my program, and at the same time I didnāt know enough to actually start without messy code. Although I started in some aspects ā UI, business logic, and data storage, I couldnāt connect everything together.
However, a few days ago, I was so happy to discover that I actually know everything I need to build my program! Of course, my knowledge isnāt deep, but itās enough to create a base of a scalable program without messy code and following all the recommended best practices.
I donāt know whether itās because I developed that mindset for learning only the necessary concepts and leaving the rest for the time I actually need a certain thing or itās because I already knew much and just underestimated my progress, but in the first week of this period I learned all the remaining concepts I needed and discovered such pleasing truth. Seriously, look at the plan Iāve been following:
- Android basics
- Kotlin
- Jetpack Compose basics
- Advanced state, side effects, and Gradle
- Inline functions, testing, introduction to Coroutines and Flow āļø
- Databases and modularization
- Interaction with remote API
- Dependency injection
- Architecture (MVVM, MVI) and other stuff š
āļø ā where I was two weeks ago
š ā where I am now
Now the plan is to catch up on building my program, fill in the gaps in knowledge while working, and actually complete the challenge in the remaining time. (at least Iāll try).
Oh, and here's what I've learned:
Interaction with remote API
Nothing interesting in remote API itself actually. The basics are not difficult at all and I donāt need it for now. Contrary to what I expected, it didnāt help me better understand coroutines either.
However, it was a good introduction to Rest API. It also helped me a lot in understanding dependency injection.
Here is the course Iām speaking about.
Dependency injection (di)
I learned the basics of Hilt with the help of this amazing codelab. This helped me understand how di and di frameworks work overall. And itās not about learning Hilt because I actually donāt plan to use it in my app.
I don't really understand why people perceive dependency injection as a complex thing. For now, I see it just as a workaround in situations when I can't pass dependencies in constructors (a typical situation in Android). According to what I've seen in the codelab, manual di requires almost the same amount of code. So it currently looks simpler and safer to me.
I would appreciate it if someone explained to me what all the fuss is about.
Anyway, I probably just don't know something because experienced guys say di is very important. I was right about the manual di, though. It is indeed a great option because it eliminates the overhead created by di frameworks. But this is not an option for me because frameworks provide some template while doing it manually gives me so much freedom that I risk of creating a monster, riddled with bugs.
So I learned hilt and found out that I couldn't use it in my project right after that. š I can't use it because I aim to expand my project to iOS using Kotlin Multiplatform, but Hilt is a pure Android thing. So I'll use the second most popular di framework ā Koin.
Databases
When I first met the concept of databases, I found out that database programming is very limited compared to object-oriented programming. Lately, when I got back to this topic again, I found out that itās not difficult at all, and you donāt need to read a book or pass a crash course to correctly design database schemes.
The first tricky thing is database inheritance. There are three approaches here ā look at this answer on Stack Overflow. Due to limitations of the framework and other considerations, I picked the first one.
The second tricky thing is modeling relationships such as one-to-many and many-to-many. This is perfectly explained here.
When it comes to choosing the framework, Room is the obvious choice for Android. But this is once again a pure Android thing that doesnāt work with KMM, so I use SQLDelight instead.
Modularization
Checked the information about the recommended architecture of a project that consists of data, domain, and presentation layers. Also found out about CLEAN architecture from this example.
I didnāt dive into modularization itself though. Thatās because Iāll introduce it later when my project grows.
There need to be 3 main modules: app, feature, and core. For now, I decided to use packages instead of modules and have several sub-packages for data, domain, and presentation.
MVVM vs MVI
Finally, when it comes to a serious Android project, there are lots of considerations. One of them is whether to use mvvm or mvi. Other solutions are generally not an option because they are too legacy. I decided to use MVI because of its benefits. There are many drawbacks too, but we can work around them. One of the decisive factors is that itās more modern and Google recommends MVI for Jetpack Compose projects now. š
With XML, the situation is different because, AFAIK MVI isnāt good for performance there. It causes the whole UI to rerender each time something changes, which is not true about compose since its compiler is smart enough.
Thanks, Philipp for the great explanation.
There is another interesting thing, by the way. Although itās better for beginners to follow the recommended practices and decide on something only when they get some experience, one can essentially do everything they want and use their own solutions as long as everything works correctly, the code is readable and still follows the best practices.
For example, the matter of whether to use ViewModel
is questionable. I recently discovered that the main reason we use it is because it caches the data so that we donāt need to execute network requests when nothing changes. We also save resources by not fetching data when a configuration change occurs. There are other benefits of ViewModel
. Here is a great talk related to this topic.
However, there are alternative approaches to achieving that. For example, compose provides rememberSaveable for saving state across configuration changes and even across activity recreations.
So there are lots of ways for achieving the same thing and itās not necessary to use only recommended solutions. Getting more experience, Iām becoming more and more convinced in that.
Ending
I wrote this article for myself mainly. But if you read this far, thanks for being interested in me. š¤
If you're learning Android and struggling with some of these topics, you can DM me onĀ TwitterĀ or email me (daniel.rendox@gmail.com) and we'll figure it out together.