lundi 31 janvier 2011

De la conception au déploiement avec le SDK Google Android 2

Voici une autre référence de lecture dans le domaine.
Cette fois-ci, c'est un livre aux éditions Eyrolles et donc dans la langue de Voltaire.

Source: Amazon.fr

Selon les différents commentaires, cet ouvrage présente des exemples simples et assez riches. Le livre est clair et complet.
Mais pour certains autres, il ressemble plus à un manuel de référence n'approfondissant pas assez certains concepts essentiels d'Android (ex: les adaptateurs) alors qu'une information nettement plus claire est disponible sur la documentation en ligne d'Android.
  • Broché: 486 pages
  • Editeur : Eyrolles (30 avril 2010)
  • Langue : Français
  • ISBN-10: 2212125879
  • ISBN-13: 978-2212125788

vendredi 28 janvier 2011

Un logiciel de capture d'écran professionel pour Ubuntu

Introduction
J'utilise de plus en plus ma distribution Ubuntu. Je l'ai même installée sur un portable pour passer ma curiosité sur les développements Android.
Comme je documente mes diverses découvertes, il vient forcement un moment où je désire insérer des captures d'écrans (ou de portions d'écrans) dans mes articles.

Force est de constater que l'outil de capture installé par défaut sous Ubuntu est plutôt minimaliste.
Ce que j'aurais voulu trouver c'est un FastStone Screen Capture pour Ubuntu.
Jusqu'aujourd'hui FastStone était pour moi un logiciel de référence car il est simple, efficace et fonctionnel... mais j'ai trouvé encore mieux.

Pour résumer, FastStone est un logiciel qui permet de:
  • Faire des captures d'écran ou de portion d'écran. Qui permet de capturer les menus, etc.
  • Annoter les images avec du texte.
  • D'ajouter des flèches et des instructions.
  • De réduire la taille de l'image (et donc son poids).
  • Appliquer différentes transformations (le floutage de zones par exemple).
Si FastStone Screen Capture n'existe pas sur Ubuntu, il existe néanmoins Shutter. Un logiciel tout aussi professionnel, peut-être même plus.

Shutter
Shutter est fortement intégré à Gnome (et donc à Ubuntu), ce qui permet  d'offrir un grand nombre de fonctionnalités de captures.

Comparaison de Shutter et FastStone:
  • Tout comme FastStone, Shutter:
    • Reste en tâche de fond et attends que l'on ai besoin de lui.
    • Sait envoyer des e-mail, sauver sur le disque en automatique.
    • Couper les images (crop) via l'éditeur intégré.
    • Supporte plusieurs format d'image.
    • Dispose de nombreuses options de configuration.
    • Supporte divers format de fichier pour les images.
    • Permet d'annoter les images (vraiment pratique pour la documentation).
  • Ce que Shutter fait mieux:
    • Envoyer l'image dans un PDF.
    • Supporte plusieurs captures d'affilés (un onglet par image).
    • Un éditeur d'image plus complet (voir ci-dessous).
    • Dispose de plusieurs plugins permettant de faire du traitement d'image (sépia, bordure, fondue, etc) en vue d'une meilleure intégration soit dans un site Web, soit dans un document professionnel (ex: publicité).
L'éditeur d'image intégré
L'éditeur d'image intégré de Shutter va bien plus loin que celui proposé par FastStone.
Si le floutage et les flèches sont plus somaires (mais efficace) et qu'il n'y a pas d'effet d'ombrage, Shutter propose les avantages suivants:
  • Insertion d'image depuis une librairie disponible en un click et par ailleurs bien garnie! Super pratique pour ajouter une tête de mort ou un panneau "Stop" pour attirer l'attention.
  • Insertion de bulles auto numérotées (1, puis, 2 puis 3, etc) sans chipotage.
  • Toutes les commandes de dessins sont accessibles via des raccourcis claviers (c'est un point vraiment important lorsque l'on fait beaucoup de documentation).
  • Un sur-ligneur propre et pratique (à utiliser avec la touche CTRL pour un maximum de propreté).

NB: dans certains cas, l'éditeur d'image n'est pas disponible après l'installation de Shutter. Il est possible de corriger facilement ce problème... voir la solution plus loin dans cet article.

Plus d'information
Plus d'informations sont disponibles sur le site officiel Shutter-Project et la présentation de Shutter sur doc.ubuntu-fr.org


Installer Shutter
Il suffit de passer par la logitech Ubuntu :-). Une fois installé, Shutter est disponible dans le menu Applications | Accessoires.
Lorsqu'il est démarré, Shutter apparait dans la barre de notification du système. Il suffit de cliquer dessus pour l'activer.

Quelques recommendations:
Activer Shutter lors du "Print Screen":
Shutter peut remplacer le logiciel de capture par défaut de Gnome. Ainsi, lorsque l'on presse le bouton "Print Screen", c'est Shutter qui est activé.
J'ai également activé le "ALT+Print Screen" pour capturer une région de l'écran (c'est aussi très pratique).
Comment faire:
  • Démarrer Shutter et l'activer (en cliquant sur son icone dans la barre de notification).
  • Sélectionner le menu "édition|préférence".
  • Modifier les options du volet Keyboard.

Attention à la compression des images:
Par défaut, Shutter sauve des images png avec un niveau de compression égal à 9.
Avec un tel niveau de compression, les textes d'une carte routière deviennent illisibles. Il faut alors diminuer le niveau de compression (attention, la taille des fichiers des images seront aussi plus grande).
Comment faire:
  • Démarrer Shutter et l'activer (en cliquant sur son icone dans la barre de notification).
  • Sélectionner le menu "édition|préférence".
  • Modifier les options du volet Principal.

Traits horizontaux et verticaux dans l'éditeur d'image:
Presser la touche CTRL pour dessiner facilement un trait horizontal en déplacant la souris.
Presser la touche SHIFT pour un trait vertical.

L'éditeur interne d'image est manquant!
Au cours de ma découverte de Shutter, je ne manquais pas de trouver le programme de capture très professionnel. Cependant il me manquait toujours cette possibilité d'annoter mes images.
Cette fonctionnalité est normalement prise en charge par l'éditeur d'image interne de Shutter. Le problème, c'est que le bouton restait désactivé!

En cherchant un peu, j'ai trouvé une explication sur le net.
Il semblerait que cela soit un package manquant sur le système.
Pour vérifier cette assertion, il faut démarrer Shutter en mode Terminal et vérifier les messages affichés.

"INFO: checking installed components...

WARNING: gnome-web-photo is missing --> screenshots of websites will be disabled!

WARNING: Goo::Canvas/libgoocanvas is missing --> drawing tool will be disabled!

INFO: no command line parameters set..."
source: Shutter Bug #539527

Pour résoudre le problème, il suffit d'installer le package libgoo-canvas-perl avec la commande suivante:
sudo apt-get install libgoo-canvas-perl


Installer la toute dernière version de Shutter
Bien que Shutter soit disponible dans le logictech Ubuntu, ce n'est généralement pas la toute dernière version qui s'y trouve.
Pour profiter des dernière fonctionnalités (par exemple l'article de Claude Picot "De nouvelles fonctionnalités dans la dernière version de Shutter"), il faut donc l'installer directement depuis le dépôt de Shutter.

sudo add-apt-repository ppa:shutter/ppa

mettez vous sources de dépôts à jour avec la commande

sudo apt-get update

et lancez l’installation

sudo apt-get install shutter

jeudi 27 janvier 2011

Développment Android sous Ubuntu

Qu'est ce qu'Android
Android est un système d'exploitation open source pour smartphones, PDA et terminaux mobiles conçu par Android, une startup rachetée par Google.
D'autres types d'appareils possédant ce système d'exploitation existent, par exemple des téléviseurs et des tablettes comme le Samsung Galaxy Tab.

Source: wikipedia
Android est un système d'exploitation fondé sur un noyau Linux, il comporte une interface spécifique, développée en java, les programmes sont exécutés via un interpréteur JIT, toutefois il est possible de passer outre cette interface, en programmant ses applications en C.
Android a été conçu pour intégrer au mieux des applications existantes de Google comme le service de courrier Gmail, ou celui de cartographie, Google Maps, ou encore Google Agenda, Google Talk, YouTube.
Source: Android sur Wikipédia

Introduction
Le but de cet article est de décrire comment installer un environnement Android sous Ubuntu.
Un dilemme se pose déjà avant même de commencer. En effet, il est possible de tirer partiellement parti de la Logitech d'Ubuntu mais cette façon de faire n'est pas en phase avec les documentations techniques proposés par Google.
 
La méthode Ubuntu
Il est visiblement possible d'installer Eclipse et un environnement Java (JDK) depuis les dépôts d'Ubuntu. Si cette voie semble raisonnable, je m'en suis écarté immédiatement pour plutôt me conformer à la méthode Google.
L'article Installer Eclipse paru sur le site communautaire d'Ubuntu fait d'ailleurs largement référence à l'utilisation des dépôts.

La méthode Google
Par contre, je me suis entêté à suivre la voie générale décrite par Google dans son document "installing the SDK" (celui d'Android bien entendu), document qui donne également des précisions sur l'installation d'Eclipse et de Java.
Voici le résultat de mes tribulations.
Tout ne fût pas toujours roses et violettes, aussi simple que le laisse paraitre la documentation. Mais je suis finalement arrivé a bon port.

Installer Eclipse
Il faut installer Eclipse en version 3.5 au minimum.
Cette version est disponible dans la section téléchargement de Eclipse.Org.
J'ai installé "Eclipse Classic" depuis eclipse.org au lieu d'opter pour le package Eclipse dans la "Logitech Ubuntu".
Les instructions d'installations mentionnent de simplement dézipper le contenu de l'archive, cela crée un sous répertoire "eclipse" (utiliser le gestionnaire d'archive ou la commande "file-roller").
J'ai choisi de placer les fichiers dans mon répertoire home (/home/domeu/ ou ~ ).
Eclipse est donc installé dans ~/eclipse, emplacement où les fichiers peuvent être modifiés librement par Eclipse lui-même.
Note:
Lors d'une première tentative j'ai bien essayé d'installer éclipse dans /usr/bin/eclipse/ mais il s'est avéré que je ne pouvais le démarrer qu'en mode super user! (et cela même après modification des droits d'accès sur les répertoires et fichiers).

Installer Java
Il est possible de télécharger le JDK 6 Java SE depuis la section de téléchargement du site d'Oracle. J'ai opté pour Oracle car il faut impérativement disposer d'un JDK, un JRE (Java RunTime Environment) étant insuffisant selon la documentation d'Android.
Il faut télécharger les binaires pour linux et effectuer l'installation manuelle puisqu'Ubuntu ne supporte pas les RPM.

En suivant les instructions d'installation sur le site d'Oracle:
  • j'ai downloadé la version 6.23 du JDK (soit le fichier jdk-6u23-linux-i586.bin).
  • J'ai déplacé le bin dans /usr/bin (c'est une archive auto extract).
    J'ai utilisé un sudo nautilus pour disposer des droits nécessaires (être certain de déplacer l'archive dans /usr/bin).
  • J'ai activé un terminal en mode super user (ouvrir terminal puis sudo -i).
  • J'ai activé l'exécution du binaire (chmod +x jdk-6u23-linux-i586.bin) dans /usr/bin.
  • J'ai exécuté l'archive (./jdk-6u23-linux-i586.bin), elle s'est décompressée dans le sous répertoire /usr/bin/jdk1.6.0_23/ 
  • J'ai effacé l'archive.
La JVM (l'exécutable "java") est accessible dans le JRE /usr/bin/jdk1.6.0_23/jre/bin ou bien encore dans le JDK /usr/bin/jdk1.6.0_23/bin

Tester le démarrage d'éclipse
Pour ce premier test, je fini par ne pas définir les variables système JAVA_HOME, ni PLUGIN_HOME de java comme précisé dans plusieurs documents (ex: Eclipse sur Ubuntu-Fr). Mes premiers tests étaient tous infructueux.

Je n'ai pas défini le fichier ~/.eclipse/eclipserc non plus comme mentionné dans la documentation d'installation d'éclipse trouvé sur Ubuntu.fr (mes essais étaient également infructueux, c'est peut être parce que la documentation Ubuntu-fr fait référence à la VM de Sun et une installation à l'aide d'apt-get).

Pour démarré éclipse, j'ai utilisé un terminal et depuis le répertoire /home/domeu/eclipse, j'ai démarré éclipse en indiquant l'emplacement de la JVM (Java Virtual Machine).
Soit l'exécution de la commande suivante:
./eclipse -vm /usr/bin/jdk1.6.0_23/bin

Au démarrage, eclipse demande de paramètrer le répertoire Workspace.
J'ai volontairement choisi /home/domeu/eclipse/workspace au lieu de /home/domeu/workspace pour éviter la prolifération des répertoires.

Démarrer éclipse sans devoir spécifier la JVM
L'article "installer Eclipse sur Ubuntu" paru sur aide-ubuntu.com propose de créer un fichier ~/.eclipse/eclipserc et d'y ajouter la commande export JAVA_HOME=/usr/bin/jdk1.6.0_23/bin
Je ne suis jamais arrivé à quoi que cela soit avec cette option.
PAR CONTRE, après quelques recherche, j'ai finalement réaliser que "java" ne pouvait être accessible que depuis l'un des répertoires de $PATH (echo $PATH).
Cette liste de répertoire n'incluant pas le jdk mais bien /usr/bin.

Il suffit donc de rajouter le lien symbolique suivant depuis le répertoire /usr/bin:
sudo ln -s /usr/bin/jdk1.6.0_23/bin/java java

Maintenant la simple commande "./eclipse" sans paramètre démarre aussi Eclipse :-)
Nous verrons plus tard que le SDK d'Android utilise aussi le lien symbolique "java", il est donc primordial de le déclarer correctement.

Installer le SDK d'Android
Le SDK d'Android est disponible sur la page de téléchargement de Google.
J'y ai téléchargé le SDK correspondant à Linux (android-sdk_r08-linux_86.tgz) que j'ai ensuite décompressé dans /usr/bin à l'aide du gestionnaire d'archive (sudo file-roller).
Après décompression, le répertoire /usr/bin/android-sdk-linux_86 est disponible.

Modifier les droits sur le répertoires et fichiers /usr/bin/android-sdk-linux_86 pour permettre l'écriture et modification pour tous les utilisateurs.
Si cela n'est pas fait, le logiciel Android ne sera pas capable de créer les sous-répertoires temporaires dont il aura besoin.

Tester le SDK android
Pour fonctionner, il est impératif que le lien symbolique java ait été définit dans /usr/bin comme décrit précédemment.
Se rendre dans le répertoire /usr/bin/android-sdk-linux_86/tools et exécuter android (./android).
Cet outil contient le package principal permettant de télécharger le restant du SDK en fonction des besoins. L'outil donne également accès aux différentes machines virtuelle d'Android.
En quelques manipulations complémentaires, j'ai installé les packages suivants:
  • Android SDK platform-tools, revision 1
  • Documentation for Android SDK, API 9
  • SDK Platform Android 2.3, API 9
  • SDK Platform Android 2.2, API 8
  • Samples for SDK API 9
  • Samples for SDK API 8

Création d'une machine virtuelle
Maintenant que les packages sont installés avec l'outil android, aller dans la section machine virtuelle et créer une nouvelle machine virtuelle.
Les machines virtuelles sont appelées AVD pour Android Virtual Device.

Le site d'Android fournit également plus d'information sur les propriétés supportées les machines virtuelles.

Soit, créons un device nommé "Domeu" avec une carte SD de 32 mb, un skin par defaut (HVGA), un track-ball, un clavier et une camera (640 pixels max).
Il ne reste plus qu'à demarrer le nouvel AVD :-)

Attention, les AVD sont lentes
Si le tout fonctionne bien d'une façon générale, je dois reconnaitre que cela rame quand même un peu (DuoCore T3200 à 2Ghz avec 3Go de Ram), mes pauvres processeurs sont presque tout le temps au dessus de 80%.
Ainsi, il ne faudra pas être trop exigeant sur le temps de démarrage du simulateur, mon premier essai aura pris presque 4 minutes de boot.
Comme recommandé sur certains fils de discussions, il est préférable de garder l'émulateur en route lorsqu'il à été démarré. Cela permet d'économiser beaucoup de temps.

Voir les Logs de l'AVD
En cas de doute, il est possible de voir les messages de log du device AVD.
Utiliser la commande ./adb logcat (Android Debug) disponible dans le répertoire /usr/bin/android-sdk-linux_86/platform-tools

Cet outil m'a été bien utile pour me rendre compte que mon AVD était planté dans une boucle infernale d'initialisation. Le tout se répétant indéfiniment sans aucune notification à l'écran.

Plus d'information concernant les méthodes de debugging sont disponible sur la page "Debugging Tasks" (http://developer.android.com/guide/developing/debug-tasks.html) de la plateforme Android. L'article mentionne également comment placer ses propres messages de Log.

PlugIn AVD pour éclipse
Le site d'Android offre l'extension ADT (Android Development Tools) pour l'éditeur Eclipse.
Cette extension offre un puissant environnement intégré permettant de concevoir des applications Android. Il permet de rapidemment créer de nouveaux projets Android, de créer des applications avec interface utilisateur, de débugger les applications en utilisant le SDK d'Android, d'exporter des signatures pour distributer l'application. Le developpement d'application Android en utilisant ADT et Eclipse est une approche recommendée par Google pour les nouveaux venus.

Les instructions d'installations sont disponibles dans le document Google ADT PlugIn for Eclipse
Comme j'ai installé la version Helios (3.6) d'éclipse, je vais suivre les instructions qui y sont spécifiques, à savoir:
  • Démarrer Eclipse
  • Menu Help | Install New software
  • Bouton "Add" en haut a droite de la fenêtre et y indiquer les information suivante pour le repository d'ADT:
    "Android ADT plugin"
    https://dl-ssl.google.com/android/eclipse/
  • Selectionner tous les éléments du plugin ADT et les installer.
  • Accepter les conditions de licenses, installer et redémarrer Eclipse.
Configurer le module ADT dans Eclipse
  • Afficher le module des préférences (menu Windows|préférences).
  • Sélectionner le module Android et indiquer l'emplacement du SDK Android (/usr/bin/android-sdk-linux_86).
    Cliquer sur Apply provoque l'affichage d'une liste des targets disponibles (à savoir android 2.2 et 2.3 comme précédemment téléchargés dans le SDK Android).
Un premier développement Android avec Eclipse
Le site Android Developper de Google contient l'article d'introduction "developing In Eclipse with ADT"
Ce document est une bonne prise en main pour créer et exécuter un premier projet.
ce qu'il précise moins, c'est:
  • Le détails des différentes propriétés du projet nouvellement créé.
  • La nécessité de définir un "Run Configuration" pour tester l'application sur un ADV Android.
Propriétés du projet
Avec quelques recherches sur internet en arrive assez vite à bout. Par exemple, j'ai utilisé les paramètre suivants:
Project Name: FirstAndroidApp (utilisé par Eclipse pour stocker le projet dans le workspace)
Target: Android 2.3
Application Name: My first Android App (Nom affiché dans l'ADV)
Package Name: be.domeu.firstandroidapp (un namespace unique. Il est conseillé d'utiliser uniquement des minuscules et de commencer la le code pays suivit du nom de la société).
Min SDK version: 9 (correspond à la version de l'API d'Android).

Définir un Run Configuration
Avant d'exécuter le programme pour le tester, il faut impérativement définir une configuration d'exécution pour l'application android.
Accessible depuis le menu associé au bouton Run (entrée "Run configurations..."), la configuration est composée de plusieurs volets.
Ma config se nomme "firstAndroidApp - 2.3", et en voici les détails.

Sélectionner "Android Application" et ajouter une nouvelle entrée.
Nommée l'entrée "firstAndroidApp - 2.3"
Sélectionner le projet Eclipse correspondant (à savoir "FirstAndroidApp").
Laisser l'environnement choisir l'AVD de façon automatique.
La seule correspondance disponible pour une API de version 9 est bien la machine virtuelle "Domeu" qui a été crée plus tôt dans cet article. Le système automatique fonctionnera donc parfaitement.
Activer "Display in favorites menu" pour Run et Debug.

Pour démarré l'application, il suffira de sélectionner "firstAndroidApp - 2.3" dans le popup menu du bouton Run (et de presser Run pour effectivement démarrer l'application).

Avant de démarrer l'application
Démarrer par avance un device AVD avec la bonne configuration permet de gagner un temps monstre lorsque l'on veut tester son application Android.
Le device étant déja disponible et en cours de fonctionnement, Eclipse téléchargera et activera l'application directement dans l'instance de l'ADV en cours d'exécution. C'est presque instantané.

Première application Android

Un tutoriel Android
Lars Vogel a écrit un tutoriel assez complet sur Android (version GingerBread).
Il permet de se faire la main avec l'environnement de développement et d'explorer les spécificités de l'environnement de développement.
A mon sens, il fait partie des incontournables!

Le tutoriel est disponible a l'adresse www.vogella.de/articles/Android/article.html

Le tutoriel comporte les erreurs/imprécisions suivantes:
  • L'inputType de la zone texte doit être codée "numberSigned|numberDecimal".
    Un pipe doit être utiliser pour combiner les flags.
  • Il faut être vigilant car le code fait référence à des ressources string (même pour le nom de la méthode à appeler).
  • Pour utiliser une ressource string, on utilise @string/TheStringName (ex:@string/celcius)
  • Harrg!!! Pour sélectionner une couleur, il faut utiliser le "reference chooser" dans l'éditeur de propriété... mais seulement, le reference chooser n'apparait jamais lorsque l'on clique dessus.
    Voici un workaround: il suffit de faire un clique droit sur le bouton [...] et de presser ensuite la barre d'espacement. C'est un peu contraignant mais cela fonctionne.
  • L'utilisation de l'outil "adb logcat" s'est montré très utile pour tracer les exceptions causée par les bugs de mon application. Il est vrai que lorsque je teste, je sors un peu des sentiers battus :-)
Voici d'ailleurs le résultat de mes premiers essais:


Conclusion
Cet article démontre qu'il est tout à fait possible de faire des développements Android depuis Ubuntu.
Eclipse se révèle être un environnement de développement relativement convivial et assez réactif même à sa première approche.
Un développeur .Net s'y retrouve assez facilement (aussi bien dans l'environnement qu'avec le langage Java).
Par contre, Android est un éco-système complet et y conduire des développements plus avancés demandera un investissement plus conséquent.
La plateforme dispose de nombreux widgets (composants visuels d'ailleurs nommés View) mais c'est surtout le nombre de propriétés disponibles qui les rendent difficiles à cerner au premier abord.
Les concepts habituels des fenêtres Windows est totalement balayé par d'autres concepts comme les Activity, ViewGroup, View, etc (voir le tutoriel de Lars Vogel).
C'est encore sans compter avec l'humour des concepteurs d'Android.
Le petit message "Please, enter a valid number" s'affiche avec une classe nommée Toast... comme le pain qui saute hors du Toaster.
Assez humoristique mais un peu déroutant. 

Pour poursuivre, je vous propose de consulter l'article "Hello, Android: une introduction à la plateforme de développement Google Mobile" et sa vidéo.
Cet article présente un livre de référence pour conduire le développement Android.

Ecouter les WebRadios sur Ubuntu avec RythmBox

Les radios et le WEB
Ecouter les radios sur un PC c'est assez facile, beaucoup de sites proposent une version WebRadio sur leur page Web.
Si cela peut convenir pour la plupart d'entre nous, certains seront peut être plus exigeant en voulant les écouter directement sur leurs ordinateurs.

Le stream de la WebRadio
Pour écouter une WebRadio directement sur son ordinateur, il ne faut non pas l'url de la WebRadio mais l'url du stream de la WebRadio.
Un stream est un flux de donnée constant qui transporte des données, en l'occurrence il s'agit des informations audio de la radio (la musique).
Un stream (flux de donnée), c'est un peu comme les voitures circulant sur une autoroute. Suivant cette métaphore la musique est décomposé en petit packet (les voitures) que l'on envoi sur le stream (comme sur l'autoroute).
Quand on sait où regarder (quelle autoroute), il suffit de regarder les informations passer (les voitures) pour reconstituer l'information (la musique).

Où trouver les flux de WebRadio ?
  • Sur la France:
    • Le site www.radiosflux.com contient une liste très complète des WebRadios Françaises classé par ordre alphabétique ou par genre musical (merci à Julien R. pour cet excellent lien).
    • Le site flux.radio.free.fr énumère une liste impressionnante de ces radios.
  • Sur la Belgique, le ubuntu-fr reprend une autre liste complète pour les radios belges sur sa page doc.ubuntu-fr.org/liste_radio_belgique.
On retrouvera par exemple:
Les Web Radio sur Ubuntu
WebRadio via le Web
Ubuntu est distribué avec Mozilla. En installant les greffons (plugins) nécessaires, il est possible d'écouter les WebRadio depuis les pages Internet des différentes radios. Le principal greffon nécessaire est flash.
NB: Pour installer facilement les plugins, il suffit d'effectuer les "tests du système". Ces test sont accessibles dans le menu Système|Administration|Test du système.
Certains tests systèmes concernes plus directement le Web et proposent d'installer les plug-ins nécessaires pour finaliser les tests en question. C'est un procédé d'installation très efficace. Merci Didi :-)

WebRadio directement sur Ubuntu
Ubuntu est maintenant distribué avec l'excellent lecteur multimédia RythmBox (sur wikipedia, sur Ubuntu-Fr).

RythmBox supporte la lecture des WebRadios, il suffit simplement d'ajouter l'URL du stream de la WebRadio dans la liste des WebRadios de RythmBox.
Simple et efficace.

Juste une note pour stipuler qu'il est possible de modifier l'affichage du nom de la WebRadio après l'ajout de celle-ci (par défaut, c'est l'URL qui est affichée).
Pour modifier ce nom, effectuer un clique droit pour modifier les propriétés  et modifier le "nom du morceau".

mardi 25 janvier 2011

ADO.NET - Aide mémoire - 4/4 : Tutoriel

Le présent article fait parti d'une suite logique de 4 articles: "ADO.NET - Aide mémoire - 1/4 : Execution, Parametres, StoredProc, DataReader",  "ADO.NET - Aide mémoire - 2/4 : DataSet", "ADO.NET - Aide mémoire - 2/4 : DataView" et "ADO.NET - Aide mémoire - 4/4 : Tutoriel"

eTutorial.org publie un Tuto Ado.Net plus que largement complet, le genre de référence que l'on place dans les perles du Net. Ce tutoriel prend sa source dans les excellents ouvrages de O'Reilly. Il faudra cependant composer avec l'affichage des publicités.

Admirez donc la magnifique table des matières que j'ai repris ci-dessous.
Si vous vous posez une question, tentez d'abord de trouver une réponse dans le tutoriel de eTutorial.

Preface
Audience

Contents of This Book
What's on the CD-ROM
Conventions Used in This Book
Comments and Questions
Acknowledgments

Part I: ADO.NET Tutorial

Chapter 1. Introduction


1.1 ADO.NET Data Providers
1.2 Connected and Disconnected Data

Chapter 2. .NET Data Providers

2.1 Data Providers
2.2 Selecting a Data Provider
2.3 Creating a Custom Data Provider

Chapter 3. Connections

3.1 Connection Object Overview
3.2 The Connection String
3.3 Opening and Closing Connections
3.4 Connection Pooling

Chapter 4. Commands


4.1 Command Object Overview
4.2 Creating and Executing a Command
4.3 Parameter Object Overview
4.4 Parameterized Commands
4.5 Commands with Stored Procedures
4.6 Commands and Data Definition Language (DDL)

Chapter 5. DataReaders

5.1 DataReader Object Overview
5.2 Performing a Query with a DataReader
5.3 Stored Procedures with the DataReader
5.4 DataReaders and Schema Information

Chapter 6. DataSets

6.1 Creating an Untyped DataSet
6.2 Working with Tables in the DataSet
6.3 Adding and Removing Relations
6.4 Adding Custom Information
6.5 Cloning the Schema
6.6 Copying the DataSet
6.7 Merging Two DataSets
6.8 Removing All Data
6.9 Resetting the DataSet
6.10 Committing and Discarding Changes

Chapter 7. DataTables

7.1 Creating a DataTable
7.2 Working with Columns
7.3 Constraints
7.4 Primary Key
7.5 Rows
7.6 Loading Data
7.7 Committing and Discarding Changes
7.8 Cloning the Schema of the Table
7.9 Copying the Table
7.10 Selecting a Subset of Rows
7.11 Performing Aggregate Calculations
7.12 Removing All Data
7.13 Resetting the Table
7.14 Identifying Errors in the Table
7.15 DataTable Events

Chapter 8. DataColumns

8.1 Creating DataColumns
8.2 Creating AutoIncrement Columns
8.3 Creating Expression Columns
8.4 Handling Null Values
8.5 Mapping .NET Data Provider Types to .NET Framework Types

Chapter 9. DataRows

9.1 Creating a DataRow
9.2 Updating Rows
9.3 Deleting Rows
9.4 Using Row State Information
9.5 Using Row Version Information
9.6 Accepting or Rejecting Changes to Rows
9.7 Navigating Parent and Child Rows
9.8 Using Row Error Information

Chapter 10. Constraints

10.1 Constraint Object Overview
10.2 The UniqueConstraint
10.3 The ForeignKeyConstraint

Chapter 11. DataRelations
11.1 DataRelation Object Overview
11.2 Navigating Relational Data

Chapter 12. DataViews and Data Binding


12.1 The DataView and DataViewManager
12.2 Sorting and Filtering
12.3 Accessing Data Through a DataView
12.4 Windows Data Binding
12.5 ASP.NET Data Binding

Chapter 13. Strongly Typed DataSets

13.1 Creating a Strongly Typed DataSet
13.2 Adding a Row
13.3 Editing a Row
13.4 Finding a Row
13.5 Null Data
13.6 Navigating Hierarchical Data
13.7 Annotations

Chapter 14. DataAdapters


14.1 Creating DataAdapter Object
14.2 Retrieving Data from the Data Source
14.3 Retrieving Schema Information from the Data Source
14.4 Updating the Data Source
14.5 Mapping Tables and Columns
14.6 AcceptChangesDuringFill
14.7 ContinueUpdateOnError
14.8 DataAdapter Events

Chapter 15. Updating the Data Source

15.1 SqlCommandBuilder Class Overview
15.2 Updating a Data Source Using Command Builder
15.3 Updating a Data Source Using Custom Logic
15.4 Refreshing Data After Updating
15.5 Retrieving Updated Values from the Data Source
15.6 Updating Data in Related Tables
15.7 Handling Concurrency Issues
15.8 Optimization

Chapter 16. Transactions


16.1 Manual Transactions
16.2 Isolation Levels
16.3 Savepoints
16.4 Nested Transactions
16.5 Transactions Using a DataAdapter
16.6 Automatic Transactions

Chapter 17. XML and the DataSet

17.1 DataSet XML Methods
17.2 Shaping DataSet XML
17.3 Other .NET XML Classes
17.4 XmlDataDocument Object Overview
17.5 Using the Data Objects to Edit XML
17.6 SQL Server 2000 XML

Part II: ADO.NET Core Classes

Chapter 18. The Connection Class

18.1 Comments/Troubleshooting
18.2 Properties Reference
18.3 Methods Reference
18.4 Events Reference

Chapter 19. The Command Class


19.1 Comments/Troubleshooting
19.2 Properties Reference
19.3 Collections Reference
19.4 Methods Reference

Chapter 20. The Parameter Class

20.1 Comments/Troubleshooting
20.2 Properties Reference

Chapter 21. The DataReader Class

21.1 Comments/Troubleshooting
21.2 Properties Reference
21.3 Methods Reference

Chapter 22. The DataSet Class

22.1 Comments/Troubleshooting
22.2 Properties Reference
22.3 Collections Reference
22.4 Methods Reference
22.5 Events Reference
 

Chapter 23. The DataTable Class

23.1 Comments/Troubleshooting
23.2 Properties Reference
23.3 Collections Reference
23.4 Methods Reference
23.5 Events Reference

Chapter 24. The DataColumn Class

24.1 Comments/Troubleshooting
24.2 Properties Reference
24.3 Collections Reference

Chapter 25. The DataRow Class

25.1 Comments/Troubleshooting
25.2 Properties Reference
25.3 Collections Reference
25.4 Methods Reference

Chapter 26. The Constraint Class


26.1 Comments/Troubleshooting
26.2 Properties Reference
26.3 Collections Reference

Chapter 27. The DataRelation Class

27.1 Comments/Troubleshooting
27.2 Properties Reference
27.3 Collections Reference

Chapter 28. The DataView Class

28.1 Comments/Troubleshooting
28.2 Properties Reference
28.3 Methods Reference
28.4 Events Reference

Chapter 29. The DataAdapter Class


29.1 Comments/Troubleshooting
29.2 Properties Reference
29.3 Collections Reference
29.4 Methods Reference
29.5 Events Reference

Chapter 30. The CommandBuilder Class

30.1 Comments/Troubleshooting
30.2 Properties Reference
30.3 Methods Reference

Chapter 31. The Transaction Class

31.1 Comments/Troubleshooting
31.2 Properties Reference
31.3 Methods Reference

Part III: API Quick Reference

Chapter 32. How to Use This Quick Reference

32.1 Finding a Quick-Reference Entry
32.2 Reading a Quick-Reference Entry

Chapter 33. Converting from C# to VB Syntax

33.1 General Considerations
33.2 Classes
33.3 Structures
33.4 Interfaces
33.5 Class, Structure, and Interface Members
33.6 Delegates
33.7 Enumerations

Chapter 34. The System.Data Namespace


Chapter 35. The System.Data.Common Namespace

Chapter 36. The System.Data.SqlClient Namespace

Chapter 37. The System.Data.OleDb Namespace

Chapter 38. The System.Data.SqlTypes Namespace

Part IV: Appendixes

Appendix A. ADO.NET Providers

A.1 The SQL Server Provider
A.2 The OLE DB Provider
A.3 The ODBC .NET Provider
A.4 The Oracle .NET Provider
A.5 The ODP.NET Provider

Appendix B. ADO.NET XML Extensions

B.1 codegen Namespace
B.2 msdata Namespace
B.3 diffgr Namespace

Appendix C. Microsoft Data Engine (MSDE)

C.1 Installing MSDE
C.2 MSDE Essentials
C.3 Adding the Northwind Data
C.4 Migrating MSDE to SQL Server

Type, Method, Property, and Field Index

ADO.NET - Aide mémoire - 3/4 : DataView

Le présent article fait parti d'une suite logique de 4 articles: "ADO.NET - Aide mémoire - 1/4 : Execution, Parametres, StoredProc, DataReader",  "ADO.NET - Aide mémoire - 2/4 : DataSet", "ADO.NET - Aide mémoire - 2/4 : DataView" et "ADO.NET - Aide mémoire - 4/4 : Tutoriel"

DataView
Un DataView permet de créer différentes vues des données stockées dans une DataTable, une aptitude qui est souvent utilisée dans les opérations de data-binding. En utilisant un DataView, il est possible d'exposer les données d'une table avec un ordre de tri différent, il est également possible de filtrer les données par état (avant/après modification) ou encore filtrer sur base d'une expression (équivalent d'une clause "where" en sql).

Un DataView fournit une vue dynamique des données stockées dans la DataTable sous-jacente: le contenu, l'ordre de tri, et aspects relationnels reflètent les modifications tels qu'elles se présentent. Cette caractéristique diffère de méthode "Select" de la DataTable qui produit un tableau de DataRow depuis la DataTable sur base d'un filtre et/ou tri particulier: ce contenu reproduit les modifications dans la table sous-jacente, mais les aspects relationnels et l'ordonnancement restent statiques. Les capacités dynamiques du DataView en font un candidat idéal pour l'utilisation de data-binding.

Un DataView procure une vue dynamique d'un ensemble de données unique, un peu comme les vues d'une base de données, auquel il est possible d'appliquer différents ordres de tri et critères de sélection. Au contraire d'un vue en DB, un DataView ne peut pas être manipulé comme une table et ne peut pas fournir une jointure entre plusieurs tables. Vous ne pouvez pas non plus exclure des colonnes qui existent dans la table source, ni ajouter des colonnes tels que des colonnes calculées qui ne se trouveraient pas dans la table source.

Vous pouvez utiliser une DataViewManager pour gérer la configuration des vues pour toutes les tables d'un DataSet. Le DataViewManager procure la possibilité de gérer la configuration du DefaultView de chaque table de façon pratique. Lorsqu'un contrôle est lié (bind) à plus d'une table d'un DataSet, faire le binding vers un DataViewManager est alors un choix idéal.

Voici quelques références complémentaires:
  • Page reprenant les Articles de Microsoft concernant les DataViews, articles énumérés et décrits ci-dessous.
  • Creating a DataView (ADO.NET)
    Décrit comment créer un DataView pour un DataTable
  • Sorting and Filtering Data (ADO.NET)
    Montre comment initialiser les propriétés d'un DataView pour retourner un sous-ensemble des enregistrements de données qui satisfont les critères de filtrage, ou qui retourne les données dans un ordre particulier.
  • DataRows and DataRowViews (ADO.NET)
    Explique comment accéder aux données exposées par le DataView.
  • Finding Rows (ADO.NET)
    Explique comment retrouver un enregistrement particulier dans un DataView
  • ChildViews and Relations (ADO.NET)
    Décrit comment créer une vue à partir d'une relation master-detail (parent-child) en utilisant un DataView.
  • Modifying DataViews (ADO.NET)
    Explique comment modifier les données de la DataTable sous-jacente à partir d'un DataView, incluant également l'activation/désactivation des mise-à-jours (updates).
  • Handling DataView Events (ADO.NET)
    Explique comment utiliser l'évènement ListChanged pour recevoir une notification lorsque le contenu ou l'ordre de tri d'un DataView est en cours de modification.
  • Managing DataViews (ADO.NET)
    Explique comment utiliser un DataViewManager pour gérer les configurations des DataView pour chaque table du DataSet.
Exemple de relation Master-Detail et ChildView
Directement issu d'un des articles MSDN, voici un petit morceau de code qui montre comment définir une relation Master-Detail dans un DataSet mais aussi comment l'exploiter pour créer un ChildView (CreateChildView)
DataTable catTable = catDS.Tables["Categories"];
DataTable prodTable = catDS.Tables["Products"];

// Create a relation between the Categories and Products tables.
DataRelation relation = catDS.Relations.Add("CatProdRel", 
    catTable.Columns["CategoryID"],
    prodTable.Columns["CategoryID"]);

// Create DataViews for the Categories and Products tables.
DataView catView = new DataView(catTable, "", "CategoryName", 
  DataViewRowState.CurrentRows);
DataView prodView;

// Iterate through the Categories table.
foreach (DataRowView catDRV in catView)
{
  Console.WriteLine(catDRV["CategoryName"]);

  // Create a DataView of the child product records.
  prodView = catDRV.CreateChildView(relation);
  prodView.Sort = "ProductName";

  foreach (DataRowView prodDRV in prodView)
    Console.WriteLine("\t" + prodDRV["ProductName"]);
}

Autre Exemple issus de MSDN - DataViewManager, chargement Dataset.

Cet autre exemple de MSDN (légèrement adapté) est censé démontrer l'usage du DataViewManager.
Personnellement, je crois qu'il y a moyen de mieux faire.
Par contre, ce qui est beaucoup intéressant, c'est le chargement de plusieurs tables et de leurs relations dans un seul dataset. Tables de la DB AdventureWorks.

Fichier source: AdoNet_DataViewManager.cs.

using System;using System.Collections.Generic;using System.Data;using System.Data.SqlClient;using System.Windows.Forms;
public class MyClass
{
    public static void RunSnippet()
    {
        // Adventure Works creation script and database CAN BE DOWNLOADED from CodePlex
        //    http://sqlserversamples.codeplex.com/
        //
        SqlConnection connection = new SqlConnection( "Data Source=localhost;Initial Catalog=AdventureWorksLT2008;Integrated Security=SSPI;" );
        // Assumes connection is a valid SqlConnection to Northwind.
        // Create a Connection, DataAdapters, and a DataSet.
        SqlDataAdapter custDA = new SqlDataAdapter(
        "SELECT CustomerID, CompanyName FROM SalesLT.Customer", connection);
        SqlDataAdapter orderDA = new SqlDataAdapter(
        "SELECT SalesOrderID, CustomerID FROM SalesLT.SalesOrderHeader", connection);
        SqlDataAdapter ordDetDA = new SqlDataAdapter(
        "SELECT SalesOrderID, ProductID, OrderQty FROM SalesLT.SalesOrderDetail", connection);
        
        DataSet custDS = new DataSet();
        
        // Open the Connection.
        connection.Open();

        // Fill the DataSet with schema information and data.
        custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;
        orderDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;
        ordDetDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;
    
        custDA.Fill(custDS, "Customers");
        orderDA.Fill(custDS, "Orders");
        ordDetDA.Fill(custDS, "OrderDetails");
    
        // Close the Connection.
        connection.Close();
    
        // Create relationships.
        custDS.Relations.Add("CustomerOrders",
            custDS.Tables["Customers"].Columns["CustomerID"],
            custDS.Tables["Orders"].Columns["CustomerID"]);
    
        custDS.Relations.Add("OrderDetails",
            custDS.Tables["Orders"].Columns["SalesOrderID"],
            custDS.Tables["OrderDetails"].Columns["SalesOrderID"]);
    
        // Create default DataView settings.
        DataViewManager viewManager = new DataViewManager(custDS);
        
        foreach (DataViewSetting viewSetting in viewManager.DataViewSettings)
        viewSetting.ApplyDefaultSort = true;
        
        viewManager.DataViewSettings["Customers"].Sort = "CompanyName";
        
        // Bind to a DataGrid.
        //   Note: N'affichera absolument rien sous snippet compiler
        System.Windows.Forms.DataGrid grid = new System.Windows.Forms.DataGrid();
        grid.SetDataBinding(viewManager, "Customers");

    }
    
    #region Helper methods
    ...
    #endregion
}

lundi 24 janvier 2011

La "gestion coup de feu" en entreprise

Introduction
Dans cet article, je ne vais pas traiter de la gestion du coup feu. Je crois que toutes les sociétés en connaissent quelques-uns au cours de leur histoire.
Je vais plutôt parler d'un nouveau type de gestion que je nommerai "gestion coup de feu".
Elle est devenue très répandue de nos jours au point de devenir un véritable problème.
La "gestion coup de feu" est a sa source dans la gestion du personnel, principalement appliqué par la hiérarchie pour obtenir les services qu'elle attend.
Malheureusement, la "gestion coup de feu" est pratique à court terme mais aussi extrêmement dangereuse pour la stabilité des entreprises sur le long terme.

La gestion coup de feu à probablement ses origines dans le secteur informatique où les erreurs sont courantes mais touche aujourd'hui tous les secteurs de tout type d'industrie. Même le secteur des services et de la consultance n'y échappent plus.
Les comptables, acheteurs, vendeurs, secrétaires et ouvriers de productions de grosses entreprises pourtant réputées connaissent aujourd'hui les affres de la "gestion coup de feu".

C'est quoi au juste la "gestion coup de feu"
Et bien, c'est assez simple et cela résume en "J'en ai besoin là maintenant. Tout de suite, cela ne peut pas attendre!" à longueur de journée.
Peut-être un peu expéditif comme mise en bouche mais terriblement réaliste.
Tout au long de la journée, le travail de fond est interrompu pour résoudre des problèmes devenus impératifs dans l'instant. Bien évidemment, il ne s'agit pas d'une requête introduite plusieurs jours à l'avance (histoire de pouvoir planifier son travail) mais de besoins aussi soudains que pressants.
Ainsi, en courant de journée, il n'est plus possible d'accomplir son travail dans des conditions normales, et cela en étant interrompu systématiquement en cours de journée.
La plupart du temps, il n'est d'ailleurs plus possible de faire attendre la réponse jusqu'à un moment adéquat à l'organisation de son propre travail, la pression hiérarchique est également là pour épauler ces demandes qu'il convient de ne pas différer pour la bonne marche de société.
L'homme perd son statut humain pour se transformer en automate.
Que vous soyez débordés ou pas dans votre travail, la priorité est au coup de feu... il est important de l'éteindre immédiatement (ce qui est somme toute assez raisonnable).
Même si vous êtes visiblement débordé et de bonne volonté pour aider votre prochain à trouver ses réponses, votre interlocuteur stressé et stressant saura même vous agresser verbalement parce que le résultat de ses attentes n'est pas déposé tel qu'il l'attend dans le creux de ses mains.

Comment est-ce que cela s'installe ?

C'est en fait assez simple. La gestion coup de feu s'installe par un manque de vigilance de la chaine hiérarchique.
Je m'explique:
De nos jours, on attend un maximum de résultat et de réactivité des sociétés tout en compressant les coût de fonctionnement. Cela signifie moins de stock, des délais de production écourtés et aussi la compression du personnel. Les choses allant de plus en plus vite (comme la réactivité attendue d'ailleurs), des erreurs se glissent dans la chaîne du travail. Certes, des erreurs mineures mais elles s'amoncellent.
Il n'est alors plus possible pour les différents employés/ouvriers de la chaîne d'accomplir leur travail vraiment correctement, les choses allant trop vite, il faut quelque-fois (souvent) laisser passer des petites choses, voir des problèmes plus gros mais sans impact immédiat.
Lorsque la hiérarchie est tenue au courant (ce qui est souvent le cas lorsque le régime monte), il décide de laisser passer l'alerte pour traiter le problème lorsqu'il se présentera.
Avec les flux de plus en plus tendus et les exigences de réactivités de plus en plus sévères, il n'est même plus possible de vraiment "alarmer" ses supérieurs.
Ainsi, pendant de longs mois, ces "erreurs" se glissent un peu partout pour finalement se terminer par une avalanche... et c'est là que commence la "gestion coup feu".
En effet, si la charge de travail a évolué ces derniers mois au point de ne plus vraiment avoir le temps de faire son travail à fond (comme on le voudrait d'ailleurs), les problèmes induits par les erreurs sont "graves pour le client" et doivent donc être traités et résolus en priorité.
Cela consomme une énergie folle et cause beaucoup de stress. Déjà, vous aurez à absorber les conséquences de vos petites erreurs imposées par la nécessité de production mais en plus vous subirez immédiatement (ou en dommage collatéral) les erreurs des autres services qui auront aussi besoin de votre soutien pour un point ou l'autre afférent à votre travail.
Ainsi l'avalanche devient double... il faut toujours assumer son travail... et il n'y a plus d'autre solution que de gérer les problèmes entrants (et demandes) au coup par coup... et cela pendant des journées entières durant des mois, voire des années.
Au quotidien, la gestion coup de feu s'inscrit dans une système "action-réaction" ou la planification est devenue impossible.

Où est l'erreur de gestion?
Les erreurs primaires, cause d'une gestion coup de feu, résident:
  1. Dans le manque de recul lors de la gestion des impératifs de production.
    A un moment donné, l'on aura préféré une production incomplète et moins respectueuse des critères de qualités pour satisfaire aux exigences de productivité (en quantités, délais raccourcis ou compression de personnel). Tout se paie un jour.
  2. Dans la non prévision des conséquences des erreurs que l'on a volontairement laissées passer.
    Des erreurs (ou "trou") que l'on ne cherchera pas à combler par la suite. En effet, le passé c'est du passé. Et l'on est souvent tenté d'enchainer les solutions faciles.
Erreurs de gestions plus spécifiques au monde de l'informatique
En ce qui concerne le monde informatique (IT et développement), les deux erreurs de gestion précédemment décrites sont vraiment très courantes. Je dirais même que c'est édifié en règles standards de production (ouch!!).
Ainsi, l'on rencontre souvent les comportements suivant:
  • Remettre à plus tard certains développements.
  • Ne pas blinder certaines logiques, voire carrément omettre des pans entiers de code... (on verra bien si cela explose!).
  • Ne pas tester les modifications... agir en "live" et surtout dans l'urgence.
  • Négliger les sessions de tests (cela prend du temps et forcement cela coûte cher dans un budget).
  • Sortir la version du logiciel coûte que coûte ( "par la porte ou par la fenêtre" est un terme régulièrement usité) sans considération particulière pour les problèmes potentiels (encore une fois, "on verra plus tard...").
  • Produire plus et plus vite... au point de ne plus être méticuleux sur la cohérence des informations produites/stockées.
  • Attendre la dernière minute pour faire mettre en place des modifications importantes ou impératives.
Dans le monde de l'IT, ces comportements sont fréquents et les conséquences sans appel!
En effet, de petites erreurs en petites erreurs, et lorsque l'utilisateur final tente de trouver seul une autre voie pour résoudre ses problèmes (1*) les erreurs se glissent doucement dans la base de données... ou les documents produits (code barre) ne contiennent pas les bonnes informations.
Le niveau d'incohérence s'élève peu à peu sans que l'on s'en rende vraiment compte... les problèmes logiciels étant généralement mis sur le dos des utilisateurs... et lorsque cela devient important au point de faire des investigations, il est déjà trop tard car l'on rentre déjà dans un cycle "Action-Réaction".
Et comme un problème informatique n'arrive jamais seul... (autres clients ou autres problèmes), l'on passe très vite dans le mode "gestion coup de feu"... bye-bye la planification.

1*) C'est lorsque l'utilisateur rencontre des problèmes (ou qu'il est bloqué par le logiciel) qu'il se met à explorer les autres options/façons d'arriver à ses fins. C'est ainsi qu'il arrive tôt ou tard à exécuter les portions de code non blindées ou faites "à la va vite". Dans le meilleur des cas, cela plante le logiciel, ce qui est une bonne chose car dans le pire des cas, cela corrompt les données, l'intégrité de celles-ci, exécute un processus de façon incomplète ou produit une action/document orphelin qui peut se perdre dans les méandres de l'administration.

Mon avis est que même les cas d'erreurs doivent être prévus, documentés et bloqués!
Si une section du logiciel est incomplète, et à moins d'une analyse de risque (et solution) rigoureuse, cette section doit être désactivée ou produire une erreur compréhensible.
Cela évite d'entrer dans un processus de gestion de coup de feu qui est une nuisance grave (cfr la métaphore de l'incendie) pour maintenir un bon train de production à court terme comme à long terme.

En parallèle, j'évoquerais le cas d'une construction où les futurs propriétaires ne disposent pas d'assez de moyen pour avoir une cave de plain pied sous la maison mais d'une cave sous une partie seulement de la construction à venir.
Dans ce cas de figure où il faut abandonner une partie de la construction, la maison ne disposera pourtant pas d'une bonne fondation côté cave et d'une mauvaise fondation côté "sans" cave.
Pour résoudre ce problème, les professionnels placent une semelle en béton et un vide ventilé sous la partie "sans" cave.
L'ensemble cave + semelle est monté sous forme d'un ensemble cohérent visant à assurer coûte que coûte la stabilité complète de la construction.
Il devrait en être de même dans le monde logiciel. 

S'échapper de la gestion coup de feu
Pour cela, il faudra que quelqu'un prenne la décision d'agir sur le processus pour résorber les problèmes avant qu'ils n'arrivent (ou limiter les conséquences de ces problèmes).
En modifiant le schéma systémique, il est possible de rétablir une situation normale, mais cela prend du temps et des ressources, car durant cette période de transition il faut aussi continuer à gérer les coups de feu en cours. 

Pour arriver à cela ou éviter de tomber dans une "gestion coup de feu", il faut prendre la décision d'avoir un produit (et une chaine de production) où l'erreur est traquée avant qu'elle n'ait une répercussion... même des mois plus tard.
C'est un travail d'analyse continu ou la vigilance doit rester constante.
Dans le cadre d'un rétablissement de gestion en planification, cela représente aussi une lourde responsabilité car cela impose, à un moment donné, de freiner la production pour réorganiser les ressources, les objectifs et y mettre de l'ordre.

Dans la pratique, les contraintes de production sont telles que le hiérarchie ne réagit pas à temps (voire pas du tout).
Quand le phénomène "gestion coup de feu" s'amorce, les employés tardent d'ailleurs à réagir. C'est en effet lorsque la charge quotidienne de travail semble démesurée qu'ils se réinterrogent sur "ce qu'il se passe". Mais dans la plupart des cas, ils avaient déjà levé le lièvre plusieurs mois avant... problème sans importance immédiate à l'époque. Il sera déjà trop tard au moment du constat.

Dans les faits, et même si les employés se plaignent, ils ont souvent assez de conscience professionnelle pour joindre les deux bouts quand même.
Malgré une perte de production apparemment raisonnable, ce "laisser aller" à un prix à long terme (bien plus grave que l'effet d'avalanche déjà décrit). Nous aborderons les conséquences plus tard lors la métaphore de l'incendie.

Et sans vouloir porter atteinte à qui que ce soit, lorsqu'une "gestion coup de feu" se met en place, les supérieurs hiérarchiques passent du statut de planificateur à celui d'aboyeur. Il n'est généralement plus là pour planifier mais pour imposer des délais ou des contraintes de solutions (système action-réaction/problèmes-solutions)... d'ailleurs la planification devient impossible tellement les équipes sont submergées par les problèmes s'ajoutant à leur travail quotidien.

La métaphore de l'incendie
Pour comprendre l'utilité d'une gestion précoce des erreurs et problèmes tout comme l'utilité de sortir d'une "gestion coup de feu", nous allons utiliser les services d'incendies comme référence d'une métaphore.

Pour commencer, les services d'incendies font de la prévention. Ils visitent régulièrement les entreprises avoisinantes pour s'assurer qu'il n'existe aucun risque en gestation. Avoir un équipement d'incendie en ordre et des conditions de travail sous contrôles de risque est impératif.
En fait, les services d'incendies traquent l'erreur dans votre système et vous encourage à le corriger au plus vite avant que cela ne devienne un gros problèmes. Plein de bon sens et pour le moment, cela n'a coûté les efforts que d'une personne. Le coût est raisonnable.

Admettons maintenant que cela ne se soit jamais passé et que votre système présente un réel risque.
Lorsque le risque tourne à l'incendie, c'est une brigade de pompier qui débarque... et si le problème est difficilement contrôlable (ce qui arrive aussi dans le domaine informatique comme la production)... c'est tous les services d'incendies qui débarquent pour limiter les dégâts et tenter de sauver ce qui peut l'être.
En faisant appel à son bon sens, on remarque facilement que:
la négligence à pour conséquence:
  • Une débauche de moyen matériel pour garder le système sous contrôle.
  • Une débauche d'énergie humaine
  • Un risque accru pour le système (les pompiers ne font pas dans la dentelle, c'est normal d'être moins regardant en période de risques accrus).
  • Un risque d'arrêt du système.
  • Cela coutent des centaines (voir des milliers) de fois plus d'argent que la prévention.
Après l'intervention:
  • Evaluer les dégats (tâche pas toujours facile).
  • Il est parfois nécessaire de reconstruire partiellement ou totalement le système (cela concerne aussi l'information!).
  • Parfois nécessaire de faire appel à des spécialistes pour nous aider à contrôler ce qui est devenu difficile à maintenir ou reconstruire une nouvelle infrastructure (aussi vrai pour l'IT!).
  • Rassurer les clients et les fournisseurs (car l'entreprise apparait bien fragile tout d'un coup!).
Les employés:
Dans cette métaphore, les pompiers sont en fait les employés qui gèrent le "coups de feu"/problèmes apparus.
Tout comme les pompiers:
  • C'est les plus expérimentés qui partent au feu. Ceux qui sauront certainement apporter les meilleures réponses tout en préservant l'intégrité du système.
  • C'est des humains qui s'épuisent. Il n'est pas possible pour un pompier de partir au feu heures après heures, jours après jours pendant des mois. C'est épuisant physiquement et psychologiquement, tout comme pour les employés.
  • C'est une denrée non renouvelable. Si l'on peut remplacer un employé ou un pompier, on ne remplace pas l'expérience au pied levé! Il ne suffit pas de le presser comme un citron et le jeter pour ensuite en reprendre un autre. C'est pourtant une conception répandue.
Les conséquences d'une gestion coup de feu
  • L'épuisement professionnel des éléments soumis à un stress constant et donc une prolifération des maladies de longue durée.
  • Perte de compétences dans l'entreprise suite aux démissions des éléments les plus aptes à apporter les réponses adéquates.
  • Une forte perte de productivité car:
    • Résoudre un coup de feu est souvent plus complexe que d'avoir résolu le le problème à son origine. Cela coûte forcement plus de temps.
    • La concentration intense est une ressource rapidement épuisable sur une journée. A force de coups de feu et problèmes divers, la performance fond comme neige au soleil.
  • Une sur-diminution de productivite:
    • Un élément expérimenté en situation d'épuisement ne forme pas (ou mal) son nouveau collègue.
    • Un élément expérimenté peu travailler jusque quatre fois plus vite qu'une nouvelle recrue. En cas de démission ou de maladie de longue durée, la perte est importante, le remplaçant est peu efficace surtout si la tâche est complexe, ce qui accentue encore la pression et le stress général.
  • Les démissions en masse ne passent pas inaperçues dans le monde du travail (on appelle cela le ratio TurnOver).
    Comme les gens n'ont pas une tendance naturelle au suicide, les candidats les plus avisés (mais aussi les plus intéressants sur le plan intellectuel et professionnel) passeront leur chemin.
    La production ne s'en portera certainement pas mieux.
  • Une baisse de qualité apparente des produits et services (2*) et donc des pertes diverses (retours, perte de contrats, poursuites diverses, surcroît de suivit de dossiers, augmentation des pertes financières, pertes d'énergie).
  • Dégradation de l'image de la société.
    Si cela est mauvais pour les relations commerciales, cela l'est encore plus pour le Goodwill des grandes sociétés.
  • Perte de stabilité sur le marché de l'emploi comme sur le marché des ventes.
2*) La perte de qualité n'est pas causée par l'incompétence des employés mais parce que (1) le savoir faire quitte la société suite aux démissions et maladies de longue durée et (2) parce que les employés débordés ne savent plus faire leur travail dans les règles de l'art.

Pourtant, les coups de feux sont inévitables
Le coup de feu occasionnel est inévitable de temps à autre. Ce qui est plus inquiétant, c'est que cela semble devenir un mode gestion des outils de productions (employés ou ouvriers).

Il existe des métiers comme la restauration où le coup de feu est quotidien. Mais la gestion est radicalement différente de la "gestion coup de feu" que j'ai décris dans cet article.
En effet, les restaurateurs (et cuisiniers) savent très bien que le coup de feu des repas est intense et qu'ils n'ont pas le temps de se retourner. Les clients attendent, ils ont faim et pire encore, tous en même temps.
Mais ce qui change radicalement dans ce cas de figure, c'est que les cuisiniers se préparent depuis le matin pour pouvoir gérer posément la surcharge de travail des heures de repas.
Dans ce cas de figure, on est dans un modèle "prévision-action", cela n'a aucun rapport avec le modèle  "gestion coup de feu" qui se base uniquement sur la loi de l' "action-réaction" (problème-solution).


Comment identifier une situation de "gestion coup de feu"
Pour éviter les dérapages dans le processus de production et les conséquences à long terme, il convient de détecter le comportement systématique qui s'installe autour des situations "coup de feu" pour éviter que s'installe une "gestion coup de feu" (si cela est encore possible).

Voici quelques pistes de recherche:
  • Détecter une augmentation des plaintes soit des employés, soit des clients ou des fournisseurs.
  • Détecter les négligences vis-à-vis des problèmes de production (manque de précision, employé désabusé).
  • Etre attentif au fait que le travail quotidien/hebdomadaire régulier puisse être absorbé normalement.
  • Autres suggestions....

samedi 22 janvier 2011

IndexedDB - Une base de données objet accessible en JavaScript

IndexedDB est un projet du W3C visant à offrir un espace de stockage structuré pour les applications WEB (sous entendu ici les pages WEB).
Cet espace de stockage est un peu une DB SQL mais pas vraiment non plus.
IndexedDB reprend certains principes et quelques exigences des moteurs relationnels mais est accessible à partir de code JavaScript et ce SANS devoir connaître la syntaxe Sql. De surcroit, l'API est asynchrone, si cela complique un peu le développement, cela permet per contre de préserver la fluidité du navigateur internet.
IndexedDB est conçu pour stocker et manipuler efficacement des objets Javascript (JSon). Le but étant de fournir un stockage persistant et performant.

IndexedDB est par ailleurs la technologie que Google ChromeOS utilise pour stocker les données utilisateurs (les "User Experiences Informations"). Ainsi, en démarrant ChromeOS sur une autre machine et après une phase de login, toutes les informations de l'utilisateur redeviennent accessibles comme s'il n'avait pas changé d'ordinateur (ses contacts, bookmarks, fond d'écran, etc).

Cette technologie actuellement en Beta est disponible sur WebKit, FireFox et Internet Explorer (via un plug-in). Elle est promise à un bel avenir... comme toutes les technologies publicités par le géant du Web.

Pour plus d'information:
Présentation
Voici une vidéo de présentation en provenance de Google. Elle est assez intéressante mais un peu longue.
Il aurait été plus intéressant de disposer de plus de code et d'un peu moins de discours.
par contre, les exemples de code sont disponibles dans le document de présentation juste en dessous de la vidéo (c'est nettement plus croustillant).




jeudi 20 janvier 2011

Gnome 3 pour Ubuntu

Bien qu'Ubuntu dispose de plusieurs shells (interfaces graphiques/gestionnaire de bureau), l'une des plus populaires reste encore Gnome.
Cette interface graphique est d'ailleurs activée par défaut sur les installations standards Ubuntu.
Déjà très conviviale et le manquant de rien face à Windows, Gnome continue malgré tout d'évoluer.
C'est ainsi que s'annonce la version 3.0, mouture visiblement intéressante et axé sur la productivité. En effet, l'environnement du bureau a été épuré pour éviter les distractions autant que cela est possible.

Je vous invite à visiter le site de promotion sur http://gnome3.org/ ou à vous faire une idée en visionnant la vidéo suivante.



Pour les plus impatients, cette prochaine vidéo reprend les instructions pour installer le nouveau gestionnaire de bureau.

mercredi 19 janvier 2011

ADO.NET - Aide mémoire - 2/4 : DataSet

Le présent article fait parti d'une suite logique de 4 articles: "ADO.NET - Aide mémoire - 1/4 : Execution, Parametres, StoredProc, DataReader",  "ADO.NET - Aide mémoire - 2/4 : DataSet", "ADO.NET - Aide mémoire - 2/4 : DataView" et "ADO.NET - Aide mémoire - 4/4 : Tutoriel"

Cet aide mémoire se focalisera plutôt sur l'utilisation générale des DataSets.
On y découvrira:
  • L'utilisation du SqlCommand, SqlDataAdapter et DataSet afin de lire les données (via DataTable et DataRow).
  • Les méthodes de lectures via:
    • DataTable.Rows : collection of DataRow
    • DataTable.Select : Permettant le filtrage et le tri d'un sous ensemble des enregistrements. Aussi une collection de DataRow.
    • DataTable.DefaultView : DataView permettant également le filtrage et le tri d'un sous ensemble. DataView contenant une collection de DataRowView.
  • Mise à jour des données d'une DataTable dans un Dataset (et sauvegarde en DB).
eTutorial.org

    En référence, je mentionnerais également:
    DataViews
    Les DataViews offrent de nombreuses possibilités avancées qui va bien au-delà de ce qui est présenté dans l'exemple de cet article.
    L'article "ADO.NET - Aide mémoire - 3/4 : DataViews" reprend une description et quelques références Microsoft.

    Exemple 
    Voici l'exemple dont seulement les parties les plus pertinentes sont reprises dans l'article (voir fichier source pour la totalité du code).
    Cet exemple utilise Snippet Compiler comme d'habitude.
    Fichier Source: AdoNet_DataSet.cs
    using System;using System.Collections.Generic;using System.Data;using System.Data.SqlClient;
    public class MyClass
    {
        public static void RunSnippet()
        {
            DropTestDatabase(); // Drop the test database if any exists
            CreateTestDatabase();
            
            DisplaySortedDataset();
            UpdateDataSet();
        }
        
        public static void DisplaySortedDataset () {
            WL( "=== DATASET read/filter/sort operation =================" );
            SqlConnection sqlConn = GetTestConnection();
            sqlConn.Open();
            
            SqlCommand sqlCmd = new SqlCommand( "select * from usr", sqlConn );
            SqlDataAdapter sqlAd = new SqlDataAdapter( sqlCmd );
            DataSet ds = new DataSet();
            sqlAd.Fill( ds, "dataTableName_User" ); // give an explicit name for the sample
            // Display all DataTable.TableName in the DataSet
            foreach( DataTable tbl in ds.Tables )
                WL( String.Format( "  DataSet.Tables[i].TableName="+ tbl.TableName ));
    
            // === DataTable Rows =====================
            // Display the Data
            WL( "Display data (Via Rows)" );
            foreach( DataRow dr in ds.Tables["dataTableName_User"].Rows )
                WL( String.Format( "   User {0} (id:{1})", dr["usrname"].ToString(), dr["uid"].ToString() ));
            
            // === DataTable Select ===================
            // Sort it + redisplay it
            WL( "Display sorted data (via Select)" );
            DataRow[] sorted = ds.Tables["dataTablename_User"].Select("usrname like '%'", "uid desc");
            foreach( DataRow dr in sorted )
                WL( String.Format( "   User {0} (id:{1})", dr["usrname"].ToString(), dr["uid"].ToString() ));
            // SubSelect + sort
            WL( "Display filtered data (via Select)" );
            DataRow[] filtered = ds.Tables["dataTablename_User"].Select("usrname like '%a%'", "usrname asc");
            foreach( DataRow dr in filtered )
                WL( String.Format( "   User {0} (id:{1})", dr["usrname"].ToString(), dr["uid"].ToString() ));
    
            // === DataView ===========================
            // Sorted and filtered with DataView
            //   DataView may be very useful to work with visual componant
            //   More information on DataViews on Microsoft site @
            //     http://msdn.microsoft.com/en-us/library/fdcwwhez.aspx
            //
            WL( "Display filtered data (via DataView)" );
            DataView dv = ds.Tables["dataTableName_User"].DefaultView;
            dv.RowFilter = "usrname like '%a%'";
            dv.Sort = "uid desc";
            // In a DataView, the Rows are available via DataRowView        
            foreach( DataRowView drv in dv )
                WL( String.Format( "   User {0} (id:{1})", drv["usrname"].ToString(), drv["uid"].ToString() ));
            
            sqlConn.Close();
        }
        
        public static void UpdateDataSet () {
            WL( "=== UPDATE operation ============================" );
            SqlConnection sqlConn = GetTestConnection();
            sqlConn.Open();
            // Read the data
            SqlDataAdapter ad = new SqlDataAdapter( "Select * from USR order by usrName desc", sqlConn );
            // Create a CommandBuilder, this will automatically generate the appropriate commands
            // and set the various properties of the SqlAdapter.
            SqlCommandBuilder cmdBuilder = new SqlCommandBuilder( ad );
            // Create and fill dataset
            DataSet ds = new DataSet();
            ad.Fill( ds, "USR" );
    
            // Display the Data
            WL( "Display data BEFORE change" );
            foreach( DataRow dr in ds.Tables["USR"].Rows )
                WL( String.Format( "   User {0} (id:{1})", dr["usrname"].ToString(), dr["uid"].ToString() ));
    
            // Update Data
            DataRow[] filtered = ds.Tables["USR"].Select( "usrname like 'anatole'", "uid" );
            if( filtered.Length > 0 ) {
                filtered[0]["usrname"] = "John Doe";
            }
            
            // Add a new row 
            //   Removal is done with DataTable.Rows.RemoveAt(RowIndex) or DataTable.Rows.Remove( DataRowObject )
            DataRow added = ds.Tables["USR"].Rows.Add();
            added["usrname"] = "Florentin Célestin";
            added["uid"] = 120;
            
            // Save the DataSet
            ad.Update(ds, "USR");
            
            // ReRead the DataSet and Display result
            ds.Clear();
            ad.Fill( ds, "USR" );
            // Display the Data
            WL( "Display data AFTER change" );
            foreach( DataRow dr in ds.Tables["USR"].Rows )
                WL( String.Format( "   User {0} (id:{1})", dr["usrname"].ToString(), dr["uid"].ToString() ));
            
            sqlConn.Close();
        }
        
        #region Sample Database helper    // Connect and create the Test Database
        // See the source file for the Full code. 
        #endregion
        
        #region Helper methods    // ...    
        #endregion
    }