I just can't (Nu)Get enough!

NuGet, pour ceux qui ne connaitrait pas encore est un projet Open Source sponsorisé par Microsoft qui adresse (enfin) le "packaging" de composants logiciels. Tout le monde en a besoin et cela manquait cruellement à l'eco-système .Net.

Ce projet est prometteur sur de nombreux aspects mais il n'adresse qu'une petite partie des enjeux. Ce post est, je l'espère, le premier d'une petite série dont l'objectif est de rendre compte de notre expérience à Invenietis en proposant des évolutions concrètes et/ou des compléments qui nous semblent cruciaux. Nous ne sommes pas les seuls à espérer plus, par exemple Davy Brion qui soulève le problème d'une dépendance à "au moins un de ces packages". Tout ce qui concerne le packaging et la gestion de dépendances n'est pas simple. Il est en fait plus souvent complexe que ce que l'on peut penser car il met en jeu notamment :

  • La stratégie de versionning des composants logiciels. Si Microsoft a donné un cadre général avec l'objet Version, il reste :
    • A décider de ce que l'on met dans les quatres nombres Major.Minor.Build.Revision (dans cet ordre! voir cette question sur stackoverflow), et ce n'est pas le plus simple (voir également cette question et ses réponses)
    • A prendre en compte qu'un assembly possède en réalité deux Versions: celle de l'Assembly proprement dite et celle du fichier (ce qui est expliqué ici). Pour faire simple :
      • La Version est utilisée par le chargeur d'Assembly de .Net. Lorsqu'une référence est spécifiée avec <specificVersion>true</specificVersion> (ce qui est le défaut), il faut que l'assembly soit exactement compatible (à propos de cette spécification de version et ses impacts sur les temps de compilation, ce billet vaut le détour).
        Cette information est stockée dans le manifeste de l'Assembly : c'est donc du "pure .Net".
      • FileVersion est plutôt pour "l'affichage"... certes mais attention : Windows Installer le le prend en compteau moment de mettre à jour (c'est pouquoi j'ai mis des guillemets à "affichage").
        Cette information est stockée dans les ressources du fichier selon le format Portable Executable (PE) : c'est donc une information "Windows".
  • La granularité des composants : le même mécanisme est-il compatible à la fois pour quelques "gros composants" et une multitude de mini-composants ?
  • Les "Saveurs" : Comment fait-on gérer les notions de Debug/Release/CodeContractInside/x32/x64/AnyCpu/SL/.Net4/etc. ?
  • La définition des dépendances, par exemple :
    • "Ceci" dépend de "cela" mais seulement à partir de sa version "x".
    • "Ceci" dépend de "cela" ou "cela" (cf. l'exemple pré-cité).
  • Le "contenu" des packages :
    • certains utilisent NuGet pour distribuer du code source. Les règles applicables à la distribution de binaire (dll, exe) sont-elles toujours valides ?
    • comment choisir les fichiers à packager ? Aujourd'hui NuGet est relativement pauvre sur cet aspect.
  • Le type de dépôt de code source : Subversion offre un Revision Number fiable et pratique car c'est un entier que l'on peut mettre dans le slot Revision de la version, mais Git et d'autres n'ont pas cette notion.
  • La Continuous Integration : car gérer toutes ces versions à la main est impossible en pratique (surtout si une granularité fine est nécessaire).

Je pense avoir fait le tour (si ce n'est pas le cas, dites le moi et je complèterai). A part un aspect : les impacts du temps qui passe... indépendamment de l'augmentation des numéros de version.

La nouvelle version du package ne dépend plus de "X". Le package "Y" a été découpé en deux. "Z" s'appelle maintenant "A". "B" n'existe plus, ses features sont intégrées dans "C". "D" que l'on croyait fiable doit impérativement être mis à jour pour des raisons de sécurité. (...)

Bref, vous voyez l'idée. il y-a-t-il UNE solution ? Peut-être pas, mais il y a certainement de bonnes idées/conventions à trouver et mettre en place pour mieux gérer ces aspects. Peut-être un jour travaillerons-nous avec NuGetMore ?