
L’agilité a fait son apparition en France depuis près de 10 ans. En tant que précurseur, Valtech a très vite adopté SCRUM sur ses projets onshores mais également offshores, et a développé une plateforme agile spécifique. Aujourd’hui, les choses ont changé et de nombreux clients comme Valtech en son temps, adoptent les pratiques agiles SCRUM et XP tout en consolidant leurs environnements de développement et de test pour une meilleure productivité des équipes.
A l’occasion d’un séminaire à Toulouse le 14 juin 2012, les experts de Valtech aborderont des sujets moins techniques du point de vue du développement, mais beaucoup plus sensibles du point de vue de l’organisation, de la difficulté d’adoption de nouvelles pratiques agiles (processus et outils) et du management habilité à décider de l’opportunité ou non d’adopter ces pratiques.
- Adoption de l’agilité et retour sur investissement
- Le pôle architecture dans un monde agile
- Une plateforme agile pour quoi faire ?
- Innovation Game : Gadget futile ou outil redoutable ?
Inscription & Accès :
- Lieu : Toulouse ( Le lieu sera communiqué prochainement )
- Date : 28 juin 2012
- Horaire : 09:00 – 12:30
- Inscription : via le site web
L’équipe de Valtech Toulouse sera heureuse de vous accueillir pour cette matinée d’échanges.
Récemment j’ai refait un peu de JPA/Hibernate et j’ai eu besoin de mapper une relation many-to-many qui nécessite de stocker une information supplémentaire. Pour être concret, j’ai un objet Recette, un objet Ingredient et je souhaite associer une recette à un ingrédient. Ce qui est particulier dans mon cas c’est que j’ai envie de d’enregistrer en plus la quantité de cet ingrédient qui est utilisé dans ma recette de cuisine.
Rien de bien extraordinaire jusque là et je me souvenais avoir déjà géré ce genre de cas. Oui mais voilà, après quelques recherches sur les forums je n’ai trouvé aucune solution clé en main qui ne nécessite pas de parcourir les dizaines de commentaires et de les tester un à un.
Voici la solution que j’ai retenue, je suis bien sur ouvert à toute proposition permettant d’améliorer mon code ! Je ne présenterai ici que les mappings, je vous propose de retrouver l’intégralité des cas d’utilisations sur mon github (avec les Tests Unitaires et surtout le debug hibernate pour voir les requêtes qui passent).
L’idée générale est de découper le many to many en deux relations many-to-one/one-to-many avec l’utilsation d’un objet d’association qui va porter l’information que l’on souhaite rajouter (ici la quantité).
NB: je me sers de lombok pour générer les getter, setter et equals/hashcode de mes classes.
La classe Recipe:
package fr.valtech.many2many.domain;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "recipe")
@EqualsAndHashCode(of = { "id", "title" }, callSuper = false)
public class Recipe extends AbstractEntity {
@Id
@Column(name = "recipe_id")
@GeneratedValue(strategy = GenerationType.AUTO)
@Getter
@Setter
private Integer id;
@Getter
@Setter
private String title;
@Getter
@Setter
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.recipe", cascade = CascadeType.ALL, orphanRemoval = true)
private Set ingredients = new HashSet();
public void addIngredient(RecipeIngredient i) {
i.setRecipe(this);
ingredients.add(i);
}
} |
La classe Ingredient:
package fr.valtech.many2many.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Entity
@EqualsAndHashCode(of = { "id", "label" }, callSuper = false)
public class Ingredient extends AbstractEntity {
@Id
@Column(name = "ingredient_id")
@GeneratedValue(strategy = GenerationType.AUTO)
@Getter
@Setter
private Integer id;
@Getter
@Setter
private String label;
} |
La classe RecipeIngredient qui fait l’association:
package fr.valtech.many2many.domain;
import java.io.Serializable;
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.persistence.Transient;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "recipe_ingredient")
@AssociationOverrides({
@AssociationOverride(name = "pk.recipe", joinColumns = @JoinColumn(name = "recipe_id", insertable = false, updatable = false)),
@AssociationOverride(name = "pk.ingredient", joinColumns = @JoinColumn(name = "ingredient_id", insertable = false, updatable = false)) })
@EqualsAndHashCode(of = { "pk", "amount" }, callSuper = false)
public class RecipeIngredient implements Serializable {
@Getter
@Setter
@Column(nullable = false)
private String amount;
@Getter
@Setter
@EmbeddedId
private RecipeIngredientId pk = new RecipeIngredientId();
@Transient
public Recipe getRecipe() {
return getPk().getRecipe();
}
public void setRecipe(Recipe recipe) {
getPk().setRecipe(recipe);
}
@Transient
public Ingredient getIngredient() {
return getPk().getIngredient();
}
public void setIngredient(Ingredient ingredient) {
getPk().setIngredient(ingredient);
}
public RecipeIngredient() {
}
public RecipeIngredient(Ingredient ingredient, String amount) {
setIngredient(ingredient);
this.amount = amount;
}
} |
Et enfin la composite primary key de la classe d’association:
package fr.valtech.many2many.domain;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Embeddable
@EqualsAndHashCode(of = { "recipe", "ingredient" }, callSuper = false)
public class RecipeIngredientId implements Serializable {
@Getter
@Setter
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Recipe recipe;
@Getter
@Setter
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Ingredient ingredient;
} |
Les “astuces” que j’ai mis un moment à comprendre sont:
- dans la classe RecipeIngredientId il faut absolument mettre les relations en LAZY pour éviter un stackOverFlow;
- dans la classe Recipe, la relation OneToMany doit absolument comporter le orphanRemoval = true, sinon la mise à jour et la suppression des RecipeIngredient se passent mal !
Bon tout n’est pas parfait et il faut gérer quelques trucs “à la main”.
Il faut nécessairement persister en base explicitement l’ingrédient que l’on veut utiliser dans une recette que l’on souhaite elle-même persister.
/**
* Parcourt l'ensemble des ingrédient pour voir si ils existe déjà en base ou non.
* @param recipe
*/
private void reatachIngredients(Recipe recipe) {
for (Iterator it = recipe.getRecipeIngredients()
.iterator(); it.hasNext();) {
RecipeIngredient ri = it.next();
Ingredient ingredient = ri.getIngredient();
if (ingredient.getId() != null && ingredient.getId() != 0) {
Ingredient reference = getEntityManager().getReference(
Ingredient.class, ingredient.getId());
ri.setIngredient(reference);
} else {
getEntityManager().persist(ingredient);
}
}
} |
Il faut écrire une requête JPQL pour récupérer la Recette dans son intégralité, si on veut par exemple la serialiser après (certaines relations avaient été mises en LAZY, notamment sur la PK).
Query q = getEntityManager().createQuery(
"select r from Recipe as r "
+ "left join fetch r.recipeIngredients as ri "
+ "left join fetch ri.pk as pk "
+ "left join fetch pk.ingredient "
+ "where r.id = :recipeId");
q.setParameter("recipeId", recipeId);
Recipe recipe = null;
try {
recipe = (Recipe) q.getSingleResult();
} catch (NoResultException nre) {
getLogger().info("no result found");
return null;
} |
Le code complet ici: https://github.com/jbcazaux/many2many
Publié le 1/03/2012, par Pierrick Revol dans Agile | 3 Commentaires
Le travail en équipes pluridisciplinaires qui prennent en charge un sujet et le traitent de bout en bout, en faisant intervenir plusieurs métiers (architecture, code, tests…), est l’un des points clés de l’Agile (et de Scrum).
Ce sujet est généralement mal compris et suscite beaucoup d’inquiétudes, pas toujours fondées.
Nous allons d’abord clarifier le vocabulaire utilisé, puis nous verrons comment fonctionne une équipe multicompétente, comment se construit cette qualité et nous tâcherons de répondre aux objections les plus couramment formulées avant de conclure en examinant l’intérêt que vous pourrez trouver à développer ce mode de fonctionnement.

Lire la suite »
Nous vous invitons pour un nouveau Valtech AfterWork consacré cette fois-ci à la transition vers l’agilité. Pour la première fois dans nos nouveaux locaux du 7ème arrondissement de Paris,
venez découvrir gratuitement comment réaliser avec succès la transition de vos équipes vers des méthodes de travail et une organisation qui apporte plus de satisfaction à vos clients.
Ce sont nos collègues Vincent Lebreil (Architecte & Consultant) et Jean-Claude Grosjean (Coach Agile & Spécialiste UX) de Valtech Technology qui vous présenterons le sujet.
Il faut juste vous inscrire au préalable pour participer à l’événement.
- Date : 13 octobre 2010
- Horaires : De 18h30 à 21h30
- Adresse : Valtech
103, rue de Grenelle
75007 PARIS
Nous organisons une demi-journée centrée sur des sujets techniques pour les consultants de Valtech Technology le jeudi 21 octobre prochain. Ce sera l’occasion de discuter des sujets les plus pointus en toute convivialité.
Le programme est constitué d’un peu de Cloud Computing mélangé à du NoSQL, des retours d’expériences de migration JavaEE vers le Cloud et .Net vers Azure avec nos collègues de Valtech Toulouse suivis d’ateliers sur la mobilité (workshop, coding en groupe, etc.).
On se régale déjà à l’idée de vous faire vivre ce rendez-vous par notre compte twitter. On ne manquera pas aussi de faire un billet plus détaillé sur la rencontre.
Consultez nos postes à pourvoir si vous souhaitez nous rejoindre !
Crédits photo: Tous droits réservés par valtech103grenelle
Je me suis rendu le 21 janvier à Itterswiller en Alsace pour la seconde édition de l’Agile Open France qui vaut vraiment la peine d’y assister et cela pour plusieurs raisons :
D’abord, le cadre et l’endroit choisi pour les 3 jours de l’évènement sont magnifiques : village d’Alsace isolé en plein milieu des vignobles sur la route des vins. Le coup d’œil le matin sur les vignes sous un soleil naissant depuis sa fenêtre de chambre vaut vraiment le coup.
Ensuite et c’est à mon sens le plus important, la qualité des personnes présentes issues de différents univers professionnel avec des expériences variées de mise en œuvre concrète de l’Agilité, etc. mais avec UN point commun, la volonté de partager la connaissance acquise et le fait de pouvoir bénéficier de points de vue des différents acteurs de l’Open Space sur les interrogations et problématiques rencontrées au quotidien.
Nous étions au total 23 personnes dont une forte présence de l’entité commerciale Orange Business Services (6 personnes) et de nos amis belges (3 personnes) qui vont organiser prochainement un Agile Open en Belgique.
Pour ma part, c’est la première fois que je me rends à ce type d’évènement avec comme thème fédérateur l’Agilité et je fus agréablement surpris au fil de la première journée malgré mes craintes du départ – N’avions-nous pas rigolé ensemble au bureau sur le fait que se réunir épisodiquement sur l’Agilité pouvait s’apparenter à l’appartenance à une secte ?
Il est vrai que le jeu de groupe organisé en début d’évènement, pour attendre les derniers retardataires, m’y a fait penser. Tous debout en cercle en train de crier à tour de rôle un dialecte composé de 3 mots barbares en accord avec le geste adéquat pour passage de témoin avec pour objectif d’éliminer un par un les participants dans le cas où le geste ne correspondait pas au mot prononcé.
En étant plus sérieux, il est vrai qu’un Open Space (ensemble de conférences auto-organisées par les participants) est reconnu comme étant une méthode efficace qui permet de tenir des réunions dynamiques et productives alliant une communication franche et ouverte.
Après un rappel des règles de base par les organisateurs (“les personnes qui sont là sont les bonnes personnes”, ”quand ça commence, c’est que c’est bon moment pour commencer”, “quand c’est fini, c’est fini”, etc.), la planification des sessions a pû débutée. Un premier constat, beaucoup de sujets ont été l’objet de problématiques rencontrées par les participants sur leurs projets au quotidien.
Personnellement, je me suis positionné sur plusieurs sujets portant essentiellement sur des problématiques d’organisation de projets Agile, par exemple :
L’autonomie du Product Owner vis-à-vis des tests d’acceptation. Il s’agissait principalement de tenter de résoudre le problème du non-engagement du Product Owner (pour l’occasion) à fournir (ou à faire faire) des tests d’acceptation avec pour objectif de soustraire l’équipe de production à ce genre d’activité.
A ce sujet, il a été mis en avant l’utilité de définir des cas de tests et jeux de données associés le plus en amont du processus de développement de par l’approche développement orienté par les exigences. L’approche Test-Driven Requirement a été explicitée à travers nos quelques retours d’expériences sur le sujet.
Le Business value game de Pascal Van Cauwenberghe . C’est un jeu très sympa et utile qui permet de simuler la réalisation et la mise en production de versions de produit d’un point de vue du Product Owner. C’est le genre de jeu indispensable pour des mises en situation lors de formation Scrum dédié au Product Owner ou équivalent. Pour expliquer rapidement le déroulement de la session, nous avions constitué 2 équipes de Product Owner afin de pouvoir, au final, comparer les stratégies adoptées de priorisation. Il s’agissait de planifier les itérations en fonction du niveau de satisfaction des clients finaux et du retour sur investissement attendu par le développement des user stories. Est-ce le fruit du hasard ? En optant pour des stratégies différentes, nous avons obtenu les mêmes résultats : niveau de satisfaction du client et retour sur investissement identiques pour les 2 équipes.
Les problèmes de maturité et de cohésion des équipes Scrum. Il s’agissait de répondre à une problématique d’un des participants au regard de l’organisation de son projet, du contexte multi-site et de la non stabilité permanente des équipes projet. Pour cela, une analyse causale a été menée avec des premières pistes d’amélioration en guise de plan d’action par les participants qui ont fait valoir leur expérience réciproque.
Autres sujets liés au Product Owner auxquels j’ai participé : Qui doit être Product Owner ? Comment gérer des versions d’une même User Story dans un Product Backlog et les différentes manières de le visualiser.
Pour conclure, un grand bravo aux organisateurs de l’Open Space que sont Bernard Notarianni, Emmanuel Gaillot, Luc Bizeul et Raphael Pierquin pour leur superbe idée de faire en sorte que des personnes envieuses d’apprendre et d’échanger sur une thématique commune puisse le faire.
C’est vraiment très agréable et enrichissant de pouvoir partager ses expériences projet avec d’autres praticiens Agiles ou en devenir, d’échanger des idées et de participer à des petits forums de discussions en mode communication directe.
Valtech Training recrute 5 formateurs. Les profils recherchés couvrent les domaines Java et Microsoft .Net. Selon les cas, l’expérience minimum demandée peut aller d’une année à plus de cinq selon les postes :
- Concepteur développeur junior sur .Net, un an d’expérience au moins
- Architecte logiciel sur .Net, quatre ans d’expérience minimum
- Concepteur développeur junior sur Java et les Frameworks Java, deux ans d’expérience au moins (deux postes à pouvoir)
- Architecte technique sur Java EE, quatre ans d’expérience minimum
Descriptifs complets des postes à pourvoir.