Il existe un modèle assez courant utilisé dans .NET pour tester les capacités d'une classe. Ici, je vais utiliser la classe de flux comme exemple, mais le problème s'applique à toutes les classes qui utilisent ce modèle.
Le motif consiste à fournir une propriété booléenne appelée CanXXX pour indiquer que la capacité XXX est disponible sur la classe. Par exemple, la classe de flux contient des propriétés Canread, CANWRITE et CANSEEK pour indiquer que les méthodes de lecture, d'écriture et de recherche peuvent être appelées. Si la valeur des propriétés est false, appelez la méthode correspondante entraînera une notaupportedexception étant lancée. P>
de la documentation MSDN sur la classe de flux: P>
En fonction de la source de données sous-jacente ou du référentiel, les flux ne peuvent prendre en charge que certaines de ces fonctionnalités. Une application peut interroger un flux pour ses capacités en utilisant les propriétés Canread, CANWRITE et CANSEEK. EM> P> blockQuote>
et documentation pour la propriété Canreade: P>
Lorsque remplacé dans une classe dérivée, obtient une valeur indiquant si le flux actuel prend en charge la lecture. em> p>
Si une classe dérivée du flux ne prend pas en charge la lecture, les appels vers les méthodes de lecture, de lecture et de beginread lancer une notaupportedexception. em> p> blockQquote>
Je vois beaucoup de code écrit dans les lignes suivantes: p>
xxx pré> Notez qu'il n'y a pas de code de synchronisation, dites, pour verrouiller le flux L'objet de quelque manière que ce soit - d'autres threads peuvent y accéder ou des objets qu'il références. Il n'y a pas non plus de code pour attraper une notaupportedexception. P>
La documentation MSDN n'indique pas que la valeur de la propriété ne peut pas changer avec le temps. En fait, la propriété CANSEEK change de faux lorsque le flux est fermé, démontrant la nature dynamique de ces propriétés. En tant que tel, il n'y a pas de garantie contractuelle que l'appel à lire () dans l'extrait de code ci-dessus ne jettera pas une notaupportedexception. P>
Je pense qu'il y ait beaucoup de code là-bas qui souffre de ce problème potentiel. Je me demande comment ceux qui ont identifié cette question l'ont abordé. Quels modèles de conception sont appropriés ici? P>
J'apprécierais également les commentaires sur la validité de ce modèle (les paires CanXXX, XXX ()). Pour moi, au moins dans le cas de la classe de flux, cela représente une classe / interface qui tente de faire trop et devrait être divisé en pièces plus fondamentales. L'absence d'un contrat documenté serré rend l'essai impossible et la mise en œuvre encore plus difficile! P> p>
6 Réponses :
flux.Canread vérifie simplement si le flux sous-jacent a la possibilité de lire. Cela ne dit rien de savoir si la lecture réelle sera possible (E.G. Erreur de disque). P>
Il n'est pas nécessaire d'attraper notimplementaedException si vous avez utilisé des classes de lecteur * car ils supportent tous la lecture. Seul * écrivain aura Canread = Faux et jette cette exception. Si vous savez que le flux prend en charge la lecture (par exemple, vous avez utilisé SweetReader), IMHO Il n'est pas nécessaire de faire une vérification supplémentaire. P>
Vous devez toujours attraper des exceptions puisque toute erreur lors de la lecture va les jeter (E.g. Erreur de disque). p>
Notez également que tout code qui n'est pas documenté comme thread-coffre-fort n'est pas le fil-de-vin. Habituellement, les membres statiques sont en sécurité, mais les membres de l'instance ne sont pas - il est nécessaire de vérifier la documentation pour chaque classe. P>
"Il n'est pas nécessaire d'attraper notimplementedexception si vous avez utilisé des classes lecteurs" (je pense que vous voulez dire notsupportedexpection). Qu'en est-il d'un cadre qui ne traite que de la classe de flux abstraite? La seule chose qu'elle sait, c'est le contrat sur l'interface de flux - aucune attente, ce n'est pas défini du tout, cela ne sait rien. Par conséquent, le framework ne peut pas être écrit correctement ... ce n'était jamais une question de sécurité de thread, il s'agit plutôt du contrat * impliqué i> (car il n'est clairement pas documenté) par l'interface de la classe de base de flux.
Cela ressemble plus à un problème théorique qu'à un problème pratique. Je ne peux pas vraiment penser à des situations dans lesquelles un flux deviendrait illisible / inadéquide d'autres em> que de celui qui soit fermé. P>
Il peut y avoir des cas d'angle, mais je ne m'attendrais pas à ce qu'ils appartiennent souvent du tout. Je ne pense pas que la grande majorité du code a besoin de s'inquiéter de cela. P>
C'est un problème philosophique intéressant cependant. P>
Edit: Répondre à la question de savoir s'il s'agit ou non de Canread, etc. sont utiles, je crois qu'ils sont toujours - principalement pour la validation des arguments. Par exemple, simplement parce qu'une méthode prend un flux qu'il va vouloir lire à un moment donné ne signifie pas qu'il souhaite la lire au début de la méthode, mais c'est là que la validation de l'argument devrait idéalement être effectuée. Ce n'est vraiment pas différent de vérifier si un paramètre est NULL et de lancer Aussi, Cela s'appuie sur la "déséquilibre", etc. restant cohérent - mais comme je l'ai dit, cela semble être vrai dans la vie réelle. P>
D'accord, essayons de mettre de cette autre façon ... p>
Sauf si vous lisez / cherchez dans la mémoire et que vous avez déjà assuré qu'il y a suffisamment de données, ou que vous écrivez dans un tampon préallocé, il y a toujours em> une chance d'aller mal. Les disques échouent ou se remplissent, les réseaux s'effondrent, etc. Ces choses font em> se produisent dans la vie réelle, vous avez donc toujours besoin de coder de manière à survivre à l'échec (ou à choisir consciemment d'ignorer le problème quand il ne le fait pas. t vraiment compter). P>
Si votre code peut faire la bonne chose dans le cas d'une défaillance du disque, il est possible de survivre à un Si Je ne crois pas J'ai beaucoup plus gros problèmes avec le cadre, tels que l'état relativement médiocre des API de date / heure. Ils sont devenus un lot em> mieux dans les dernières deux versions, mais ils manquent toujours beaucoup de fonctionnalités de (dire) Joda Time . L'absence de collections immuables intégrées, un mauvais soutien à l'immutabilité dans la langue, etc. - ce sont de vrais problèmes qui me font des em> les maux de tête em>. Je préférerais les voir adressé que des âges dépensés sur argumentnullexception code> au lieu d'attendre un
NullReferenceException code> pour être jeté lorsque vous arrivez à la désarférence. P>
Cansek code> est légèrement différent: dans certains cas, votre code peut faire face à la fois avec des flux à la fois recherchant et non recherchant, mais avec plus d'efficacité dans le cas recherché. P>
filtream code> de l'écriture à des non-écrits. P>
flux code> a eu des contrats fermes, ils devraient être incroyablement em> faible - vous ne pouvez pas utiliser de vérification statique pour prouver que votre code fonctionnera toujours. Le mieux que vous puissiez faire est de prouver que cela faisait la bonne chose face à l'échec. P>
flux code> va changer de temps bientôt. Bien que j'accepte certainement que cela pourrait être mieux documenté, je n'accepte pas l'idée qu'il est "complètement cassé". Ce serait plus em> cassé si nous ne pouvions pas l'utiliser dans la vie réelle ... et si cela pourrait être plus brisé que maintenant, il n'est pas logiquement complètement em> cassé . p>
code> qui me semble être un problème théorique quelque peu intraitable qui provoque peu de problèmes dans la vie réelle. P>
(Ajout à ce que vous avez dit.) Je pense que le problème devient: "Devrions-nous utiliser la propriété CanXXX pour quelque chose?" Si l'opération lise un flux et qu'elle échoue, vous devez organiser une exception. Ce n'est pas comme les méthodes Tryparse CODE>.
Si par "théorique", vous voulez dire "mathématiquement correct", alors oui c'est un problème théorique. Pour moi, c'est tellement important - si Microsoft ne peut pas documenter le contrat sur une classe abstraite, comment peut-on chaque programme? Vous ne savez pas quelles hypothèses vous pouvez faire, voire pire, quelles hypothèses les autres ont fait. Sommes-nous tous condamnés?
Je veux dire "théorique" comme "oui, un flux pourrait i> changer s'il est lisible sans être fermé, mais il n'a pas tendance à se produire dans la vie réelle." Oui, il y a beaucoup d'interfaces et de classes abstraites qui ne sont pas aussi bien conçues que possible, malheureusement.
N'arrive pas dans la vraie vie ... Wow. Si cela ne se produit pas, il ne devrait pas être autorisé à se produire et à documenter en tant que tel. Vous avez raison que cette classe abstraite n'est pas aussi bien conçue que possible, car il est difficile de pire que complètement cassé.
Mais, Jon, les interfaces sont également utilisées pour que d'autres puissent les implémenter. Si j'utilise une classe de flux que quelqu'un d'autre a écrit, tous les paris sont déséquilibrés que ce qui est spécifié clairement dans le contrat.
@Jesse: Je suis d'accord avec vous en théorie - mais dans la pratique, nous semblons utiliser des flux assez raisonnablement dans la vie réelle, n'est-ce pas? Mettez-le de cette façon: cette possibilité spécifique jamais i> est un problème dans tout logiciel de vie réel que vous avez vu? Je suis tout pour essayer de rendre les choses aussi robustes et bien spécifiées que possible, mais je trouve qu'il est difficile de faire trop de travail à ce cas.
@Daniel: Si les gens utilisent des flux avec succès, je ne vois pas comment vous pouvez les décrire comme "complètement cassé".
@Jon - c'est tout à propos de la chance muette. J'ai un dicton qui est approprié ici ", la seule chose pire que de faire la mauvaise chose pour la bonne raison fait la bonne chose pour la mauvaise raison." Autant que je sache, tout le monde utilisant des flux .NET qui ne sont pas en colère contre le manque de documentation sur l'interface de flux font la bonne chose pour les mauvaises raisons. Cela conduit à perpétuer la mauvaise qualité de logiciels qui témoigne des pratiques actuelles de développement de logiciels.
@Daniel: Je suppose donc que vous éviteriez consciencieusement à utiliser le flux dans votre code, étant donné comment il est "complètement cassé"? Je préfère avoir un code pratique qui fonctionne dans la vie réelle que le code qui est théoriquement parfait mais ne fait rien. Vous demandez "Comment quelqu'un peut-il jamais programmer contre [ruisseau]?" Mais les gens le font avec succès tous les jours. Assez étrangement, nous ne semble pas i> sembler complètement condamné. Je vais demander à nouveau: cette possibilité a-t-elle déjà été une question dans n'importe quel logiciel de vie réel que vous avez vu?
Notez que je ne fais aucune façon de discuter contre des interfaces bien conçues - je vis simplement que vous semblez faire beaucoup de bruit sur quelque chose qui ne en fait i> semble causer une pratique pratique problèmes.
Mon problème pratique consistait à écrire un adaptateur à une bibliothèque de flux C ++ qui avait un contrat très clair défini sur son interface. J'ai l'impression que l'adaptateur est une bombe de temps.
«Ces choses se produisent dans la vraie vie, vous avez donc toujours besoin de coder de manière à survivre à l'échec» - Je n'ai jamais dit que vous ne devriez pas attraper des exceptions pour que vous puissiez traiter. "Problème théorique intraitable" - pouvez-vous prouver que? Ecrire sûrement un petit doco n'est pas intraitable ... N'est-ce pas tout ce dont il a besoin?
"Je préfère avoir un code pratique qui fonctionne dans la vie réelle que le code théoriquement parfait mais ne fait rien." Pourquoi considérez-vous les deux à être mutuellement exclusives? J'ai de nombreux exemples quand une bonne base théorique a conduit à des implémentations extrêmement pratiques - elles travaillent dans le monde réel et ont été motivées par un raisonnement pragmatique.
Que disent ces documents exactement? Pourquoi ne pas proposer à Microsoft, au lieu de simplement affirmer que c'est «complètement cassé»? Je soupçonne qu'il serait raisonnable de dire que si le flux est ouvert, un flux ne devrait pas devenir illisible, non écrinable ou désignable s'il est initialement fait i> cette capacité - bien que je ne voudrais pas faire des garanties le dans l'autre sens. Je conviens qu'il existe une inadéquation de l'impédance fondamentale entre une bibliothèque avec des contrats fermes et un sans, et j'ai convenu que .net pourrait être mieux spécifié. Je pense juste que vous êtes trop dramatique à ce sujet.
@Daniel: Oui, ils peuvent travailler ensemble. Vous pouvez également obtenir des situations où tout semble si élégant, mais est très pratique. (Le Java Dom API est un exemple classique de cela - si pluggable que c'est une douleur à utiliser réellement.) Pour répondre à la question de votre titre: Dans toutes les situations pratiques que j'ai vues, à moins que un autre fil ferme le flux pendant que vous êtes L'utilisation de celle-ci (dans laquelle vous avez des problèmes plus gros), le modèle CanXXX est i> sûr. Non, ce n'est pas garanti ... mais je n'ai jamais vu que c'était un problème.
À propos, on dirait que vous pourriez profiter de contrats de code ( recherche.microsoft.com/contracts ) si Vous ne l'avez pas vu. Je doute que cela vous aiderait dans ce cas particulier, mais cela montre une solution possible. (Il n'y a rien de particulièrement nouveau dans l'idée de contrats, bien sûr - mais c'est la plus grande "poussée" pour la rendre traditionnelle que j'ai vue.)
Pour le moment, je vous suggérerais Supposons I> Un contrat de canread / CANWRITE / CANSEEK n'allant jamais de FAUX à FAUX autre que de la fermeture du flux.
(J'essaie de déterminer si cette réponse + commentaires est en réalité une conversation constructive ou si je devrais simplement le supprimer comme un argument inutile. Hmm.)
Je sens que votre réponse + des commentaires est utile et constructif. Il semble que vous ayez besoin d'un peu de provoquer pour sortir tout ce que vous avez dû dire.
@Daniel: Droite, je commence une nouvelle réponse pour espérons que les choses plus claires et plus constructives, nous pouvons envisager de saisir celui-ci.
@Jon: Votre patience est incroyable. J'aurais perçu pour cette raison, mais je voulais préserver ce moment le plus longtemps possible - une jonction jon skeet répond avec -1 votes nets.
@John: ça arrive. L'autre jour, j'ai eu une réponse acceptée avec un NET -1 :) Espérons que ma réponse plus récente est cependant plus constructive.
Je ne pense pas que votre nouvelle réponse capture tout le sentiment de cette discussion, que ce soit surmonté ou non. Je ne vois aucune raison pour que vous supprimiez cette réponse.
De votre question et de tous les commentaires ultérieurs, je suppose que votre problème est avec la clarté et la "correction" du contrat déclaré. Le contrat indiqué étant ce qui se trouve dans la documentation en ligne MSDN. P>
Ce que vous avez souligné, c'est qu'il manque quelque chose de la documentation qui oblige à faire des hypothèses sur le contrat. Plus précisément, car il n'y a rien dit de la volatilité de la propriété de lisibilité d'un flux, la seule hypothèse que l'on peut faire est qu'il est possible em> pour un Je pense que l'on doit aller sur l'intention em> de cette interface dans ce cas, c'est-à-dire: p>
Nonobstant ce qui précède, lisez * méthodes mai em> lancer potentiellement un Le même argument peut être appliqué à toutes les autres propriétés de CAN *. P> notsupportedexception code> pour être jeté, peu importe quelle est la valeur de la propriété de Canreade correspondante était de quelques millisecondes (ou plus) avant. p>
canread code> est invariante. li>
ol>
notsupportedexception code>. p>
Eric - Votre interprétation de l'intention de l'interface est assez bonne, mais je
Sans connaître les internes d'un objet, vous devez supposer qu'une propriété "drapeau" est trop volatilse pour s'appuyer sur lorsque l'objet est modifié dans plusieurs threads. P>
J'ai vu cette question plus souvent interrogée sur les collections en lecture seule que les flux, mais je pense que c'est un autre exemple de la même conception, et les mêmes arguments s'appliquent. P>
Pour clarifier, l'interface ICOLLECTION dans .NET possède la propriété IsReadonly, qui est destinée à être utilisée comme indicateur de si la collection prend en charge les méthodes pour modifier son contenu. Juste comme des flux, cette propriété peut changer à tout moment et provoquera une impression invalidée ou NotSupportedException d'être lancée. P>
Les discussions autour de cela généralement bouchent jusqu'à: p>
Les modes sont rarement une bonne chose, car vous êtes obligé de traiter plus d'un "ensemble" de comportement; Avoir quelque chose qui peut changer de mode à tout moment est considérablement pire, car votre application doit maintenant traiter avec plus d'un "ensemble" de comportement. Cependant, juste parce qu'il est possible de casser quelque chose à des fonctionnalités plus discrètes ne signifie pas nécessairement que vous devriez toujours, en particulier lorsque cela ne la casse pas pour réduire la complexité de la tâche à la main. P>
Mon opinion personnelle est que vous devez choisir le modèle le plus proche du modèle mental que vous percevez que les consommateurs de votre classe comprendront. Si vous êtes le seul consommateur, choisissez le modèle que vous aimez le plus. Dans le cas du flux et de l'Icollection, je pense qu'avoir une définition unique de ceux-ci est beaucoup plus proche du modèle mental construit par des années de développement dans des systèmes similaires. Lorsque vous parlez de flux de flux, vous parlez de flux de fichiers et de flux de mémoire, ce qui n'est pas lisible ou écrit. De même, lorsque vous parlez de collections, vous y parlez rarement en termes de "wriance". P>
Ma règle de base sur celui-ci: recherchez toujours un moyen de décomposer les comportements en interfaces plus spécifiques, plutôt que d'avoir des "modes" de fonctionnement, tant qu'il complimente un simple modèle mental. S'il est difficile de penser aux comportements séparés comme des choses séparées, utilisez un motif basé sur le mode et documentez-le
C'est une réponse bien pensée et je suis d'accord avec la plupart de ce qui est écrit. En ce qui concerne la notsupportedException, j'ai remporté cela ici: Stackoverflow.com/questions/410719 . Une chose que j'ajouterais, c'est que lorsque le modèle mental des masses est clairement imparfait, des développeurs influents (comme Sun et Microsoft) ont l'obligation d'éduquer les non lavés et de déplacer l'industrie dans une meilleure direction. Cela ne semble pas être la tendance du développement de logiciels et pour une raison quelconque, nous semblons tous accepter les ordures qui nous poussent.
Malheureusement, les modèles mentaux sont les exigences ultimes de compatibilité à l'envers dans le système hérité; NOUS NOUS NOUS NOUS NOUS INVENUSÉS, NOUS N'AVONS PAS AIMENT AIMENT DOIVRAIR DE RECOMPARRER Quelque chose qui fonctionnait parfaitement auparavant, même si la nouvelle façon est supérieure!
Ok, alors si le système hérité ne fonctionnait pas parfaitement bien? S'il travaillait bien parfaitement, il n'y aurait pas de nouvelle façon de faire des choses.
Peut-être que je suis juste un homme déraisonnable - "L'homme raisonnable s'adapte au monde; l'homme déraisonnable persiste pour essayer d'adapter le monde à lui-même. Par conséquent, tous les progrès dépendent de l'homme déraisonnable" - de "Maxims pour les révolutionnaires" par George Bernard Shaw. Espille vous, vous promouvez un homme adaptant le monde à d'autres personnes - c'est tout simplement étrange. Quelle est votre aversion pour mieux faire les choses? Les grands non lavés qui "n'aiment pas avoir à rentrer à ressentir quelque chose" ne devraient pas essayer d'écrire des logiciels ou de travailler dans une autre discipline technique.
J'aime cette phrase "Adapter le monde à d'autres personnes" beaucoup. Dans mes travaux en cours dans des logiciels, avec des interfaces utilisateur, en particulier, je trouve que tenter d'adapter mes systèmes aux personnes qui ne lui sont pas habituées, est l'un des objectifs majeurs. Personnellement croire que l'interface utilisateur avec n'importe quel produit est la partie la plus importante de ce produit, qu'il s'agisse de l'interface graphique, de la ligne de commande ou de la programmation. Création d'interfaces que les utilisateurs n'ont pas à s'adapter pour constituer une énorme accomplissement de cet objectif.
D'accord, voici une autre tentative qui saura être plus utile que mon autre réponse ...
Il est malheureux que MSDN ne donne aucune garantie spécifique sur la façon dont dans certains cas, je pense que ce serait raisonnable Pour un flux pour deviendra em> recherchable ultérieurement - par exemple, il pourrait tamponner tout ce qu'il lit jusqu'à ce qu'il atteigne la fin des données sous-jacentes, puis autoriser la recherche en elle ensuite à laisser les clients relisez les données. Je pense qu'il serait raisonnable qu'un adaptateur ignore cette possibilité, cependant. P> Cela devrait prendre en charge tous les cas les plus pathologiques. (Streams à peu près conçus pour causer des ravages!) L'ajout de ces exigences à la documentation existante est un changement théoriquement rupture, même si je soupçonne que 99,9% des implémentations obéiront déjà. Néanmoins, il pourrait être intéressant de suggérer sur Connect . P> Maintenant, comme pour la discussion entre d'utiliser une API "basé sur la capacité" (comme s'il l'autorise em> le permet, cela pourrait être raisonnable - mais sans cela, vous vous retrouvez avec Une explosion d'interfaces potentielles: p> Je pense que c'est Messier que la situation actuelle - bien que je pense que je serait em> soutenir l'idée de Canread
CANWRITE code> /
CANSEEK code> peut changer au fil du temps. Je pense qu'il serait raisonnable de supposer que si un flux est lisible, il continuera d'être lisible jusqu'à ce qu'il soit fermé - et il en va de même pour les autres propriétés P>
flux code>) et une interface - basé sur une interface ... Le problème fondamental que je vois est que .NET ne fournit pas la possibilité de spécifier une variable doit être une référence à une implémentation de plusieurs interfaces. Par exemple, je ne peux pas écrire: p>
IRLEABLE CODE> et
IWRITABLE CODE> En plus du flux CODE> existant CODE> Classe. Cela faciliterait la tâche que les clients expriment de manière répréhensible ce dont ils ont besoin. P>
+1. En ce qui concerne foo readfoo (flux irseadable et isechable) code>: le problème ne passe pas un
irrafinable et isiétable code> flux dans i> la méthode; Il suffit d'écrire
foo readfoo
OpenForread OpenForread (Nom de la chaîne) Où T: Irleadable, Iseekable Code> ne compilera pas. C'est là que vous auriez besoin d'une interface
IreadSeekable: IRLEABLE, ISEEKABLE CODE>.
En ce qui concerne les flux qui ne deviennent recherchés qu'après un certain temps: dans ce cas, il devrait y avoir un événement code> CANSeeekChanged code>. Sa présence signalerait immédiatement les consommateurs que CANSEEK code> mai i> change à tout moment et aurait en même temps que le rendez-vous répété interrogatoire répété inutile.
Ou, en l'absence d'un événement code> CANSeekChanged code>, si CANSEAK code> était une méthode au lieu d'une propriété, ce serait une autre petite indication que la valeur renvoyée pourrait ne pas être constante, c'est-à-dire pourrait changer à tout moment. (Cette interprétation résulte de la . Directives de conception-cadre net )
J'apprécierais également les commentaires sur la validité de ce modèle (les paires CanXXX, XXX ()). em> p> blockQuote>
Quand je vois une instance de ce modèle, je m'attendrais généralement à ce que ceci: p>
A
PARAMETER-MOINS-MOINS-MOINS-MOINS CODE> CANXXX CODE> STRORT> retournera toujours la même valeur, à moins que ... P> li> ... en présence d'un
Canxxxchanged CODE> EVENT STRY>, où un paramètre moins
canexxx code> peut renvoyer une valeur différente avant et après une occurrence de cet événement; Mais cela ne changera pas sans déclencher l'événement. P> li>
a paramétré
canexxx (...) code> strong> Membre peut renvoyer des valeurs différentes pour différents arguments; Mais pour les mêmes arguments, il est susceptible de renvoyer la même valeur. C'est-à-dire que
canexxx (constvalue) code> est susceptible de rester constant. P>
Je suis prudent ici: si
stream.canwritetodique (largeconstobject) code> retourne
vrai code> est-il raisonnable de supposer qu'il retournera toujours
vrai code> dans le futur? Probablement pas, alors cela dépend peut-être du contexte si un
canexxx (...) paramétré (...) code> renvoie la même valeur pour les mêmes arguments ou non. SUB> P> blockQuote> li>
un appel à
xxx (...) code> strud> ne peut réussir que si
canexxx code> retourne
vrai code>. < / p> li> ol>
Cela étant dit, je suis d'accord que
Stream code> de ce modèle est quelque peu problématique. Au moins en théorie, s'il n'est peut-être pas tant dans la pratique. P>
Je crois que c'est une excellente présentation d'un problème actuel et valide. +1