Eu tenho um colega sentado ao meu lado que projetou uma interface como esta:
public interface IEventGetter {
public List<FooType> getFooList(String fooName, Date start, Date end)
throws Exception;
....
}
O problema é que, no momento, não estamos usando esse parâmetro "end" em nenhum lugar do nosso código, ele está lá porque podemos ter que usá-lo em algum momento no futuro.
Estamos tentando convencê-lo de que é uma má idéia colocar parâmetros em interfaces que não são úteis no momento, mas ele continua insistindo que muito trabalho será necessário se implementarmos o uso da data "final" em algum momento depois e tem que adaptar todo o código então.
Agora, minha pergunta é: existem fontes que estão lidando com um tópico como este de gurus de codificação "respeitados" aos quais podemos vinculá-lo?
end
parâmetro para esse objeto e até mesmo de TI padrão, a fim de não quebrar o códigonull
,. As classes de implementação podem substituir, conforme necessário.IQueryable
(só pode tomar certas expressões) para o código fora do DALRespostas:
Convide-o a aprender sobre YAGNI . A parte Racional da página da Wikipedia pode ser particularmente interessante aqui:
Outros argumentos possíveis:
“80% do custo vitalício de um software é destinado à manutenção” . Escrever código na hora certa reduz o custo da manutenção: é preciso manter menos código e concentrar-se no código realmente necessário.
O código fonte é escrito uma vez, mas é lido dezenas de vezes. Um argumento adicional, não usado em lugar algum, levaria à perda de tempo para entender por que existe um argumento que não é necessário. Dado que esta é uma interface com várias implementações possíveis, torna as coisas apenas mais difíceis.
O código-fonte deve ser auto-documentado. A assinatura real é enganosa, pois um leitor pensaria que isso
end
afeta o resultado ou a execução do método.As pessoas que escrevem implementações concretas dessa interface podem não entender que o último argumento não deve ser usado, o que levaria a diferentes abordagens:
Eu não preciso
end
, então simplesmente ignorarei seu valor,Eu não preciso
end
, então lançarei uma exceção, se não fornull
,Não preciso
end
, mas tentarei usá-lo de alguma forma,Escreverei muito código que poderá ser usado mais tarde, quando
end
necessário.Mas lembre-se de que seu colega pode estar certo.
Todos os pontos anteriores se baseiam no fato de que a refatoração é fácil, portanto, adicionar um argumento posteriormente não exigirá muito esforço. Mas essa é uma interface e, como interface, pode ser usada por várias equipes que contribuem para outras partes do seu produto. Isso significa que alterar uma interface pode ser particularmente doloroso; nesse caso, o YAGNI não se aplica aqui.
A resposta do hjk fornece uma boa solução: adicionar um método a uma interface já usada não é particularmente difícil, mas em alguns casos, também tem um custo substancial:
Algumas estruturas não suportam sobrecargas. Por exemplo, e se bem me lembro (me corrija se estiver errado), o WCF do .NET não suporta sobrecargas.
Se a interface tiver muitas implementações concretas, adicionar um método à interface exigiria passar por todas as implementações e adicionar o método também.
fonte
(algum tempo depois)
É tudo o que você precisa, sobrecarregando o método. O método adicional no futuro pode ser introduzido de forma transparente, sem afetar as chamadas para o método existente.
fonte
end
parâmetro é desnecessário agora e passou a usar oend
método -less em todo o (s) projeto (s), a atualização da interface é a menor das preocupações, pois torna-se necessário atualizar o classes de implementação. Minha resposta está voltada especificamente para a parte "adaptar todo o código", porque parece que o colega estava pensando na mesma linha de ter que atualizar os chamadores do método original em todo o projeto para introduzir um terceiro parâmetro padrão / falso .Os apelos à autoridade não são particularmente convincentes; melhor apresentar um argumento válido, independentemente de quem o tenha dito.
Aqui está uma reductio ad absurdum que deve convencer ou demonstrar que seu colega de trabalho está preso em estar "certo", independentemente da sensibilidade:
O que você realmente precisa é
Você nunca sabe quando terá que se internacionalizar para o Klingon, então é melhor cuidar dele agora, porque isso exigirá muito trabalho para se adaptar e os Klingons não são conhecidos por sua paciência.
fonte
You never know when you'll have to internationalize for Klingon
. É por isso que você deve passar aCalendar
e deixar o código do cliente decidir se ele deseja enviar umGregorianCalendar
ou aKlingonCalendar
(aposto que alguns já o fizeram). Duh. :-pStarDate sdStart
eStarDate sdEnd
?Date
!HebrewDate start
eHebrewDate end
.Do ponto de vista da engenharia de software, acredito que a solução adequada para esse tipo de problema está no padrão do construtor. Esse é definitivamente um link dos autores do 'guru' para o seu colega http://en.wikipedia.org/wiki/Builder_pattern .
No padrão do construtor, o usuário cria um objeto que contém os parâmetros. Este contêiner de parâmetro será passado para o método Isso cuidará de qualquer extensão e sobrecarga de parâmetros que seu colega precisaria no futuro, ao mesmo tempo em que tornará tudo muito estável quando forem necessárias alterações.
Seu exemplo se tornará:
fonte
IEventGetter
paraISearchFootRequest
. Em vez disso, sugiro algo comopublic IFooFilter
com membropublic bool include(FooType item)
que retorna se deve ou não incluir o item. Então implementações de interface indivíduo pode decidir como eles vão fazer isso de filtragemVocê não precisa agora, então não adicione. Se você precisar mais tarde, estenda a interface:
fonte
Nenhum princípio de design é absoluto; portanto, embora eu concorde com as outras respostas, pensei em interpretar o advogado do diabo e discutir algumas condições sob as quais consideraria aceitar a solução do seu colega:
Now()
, a adição de um parâmetro remove um efeito colateral, o que traz benefícios para o armazenamento em cache e o teste de unidade. Talvez isso permita uma implementação mais simples. Ou talvez seja mais consistente com outras APIs no seu código.Dito isto, na minha experiência, o maior corolário de YAGNI é YDKWFYN: Você não sabe de que forma precisará (sim, acabei de criar esse acrônimo). Mesmo que a necessidade de algum parâmetro de limite possa ser relativamente previsível, ele pode assumir a forma de um limite de página, ou número de dias ou um valor booleano que especifica o uso da data de término em uma tabela de preferências do usuário ou de várias outras coisas.
Como você ainda não possui o requisito, não há como saber que tipo de parâmetro deve ser. Muitas vezes, você acaba tendo uma interface estranha que não é a mais adequada para seus requisitos ou precisando alterá-la de qualquer maneira.
fonte
Não há informações suficientes para responder a essa pergunta. Depende do que
getFooList
realmente faz e como faz.Aqui está um exemplo óbvio de um método que deve suportar um parâmetro adicional, usado ou não.
A implementação de um método que opera em uma coleção em que você pode especificar o início, mas não o final da coleção, costuma ser boba.
Você realmente precisa analisar o problema em si e perguntar se o parâmetro não faz sentido no contexto de toda a interface e realmente qual a carga que o parâmetro adicional impõe.
fonte
Receio que seu colega possa ter um argumento válido. Embora sua solução não seja realmente a melhor.
Pela interface proposta, fica claro que
está retornando instâncias encontradas dentro de um intervalo de tempo. Se os clientes atualmente não usam o parâmetro final, isso não altera o fato de que esperam instâncias encontradas dentro de um intervalo de tempo. Apenas significa que atualmente todos os clientes usam intervalos abertos (do início à eternidade)
Portanto, uma interface melhor seria:
Se você fornecer um intervalo com um método estático de fábrica:
os clientes nem sentirão a necessidade de especificar um horário de término.
Ao mesmo tempo, sua interface transmite mais corretamente o que faz, pois
getFooList(String, Date)
não comunica que isso lida com um intervalo.Observe que minha sugestão segue o que o método atualmente faz, não o que deveria ou poderia fazer no futuro e, como tal, o princípio YAGNI (que é muito válido de fato) não se aplica aqui.
fonte
Adicionar um parâmetro não utilizado é confuso. As pessoas podem chamar esse método, assumindo que esse recurso funcione.
Eu não adicionaria. É trivial adicioná-lo posteriormente usando uma refatoração e consertando mecanicamente os sites de chamada. Em uma linguagem de tipo estaticamente, isso é fácil de fazer. Não é necessário adicioná-lo avidamente.
Se não é uma razão para ter esse parâmetro, você pode evitar a confusão: Adicionar uma declaração na implementação dessa interface para impor que este parâmetro ser passado como o valor padrão. Se alguém acidentalmente usar esse parâmetro, pelo menos, ele notará imediatamente durante o teste que esse recurso não foi implementado. Isso elimina o risco de colocar um bug na produção.
fonte