Things that I've learned doing a coding challenge in Kotlin (Android)
Tags: android, mobile, programming, kotlin
Published: 2023-11-06 14:45:11

In the past days, I taked a coding challenge, that, in summary, required making a Tic Tac Toe game.

The requirements involves, optionally, target mobile platforms, using Kotlin, Swift or Flutter, but it can be maded using a minimal TUI.

My main language is Java, most of my projects and my study targets Java, and profissionally I worked most with React and Typescript. The logical choice here could be going for TUI with Java or Typescript, but I opt in target mobile platform, and learn Jetpack Compose and Android Development in the proccess.

Here is what I've learned:

## The Programming Model

The modern Android development uses Jetpack Compose library for developing UI's. How is it?

It's mainly similar to React model of making UI. 

The main artifact that you produce to compose a UI is a Composable. Composables are functions marked with `@Composable` annotation, that can return an `Unit` (that's somewhat similar to void) or can return some value, but the majority of composables returns just `Unit`.

But how is it similar to React if React return objects (behind JSX)?

The DSL is really clear in this aspect. Composables are functions that paint the UI, where you use composition, crafting the UI with other Composables.

Here's an example of a dummy Composable:

 ```kotlin
@Composable
fun FormSection(
    @StringRes title: Int,
    modifier: Modifier = Modifier,
    children: @Composable (() -> Unit) = {},
) {
    Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
        Text(
            text = stringResource(title),
            fontWeight = FontWeight.Bold,
            fontSize = TextUnit(20.0F, TextUnitType.Sp),
            textAlign = TextAlign.Center
        )
        Spacer(modifier = Modifier.height(5.dp))
        children()
    }
}
```

This composable is dummy because it don't holds any state or effect in it. Here, it accepts another function, similar to the `children` declared in React to accept another composable.

## "Hooks"

In Jetpack Compose, we don't have any type of hooks, but we have constructs that acts similarly to hooks.

Explicitly, the programming model is builded around observables. Observables are based on the Observer pattern, were we have a set of subscribers, that consists of callbacks. When the Observable receives some update (or some value), it gonna notify every subscriber, by invoking the stored callbacks.

The Jetpack Compose's useState behaves exactly like that. We use delegation to `remember` function, and the callback function it receives returns a `mutableStateOf<T>`.

```kotlin
var someState by remember { mutableStateOf(0) }
```

But, an important thing to see here is that, the main subscriber of this observer is the Composable. When the observer receives some value, the Composable is invoked again  in a process called **recomposition**. Just like React's **reconciliation**.

Another interesting thing are `LaunchedEffect`s. They are really the `useEffect` of Jetpack Compose. They are really fit to run some asynchronous rotine, like a Coroutine Timeout to close some type of dialog:

```kotlin
LaunchedEffect(key1 = "Popup") {
  // this is a suspend function call 
  viewModel.makeRobotPlay()
}
```

The best part of this is, unlike React, `LaunchedEffect`s can run in any part of Composable lifecycle. So we can wrap this in some conditional to run only in a certain condition:

```kotlin
 if (openRobotPlayingTime) {
   LaunchedEffect(key1 = "Popup") {
     viewModel.makeRobotPlay()
   }
   AlertDialog(
     onDismissRequest = { /*TODO*/ }, 
     confirmButton = { /*TODO*/ }, 
     text = {
       Column(
         verticalArrangement = Arrangement.spacedBy(10.dp)
       ) {
         Text(
           text = stringResource(R.string.robot_time_playing_popup_title),
           style = MaterialTheme.typography.titleLarge
         )
         Text(
           text = stringResource(R.string.robot_time_playing_popup_content))
      }
   })
}
```
Every composable here can be invoked in any order.

## Coroutines

Coroutines are core part of Kotlin programming, so here it haves a central utility. 

Normally you can use coroutines for every async need, but remember that coroutines are colored functions (just like Promises). So, remember that coroutine only runs in:

* A `CoroutineScope` launch callback
* A LaunchedEffect
* Another suspend function

To tackle this in a functional and synchronous programming model, Jetpack Compose give us Reactive Programming based upon observables.
I learned the hard way that some observables should not be used on some type of coroutine scope (generally associated on data persistence). 
These observables can be used to manage state accross application.

## View Model

The view model is where we centralize the application state to manage more complex states in simple data objects. Then, we gonna wrap these objects in `StateFlow` and make progressive updates on these objects. Every function and composable listening on the `StateFlow` gonna be notified and updated.

Is really that simple on three steps:

1. Create a data class that will represent the state of application

```kotlin
data class GameState(
    val player1Name: String? = null,
    val player2Name: String? = null,
    val isRobotEnabled: Boolean = false,
    val tableSize: Int = 3,
    val gameTable: Array<Array<CellStates>>? = null,
    val playerTime: PlayerTime = PlayerTime.Player1,
    val winner: Winner = Winner.NoWinner
)
```

2. Create your view model, based on this data class. The object should be wrapped on a `StateFlow` observable and should be exposed with `.asStateFlow()` function.

```kotlin
class GlobalStateViewModel(db: AppDatabase) : ViewModel() {
    private val _uiState = MutableStateFlow(GameState())
    val uiState = _uiState.asStateFlow()
}
```

3. Subscribe to the view model in Composable using delegation:

```kotlin
@Composable
fun GameScreen(
    viewModel: GlobalStateViewModel, modifier: Modifier = Modifier,
    onNewGame: () -> Unit
) {
    val globalUiState by viewModel.uiState.collectAsState()
}
```

To update the data on this viewModel, just call the method update on the `_uiState`. The update should be exposed through a viewModel method:

```kotlin
fun makeUpdate{
  _uiState.update {
    it.copy(
     // update the components of the data class here
    )  
  }
}
```

## Data Access

Data access can be maded with Room Library.
I describe this library as Spring Data without steroids.
We use annotated classes and interfaces to model the data access and data entities of app persistence level.

```kotlin
@Entity 
data class User(@PrimaryKey(autoGenerated = true) val id: Long?, @ColumnInfo(name="name) val name: String?)

@Dao 
interface UserDao {
  @Insert 
  fun create(user: User): Long?
}
```

Finally, we then define our database with an abstract class that gonna expose the creation of our Dao.

```kotlin
@Database(version = 1, entities=[User::class])
abstract class AppDatabase :  RoomDatabase() {
  abstract fun userDao(): UserDao
}
```

And that's it. 
Just instantiate the database in your code and you are ready to use it.

```kotlin
 val db = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java, "tic-tac-toe"
).build()
```

Initially, when using database, I go through some crashes. It's because the database cannot be accessed on the main thread, to prevent blockings on the UI.

Behind the scenes, Room is just a wrapper around SQLite. So it's just a file, and the interaction with the file is maded with some C functions.

How to access the database without blocking the UI?
You can use a corroutine with `Dispatchers.IO` dispatcher, like that:

```kotlin
viewModelScope.launch(Dispatchers.IO) {
  dao.create(user)
}
```

I find that a good way to abstract this is using in viewModel.

## Conclusion

That was a good experience, and I learned a lot of things!

The final code for this challenge is here:

https://github.com/EronAlves1996/TicTacToe

pt-BR version: https://github.com/EronAlves1996/artigos-ptbr/blob/main/Coisas-que-aprendi-fazendo-um-desafio-de-codigo-em-kotlin-(android).md