Skip to content

Instantly share code, notes, and snippets.

@darrencauthon
Created September 3, 2014 02:38
Show Gist options
  • Save darrencauthon/9a02cca19aeeeb548555 to your computer and use it in GitHub Desktop.
Save darrencauthon/9a02cca19aeeeb548555 to your computer and use it in GitHub Desktop.
DI Sample
class ProductController < ApplicationController
def index
@products = Product.all
end
end
public class ProductController : Controller
{
private IProductRepository _productRepository;
public ProductController(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public ActionResult Index()
{
products = productRepository.getAll();
return View(products);
}
}
@RonJeffries
Copy link

Hmm. At a glance, I'd have said that Dependency Injection occurs when one passes a dependent object to a client. So that the C# code represents Constructor Injection. In the Ruby code, on the other hand, se apparently know the dependent object (or at least some provider), Product. So in the C# we're not dependent on Product (just on anything that is iProductRepository) and in the Ruby, we are. So, to me, it DOES reach out to get it. It's true that you can override all (or otherwise hack it) to give the controller a different object than the usual. So it's not really injection IMO.

Note that you can do injection in the constructor but you can also do it other ways. The wikipedia article is pretty good on the subject.

@darrencauthon
Copy link
Author

@RonJeffries I'm going to have some internal thoughts about my reference to "dependency injection" here... I think I have some thought churning to do there.

But for the practical application of managing dependencies, I think these two samples are functionally the same - but the Ruby example just has less work around it.

This is a product controller, and its purpose is to show the products. That's all it should care about -- it just shows products, and it leaves it up to the outside world to tell it what products. Given that, there's a big difference between:

    public ProductController(products)
    {
        _products = products;
    }

    public ActionResult Index()
    {
        return View(_products);
    }

and

    public ProductController(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public ActionResult Index()
    {
        products = productRepository.getAll();
        return View(products);
    }

With the former, the controller's dependency is on exactly what it needs: the products. With the latter, the controller has two dependencies:

1.) An object that the controller can use to get the data it wants, and
2.) The unwritten, general knowledge amongst all developers that "all of the products" is retrieved through the GetAllProducts() function.

(1) was injected in, of course... but (2) was not. Everything tied to that method call - the method signature and the return values -- are the responsibility of the controller to know and use. Otherwise, how would it get the products?

With the Ruby example, I feel that (1) comes with (2), just by the nature of Ruby. The method signature isn't just a method on an abstract type, it's a method on an object. And as a method on an object, I can override it just as easily as anything I'd pass through an IoC container.

@darrencauthon
Copy link
Author

One other note:

So in the C# we're not dependent on Product (just on anything that is iProductRepository) and in the Ruby, we are.

I'd disagree with this, but only because of my insider knowledge knowing the code sample that's in my head. πŸ˜„

If I have a C# method call like this:

productRepository.getAll()

that method has to return something, and in most cases with will be this:

IEnumerable<Product>

The dependency on Product still exists. It's a concrete type, sealed up in a DLL along with everything else that's there.

Why does this matter? Because I want to blow @hotgazpacho 's mind... I sometimes have tests written like this:

describe "index" do
  it "should pass the products to the view" do
    products = Object.new
    Product.stubs(:all).returns products
    controller.index
    controller.instance_eval { @products }.must_be_same_as products
  end
end

To me, this illustrates the real nature of Product.all, and how it differs from the C# example. Product.all, indeed, a method on a Product, but within our code it's more of that (2) I mentioned above. It's our way to get the products, no matter what they might be... and we leave it to the outside world to define what that way is. This is much different that the C# example, where ALL of the dependencies of the interface are brought to bear as soon as I reference it.

Of course, with this great power comes great responsibility. ⚠️

@hotgazpacho
Copy link

Heh. Sorry to disappoint, @darrencauthon, but my mind remains intact. That Ruby example is pretty much exactly what I had in mind πŸ˜‰

@hotgazpacho
Copy link

Question for you, though, @darrencauthon. Does calling controller.index like that, as opposed to the more common apraoch of using the TestRequest class, still invoke the before/after/around filters for the action?

@darrencauthon
Copy link
Author

@hotgazpacho It does not call the filters... but that's what I want! I want to be able to unit test the controller action in isolation from anything else.

I am a rare bird 🐦 as I use Rails yet I unit test my code. I know there are debates about unit testing versus integration tests, but to me -- without unit tests, I can't TDD, and if I can't TDD I'm not able to architect and verify my output.

I also use few filters.... if things get complicated, I'll string an integration test through them. But if things are complicated, I'm doing something else wrong. πŸ˜†

@RonJeffries
Copy link

This may be a perfectly good way to code it, and to test it. It's simple, I like it, and it'll probably do just fine. IMO, however, it is not Dependency Injection, simply because there is no injection going on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment