Should I write toJson or fromJson method in Kotlin data class? - kotlin

It's mentioned that a Kotlin data class is for storing data. It's equivalent to the data structure. As such, it shouldn't have any behaviour method. In clean code, implementing behaviour method in a data class would violate many principles namely, SRP, OCP, ...
I was wondering if the fromJson and toJson methods are considered as behaviour method. If it is, then where should I implement those methods in my code?
I'm using Kotlin data class to store User, Product, etc. In my supposedly clean architecture and clean code that I am learning, I restricted those data class to a corner for storing only domain data.
I tried to find information about this but I can't seem to find anyone talking about data class and these methods.
Here's the code I've imagined. It should be something like this.
data class User(val id: String, val name: String) {
fun toJson(): Json {}
fun fromJson(json: Json): User {}
}
Or should I have other class responsible for toJson and fromJson implementation?

As you have tagged your query with clean architecture I assume you refer to https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html.
From this perspective a "domain entity" should be independent from any kind of serialization format, persistence aspects or other specific "technology" or "framework".
A common pattern to handle "persistence ignorance" for domain objects is the repository pattern. An important aspect here to keep in mind in context of clean architecture is that the interface of the repository is defined in the "use case layer" (business logic) while the implementation is in the "gateway layer" or even "framework layer".

Related

Kotlin override method for different subclasses without code duplication

I have the following class hierarchy (minecraft modding with fabric):
SwordItem, AxeItem extend ToolItem
ModSwordItem extends SwordItem, ModAxeItem extends AxeItem,
where ModSwordItem and ModAxeItem are my own classes with some custom logic (SwordItem, AxeItem and ToolItem are existing classes. And there also are classes for pickaxe, shovel and hoe).
Now I want to implement some custom logic for my own modded classes (I want to override the inventoryTick method), but I don't want to implement the logic "manually" in both ModSwordItem and ModAxeItem, because of code duplication. I already extracted the logic to an external function, but I still have to manually write the whole override statement and method call to the logic, like this:
open class ModSwordItem(...): SwordItem(...) {
override fun inventoryTick(...): Unit {
customLogic(...)
super.inventoryTick(...)
}
}
Of course, that doesn't seem like a lot of code at first glance, but because there are 5 subclasses (sword, axe, pickaxe, hoe and shovel) it really is a lot of unnecessary code duplication. Plus I want to implement different subclasses with different logic. So each time I do that, I have to write the same code 5 times.
My question: Is there any way to tell Kotlin to automatically override the same method for the given 5 subclasses? I already thought about using mixins, but that seems like a weird workaround.
Here's a possible solution by composition. It may not fit perfectly with how you're using these classes, but could give you an idea of how you could refactor it.
I have zero experience with Minecraft, so I don't know which classes are yours and which are provided by the framework such that you can't modify them. Assuming ToolItem is a Minecraft abstract class that you can't change, you could define your own intermediate abstract class that uses composition for this behavior like this:
fun interface InventoryTickBehavior {
fun inventoryTick(toolItem: ComposedToolItem, /*...*/)
}
abstract class ComposedToolItem(
private val inventoryTickBehavior: InventoryTickBehavior = { _, /*...*/ -> }
) {
override fun inventoryTick(/*...*/): Unit {
inventoryTickBehavior(this, /*...*/)
}
}
Then you can create a class or singleton object that implements the interface and has your common behavior, and use it in multiple subclasses of ComposedToolItem.
Or, if you want, you could create Behavior interfaces for all the different ToolItem functions you might want to override. Then your ComposedToolItem class doesn't even need to be abstract. You might not need to subclass it at all, and just build your ToolItems out of instances of ComposedToolItem with various different behaviors attached. However, this depends on how Minecraft uses the class. If generics are involved, it might not be usable in the case.
This could get more complicated if you have behaviors for multiple different things in the class and they need to talk to each other. Game engines that rely heavily on composition (such as Unity) use a design strategy called Entity Control System, where the behaviors can talk to each other by passing String messages up to parent objects, which can then delegate the message back down to children. The attached behaviors just listen for messages they're interested in. But this is likely way too complicated to retrofit into Minecraft just for a mod.

What are the benefits of abstract classes?

i have researched the topic of abstract classes. And I am not sure, if I understand the sense of this construct.
Is it right, that abstract classes are only control structures in OOP, respectively that I don't forget to implement a method in a sub class? I see no other benefits. I know that abstract classes never become an object. So, what the sense / benefits of abstract classes, abstract methods etc.?
Thanks for help.
Is it right, that abstract classes are only control structures in OOP, respectively that I don't forget to implement a method in a sub class?
This is actually the responsibility of interfaces.
Abstract classes are for sharing the code, the logic or behavior between multiple subclasses. And because the behavior provided by the base class may require that some missing parts of the logic are provided by subclasses, we can declare a base class as abstract and declare abstract members in it - similarly to interfaces. "abstract" in this context basically means that the functionality is incomplete and can't be used straight away, without filling the gaps.
In practice, sharing of the code through subtyping is generally discouraged and therefore abstract classes are less popular nowadays than in the past. We learnt that it is usually better and easier to maintain if we share the code by composition of multiple separate classes than by subclassing (https://en.wikipedia.org/wiki/Composition_over_inheritance).
Edit: see this example:
abstract class AbstractDataHandler {
fun doSomething() {
// acquire data
processData(data)
// do something else with data
}
abstract fun processData(data: Data)
}
class MyDataHandler : AbstractDataHandler() {
override fun processData(data: Data) {
// process data
}
}
We have some kind of a data handler. At some point it has to perform some kind of data processing, but this processing should be different depending on the specific subclass. So AbtractDataHandler can't perform the whole operation alone. It needs a way to invoke data processing step that is provided by the subclass. It defines this processing as an abstract function.
The same example could be implemented with composition instead:
interface DataProcessor {
fun processData(data: Data)
}
class DataHandler(private val processor: DataProcessor) {
fun doSomething() {
// acquire data
processor.processData(data)
// do something else with data
}
}
(In this specific case it would be probably more Kotlin-ish to not use an interface, but a function type.)
Also, abstract classes are common if we need to implement an interface and there is some very basic functionality that is the same across all implementations. For example, all implementations have to provide the same fields for storing the data. Then abstract class could provide these fields, but it does know nothing about implementing the rest of the interface, so most of functions remain abstract.

Kotlin data class overhead

According to the official doc, a Kotlin data class has the following generated functionalities:
equals()/hashCode() pair
toString()
componentN() functions corresponding to the properties in their order of declaration
copy()
Now I understand that these functions are useful sometimes, I feel that in a lot of cases they are not necessary becase regular Kotlin classes already have auto-generated setters and getters. For example, in a Spring controller, if I want to create a DTO class to store and validate the request body, a regular Kotlin class (with validation annotations) seems enough.
I like that data class conveys the semantics that this class is a dumb data container, but I'm concerned that overusing data classes when we don't need their genereted goodies can negatively impact the code size & thus speed. Is there anything (such as an official style guide) that touches on this?

SOLID - are the Single Responsibility Principle and the Open/Closed Principle mutually exclusive?

The Single Responsibility Principle states that:
A class should have one, and only one, reason to change.
The Open/Closed Principle states that:
You should be able to extend a classes behavior, without modifying it.
How can a developer respect both principles if a class should have only one reason to change, but should not be modified?
Example
The factory pattern is a good example here of something that has a single responsibility, but could violate the open/closed principle:
public abstract class Product
{
}
public class FooProduct : Product
{
}
public class BarProduct : Product
{
}
public class ProductFactory
{
public Product GetProduct(string type)
{
switch(type)
{
case "foo":
return new FooProduct();
case "bar":
return new BarProduct();
default:
throw new ArgumentException(...);
}
}
}
What happens when I need to add ZenProduct to the factory at a later stage?
Surely this violates the open/closed principle?
How can we prevent this violation?
This feels like a discussion of the semantics of 'extend a classes behaviour'. Adding the new type to the factory is modifying existing behaviour, it's not extending behaviour, because we haven't changed the one thing the factory does. We may need to extend the factory but we have not extended it's behaviour. Extending behaviour means introducing new behaviour and would be more along the lines of an event each time an instance of a type is created or authorising the caller of the factory - both these examples extend (introduce new) behaviour.
A class should have one, and only one, reason to change.
The example in the question is a factory for creating Product instances and the only valid reason for it to change is to change something about the Product instances it creates, such as adding a new ZenProduct.
You should be able to extend a classes behavior, without modifying it.
A really simple way to achieve this is through the use of a Decorator
The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.
public interface IProductFactory
{
Product GetProduct(string type);
}
public class ProductFactory : IProductFactory
{
public Product GetProduct(string type)
{
\\ find and return the type
}
}
public class ProductFactoryAuth : IProductFactory
{
IProductFactory decorated;
public ProductFactoryAuth(IProductFactory decorated)
{
this.decorated = decorated;
}
public Product GetProduct(string type)
{
\\ authenticate the caller
return this.decorated.GetProduct(type);
}
}
The decorator pattern is a powerful pattern when applying the SOLID principles. In the above example we've added authentication to the ProductFactory without changing the ProductFactory.
A class should have one, and only one, reason to change.
This basically means, your class should represent single responsibility and shouldn't be modified thereafter to accommodate new feature.
For example, if you have class, which is responsible to print report in pdf format. Later, you wanted to add new feature to support printing report in other formats. Then instead of modify the existing code, you should extend it to support other format, which also implies extend a classes behavior, without modifying it
I think it depends on your interpretation of the SRP. This stuff is always somewhat subjective. Ask 100 people to define "single responsibility" and you'll probably get 100 different answers.
Using the scenario in Ravi's answer, a typical solution might be to have a ReportGenerator class which exposes a GeneratePdf method. It could then be later extended with an additional GenerateWord method if required. Like yourself though, I think this has a whiff about it.
I would probably refactor the GeneratePdf method into a PdfReportGenerator class and then expose that through the ReportGenerator. That way the ReportGenerator only has a single responsibility; which is to expose the various report generation mechanisms (but not contain their logic). It could then be extended without expanding upon that responsibility.
I'd say that if you find a conflict, it might well be an architectural smell that warrants a quick review to see if it can be done in a better way.
I have a class StudentOrganiser class which takes IStudentRepository dependency. Interfaces exposed by IStudentRepository is say GetStudent(int studentId)
Class obeys SRP because it does not have any logic related to manage the connection with repository source.
Class obeys OCP because if we want to change repository source from SQL to XML, StudentOrganiser need not to undergo any changes => open for extension but closed for modification.
Consider if StudentOrganiser was designed to not take dependency of IStudentRepository, then method inside class itself must be taking care of instantiating new StudentSqlRepository() If later on requirement would have come to also support StudentXMLRepository on the basis of certain run time condition, your method would have ended with some case switch kind of paradigm and thus violating SRP as method is also indulged in actual repository deciding factor. By injecting repository dependency we taken off that responsibility from class. Now StudentOrganiser class can be extended to support StudentXMLRepository without any modification.

Scala and encapsulation?

Since I started to study OOP encapsulation was always something that raised questions to me. Getters and setters in 99% of the cases seemed like a big lie: what does it matter to have setter if it changes the reference of the private field, and getter that returns reference to mutable object? Of course there are many things that make life easier with getters and setters pattern (like Hibernate that creates proxies on entities). In Scala there is some kind of solution: don't lie to yourself, if your field is val you have nothing to fear of and just make it public.
Still this doesn't solve the question of methods, should I ever declare a method private in Scala? Why would I declare a method private in Java? Mostly if it's a helper method and I don't want to pollute my class namespace, and if the method changes our internal state. The second issue doesn't apply (mostly & hopefully) to Scala, and the first one could be simply solved with appropriate traits. So when would I want to declare a method private in Scala? What is the convention for encapsulation in Scala? I would highly appreciate if you help me to order my thoughts on subject.
Getters and setters (or accessor/mutator methods) are used to encapsulate data, which is commonly considered one of the tenets of OOP.
They exist so that the underlying implementation of an object can change without compromising client code, as long as the interface contract remains unchanged.
This is a principle aiming to simplify maintenance and evolution of the codebase.
Even Scala has encapsulation, but it supports the Uniform Access Principle by avoiding explicit use of get/set (a JavaBean convention) by automatically creating accessor/mutator methods that mimics the attribute name (e.g. for a public val name attribute a corresponding def name public accessor is generated and for a var name you also have the def name_= mutator method).
For example if you define
class Encapsulation(hidden: Any, val readable: Any, var settable: Any)
the compiled .class is as follows
C:\devel\scala_code\stackoverflow>javap -cp . Encapsulation
Compiled from "encapsulation.scala"
public class Encapsulation {
public java.lang.Object readable();
public java.lang.Object settable();
public void settable_$eq(java.lang.Object);
public Encapsulation(java.lang.Object, java.lang.Object, java.lang.Object)
}
Scala is simply designed to avoid boilerplate by removing the necessity to define such methods.
Encapsulation (or information hiding) was not invented to support Hibernate or other frameworks. In fact in Hibernate you should be able to annotate the attribute field directly, all the while effectively breaking encapsulation.
As for the usefulness of private methods, it's once again a good design principle that leads to DRY code (if you have more than one method sharing a piece of logic), to better focusing the responsibility of each method, and to enable different composition of the same pieces.
This should be a general guideline for every method you define, and only a part of the encapsulated logic would come out at the public interface layer, leaving you with the rest being implemented as private (or even local) methods.
In scala (as in java) private constructors also allows you to restrict the way an object is instantiated through the use of factory methods.
Encapsulation is not only a matter of getter/setter methods or public/private accessor modifiers. That's a common misconception amongst Java developer who had to spend to much time with Hibernate (or similar JavaBean Specification based libraries).
In object-oriented programming, encapsulation not only refers to information hiding but it also refers to bundling both the data and the methods (operating on that data) together in the same object.
To achieve good encapsulation, there must a clear distinction between the those methods you wish to expose to the public (the so called public interface) and the internal state of an object which must comply with its data invariants.
In Scala the are many ways to achieve object-oriented encapulation. For example, one of my preferred is:
trait AnInterface {
def aMethod(): AType
}
object AnInterface {
def apply() = new AnHiddenImplementation()
private class AnHiddenImplementation {
var aVariable: AType = _
def aMethod(): AType = {
// operate on the internal aVariable
}
}
}
Firstly, define the trait (the public interface) so to make immediately clear what the clients will see. Then write its companion object to provide a factory method which instantiate a default concrete implementation. That implementation can be completely hidden from clients if defined private inside the companion object.
As you can see the Scala code is much more concise of any Java solution