Is it terrible to connect to an external service i...
# announcements
l
Is it terrible to connect to an external service in the constructor? i.e...
Copy code
init {
        factory = ConnectionFactory().apply {
            setUri(config_uri)
            // Attempt recovery every 5 seconds
            isAutomaticRecoveryEnabled = true
        }
        rabbitConnection = factory.newConnection()
n
IMHO, the major concern is that it makes it pretty hard to test, right?
You probably want to be able to create this object, without connecting to the external service, for unit testing
s
Yup, inject the dependencies. Have an other piece of code create the
rabbitConnection
and provide that to the constructor of your class.
2
l
👍
n
i guess what's annoying is that if you don't control the connection class
and it doesn't already inherit from some interface
there's no nice way to solve this in kotlin, is there?
You'd have to create your own interface (which is fine), but then you'd need to have a wrapper class to forward the interface
s
Yes. You'd need to create an interface and have an implementation of it that uses that 'connection' class. That is not bad, rather a standard way of abstracting out external/3rd-party services. If that is hard to do in your code, for testing you could mock the 'connection' class instance instead.
n
@streetsofboston I'm not saying it's the end of the world, but let's not pretend it's not bad
it's the standard way to handle it in languages that don't have a way to do polymorphism non-intrusively
n
Luis, repeating a bit what Nir and Anton have said, the connection factory should be abstract, not just for the sake of testing, but flexibility. Your business logic only cares about connecting to the service. It doesn't need to know anything about the service details other than the abstract interface to the service.
The easiest way to do dependency injection (my opinion) is to just have a constructor parameter. E.g.
Copy code
class MyController(val connectionFactory: IConnectionFactory) {
  val rabbitConnection = connectionFactory.newConnection()
}
I prefer to avoid dependency injection that uses reflection, or anything super complicated (especially anything where timing is involved.) Either the interface directly as a constructor parameter, or an 'injector' which can just be a map of interfaces to their implementations.
As far as making the (abstract) connection in the constructor goes, I don't see a problem with that except that making and using connections should be asynchronous. You might want to look at kotlin coroutines for this.