tim
03/18/2021, 4:51 PMAccountState
object in one micro service. Now for the various use cases that act on this state all have narrowed attributes of the state they're interested in. For example, Login only cares about Username and Password, whereas Change Profile Details cares about the Name and Address fields.
When I retrieve data from mongo, I'd like to use a projection to only return the fields needed in the running use case and then I'd like to de-serialise that projection into something where my use cases can access those values without being cluttered with every filed that on the complete state object. ie. i don't want to create a version of the state where every value is nullable / wrapped in an Option.
In typescript I would use something along these lines:
type State {
const id: string
const username: string
const password: string
const name: string
const address: string[]
}
type NarrowViewOfState = Pick<State, "name", "address">
But as kotlin doesn't offer the same type flexibility; has anyone had success here?tim
03/18/2021, 5:00 PMinterface NarrowedView<T>
type that any narrow viewed class should extend. Obviously this is a human/process control whereas I would prefer something that still offered type saftety and additionally it leads to a lot more boilerplate which would all need to be updated any time the interface change ... and the compiler won't catch errors 😞Nir
03/19/2021, 12:13 AMNir
03/19/2021, 12:14 AMinterface NarrowViewOfState { val name: String, val address: List<String>
Nir
03/19/2021, 12:15 AMclass State(override val name: String, override val address: List<String>)
etcNir
03/19/2021, 12:17 AMNir
03/19/2021, 12:18 AMtim
03/19/2021, 10:01 AMinterface NarrowViewOfState
has no linkage to interface CompleteState
... and so if a value were modified/added/removed from CompleteState
its unlikely to be caught until runtime which I'd like to avoid?
My colleague has put together a poc using reflection that allows us to do something like this:
interface State {
val a: String
val b: Int
}
interface Narrow<T>
class CompilesNarrowedState(
val a: String
) : Narrow<State>
class FailsToCompileBecauseUnknownPropertyNarrowState(
val bad: String
) : Narrow<State>
If we can get this working more completely I think it'll achieve the effect we're after 🤞
I guess the bit that isn't great with this solution is we won't get feedback until compile time ... something about cake and eating it 🥮 🤔Nir
03/19/2021, 2:10 PMNir
03/19/2021, 2:10 PMNir
03/19/2021, 2:11 PMNir
03/19/2021, 2:11 PMNir
03/19/2021, 2:12 PMNir
03/19/2021, 2:12 PMNir
03/19/2021, 2:14 PMNir
03/19/2021, 2:14 PMNir
03/19/2021, 2:14 PMtim
03/19/2021, 2:16 PMNir
03/19/2021, 2:27 PMtim
03/19/2021, 2:29 PM// Repo 1 shared code between all services
package example.common.kernel
interface State {
val a: String
val b: String
}
interface Narrow<T>
// Repo 2 for a specified service that operates on one part of state
package example.a
import example.commons.kernel.State
import example.commons.kernel.NarrowView
data class(val a: String): NarrowView<State>
// Repo 3 for another service that operates on a different part of state
package example.b
import example.commons.kernel.State
import example.commons.kernel.NarrowView
data class(val b: String): NarrowView<State>
Within Service A and Service B each would then have its own projection to only include the fields from that state object when touching the database. I should point out this is for reads no writes and I'm conscious that we've got some issues with shared state between services 🙂tim
03/19/2021, 2:30 PMtim
03/19/2021, 3:03 PM