Focus on Distinction

John laPlante's blog. The title comes from the idea that there is often some critical detail that makes all the difference in a design, a movie, an event, etc. I am espeically interested in usability and design.

Wednesday, October 29, 2008

Usability and Dependeny Injection

Usability and programming is a pet topic. I've often thought that a big limit on advanced topics in programming is related to usability issues, such as jargon, the use of complicated examples, and abstract, imprecise language that reminds of an over use of pronouns (he said to her that they did that with the other). Sadly, many practitioners feel that their hard won knowledge is a badge of honor and that newbies should suffer to join the club.

I've recently been listening to a lot of Flex Show podcasts that focus on frameworks. Most of these related to dependency injection and inversion of control. The speaker usually starts out by saying something like: this is a difficult topic to discuss but let me try. Then true to form, they are incomprehensible. They start throwing in a lot of terms about objects, factories, servers, references, remote objects, calls, etc. Jargon, jargon, jargon. I wrote this article to explain some of these concepts in a simple fashion, trying to use uncluttered examples .

Dependency Injection & Inversion of Control

I've heard a lot of speakers in podcasts talks about dependency injection, most of which make it amazingly hard to understand largely due to the speaker using too much jargon, using abstract examples, and using examples that are realistic but unnecessarily complex to convey the idea. In fact, it is a very simple idea. Wikipedia has a relatively simple explanation. The simplest way I can put it is: think of injection as assigning a variable and a dependency as a reference a class so it is assigning a reference to a variable. what could be simpler? More specifically, it is a technique that assigns (i.e., injects) a reference to class B or C or D (i.e., a dependency) to a public property X in a class A rather than assigning that property within class A. This moves any decision making about the assignment from class A to the code that makes the assignment. This technique keeps class A uncomplicated and doesn't change it. Now class A isn't doing the controlling but rather the class that assigned property X which is where the term inversion of control comes in. We inverted the control from A instatiating B to something else instantiating B on A.

Further, imagine we have two classes, A & B. We could create a instance of B within A with a statement new B(). The 'problem' that people have with this is that if we wanted to swap out B for class C then we'd need to change A and recompile. Alternatively, we could have an IF THEN ELSE block in class A and instantiate B in one case and C in another but this is messy and what if later we wanted D. It would be nice to get class A complete & bug free then not have to touch it (see similar reasoning for using events). This is where the injection comes and it boils down to assigning a public property in A from another class. That is assign (i.e, inject) that property (i.e., dependancy). The code that makes this assignment is usually put in a class that is neither class A or B. In 'inversion of control' frameworks, it is usually given some mystical name like 'application context' etc. which make it sounds like rocket science. It is advantageous to have the the code for managing the injection separate from A & B because it centralizes part of your code that often changes and by centralizing it, you've reduced the number of files and classes that change.

This seems like a lot of trouble to go to to simply assign a property (i.e., inject a dependency). Besides the thrill of far flung abstractions and being able to out-geek your neighbor, this has some practical, effort saving benefits. Classes B, C, and D in a real application often deal with code for communicating with the server. For testing A, it is common to fake the server with some client code. The real server code might be in class B but the fake server could be in C. Further, class D could be a unit test for evaluating class A. If the programmer had to change class A for each of these cases, then it would require frequent changes to class A which is time consuming and likely to introduce bugs into class A. Another benefit is re-use of class A for other projects. For example, if class A is a user interface view. Realistically, it is unlikley that a user interface could be re-used whole-cloth. But, by keeping class A relatively simple, a programmer could readily re-purpose it for another project.

Loose Coupling

Proponents of the dependency injection technique often bring up the term coupling which means that one piece of logic is connected logically to another. In the software engineering world, loose coupling is a stated common goal. But, what is 'loose' mean. In the example, any way you look at it, class A is coupled to class B. In the first case where class A instantiate class B, class B it is tightly coupled to class A. With dependency injection, class B is loosely coupled to class A. Why is it 'loosely' coupled? Because it is easy to change the coupling of A to C or A to D. Maybe it should be called flexible or optional coupling. The biggest issue I have with the term is that it implies that coupling is bad. Programs are interconnected by their nature which means they are coupled. The real problem is that they coupling often is done in a rigid manner which makes a program hard to extend or change to provide alternative behavior. Techniques like dependency injection were developed by software engineers to provide more flexible coupling.

Conditional Logic

What could be more basic than IF THEN ELSE. I don't hear any podcasts about this topic or how someone has invented a framework to add it to your project. But, I can be sure that folks use it every day in their work. That is because it offers a basic way to add alternatives to a computer program. I bring this up because that is exactly what dependency injection and inversion of control do as well. Plus they add the ability to move the control to a strageic place in your code which is largely possible because of object orientation. The ability to strategically position logic is yet another way to organize and modularize a program which relates to past improvements to computer programming, such as putting code into functions rather than using goto statements. It is also where programming gets into architecture. Too bad that it these tecniques involve so much jargon and complication to setup. But, then I don't think about the label 'conditioanl logic' when I use it, I just use it.

Using Events to Connect Code

I see a common thread between dependency injection and the use of events and event dispatching. Class A can call a method B1 on class B in which case I would consider method B1 tightly coupled to class A. Another way to handle this is for class A to dispatch an event when something critical happens and for class B to listen for that event. I would then consider the connection loosely coupled. In the first case, if I want to change the logic, I could change method B1 which may not be ideal or I could change class A and call B2. A problem here is that I don't want to change class A nor method B1. Using events, I could change the listener of B to handle the event differently. Another scenario is that I want to add class C at a later time. Using events, I can add a listener to class C for the event that class A dispatches and I don't need to make any changes to class A.

In both the use of dependency injecdtion and events, I can architect my program so that I don't have to change class A and I can add flexibility to my program without doing a lot of rewiring. One of the themes here is leaving well enough alone. If you can write parts of your program and then leave them and still add new functionality, it is a recipe for faster programming and less errors.

Factories

In most talks that I've heard on the subject of dependancy injection, the topic of Factories arises. At first, I envisioned a rusty, noisy steel mill that is pumping out objects which seemed a tad mysterious. But again it isn't that complicated. A factory is a class where you can put the code you use to instantiate objects. This is a way to organize and centralize your code for instantiating class instances so that you aren't instantiating instances throughout your code which can be messy. In the dependency injection example, we referred to the idea of a 'application context' that instantiates class B and assigns it to property X on class A. This is an example of a Factory. In addition to the basic instantiating, a Factory can provide extra benefits. For example, it can organize (e.g., lists, hashes, etc.) and provide access to instances of a class. If you want to only instantiate a class one time and use that instance repeatedly (a singleton) rather than repeatedly instantiating instances, then a Factory can manage this for you. It isn't hard to write a singleton but it is convenient to have a class that can manage that process.

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home