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.
Top comments (2)
Hey, Daniel, sounds like you've made the most of your time! I recently transitioned from having all day for iOS learning to stealing a few minutes here and there while I teach full-time. It's a bit of a shock to the system. Good luck, and I hope you're able to complete your challenge. I'm sure you will!
Haha, I actually switched from full productivity mode to part-time working, part-time fun having, and also learning things I was forced to learn. My progress was definitely not caused by productivity improvements. 😁
Thanks for your kind words, Monty!