Protegendo os não iniciados (desenvolvedor) dos genéricos

4

É aceitável ter um parâmetro genérico fictício na lista de parâmetros para salvar os consumidores de métodos da necessidade de especificar argumentos de tipo? Por exemplo -

public T Generate<T>(int paramForInstance) where T : MyClass {
    return MyClass.SomeFactoryMethod<T>(paramForInstance);
}

//calling code needs to specify type
MyDerivedClass instance = Generate<MyDerivedClass>(5);

public T Generate<T>(int paramForInstance, T dummy) where T : MyClass {
    return MyClass.SomeFactoryMethod<T>(paramForInstance);
}

//calling code needs to provide a "sample" to enable type inference
MyDerivedClass instance = null;
instance = Generate(5,instance);

A suposição aqui é que, se junior outros desenvolvedores da equipe não precisarem pensar em genéricos, é menos provável que eles desistam.

Um pouco de fundo (sinta-se à vontade para pular isso)

Algumas semanas atrás, um tipo de desenvolvedor de gerenciamento em minha equipe se assustou quando viu o código (meu código) que se parecia com isso:

//conversion methods, using generics
private static TResult? IfNotDangerous<TResult>
  (SomeType firstThing, string name, Func<object, TResult?> conversion) 
  where TResult : struct
{
    return IfNotDangerous(firstThing, name, 
          (any, dummy) => conversion(any), (TResult?)null);
}

private static TResult IfNotDangerous<TResult>
  (SomeType firstThing, string name, Func<object, TResult, TResult> conversion,
  TResult defaultValue)
{
    if (firstThing == null) return defaultValue;
    if (!firstThing.Contains(name)) return defaultValue;
    if (firstThing[name] == DangerousValue) return defaultValue;
    return conversion(firstThing[name], defaultValue);
}

A queixa que ele tinha era: "Por que você está usando uma struct ?! Isso é tão pesado em recursos! E o que 'where' significa? Ninguém no desenvolvimento sênior sabe o que isso faz - Eu perguntei a todos eles! "

Depois de superar minha autopiedade, descobri que não usava genéricos para esse método em particular. O apaziguamento foi alcançado. Mas eu gostaria de evitar problemas no futuro, se possível.

EDITAR

Eu aprecio todo o encorajamento, mas a questão não era "eu deveria procurar outro lugar para o trabalho?" - foi "isso é uma solução útil?"

    
por sq33G 18.12.2011 / 09:18
fonte

7 respostas

30

É triste ver programadores que não se movem com os tempos.

O fato é que os genéricos têm sido parte do C # e do .NET desde a versão 2 e do LINQ desde a versão 3. Não são mais novas técnicas de ponta.

Em vez de "Protegê-los", você deve estar ensinando eles. Comece um tutorial semanal (durante o almoço, se você não tiver buy-in) para todos os desenvolvedores interessados em permanecer atualizados.

O fato é que, se eles trouxerem um novo sênior, as chances são de que eles também usariam genéricos e LINQ. Manter esses "ocultos" ou não usá-los é um desserviço aos outros desenvolvedores e à empresa.

Se lhe disserem para não usar generics e LINQ, eu infelizmente concluiria que é hora de procurar um emprego onde os desenvolvedores não se aleijam.

Atualização:

Já que você não acha que a resposta acima responde à pergunta "isso é uma solução útil?" Eu responderei agora:

Não, não é. É um abuso de genéricos e tem muita "mágica" - é até mesmo menos compreensível que o código genérico direto e, se algum de seus colegas tiver que se aprofundar nele, eles não poderão descobrir isso.

O fato de que ele funciona e faz o que você quer (ocultar o uso de genéricos) é além do ponto. É opaco e até mesmo o uso não é idiomático (dando um "protótipo" à função para que ele funcione).

    
por 18.12.2011 / 10:55
fonte
4

A partir do momento que eles não permitem que você use todos os recursos da linguagem (uma língua que, eu presumo, foi escolhida por eles, não você), vale tudo. Isso é aceitável? Claro que é. Eu nunca faria uma coisa dessas, mas parece que você tem que fazer. E vai funcionar.

Mas se eu estivesse no seu lugar, eu daria tudo certo: eu definiria o nível de compatibilidade do compilador (nas opções do projeto) para que as construções de linguagem que considerassem inaceitáveis não pudessem compilar, o que significaria que o loja inteira seria codificação em C # 1.0. E eu começaria a procurar outro emprego.

    
por 18.12.2011 / 12:25
fonte
4

A maneira como vejo sua pergunta é a seguinte:

Should I write code which doesn't follow the standard conventions and will teach people who don't know generics bad habits, or should I use them the way they're intended to be used?

Visto dessa perspectiva, acho que responde a si mesmo.

Em resposta a "O que significa where ?" você poderia enviar um link de e-mail para link explicando que, embora MS tem claramente borked o link "Outras versões", a documentação das cláusulas where do VS2005 ainda é válida.

    
por 18.12.2011 / 15:13
fonte
2

A introspecção sobre se você está tornando o código muito complicado ou se é razoável esperar que os outros estejam prestes a entender e usar seu código é uma coisa boa. No entanto, neste snippet em particular

MyDerivedClass instance = null; 
instance = Generate(5, instance); 

Eu não gosto disso. Na minha opinião, isso não torna o código mais simples. E obviamente não é mais sucinto. Você não salvou o desenvolvedor de ter que especificar o tipo de classe para a chamada do método genérico, você simplesmente moveu onde está especificado. De qualquer maneira, você declarou explicitamente o tipo. Você também está me perguntando o que o método poderia estar fazendo com instance , por que estou reatribuindo, etc. (Lembre-se, alguém pode muito bem ser "novato" ou ter uma instância antes da chamada do método. ) Para um desenvolvedor experiente, isso pode não ser um problema. Para o júnior você está tentando se abrigar?

Não, eu optaria pelo que deveria ser simples o suficiente para raciocinar.

var instance = Generate<MyDerivedClass>(5); 

Você certamente deseja tornar o código tão fácil de ler, usar e decifrar quanto possível, mas criar sobrecargas com parâmetros degenerados provavelmente não é a solução.

(*) Recentemente me envolvi em ajudar a entrevistar candidatos para cargos na minha equipe atual. Vamos apenas dizer que os "desenvolvedores experientes" não são tão experientes quanto você e eu podemos desejar e eles podem acreditar. Esses desenvolvedores com 5, 8 e até 20 anos de experiência não entenderiam nem mesmo o seu snippet mais simples. Estas são pessoas que estão na indústria há anos, desenvolvem C # desde 1.1 ou 2.0. Eles também são pessoas que ainda não podem raciocinar sobre genéricos, sua coleção preferida ainda é ArrayList, eles não podem descrever adequadamente muito menos implementar comportamentos polimórficos, etc., eu não sei o que dizer. Talvez eles simplesmente não tenham sido empurrados para seus papéis anteriores. Talvez eles não sejam tão apaixonados pelo desenvolvimento ou resistentes a mudanças. Talvez eles sejam apenas culto de carga. Basta dizer que posso simpatizar com a sua situação.

    
por 19.12.2011 / 16:29
fonte
1

Eu acho que você absolutamente não deveria fazer isso.

Você não está realmente ajudando ninguém, mesmo que eu entenda o que você está tentando. Mas no final, você está impedindo a compreensão do sistema de tipo estático, ocultando algo fundamental. Quero dizer, não é como se estivéssemos falando de covariância / contravariância ou tipos de ordem superior aqui. Estes são simples, parâmetros de tipo de primeira ordem com restrições. Isso é algo que todo programador deve entender. Se eles não o fizerem, eles devem aprender, e eles realmente não estão dispostos a fazê-lo, eles devem codificar em uma linguagem dinâmica (ou ser demitido se você me perguntar).

O ponto dos sistemas de tipos estáticos é codificar seu conhecimento de domínio para a semântica de linguagem. Quanto mais poderoso for o sistema de tipos, mais difícil será aprender, mas mais segurança você obterá automaticamente. Este é um investimento de talvez meio dia de tutoria, no máximo, que começará a pagar dentro de algumas semanas. Sua base de código se tornará mais robusta, portanto mais flexível e, portanto, o custo de responder às mudanças de requisitos e depuração em geral será reduzido consideravelmente.

Se você realmente acha que deve fazer isso, então eu acho que você deve fazer algo como (não sei como isso deve realmente parecer em C #):

public T Generate<T>(Class<T> theClass, int paramForInstance) where T : MyClass {
    return MyClass.SomeFactoryMethod<T>(paramForInstance);
}
//which should make this possible
var instance = Generate(MyDerivedClass, 5);

A questão é que você está virtualmente usando os parâmetros de tipo aqui. Uma vez que seus colegas de trabalho aceitem isso, fazer a transição para Generate<MyDerivedClass>(5) é apenas um pequeno passo para eles, mas um salto gigantesco para sua equipe;)

    
por 19.12.2011 / 13:35
fonte
1

Uma coisa que eu acho que você tem que estar ciente de estar em uma "equipe" de desenvolvimento é que seu código precisa ser legível e mantido pelos outros. Concordo com as respostas para ensinar e levar a equipe adiante, mas até que isso aconteça, você precisa se ater a construções que todos entendam e estejam confortáveis.

    
por 19.12.2011 / 15:38
fonte
0

O parâmetro gerneric no seu código não é "fictício", pois é usado como tipo de retorno. Este é um padrão comum também usado pela Microsoft na BCL. Exemplo encontrado em

System.Data.DataRowExtensions

public static T Field<T>(this System.Data.DataRow row, string columnName)
    
por 18.12.2011 / 16:24
fonte

Tags