Quelques raisons d'utiliser MongoLink

Il y a presque deux ans maintenant je pense, nous avons commencé à nous mettre à utiliser mongodb dans certains de nos projets. Les raisons sont multiples, mais ce qui nous a particulièrement séduit, c'est :

  • une plus grande souplesse dans la manipulation de schéma (si on peut parler de schéma),
  • les documents sont bien plus proches de l'objet que ne l'est un SGBD,
  • l'atomicité se limite au document, et donc en modélisant un agrégat par collection, c'est assez proche d'une philosophie DDD

Ceci étant dit, MongoDB reste une base de données, et nous souhaitons toujours mettre le métier au cœur de nos préoccupations, en appliquant, entre autre, l'ignorance de la persistance. Il y a plusieurs manière bien sur d'obtenir ce résultat, mais l'approche mapper, avec ses défauts, a l'avantage normalement de simplifier la chose. À l'époque, il existait bien sur déjà en java quelques solutions, mais aucune ne respectait tous nos critères, et nous avons donc pris cette décision un peu folle de faire la notre : MongoLink

Pas d'annotation, pas de XML

Ah, voici bien quelque chose qui nous tenait à cœur : ne pas avoir à mélanger des responsabilités dans notre métier en plaçant des annotations de persistance partout, parfois prenant plus de place que le code lui-même. Nous ne voulions pas non plus de XML, ou même de n'importe quel autre type de fichier pour déclarer le mapping, pour limiter les résistances au refactoring. La solution restante était donc de déclarer le mapping en code, via une Fluent Interface. Fluent NHibernate a été une grosse source d'inspiration.

Voilà donc à quoi peut ressembler un mapping :

public class FruitMapping extends AggregateMap<Fruit> {

    public FruitMapping() {
        super(Fruit.class);
    }

    @Override
    public void map() {
        id(element().getId());
        property(element().getName());
        collection(element().getVarieties());
        subclass(new SubclassMap<Banana>(Banana.class) {

            @Override
            protected void map() {
                property(element().getSkin());
            }
        });

    }

}


Support du polymorphisme sur les objets valeurs

Voilà une fonctionnalité dont je rêve depuis des années. Combien de fois avec Hibernate j'ai du transformer un objet valeur en entité pour pouvoir gérer du polymorphisme, et du coup brouiller le métier, et complexifier le mapping ! Non avec mongolink, pas de soucis. Si vous voulez par exemple mapper un State, aucun problème :

public class StateMapping extends ComponentMap<State> {

    public StateMapping() {
        super(State.class);
    }

    @Override
    protected void map() {
        subclass(new SubclassMap<OpenState>(OpenState.class) {
            @Override
            protected void map() {

            }
        });
        subclass(new SubclassMap<CloseState>(CloseState.class) {
            @Override
            protected void map() {

            }
        });
        subclass(new SubclassMap<PendingState>(PendingState.class) {
            @Override
            protected void map() {

            }
        });
    }
}


Mise à jour automatique en émettant que les operators nécessaires

Qui dit ignorance de la persistance, dit ne pas avoir à explicitement pousser ses mises à jour vers la base de données. Pour supporter cette approche, tous les chargements dans MongoLink sont encapsulés dans une session, qui se chargera toute seule à la fin de déterminer les modifications qui ont été effectuées sur les objets chargés. Si vous avez utilisez Hibernate, rien de bien neuf pour vous, mais là ou ça devient plus délicat quand on parle de MongoDB, c'est qu'il vaut mieux exprimer ses mises à jour à l'aide de seulement les operators nécessaires.

Disons donc que vous avez le code suivant :

.
.
.
mongoSession.start();
MaClasse instance = mongoSession.get("monId", MaClasse.class);
instance.setUneValeur("une valeur");
mongoSession.stop();


La session va seulement émettre cette opération :

{ "$set" : { "uneValeur" : "une valeur"} }


Les classes de mapping sont cherchées par MongoLink

Une des frustrations que nous avions avec Hibernate, c'était de devoir tenir une liste dans la configuration de tous les fichiers de mapping. De plus, il n'est pas forcément facile à configurer. Nous voulions donc avoir une solution simple pour démarrer mongolink :

ContextBuilder builder = new ContextBuilder("org.mongolink.test.integrationMapping");
Settings settings = Settings.defaultInstance();
MongoSessionManager sessionManager = MongoSessionManager.create(builder, settings);
.
.
.
MongoSession mongoSession = sessionManager.createSession();


Conclusion

Bien, tout ceci était finalement une introduction rapide à la philosophie de MongoLink :

  • DDD et ignorance de la persistance
  • Mapping en code
  • Vrai support du polymorphisme des objets valeurs
  • Mises à jour efficaces
  • Simplicité de configuration

Je pourrais ajouter en vrac, le fait qu'il ne retourne pas de proxy, passe toujours par les fields pour les mises à jour pour ne pas nécessiter de setters; possède une api de recherche; fournit des outils pour faciliter les tests; mais il faut garder de la substance pour d'autres articles :)

J'espère que cela vous donnera envi de l'essayer, même si je vous l'accorde, il reste du travail pour le rendre plus grand public, et qu'il y aurait bien d'autres choses à dire.