Pages

Tuesday, February 21, 2012

Le TDD n'est pas naturel mais très addictif!

Danger

Il faut faire très attention! : un peu comme la chirurgie esthétique, le TDD n'est pas une démarche naturelle mais une fois qu'on y a goûté, cette démarche a un fort pouvoir addictif! (désolé, je n'ai pas trouvé mieux comme métaphore :-))

extrait Nip Tuck
Le TDD c'est :

Le TDD signifie Test Driven Developpement ou Développement Dirigé par les Tests. Comme son nom l'indique c'est une méthode de développement basé (et même dirigé par les tests). L'idée principale est, pour développer une fonctionnalité, de faut d'abord l'exprimer sous forme de tests et d'ensuite développer la fonctionnalité pour faire passer le Test.

On entend souvent parler de "red, green, refactor" pour décrire le TDD :
- D'abord écrire un test qui échoue (vous exécutez votre test dans votre IDE et "la barre est rouge")
- Ecrire le code pour que le test passe  (vous exécutez votre test dans votre IDE et "la barre est verte")
- Refactorer le code pour le rendre clair, lisible, limpide pour fair simple : beau!

Me
Pfff... Après y avoir goûté, on se retrouve à porter des tee-shirts ridicules de geek sur le TDD... :-)

Une des pratiques du TDD poussée à l’extrême est le "TDD as you meant it" qui consiste globalement à tout écrire dans la classe de test (même le code pour faire passer le test) et de ne déplacer les méthodes en refactorant qu'une fois que le test passe.

Constat:
Le TDD n'est pas une démarche naturelle. C'est quelque chose qui fait partie de l'évolution du développeur. En revanche quand on y a goûté, c'est une démarche qui parait naturelle et qu'on a envie de reproduire.
Evolution de l'homme
Quand on commence sa vie de développeur, on ne commence pas à directement faire du TDD. Je pense que la démarche est de d'abord comprendre la technologie, le langage et ses concepts avant de faire des Test Unitaires puis du TDD. Vous souvenez vous de la première ligne de code Java que vous avez écrite?

C'était plutôt ça :
public static void main(String[] args) {
        System.out.println("hello world");
    }

ou plutôt ça :
@Test
public void shouldSayHelloWorld() throws Exception {
    HelloWorld hello = new HelloWorld();
    assertThat(hello.say()).isEqualTo("Hello World");
}

Moi, par exemple, j'ai commencé par la première façon pas par la deuxième. J'imagine que pour beaucoup d'autres nous (les développeurs) c'était aussi le cas. CQFD :

Le TDD n'est pas une démarche facile et naturelle!

Le TDD est une démarche vers laquelle un développeur peut, suivant son évolution et son contexte, avoir envie d'adopter. Cette évolution n'est pas forcément liée à un facteur temps: l'adoption peut être rapide ou ne jamais arriver.

La difficulté du TDD est que pour vraiment comprendre la démarche, je pense qu'il faut l'avoir pratiqué ou l'avoir vu pratiquer. Je pense qu'il est donc difficile de convaincre quelqu'un de faire du TDD simplement en échangeant sur le sujet. La meilleure solution dans ce cas, c'est de lui proposer d'essayer!

Envie d'y goûter?
Pour illustrer l'idée, je vais reprendre la désormais célèbre scène de Matrix : la pilule bleu ou la pilule rouge. L'idée c'est donc ça :

extrait Matrix
  • Si tu ne dors plus la nuit car tu n'as pas confiance dans le code de ton application
  • Si tu es fatigué après chaque modification de code de devoir passer en mode debug pour voir comment se comporte ton code
  • Si à chaque message de commit tu as envie d'écrire "banzaï, on verra bien si ça marche"
  • Si tu as peur de refactorer ton code par peur de tout casser
  • Si tu ne sais pas comment concevoir ton application car cela te parait trop compliqué et que tu aimerais commencer simplement...
C'est que tu es forcément attiré une autre réalité... et la pilule rouge du Tests Unitaires et du TDD te fait de l'oeil.

A la différence de Matrix, une fois que vous avez pris la pilule rouge, il vous reste encore tout à faire... Comment concrètement vous y mettre :

Les outils gravitant autour des tests unitaires du TDD (Java oriented):
Il existe une ensemble d'outillage pour vous aider à faire du TDD :
  • une librairie de tests unitaires : JUnit. Le framework de base pour faire des tests unitaires en Java.
  • des facilitateurs technologique : *Unit. Ces librairies ont pour but de venir en complément pour simplifier les tests liés à certaines technologies (DBUnit vous aidera sur des tests avec une BDD relationnelle, JWebUnit vous aidera sur des tests avec une application WEB , HtmlUnit vous aidera à tester du HTML, XmlUnit vous aidera à tester du Xml, CassandraUnit vous aidera sur des tests avec Cassandra...)
  • des facilitateurs sur la lisibilité du test (notamment sur les assertions) : Hamcrest ou Fest-Assert.
  • les librairies de Mock : Les objets "mocké" sont globalement des objets utilisés dans les tests dont on maîtrise le comportement pour tester d'autres objets (JMock ou Mockito par exemple).
  • des librairies s'intégrant dans votre IDE pour faire du test en continu comme InfiniTest.

Le TDD partout?
C'est toujours plus facile à dire qu'à faire. Hum, tout un débat possible en perspective... Je ne suis pas un intégriste sur la question, je dirais simplement qu'il y a parfois beaucoup moins de plus value à faire du TDD sur certains couches applicatives... Par exemple, faire du TDD pour tester que quand on clique sur un bouton et bien ça clique sur le bouton...


Le TDD sur du code existant
Oui et oui. Cet article de Xebia ici l'explique d'ailleurs très bien.

Pour conclure
Je pense qu'il y a un réel fossé entre un développeur qui a déjà fait du TDD et un qui n'en a jamais fait. Chacun trouve d'ailleurs que l'autre est un extra terrestre :-). Je pense qu'une fois de plus, c'est une démarche très intéressante que j'ai adoptée mais je comprend aussi que dans certains contextes il est difficile de la mettre en oeuvre. De toute façon, le TDD, c'est un peu la cerise sur le gâteau, car il est très difficile d'expliquer les avantages du TDD lorsqu'il faut parfois commencer par expliquer l'avantage de faire des tests!

Le plus simple en tous cas avec le TDD pour vous faire votre propre avis, c'est d'y goûter :-)

Monday, February 13, 2012

xml vs json vs yaml (Java oriented)

Il existe aujourd'hui un ensemble de format permettant de stocker des données. Il y a du choix!

On connait historiquement le format XML mais d'autres formats sont de plus en plus utilisés tels que JSON ou YAML.

Je vous propose ici de faire une petit comparaison de ces 3 formats notamment lorsqu'on doit faire de la sérialisation/déserialisation en Java.

XML : "le classique"

Le bon "vieux" format XML est un standard incontournable de stockage de données.

Ses forces :
  • Il est clairement fortement répandu, voir incontournable.
  • Il possède des langages de description permettant de contractualiser le contenu : DTD (Document Type Definition) ou XML Schema.
  • Il est très outillé.
  • Il est lisible.
Ses faiblesses :
  • Il est très (trop) verbeux.
  • "complexe" à mettre en oeuvre.
Comment on fait en java? 
Il existe plusieurs type d'APIs pour "discuter XML" en Java. Dans une première approche, Il existe JDOM  qui propose 2 orientations. La première est orienté "DOM" qui est de créer une représentation des données (non typé, à base de classe JDOM) XML en JAVA en mémoire. la seconde est orienté "SAX" qui est une APIs évènementielle qui parcourt le document et sur lequel on vient se câbler pour récupérer des morceaux de document.

Du coté des APIs plus haut niveau, JIBX ou JAXB (notamment dans sa version 2) offre un environnement de travail complet sérialiser/déserialiser. Elles permettent notamment de manipuler en java des objets typés.

Si on prend l’exemple de JAXB, l'idée est :
  • de récupérer ou créer le XML Schema représentant le document que l'on souhaite sérialiser/déserialiser (c'est le "contrat")
  • de générer avec XJC (outil de génération de classes de JAXB) les classes (annotées) correspondants à la structure du document. Un plugin maven permet d'intégrer ça au process de build : jaxb2-maven-plugin
  • à l’exécution, utiliser les APIs JAXB avec les classes générés pour écrire ou lire du XML.
Voilà ce que cela peut donner : 
Pour déserialiser : 
JAXBContext jc = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(this.getClass().getResource("/user.xsd"));
unmarshaller.setSchema(schema);
User user = (User) unmarshaller.unmarshal(new File("user.xml"));

Pour sérialiser :
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, 
  Boolean.TRUE);
marshaller.marshal( user, new File("user-modified.xml") );

C'est un peu verbeux mais ça marche bien :-)

JSON : "à la mode"

Ses forces :
  • Il est très à la mode et très répandu.
  • Il est bien outillé.
  • Il est peu verbeux.
Ses faiblesses :
  • Il est peu lisible.
  • Il n'existe pas de format de définition de schéma (seulement un draft).
Je trouve le JSON moins lisible pour un humain mais il est souvent utilisé comme format d'échange inter applicatif (entre un client et un serveur par exemple) où le but n'est pas qu'il soit lisible mais qu'il soit léger et concis. C'est un format qui est notamment beaucoup utilisé dans les architectures REST.

Comment je fais en java?
Il existe pas mal de librairies permettant de faire la sérialisation/désérialisation en JAVA. Pour en citer quelques unes : json-lib, google-gson, FlexJSON ou encore Jackson. C'est cette dernière que j'utilise en général. 

Dans le cas de Jackson par exemple, l'APIs pour sérialiser/désérialiser en Java est très simple, il n'y a aucun impact sur votre code. Vous pouvez utiliser vos classes existantes et les sérialiser.

Pour désérialiser :
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
User user = mapper.readValue(new File("user.json"), User.class);

Pour sérialiser :
mapper.writeValue(new File("user-modified.json"), user);

C'est tout...

YAML : "l'anti balise"

Sa force :
  • Il est très peu verbeux.
  • Il est très lisible.
Ces faiblesses :
  • Il est moins connu et moins répandu.
Le YAML regroupe 2 points très intéressants : il est très lisible et peu verbeux. Comme le précise le site de YAML, son objectif est d'être "human friendly".

Comment je fais en java?
Il y a quelques librairies en java permettant de faire le job : JYaml et SnakeYAML. C'est d'ailleurs cette dernière que j'utilise.

Dans le cas de SnakeYAML, comme pour Jackson avec JSON, il n'y a aucun impact en terme de code et vous pouvez réutiliser vos classes existantes en l'état.

Pour désérialiser :
Yaml yaml = new Yaml();
User user = yaml.loadAs(new File("user.yaml"), User.class);

Pour sérialiser:
Yaml yaml = new Yaml();
yaml.dump(user,new FileWriter("user-modified.yaml"));

C'est tout aussi...

Comparons : 

Bon, et maintenant si on faisait un petit test en exprimant la même chose dans les 3 formats et en regardant le résultat. Je vais baser l'exemple en exprimant un dataSet de CassandraUnit. On peut exprimer un dataSet dans ces 3 formats.

Voici donc une première version xml :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<keyspace xmlns="http://xml.dataset.cassandraunit.org">
    <name>otherKeyspaceName</name>
    <strategy>org.apache.cassandra.locator.SimpleStrategy</strategy>
    <replicationFactor>1</replicationFactor>
    <columnFamilies>
        <columnFamily>
            <name>beautifulColumnFamilyName</name>
            <type>STANDARD</type>
            <keyType>UTF8Type</keyType>
            <comparatorType>LongType</comparatorType>
            <row>
                <key>key10</key>
                <column>
                    <name>11</name>
                    <value>utf8(value11)</value>
                </column>
                <column>
                    <name>12</name>
                    <value>utf8(value12)</value>
                </column>
            </row>
            <row>
                <key>key20</key>
                <column>
                    <name>21</name>
                    <value>uuid(13816710-1dd2-11b2-879a-782bcb80ff6a)</value>
                </column>
            </row>
        </columnFamily>
        <columnFamily>
            <name>columnFamilyWithCompositeType</name>
            <type>STANDARD</type>
            <keyType>CompositeType(LongType,UTF8Type)</keyType>
            <comparatorType>CompositeType(UTF8Type,IntegerType,UTF8Type)</comparatorType>
            <defaultColumnValueType>UTF8Type</defaultColumnValueType>
            <row>
                <key>10:azerty</key>
                <column>
                    <name>aa:10:aa</name>
                    <value>Chuck</value>
                </column>
                <column>
                    <name>aa:10:ab</name>
                    <value>Larry</value>
                </column>
            </row>
        </columnFamily>
    </columnFamilies>
</keyspace>


Voici le même dataSet exprimé en JSON :
{
    "name" : "otherKeyspaceName",
    "replicationFactor" : 1,
    "strategy" : "org.apache.cassandra.locator.SimpleStrategy",
    "columnFamilies" : [{
        "name" : "beautifulColumnFamilyName",
        "type" : "STANDARD",
        "keyType" : "UTF8Type",
        "comparatorType" : "LongType",
        "rows" : [{
            "key" : "key10",
            "columns" : [{
                "name" : "11",
                "value" : "utf8(value11)"
            },
            {
                "name" : "12",
                "value" : "utf8(value12)"
            }]
        },
        {
            "key" : "key20",
            "columns" : [{
                "name" : "21",
                "value" : "utf8(value11)"
            },
            {
                "name" : "12",
                "value" : "uuid(13816710-1dd2-11b2-879a-782bcb80ff6a)"
            }]
        }]
    },
    {
        "name" : "columnFamilyWithCompositeType",
        "type" : "STANDARD",
        "keyType" : "CompositeType(LongType,UTF8Type)",
        "comparatorType" : "CompositeType(UTF8Type,IntegerType,UTF8Type)",
        "defaultColumnValueType" : "UTF8Type",
        "rows" : [{
            "key" : "10:azerty",
            "columns" : [{
                "name" : "aa:10:aa",
                "value" : "Chuck"
            },
            {
                "name" : "aa:10:ab",
                "value" : "Larry"
            }]
        }]
    }]
}

Enfin, toujours le même dataSet exprimé en YAML :
name: otherKeyspaceName
replicationFactor: 1
strategy: org.apache.cassandra.locator.SimpleStrategy
columnFamilies:
- name: beautifulColumnFamilyName
  type: STANDARD
  keyType: UTF8Type
  comparatorType: LongType
  rows:
  - key: key10
    columns:
    - {name: 11, value: utf8(value11)}
    - {name: 12, value: utf8(value12)}
  - key: key20
    columns:
    - {name: 21, value: utf8(value11)}
    - {name: 12, value: uuid(13816710-1dd2-11b2-879a-782bcb80ff6a)}
- name: columnFamilyWithCompositeType
  type: STANDARD
  keyType: CompositeType(LongType,UTF8Type)
  comparatorType: CompositeType(UTF8Type,IntegerType,UTF8Type)
  defaultColumnValueType: UTF8Type 
  rows:
  - key: "10:azerty"
    columns:
    - {name: "aa:10:aa", value: Chuck}
    - {name: "aa:10:ab", value: Larry}

et là on se dit, tiens, c'est sympa le YAML :-).

Pour exprimer la même chose, il aura fallu :

  • 1131 octets au format XML (non formaté)
  • 793 octets au format JSON (non formaté)
  • 779 octets au format YAML

Conclusion
L'objet de cet article n'est pas de dire qui est le meilleur. Le cas de stockage de DataSet est en effet particulier car un des critères est justement qu'il soit "human readable" mais ce qui est surprenant c'est qu'au final, c'est YAML qui est le plus lisible mais aussi le plus concis.

En général, chacun de ces formats est utilisés dans des contextes différents même s'il est vrai que le XML et le JSON, qui sont plus répandus, sont souvent opposés en terme de comparaison : 
web services SOAP/XML vs web services REST/JSON. 
Oui le XML est plus verbeux que le JSON mais il est plus "contractuel". 

On retrouve en revanche plus le format YAML comme format de fichiers de configuration comme c'est le cas pour le fichier de configuration de Cassandra par exemple. Je trouve en tous cas ce format de fichier comme une alternative intéressante qu'il ne faut pas oublier!

Friday, February 10, 2012

CassandraUnit : un outil Dev & Ops!

CassandraUnit est un framework permettant de vous aider à développer des applications Java basé utilisant Cassandra.

Depuis la version 1.0.1.4, C'est maintenant un outil à la fois Dev & Ops, car il peut vous accompagner dans toutes les phases de votre projet :

Un outil @Dev:
CassandraUnit est initialement né de la volonté de vouloir faire du TDD en testant aussi la persistance dans Cassandra. Le but était de répondre à 2 problématiques : 
  • Comment développer un service de lecture de données dans Cassandra en faisant du TDD sans avoir de cluster Cassandra?
  • Comment faire en sorte que mes tests unitaires soient portables et isolés pour pouvoir faire de l'intégration continue?
L'idée directrice était de proposer un environnement au niveau des tests unitaires qui permettent avant leur exécution :
  • de démarrer une instance embarquée de Cassandra.
  • de remplir cette instance avec un keyspace et des données.
Comment ça marche ?

Il faut dans un premier temps définir votre dataSet, C'est le jeu de données qui sera inséré dans Cassandra pour votre test unitaire.

CassandraUnit vous permet selon votre préférence de définir un dataSet au format XML, JSON ou Yaml ( plus d'infos ici)

Il faut ensuite l'intégrer au niveau de votre test ou de votre code. Il est possible de faire ça de plusieurs manières :
  • soit de manière native en manipulant l'APIs (donc pas forcément dans un test) : 
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
DataLoader dataLoader = new DataLoader("TestCluster", "localhost:9171");
dataLoader.load(new ClassPathJsonDataSet("simpleDataSet.json"));
  • soit par héritage au niveau de votre classe de Test :
public class yourTest extends AbstractCassandraUnit4TestCase {

    @Override
    public DataSet getDataSet() {
        return new ClassPathJsonDataSet("simpleDataSet.json");
    }

    @Test
    public void shouldHaveLoadASimpleDataSet() throws Exception {
        assertThat(getKeyspace(), notNullValue());
        /* and query all what you want */
    }

}
  • soit sans héritage! merci Junit @Rule
public class SecondaryIndexWithRuleTest {

    @Rule
    public CassandraUnit cassandraUnit = new CassandraUnit(new ClassPathJsonDataSet("simpleDataSet.json"));

    @Test
    public void shouldHaveLoadASimpleDataSet() throws Exception {
        assertThat(getKeyspace(), notNullValue());
        /* and query all what you want */
    }

}

Un outil @Ops
Depuis la version 1.0.1.4, CassandraUnit propose un outil en ligne de commande multi OS : le "cu-loader".
Cet outil en ligne de commande permet de réutiliser vos dataSets pour créer vos keyspaces et/ou charger vos données dans d'autres cluster Cassandra que votre instance de Cassandra embarquée en @Dev.

L'outil permet de réutiliser les dataSets sans les modifier mais avec la possibilité de surcharger certaines déclaration liées à la configuration du cluster Cassandra (comme le replication factor, la stratégie, ...).

L'objectif de l'outil est d'éviter d'introduire des erreurs liées au changement d'environnement en créant un keyspace qui ne correspondrait au keyspace utilisé en développement.

CassandraUnit est diponible sous forme de distribution téléchargeable depuis github ici ainsi que sur le repo central maven. Il suffit donc de le décompresser et de rajouter

Voici ce que ça donne à l'utilisation :

> cu-loader
Missing required options: f, h, p
usage: CassandraUnitLoader is a tool to load CassandraUnit data Set into cassandra cluster
 -f,--file <arg>                dataset to load
 -h,--host <arg>                target host (required)
 -o,--onlySchema                only load schema (optional)
 -p,--port <arg>                target port (required)
 -r,--replicationFactor <arg>   override the replication factor set in the dataset (optional)
 -s,--strategy <arg>            override the strategy set in the dataset (optional)
Un exemple simple :
> cu-loader -f datasetDefaultValue.xml -h localhost -p 9160
Un exemple complet :
> cu-loader -f datasetDefaultValue.xml -h 10.10.10.01 -p 9160 -o -r 3 -s org.apache.cassandra.locator.NetworkTopologyStrategy
Vous trouverez plus de détails dans le doc ici

Voici des liens qui pourront vous être utile si vous voulez aller plus loin :
- github : https://github.com/jsevellec/cassandra-unit/
- mailing list : https://groups.google.com/group/cassandra-unit-users?hl=fr
- twitter : https://twitter.com/cassandraunit

Bref. Un bel outil. :-)



Friday, January 27, 2012

Brancher Nexus sur Active Directory (LDAP)

Après avoir perdu un peu de temps à configurer Nexus sur Active Directory par l'intermédiaire du protocole LDAP, Je vous propose de vous faire partager mon expérience sur le sujet et en français

Mon besoin était le suivant :
  • Mettre en place un Nexus.
  • Mettre en place un système d'authentification pour l'administration du Nexus.
  • Réutiliser le  référentiel d'utilisateur de l'entreprise.
  • Ne pas ouvrir l'administration de Nexus à tous les utilisateurs présents dans l'AD mais seulement à un groupe.
Une documentation très bien faite est mise à disposition par Sonatype Ici.

Le problème n'est pas dans la qualité de la documentation mais se brancher sur un AD par l'intermédiaire de LDAP n'est jamais simple : beaucoup d'options, de paramétrages, des contenu dans les référentiels LDAP très différents.

Etape 1 : Obtenir un accès
Avant de commencer, il faut obtenir un utilisateur/mot de passe qui soit capable de naviguer en lecture au sein de l'AD. En général, il faut créer ou faire créer un utilisateur générique par lequel vos applicatifs (comme Nexus) viendront interroger votre AD.

Une fois cet utilisateur en poche (ça peut prendre du temps à avoir ce genre de choses...) , je vous conseille de le tester avec un browser LDAP. Je me suis servi d'Apache Directory Studio. Il est Open Source et c'est une application RCP. Bref, il fait plutôt bien le job.

Il vous suffit donc de créer une connexion (host et port de l'AD, user, password) et hop vous pouvez naviguer à l'intérieur.

Il faut aussi créer un groupe AD et y rattacher les utilisateurs à qui vous souhaitez donner l'accès à l'administration de Nexus. Votre AD possède peut être déjà un groupe qui correspond à la population qui vous intéresse. Vous pouvez dans ce cas le réutiliser. Pour la suite de l'article, nous appellerons ce groupe "equipe-de-developpement".

Mais ça n'est pas fini...

Etape 2 : Obtenir une bonne vision de l'arborescence de l'AD

Le plus important et de récupérer l'adresse LDAP racine dans laquelle tous les utilisateurs se trouvent. Nous l’appellerons pour la suite de l'article "l'adresse racine utilisateur".
par exemple : CN=Users,DC=votreDomaine,DC=com

Mais ça n'est pas fini...

Etape 3 : configurer la partie LDAP de Nexus
Connectez-vous en admin sur Nexus et déplacez-vous dans la partie Security > "LDAP Configuration" accessible depuis le menu latéral gauche. C'est parti pour la partie conf : 
  • Connection : (permet de définir les paramètres de connexion à l'AD)
    • Protocol : Ldap
    • Hostname : adresse de l'AD (le même que vous avez utilisé avec botre browser LDAP).
    • Port : port de l'AD (en général c'est 389).
    • Search Base : c'est l'adresse par défaut à partir de laquelle le requêtage LDAP se fera une fois connecté. Remplissez le avec l'adresse racine utilisateur.
  • Authentication : (permet de définir la manière dont Nexus s'authentifie sur l'AD)
    • Authentication method : Choisir "Simple Authentication"
    • SASL Realm  : laisser vide.
    • Username : le username de votre utilisateur générique ayant accès en lecture à AD.
    • Password : le password de votre utilisateur générique ayant accès en lecture à AD.
Vous pouvez faire un "check authentication". Si tout est ok vous devez avoir un "LDAP connection and authentication test completed successfully." Ça veut dire que votre Nexus sait se connecter à votre AD.
  • User Element mapping : (permet de définir la manière dont Nexus va vérifier si un user existe)
    • Base DN : laisser vide (si vous avez bien renseigné dans la partie connection que l'adresse par défaut de requêtage est bien l'adresse racine utilisateur).
    • User Subtree : à cocher.
    • Object Class : Saisir "Person", c'est le type d'objet LDAP contenant les utilisateurs.
    • User ID Attribute : Il faut indiquer le nom de l'attribut LDAP qui contient les logins utilisateurs AD. Saisir : "sAMAccountName"
    • Real Name Attribute : Il faut indiquer le nom de l'attribut LDAP qui contient le nom complet des utilisateurs AD. Saisir : "displayName".
    • E-Mail Attribute : Il faut indiquer le nom de l'attribut LDAP qui contient l'adresse mail des utilisateurs AD. Saisir : "mail".
    • Password Attribute : Il faut indiquer le nom de l'attribut qui contient le mot de passe des utilisateurs AD. Laisser vide (c'est un attribut par défaut).
  • Group Element Mapping : (permet de définir la manière donc Nexus va récupérer la liste des groupes).
    • Group Type : Saisir "Dynamic Groups". Il y a 2 types de groupes LDAP : un groupe dynamique correspondant à un attribut dans un objet "user" LDAP. Un groupe statique, c'est le contraire, c'est la référence à une liste d'utilisateurs dans un objet LDAP "group". Avec AD, à priori, quand un groupe est créé il l'est en statique et dynamique. Autant donc choisir dynamique car il y a beaucoup moins de configuration ;-).
    • Member Of Attribute : Il faut indiquer le nom de l'attribut LDAP dans lequel un groupe dynamique est défini. Saisir : "memberOf".
Vous pouvez faire un "Check User Mapping". Si tout est ok, Nexus vous affiche un début de liste d'utilisateurs qu'il a réussi à requêter. 

N'oubliez pas de faire "save" :-)

Mais ça n'est pas fini...

Etape 5 : Mapper votre groupe AD avec un rôle NEXUS.

Il faut maintenant configurer à Nexus pour que les utilisateurs de votre groupe AD equipe-de-developpement correspondent à un rôle dans Nexus, par exemple "Administrateur Nexus".

Déplacez-vous dans la partie "Roles" accessible depuis le menu latéral gauche :
  • Sélectionner "Add" > "External Role Mapping"
  • Realm : choisir "LDAP"
  • Role : La liste des rôle LDAP de votre AD doit être présente. choisir votre groupe equipe-de-developpement
  • Ajouter ensuite le Rôle associé en cliquant sur "add"
  • Cocher le "Nexus Administrator Role"
  • Cliquer sur OK
Mais ça n'est pas fini...

Etape 6 : activer l'authentification LDAP pour Nexus
Il faut maintenant simplement activer l'authentification par LDAP. Je dis "simplement", mais j'ai cherché un bout de temps avant de comprendre pour tout ça ne marchait pas ;-).


Déplacez-vous dans la partie "Administration" > "Server" accessible depuis le menu latéral gauche :

  • Dans la partie "Security Settings": déplacer "OSS LDAP Authentication Realm" de "Available Realms" vers "Selected Realms".
That's all...










Friday, January 13, 2012

Agilité par contamination


Lorsqu'on souhaite mettre en oeuvre Scrum la première fois, il est souvent dit de mettre en place la totalité du framework et dans un second temps de l'adapter quand l'ensemble des acteurs possèdent le recul nécessaire (pour justement l'adapter favorablement). Cette mise en place totale a pour but de ne pas tomber dans les fameux "Scrum But", souvent cause de l'échec de la mise en place de Scrum. Les "Scrum But" pour simplifier représentent les entorses au framework (Exemple : c'est le ScrumMaster qui fait les estimations et affectent les tâches, oui ça c'est de la très grosse entorse ;-)).

Je vous propose ici de vous raconter un de mes retours d'expérience sur le sujet qui est très différent de l'approche dont je viens de vous parler.

Il y a bientôt un an, j'ai intégré une équipe de développement chez un éditeur logiciel qui ne pratiquait pas "l'agilité". Ce nouvel environnement me paraissait idéal pour mettre en place Scrum couplé avec un peu d’Extrême Programming pour plusieurs raisons :
  • une petite structure (moins de 25 personnes).
  • une équipe de développement de moins de 6 personnes.
  • une forte croissance.
  • la volonté de développer une nouvelle version d'un produit.

Il faut avouer que Scrum est très déroutant dans ces pratiques quand on ne les a jamais mises en oeuvre. Comme je ne m'appelle pas Jeff Sutherland (un des papas de Scrum) et que je ne suis pas un extrémiste (enfin j'estime ne pas l'être, ce qui est différent, je vous l'accorde), je n'ai pas forcé pour la mise en place de Scrum.

En revanche, je travaillais sur un sujet isolé et avec une liberté totale sur ma façon de travailler. J'ai donc fait du Scrum et de l'Xp seul (ok ce n'est pas vraiment du Scrum). Tiens ça me fait penser à Jean Jacques.

Hey hop, c'est parti, je récupère un tableau en carton, j'ai un mur juste derrière moi, impeccable,  ça sera mon scrum board. Un petit tour par la compta : "Heu, vous auriez des post-its? Ha, vous n'avez que cette couleur, ok ça ira très bien pour commencer. Vous pouvez en commander d'autres? et de plusieurs couleurs?".


Un ou deux jours passent...

Réaction 1 : "Ha c'est comme ça que tu travailles?"
Réaction 2 : "C'est jolie tous ces post-its derrière toi, c'est quoi, ça marche comment?"


Côté pratique d'ingénierie, pas d'intégration continue, pas de DVCS (en tous cas pas celui que je voulais :-)), pas de suivi de qualité, pas de déploiement continu. Ok, qu'à cela ne tienne, "Just Do It". C'est parti pour mettre en place une forge logicielle complète sur une machine virtuelle dans un coin de serveur (apache, jenkins, git, sonar, maven, ...).

Réaction 3 : "C'est quoi l'intégration continue?"

J'avais maintenant tous les outils que je souhaitais pour développer. C'est parti. Les semaines passent, les post-its s'entassent...

Réaction 4 : "C'est pas mal ton tableau avec les post-its pour voir l'avancement du travail"

A force de question et de discussion autour de Scrum avec l'équipe de développement, je me propose de leur faire une présentation de Scrum. C'est parti pour une présentation de 2h très conviviale. L'objectif est de faire découvrir les principes du framework. Rien de plus.

Réaction 5 : "C'est vraiment très différents, ça n'est pas du tout aujourd'hui notre façon de travailler, ça fait un peu peur"

Les semaines passent... et qu'est-ce que je vois sur le bureau du collègue à côté de moi, le livre "Scrum" de Claude Aubry. Je lui dis que c'est un super bouquin qu'il a bien fait de l'acheter.

Réaction 6 : "C'est ma compagne qui me l'a acheté car je lui avais parlé de la présentation que tu avais faite"

Alors là je suis scotché!

Les semaines passent... et un gros sujet à traiter par toute l'équipe nous tombe dessus. On ne sait pas par quel bout le prendre. Je propose aux membres de l'équipe qui connait le mieux le sujet de faire un mind map pour modéliser le travail à effectuer ainsi qu'une réunion tous ensemble où l'on ajuste le Mind Map pour tous obtenir une bonne vision de ce qu'on va devoir faire.  J'extrais ensuite le contenu du Mind Map dans un fichier Excel.

Réaction 7 : "C'est un peu comme un Backlog ce fichier Excel, non?"

Je l'ai ensuite renommé en "Backlog".

Réaction 8 : "Par quoi on commence?"

Je propose de refaire une réunion avec toute l'équipe pour qu'on priorise les sujets/tâches tous ensemble pour traiter les tâches les plus urgentes.

Réaction 9 : "On priorise tout, tout de suite?"

Je propose alors de faire un point tous ensemble toutes les semaines et de prioriser/reprioriser les sujets.

Réaction 10 : "On migre les applis existantes sur git"?

Yes!

Réaction 11 : "Comment on fait pour rajouter un Job dans Jenkins"?

Yes! Je te montre!

Les semaines passent... et je discute avec le directeur général. Il m'apprend qu'il s'est documenté sur Scrum et les méthodes Agiles qu'il trouve ça très intéressant et qu'il souhaite qu'on fasse des petites réunions tous les matins.

Aujourd'hui, nous ne pouvons pas dire que nous "faisons du Scrum" mais tous ce qui est mis en place nous aident réellement au quotidien. L'utilisation d'un backlog et la réalisation du Daily Scrum du matin sont maintenant une évidence. J'espère que cette démarche (non préméditée) de contamination va se poursuivre.

Alors que je pensais que Scrum ne pouvait fonctionner sur le principe du tout ou rien, je me rends compte que l'agilité progressive est un succès dans notre cas.

Vous en pensez quoi?