Are DI frameworks really useful? - kotlin

there are a sufficient number of DI frameworks in Kotlin's world that pursue one goal - to introduce dependency into the class.
More to the point, my question is: why are these frameworks better than just doing this:
// UserService.kt
interface UserService {
fun getUserById(id: String): User
}
// UserServiceImpl.kt
class UserServiceImpl : UserService {
override fun getUserById(id: String): User = TODO()
}
// Components.kt
fun userService(): UserService = UserServiceImpl()
// UserOfUserService.kt
class UserOfUserService {
private val userService = userService()
}
This is the most common example that came to my mind.
I know that DI frameworks offer more features than the example above. But in the term of an application with non-complex dependencies - is it possible to use this approach?
Thank you.

As Michael noted earlier, DI frameworks can be useful in the case of large applications with many dependencies, since it is much easier to delegate their management to the DI framework than to use even more confusing factories.
I wanted to know if my approach to using the factory method for small applications (or rather, libraries) is correct and got the answer, thank you.

Related

Get Kotlin class from string a call a method in it

I have 2 simple classes in kotlin
package com.sample.repo
class SampleClassA() {
fun test(): String {
return "Do things A way"
}
}
package com.sample.repo
class SampleClassB() {
fun test(): String {
return "Do things B way"
}
}
Now i have a configuration file that tells me which class to use.
Let's say i have a string
val className = "SampleClassA" // assuming all classes are in same package
I want obtain this class and invoke the test function in it
I was able to do below
fun `some random test`() {
val className = "SampleClassA"
val packageName = "com.sample.repo"
val kClass = Class.forName("$packageName.$className").kotlin
val method = kClass.members.find { it.name == "test" }
// How do i call this method ??
}
}
You should create an object of the class and then call method on it.
Example:
//...code from your example
val method = kClass.members.find { it.name == "test" }!!
val obj = kClass.primaryConstructor?.call()
val result = method.call(obj)
println(result)
I wouldn't do it that way. Instead, I'd require that the classes you're choosing between implement some common interface, which you can then refer to directly. For example:
interface Testable {
fun test(): String
}
 
package com.sample.repo
class SampleClassA() : Testable {
override fun test() = "Do things A way"
}
 
package com.sample.repo
class SampleClassB() : Testable {
override fun test() = "Do things B way"
}
 
fun `some random test`() {
val className = "SampleClassA"
val packageName = "com.sample.repo"
val testable = Class.forName("$packageName.$className").kotlin
.createInstance() as Testable
testable.test()
}
I don't know if this applies to OP, but judging from some of the questions asked here on StackOverflow, many people are coming to Kotlin from weakly-typed languages where it's common to use ‘string typing’ to fudge the lines between types, to assume that developers can always be trusted, and that it's fine to discover problems only at runtime. Of course, it's only natural to try to apply the patterns and techniques you're familiar with when learning a new language.
But while that style of programming is possible in Kotlin (using reflection), it's rarely a good fit. If you'll excuse one of my standard rants, reflection is slow, ugly, fragile, insecure, and hard to maintain; it's easy to get wrong, and forces you to handle most errors at runtime. Don't get me wrong: reflection is a very valuable tool, and there are situations where it's vital, such as writing frameworks, plug-ins, some forms of dependency injection, build tools, and similar. But reflection should be a tool of last resort — for general application coding, there's almost always a better approach, usually one that's more concise, easier to read, performs better, spots more problems at compile-time, can be autocompleted in your IDE, and works with the language and its type system, not against it.
Kotlin is a strongly-typed language; it has a fairly sophisticated type system (and type inference, so you don't need to keep repeating yourself), which is safer and smarter, turns many errors into compile-time errors, allows many optimisations, and is effectively self-documenting (making more explicit the contract between called code and its callers). It's better to try to work with the type system when you can, rather than subvert if (which is what reflection does).
The example above uses reflection to create an instance of a class which is assumed to implement the Testable interface (and will give ugly errors at runtime if the class isn't available, doesn't implement that interface, or doesn't have a public constructor with no required params), but after that uses normal, typed code which is much safer.
(In fact, depending how your test code is structured, you might find a way to configure it with Testable instances rather than String classnames, and avoid reflection altogether. That would be simpler and safer still.)

Usage of Dagger2 outside Android

I've recently started to learn Dagger. In order to do that, i've decided to write a simple console application to get the feeling of how various dagger features (like modules, component, subcomponents and component dependencies) fit together in an app architecture. As I don't really understeand it and given how hard it is to find an application sample created with dagger2 which is not Android app, i've decided to open a question here.
The first and probably most important question is: is dagger2 even ment to be used outside android?
If yes, then lets consider a simple application architecture: we have the data layer, service layer and ui layer
Data layer might consist of some kind of facade:
(Following code snippets will be written in Kotlin)
class Entity(var id: Int)
interface Repository {
fun findEntityById(id: Int): Entity?
fun deleteEntity(entity: Entity): Boolean
fun saveEntity(entity: Entity): Boolean
fun findAllEntities(): List<Entity>
}
Then i could have a couple of implementations of this facade:
class InMemoryRepository #Inject constructor() : Repository {
private val entities: MutableList<Entity> = LinkedList()
override fun findEntityById(id: Int): Entity? = entities.firstOrNull { it.id == id }
override fun deleteEntity(entity: Entity) = entities.remove(entity)
override fun saveEntity(entity: Entity) = entities.add(entity)
override fun findAllEntities(): List<Entity> = LinkedList(entities)
}
For which i would have modules:
#Module
interface InMemoryPersistenceModule {
#Singleton
#Binds
fun bindRepository(rep: InMemoryRepository): Repository
}
Service layer would be simpler:
#Singleton
class Service #Inject constructor(repository: Repository) {
fun doSomeStuffToEntity(entity: Entity) {}
}
#Singleton
class AnotherService #Inject constructor(repository: Repository) {
fun doSomeStuffToEntity(entity: Entity) {}
}
But it gets a little bit unlcear when it comes to the UI layer. Lets say i have some kind of android-like activity:
interface Activity : Runnable
And some kind of class that manages those activities:
class UserInterfaceManager {
val activityStack: Stack<Activity> = Stack()
val eventQueue: Queue<Runnable> = LinkedList()
fun startActivity(activity: Activity) = postRunnable {
activityStack.push(activity)
activity.run()
}
fun postRunnable(callback: () -> Unit) = eventQueue.add(callback)
fun stopActivity() { TODO() }
//other
}
How does dagger fit into this scenario? The articles i have read about the the dagger with android suggest createing the application component to inject my activites:
#Singleton
#Component(modules = [InMemoryPersistenceModule::class])
interface ApplicationComponent {
fun injectSomeActivity(activity: SomeActivity)
// and more
}
But then, where would the injection go to? It does't really make sense to put it in the UserInterfaceManager as Activities will most likely need an instance of it, which would create a circular dependency.
I also do not like the idea of the component being obtained from some kind of static method/property and injecting the activity from inside of it at the startup, as it creates duplicate lines of code in each activity.
Also, where do components and subcomponents fit in this kind of architecture? Why not create the separate
component for the data layer and expose just the repository and declare it as a dependency of the app component which would further isolate the details from abstraction? Maybe i should declare this component a dependcy of a service component which would enforce the layer architecure, as components can only use the types exposed in component interface? Or maybe i should use compoenent only when i need a custom scope and use the modules everywhere elsewhere?
I just overally think I am missing the bigger picture of the dagger. I will be really greatefull for answers, explanations and links to articles and other resouces that will let me understeand it better.
From the perspective of an Android developer, I fully understand your point. I asked myself this question too. The way how you construct an object in plain Java/Kotlin world is a little bit different. The main reason is due to the fact basic Android components (Activity/Fragment) don't allow constructor injection.
The answer to your question is, though, pretty straightforward. The Dagger Component is responsible for object creation, and you, as a developer, control what objects specific component provides. Let's use it in your scenario and provide some of the objects you might be interested in:
#Singleton
#Component(modules = [InMemoryPersistenceModule::class])
interface ApplicationComponent {
val service: Service
val anotherService: AnotherService
}
ApplicationComponent should be understood as a component for your whole application. It's not related to Android's Application class in any way. Now, you can simply create your component and let Dagger instantiate your objects:
val component = DaggerApplicationComponent.create()
val anotherService: AnotherService = component.anotherService
val service: AnotherService = component.service

Is it a good idea to place the code of instance a class in a interface in Kotlin?

The Code A is from the project android/architecture-components-samples.
The author place the code of instance a class DefaultServiceLocator in the interface ServiceLocator.
In my mind , normally a interface should not include any implement code.
Is it a good idea to place the code of instance a class in a interface in Kotlin?
Code A
interface ServiceLocator {
companion object {
private val LOCK = Any()
private var instance: ServiceLocator? = null
fun instance(context: Context): ServiceLocator {
synchronized(LOCK) {
if (instance == null) {
instance = DefaultServiceLocator(
app = context.applicationContext as Application,
useInMemoryDb = false)
}
return instance!!
}
}
/**
* Allows tests to replace the default implementations.
*/
#VisibleForTesting
fun swap(locator: ServiceLocator) {
instance = locator
}
}
...
}
open class DefaultServiceLocator(val app: Application, val useInMemoryDb: Boolean) : ServiceLocator {
...
}
In my mind , normally a interface should not include any implement code.
Welcome back from hibernation ;) Yes, you could achieve the same with interface + abstract class but you can have default implementation also as part of the interface for some time now in many languages. Which way you go is up to you, but if you have only one abstract class implementing your interface then it is often handy to be able to merge this into one file for sake of ease of future maintenance.
As per kotlin interfaces documentation:
Interfaces in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties but these need to be abstract or to provide accessor implementations.
So... there's no problem in using method implementations on the interfaces. That feature might offer you extra power (if you like and need to use it).

Function interface in Kotlin 1.4

This feature will be coming Kotlin 1.4. Here is an excerpt from KotlinConf'19.
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
runAction{
println("Hello")
}
It looks nice, but I still don't know what it does.
What is the function interface? What is its practical value? What specific scenarios can it be used for?
This is about functional interfaces — interfaces with a Single Abstract Method (also called SAM interfaces).
To understand the point, I'll need to cover a little history…  In Java, lambdas were added relatively recently.  Before that, you implemented callbacks and similar by implementing a suitable interface.  For example, if you wanted to be informed when an AWT component was actioned, you'd create an object which implemented the ActionListener interface.  That has a single method (called actionPerformed()); you'd put your code inside that method:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Do something
}
});
When they added lambdas, they wanted to blend in with all the existing code, and change as little as possible, so they did it exactly the same way: the compiler infers which interface you're implementing, and creates an object implementing that interface.  You could write:
myButton.addActionListener(e -> {
// Do something
});
which is shorter — but it compiles down to pretty much the same as the first example.
So in Java, functions are not first-class objects; lambdas are simply a more concise way to implement functional interfaces.
In Kotlin, however, functions are first-class objects: you can write a lambda (or an anonymous function) on its own, assign it, pass it to functions, return it from functions, and so on — so there's no need for SAM interfaces at all!
For easier interoperability with Java, Kotlin lets you easily implement Java SAM interfaces, in the same way you do from Java:
myButton.addActionListener {
// Do something
}
But Kotlin <= 1.3 doesn't let you implement Kotlin interfaces that way; you need to implement those explicitly.  (I suspect this was partly to encourage developers to use proper functions, with all their other advantages, and not rely on the Java-style workaround.)
Your example illustrates this.  It has an interface (Action) with one abstract method (run()).  It has a function (runAction()) which takes an instance of that interface.  And it has some code which wants to call that function, passing just the code for the run() method.
In Kotlin <= 1.3, you'd have to do the latter explicitly, e.g.:
runAction(object : Action {
override fun run() {
println("Hello")
}
})
But from Kotlin 1.4, you can mark the interface as fun interface, and use the Java-style shortcut, as in your example.
(You may or may not think this is a good thing…)

Is there a way to dynamically implement API interface classes in kotlin with bytebuddy? (Mixins pattern)

Let me summerize what I am trying to achieve. Basically I want a way to have a set of interfaces which server an an api that external plugins use to interact with the engine.
Here is how I currently have things setup.
class Engine : ApiEngine {
override fun start() {
println("Starting Engine")
}
override fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
fun start()
fun stop()
}
This is cumbersome and I have seen some other solutions using ASM and injecting the interface dynamically into the "Engine" class. I have seen something like this in another source but never could fully figure out how to do.
#Implements("ApiEngine")
class Engine {
#Export("start")
fun start() {
println("Starting Engine")
}
#Export("stop")
fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
#Import("start")
fun start()
#Import("stop")
fun stop()
}
My question is, in ByteBuddy, is it possible to effively make Engine implement ApiEngine so that it an instance of Engine() can be cast to ApiEngine for API usage?
This is very much possible. You can for example integrate Byte Buddy as a build tool where you generate interfaces upon discovery. Simply implement the Plugin interface and match types based on your annotation being present.
As a next step, you would need to instrument those types to implement an additional interface using the DynamicType.Builder DSL that Byte Buddy provides you. If your methods always match their signature, there is nothing more to be done since Byte Buddy automatically detects those overrides. If the method signatures can vary, you would need to implement the interface methods using MethodCall to implement a delegation to the actual implementation.