49 votes

concevoir de grands projets dans OCaml

Ce qui est une des meilleures pratiques pour écrire de grands projets logiciels en OCaml?

Comment faites-vous la structure de vos projets?

Quels traits de OCaml devrait et ne devrait pas être utilisé pour simplifier le code de gestion? Des Exceptions? D'abord-les modules de classe? GADTs? Les types d'objet?

Système de construction? Framework de test? Bibliothèque de la pile?

J'ai trouvé de grands recommandations pour haskell, et je pense qu'il serait bon d'avoir quelque chose de similaire pour OCaml.

60voto

Martin Jambon Points 1522

Je vais répondre pour un projet de moyenne envergure dans les conditions que je suis familier avec, entre 100K et 1M de lignes de code source et jusqu'à 10 développeurs. C'est ce que nous utilisons maintenant, pour un projet qui a commencé il y a deux mois, en août 2013.

Système de construction et le code de l'organisation:

  • une source capable de script shell définit le CHEMIN d'accès et d'autres variables de notre projet
  • un .ocamlinit fichier à la racine de notre projet est chargé d'un tas de bibliothèques lors du démarrage d'une session toplevel
  • omake, qui est rapide (avec l'option-j pour des constructions parallèles); mais nous éviter de faire un fou personnalisé omake plugins
  • une racine Makefile contient tous les objectifs essentiels (installation, de construction, de test, propre, et plus)
  • un niveau de sous-répertoires, pas deux
  • la plupart des sous-répertoires de construire dans une bibliothèque OCaml
  • certains sous-répertoires contiennent d'autres choses (configuration, scripts, etc.)
  • OCAMLPATH contient la racine du projet; chaque sous-répertoire de la bibliothèque produit un fichier de métadonnées, de faire de tous OCaml parties des projets accessibles à partir de la racine à l'aide de #l'exigent.
  • un seul OCaml exécutable est construit pour l'ensemble du projet (permet d'économiser beaucoup de temps de lien; encore ne sais pas pourquoi)
  • les bibliothèques sont installées via un script d'installation à l'aide de opam
  • local opam les emballages sont fabriqués pour un logiciel qu'il n'officiel de l'opam référentiel
  • nous utilisons un opam interrupteur qui est un alias nommé d'après notre projet, éviter les conflits avec d'autres projets sur la même machine

Source-l'édition de code:

  • emacs avec opam paquets ocp-tiret et ocp-index

Source de contrôle et de gestion:

  • nous utilisons git et github
  • tous les nouveaux code est examiné par les pairs via github pull requests
  • archives pour la non-opam non github bibliothèques sont stockées dans un autre dépôt git (qui peuvent être emportés si l'histoire devient trop grande)
  • saignement-bord bibliothèques existantes sur github sont fourche dans notre compte github et installé par l'intermédiaire de notre propre local opam paquet

Utilisation d'OCaml:

  • OCaml ne compense pas pour les mauvaises pratiques de programmation; l'enseignement de bon goût est au-delà de la portée de cette réponse. http://ocaml.org/learn/tutorials/guidelines.html est un bon point de départ.
  • OCaml 4.01.0 le rend beaucoup plus facile qu'avant de réutiliser enregistrer les étiquettes de champ et de la variante de constructeurs (c - type t1 = {x:int} type t2 = {x:int;y:int} let t1_of_t2 ({x}:t2) : t1 = {x} fonctionne maintenant)
  • nous essayons de ne pas utiliser de camlp4 extensions de syntaxe dans notre propre code
  • nous n'utilisons pas de classes et d'objets, à moins que mandaté par certains de bibliothèque externe
  • en théorie, depuis OCaml 4.01.0 nous devrions préférer classique variantes plus de variantes polymorphes
  • nous utilisons des exceptions pour indiquer les erreurs et les laisser aller à travers heureux jusqu'à ce que notre serveur principal en boucle les attrape et les interprète comme "erreur interne" (par défaut), "bad request", ou quelque chose d'autre
  • des exceptions comme Sortie ou Not_found peut être utilisé localement lorsque cela a du sens, mais dans le module d'interfaces, nous avons préféré utiliser les options.

Les bibliothèques, les protocoles, les cadres:

  • nous utilisons des Batteries pour tous les produits de base des fonctions qui manquent à OCaml de la bibliothèque standard; pour le reste, nous avons un "util" de la bibliothèque
  • nous utilisons Lwt pour la programmation asynchrone, sans la syntaxe des extensions, et la liaison de l'opérateur (>>=) est le seul opérateur que nous utilisons (si vous avez de savoir, nous ne contrecœur utilisation camlp4 de prétraitement pour mieux exception de suivi sur lier points).
  • nous utilisons l'adresse HTTP et JSON pour communiquer avec la 3e partie du logiciel et nous attendons de tous les services modernes pour fournir ces Api
  • pour servir HTTP, nous gérons notre propre SCGI serveur (ocaml-scgi) derrière nginx
  • comme un client HTTP, nous utilisons Cohttp
  • pour la sérialisation JSON nous utilisons atdgen

Services "en nuage":

  • nous utilisons beaucoup d'entre eux car ils sont généralement bon marché, facile à interagir avec, et de résoudre l'évolutivité et la maintenance des problèmes pour nous.

Test:

  • nous avons un faire/omake cible pour les tests rapides et d'une lente tests
  • rapide les tests sont des tests unitaires; chaque module peut fournir une fonction "test"; un test.ml fichier s'exécute la liste des tests
  • lent tests sont ceux qui impliquent l'exécution de plusieurs services; ceux-ci sont fabriqués spécialement pour notre projet, mais ils couvrent autant que possible comme un service de la production. Tout fonctionne localement, soit sur Linux ou MacOS, sauf pour les services de cloud pour laquelle nous trouver des moyens pour ne pas interférer avec la production.

Réglage de tout cela est tout à fait un peu de travail, surtout pour quelqu'un qui ne sont pas familiers avec OCaml. Il n'y a pas de cadre en prenant soin de tous, mais au moins vous aurez le choix des outils.

10voto

gildor Points 91

OASIS

Pour ajouter à Pavel réponse:

Avertissement: je suis l'auteur de l'OASIS.

OASIS a également oasis2opam qui peuvent aider à créer des OPAM colis rapidement et oasis2debian pour créer des paquets Debian. C'est extrêmement utile si vous souhaitez créer une "libération" de la cible, permettant d'automatiser la plupart des tâches d'envoyer un paquet.

OASIS est également livré avec un script appelé oasis-dist.ml qui crée automatiquement une archive à télécharger.

Regarder tout cela dans https://github.com/ocaml.org.

Les tests

J'utilise OUnit faire mes tests. C'est simple et assez efficace si vous êtes habitué à xUnit tests.

Source/contrôle de gestion

Avertissement: je suis le propriétaire/responsable de forge.ocamlcore.org (aka forge.o.o)

Si vous souhaitez utiliser git, je vous recommande d'utiliser github. C'est vraiment efficace pour l'examen.

Si vous utilisez darcs ou de subversion, vous pouvez créer un compte sur la forge.o.o.

Dans les deux cas, avoir une liste de diffusion publique où vous envoyez tous les commettre de notification est un must, de sorte que tout le monde puisse les voir et les revoir. Vous pouvez utiliser Google groupes ou une liste de diffusion sur la forge.o.o.

Je recommande d'avoir un beau site web (github ou d'une forge.o.o) la page avec ocamldoc peut être de la documentation construire à chaque fois que vous s'engager. Si vous avez une énorme base de code cela vous aidera à utiliser le ocamldoc peut être généré de la documentation dès le début (et de corriger le problème rapidement).

Je vous recommande de créer des archives lorsque vous atteignez un stable stade. Ne vous fiez pas seulement sur la vérification de la dernière version du git/svn version. Cette astuce m'a permis d'économiser des heures de travail dans le passé. Comme le dit Martin, stocker tous vos fichiers dans un endroit central (un dépôt git est une bonne idée pour que).

5voto

Pavel Zaichenkov Points 530

Sans doute celui-ci ne répond pas à votre question complètement, mais voici mon expérience concernant l'environnement de compilation:

J'apprécie vraiment OASIS. Il a une belle gamme de fonctionnalités, d'aider non seulement à construire le projet, mais aussi à écrire de la documentation et de support de l'environnement de test.

Système de construction

  • OASIS génère setup.ml le fichier à partir de la spécification (_oasis le fichier), qui travaille sur la base d'un script de construction. Il accepte -configure, -build, -test, -distclean drapeaux. J'ai bien utilisé, tout en travaillant avec différents GNU et d'autres projets qui utilisent habituellement les Makefiles et je trouve ça pratique qu'il est possible de les utiliser toutes automatiquement ici.
  • Les Makefiles. Au lieu de générer setup.ml, il est également possible de générer un Makefile avec toutes les options décrites ci-dessus.

Structure

Habituellement mon projet qui est construit à l'OASIS dispose d'au moins trois répertoires: src, _build, scripts et tests.

  • Dans l'ancien répertoire de tous les fichiers sources sont stockées dans un répertoire: source: (.ml) et de l'interface.mli) les fichiers sont stockés ensemble. Peut-être si le projet est trop grand, il vaut la peine d'introduire plus de sous-répertoires.
  • L' _build répertoire est sous l'influence de l'OASIS de construction du système. Il stocke à la fois source et objet de fichiers, et j'aime créer des fichiers ne sont pas interféré avec les fichiers source, donc je peux facilement le supprimer dans le cas où quelque chose va mal.
  • Je stocker plusieurs scripts shell dans l' scripts répertoire. Certains d'entre eux sont pour l'exécution de tests et de l'interface de génération de fichier.
  • Toutes les entrées et les fichiers de sortie pour les tests je les stocker dans un répertoire séparé.

Interfaces/Documentation

L'utilisation de fichiers d'interface (.mli) a à la fois des avantages et des inconvénients pour moi. Il aide vraiment à trouver des erreurs de type, mais si vous les avez, vous avez à les modifier aussi bien lorsque vous apportez des modifications ou des améliorations dans votre code. Oublier parfois cela provoque méchant erreurs.

Mais la principale raison pourquoi j'aime les fichiers d'interface est de la documentation. J'utilise ocamldoc peut être de générer des OASIS (prend en charge cette fonctionnalité avec -doc drapeau) des pages html avec des documents automatiquement. C'est à mon avis suffisant pour écrire des commentaires décrivant chaque fonction dans l'interface et de ne pas insérer des commentaires dans le milieu de code. En OCaml, les fonctions sont généralement courtes et concises, et si il y a une nécessité d'insérer l'ajout de commentaires là, peut-être que c'est mieux de diviser la fonction.

Également être conscients de l' -i drapeau pour ocamlc. Le compilateur peut générer automatiquement un fichier d'interface pour un module.

Tests

Je n'ai pas trouver une solution raisonnable pour le soutien des tests (je voudrais avoir quelques - ocamltest application), c'est pourquoi je suis en utilisant mes propres scripts pour l'exécution et la vérification des cas d'utilisation. Heureusement, OASIS prend en charge l'exécution des commandes personnalisées lors de l' setup.ml est exécuté avec -test drapeau.

Je n'utilise pas d'OASIS pour un temps long et si quelqu'un sait toutes les autres caractéristiques intéressantes, j'aimerais aussi savoir à leur sujet.

Aussi, il vous ne sont pas conscients de l' OPAM, il est certainement intéressant de regarder. Sans elle, l'installation et la gestion de nouveaux paquets est un cauchemar.

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