CiviKey évolue encore un peu

Comme je vous le disais il y a pile un mois (ou un peu plus), une version 2.6.0 de CiviKey est dans les cartons pour la nouvelle année.

Et bien une nouvelle release de la distribution Alpha est disponible (la 2.6.1). Cette release apporte des corrections de bugs dans différents plugins, et surtout de nouvelles fonctionnalités !

Une aide intégrée, facile à utiliser, et bientôt facile à éditer.

 

Un éditeur de clavier beaucoup plus puissant.

Il permet maintenant de créer, modifier, supprimer des touches, des zones, ainsi que leurs layouts etc etc etc. Bref vous pouvez (presque) tout faire avec !

 

 

Niveau stabilité, il reste un peu de chemin à faire afin de corriger les derniers bugs qui peuvent survenir lors de l'utilisation des nouveaux plugins. Cependant le plus dur est fait, il reste maintenant à passer les derniers coups de polish et nous serons près d'ici 2013 pour vous livrer une nouvelle version !

On vous tient au courant :)

Comme la dernière fois, n'hésitez pas à lire le code sur GitHub ou à nous suivre sur Twitter ou Facebook

Une version 2.6.0 de CiviKey pour 2013

Et oui, outre la sortie du nouveau site officiel en aout dernier et un léger problème de mise à jour automatique, CiviKey continu d'évoluer !

Grâce au soutien de la Fondation Garches et d'Alcatel Lucent, CiviKey passera pour la nouvelle de la version 2.5.2 à la version 2.6 !

Une 2.6, pas une 3.0 ?

Et non, pas une 3.0 car aucun changement majeur n'a été fait au sein du noyau depuis la grande bataille de la 2.5. L'objectif de la 2.6 est d'ajouter à CiviKey différents plugins indispensables aux ergothérapeutes et personnes en situations de handicap qui l'utilisent au jour le jour.

Au menu de cette 2.6 les fonctionnalités que tout bon clavier visuel se doit d'avoir : une prédiction de mot, et une solution de défilement des touches du clavier. S'ajoute à cela quatre nouveautés :

  • un clavier permettant grâce au défilement de déplacer et d'effectuer opérations de base de la souris
  • un assistant au premier démarrage
  • un assistant création 
  • et édition de clavier, et enfin une aide contextuelle intégrée

D'ici 2013 ... et avant ?

La sortie finale de la version 2.6 est prévu pour 2013. Vous souhaitez d’ores et déjà essayer nos builds fraichement sortis du four ?

Contactez-nous et nous vous fournirons un installeur spécifique pour la pre-release. Cette alpha version:

  • est déployée parallèlement à tout autre installation existante;
  • se mettra à jour sur notre "canal alpha", un canal de mise à jour différent de celui de la version stable actuelle.

En attendant voici quelques captures des derniers plugins !

La prédiction et défilement fonctionnant sur la skin WPF

Le clavier souris avec le défilement

La première étape de l'assistant création et édition de clavier

 

Evidemment pour ne pas perdre la tradition des posts technique sur l'architecture et l'implémentation de CiviKey de ce blog, deux posts suivront dans les prochaines semaines.

Le premier fera le point sur l'implémentation actuelle du défilement, les concepts sous-jacents ainsi que les évolutions prévues. Et enfin le second plongera dans les tréfonds de la prédiction de mot et explicitera comment cette fonctionnalité majeure est intégrée au sein de notre architecture de plugins. Vaste programme !

En attendant, n'hésitez pas à lire le code sur GitHub ou à nous suivre sur Twitter ou Facebook

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.

NextResult() and so what ?

J’ai parfois du mal à me souvenir du fonctionnement précis de certaines API. Le comportement du IDataReader avec plusieurs résultats en fait partie. Un petit test unitaire s’impose :

[Test]
public void TestDataReaderBehavior()
{
       ExecuteReader( "select 1;",
              delegate( IDataReader r )
       {
             Assert.IsTrue( r.Read(), "We are directly BEFORE the first record." );
             Assert.AreEqual( 1, r.GetInt32( 0 ) );
             Assert.IsFalse( r.Read() );
             Assert.IsFalse( r.Read(), "One can always call Read." );
             Assert.IsFalse( r.NextResult() );
             Assert.IsFalse( r.NextResult(), "One can always call NextResult." );
             Assert.IsFalse( r.IsClosed, "A data reader must explicitely be closed (except if obtained with ExecuteReader( CommandBehavior.CloseConnection )." );
       } );
 
       ExecuteReader( "select 1; select 2;",
              delegate( IDataReader r )
       {
             Assert.IsTrue( r.Read() );
             Assert.AreEqual( 1, r.GetInt32( 0 ) );
             Assert.IsTrue( r.NextResult() );
             Assert.IsTrue( r.Read(), "Here also we are BEFORE the first record." );
             Assert.AreEqual( 2, r.GetInt32( 0 ) );
             Assert.IsFalse( r.Read() );
             Assert.IsFalse( r.NextResult() );
       } );
 
       ExecuteReader( "select 1 from sys.tables where 0=1; select 2;", 
              delegate( IDataReader r )
       {
             Assert.IsFalse( r.Read(), "First select has no results." );
             Assert.IsTrue( r.NextResult() );
             Assert.IsTrue( r.Read() );
             Assert.AreEqual( 2, r.GetInt32( 0 ) );
             Assert.IsFalse( r.Read() );
             Assert.IsFalse( r.NextResult() );
       } );
 
       ExecuteReader( "select 1;select 'Impossible' from sys.tables where 0=1;select 3",
              delegate( IDataReader r )
       {
             Assert.IsTrue( r.Read() );
             Assert.AreEqual( 1, r.GetInt32( 0 ) );
             Assert.IsTrue( r.NextResult(), "There is a 2nd result..." );
             Assert.IsFalse( r.Read(), "...but it is empty." );
             Assert.IsTrue( r.NextResult(), "There is a 3rd result..." );
             Assert.IsTrue( r.Read() );
             Assert.AreEqual( 3, r.GetInt32( 0 ) );
             Assert.IsFalse( r.Read() );
             Assert.IsFalse( r.NextResult() );
             Assert.IsFalse( r.IsClosed );
       } );
}

Cela vaut bien un long discours, non ?
En tous cas, cela vaut mieux que la documentation MSDN ci-dessous qui annonce faussement qu’après l’appel à NextResult, le lecteur est positionné sur le premier enregistrement. J’ai signalé l’erreur (après m’être créé un login .Net passport suite à des années de résistance).

Je vais pouvoir compter les jours avant la correction Smile.
 
Update jeudi 8 octobre 2009 : Il n’y a toujours pas eu de corrections mais une contribution supplémentaire de David Matson qui considère que l’interprétation de la remarque doit se comprendre au niveau de chaque result set et non au niveau des lignes.

Il a complètement raison ce monsieur !