Nate Kohari on Releasing Ninject 1.0
Nate Kohari released version 1.0 of his dependency injection container for .NET called Ninject. Dependency Injection has been a popular topic and this attention has given rise to new tools to take advantage of this technology.
Ninject is touted as a lightning-fast, ultra-lightweight dependency injector for .NET applications. Helping developers split applications into a collection of loosely-coupled, highly-cohesive pieces, and then glue them back together in a flexible manner. Using Ninject to support your software's architecture, your code will become easier to write, reuse, test, and modify.
The Ninject website describes Ninject as:
- Focused. Too many existing dependency injection projects sacrifice usability for features that aren't often necessary. Each time a feature is added to Ninject, its benefit is weighed against the complexity it adds to everyday use. Our goal is to keep the barrier to entry - the baseline level of knowledge required to use Ninject - as low as possible. Ninject has many advanced features, but understanding them is not required to use the basic features.
- Sleek. Framework bloat is a major concern for some projects, and as such, all of Ninject's core functionality is in a single assembly with no dependencies outside the .NET base class library. This single assembly's footprint is approximately 110KB when compiled for release.
- Fast. Instead of relying on reflection for invocation, Ninject can take advantage of the lightweight code generation features in version 2.0 of the CLR. This can result in a dramatic (8-50x) improvement in performance in many situations.
- Precise. Ninject helps developers get things right the first time around. Rather than relying on XML mapping files and string identifiers to wire up components, Ninject provides a robust domain-specific language. This means that Ninject takes advantage of the capabilities of the language (like type-safety) and the IDE (like IntelliSense and code completion).
- Agile. Ninject is designed around a component-based architecture, with customization and evolution in mind. Many facets of the system can be augmented or modified to fit the requirements of each project.
- Stealthy. In spite of its use of .NET attributes, Ninject will not invade your code. You can easily isolate the dependency on Ninject to a single assembly in your project.
- Powerful. Ninject includes many advanced features. For example, Ninject is the first dependency injector to support contextual binding, in which a different concrete implementation of a service may be injected depending on the context in which it is requested
InfoQ had the opportunity to talk with Nate about this framework, what it is and how it can help developers.
Robert Bazinet (RB): Who are you?
Nate Kohari (NK): I'm a 25-year old software architect from Akron, Ohio. I work for Commercial Timesharing, Inc. (CTI), a consulting firm that creates custom software and business intelligence solutions. At CTI, my role is to provide architectural guidance on .NET projects, but I still do my share of the development -- I'm definitely an "in the trenches" architect. Throughout my college days and early career, I did a lot of work in C, C++, PHP, and Perl on Linux, which is probably part of the reason why I'm such a big proponent of open source today.
RB: What is Ninject?
NK: Ninject is a dependency injection framework, or if you prefer, an "inversion of control container". We've all heard of the factory pattern, right? Well, Ninject is kind of like a "super factory", in that it knows how to create all sorts of objects, based on hints that you provide. Basically, if you think of your application like a jigsaw puzzle, if you tell Ninject what pieces to use, and how they fit together, it will put together the puzzle for you. Then, if you want to change the way the puzzle looks in the future, you can just change your bindings, and Ninject will do the rest of the work.
RB: Why is dependency injection important?
NK: As the adage goes, "the only constant is change," and nowhere is this more true than in software. Fred Brooks wrote about this in No Silver Bullet -- since software is "easy" to change (relatively speaking), people will find reasons to change it. Projects evolve and scope creeps, and all of a sudden your little prototype application has turned into a mission-critical enterprise-wide system. Inversion of control -- which is a practice that's often implemented by using dependency injection -- helps you design the needed flexibility into your software from the ground up, so when change inevitably happens, your software is malleable enough to alter. This flexibility also makes unit testing your code much, much easier, since you can swap out real components for mock objects during your tests.
RB: Why another dependency injection container?
NK: Dependency injection frameworks have traditionally relied on XML to define the metadata necessary to wire up the components of your application. Not only is XML a lot more cumbersome to write, but it also doesn't scale well: as your application grows, the XML file that defines your metadata can get bloated very quickly. Ninject takes the approach of Google Guice, a relatively new DI framework in the Java space, by providing a fluent interface that can be used to connect the various pieces of your software. The goal of Ninject is to make dependency injection feasible in projects of all sizes, and make it easier to manage your metadata as your project grows. I wanted to lower the "barrier to entry," so to speak, of dependency injection. To that end, I've tried to create the lightest, fastest, most easy to use dependency injection framework.
RB: Why would I use Ninject over other products like StructureMap, Unity, Windsor, and others?
NK: Don't get me wrong, those are all great projects. However, they all suffer from what I consider an "XML-first" mindset. Since Ninject lets you use code to set up your components, you can take advantage of features of the language and your IDE -- things like type safety and code completion -- that you're used to when writing C# and VB.NET but that aren't there when you write XML. While it's true that some of the other frameworks have built on fluent interfaces to supplement their XML configuration, they are largely second-class citizens in terms of the API.
Ninject helps to make dependency injection a feature of your application's design. With Ninject, you declare one or more "modules", each of which is in charge of wiring up a piece of your application. Since these modules are just classes, it's very simple to build in more intelligence -- for example, you could read command line arguments, scan assemblies for certain types, or even read configuration out of a database -- things you just can't do with XML. Ninject also has a very powerful advanced feature called "contextual binding," which can be used to declare multiple bindings for a specified type, and have Ninject evaluate which should be used based on the context in which the object is being created. Finally, Ninject is also very, very extensible -- great care was taken to make sure that every single piece of the framework could be customized and integrated with various other libraries.
RB: Is Ninject designed in such a way to be able to be used in an existing project? If yes, in general terms, how could a developer take Ninject and use it effectively going forward for either refactoring code or just moving forward with new code.
NK: Inversion of control is a mindset, and dependency injection of any kind (with or without a framework) relies on your software being designed with the goals of inversion of control in mind. Legacy software commonly suffers from poor cohesion (bad separation of concerns) and the "problem of control", in which objects are in charge of creating their own dependencies. The more of these inversion-of-control anti-patterns the software has, the more difficult it will be to reshape it to work with Ninject -- or any dependency injection technique, for that matter. That being said, it's certainly possible. Ninject makes resolving dependencies ultra-simple, so once you're using it in your software, it becomes much easier to correct these anti-patterns. The first step is to find and create the proper separations between your components, and wire them up with Ninject. After you do that, you can begin to introduce flexibility by altering your components to interact via interfaces. Start with a small segment of your application, and gradually branch out to the rest as time permits. It can also be helpful to use dependency injection for new code, because once you start using it, it has a tendency to spread throughout your code. Remember, this is a good thing -- it means your code is becoming more flexible!
RB: Is Ninject a product that every developer can use or would Ninject or other DI containers really be used by those higher-level folks such as architects or those very senior-level developers?
NK: Inversion of control is something that all of the developers on a project have to buy into and participate in to be successful -- like I said, it's really a different mindset. Ninject was designed to have a "low barrier to entry", meaning the framework is easy enough for anyone to participate in, without requiring an understanding of its advanced features. Typically, though, since inversion of control takes buy-in by the team at large, it's something that has to be mandated by a lead developer or architect in order for it to be adopted. Sometimes it's a hard sell up front ("What do you mean we have to use this framework? Why can't we just use 'new'?"), but it's all about design debt. Using a dependency injection framework early on in a project is like paying cash rather than using credit -- when change inevitably happens, it will be much easier to adapt the software to the new needs. In my experience, once that "big refactoring" becomes as simple as implementing the new version and altering your bindings, the value of inversion of control starts to become more apparent. Writing your software with inversion of control in mind also makes unit testing much, much easier, because you can swap out real implementations for mocks in your tests. If you're not writing unit tests, you should be!
RB: I noticed Ninject has Silverlight 2.0 Beta 2 support, can you elaborate on this?
NK: Yes! One of the main goals of the Ninject project was to make dependency injection accessible to applications of all sizes and types. To that end, Ninject 1.0 has support for not only the .NET Framework 2.0, 3.0, and 3.5, but also .NET Compact Framework 2.0 and 3.5, and the latest beta of Silverlight 2.0 (beta 2). This multi-platform support is something that I've put a lot of effort into, and am particularly proud of. I think there's a misconception that dependency injection can only be effectively applied to big "enterprise-y" projects, but Ninject is lightweight and fast enough to make it work pretty much anywhere you can run a .NET runtime. I've personally had a lot of success using Ninject in applications built for on handheld devices running the .NET Compact Framework.
RB: Ninject is open-source, how can other developers get involved to submit code?
NK: Yes, Ninject is released under the Apache License 2.0, meaning it can be used in projects of all kind without the requirement of redistributing source. I'm always looking for feedback on ways to improve the framework, and if you create something cool that you want to share, I'm always interested in patches. The best way to submit them is to post them to the users group. The link is available on the Ninject website by selecting "speak your mind". Also, if you're interested in contributing additional documentation, including tutorials, examples, or anything else, you can participate in the documentation wiki. Open-source is all about discussion and community, and I while Ninject is "opinionated software" by default, I'm very interested in providing solutions to match the needs of the community.
RB: What the best way for developers to grab Ninject 1.0 and get started with it right away or with little effort?
NK: You can get the binaries or the source for 1.0 on the Ninject website, or if you're interested in staying on the bleeding edge, you can check the latest trunk build out of the Subversion repository. If you plan to submit patches, you should check out a copy from Subversion to make sure you have the latest bits.
RB: Does Ninject have detailed documentation and code examples/best-practices?
NK: Sure! Head on over to the Dojo. There is a good walk-through on how to get started with Ninject there, as well as an example application that demonstrates some of the more advanced features. The Dojo is still a work in progress, but now that 1.0 is out I plan to spend my time writing more documentation. Open-source software often suffers from a lack of good documentation, and I don't want Ninject to be in that group!
RB: Nate, thank you very much for your time.
More information as well as detailed documentation, downloads and support for Ninject 1.0 at the companies web site. Information about the author of the framework, Nate Kohari can be found on Nate's blog.
Brandon Holt, Preston Briggs, Luis Ceze, Mark Oskin May 21, 2015
Kai Kreuzer, Olaf Weinmann May 21, 2015