How to keep use cases and entity layer in Functional Clean Architecture pure when having database read/write interactions? - kotlin

Intro
I've been diving into functional programming in the last few months, and since I'm really intrigued by the Kotlin language, I've been using the Arrow library to toy around with a few things.
A few weeks ago, I've been researching for a guest lecture at university on Clean Architecture and while doing so, I stumbled upon this great blog Post by Mark Seemann, describing how using functional programming automatically leads to Clean Architecture (or with a language like Haskell may the compiler may even enforce Clean Architecture).
That inspired me to come up with a draft (checkout and build of the repo should be a breeze, if you're interested) of a restaurant reservation Software (staying true to Mark Seemann's domain ;) ). However, I'm not entirely sure if the use case layer in this draft can be called pure, and I wanted some feedback from people with more experience and knowledge with FP than myself.
Entity layer
A basic use case is trying to create a new reservation for a certain number of seats in our restaurant. I've modelled the entity layer for that the following way:
fun reservationPossible(
requestedSeats: Int,
reservedSeats: Int,
capacity: Int
): Either<RequestedTooManySeats, ReservationPossible> =
if (reservedSeats + requestedSeats <= capacity) {
ReservationPossible(requestedSeats + reservedSeats).right()
} else {
RequestedTooManySeats.left()
}
const val CAPACITY = 10
object RequestedTooManySeats : Error()
sealed class Error
data class ReservationPossible(val newNumberOfReservedSeats: Int)
Nothing too fancy going on here, just a function checking if a reservation with a certain number of requested seats would be possible or not. Some Error and Result classes are also down below as well as a (for the sake of simplicity) const val to model the capacity of our restaurant.
Frameworks/Adapters #1
To make sense in a real world application, some data would also need to be stored in and loaded from some sort of persistence layer. So, in the outermost layer of our onion architecture, there would be a Database which I mocked for this example:
suspend fun getCurrentlyReservedSeats(): Either<ReadError, Int> {
delay(1) // ... get stuff from db
return 4.right()
}
suspend fun saveReservation(value: String, reservationPossible: ReservationPossible): Either<WriteError, Long> {
delay(1) // ... writing something to db
return 42L.right() // newRecordId
}
abstract class DbError : Error()
object ReadError : DbError()
object WriteError : DbError()
Again, not too much going on here... Just stubs for Database read/write ops. Note however, that (by convention proposed by Arrow) these functions are marked with the suspend modifier as impure functions.
Use Case
So now for the use case, which basically describes our application flow:
get number of currently reserved seats from DB
check if the requested number of seats is still available
if so, persist the new reservation
and return the newly created reservation id
which is translated to code in the reservationUseCase function:
data class UseCaseData(
val requestedSeats: Int,
val reservationName: String,
val getCurrentlyReservedSeats: suspend () -> Either<ReadError, Int>,
val writeVal: suspend (String, ReservationPossible) -> Either<WriteError, Long>,
)
fun reservationUseCase(data: UseCaseData): suspend () -> Either<Error, UseCaseResultData> = {
data.getCurrentlyReservedSeats()
.flatMap { reservationPossible(data.requestedSeats, it, CAPACITY) }
.flatMap { data.writeVal(data.reservationName, it) }
.flatMap { UseCaseResultData(it).right() }
}
data class UseCaseResultData(val newRecordId: Long)
Here is the point, where it gets interesting: This function takes some UseCaseData as input and returns a suspend function to be executed at the program entry like this:
suspend fun main() {
reservationUseCase(
UseCaseData(
requestedSeats = 5,
reservationName = "John Dorian",
::getCurrentlyReservedSeats,
::saveReservation,
)
).invoke().fold(
ifLeft = { throw Exception(it.toString()) },
ifRight = { println(it.newRecordId) },
)
}
So now my questions are:
Can the reservationUseCase function itself be considered pure? I've read some blog post (taking F# as example language, however) suggesting that pure functions which receive impure functions as parameters could be pure, but cannot be guaranteed to be pure. reservationUseCase in this example clearly does receive impure functions with the UseCaseData.
If it can't be considered pure, how could one write a pure use case like the one described above in Kotlin and Arrow?

As you already assume, strictly speaking, reservationUseCase is not a pure function.
The only way I see how you could make it a pure function is to pass all the needed data directly instead of a function which provides access to that data but I doubt that this makes your code finally more clean or nicer to read.
This would lead to the conclusion that use case functions which orchestrate "workflows" can rarely be pure as almost always some interaction with some kind of repository is needed.
If you want some core logic to be pure you would have to extract those into functions which again only accept and return pure data.

Related

implement a monad comprehension on a list in kotlin using a coroutine

I wonder if it is possible to implement something similar to the do-notation of Haskell in Kotlin on Lists or List-Like structures with monadic properties.
Take following example:
fun <A, B> cartesianProduct(xs: List<A>, ys: List<B>): List<Pair<A, B>> =
xs.flatMap { x -> ys.flatMap { y -> listOf(x to y) } }
It would be nice if I could write something like
suspend fun <A, B> cartesianProduct(xs: List<A>, ys: List<B>): List<Pair<A, B>> =
list {
val x = xs.bind()
val y = xs.bind()
yield(x to y)
}
Arrow-Kt defines similar comprehensions using coroutines for either, nullable, option and eval. I looked at the implementation and also its Effect documentation, but I have trouble to translate the concept to Lists. Is this even possible in kotlin?
It's not possible at the moment to implement monad comprehension for List, Flow, and other non-deterministic data structures that emit more than one value. The current implementation of continuations in Kotlin is single shot only. This means a continuation can resume a program with a single emitted value. Resuming the program more than once requires hijacking the continuation stack labels with reflection in order to replay their state in the second resumption. Additionally replaying a block in which a multishot data type is binding would replay all effects previous to the bind since the block has to emit again.
list {
println("printed 3 times and not cool")
val a = listOf(1, 2, 3).bind()
a
}
The arrow-continuations library already includes a MultiShot delimited scope for reset/shift but it's currently internal since is not safe until Kotlin suspension or continuations provide the ability to multishot without replaying the current block. Alternatively we would need real for comprehensions or a similar structure to enforce binds happen before other code which would also solve the block replaying issue.
The Effect interface ultimately delegates to one of these scopes for its implementation. The current versions of Reset.suspended and Reset.restricted are single shot.

Create an object of random class in kotlin

I learned java and python in high school and I became very comfortable with python. I have recently started to learn kotlin, mainly for fun (the keyword for defining a function is fun so it has to be a fun language, right), but I have a little problem.
Let's suppose I have a hierarchy of classes for Chess pieces:
abstract class Piece {
...
}
class Rook : Piece() {
...
}
class Bishop : Piece() {
...
}
.
.
.
I am taking input from the user to generate the board, so if the user types r, I need to create a Rook object, if he types b, I need to create a Bishop etc.
In python, I'd probably use a dictionary that maps the input string to the corresponding class, so I can create an object of the correct type:
class Piece:
...
class Rook(Piece):
...
class Bishop(Piece):
...
.
.
.
input_map = {
'r': Rook,
'b': Bishop,
...
}
s = input_map[input()]() # use user input as key and create a piece of the correct type
I was really amazed by this pattern when I discovered it. In java, I had to use a switch case or a bunch of if else if to achieve the same result, which is not the end of the world, especially if I abstract it into a separate function, but it's not as nice as the python approach.
I want to do the same thing in kotlin, and I was wondering if there is a similar pattern for kotlin since it's a modern language like python (I know, I know, python isn't new, but I think it's very modern). I tried to look online, but it seems like I can't store a class (class, not an object) in a variable or a map like I can in python.
Am I wrong about it? Can I use a similar pattern in kotlin or do I have to fall back to the when statement (or expression)?
If I am not mistaken, a similar pattern could be achieved in java using reflection. I never got to learn reflection in java deeply, but I know it's a way to use classes dynamically, what I can do for free in python. I also heard that in java, reflection should be used as a last resort because it's inefficient and it's considered "black magic" if you understand my meaning. Does it mean that I need to use reflection to achieve that result in kotlin? And if so, is it recommended to use reflection in kotlin, and is it efficient?
I'd like to know how I can approach this problem, and I accept multiple answers and additional solutions I didn't come up with. Thanks in advance.
This can be done without reflection.
You can map the input characters to the constructors:
val pieceConstructorsByKeyChar = mapOf(
'r' to ::Rook,
'b' to ::Bishop,
// etc.
)
Getting values from a map gives you a nullable, since it's possible the key you supply isn't in the map. Maybe this is fine, if when you use this you might be passing a character the player typed that might not be supported. Then you would probably handle null by telling the player to try again:
val piece: Piece? = pieceConstructorsByKeyChar[keyPressed]?.invoke()
Or if you do the look-up after you've already checked that it's a valid key-stroke, you can use !! safely:
val piece: Piece = pieceConstructorsByKeyChar[keyPressed]!!()
Yes you can use similiar approach with Kotlin. Kotlin has many features and supports reflection. Let me write an example about your problem.
Firstly create your classes that will be generate by user input.
abstract class Piece
class Rook : Piece()
class Bishop : Piece()
Create your class map
val inputMap = mapOf(
"r" to Rook::class.java,
"b" to Bishop::class.java
)
Create an instance what you want using newInstance function. If your input map doesn't contains key you gave then it will return null.
val rook = inputMap["r"]?.newInstance()
val bishop = inputMap["b"]?.newInstance()
// null
val king = inputMap["k"]?.newInstance()
Also you can write your custom extensions to create new objects.
fun <T> Map<String, Class<out T>>.newInstance(key: String) = this[key]?.newInstance()
// Create an instance with extension function
inputMap.newInstance("r")

design pattern to express that "container" over derived class is derived from container of a base class

I have a class Track which holds a set of Points and represent person location in time. In order to get this result I run an iterative optimization routine combining different data. In order to do it I extend Point with a class OptimizedPoint which holds data for optimization for this point and current value. I also introduce OptimizedTrack which is a collection of OptimizedPoints and additional data needed for optimization associated with the whole track.
I run an optimization on OptimizedTrack and at the last iteration, I return to the user clean data (Track) which only has the result and doesn't have additional data. However, I can not find a way to express with OOP that OptimizedTrack is somehow an extension of the Track and introduce common routines for them. F.e getting a length of the track which should be available for both of them as it only uses data which can be found both in OptimizedTrack and Track
Right now I have such architecture Point{x, y, z}, OptimizedPoint extends Point {additional_data}. Track {array<Point>}, OptimizedTrack {array<OptimizedPoint>, additional_data}. I don't understand how to express that OptimizedTrack is an extension of Track as I can not express array<OptimizedPoint> extens array<Point>. So I can not introduce a common routine length which can be calculated for array and therefore also from array.
I do not insist on my current architecture. It's most probably wrong, I only write it here to express the problem I am facing. How would you propose to refactor my architecture in this case?
I believe that the basic premise of what you are trying to do is faulty if you are following what is considered to be proper use of inheritance to express subtyping relationships.
Inheritance can be used for various purposes and I am not wishing to pontificate upon the subject, but the opinion of most authorities is that inheritance is best and most safely used when used for subtyping. In short, an instance of a subclass should be able to be substituted for an instance of its base class without "breaking" the program (see: Liskov Substitution Principle).
Let us assume that OptimizedPoint is a subtype of Point. Then all the methods defined in class Point when invoked on an instance of OptimizedPoint will continue to function as expected. That means that OptimizedPoint cannot require any more stringent preconditions on any of these method invocations nor can it weaken any of the promissed postconditions that the contract Point has made.
But it is a common fallacy that just becuase OptimizedPoint is a subtype of Point that a container of OptimizedPoint, i.e. OptimizedTrack, is a subtype of a container of Point, i.e Track. This is because you cannot substitute an instance of OptimizedTrack for an instance of Track (due to your not being able to add an instance of Point to an instance of OptimizedTrack).
So, if you are trying to follow "good object-oriented design principles", it is disastrous trying to somehow make OptimizedTrack a subclass of Track, because it can certainly never be a subtype. You can, of course, reuse Track to build OptimizedTrack using composition, i.e. OptimizedTrack would contain within an instance of Track to which methods such as length would be delegated.
I'm not sure why you want to return a Track to your client code after the optimisation process, considering that OptimizedTrack is a Track itself. Below is a quick example of what I think you're trying to achieve (written in Kotlin because is less verbose).
You can achieve a lot more flexibility and solve the type issue if you consider Track to be an iterable object of points of type Point. This way, when you extend OptTrack from Track, you will be able to:
Substitute Track and OptTrack with no problem (even if your optimised track object has not computed a simplified Track object).
Simplify through optimize and return a Track from OptTrack with no issues (the optimize function on Point is irrelevant, you can return an OptPoint inside your Track because it extends the object Point)
open class Point(val x: Int, val y: Int, val z: Int) {
override fun toString(): String =
"Point(${this.x}, ${this.y}, ${this.z})"
}
data class OptPoint(val point: Point, val additional: Int):
Point(point.x, point.y, point.z) {
override fun toString(): String =
"OptPoint(${this.point}, ${this.additional})"
fun optimize(): Point {
return Point(this.x, this.y, this.z)
}
}
open class Track(private val points: Iterable<Point>): Iterable<Point> {
override operator fun iterator(): Iterator<Point> {
return this.points.iterator()
}
override fun toString(): String =
"Track(${this.points})"
}
data class OptTrack(private val points: Iterable<OptPoint>): Track(listOf()) {
override operator fun iterator(): Iterator<Point> {
return this.points.iterator()
}
fun optimize(): Track {
return Track(this.points.map{ it.optimize() })
}
}
fun main(args: Array<String>) {
val track: Track = OptTrack(listOf(
OptPoint(Point(1, 2, 3), 4))).optimize()
println(track)
// Track([Point(1, 2, 3)])
val other: Track = OptTrack(listOf(OptPoint(Point(1, 2, 3), 4)))
println(other)
// OptTrack(points=[OptPoint(Point(1, 2, 3), 4)])
}
In OOP you should prefer object composition to object inheritance. In your problem, I think creating interfaces for point and track could help. In order to achieve the proper result, I think, you should create two interfaces, IPoint & ITrack. Both Track and OptimizedTrack implement the ITrack interface and for common operations, you could create another class that both classes delegate the requests to it. After that you could create an strategy class, taking in an ITrack and returns another optimized ITrack. In the ITrack you could create GetPath which returns a list of objects of type IPoint.

Kotlin benifits of writing helper/util methods without wrapping in class

There are can be two ways of writing helper method in Kotlin
First is
object Helper {
fun doSomething(a: Any, b: Any): Any {
// Do some businesss logic and return result
}
}
Or simply writing this
fun doSomething(a: Any, b: Any): Any {
// Do some businesss logic and return result
}
inside a Helper.kt class.
So my question is in terms of performance and maintainability which is better and why?
In general, your first choice should be top-level functions. If a function has a clear "primary" argument, you can make it even more idiomatic by extracting it as the receiver of an extension function.
The object is nothing more than a holder of the namespace of its member functions. If you find that you have several groups of functions that you want to categorize, you can create several objects for them so you can qualify the calls with the object's name. There's little beyond this going in their favor in this role.
object as a language feature makes a lot more sense when it implements a well-known interface.
There's a third and arguably more idiomatic way: extension functions.
fun Int.add(b: Int): Int = this + b
And to use it:
val x = 1
val y = x.add(3) // 4
val z = 1.add(3) // 4
In terms of maintainability, I find extension functions just as easy to maintain as top-level functions or helper classes. I'm not a big fan of helper classes because they end up acquiring a lot of cruft over time (things people swear we'll reuse but never do, oddball variants of what we already have for special use cases, etc).
In terms of performance, these are all going to resolve more or less the same way - statically. The Kotlin compiler is effectively going to compile all of these down to the same java code - a class with a static method.

Why does the expert change MutableList to List?

I asked a question at How to design a complex class which incude some classes to make expansion easily in future in Kotlin? about how to design a complex class which incude some classes to make expansion easily in future in Kotlin.
A expert named s1m0nw1 give me a great answer as the following code.
But I don't know why he want to change MutableList to List at https://stackoverflow.com/posts/47960036/revisions , I can get the correct result when I use MutableList. Could you tell me?
The code
interface DeviceDef
data class BluetoothDef(val Status: Boolean = false) : DeviceDef
data class WiFiDef(val Name: String, val Status: Boolean = false) : DeviceDef
data class ScreenDef(val Name: String, val size: Long) : DeviceDef
class MDetail(val _id: Long, val devices: List<DeviceDef>) {
inline fun <reified T> getDevice(): T {
return devices.filterIsInstance(T::class.java).first()
}
}
Added
I think that mutableListOf<DeviceDef> is better than ListOf<DeviceDef> in order to extend in future.
I can use aMutableList.add() function to extend when I append new element of mutableListOf<DeviceDef>.
If I use ListOf<DeviceDef>, I have to construct it with listOf(mBluetoothDef1, mWiFiDef1, //mOther), it's not good. Right?
var aMutableList= mutableListOf<DeviceDef>()
var mBluetoothDef1= BluetoothDef(true)
var mWiFiDef1= WiFiHelper(this).getWiFiDefFromSystem()
aMutableList.add(mBluetoothDef1)
aMutableList.add(mWiFiDef1)
// aMutableList.add(mOther) //This is extension
var aMDetail1= MDetail(myID, aMutableList)
Sorry for not giving an explanation in the first place. The differences are explained in the docs.:
Unlike many languages, Kotlin distinguishes between mutable and immutable collections (lists, sets, maps, etc). Precise control over exactly when collections can be edited is useful for eliminating bugs, and for designing good APIs.
It is important to understand up front the difference between a read-only view of a mutable collection, and an actually immutable collection. Both are easy to create, but the type system doesn't express the difference, so keeping track of that (if it's relevant) is up to you.
The Kotlin List<out T> type is an interface that provides read-only operations like size, get and so on. Like in Java, it inherits from Collection<T> and that in turn inherits from Iterable<T>. Methods that change the list are added by the MutableList<T> interface. [...]
The List interface provides a read-only view so that you cannot e.g add new elements to the list which has many advantages for instance in multithreaded environments. There may be situations in which you will use MutableList instead.
I also recommend the following discussion:
Kotlin and Immutable Collections?
EDIT (added content):
You can do this is a one-liner without any add invocation:
val list = listOf(mBluetoothDef1, mWiFiDef1)