Au fil des flows

2juin/141

Implementer ContinueWith pour les Rx Extension .Net

Posted by Fabien Arcellier

En ce moment, j'utilise beaucoup la librairie Rx Extension pour ma mission actuelle. Il s'agit d'un client lourd en WPF et .NET 4. Pour les requetes vers notre backend, nous avons choisi un schéma orienté flux pour requêter de manière plus naturelle des données sur un backend exposant certains de nos services en WCF.

Il nous a fallu à un moment synchroniser 2 requêtes. Je n'ai pas trouvé dans les Rx extensions de méthode permettant de rendre séquentiel le post traitement de 2 flux. L'opérateur Join s'en rapproche mais s'appuie sur une fenêtre temporelle.

Pour résoudre ce cas, j'ai décidé de coder un opérateur WaitOnceFor. Pour déclencher l'envoi d'un evenement (et d'un seul) du flux 1, j'attends de recevoir celui du flux 2.

var observable1 = Observable.CreateAsync<...>(...);
var observable2 = Observable.CreateAsync<...>(...);

observable1.WaitOnceFor(observable2).Subscribe(v => { "J'ai reçu mon signal" });

Pourquoi WaitOnceFor ?

J'aurai pu l'appeller ContinueWith ou ContinueAfter. Je cherchai effectivement un comportement proche du ContinueWith qu'offre les Tasks.

La nature des Rx Extension est cependant très différent du système de Task. Un IObservable représente pas une valeur comme le ferait une tache mais une suite de valeurs. Les opérateurs doivent tenir compte de cette nature et justement l'opérateur que je propose va à contre courant.

Si je l'avais appellé ContinueWith or ContinueAfter, j'aurai du implémenter un opérateur fonctionnant sur une suite d'événement. Dans mon cas, c'est un appel asynchrone qui fonctionne exactement sur le modèle d'une Task, à part que je veux profiter de l'Async Pattern. N'etant pas en .Net 4.5, je n'avais pas la possibilité de m'appuyer sur le mécanisme async/await

Le code

Voici la solution que je vous propose. C'est une méthode d'extension. Si other est de valeur null, ça signifie que je n'ai pas besoin de l'attendre, donc je forward directement l'observable source.

Elle est loin d'être parfaite. Voici le snippet.WaitOnceFor

/// Send a single signal when events of both IObservable where sent at least once
/// case 1 :
/// source : --- 1 --- 2 --- 3 --- 4
/// other  : ------------------ 1 ---
/// Result : ------------------ 1 ---
///
/// case 2:
/// source : ------------------ 1 ---
/// other  : --- 1 --- 2 --- 3 --- 4-
/// Result : ------------------ 1 ---
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="other"></param>
/// <returns></returns>
public static IObservable<T> WaitOnceFor<T, K>(this IObservable<T> source, IObservable<K> other)
{
    if (other == null)
        return source;

    return Observable.Create<T>((IObserver<T> observer) =>
    {
        bool sourceDone = false;
        bool otherDone = false;
        T value = default(T);
        Action<T> trycomplete = (T val) =>
        {
            if (otherDone == true && sourceDone == true)
            {
                observer.OnNext(val);
                observer.OnCompleted();
            }
        };

        var d2 = source.Take(1).Subscribe(r =>
        {
            sourceDone = true;
            value = r;
            trycomplete(value);
        });

        var d1 = other.Take(1).Subscribe(r =>
        {
            otherDone = true;
            trycomplete(value);
        });

        return Disposable.Create(() =>
        {
            d1.Dispose();
            d2.Dispose();
        });
    });
}
Remplis sous: Non classé 1 commentaire
15déc/130

Intel Perceptual SDK – Capture des gestes

Posted by Fabien Arcellier

Cet article est une copie de celui que j'ai rédigé sur l'intel developer zone.

Dans la suite de la découverte de l'Intel Perceptual SDK, je vous invite a explorer un domaine qui me laisse rêveur, la capture de la gestuelle de l'utilisateur.

Vous souvenez vous de Tom Cruise manipulant avec fluidité les visions des precogs dans Minority Report ?

Le reve evoque par Philipp K Dick

Aujourd'hui, c'est devenu bien réel. La réalité dépasse la fiction. Dans minority report, il fallait des gants pour interagir avec l'ordinateur. Dans notre cas, nul besoin, la camera Senz3D vous permet de le faire en utilisant seulement vos mains. Avant de découvrir comment le mettre en oeuvre dans une de vos applications, je vous propose d'explorer certains concepts concernant les interfaces naturelles.

Remplis sous: Non classé Lire la suite
10déc/131

Decouvrir le SDK Intel Perceptual Computing

Posted by Fabien Arcellier

Cet article est une copie de celui que j'ai rédigé sur l'intel developer zone.

J ai eu la chance grâce à BeMyApp et Intel d avoir accès a la camera Creative Senz3d. Je vous invite dans ce billet de blog à découvrir les possibilités que ce système autorise.

La réalité augmentée en est a ses balbutiements. vous pouvez noter 2 courants complémentaires :

  • le premier, amener le digital dans le réel,
  • la second, amener le réel dans le digital

C est au travers du SDK Intel Perceptual Computing que je vous propose d explorer cette seconde voie. Même si il est compatible avec une simple Webcam, vous aurez besoin de la camera Creative Senz3d pour en tirer pleinement partie, notamment pour la capture des gestes, la suppression de l'arrière plan, ...

01-materiel

Remplis sous: Non classé Lire la suite
9déc/130

Forcer Visual studio a s’attacher au programme qui se lance avec une ligne de programmation

Posted by Fabien Arcellier


protected override void OnStartup(StartupEventArgs e)
{
  if (e.Args.Contains<string>("-d"))
  {
    System.Diagnostics.Debugger.Launch();
  }

  base.OnStartup(e);
}

Quand vous lancez l'application en ajoutant -d à la ligne de commande et que Visual Studio est installé, vous obtenez la fenêtre suivante :

Remplis sous: Non classé Aucun commentaire
22août/135

Tester une application adossee a une base de donnee avec PHP Unit

Posted by Fabien Arcellier

Hier, j'ai écrit pour Vamos à la playa, une série de tests automatisés pour valider la partie serveur.

Au moment où j'écris ce billet, cette partie compte seulement 4 classes et un routeur. La partie serveur expose une API Restful qui compte une dizaine d'opération.

Le problème que je rencontrai depuis le départ, c'est quoi tester ? 90% du travail d'exposition des données consistent à récupérer les résultats en base et à les exposer au format json.

Qu'est ce que je teste ?

C'est naturellement que j'ai commencé à créer un projet de tests unitaires sous PHP Unit. J'ai réfléchi à 2 solutions :

  1. Encapsuler la récupération des données et écrire un bouchon pour les tests
  2. Considérer la base de donnée comme un composant logiciel avec un état

La solution 1 me posait un problème. Actuellement, Vamos est adossé à une base mysql. Vu le type d'application, c'est un choix raisonnable au départ du projet. C'est une techno maîtrisée et facile à mettre en oeuvre. A terme, si l'API évolue et que le projet grandit, il faudra envisager d'autres solutions techniques. La façon dont j'accède aux données présage nullement de la façon dont j'y accéderai demain. Si je conçois la partie DAO comme une partie indépendante et que je fige les interfaces, je fais un choix d'architecture prématurée.

Il reste donc la solution 2.

La base de donnee, un composant logiciel comme un autre

Vous vous demandez surement ce que j'entend par composant logiciel ? Un composant logiciel est une vue de l'esprit. Il traite des requêtes (qu'on peut généraliser par message) et modifie son état interne.

La base de donnée est un composant logiciel de mon application :

  • Elle exécute les requêtes de celle ci (SQL)
  • Elle modifie son état interne en conséquence

Si je ne maîtrise pas l'état de ce composant, aucune chance de pouvoir tester mon application.

Principe du test logiciel

Pour effectuer du test automatisé, un composant peut soit être remplacé par un bouchon (cas d'un test unitaire), soit être initialisé dans un état cohérent (cas pour un test fonctionnel).

J'ai écarté la première solution. Comment mettre en oeuvre la seconde de manière efficace ?

Le module DbUnit de PHPUnit

D'après ce que j'ai constaté, ce module répond à 2 besoins :

  • Initialiser une base de donnée à l'état voulu
  • Comparer l'état d'une base de donnée à un état attendu

Pour cela, le système s'appuie sur le concept de Dataset. Un dataset est une vue simplifiée des enregistrements présents dans les tables d'une base de donnée.

Ce concept s'appuie sur un autre format que le sql pour être plus facile à traiter.

Concrètement, voici un dataset au format xml :

<?xml version="1.0" encoding="UTF-8"?>
<!--
Dataset contains :
 * 2 playas
 * 4 olas
-->
<dataset>
  <table name="valp_beaches">
    <column>id</column>
    <column>name</column>
    <column>city</column>
    <column>latitude</column>
    <column>longitude</column>
    <column>modified</column>
    <column>created</column>
    <row>
      <value>1</value>
      <value>Playa 1</value>
      <value>City 1</value>
      <value>45.0</value>
      <value>45.0</value>
      <value>2013-08-24 17:15:23</value>
      <value>2013-04-24 17:15:23</value>
    </row>
    <row>
      <value>2</value>
      <value>Playa 2</value>
      <value>City 2</value>
      <value>46.0</value>
      <value>46.0</value>
      <value>2013-09-24 17:15:23</value>
      <value>2013-09-24 17:15:23</value>
    </row>
  </table>
  <table name="valp_beaches_gps" />
  <table name="valp_beaches_ondas">
    <column>id</column>
    <column>message</column>
    <column>created</column>
    <row>
      <value>1</value>
      <value>J'ai vu un requin</value>
      <value>2013-09-29 17:15:23</value>
    </row>
    <row>
      <value>2</value>
      <value>Ola 2</value>
      <value>2013-09-29 17:16:23</value>
    </row>

  </table>
</dataset>

Php unit utilise ce dataset pour :

  • Vider les tables qui y sont référencés
  • Les peupler avec les données

Pour utiliser cette feature, vous devez créer une classe de test qui hérite de PHPUnit_Extensions_Database_TestCase

class DatabaseTest extends \PHPUnit_Extensions_Database_TestCase {

  protected function getConnection() {
    $conf_database = array('connection_string' => 'mysql:host=127.0.0.1;dbname=mabase',
                            'user' => 'mabase_user',
                            'password' => 'mabase_password');

    $pdo = new \PDO($conf_database['connection_string'], 
            $conf_database['user'], 
            $conf_database['password'], 
            array(\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
    $pdo -> setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    
    return $this->createDefaultDBConnection($pdo, ':memory:');
  }

  protected function getDataSet() {
    return $this->createXmlDataSet('datasets/playa_2_ola_2.xml');
  }

  public function testReadAll() {
    // ... Votre test
  }
}

J'ai simplifié ma classe de tests pour ce billet. Je vous renvoie à la documentation officielle pour avoir plus d'information sur les bonnes pratiques dans l'initialisation de votre base.

Avant d'exécuter le test DatabaseTest::testReadAll, PHP Unit initialisera la base avec les données provenant de notre dataset.

Pour conclure

Le mécanisme offert par PHP Unit permet de comparer une base après une opération qui a modifiée les données qu'elle contient avec un dataset.

A noter que sans utiliser cette extension, vous pouvez tout à fait initialiser votre base en utilisant un script sql exécuté dans la méthode setUp de votre classe de test. Cette solution vous privera de la possibilité de comparer le contenu de votre base avec un fichier dataset.

Remplis sous: Non classé 5 Commentaires