I’m writing a user management web service in Kotlin, and it’s forced me to consider more deeply how I approach my code - should I stick with old-school OO approaches to my data and behavior, or should I consider a more purely functional approach to my coding?
Let’s take an example: I have a User object, that among other things has a username, name, and password. Let’s say I want to change the password. In an OO language like Java, I’d have a method like this:
public void changePassword(String oldPassword, String newPassword) throws PasswordMismatchException, PasswordValidationException
If everything goes right, I change the password and return nothing. If I cannot change the password, I throw an exception (depending on whether the old password didn’t match, or the new password failed the validation rules). Note that there’s no getter or setter for password, it’s completely protected by the object - you can just send messages to change or authenticate.
In an FP language (like Clojure), I’d do this differently. I’d define a User data structure with all its fields, but there wouldn’t be a complicated constructor that tried to take only the publically-facing fields. Instead, I’d have some global functions that operated on this data structure in certain ways. Sure, I could conj in a different password if I wanted to, but really I should call the change-password method that does the validation, and returns a new copy of the immutable User data structure, with the new password on it. If I have a problem, maybe I throw a Java exception, or maybe I use an Either structure or a map to indicate a failure alongside the data structure.
Now, in Kotlin, I have choices. I could write Java-style OO code, with special constructors and visibility rules, or I could take a different approach and define my domain objects as immutable
data objects, and define some global functions to operate on them instead. I could use kategory/arrow to import some functional monads and generally write with a more functional approach.
I’m just curious what has worked for everyone else? I’m leaning in favor of using a more functional approach, and not fighting with specific setter visibility on each field, but I’m not totally sure that’s my best bet in a hybrid language like Kotlin.