More on Akka and dependency injection

Just as a quick follow-up to my previous post, I thought I’d note that the official Akka blog has published a post regarding Akka and dependency injection (kind of weirdly expressed as a mini white paper, as though the internet at large had issued an RFP for an actor-based concurrency system with dependency injection).

While, as I mentioned before, I should emphasize that I’m by no means an expert in Akka or actor best practices, I’m not convinced that this document addresses my particular concerns with the intersection of Akka and dependency injection. I’m still thinking about a larger post breaking down the approaches to this topic that I’ve seen online, but this one sort of falls into the “mock stuff outside of Akka” camp.

The document has two main points: firstly, if you have an existing dependency-injected service, you can pass along a factory which knows where to find it to the Props constructor of an actor, and there’s a way to attach a DI application context to an ActorSystem to support this, in what seems like a pretty convenient way. Secondly, if you need to expose an interface from actors to an existing system based on a DI framework, you can include an ActorSystem singleton in your DI object graph, and then expose a sort of regular-object facade over it which finds specific actors and returns either ActorRefs or futures resulting from sending ask messages to them.

That’s all well and good, but it seems more like a way to integrate between Akka and an existing synchronous DI-based system than anything that makes dependency injection useful or usable inside a purely Akka-based system. (In particular, the document’s unfortunate final section seems to be aimed squarely at recalcitrant middle managers who need to be convinced that a move to Akka will not result in a whole bunch of now-legacy code needing to be tossed out.) While I’m not incredibly interested in this topic myself, I thought Akka already had a talking point for this integration problem in the form of “typed actors“.

The bit that I still haven’t seen addressed is that if Akka likes actors to explicitly manage the lifecycles of other actors they supervise, there doesn’t seem to be any room for the inversion of control that is the hallmark of dependency injection frameworks in the first place. To put it in more concrete terms, if I’m running a partial integration test of my simple notification service and I want it to have a real database actor and mock REST web service actors, how can I tell the actor that supervises all the HTTP worker actors to create mock actors instead of live ones?

I have a half-formed idea of how this could work that involves having a sort of service locator / factory actor which is responsible for actor instantiation, but the idea in my head doesn’t particularly jibe with Akka’s supervision hierarchy, which as far as I can tell is coupled very tightly to actor instantiation.

Advertisements

Testing Akka: actors, dependency injection and mocks

I’ve been digging into what the expected way is to test my small Akka system, as described in my previous post on the subject. I think my problem partially arises from being unclear as to the proper mode of dependency injection in Akka. In other words, I don’t know what the proper way is for my Root actor to obtain a reference to its Database and HTTP sub-actors. Does it create them itself? Look them up from a service locator? And what if I need to inject mock actors into the system in some parts in order to test it?

Various bits of Akka documentation suggest different approaches to wiring actors together; for instance, this page in the official docs suggests either passing dependent actors as constructor arguments, creating them in a preStart() method, or passing them to their referring actors in a message and using become() to switch between initialization states. This example from the testkit docs takes the latter approach, but I can’t say I like the result:

class MyDoubleEcho extends Actor {
  var dest1: ActorRef = _
  var dest2: ActorRef = _
  def receive = {
    case (d1: ActorRef, d2: ActorRef) =>
      dest1 = d1
      dest2 = d2
    case x =>
      dest1 ! x
      dest2 ! x
  }
}
/* ... */

val probe1 = TestProbe()
val probe2 = TestProbe()
val actor = system.actorOf(Props[MyDoubleEcho])
actor ! (probe1.ref, probe2.ref)
actor ! "hello"
probe1.expectMsg(500 millis, "hello")
probe2.expectMsg(500 millis, "hello")

This does seem to work, but it seems to me that it pollutes the actor with a bunch of test-related code that probably doesn’t belong in production (by which I mean the receive pattern which takes the two dest parameters).

I have found an interesting take on this question in this presentation by Roland Kuhn, introducing akka-testkit from Scala Days 2012—the entire presentation is worth watching, but the part I’m interested in starts at around 22:05 or so.  After a not terribly helpful note about how if you have difficulty injecting mocks into your code, then there is probably something wrong with your design (there may be something to that, but it’s not all that helpful to hear when you’re looking for a solution for injection), Mr. Kuhn mentions a third option for users of the (then-new) Akka 2.0: actors can use actor path naming to look up their dependent actors; the test ActorSystem can then supplant the real implementations with mocks at the same locations.

Of course, all of this sort of assumes that you have a way of separating out actor creation and lifecycle control from dependency injection itself. A lot of the other Akka literature I’ve read seems to posit the integrated lifecycle management bits of Akka as a feature, right down to the “Let It Crash” maxim on the public Akka blog, and all of these features seem to be in direct opposition to the inversion of control notions that most dependency injection systems are founded on. In the last part of Mr. Kuhn’s talk above, he suggests breaking up actor models into somewhat discrete trees, which then use service locators or similar things to find one another; this might be something I can look into.

There was also a talk at this year’s Scala Days about integrating Spring and Akka, which might have some merit for this purpose, and I recently ran across this promising post which describes an approach to autowiring actors with Spring and Akka 2.2 (in Java). Overall, though, this doesn’t seem to be a problem with a clear solution.

The Cake walk

I come from a very Spring-heavy background in Java.  Spring is a bit of a loose, baggy monster, containing probably hundreds of features which aren’t all terribly well-connected to one another, but one thing that became second nature to me in Spring was the dependency-injection and IoC features.  Structuring software into composable components makes sense to me for scalability and ease of testing.

There are a few logical bits in random-album-cover that are clear candidates for components.  In particular,  the three distinct bits of information we’re getting from the web should probably each have a testing implementation and a live one (one which actually connects to the web and scrapes a page).  My Java instincts would probably structure the code something like the following:

interface Cover { ... }
class CoverImpl implements Cover { ... }

interface QuoteService {
    String getQuote();
}
class TestingQuoteServiceImpl implements QuoteService {
    String getQuote() { return "testing"; }
}
class LiveQuoteServiceImpl implements QuoteService {
    String getQuote() {
        // Fire up httpClient, connect to quote page, scrape for quote
        return result;
    }
}

interface CoverFactory {
    Cover generateNewCover();
}
class CoverFactoryImpl {
    QuoteService quoteService;
    Cover generateNewCover() {
        String quote = quoteService.getQuote();
        return new CoverImpl(quote);
    }
    void setImageService(QuoteService imageService) { ... }
}

Not shown: some Spring configuration that would wire up one of the two quote factory implementations into a CoverFactoryImpl instance.

None of this is rocket science. Translating it to idiomatic Scala is a bit trickier than it seemed at first. There are a few libraries which exist to do dependency injection in Scala, but there is also a method which relies on native library features, the Cake Pattern.  Adam Warski’s post from 2010 is a good summary of the idea, with code examples.

Digging a little more deeply into it, though, I found some discussion of the Cake Pattern which gave me pause.  In particular, the discussion on this post from Adam Warski, along with this post by Przemek Pokrywka and this one by Debasish Ghosh made me wonder if my understanding of what exactly the pattern does and how to implement it was not quite up to speed.

This had the salutary effect of driving me back to my primary sources (the Odersky et al “staircase book” and to a lesser extent, the O’Reilly book) for a refresher on self type annotations.  I’m still not entirely sure I grasp what the ultimate purpose of self types are; I can see the pragmatic effect of requiring that a concrete class which mixes in one trait must also mix in the trait that is referred to as a self type, but I don’t exactly see how to generalize this to more than a one-to-one trait relationship.  In some of the larger Spring projects I have worked on, literally hundreds of services (Java singleton instances) were composed and wired together — in the end there was an object graph.  If traits can only declare one self type, though, I don’t quite see how you would use this mechanism for anything other than an object list.  Clearly I’m missing something, but the staircase book is uncharacteristically terse on this point.

In any event, all was not lost, because chapter 29 of the staircase book essentially sets out to solve the exact problem I’d been working on: how best to structure and compose component-based software in Scala.  There seem to be a few ways of going about it, but for now I should have some simple examples to use as the basis for assembling my tiny services.  (It also opens up the possibility of comparing some of the more lightweight Scala DI frameworks down the road, which is something I’d probably enjoy.)