J'ai soumis une demande que j'ai écrite à d'autres architectes pour la révision du code. L'un d'eux m'a presque immédiatement répondu et m'a dit "N'utilisez pas static
. Vous ne pouvez pas écrire de tests automatisés avec des classes et des méthodes static
. static
est à éviter . "
J'ai vérifié et entièrement 1/4 de mes classes sont marquées static
. J'utilise static
lorsque je ne vais pas créer une instance d'une classe car la classe est une seule classe globale utilisée dans tout le code.
Il a ensuite mentionné quelque chose impliquant des techniques de moquerie, IOC/DI qui ne peuvent pas être utilisées avec du code statique. Il dit qu'il est regrettable que les bibliothèques tierces soient statiques en raison de leur non-testabilité.
Cet autre architecte a-t-il raison?
mise à jour: voici un exemple:
APIManager
- cette classe conserve les dictionnaires des API tierces que j'appelle avec la prochaine heure autorisée. Il applique les limites d'utilisation des API que beaucoup de tiers ont dans leurs conditions de service. Je l'utilise partout où j'appelle un service tiers en appelant Thread.Sleep(APIManager.GetWait("ProviderXYZ"));
avant de passer l'appel. Tout ici est thread-safe et cela fonctionne très bien avec le TPL en C #.
Cela dépend si les classes statiques maintiennent l'état ou non. Personnellement, je n'ai aucun problème avec les fonctions sans état regroupées dans une classe statique.
Il est trop général à ce sujet. Il a raison, ça gêne les tests. Cependant, les classes et les méthodes static
ont leur place et cela dépend vraiment du contexte. Sans exemples de code, vous ne pouvez pas vraiment le dire.
J'utilise statique lorsque je ne vais pas créer d'instance d'une classe car la classe est une seule classe globale utilisée dans tout le code.
Cela peut être une forte odeur de code. Pourquoi utilisez-vous les cours? Pour conserver des données? Pour accéder à une base de données? Alors il a raison. Dans ce cas, vous devez rechercher l'injection de dépendances, car une telle classe statique est en fait un singleton implicite.
Si vous les utilisez pour des méthodes d'extension ou des aides qui ne changent pas l'état et fonctionnent uniquement sur les paramètres que vous fournissez, ceux-ci sont généralement corrects.
J'ai vérifié et entièrement 1/4 de mes classes sont marquées "statiques". J'utilise statique lorsque je ne vais pas créer d'instance d'une classe car la classe est une seule classe globale utilisée dans tout le code.
La meilleure chose à faire est d'essayer de tester votre code à l'unité. Essayez de concevoir des tests reproductibles, indépendants, simples et testez une seule méthode à la fois. Essayez d'exécuter vos tests dans un ordre aléatoire différent. Pouvez-vous obtenir une construction "verte" stable?
Si oui, c'est un point valable pour défendre votre code. Si toutefois vous rencontrez des difficultés, vous devriez peut-être opter pour des méthodes basées sur des instances.
Les réponses déjà publiées couvrent de très bons points, mais il semble en manquer une:
Les champs statiques ne sont jamais collectés.
C'est vraiment important si vous avez une application avec beaucoup de contraintes de mémoire, et ce modèle peut être très courant lorsque les gens essaient d'implémenter un cache.
Les fonctions statiques ne sont pas aussi mauvaises, mais tout le monde a déjà couvert cela suffisamment en détail.
L'un des avantages de l'IoC/DI est que la plupart des interactions entre les classes sont négociées entre les interfaces. Cela facilite les tests unitaires car les interfaces peuvent être simulées automatiquement ou semi-automatiquement, et donc chacune des pièces peut être testée pour les entrées et les sorties. De plus, au-delà de la testabilité, mettre des interfaces entre tout vous permet d'avoir le code le plus modulaire possible - vous pouvez facilement remplacer une implémentation sans trop vous soucier de bousiller les dépendances.
Étant donné que C # n'a pas de métaclasses, une classe ne peut pas implémenter une interface à l'aide de fonctionnalités statiques, donc les fonctionnalités statiques des classes finissent par faire tout effort pour implémenter un modèle d'objet IoC/DI pur. Autrement dit, vous ne pouvez pas créer de maquette pour les tester et vous devez créer de véritables dépendances.
Si votre entreprise/projet est fortement investi dans la réalisation de l'IoC, cela est bien sûr une préoccupation raisonnable, et la douleur que vous traversez est pour le gain de tous. D'un point de vue architectural, cependant, je ne pense pas personnellement qu'un modèle devrait être suivi jusqu'à la tombe. Il y a certaines choses qui ont du sens à implémenter en utilisant des méthodes statiques - la stratégie de conception singleton, par exemple. Je suis moins enclin aux classes statiques moi-même parce que je pense qu'elles ont tendance à perdre les avantages d'OO, mais il y a des moments où une classe de bibliothèque est probablement une expression plus naturelle de quelque chose qu'un moteur.
Commenter me rappelle les méthodes d'extension, qui doivent bien sûr être dans des classes statiques en C #. C'est légitime et c'est un exemple de la façon dont l'IoC pur ne fonctionne pas très bien en C #, du moins si vous essayez de profiter de l'étendue du langage.
Les classes statiques sont parfois mal utilisées et devraient être:
Il peut également s'agir d'une fonction dite "utilitaire" et d'une partie d'une classe utilitaire. Les classes utilitaires sont des classes qui contiennent uniquement des méthodes statiques et servent de fonctions d'assistance sans aucun contexte.
Les méthodes statiques sont bien à utiliser et ont une place légitime dans la programmation. Il semble que votre architecte dispose d'un cadre de test qui ne prend pas totalement en charge les méthodes statiques. Si votre code fait partie d'un projet plus vaste, il est important de respecter les directives des architectes. Cependant, ne laissez pas ce projet vous dissuader d'utiliser des méthodes statiques lorsque cela est approprié.
J'utilise des propriétés statiques pour des choses communes à toutes les instances d'une classe. Et j'utilise des méthodes statiques pour obtenir des groupes d'objets de classe. Je ne suis en aucun cas un expert mais cela a fonctionné pour moi jusqu'à présent.
Exemple PHP:
class vendorData {
private static $data_table = 'vendor_data'; // static property
private $id; // instance property
private $name; // instance property
public function __construct($vendor_id) {
if(!self::validId($vendor_id) ) { // static method
return false; // id doesn't exist
}
$this->id = $vendor_id; // id has been validated
$this->getProperties(); // object method
}
private static function validId($vendor_id) {
// send db query to find if the id exists
// return true/false;
}
private function getProperties() { // object method
$sql = "SELECT * FROM `{self::$data_table}` // using static property
WHERE `id` = {$this->id}"; // using object instance property
// get resultset
foreach($result as $property => $value) {
$this->$property = $value; // object instance properties all set
}
}
// and here
public static function getBy($property,$value) { // static method to return object array
$sql = "SELECT `id` FROM `{self::$data_table}` // using static property
WHERE `$property` = '$value'";
// send query, get $ids array
$obj_array = array();
foreach($ids as $id) {
// create array of current class objects using special static keyword
// meaning of static here is different than in property/method declarations
$obj_array[$id] = new static($id);
}
return $obj_array;
}
}
Je dirai que les principes qu'ils ont sont corrects mais l'énoncé (n'utilisez pas de statique) peut être faux. Quelle est la couverture de votre code? si le nombre est élevé et que vous êtes à l'aise avec les tests unitaires de votre application, vous êtes d'accord. Sinon, je suggère de revoir le code. Vous pouvez trouver que les classes statiques sont la raison ou non, cela dépendra de beaucoup de choses.