web-dev-qa-db-fra.com

Quand une méthode doit-elle dépendre d'une source de données et de ne pas avoir déclaré un paramètre?

On m'a assigné une revue de code à l'un de mes collègues. J'ai posé ce qui suit, que je voulais partager ici afin d'apprendre si je suis bien ou mal.

Considérez l'extrait de code suivant:

public void DoSomethingWithList()
{
   var list = AnotherClass.GetList();
   var itemsToRemove = list.Where(...);
   list.Remove(itemsToRemove);
   .
   .
   .
}

Je soutiens que la méthode ci-dessus devrait avoir list déclaré comme une dépendance (en d'autres termes, déclarée par paramètre dans la signature de la méthode). Pourquoi ? Suivre le principe de responsabilité unique et/ou à des fins de test. (Je pense que c'est le cas pour un appel de classe externe, mais même si GetList était une méthode privée à l'intérieur de la même classe, je revendiquerais toujours la même chose - même si le seul motif serait la clarté du code (appelez-le " Butle Clarity ") ").

Mon collègue dit que ce n'est pas le cas. Avoir à appeler cette fonction chaque fois que toujours le même paramètre est lourde.

Je comprends évidemment cela comme un développeur, mais j'ai insisté pour que les principes d'ingénierie logicielle " visant à la maintenabilité du code " devraient prévaloir sur " La paresse du développeur "(moi-même inclus!)

Je comprends qu'il n'y a pas de règles balulées, mais néanmoins qu'ils ne devraient être cassés que pour une très bonne raison.

Je me demande si je me trompe. Et si je ne suis pas, quels autres aspects que je n'ai pas mentionnés auraient dû être.

1
Veverke

Cette méthode est quelque peu difficile à tester car elle ne prend rien dans ni rien ne le retourne. Donc, pour tester vous auriez besoin de savoir quelque chose sur les internes de la méthode, c'est ce qui est modifié en interne.

Tester cela implique de faire appel à cette méthode et d'inspecter les résultats de la méthode unc.Classes.getlist (). Cela pourrait également impliquer une certaine configuration pour créer initialement la liste afin que vous puissiez voir les résultats de Dosomethlist ().

Ce n'est pas idéal mais faisable.

Transférer dans la liste rend la fonction plus explicite.

DoSomethingWithList(List theList)

Si je regarde désormais que je peux supposer que la liste peut être modifiée d'une manière ou d'une autre. Directement en avant pour écrire un test.

Dosomethingwithlist () n'a pas cette clarté.

Comme Erik suggère, essayez-le des deux manières et découvrez ce qui est plus facile à lire, à comprendre et à tester. À la fin de la journée, ce qui compte.

1
Jon Raynor

Le problème avec l'approche de votre ami est qu'il est impossible de stiper l'appel à GetList() pour des tests d'unité, car il s'agit d'une méthode statique. Vous ne pourrez pas tester DoSomethingWithList sans tester aussi GetList. Cela pourrait constituer un problème grave pour vos tests automatisés si le magasin de support pour GetList n'est pas disponible sur l'environnement de lit d'essai.

Le chemin facile vers l'avant est de convertir AnotherClass à une classe instanciée et de l'injecter. Vous l'enregistrez ensuite avec votre conteneur IOC comme un singleton afin que tout le monde partage la même copie.

interface IAnotherClass 
{
    List<Foo> GetList();
}

class AnotherClass : IAnotherClass
{
    private IExpensiveDatabaseConnection _singleInstance; 

    public List<Foo> GetList()
    {
        return _singleInstance.GetList();
    }
}



class Bar
{
    protected readonly IAnotherClass _anotherClass;

    public Bar(IAnotherClass anotherClass)
    {
        _anotherClass = anotherClass;
    }

    public void DoSomethingWithList()
    {
        var list = _anotherClass.GetList();
        var itemsToRemove = list.Where(...);
        list.Remove(itemsToRemove);
    }
}

Bien sûr, si vous allez faire cela, vous devrez peut-être refactuer un autre code pour la correspondre. S'il s'agit d'une base de code héritée avec beaucoup d'appels de méthode statiques, il pourrait être plus rentable pour continuer à utiliser l'ancien motif.

0
John Wu