Blog Infos
Author
Published
Topics
, , , ,
Published

Photo by Towfiqu barbhuiya on Unsplash

Encapsulation is one of the first concepts we learn in programming, but sometimes it turns into ritual instead of necessity. Why confusing what’s technically possible with what’s realistically a threat ?

Let’s take the common claim that you must always call .asStateFlow() to protect your state in your app.

private val _uiState = MutableStateFlow(UiState())
val uiState = _uiState.asStateFlow()

.asStateFlow() returns a read only StateFlow by wrapping the value in a ReadonlyStateFlow so consumers of the flow cannot cast back to MutableStateFlow and change the values.

I agree, it is simpler than explicitly typing a property as StateFlow<T>. No problem there.

You can also do :

private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState

But some insist you still need to call .asStateFlow() even when the property is already typed as StateFlow<T>, because “someone could cast it back to MutableStateFlow and modify it.”

That’s technically true, but it doesn’t make much sense. Casting back is a deliberate, extra step. If someone on your team goes that far, either fire them or teach them how to code.

It’s like writing a setter that just assigns a value and a getter that just returns it no logic, no validation, just boilerplate for the sake of ceremony.

class A {
    private var b: B

    fun setB(b: B) {
        this.b = b
    }

    fun getB(): B {
        return this.b
    }
}

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Kotlin Coroutine Mechanisms: A Surprisingly Deep Rabbithole

Sometimes you think you know coroutines, and then after a while, you’re like, “Wait, do I really know coroutines?”
Watch Video

Kotlin Coroutine Mechanisms: A Surprisingly Deep Rabbithole

Amanda Hinchman-Dominguez
Senior Android Developer
SpotOn

Kotlin Coroutine Mechanisms: A Surprisingly Deep Rabbithole

Amanda Hinchman-Do ...
Senior Android Devel ...
SpotOn

Kotlin Coroutine Mechanisms: A Surprisingly Deep Rabbithole

Amanda Hinchman- ...
Senior Android Developer
SpotOn

Jobs

That’s not engineering, that’s dogma. (Looking at you, Java-style OOP.)

Encapsulation is useful when it adds value: validation, invariants, side effects, meaningful contracts. But adding layers just to stop someone from intentionally breaking your design is like putting a lock on a drawer that everyone already has the key. We can use reflection to bypass your encapsulation.

Like Python devs say, we’re all adults here.

At the end of the day, .asStateFlow() isn’t the enemy, nor is it a silver bullet. It’s a tool. In a public SDK, it makes perfect sense to lock things down because you can’t control the consumers. In an internal codebase, the threat model is different.

When we start adding layers “just in case” someone takes deliberate steps to bypass our design, we’re no longer writing protective code, we’re writing ceremonial code.

Write clear contracts for your team, and reserve extra locks for when they solve real problems. Everything else is noise.

This article was previously published on proandroiddev.com

Menu