Coding: Weak/Strong APIs
An interesting problem that I've come across a few times in the last couple of week centres around how strongly typed we should make the arguments to public methods on our objects.
There seem to be benefits and drawbacks with each approach so I'm not sure which approach is better – it possibly depends on the context.
When we have a strong API the idea is that we pass an object as the argument to a method on another object.
To given an example, recently a colleague and I were working on a little application to compare two objects and show the differences between them.
One of the decisions to be made was how to accumulate the differences. We created PropertyDifference and PropertyDifferences objects to do this, but the question became who should have the responsibility for creating the PropertyDifference.
The choice was between having PropertyDifferences API look like this:
public class PropertyDifferences { public void Add(PropertyDifference propertyDifference) { // code to add a difference } }
Or like this:
public class PropertyDifferences { public void Add(string propertyName, object actualValue, object expectedValue) { var propertyDifference = new PropertyDifference(propertyName, actualValue, expectedValue) // code to add a difference } }
In the former the client (ObjectComparer) needs to create the PropertyDifference before passing it to PropertyDifferences whereas in the latter that responsibility for doing that rests with PropertyDifferences.
I'm in favour of the former strong API approach which James Noble describes in his paper 'Arguments and Results' as the Arguments Object.
What I like about this approach is that it simplifies the API of PropertyDifferences – we just have to pass in a PropertyDifference and then we don't need to worry about it. I also find it more expressive than having each of the arguments individually.
However, while reading through Object Design this morning I've started to see that there can be some benefits in the weak API approach as well.
(from page 7 of the book)
As we conceive our design, we must constantly consider each object's value to its immediate neighbourhood. Does it provide a useful service? Is it easy to talk to? Is it a pest because it is constantly asking for help?…The fewer demands an object makes, the easier it is to use.
By that logic PropertyDifferences is making itself more difficult to use by demanding that it gets sent a PropertyDifference since objects which use it now need to create that object. I suppose the other way of reading that could be that if PropertyDifferences demands that it gets three different arguments instead of one then that is more demanding.
The other advantage I can see with the weak API is that we can reduce the places in the code where we new up a PropertyDifference. If we then decide to change the way that you create a PropertyDifference then we have less places to change.
The down side is that we end up coupling PropertyDifferences and PropertyDifference which maybe isn't so bad since they are fairly closely related.
I still favour having a stronger API on objects since I believe it makes objects more expressive and I currently consider that to be the most important thing when coding but weaker APIs certainly have their place too.
Hi, Mark
What really called my attention is the reference to property names and property values at this point.
I expect this detailed information to be already abstracted by a Property value object, so the question would be to use Property objects or PropertyDifference objects in the API.
Cheers, Rafael
Rafael Peixoto de Azevedo
27 Apr 09 at 9:20 pm
Hi Mark,
I'm in favor of the former API, too. As a TDD very (very) beginer I'd say mocking PropertyDifference and putting PropertyDifferences under test would be much easier for me. PropertyDifferences seems to be ordinary collection, some place to store object differences, so I woudn't expect its responsibility to 'create' but to 'operate on' its items. The later API also suggests that PropertyDifference can not exist without PropertyDifferences, that PropertyDifference is only valid within PropertyDifferences. Maybe that's just my feeling.
Maciek
Maciek Szymanski
27 Apr 09 at 10:43 pm
The choice is between passing (1) what the client probably has on hand already (the pieces) vs. passing (2) what the class demands (a pre-formed object). Which serves the client better and more naturally?
Which brick-and-mortar shop gets more business–the one taking credit cards (already in the customers' hands), or the one demanding cash in some foreign currency (which the customers first have to go get)?
Subordinate the service's convenience to the client's. Accept what a client likely has at the ready. (At the least, offer an overloaded constructor that does so.)
Eric
30 Apr 09 at 11:22 am
[...] of this approach is that we make it more difficult for clients to use our API. I think this was best summed up in a comment on a post I wrote about using weak or strong APIs by [...]
Book Club: Arguments and Results (James Noble) at Mark Needham
16 Jun 09 at 11:38 pm