48 votes

Ecriture de code R robuste: espaces de noms, masquage et utilisation de l'opérateur `::`

Version courte

Pour ceux qui ne veulent pas lire à travers mon "cas", c'est l'essence même:

  1. Quelle est la méthode recommandée pour minimiser les chances des nouveaux paquets à casser le code existant, c'est à dire de rendre le code que vous écrivez aussi robuste que possible?
  2. Quelle est la meilleure façon de faire le meilleur usage de l' espace de noms mécanisme lorsque

    a) tout en utilisant contribué paquets (mot à dire dans seulement quelques-R Analyse de Projet)?

    b) à l'égard de l'élaboration propres paquets?

  3. La meilleure façon d'éviter les conflits à l'égard des classes formelles (principalement des Classes de Référence dans mon cas) car il n'y a même pas un mécanisme d'espace de noms comparables à :: pour les classes (AFAIU)?


La façon dont le R univers fonctionne

C'est quelque chose qui a été lancinante dans le dos de mon esprit pendant près de deux ans maintenant, mais je ne me sens pas comme si je suis arrivé à une solution satisfaisante. En Plus je sens qu'il est en train d'empirer.

Nous voyons un nombre toujours croissant de paquets sur CRAN, github, R-Forge et similaires, ce qui est tout simplement formidable.

Dans un tel environnement décentralisé, il est naturel que le code de base qui permet de R (disons que c'est la base de R et a contribué R, pour des raisons de simplicité) va s'écarter de l'idéal de l'état à l'égard de la robustesse: les gens suivent les différentes conventions, il n'y a S3, S4, S4 Classes de Référence, etc. Les choses ne peuvent pas être "aligné", comme ils le seraient si il y avait une "centrale de compensation de l'instance" qui a appliqué les conventions. Ce n'est pas grave.

Le problème

Compte tenu de ce qui précède, il peut être très difficile à utiliser R pour écrire du code robuste. Pas tout ce que vous devez être à la base de R. Pour certains projets, vous finirez chargement assez peu contribué paquets.

À mon humble avis, la question la plus importante à cet égard est la façon dont le concept d'espace de noms est mis à profit dans R: R permet simplement d'écrire le nom d'une fonction/méthode, sans explicitement le nécessitant de l'espace de noms (c - foo vs namespace::foo).

Donc, par souci de simplicité, c'est ce que tout le monde est en train de faire. Mais de cette façon, les collisions de noms, de code cassé et la nécessité de réécrire/restructurer le code sont juste une question de temps (ou du nombre de forfaits).

Au mieux, vous savez au sujet de laquelle les fonctions sont masqués/surchargé par un nouveau paquet. Au pire, vous n'avez aucune idée jusqu'à ce que votre code de pauses.

Quelques exemples:

  • essayez de charger RMySQL et RSQLite dans le même temps, ils ne vont pas très bien
  • aussi RMongo va remplacer certaines fonctions de RMySQL
  • prévisions masques beaucoup de choses à l'égard de ARIMA fonctions liées à la
  • R. utils même des masques à l' base::parse de routine

(Je ne me souviens pas les fonctions qui, en particulier, ont été à l'origine des problèmes, mais je suis prêt à le rechercher si il y a un intérêt)

Étonnamment, cela ne semble pas déranger beaucoup de programmeurs là-bas. J'ai essayé de susciter l'intérêt d'un couple de fois à la r-devel, ne sont pas significatives, en vain.

Les désavantages de l'utilisation de l' :: de l'opérateur

  1. À l'aide de l' :: opérateur pourrait frapper beaucoup d'efficacité dans certains contextes, comme Dominick Samperi souligné.
  2. Lors de l' élaboration de votre propre forfait, vous ne pouvez même pas utiliser l' :: de l'opérateur tout au long de votre propre code que votre code n'est pas véritable package pour le moment et donc il n'y a également aucun espace de noms encore. Si je dois d'abord en tenir à l' foo , construire, tester, puis revenir en arrière pour tout changer pour namespace::foo. Pas vraiment.

Les solutions possibles pour éviter ces problèmes

  1. Réaffecter chaque fonction de chaque paquet à une variable qui suit certaines conventions de nommage, par exemple, namespace..foo afin d'éviter les inefficacités liées aux namespace::foo (je l'ai décrit une fois ici). Avantages: il fonctionne. Inconvénients: il est maladroit et on double la quantité de mémoire utilisée.
  2. Simuler un espace de noms lors du développement de votre colis. AFAIU, ce n'est pas vraiment possible, au moins j'ai dit donc, pour revenir ensuite.
  3. Rendre obligatoire pour utiliser namespace::foo. À mon humble avis, ce serait la meilleure chose à faire. Bien sûr, nous perdrions une certaine mesure, de la simplicité, mais là encore, la R de l'univers n'est tout simplement pas simple plus (au moins, il n'est pas aussi simple que dans le début des 00's).

Et que dire de (formelle) des classes?

Outre les aspects décrits ci-dessus, :: fonctionne assez bien pour les fonctions/méthodes. Mais ce que sur les définitions de classe?

Prendre le paquet heuredate avec c'est classe timeDate. Dire un paquet vient le long qui a également une classe timeDate. Je ne vois pas comment je pourrais explicitement état que je voudrais une nouvelle instance de la classe timeDate depuis l'un des deux paquets.

Quelque chose comme cela ne fonctionnera pas:

new(timeDate::timeDate)
new("timeDate::timeDate")
new("timeDate", ns="timeDate")

Qui peut être un énorme problème, car de plus en plus de personnes passent à la programmation orientée objet-style pour leur R les paquets, conduisant à beaucoup de définitions de classe. Si il est une façon d'aborder explicitement l'espace de noms de la définition d'une classe, je serais très heureux d'un pointeur!

Conclusion

Même si c'était un peu long, j'espère que j'ai été en mesure de préciser le cœur du problème/question, et que je peux faire plus de sensibilisation ici.

Je pense que devtools et mvbutils avez quelques approches qui peuvent être en vaut la propagation, mais je suis sûr qu'il ya plus à dire.

35voto

SFun28 Points 6444

GRANDE question.

Validation

Écrit robuste, stable et prêt à la production de R code EST dur. Vous avez dit: "Étonnamment, cela ne semble pas déranger beaucoup de programmeurs là-bas". C'est parce que la plupart de la R les programmeurs ne sont pas de l'écriture à la production de code. Ils sont performants one-off académique/tâches de la recherche. Je remettrait sérieusement en question le niveau de compétences de tout coder qui prétend que R est facile à mettre en production. En dehors de mon post sur la recherche/rechercher mécanisme qui vous ont déjà lié, j'ai aussi écrit un post sur les dangers de l' avertissement. Les suggestions qui aideront à réduire la complexité de votre code de production.

Conseils pour la rédaction d'robuste/R code de production

  1. Éviter les paquets qui utilisent Dépend et de la faveur de paquets que le recours aux Importations. Un paquet avec des dépendances en peluche dans les Importations n'est complètement sûrs à utiliser. Si vous devez absolument utiliser un package qui emploie Dépend alors de courriel de l'auteur immédiatement après que vous appelez install.packages().

Voici ce que je dis aux auteurs: "Salut l'Auteur, je suis un fan de la version de XYZ. Je voudrais faire une demande. Pourriez-vous vous déplacez ABC et DEF de la part des Importations dans la prochaine mise à jour? Je ne peux pas ajouter votre colis à mon propre paquet Importations jusqu'à ce que cela arrive. Avec R 2.14 l'application de l'espace de NOMS pour chaque paquet, le message général de R de Base est que les paquets doivent essayer d'être "bons citoyens". Si je charge Dépend d'un paquet, il ajoute une charge de travail importante: je dois vérifier les conflits chaque fois que je prends une dépendance sur un nouveau paquet. Avec des Importations, le paquet est libre d'effets secondaires. Je comprends que vous risquez d'endommager d'autres personnes de paquets en faisant cela. Je pense que c'est la bonne chose à faire pour démontrer un engagement à l'importation et à long terme, il sera aider les gens à produire plus robuste R code."

  1. Utilisation importFrom. Ne pas ajouter un package complet pour les Importations, ajouter uniquement les fonctions spécifiques que vous avez besoin. - Je y arriver avec Roxygen2 fonction documentation et roxygenize() qui génère automatiquement le fichier d'espace de NOMS. De cette façon, vous pouvez importer des deux paquets qui ont des conflits où les conflits ne sont pas dans les fonctions dont vous avez réellement besoin de l'utiliser. Est-ce fastidieux? Seulement jusqu'à ce que cela devienne une habitude. L'avantage: vous pouvez identifier rapidement l'ensemble de vos de la 3e partie des dépendances. Qui aide à...

  2. Ne pas mettre à niveau les paquets à l'aveuglette. Lire le changelog, ligne par ligne, et d'envisager comment les mises à jour vont affecter la stabilité de votre propre paquet. La plupart du temps, les mises à jour ne touche pas les fonctions que vous utilisez réellement.

  3. Éviter S4 classes. Je fais une main brandissant ici. Je trouve S4 être complexe, et il prend assez de cerveau pour la recherche/rechercher mécanisme sur le côté fonctionnel de R. avez-vous vraiment besoin de ces OO fonctionnalité? La gestion de l'etat = la gestion de la complexité - pour Python ou Java =)

  4. Écrire des tests unitaires. Utiliser le testthat paquet.

  5. Chaque fois que vous R CMD construire et tester vos colis, analyser les données en sortie et de regarder pour la NOTE, INFO, WARNING. Aussi, physiquement scan avec vos propres yeux. Il y a une partie de l'étape de génération, les notes des conflits, mais ne fixez pas un WARN, etc. à elle.

  6. Ajouter les affirmations et les invariants à droite après un appel à une 3ème partie du package. En d'autres termes, ne pas faire entièrement confiance à ce que quelqu'un d'autre vous donne. Sonde le résultat un peu et stop() si le résultat est inattendu. Vous n'avez pas à devenir fou - choisir un ou deux assertions qui implique valide/haut niveau de confiance des résultats.

Je pense qu'il y a plus, mais c'est devenu la mémoire musculaire maintenant =) je vais augmenter si de plus qui vient à moi.

19voto

Joris Meys Points 38980

Mon prendre sur elle :

Résumé : la Flexibilité est livré avec un prix. Je suis prêt à payer ce prix.

1) je n'ai tout simplement pas utiliser les paquets qui cause ce genre de problèmes. Si j'ai vraiment, vraiment besoin d'une fonction à partir de ce paquet dans mes paquets, j'utilise l' importFrom() mon NAMESPACE le fichier. En tout cas, si j'ai de la difficulté avec un paquet, j'ai contacter l'auteur du package. Le problème est à leur côté, de ne pas R l'.

2) je n'ai jamais utiliser :: à l'intérieur de mon propre code. En exportant uniquement les fonctions nécessaires par l'utilisateur de mon colis, je peux garder mes propres fonctions à l'intérieur de l'espace de NOMS sans se heurter à des conflits. Les fonctions qui ne sont pas exportés ne cachent pas les fonctions avec le même nom, donc c'est une double victoire.

Un bon guide sur comment exactement les environnements, les espaces de noms et les goûts de travail que vous trouverez ici: http://obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/

C'est certainement un must-read pour tout le monde écrit des paquets et l'aime. Après avoir lu cela, vous vous rendrez compte que l'utilisation d' :: dans votre forfait code n'est pas nécessaire.

0voto

Ajay Ohri Points 59

devrait-il y avoir quelqu'un pour nettoyer les paquets sur CRAN - imbh c'est parce que de trop nombreux package de développement

aussi certains documents d'orientation pourrait aider à définir (ou de nommage) de nouvelles classes/fonctions pour encore plus de paquets

les réponses à vos questions-

Quelle est la méthode recommandée pour minimiser les chances des nouveaux paquets à casser le code existant, c'est à dire de rendre le code que vous écrivez aussi robuste que possible?

A-difficile de le faire pour 5000+ les paquets (et croissante) sans utilise pour pinting les conflits.

Quelle est la meilleure façon de faire le meilleur usage de l'espace de noms du système de a) à l'aide contribué paquets et b) à l'égard de l'élaboration propres paquets?

Un - je ne sais pas, mais il serait utile si nous savions que la fréquence ainsi que l'impact de code ruptures étant donné le grand nombre de R de paquets.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X