A lista de parâmetros de um método deve conter objetos ou identificadores de objeto?

10

Nossas equipes estão tendo a seguinte discussão:

Digamos que temos os dois métodos a seguir:

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);

o que é enviado por fio são apenas os IDs.

um lado diz que o primeiro método está correto, porque só temos os IDs de terminal e clube e deve ficar claro que não temos mais nada, essa é a minha abordagem.

o outro lado diz que o segundo método está correto porque é mais flexível.

Estamos familiarizados com a ideia de parâmetro de objeto, o outro lado também pensa que o parâmetro de objeto deve ter os objetos como propriedades.

Qual é a abordagem correta?

Talvez haja uma terceira abordagem ainda melhor?

Mithir
fonte
? O que ...........
James
11
Contexto? Serviço de internet? WCF?
CodesInChaos
11
@ James - desculpe, eu escrevi esta pergunta meio rápido, você pode me dizer o que não está entendido para que eu possa editá-lo?
Mithir
@CodesInChaos os métodos são realmente métodos BL
#

Respostas:

10

A resposta depende do contexto.

Se o cliente tiver todos esses objetos disponíveis , eu usaria os parâmetros do objeto. Caso contrário, o código deles parecerá mais complicado do que precisa. (Por exemplo, eles terão chamadas como club.getId(), por exemplo.)

Se o cliente tiver apenas os IDs disponíveis com facilidade, talvez a segunda abordagem seja melhor, pois talvez você não queira que o cliente tenha que montar / carregar todos esses objetos se realmente precisar apenas dos IDs.

Uma opção é fornecer os dois métodos , para que o cliente possa escolher qual deles usar (já que isso não atrapalha sua API)

Em geral, os parâmetros do objeto são mais extensíveis, pois se no futuro você precisar de outro dado para fazer o trabalho, não precisará introduzir outro método que utilize essas informações extras.

Por fim, as assinaturas do seu método não devem ser ditadas pelas especificidades do que o método faz (no seu caso, o que exatamente ocorre por fio). A API deve fazer sentido abstratamente, portanto, se a implementação mudar, você não está ferrado.

c_maker
fonte
3
+1 Eu acrescentaria apenas mais um ponto: para métodos chamados remotamente ("over the wire"?), A passagem de objetos pode levar à serialização profunda de uma extensa árvore de objetos. Os IDs são excelentes substitutos para objetos quando você está preocupado com o tamanho de uma carga útil de chamada remota.
Ross Patterson
11
Nesse caso, parece que você está acoplado a um conjunto de abstrações, então passar IDs não comprará mais flexibilidade e provavelmente aumentará a probabilidade de você reverter parâmetros. A questão é com que precisão o código do método está associado às abstrações pelas quais estou passando? Por exemplo, um método como "validateCreditCard (string card, string cvi)" provavelmente deve ficar com primitivas para evitar ser fortemente associado a algum tipo de objeto CreditCard.
Ipaul 03/03
Eu me encontrava no meio e usava uma interface na lista de parâmetros. Então seu clube pode ser um clube, mas também uma sauna no futuro.
Pieter B
13

A primeira abordagem é indicativa de obsessão primitiva . Como você está passando ints e strings, é muito fácil para o programador cometer um erro (por exemplo, passando um clubId para o parâmetro terminalId). Isso resultará em erros difíceis de encontrar.

No segundo exemplo, é impossível aprovar um clube quando um terminal é esperado - isso geraria um erro de tempo de compilação.

Mesmo assim, eu ainda olharia string invoice. Uma fatura é realmente uma string? O que amountsignifica isso ? É mais provável que seja um valor monetário.

Você mencionou na sua pergunta "o que é enviado por fio são apenas os IDs". Isso está correto, mas não deixe esse requisito enlamear seu domínio.

A melhor explicação que vi a favor dessa abordagem foi na regra 3 da Object Calisthenics :

Um int por si só é apenas um escalar, por isso não tem significado. Quando um método usa int como parâmetro, o nome do método precisa executar todo o trabalho de expressar a intenção. Se o mesmo método demorar uma hora como parâmetro, é muito mais fácil ver o que está acontecendo. Objetos pequenos como esse podem tornar os programas mais fáceis de manter, pois não é possível passar um ano para um método que usa o parâmetro Hour. Com uma variável primitiva, o compilador não pode ajudá-lo a escrever programas semanticamente corretos. Com um objeto, mesmo que pequeno, você fornece informações adicionais ao compilador e ao programador sobre qual é o valor e por que ele está sendo usado.

MattDavey
fonte
Então a segunda abordagem é preferida? mesmo se houver um objeto club com apenas a propriedade id preenchida?
Mithir
Este parece ser um blog aleatório. Não há evidências para dizer o que é preferido. Quem se importa realmente com o que é preferido? Faça o que funciona para você
James
@ James Não há resposta definitiva para essa pergunta, principalmente porque o OP não nos deu muito contexto. Qualquer pessoa que afirme categoricamente que uma abordagem é preferível à outra está fazendo um desserviço ao OP. Não é tão preto e branco.
precisa saber é o seguinte
11
@ James Apenas mencionei que a primeira abordagem facilita muito a introdução de bugs difíceis de encontrar. Não estou dizendo que tipos primitivos são ruins, mas o objetivo dos tipos primitivos é criar tipos de domínio significativos. Usá-los fora desse contexto é a própria definição do cheiro primitivo do código de obsessão.
precisa saber é o seguinte
5
@ James: O que MattDavey disse é um fato bem estabelecido. Ele não está dizendo que tipos nativos são ruins, o que ele está dizendo é o seguinte: someMethod (int, int, int, string, decimal) é muito mais difícil de entender e usar por um cliente do que someMethod (Club, Terminal, Card, String , decimal)
c_maker 03/03
2

Não há resposta certa para este. Qualquer uma das opções pode estar certa para o trabalho. Bem, de qualquer maneira, o argumento da fatura levantou um sulco na minha testa, eu não tenho idéia do que é isso ao ler o código.

Se você enviar um ID, os dois sistemas precisarão ser fortemente acoplados ao que isso representa. O ClubID é a chave na tabela de clubes. Mais especificamente, o chamador e o destinatário precisam concordar como a tabela Clubs é chamada e em qual banco de dados está. Se você não deseja ou não pode impor essa restrição, passaria o objeto usando alguma descrição comum, nativo, serializado, xml, nome = valor qualquer que seja, um arquivo ini :)

Isso, como você identificou, custará "over the wire". Evitar isso, basta enviar o identificador para você em outro lugar. Então, qual deles te machuca menos agora (ou pode ser mais tarde ...) é o indicador de bom versus ruim.

Tony Hopkinson
fonte