Complexities of APIs
This post is in addition to Boris’ post about accidental complexity of APIs, and problems around evolving them over time, and a a summary of some comments on that blog post.
Dependency injection over Service Locator.
Each one has their own baggage of merits and de-merits.
DI also adds to better design, so that classes do not start doing Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID).createExecutableExtension(myProperty) in the middle of nowhere, and there’s no way that I can start testing them unless the tests put something in the registry. Service Locator makes provisions for the some of the extensibility that eclipse needs. Injecting objects that locate services into objects that need these services seems to be a right thing to do:
Here’s an example of what we do: makes for easy testing because it is now possible to mock the interface out for testing the object.
public class FooBarFacade {
public FooBarFacade(IConfigurationElement driver) {
options = (IFooBarOptionsOptions) driver.createExecutableExtension(OPTIONS_EXTENSION_POINT);
optionsComposite = (IFooBarOptionsComposite) driver.createExecutableExtension(OPTIONS_UI);
optionsInitializer = (IFooBarInitializer) driver.createExecutableExtension(INITIALIZER);
}
}
Interfaces with getter/setter methods
The other point that always strikes me in the API are some really huge interfaces with get/set methods. Clearly the interface/implementation is doing more than that, using abstract classes is probably a good thing to do in such cases (more so, if there’s going to be just one implementation of the interface anyway)
Why do we need getters and setters anyway ? Do they not break encapsulation ? There’s two schools of opinions I’ve come across here. One that likes to follow the javabeans specfications. The other that says hates getters and setters for the reason that objects then tell you who their friends are (Disclosure: I belong to such a group). Objects should expose behavior and not their friends that may help you out.
Law of Demeter
The Law of Demeter says “talk to your immediate friends”. getA().getB().getC().doSomething is probably a bad thing to do.
Don’t confuse your dog. Asking a dog to walk its legs is easier(and less confusing) than asking the dog for it’s legs and then making them walk.
Singletons and the law of demeter
I’m always having to do something like:
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getWorkbench().doSomething();
IJavaProject p = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot().getProject("foobar"));
So much so that I’ve now got templates for all such APIs. Why not just:
Workbench.getActiveWorkbench().doSomething();
IJavaProject p = JavaCore.createProject("foobar");
In Conclusion: How much API is “good enough” API ?
Returning the legs of a dog is an easier thing to do, and let clients manage the walking, but heck, I can’t imagine anything I’d want to do with a dog’s legs other than to walk, so I might was well want to ask the dog to walk itself.
This is certainly not a solved problem. I prefer to follow a simple rule. Provide just about enough API to make 80% of the users happy. Provide just about enough extensibility to make the other 20% happy, just in case someone wants to make the dog walk backwards!