L'information cache-t-elle plus qu'une convention?

20

En Java, C # et de nombreux autres langages fortement typés et vérifiés statiquement, nous sommes habitués à écrire du code comme ceci:

public void m1() { ... }
protected void m2() { ... }
private void m2() { ... }
void m2() { ... }

Certaines langues vérifiées dynamiquement ne fournissent pas de mots clés pour exprimer le niveau de "confidentialité" d'un membre de classe donné et s'appuient plutôt sur des conventions de codage. Python, par exemple, préfixe les membres privés avec un trait de soulignement:

_m(self): pass

On peut affirmer que la fourniture de tels mots clés dans des langues vérifiées dynamiquement ajouterait peu d'utilité car elle n'est vérifiée qu'au moment de l'exécution.

Cependant, je ne trouve pas non plus une bonne raison de fournir ces mots clés dans des langues à vérification statique. Je trouve l'exigence de remplir mon code avec des mots clés assez verbeux comme protectedennuyeux et distrayants. Jusqu'à présent, je n'ai pas été dans une situation où une erreur de compilation générée par ces mots clés m'aurait sauvé d'un bug. Bien au contraire, j'ai été dans des situations où un placement par erreur protectedm'a empêché d'utiliser une bibliothèque.

Dans cet esprit, ma question est:

L'information cache-t-elle plus qu'une convention entre programmeurs utilisée pour définir ce qui fait partie de l'interface officielle d'une classe?

Peut-il être utilisé pour empêcher un état secret d'une classe d'être attaqué? La réflexion peut-elle passer outre ce mécanisme? Qu'est-ce qui en vaut la peine pour le compilateur d' appliquer la dissimulation d'informations?

blubb
la source
10
Désolé, Eric Lippert est en vacances :)
Benjol
Votre question est un peu difficile à comprendre. Êtes-vous simplement en train de demander si quelqu'un peut accéder à un membre privé de l'extérieur?
Morgan Herlocker
1
Question connexe: programmers.stackexchange.com/questions/92380/…
user281377
@ironcode: Je peux dire que je ne m'exprime pas assez clairement à partir de certaines réponses. Pouvez-vous dire ce qui le rend particulièrement difficile à comprendre? Je vais essayer de clarifier.
blubb
2
"Il est absurde de fournir des informations au moment de la compilation et de les vérifier uniquement lors de l'exécution" - vraiment? Mieux vaut le dire à Microsoft, car c'est sur cette base qu'une partie importante du cadre .NET actuel est basée: l'activation ou la désactivation sélective de la frappe statique. Je ne pense pas que ce soit vraiment ce que vous voulez dire; la question parle à plusieurs reprises de vérification "statique" contre "dynamique", mais ce sont là les caractéristiques du système de types; ce qui est vraiment en cause ici, c'est la liaison entre la compilation et l' exécution .
Aaronaught

Réponses:

4

J'étudie pour la certification Java et tout un tas de problèmes concernent la gestion des modificateurs d'accès. Et ils ont un sens et doivent être utilisés correctement.

J'ai travaillé avec python et, au cours de mon parcours d'apprentissage, j'ai entendu qu'en python, la convention est là parce que les gens qui y travaillent devraient savoir ce que cela signifie et comment l'appliquer. Cela dit, _m(self): passle trait de soulignement m'alerterait de ne pas jouer avec ce domaine. Mais est-ce que tout le monde suivra cette convention? Je travaille avec javascript et je dois dire que non . Parfois, je dois vérifier un problème et la raison en est que la personne faisait quelque chose qu'elle n'était pas censée faire ...

lire cette discussion concernant le trait de soulignement python

L'information cache-t-elle plus qu'une convention entre programmeurs utilisée pour définir ce qui fait partie de l'interface officielle d'une classe?

D'après ce que j'ai dit, oui.

Peut-il être utilisé pour empêcher un état secret d'une classe d'être attaqué? La réflexion peut-elle passer outre ce mécanisme? Y a-t-il d'autres avantages fournis par un mécanisme plus formel appliqué par le compilateur?

Oui, il peut être utilisé pour sécuriser l'état secret d'une classe et il doit non seulement être utilisé pour cela, mais pour empêcher les utilisateurs de jouer avec l'état des objets afin de changer leurs comportements en quelque chose qu'ils pensent être la manière dont l'objet devrait avoir je travaillais. En tant que développeur, vous devez planifier et réfléchir à cela et concevoir votre classe de manière logique, de manière à ce que son comportement ne soit pas altéré. Et le compilateur, en tant que bon ami, vous aidera à garder le code tel que vous l'avez conçu en appliquant les politiques d'accès.

EDITÉ Oui, la réflexion peut, vérifiez les commentaires

La dernière question est intéressante et je suis prêt à lire les réponses la concernant.

wleao
la source
3
La réflexion peut généralement contourner la protection d'accès. Pour Java et C #, ils peuvent tous deux accéder à des données privées.
Mark H
Merci! Les réponses ici: stackoverflow.com/questions/1565734/… expliquez-le!
wleao
1
La culture Javascript est très différente de la culture python. Python a pep-08 et presque tous les développeurs de python suivent ces conventions. Les violations de PEP-08 sont souvent considérées comme un bug. Je pense donc que l'expérience javascript / php / perl / ruby ​​se traduit très peu en expérience python à cet égard: _private fonctionne très bien en python.
Mike Korobov
1
Dans certains langages de programmation (mais pas tous), la dissimulation d'informations peut être utilisée pour se protéger contre un code hostile. Les informations cachées ne peuvent pas être utilisées pour se protéger contre les utilisateurs hostiles.
Brian
2
@Mike si les violations de PEP-08 sont si souvent "considérées comme un bogue", et qu'aucun développeur de Python ne rêverait de ne pas suivre les conventions, alors vous pouvez aussi les faire appliquer par le langage! Pourquoi le travail subalterne alors que la langue peut le faire automatiquement?
Andres F.
27

Le spécificateur d'accès "privé" ne concerne pas l'erreur de compilation qu'il génère la première fois que vous le voyez. En réalité, il s'agit de vous empêcher d'accéder à quelque chose qui peut encore changer lorsque l'implémentation de la classe contenant le membre privé change.

En d'autres termes, ne pas vous permettre de l'utiliser quand il fonctionne toujours vous empêche de l'utiliser accidentellement quand il ne fonctionne plus.

Comme Delnan l'a fait remarquer ci-dessous, la convention de préfixe décourage l'utilisation accidentelle de membres susceptibles de changer tant que la convention est respectée et comprise correctement. Pour un utilisateur malveillant (ou ignorant), cela ne l'empêche pas d'accéder à ce membre avec toutes les conséquences possibles. Dans les langues avec prise en charge intégrée des spécificateurs d'accès, cela ne se produit pas dans l'ignorance (erreur du compilateur) et se démarque comme un pouce douloureux lorsqu'il est malveillant (constructions étranges pour arriver au membre privé).

Le spécificateur d'accès "protégé" est une autre histoire - ne pensez pas que ce soit simplement "pas tout à fait public" ou "un peu comme privé". Signifie « protégés » que vous aurez probablement envie d'utiliser cette fonctionnalité lorsque vous dérivez de la classe contenant le membre protégé. Les membres protégés font partie de l '"interface d'extension" que vous utiliserez pour ajouter des fonctionnalités au-dessus des classes existantes sans modifier ces classes existantes elles-mêmes.

Donc, bref récapitulatif:

  • public: utiliser en toute sécurité sur les instances de la classe, le but de la classe, ne changera pas.
  • protected: à utiliser lors de l'extension (dérivant) de la classe - peut changer si l'implémentation doit changer radicalement.
  • privé: ne touchez pas! Peut changer à volonté pour fournir une meilleure implémentation des interfaces attendues.
Joris Timmermans
la source
3
Plus important encore, toute convention (facilement reconnaissable, ce qui est le cas, par exemple, des traits de soulignement principaux) non appliquée pour les "détails de mise en œuvre, sous réserve de modifications" évite également l'utilisation à titre personnel d'un membre privé. En Python, par exemple, la seule fois où un programmeur sensé écrit du code en utilisant un membre privé de l'extérieur (et même alors il fronce les sourcils) est quand c'est presque inévitable, il sait exactement ce qu'il fait et accepte la rupture potentielle dans les versions futures . C'est-à-dire une situation dans laquelle, par exemple, les programmeurs Java utiliseraient la réflexion.
3
@Simon Stelling - non, je dis que l'implémenteur d'origine de la classe qui a fait quelque chose de privé vous dit "ne l'utilisez pas, tout comportement ici peut changer à l'avenir". Par exemple, une variable membre privée d'une classe qui contient d'abord une distance entre deux points peut ultérieurement contenir la distance entre deux points au carré pour des raisons de performances. Tout ce qui aurait reposé sur l'ancien comportement se briserait en silence.
Joris Timmermans
1
@MadKeithV: Alors, comment un mot-clé au niveau de la langue dit "ne pas toucher parce que ..." différent d'une convention signifiant la même chose? Seul le compilateur l'applique, mais nous revenons à la discussion statique vs dynamique.
7
@Simon Stelling (et Delnan) - pour moi, c'est un peu comme demander "en quoi un limiteur de moteur est-il différent d'un panneau de limitation de vitesse".
Joris Timmermans
1
Je suis bien conscient de la différence et je n'ai jamais dit que ce n'était pas là. Je constate simplement que votre réponse et la plupart de vos commentaires de suivi décrivent simplement les types d'annotations aux membres et les méthodes qui peuvent être faites avec des conventions ou des mots clés au niveau de la langue et laissent la différence réelle (présence d'une application au niveau de la langue) à être déduit par le lecteur.
11

Si vous écrivez du code qui sera consommé par quelqu'un d'autre, la dissimulation d'informations peut fournir une interface beaucoup plus facile à comprendre. "Quelqu'un d'autre" pourrait être un autre développeur de votre équipe, des développeurs consommant une API que vous avez écrite commercialement, ou même votre futur moi qui "ne se souvient tout simplement pas comment fonctionne le truc". Il est beaucoup plus facile de travailler avec une classe qui n'a que 4 méthodes disponibles que celle qui en a 40.

Morgan Herlocker
la source
2
Je suis totalement d'accord, mais cela ne répond pas à ma question. Que j'utilise _memberou private memberdans ma classe est négligeable, tant que l'autre programmeur comprend qu'il ne doit regarder que les publicmembres ou non préfixés.
blubb
6
Oui, mais la documentation publique d'une classe écrite dans un langage dynamique ne vous lance pas non plus ces 36 parties privées (du moins pas par défaut).
3
@Simon L'affirmation qu'il ne s'agit que d'une "convention" est trompeuse, car elle présente de réels avantages. "Juste une convention" est quelque chose comme des accolades sur la ligne suivante. Une convention avec des avantages est quelque chose comme l'utilisation de noms significatifs, ce qui, je dirais, est totalement différent. Est-ce que mettre quelque chose en privé empêche quelqu'un de vous voir "des méthodes secrètes"? Non, pas s'ils sont déterminés.
Morgan Herlocker
1
@ Simon - également, seule l'exposition de méthodes qui sont sûres à utiliser augmente le capot probable que l'utilisateur ne cassera pas quelque chose en essayant d'utiliser la classe. Il pourrait facilement y avoir des méthodes qui pourraient planter un serveur Web s'il était appelé mille fois. Vous ne voulez pas que les consommateurs de votre API puissent le faire. L'abstraction est plus qu'une simple convention.
Morgan Herlocker
4

Je suggère que pour le fond, vous commencez par lire sur les invariants de classe .

Un invariant est, pour faire court, une hypothèse sur l'état d'une classe qui est censée rester vraie pendant toute la durée de vie d'une classe.

Prenons un exemple C # très simple:

public class EmailAlert
{
    private readonly List<string> addresses = new List<string>();

    public void AddRecipient(string address)
    {
        if (!string.IsNullOrEmpty(address))
            addresses.Add(address);
    }

    public void Send(string message)
    {
        foreach (string address in addresses)
            SendTo(address, message);
    }

    // Details of SendTo not shown
}

Que se passe t-il ici?

  • Le membre addressesest initialisé lors de la construction de la classe.
  • C'est privé, donc rien de l'extérieur ne peut le toucher.
  • Nous l'avons également fait readonly, donc rien de l' intérieur ne peut le toucher après la construction (ce n'est pas toujours correct / nécessaire, mais c'est utile ici).
  • Par conséquent, la Sendméthode peut faire une hypothèse qui addressesne sera jamais null. Il n'a pas à effectuer cette vérification car il est impossible de modifier la valeur.

Si d'autres classes étaient autorisées à écrire dans le addresseschamp (c'est-à-dire si c'était le cas public), cette hypothèse ne serait plus valide. Toutes les autres méthodes de la classe qui dépendent de ce champ devraient commencer à effectuer des vérifications null explicites , sinon elles risqueraient de planter le programme.

Alors oui, c'est bien plus qu'une "convention"; tous les modificateurs d'accès sur les membres de la classe forment collectivement un ensemble d'hypothèses sur quand et comment cet état peut être changé. Ces hypothèses sont ensuite incorporées dans des membres et des classes dépendants et interdépendants afin que les programmeurs n'aient pas à raisonner sur l'état complet du programme en même temps. La capacité de faire des hypothèses est un élément essentiel de la gestion de la complexité des logiciels.

À ces autres questions:

Peut-il être utilisé pour empêcher un état secret d'une classe d'être attaqué?

Oui et non. Le code de sécurité, comme la plupart des codes, va s'appuyer sur certains invariants. Les modificateurs d'accès sont certainement utiles comme panneaux de signalisation pour les appelants de confiance qu'ils ne sont pas censés jouer avec. Le code malveillant ne s'en souciera pas, mais le code malveillant ne doit pas non plus passer par le compilateur.

La réflexion peut-elle passer outre ce mécanisme?

Bien sûr que oui. Mais la réflexion nécessite que le code appelant ait ce niveau de privilège / confiance. Si vous exécutez du code malveillant avec une confiance totale et / ou des privilèges administratifs, vous avez déjà perdu cette bataille.

Qu'est-ce qui en vaut la peine pour le compilateur d'appliquer la dissimulation d'informations?

Le compilateur déjà fait l' appliquer. Il en va de même pour l'exécution dans .NET, Java et d'autres environnements de ce type - l'opcode utilisé pour appeler une méthode ne réussira pas si la méthode est privée. Les seuls moyens de contourner cette restriction nécessitent un code de confiance / élevé, et le code élevé pourrait toujours simplement écrire directement dans la mémoire du programme. Il est appliqué autant qu'il peut l' être sans nécessiter de système d'exploitation personnalisé.

Aaronaught
la source
1
@Simon: Nous devons clarifier ici "l'ignorance". Préfixer une méthode avec _indique le contrat, mais ne l'applique pas. Cela peut rendre difficile l' ignorance du contrat, mais il n'est pas difficile de rompre le contrat, surtout pas par rapport à des méthodes fastidieuses et souvent restrictives comme la réflexion. Une convention dit: "vous ne devriez pas casser cela". Un modificateur d'accès dit "vous ne pouvez pas casser cela". Je n'essaie pas de dire qu'une approche est meilleure que l'autre - elles sont toutes les deux très bien selon votre philosophie, mais ce sont néanmoins des approches très différentes.
Aaronaught
2
Que diriez-vous d'une analogie: Un modificateur d'accès private/ protectedest comme un préservatif. Vous n'êtes pas obligé d'en utiliser un, mais si vous n'y allez pas, vous feriez mieux de vous assurer de votre timing et de vos partenaires. Cela n'empêchera pas un acte malveillant et pourrait même ne pas fonctionner à chaque fois, mais cela réduira certainement les risques de négligence, et ce, bien plus efficacement que de dire "s'il vous plaît soyez prudent". Oh, et si vous en avez un, mais ne l'utilisez pas, n'attendez pas de sympathie de ma part.
Aaronaught
3

La dissimulation d'informations est bien plus qu'une simple convention; essayer de le contourner peut en fait casser la fonctionnalité de la classe dans de nombreux cas. Par exemple, il est assez courant de stocker une valeur dans une privatevariable, de l'exposer à l'aide d'un protectedoupublic propriété de la même heure, et dans le getter, de vérifier la valeur null et de faire l'initialisation nécessaire (c'est-à-dire le chargement paresseux). Ou stockez quelque chose dans une privatevariable, exposez-la à l'aide d'une propriété, et dans le setter, vérifiez si la valeur a changé et déclenchez PropertyChanging/ PropertyChangedévénements. Mais sans voir l'implémentation interne, vous ne sauriez jamais tout ce qui se passe dans les coulisses.

Joel C
la source
3

Les informations cachées ont évolué à partir d'une philosophie de conception descendante. Python a été appelé un langage ascendant .

Le masquage des informations est bien appliqué au niveau de la classe en Java, C ++ et C #, donc ce n'est pas vraiment une convention à ce niveau. Il est très facile de faire d'une classe une "boîte noire", avec des interfaces publiques et des détails (privés) cachés.

Comme vous l'avez souligné, en Python, c'est aux programmeurs de suivre la convention de ne pas utiliser ce qui est censé être caché, car tout est visible.

Même avec Java, C ++ ou C #, à un moment donné, la dissimulation d'informations devient une convention. Il n'y a pas de contrôle d'accès aux niveaux d'abstraction les plus élevés impliqués dans les architectures logicielles plus complexes. Par exemple, en Java, vous pouvez trouver l'utilisation de ".internal".noms des packages. Il s'agit purement d'une convention de dénomination, car il n'est pas facile d'appliquer ce type d'informations cachées via l'accessibilité des packages uniquement.

Eiffel est un langage qui s'efforce de définir formellement l'accès. Cet article souligne quelques autres faiblesses masquant les informations de langages tels que Java.

Contexte: La dissimulation d'informations a été proposée en 1971 par David Parnas . Il souligne dans cet article que l'utilisation d'informations sur d'autres modules peut «augmenter de façon désastreuse la connectivité de la structure du système». Selon cette idée, le manque d'informations cachées peut conduire à des systèmes étroitement couplés et difficiles à maintenir. Il poursuit avec:

Nous souhaitons que la structure du système soit déterminée explicitement par les concepteurs avant le début de la programmation, plutôt que par inadvertance par l'utilisation des informations par un programmeur.

Fuhrmanator
la source
1
+1 pour la citation "utilisation des informations par le programmeur", c'est tout (même si vous avez une virgule supplémentaire à la fin).
jmoreno
2

Ruby et PHP l'ont et l'appliquent au moment de l'exécution.

Le point de dissimulation de l'information est en fait une information qui s'affiche. En «cachant» les détails internes, le but devient apparent d'un point de vue extérieur. Il y a des langues qui embrassent cela. En Java, l'accès par défaut au package interne, dans haXe à protégé. Vous les déclarez explicitement publics pour les exposer.

Le but de tout cela est de rendre vos classes faciles à utiliser en exposant uniquement une interface très cohérente. Vous voulez que le reste soit protégé, afin qu'aucun gars intelligent ne vienne perturber votre état interne pour inciter votre classe à faire ce qu'il veut.

De plus, lorsque les modificateurs d'accès sont appliqués au moment de l'exécution, vous pouvez les utiliser pour appliquer un certain niveau de sécurité, mais je ne pense pas que ce soit une solution particulièrement bonne.

back2dos
la source
1
Si votre bibliothèque est utilisée dans la même entreprise dans laquelle vous travaillez, vous vous en soucierez ... S'il plante son application, vous aurez du mal à la réparer.
wleao
1
Pourquoi faire semblant de porter une ceinture de sécurité alors que vous pourriez en porter une? Je reformulerais la question et demanderais, y a-t-il une raison pour qu'un compilateur ne l' applique pas, si toutes les informations sont disponibles. Vous ne voulez pas attendre d'avoir un accident pour savoir si cette ceinture de sécurité valait la peine d'être portée.
Mark H
1
@Simon: pourquoi encombrer une interface avec des choses que vous ne voulez pas que les gens utilisent. Je déteste que C ++ nécessite que chaque membre soit présent dans la définition de classe dans un fichier d'en-tête (je comprends pourquoi). Les interfaces sont destinées à d'autres personnes et ne doivent pas être jonchées d'objets qu'ils ne peuvent pas utiliser.
phkahler
1
@phkahler: pydocsupprime _prefixedMembersde l'interface. Les interfaces encombrées n'ont rien à voir avec le choix d'un mot clé vérifié par le compilateur.
blubb
2

Les modificateurs d'accès peuvent certainement faire quelque chose que la convention ne peut pas faire.

Par exemple, en Java, vous ne pouvez accéder à un membre / champ privé que si vous utilisez la réflexion.

Par conséquent, si j'écris l'interface pour un plugin et que je refuse correctement les droits de modifier les champs privés par la réflexion (et de définir le gestionnaire de sécurité :)), je peux envoyer un objet aux fonctions implémentées par n'importe qui et savoir qu'il ne peut pas accéder à ses champs privés.

Bien sûr, il peut y avoir des bogues de sécurité qui lui permettraient de surmonter cela, mais ce n'est pas philosophiquement important (mais en pratique, c'est certainement le cas).

Si l'utilisateur exécute mon interface dans son environnement, il a le contrôle et peut ainsi contourner les modificateurs d'accès.

user470365
la source
2

Je n'ai pas été dans une situation où une erreur de compilation générée par ces mots clés m'aurait sauvé d'un bug.

Il ne s'agit pas tant de sauver les auteurs d'applications des bogues que de laisser les auteurs de bibliothèques décider quelles parties de leur implémentation ils s'engagent à maintenir.

Si j'ai une bibliothèque

class C {
  public void foo() { ... }

  private void fooHelper() { /* lots of complex code */ }
}

Je veux peut-être pouvoir remplacer foola mise en œuvre de et éventuellement changer fooHelperde façon radicale. Si un tas de gens ont décidé d'utiliserfooHelper malgré tous les avertissements dans ma documentation, je ne pourrai peut-être pas le faire.

privatepermet aux auteurs de bibliothèque de diviser les bibliothèques en méthodes de taille gérable (et en privateclasses d'assistance) sans craindre d'être obligés de conserver ces détails internes pendant des années.


Qu'est-ce qui en vaut la peine pour le compilateur d'appliquer la dissimulation d'informations?

Par ailleurs, en Java privaten'est pas appliqué par le compilateur, mais par le vérificateur de bytecode Java .


La réflexion peut-elle passer outre ce mécanisme? Qu'est-ce qui en vaut la peine pour le compilateur d'appliquer la dissimulation d'informations?

En Java, non seulement la réflexion peut remplacer ce mécanisme. Il existe deux types de privateJava. Le type de privatecela empêche une classe externe d'accéder aux membres d'une autre classe externe, privatece qui est vérifié par le vérificateur de bytecode, mais aussi les privates qui sont utilisés par une classe interne via une méthode d'accesseur synthétique package-private comme dans

 public class C {
   private int i = 42;

   public class B {
     public void incr() { ++i; }
   }
 }

Puisque la classe B(vraiment nommée C$B) utilise i, le compilateur crée une méthode d'accesseur synthétique qui permet Bd'accéder C.id'une manière qui dépasse le vérificateur de bytecode. Malheureusement, puisque ClassLoadervous permet de créer une classe à partir de a byte[], il est assez simple de se rendre chez les particuliers qui Cont exposé aux classes internes en créant une nouvelle classe dansC le package de 's qui est possible si Cle pot de' s n'a pas été scellé.

Une mise en œuvre appropriée privatenécessite une coordination entre les chargeurs de classe, le vérificateur de bytecode et la politique de sécurité, ce qui peut empêcher l'accès réfléchi aux utilisateurs privés.


Peut-il être utilisé pour empêcher un état secret d'une classe d'être attaqué?

Oui. La "décomposition sécurisée" est possible lorsque les programmeurs peuvent collaborer tout en préservant chacun les propriétés de sécurité de leurs modules - je n'ai pas à faire confiance à l'auteur d'un autre module de code pour ne pas violer les propriétés de sécurité de mon module.

Les langages de capacités d'objet comme Joe-E utilisent le masquage d'informations et d'autres moyens pour rendre possible une décomposition sécurisée:

Joe-E est un sous-ensemble du langage de programmation Java conçu pour prendre en charge la programmation sécurisée selon la discipline de capacité objet. Joe-E est destiné à faciliter la construction de systèmes sécurisés, ainsi qu'à faciliter les examens de sécurité des systèmes construits dans Joe-E.

Le document lié à partir de cette page donne un exemple de la façon dont privatela mise en œuvre rend possible une décomposition sécurisée.

Fournir une encapsulation sécurisée.

Figure 1. Une fonction de journalisation en annexe uniquement.

public final class Log {
  private final StringBuilder content;
  public Log() {
    content = new StringBuilder();
  }
  public void write(String s) {
    content.append(s);
  }
}

Considérez la figure 1, qui illustre la façon dont on peut créer une fonction de journal avec ajout uniquement. À condition que le reste du programme soit écrit en Joe-E, un réviseur de code peut être sûr que les entrées de journal ne peuvent être ajoutées, et ne peuvent pas être modifiées ou supprimées. Cette révision est pratique car elle ne nécessite qu'une inspection de la Log classe et ne nécessite la révision d'aucun autre code. Par conséquent, la vérification de cette propriété nécessite uniquement un raisonnement local sur le code de journalisation.

Mike Samuel
la source
1

La dissimulation d'informations est l'une des principales préoccupations d'une bonne conception de logiciels. Découvrez tous les articles de Dave Parnas de la fin des années 70. Fondamentalement, si vous ne pouvez pas garantir la cohérence de l'état interne de votre module, vous ne pouvez rien garantir de son comportement. Et la seule façon de garantir son état interne est de le garder privé et de ne le modifier que par les moyens que vous fournissez.

TMN
la source
1

En intégrant la protection à la langue, vous obtenez quelque chose: une assurance raisonnable.

Si je rend une variable privée, j'ai une assurance raisonnable qu'elle ne sera touchée que par du code au sein de cette classe ou des amis explicitement déclarés de cette classe. La portée du code qui pourrait raisonnablement toucher cette valeur est limitée et explicitement définie.

Existe-t-il maintenant des moyens de contourner la protection syntaxique? Absolument; la plupart des langues en ont. En C ++, vous pouvez toujours convertir la classe en un autre type et pousser ses bits. En Java et C #, vous pouvez vous y refléter. Et ainsi de suite.

Cependant, cela est difficile . Il est évident que vous faites quelque chose que vous ne devriez pas faire. Vous ne pouvez pas le faire par accident (en dehors des écritures sauvages en C ++). Vous devez penser volontiers: "Je vais toucher quelque chose que mon compilateur m'a dit de ne pas faire." Vous devez volontairement faire quelque chose de déraisonnable .

Sans protection syntaxique, un programmeur peut juste accidentellement bousiller les choses. Vous devez enseigner à l'utilisateur une convention, et il doit suivre cette convention à chaque fois . S'ils ne le font pas, le monde devient très dangereux.

Sans protection syntaxique, la responsabilité incombe aux mauvaises personnes: les nombreuses personnes qui utilisent la classe. Ils doivent suivre la convention ou une méchanceté non spécifiée se produira. Grattez cela: une méchanceté non spécifiée peut se produire.

Il n'y a rien de pire qu'une API où, si vous faites la mauvaise chose, tout pourrait fonctionner de toute façon. Cela donne une fausse assurance à l'utilisateur qu'il a fait la bonne chose, que tout va bien, etc.

Et qu'en est-il des nouveaux utilisateurs de cette langue? Non seulement ils doivent apprendre et suivre la syntaxe réelle (appliquée par le compilateur), mais ils doivent maintenant suivre cette convention (appliquée au mieux par leurs pairs). Et s'ils ne le font pas, alors rien de mauvais ne peut se produire. Que se passe-t-il si un programmeur ne comprend pas pourquoi la convention existe? Que se passe-t-il quand il dit «vissez-le» et ne fait que piquer vos soldats? Et que pense-t-il si tout continue à fonctionner?

Il pense que la convention est stupide. Et il ne le suivra plus jamais. Et il dira à tous ses amis de ne pas trop déranger.

Nicol Bolas
la source