Sexe aléatoire, nullité et Sql

Avec un titre comme ça, je suis sûr d’avoir 2 ou 3 lecteurs. Je lis actuellement « Sql for smarties » de Joe Celko. Tout n’est pas parfait dans ce livre, mais il y a certaines choses amusantes que je découvre avec plaisir : par exemple que le genre est normalisé par ISO 5218 « Information technology — Codes for the representation of human sexes ». Il s’agit d’un chiffre unique désigné dans le standard par « SEX » dont les quatre valeurs possibles sont :

  • 0 = inconnu (unknown),
  • 1 = homme (male),
  • 2 = femelle (female),
  • 9 = non applicable (not applicable).

Note 1 : Les rédacteurs du standard ont pris la peine de préciser que le fait que Homme était 1 et la Femme 2 n’avait aucune signification particulière... que cela était dû aux pays qui ont « poussé » ce standard. Et vous reconnaissez le premier chiffre du numéro de sécurité sociale français : c’est une preuve irréfutable du rayonnement culturel de la France dans le monde.

Note 2 : Sexe « non applicable » ne recouvre pas d’accident biologique particulier, il s’agit d’une valeur à utiliser pour des personnes morales (une entreprise n’est donc ni homme ni femme – bien au contraire aurait ajouté Pierre Dac).

Note 3 : Je viens, l’air de rien, de vous faire économiser 92 francs suisses, soit environ 65 euros. C’est en effet le prix à payer pour le PDF officiel de la norme ISO 5218. C’est scandaleux mais c’est comme ça : les standard ISO sont payants.

Revenons au SEX (avec ce billet, ce blog va perdre des points de ranking) et à SQL pour insister sur « l’inconnu » et le « non applicable ». Ces deux notions se cachent habituellement derrière le NULL, ici elles ont été explicitées et c’est une bonne chose d’un point de vue lisibilité/expressivité ainsi qu’en terme de mise en œuvre (moins on utilise de colonne NULLABLE, mieux on se porte et je ne vais pas faire ici le topo classique de la logique ternaire et des problèmes subtils introduits par le NULL car on les trouve partout).

Une autre découverte pour moi de la lecture du livre de Joe Celko est un aspect de l’instruction CASE que j’ignorais. Supposons que l’on veuille initialiser une valeur aléatoire pour un SEX. Nous avons 4 valeurs à tirer au sort (de façon équiprobable), le code suivant semble correct :

select case CAST( (4*rand()) as int )
          when 0 then '0' -- Unknown
          when 1 then '1' -- Male
          when 2 then '2' -- Female
          when 3 then '9' -- Unapplicable
       end

Et pourtant il ne l’est pas. Ci-dessous un test tout bête : il remplit 200 000 lignes d’une table avec une colonne SEX aléatoire selon le code précédent.

create table dbo.tTest( Sex char );
-- Caution: Declare and initialize in the same statement like this 
-- works only on Sql Server 2008, not 2005. 
declare @i int = 200000; 
while @i > 0
begin
	insert into dbo.tTest( Sex )
		select	case CAST( (4*rand()) as int )
					when 0 then '0' -- Unknown
					when 1 then '1' -- Male
					when 2 then '2' -- Female
					when 3 then '9' -- Unapplicable
				end
	set @i = @i-1;
end

Et on affiche le contenu de la table résultante avec le compte et la probabilité résultante.

select 	Sex, 
        COUNT(*), 
        Prob = cast(COUNT(*) as float)/200000 
    from dbo.tTest
   group by Sex
   order by 1;

Première observation : NULL apparait.

Deuxième constat : les nombres respectifs de valeurs (et donc leurs probabilités) ne sont pas équitablement répartis.

SexCountProb
NULL 63338 0,31669
0 50067 0,250335
1 37320 0,1866
2 27918 0,13959
9 21357 0,106785

Les matheux auront compris. L’instruction CASE est, en fait, réécrite ainsi :

select	case 
		when CAST( (4*rand()) as int ) = 0 then '0' -- Unknown
		when CAST( (4*rand()) as int ) = 1 then '1' -- Male
		when CAST( (4*rand()) as int ) = 2 then '2' -- Female
		when CAST( (4*rand()) as int ) = 3 then '9' -- Unapplicable
	end

Ce qui ne correspond pas du tout à l’idée initiale, et pouf pas marche.

La solution est évidemment de capturer la valeur fournie par la fonction rand() dans une variable:

declare @p int = CAST( (4*rand()) as int );
select	case @p
			when 0 then '0' -- Unknown
			when 1 then '1' -- Male
			when 2 then '2' -- Female
			when 3 then '9' -- Unapplicable
		end

N'incriminez pas SQL Server : ce sont les spécifications de SQL. C’est comme ça et pas autrement que le CASE doit être implémenté, la forme « classique » du switch-case que l’on connait dans de nombreux langages n’est pas celle réellement supportée par SQL, elle n’est qu’un sucre syntaxique autour du « râteau de si ». SQL ne connait vraiment que le râteau !

Pour finir, un exercice : montrer en calculant les probabilités formellement que le comportement observé (NULL et probabilités différentes) est parfaitement logique.

Les arguments d’un évènement

Suite à une remarque d’Antoine, je me sens obligé aujourd’hui d’expliquer un point de conception lié à la modélisation des évènements dans CK.

Néanmoins, avant de plonger dans la technique, une remarque préliminaire s'impose:

L'Académie française, dans la neuvième édition de son Dictionnaire, écrit, en accord avec les recommandations du Conseil supérieur de la langue française de 1990, évènement. La graphie ancienne événement n'est cependant pas considérée comme fautive, encore que rien ne la justifie plus. Sa survivance s'explique par le fait que la régularisation de ce mot, ainsi que de quelques autres, d'abrègement à vènerie, avait été oubliée lors de la préparation tant de la septième édition (1878) que de la huitième (1935).
www.academie-francaise.fr/langue/rectifications_1990.pdf

Hériter… ou pas.

En règle générale, les concepteurs essayent d’éviter autant que possible les arbres d’héritage profonds : une structure d’héritage « flat » (et orthogonale) est toujours préférable (à une horreur de type MFC) car elle garantit à la fois une meilleure lisibilité (et donc maintenabilité) et réutilisabilité. Pourtant, dans CK, il existe un endroit où la structure d’héritage n’est pas du tout, mais alors vraiment pas, plate… Il s’agit des objets arguments d’évènements. Par exemple, l’argument de l’évènement correspondant à l’échange des modes de deux touches réelles. Cette classe s’appelle ActualKeyModeSwappedEventArgs et voici sa chaîne d’héritage:

ActualKeyModeSwappedEventArgs Les modes de deux touches ont été échangés.
 > ActualKeyModeChangedEventArgs  Le mode d’une touche a changé.
  > ActualKeyEventArgs L’évènement concerne une touche réelle.
   > KeyEventArgs L’évènement concerne une touche.
    > KeyboardEventArgs L’évènement concerne un clavier.
     > ContextEventArgs L’évènement concerne un contexte CK.
      > EventArgs Un évènement s’est produit.

Six classes de base !

Pourquoi les arguments d’évènements s’inscrivent-ils dans une chaîne d’héritage si profonde ? Le concepteur aurait-il abusé de substances illicites ? Que nenni (enfin si mais cela n’a pas eu d’impact sur ce qui nous occupe). Nous avons là une exception qui confirme la règle de la platitude (je ne sais pas si c’est la seule exception), car cette chaîne d’héritage permet aux évènements d’être interceptés à n’importe quel niveau de précision. Et c’est bien pratique.

Le bon héritage

Relevons d’abord un aspect important : cette conception respecte totalement la sémantique de la spécialisation et ne crée aucun des problèmes souvent rencontrés lorsque l’on abuse de l’héritage.

  • Sur le respect de la sémantique d’abord, analysons la chaîne présentée ci-dessus :
    Le fait d’échanger les modes de deux touches est un (is_a) changement de mode qui est un (is_a) évènement d’une touche réelle qui est un (is_a) évènement d’une touche qui est un (is_a) évènement d’un clavier qui est un (is_a) évènement d’un contexte qui est un (is_a) évènement.
    Ce respect de la règle est un (is a en anglais) est la règle fondamentale à respecter lorsque l’on spécialise une classe. Si on ne peut pas dire A est un B, alors A ne devrait pas hériter de B (les exceptions à cette règle existent - mixins et autres héritages de réutilisation – mais ne les commettez qu’en toute connaissance de causes et d’effets).
  • Sur la mise en œuvre d’autre part, il faut noter que ces « classes évènements » sont implémentées sans mettre en œuvre de propriétés ou méthodes protégées : ici, l’héritage ne peut « casser l’encapsulation » (chercher dans votre moteur préféré « inheritance breaks encapsulation » pour plus d’information sur ce sujet parfois un peu subtil). Chaque classe apporte des propriétés publiques qui décrivent, précisent, l’évènement correspondant : aucune réutilisation d’implémentation n’est faite ici, on est dans le cas d’un sous-typage (subtyping) plutôt que d’un héritage (inheritance).

Cet usage de l’héritage est donc correct en regard des canons de l’ingénierie logicielle. Mais à quoi cela sert ?

« Client side » : je consomme l’évènement

Comme je l’ai déjà écrit ci-dessus, l’intérêt est de faciliter la prise en compte de ces évènements au « niveau de détail » que l’on souhaite. Considérons l’évènement correspondant à un des arguments ci-dessus :

public interface IKey
{
   ...
   event EventHandler ActualKeyModeChanged;
   ...
}

En tant que client, je peux inscrire ces évènements auprès de n’importe quelle fonction dont la signature respecte le type de l’argument en tenant compte de l’héritage. Je peux, bien évidemment, m’inscrire ainsi à l’évènement :

   IKey k = ...;
   k.ActualKeyModeChanged += OnKeyModeChanged;
   ...

void OnKeyModeChanged( object source, ActualKeyModeChangedEventArgs e )
{
   ...
}

Mais, je peux aussi m’intéresser à ce même évènement ainsi :

   IKey k = ...;
   ...
   k.ActualKeyModeChanged += OnSomethingChangedInKey;
   k.KeyPropertyChanged += OnSomethingChangedInKey;
   ...

void OnSomethingChangedInKey( object source, KeyEventArgs e )
{
   ...
}

Ou même :

   IKey k = ...;
   ...
   k.ActualKeyModeChanged += OnSomethingHappened;
   k.Keyboard.AvailableModeChanged += OnSomethingHappened;
   k.Context.CurrentKeyboardChanged += OnSomethingHappened;
   ...

void OnSomethingHappened( object source, EventArgs e )
{
   ...
}

Vous voyez l’idée : comme le changement de mode d’une touche réelle est un (is_a) évènement, je peux y souscrire justement comme à un évènement quelconque, je ne suis pas contraint d’utiliser le type précis de l’argument.

« Server Side » : j’émets un évènement

Il existe une autre utilisation possible de cet héritage si l’on se place de l’autre coté de la barrière : celui où on émet l’évènement plutôt que de le recevoir. En l’occurrence, il se trouve que ActualKeyModeSwappedEventArgs et ActualKeyModeChangedEventArgs illustrent cette utilisation.

Le premier correspond à l’échange des modes de deux touches, le deuxième (qui généralise le premier) à un changement de mode d’une touche.
Les interfaces IKey et IKeyboard exposent toutes deux l’évènement ActualKeyModeChanged. Le fait que le changement soit dû à un échange plutôt qu’à un changement direct est un détail pour la grande majorité des clients (les plugins en l’occurrence), mais on souhaite quand même exposer la cause de l’évènement à ceux qui sont susceptibles de s’y intéresser. La première idée est d’exposer un deuxième évènement :

public interface IKey
{
   ...
   event EventHandler<ActualKeyModeChangedEventArgs> ActualKeyModeChanged;
   event EventHandler<ActualKeyModeSwappedEventArgs> ActualKeyModeSwapped;
   ...
}

Mais cela pose un vrai problème de conception : tout déclenchement de l’évènement Swapped doit être doublé d’un déclenchement de Changed sinon un client qui ne s’est inscrit qu’au premier ne verra jamais les changements causés par un échange de mode. Outre la pollution de l’interface IKey par un évènement peu utilisé, cela entraîne aussi le fait que le client qui s’intéresse aux deux devra dédoublonner les évènements pour éviter de les prendre en compte deux fois… Ce ne sera pas fait. Ou mal fait. C’est ce qu’on appelle une usine à bugs.

La bonne solution consiste à utiliser l’héritage dans l’autre sens. On ne publie qu’un seul évènement :

public interface IKey
{
   ...
   /// 
   /// Fires whenever the mode of one of our <see cref="ActualKeys"/> changed.
   /// The event argument may be an instance of the 
   /// <see cref="ActualKeyModeSwappedEventArgs"/> class if the change 
   /// is the result of a call to <see cref="IActualKey.SwapModes"/> 
   /// instead of <see cref="IActualKey.ChangeMode"/>.
   /// 
   event EventHandler<ActualKeyModeChangedEventArgs> ActualKeyModeChanged;
   ...
}

Et son argument sera du type ActualKeyModeSwappedEventArgs dans le cas du Swap, ce qui est facile à tester par les clients que cela intéresse :

void OnKeyModeChanged( object source, ActualKeyModeChangedEventArgs e )
{
   ActualKeyModeSwappedEventArgs eSwap = e as ActualKeyModeSwappedEventArgs;
   if( eSwap != null )
   {
      // The change is due to a swap. The event argument gives us the swapped key.
      IActualKey other = eSwap.SwappedKey;
      ...
   }
   else
   {
     // Handle ChangeMode event.
     ...
   }
}

En résumé, cette technique permet de ne pas polluer les interfaces avec des évènements rarement utilisés et de permettre une prise en compte simple et efficace de « sous-catégories » précises d’évènements.

Conclusion

Le modèle des évènements de .Net, qui repose sur les délégués (delegates) et la signature standard (object source, EventArgs e) est simple et puissant. A condition de l’exploiter correctement, et donc de l’avoir compris.

Cette discussion, qui nous a amené à traiter du bon usage de l’héritage, introduit deux aspects de l’utilisation de l’héritage en conception. Pour aller plus loin, je vous encourage à regarder du coté de la co-variance et de la contra-variance qui sont des notions très proches de ce que nous avons présenté ici.

Dans un prochain post traitant des évènements, j’aborderai de ce que je considère comme une des (rares) erreurs de conception du framework .Net : la classe EventArgs elle-même…

La roadmap de CiviKey : déjà une V2.5 ?

Le nom final du produit CVK a été trouvé et accepté lors d’une réunion des partenaires actuels : il s’agit de CiViKey (ou CiviKey ?). Compromis certes (l’historique est préservé) mais promesse d’une communication grand public facilitée.
 
C’est l’occasion pour moi de faire un petit point sur les aspects techniques : un état des lieux d’abord et un éclairage sur le futur ensuite.
 
Ce que l’on appelle aujourd’hui CiviKey a pour nom de code CVK-V2. A l’origine, ce projet n’était qu’un support de cours qui avait pour objectif :

  • D’effectuer une « Modélisation » en direct, « Les claviers » étant la réalité à modéliser.
    (Note : Le fait que des notions « irréelles », applicables uniquement à la modélisation était un aspect particulièrement intéressant n’a guère excité que moi… Solitude du pédagogue…
    Exercice : isoler ces aspects propres au modèle dans le code.)
  • De mettre en œuvre des collections, des accesseurs complexes, d’encapsuler, de sécuriser une API (au sens de limiter le développeur à des actions en accord avec la donnée), de couvrir autant de types de relations directs entre objets possibles (cycle de vie, attachement/détachement, unicité de nommage, multiplicité d’accesseurs), etc.
  • De réaliser une application graphique en .Net (un petit peu plus complexe que les applications scolaires traditionnelles).

Nous n’avons pas eu le temps, au moment où la décision a été prise d’utiliser cette base pour la V2, de revoir le noyau. De fait, la conception initiale du Contexte (Keyboard, Zone, Key, etc.) a couvert les besoins durant deux ans en supportant très correctement l’ajout des fonctionnalités : la gestion des plugins, des propriétés dynamiques (le Shared Dictionary), de la persistance, des éditeurs, etc.
 
Ayant relu attentivement le code dernièrement, j’ai néanmoins tiqué sur 2 aspects très discutables de l’implémentation actuelle car peu ou mal spécifié et réfléchis (ce qui est nettement plus grave J) que sont :

  1. la gestion des Modes du clavier (pour des raisons qui seraient un peu longue à détailler ici) ;
  2. le support du copier-coller, principalement car elle se contente d’utiliser « de l’extérieur » l’import/export xml original (destiné à la persistance) alors qu’il eut fallu une refonte/adaptation/extension de l’import afin de supporter naturellement le collage.

Nous avions par ailleurs pris la décision il y a quelques mois de masquer l’implémentation (absolument tous les objets d’implémentation) au profit d’un modèle public purement abstrait (constitué uniquement d’interfaces) et ce afin de maximiser les capacités d’évolutions du noyau. Ce travail de refactoring est un très classique processus de découplage que nous pensons nécessaire compte tenu des objectifs de pérennité de l’application.
 
Enfin, une évolution très importante en termes de fiabilité est actuellement en attente dans les cartons : la création dynamique de proxy d’interception des Services supportés par les Plugins qui ont pour objectifs :

  • d’isoler les plugins mal programmés (qui ne respectent pas les règles du jeu en terme d’appel des autres plugins ou d’émission d’événements selon l’état – Running/Stopped – des plugins) ;
  • de pouvoir éventuellement tracer tous les appels inter-plugins (idéalement, il est possible de décider des traces pour chaque méthode ou événements du système en cours d’exécution) ;
  • d’être une démonstration de la <pub>capacité de .Net à faire des trucs impressionnants et ce, tout bien pesé, assez facilement </pub>.

Le proxy (le modèle ainsi que la génération dynamique de code IL) est prêt. Il ne contient pas les fonctionnalités d’interception en tant que telle (et évidemment encore moins sa « configurabilité »). Il est maintenant nécessaire de l’intégrer et de fournir les objets proxy aux plugins plutôt que les objets Plugins eux-mêmes.

Regroupées, ces évolutions sont assez lourdes et nous avons donc décidé d’en faire une mile stone importante de release dans les prochains mois : CiviKey (CVK-V2) n’est pas encore (vraiment) sorti qu’une version 2.5 se profile déjà.

Le Nom de la Chose

Quel doit être le nom du CVK ?
Je ne sais pas. Il y a des gens autrement plus qualifiés que moi qui se posent la question. En attendant, on a besoin d’avancer et ce genre de détail a un impact sur le code.
Dans la version actuelle, un très grand nombre de classes sont préfixées par CVK (CVKContext par exemple). Nous avons décidé de supprimer ce préfixe.
Il reste cependant l’espace de nommage : CVK.Core, CVK.Model, etc.
Si le nom retenu finalement est Ubikey (par exemple ;-)), va-t-il falloir tout renommer en UBK ? Si oui, il faudra aussi renommer les répertoires du système de fichier (il serait très désagréable de travailler avec un tel décalage).
 
Non seulement cela demande quelques heures de travail, mais renommer des répertoires proche de la racine « casse » assez violemment le dépôt de code source sous Subversion (notamment la consultation de l’historique). (Oui, je sais, normalement cela fonctionne très bien le renommage dans SVN… J’ai néanmoins eu des très mauvaises expériences.)
 
Parallèlement à cela, en essayant de faire passer FxCop sur les sources, cette règle est apparue :
 
 Resolution   : "Correct the casing of 'CVK' in assembly name 'CVK.SharedDic.dll'
                 by changing it to 'Cvk'."
 Help         : http://msdn2.microsoft.com/library/ms182240(VS.90).aspx  (String)
 RuleFile     : Naming Rules  (String)
 Info         : "Type, namespace, and member identifiers are Pascal-cased.
                 Parameter identifiers are camel-cased. Two letter acronyms
                 within these identifiers should be upper-cased, for
                 example, use System.IO instead of System.Io. Acronyms
                 of three or more letters should be Pascal-cased, for
                 example, use System.Xml instead of System.XML. The
                 pascal-casing convention capitalizes the first letter
                 of each word, as in BackColor. The camel-casing convention
                 formats the first letter of the first word in lowercase
                 and capitalizes the first letter of all subsequent
                 words, as in backgroundColor. Although it may be common
                 practice for some two letter acronyms to not be fully
                 capitalized, violations of this rule should not be
                 excluded for this reason. For example, 'DbConnection',
                 is common but incorrect; use DBConnection. A violation
                 of this rule might be required for compatibility with
                 existing, non-managed symbol schemes. In general, however,
                 these symbols should not be visible outside the assembly
                 that uses them."

 
En substance, il faut renommer CVK en Cvk pour être parfaitement en ligne avec les règles de nommage… Ou alors, si l’on souhaite conserver les majuscules, il faut retirer une lettre…
 
Du coup, j’ai décidé de nommer (une bonne fois pour toute je l’espère) l’objet technique qu’est ce Custom Keyboard en… Custom Keyboard. Ce qui nous fait un assez satisfaisant (de mon point de vue) espace de nommage (et préfixe éventuel) CK.
 
Pour conclure, il est clair que CK : « C’est le Kode ! »
Cela ne présage nullement de la dénomination officielle du produit. Mais au moins, on peut bosser.

La licence de CiviKey

Un petit mot au sujet de la licence de CiviKey. Il s’agit d’une L-GPL. Qu’est-ce donc exactement ? Que pouvez-vous faire réellement avec les codes sources, les binaires (librairies dynamiques compilées et exécutables) ?

1. Un résumé

Ci-dessous un descriptif de licence type trouvé sur internet (http://dbaling.blogspot.com/2009/02/find-missing-index.html), comme on peut en trouver beaucoup, mais avec en sus une explication claire et concise (mise en gras ci-dessous).
Il s’agit d’une licence associée à une procédure stockée, d’où la référence à une base de données.

Copyright:
Licensed under the L-GPL - a weak copyleft license - you are permitted to use this as a component of a proprietary database and call this from proprietary software.
Copyleft lets you do anything you want except plagiarize, conceal the source, proprietarize modifications, or prohibit copying & re-distribution of this script/proc.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
see <http://www.fsf.org/licensing/licenses/lgpl.html> for the license text.

Je considère cet « extrême résumé » comme plutôt bien fait et vais donc en profiter pour le traduire et le commenter dans le cadre de CiviKey.

2. La notion de « copyleft licence »

Voir wikipedia pour le terme de copyleft. En résumé c’est un jeu de mot sur l’opposition à copyright (droit d’auteur) dont le principe est le suivant
« Je suis l’auteur de ce code. J’ai fixé des limites (ou pas) à ce que vous pouvez faire de ce code via une licence. Vous pouvez faire ce que vous voulez de mon code (dans les limites de la licence : le vendre, le distribuer gracieusement, le modifier, etc.), mais en aucun cas vous ne pouvez restreindre les libertés garanties par cette licence. »
 
Pour faire encore plus simpl(ist ?)e : la notion de Copyleft permet à un auteur gentil de mettre à disposition son œuvre en ayant la garantie qu’aucun business man méchant ne s’accapare son travail et dénie à autrui ce que l’auteur gentil l’avait gentiment autorisé à faire.
 
Ça, c’est le Copyleft en général. On en distingue deux catégories très différentes en pratique : le faible (weak) et le fort (strong).

2.1    Strong Copyleft

Toujours de façon très synthétique : le Copyleft « fort » impose à toute utilisation de l’œuvre d’être redistribuée sous la même licence, là où le « faible » n’impose sa licence que pour certaines utilisations qui touchent à l’intégrité de l’œuvre elle-même : principalement la modification ou la traduction.
 
Le Copyleft fort est souvent qualifié de « virale » : tout programme qui utilise un composant avec ce type de licence devient de facto, et dans son intégralité, soumis à cette licence. La licence GPL est de ce type et l’enjeu devient alors de distinguer les utilisations qui imposent la licence de celles qui ne l’imposent pas.
Ici, on entre dans des détails techniques auxquels d’une part les juristes ne comprennent pas grand-chose (à l’instar de certains « informaticiens » d’ailleurs) et d’autre part qui évoluent avec les technologies : liens statiques ou dynamiques, encapsulation d’un exécutable, utilisation de la spécialisation (héritage), etc.
En résumé : l’objectif d’un Copyleft fort est de dire aux autres informaticiens « Mon composant vous plaît ? Si vous l’utilisez, vous devez jouer le jeu de l’Open Source comme moi ! Sinon, débrouillez vous autrement. »

2.2 Weak Copyleft

Ce n’est pas le cas de CiviKey qui est en L-GPL. « L » pour « Lesser », c'est-à-dire plus faible. Elle est plus faible dans le sens où elle permet l’utilisation du composant logiciel sans imposer sa licence : le coté « viral » a disparu.

3. La licence de CiviKey : L-GPL

Alors que reste-t-il comme contraintes à respecter ? Très peu.

you are permitted to use this as a component of a proprietary application and call this from proprietary software.

Vous pouvez utiliser CiviKey dans une application spécifique et propriétaire (dont vous ne divulguez pas les sources) et la commercialiser, développer des plugins propriétaires (dont vous ne divulguez toujours pas les sources) et les commercialiser conjointement ou non avec leur propre licence que vous choisissez comme bon vous semble.

Copyleft lets you do anything you want except plagiarize, conceal the source, proprietarize modifications, or prohibit copying & re-distribution of this script/proc.

Vous ne pouvez pas :

  • Plagier CiviKey, c'est-à-dire copier tout ou partie du code source en l’intégrant à votre programme.
  • Dissimuler l’origine : c'est-à-dire distribuer CiviKey ou une application qui l'utilise sans dire clairement à vos utilisateurs, collègues, patrons ou investisseurs que vous l'utilisez.
  • Garder les modifications pour vous : c'est-à-dire faire évoluer CivKey lui-même (le noyau) sans remettre vos modifications dans le « pot commun » et rendre ces modifications visibles à toute personne qui le demande.
  • Interdire la copie ou la redistribution : ce n’est pas parce que votre application ou plugin propriétaire ne peut être copié ou redistribué que ces interdictions s’appliquent aux composants de CiviKey eux-mêmes.

En substance, vous pouvez utiliser les composants exécutables ou librairies dynamiques comme bon vous semble. Si vous modifiez les sources, vos modifications sont de facto sous licence L-GPL. A ce titre, nous apprécierons que vous les soumettiez à la communauté afin de faire progresser le projet.
Enfin, si vous « récupérez » un ou plusieurs fichiers, une classe ou un morceau de framework et que vous l’intégrer directement dans votre application (que celle-ci soit une librairie dynamique ou un exécutable), vous devez conserver l’entête du ou des fichiers, ne pas modifier leur contenu (sauf à publier ses modifications) et surtout, afficher le fait que votre application repose, en partie, sur un « morceau » de CiviKey.

Il n’y a donc finalement que quatre écueils à éviter qui ont pour nom : Plagiat, Dissimulation, Privatisation et Restriction.
Si vous échouez sur un de ces écueils, vous vous asseyez tranquillement sur notre travail. Ce ne serait pas gentil.