Our teams is having the following discussion:
Let's say we have the following two methods:
public Response Withdraw(int clubId, int terminalId,int cardId, string invoice, decimal amount); public Response Withdraw(Club club, Terminal terminal,Card card, string invoice, decimal amount);
whats sent over-the-wire are just the ids.
one side says that the first method is correct, because we only have the ids of terminal and club, and it should be clear that we have nothing else, this is my approach.
the other side says that the second method is correct because it's more flexible.
We are familiar with object parameter idea, the other side also thinks that the object parameter should have the objects as properties.
Which is the correct approach?
Maybe there is a third even better approach?
The first approach is indicative of Primitive Obsession. Because you are passing ints and strings around, it's very easy for the programmer to make a mistake (eg passing a clubId to the terminalId parameter). This will result in difficult to find bugs.
In the second example, it's impossible to pass a club when a terminal is expected - this would give you a compile time error.
Even so, I would still look at
string invoice. Is an invoice really a string? What does
amount mean? This is more likely a monetary value.
You mentioned in your question "whats sent over-the-wire are just the ids.". This is correct, but don't let this requirement muddy your domain.
The best explanation I've seen in favour of this approach was in rule 3 of Object Calisthenics:
An int on its own is just a scalar, so it has no meaning. When a method takes an int as a parameter, the method name needs to do all of the work of expressing the intent. If the same method takes an Hour as a parameter, it’s much easier to see what’s going on. Small objects like this can make programs more maintainable, since it isn’t possible to pass a Year to a method that takes an Hour parameter. With a primitive variable the compiler can’t help you write semantically correct programs. With an object, even a small one, you are giving both the compiler and the programmer additional info about what the value is and why it is being used.
The answer is context dependent.
If the client is expected to have all those objects already available, I'd use the object parameters. Otherwise, their code will look more convoluted than it needs to be. (E.g. they will have calls like
club.getId(), for example.)
If the client will only have the ids available easily, then maybe the second approach is better, as you might not want the client to have to assemble/load all those objects if you really only need the ids.
An option is to provide both methods, so the client can choose which one to use (given that this does not clutter your API)
In general the object parameters are more extensible, since if in the future you need another piece of data to do the work, you do not need to introduce another method that takes that extra info.
Lastly, your method signatures should not be dictated by the specifics of what the method does (in your case, what exactly goes over the wire). The API should abstractly make sense so if implementation changes, you are not screwed.
There's no right answer to this one. Either option could be right for the job. Well nearly any way, the invoice argument raised a furrow on my brow, I don't have a clue what that is from reading the code.
If you send an id, then both systems need to be tightly coupled at to what that represents. ClubID is key in the clubs table. More to the point both caller and callee need to agree what the Clubs table is called and which database it's in. If you don't want to or can't impose that constraint, then you'd pass the object using some common description, native, serialized, xml, name = value whatever, an ini file:)
That as you identified will cost you "over the wire". Avoiding that by just sending the identifier costs you elsewhere. So which one hurts you the least, now (or may be later...) is the indicator of good vs bad.
Two main pieces to the question help us define the preferred option:
whats sent over-the-wire are just the ids.
...and from a comment...
So the second approach is preffered? even if there is a club object with just the id property filled?
To answer the first quote: As other people have commented, the answer is always based on context. With that in mind, we should re-frame this to:
Having said that, it makes it fairly clear that using ids for parameters as opposed to objects is the correct thing to do. At least, based on the details you were willing to share with us. :)
To address the second quote: Sparsely populated objects are often a code smell. Again, this is contextual and may be appropriate in your code base. But as you already mentioned, passing an id makes it clear that's all you have. An object with only the id populated is simply an int masquerading as an object.
At any rate, my goal here was to make it clear that given what we know, option 1 (passing ids) is the correct thing to do until we have further details informing us otherwise.