Skip to content

Blogs de Développeurs: Aggrégateur de Blogs d'Informatique sur .NET, Java, PHP, Ruby, Agile, Gestion de Projet

Forum Logiciel

Forum Logiciel : diffusion de connaissance et d’informations sur toutes les activités liées au développement d’applications informatiques en entreprise.

Agrégateur de flux

How to pass the JIRA Administration certification exam

Le blog de Valiantys - jeu, 07/20/2017 - 14:00

Not sure what to expect for how to pass the ACP-JA JIRA Administration certification? As I recently passed the exam, I’d like to share with you a few key tips to help you prepare for the exam. Am I a good candidate? Atlassian recommends having at least two to three years of experience as a JIRA ...

The post How to pass the JIRA Administration certification exam appeared first on Valiantys - Atlassian Platinum Partner.

Catégories: Blog Société

La démarche RSE, phénomène de mode ou engagement réel ?

L'actualité de Synbioz - mer, 07/19/2017 - 23:00

Comme beaucoup de personnes, vous avez déjà dû entendre parler de la démarche RSE, peut-être la pratiquez-vous déjà… et si cela ne vous dit rien, alors nous allons pouvoir vous aider.

Lire la suite...

Catégories: Blog Société

Spring Framework 5 : tour d’horizon des nouveautés

Spring

 

Spring a sorti la première release candidate de la version 5 de son framework il y a un peu plus d’un mois.

A l’heure ou nous Ă©crivons cet article, la version 5 de Spring est disponible en RC2. Une RC3 est prĂ©vue pour courant juillet, peu de temps avant la version finale.

Nous vous proposons par conséquent de découvrir ensemble les nouveautés et améliorations apportées à Spring Framework 5.

Passage Ă  Java 8

Dans sa version 4, Spring était compatible avec Java 6. Avec la version 5, le code du framework a été réécrit en Java 8.

Les développeurs en ont donc profité pour :

  • AmĂ©liorer l’accès aux paramètres d’une mĂ©thode en utilisant les amĂ©liorations de la rĂ©flexivitĂ© de Java 8
  • Utiliser les mĂ©thodes par dĂ©faut des interfaces de Spring
  • Utiliser les classes Charset et StandardCharsets (disponible depuis le JDK 7)

Et dans une optique de compatibilité avec Java 9, l’instanciation des classes se fera désormais par Constructor#newInstance au lieu de Class#newInstance qui va devenir obsolète.

Spring WebFlux

Spring se met à la programmation réactive avec WebFlux dans sa version 5.

Concrètement, il s’agit de pouvoir implĂ©menter une application web (contrĂ´leur REST) ou des clients HTTP de manière rĂ©active. Pour ce faire, Spring 5 intègre dĂ©sormais Reactor et permet de manipuler les objets Mono (qui contient un objet) et Flux (qui peut contenir N objet(s)).

PlutĂ´t qu’un long discours, un peu de code :

ImplĂ©mentation d’un contrĂ´leur rĂ©active

Voici un exemple d’un contrĂ´leur qui expose une API rĂ©active.

@RestController
public class PersonController {

 private final PersonService service;

 public PersonController(PersonService service) {
  this.service = service;
 }

 @PostMapping("/person")
 Mono<Void> create(@RequestBody Publisher<Person> personStream) {
  return this.service.save(personStream).then();
 }

 @GetMapping("/person", produces = "text/event-stream")
 Flux<Person> list() {
  return this.service.findAll();
 }

 @GetMapping("/person/{id}")
 Mono<Person> findById(@PathVariable String id) {
  return this.service.findOne(id);
 }

Notez que la méthode list envoie des événements au consommateur du service. Ce paradigme est connu sous le nom server-sent events (SSE). Ces événements lancés par le serveur peuvent êtres consommés par des clients de différentes natures: client frontal en JavaScript, ou WebClient de Spring en Java.

Ci-dessous, l’implĂ©mentation d’un contrĂ´leur AngularJS permettant l’utilisation d’un service web utilisant SSE grâce Ă  l’interface EventSource :

var personModule = angular.module('persons', []);
personModule.controller('PersonsCtrl', function($scope, Persons) {
   
  $scope.init = function() {
    var source = new EventSource('/persons');
    source.onmessage = function(event) {
      $scope.$apply(function () {
        $scope.entries = JSON.parse(event.data)
      });
    };
  };
 
});

Consommer un service réactive avec Spring

Avec Spring 5, nous pouvons maintenant utiliser WebClient, une alternative non bloquante Ă  RestTemplate qui nous permet de consommer une API REST :

WebClient client = WebClient.create("http://localhost:8080");
Mono<Account> account = client.get()
  .url("/persons/{id}", 1L)
  .accept(APPLICATION_JSON)
  .exchange(request)
  .then(response -> response.bodyToMono(Account.class));

Et pour les tests d’intĂ©gration, grâce au module spring-test, il nous est possible de facilement tester nos API grâce au WebTestClient. Une caractĂ©ristique importante de la classe WebTestClient est qu’on peut tester les points d’accès exposĂ©s par un contrĂ´leur sans dĂ©marrer un serveur de servlets (Tomcat, Netty ou autre). Cette classe propose quelques mĂ©thodes permettant de lancer des assertions sur la rĂ©ponse reçue du serveur. Voici un exemple de code :

WebTestClient client = WebTestClient
        .bindToController(new PersonController())
        .build();

client.get().uri("/persons/42")
        .exchange()
        .expectStatus().isOk()
        .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
        .expectBody(Person.class).value().isEqualTo(new Person("John"));

Bien entendu, on peut aussi se connecter une URI comme d’habitude :

WebTestClient client = WebTestClient
        .bindToServer().baseUrl("http://localhost:8080")
        .build();

client.get()...

Support avec Kotlin 1.1+

Kotlin a le vent en poupe. Et avec Spring 5, il sera possible d’utiliser le framework avec le langage de JetBrains.

Ainsi, voici comment implémenter un contrôleur REST avec Kotlin :

{
    ("/blog" and accept(TEXT_HTML)).nest {
        GET("/", fooHandler::findAllView)
        GET("/{slug}", fooHandler::findOneView)
    }
    ("/api/blog" and accept(APPLICATION_JSON)).nest {
        GET("/", this@barHandler::findAll)
        GET("/{id}", this@barHandler::findOne)
    }
}

Améliorations pour les tests

Dans sa version 5, Spring sera entièrement compatible avec les extensions de JUnit 5, en proposant SpringExtension, qui reprendra les mêmes fonctionnalités du Spring TestContext Framework.

Nous aurons aussi le droit Ă  plusieurs nouvelles annotations :

  • @SpringJUnitConfig : Ă©quivalent Ă  @ExtendWith(SpringExtension.class) (de JUnit 5) et @ContextConfiguration
  • @SpringJUnitWebConfig : tout comme @SpringJUnitConfig, avec en plus @WebAppConfiguration

Pour davantage d’informations, n’hĂ©sitez pas Ă  consulter la release notes ainsi que la documentation de Spring Framework 5.

Des exemples d’utilisation de Spring 5 sont disponibles sur GitHub, que ce soit en Java et en Kotlin.

Catégories: Blog Société

LCC 173 - Fais tourner la Hash Table

Audrey, Guillaume et Emmanuel vous parlent de serverless, de sécurité, de calculs de disponibilité, de hash table et d’autres sujets tip top.

Enregistré le 13 juillet 2017

Téléchargement de l’épisode LesCastCodeurs-Episode–173.mp3

Comment faire un crowdcasting

News Langages

Java 9 et Jigsaw passent le JCP
No swan song for Java: 10 influencers weigh in on its reputation, rivals and adoption

Matériel

le simulateur d’ordinateur quantique d’Atos
Intel Skylake/Kabylake et le bug dans l’hyperthreading

Middleware

Les framework Java populaires selon Redmonk
Spring Cloud Function
Les nouveautés de JPA 2.2
Le guide de developpement asynchrone avec vert.x
AWS Lambda et Java
Elastic Stack 5.5.0
Des tests d’intégration avec Elastic

Web

Release de JHipster 4.6.1
Node.js security release

Infrastructure

La bataille sur NTP
Raters: la face cachée de l’IA ?
Les choses Ă  savoir quand on utilise Ansible
OVH et les sites webs critiques sur un VPS
Comment fonctionne Kerberos
Distroless Docker image avec rien dedans

Outillage

Blog sur JUnit 5
ˋgit filter-branch` expliqué à ta grand-mère

Architecture

Papier sur la disponibilité et les 9 par Google
L’intérêt des data stream dans les applications non monolithe
Serverless vs Micro-Service avec infrastructure “maison”
Gestion des logs chez Algolia

Sécurité

Two-factor via your mobile phone – should you stop using it?

Loi et société et organisation

La démission de Travis Kalanick, le CEO d’Uber
Mercredi 12 juillet - Journée d’action pour la neutralité du net aux USA

Rubrique débutants

Qu’est-ce qu’une Hash Table ?

Conférences

Jug Summer Camp le 15 Septembre Ă  La Rochelle
DevFest Toulouse le 28 septembre - Inscriptions et CfP ouvert
DevFest Nantes les 19 & 20 Octobre - Inscriptions
Scala.io le 2 et 3 novembre à Lyon - Inscriptions et CfP ouvert (jusqu’au 8 sept)
Devoxx Belgique du 6 au 10 novembre - Inscriptions
Codeurs en Seine à Rouen le 23 novembre - CfP ouvert (jusqu’au 31 août)
7ème édition de SoftShake - Genève (seulement 3h de Paris en train !) 26–27 octobre 2017 le CfP est ouvert

Nous contacter

Faire un crowdcast ou une crowdquestion
Contactez-nous via twitter https://twitter.com/lescastcodeurs
sur le groupe Google https://groups.google.com/group/lescastcodeurs
ou sur le site web https://lescastcodeurs.com/
Flattr-ez nous (dons) sur https://lescastcodeurs.com/
En savoir plus sur le sponsoring?

Catégories: Blog Individuel

ITSM basics: Problem or incident?

Le blog de Valiantys - jeu, 07/13/2017 - 16:32

Amongst the ITIL processes (incident, problem, service request, change), two of these processes collide: incident and problem. In the English dictionary the two words are technically synonyms, however in the IT world the confusion between the two concepts goes beyond mere semantics. Being able to properly determine the difference between an incident and a problem means ...

The post ITSM basics: Problem or incident? appeared first on Valiantys - Atlassian Platinum Partner.

Catégories: Blog Société

Revue de Presse Xebia

revue de presse Xebia
La revue de presse hebdomadaire des technologies Big Data, DevOps et Web, architectures Java et mobilité dans des environnements agiles, proposée par Xebia.

MobilitĂ© Vision Framework – Exemples & APIs http://www.gravatar.com/avatar/3f309c992e2b1a5c3c014e63810a2f68http://blog.xebia.fr/author/scivettahttp://twitter.com/viteinfinitehttp://github.com/viteinfinitePar Simone Civetta

Depuis l’annonce de Vision Framework lors de la dernière WWDC en juin, GitHub et Medium abondent d’exemples de mises en pratique. Si vous ne savez pas lequel choisir, ou si tout simplement vous voulez commencer avec une implĂ©mentation la plus minimaliste possible, voici un article et un repository qui, Ă  l’aide de quelque snippets, fournissent une vision d’ensemble efficace des principales fonctionnalitĂ©s et des APIs du framework. En particulier :

  • reconnaissance de QR Code
  • reconnaissance de visages
  • reconnaissance des « landmarks » d’un visage (bouche, yeux, nez,…)
  • reconnaissance de textes
  • suivi (tracking) d’objet
  • Vision + CoreML
Back Kafka propose de l’exactly-once-delivery ! http://www.gravatar.com/avatar/00ebd4762e0c123dd62894728ab6c94bhttp://blog.xebia.fr/author/achotardhttp://twitter.com/horgixhttp://github.com/horgixPar Alexis Horgix Chotard

Article en cours d’Ă©criture

Confluent vient d’annoncer le support du presque mythique « exactly-once-delivery » par Apache Kafka.

La problĂ©matique est simple Ă  prĂ©senter : garantir qu’un message sera dĂ©livrĂ© et traitĂ© une seule fois; pas 0, pas 2, pas 5; une… et ce mĂŞme en cas de problème (partition rĂ©seau, crash d’un composant).

En revanche, elle est bien moins simple Ă  rĂ©soudre et encore moins de manière performante ! C’est

  • Idempotence: Exactly-once in order semantics per partition. The producer send operation is now idempotent… written once on broker
  • Transactions: Atomic writes across multiple partitions

De manière plus gĂ©nĂ©rale, cet article est un excellent rĂ©sumĂ© des problĂ©matiques de livraison de messages, et a mĂŞme Ă©tĂ© applaudi par Wernel Vogels, le CTO d’Amazon.

Data Spark 2.2 : une petit pas pour le streaming, un grand pas pour le développeur http://blog.xebia.fr/author/slequeuxhttp://twitter.com/slequeuxPar Sylvain Lequeux

Ce mardi 11 juillet, Apache Spark 2.2 a été annoncé en release. Outre les ajouts de nouveaux algorithmes distribués (cette fois-ci majoritairement sur GraphX, MLLib et SparkR), une annonce forte est faite dans la release note.

Spark Structured Streaming est maintenant considĂ©rĂ© comme « production ready ». Ceci signifie que le tag « experimental » n’est maintenant plus prĂ©cisĂ© et que les Ă©quipes de dĂ©veloppement du framework considèrent le tout comme suffisamment mature pour ĂŞtre exploitĂ© par tous.

Catégories: Blog Société

Le choix d'un Ă©diteur wysiwyg

L'actualité de Synbioz - mer, 07/12/2017 - 23:00

Tout d’abord, une petite explication s’impose : Qu’est-ce qu’un éditeur wysiwyg ? Il faut savoir que wysiwyg est l’acronyme de what you see is what you get (Ce que vous voyez c’est ce que vous obtenez). Pour être plus clair, lorsque vous formaterez du texte dans cet éditeur (mise en gras par exemple), vous verrez directement le texte en gras, et non pas avec les balises qui le formatent.

Ici, je ne vais pas écrire un classement, pour la simple raison que comme beaucoup de choses tout dépend surtout de l’utilisation que vous aurez de l’outil. Ce n’est pas non plus (loin de là) une liste exhaustive des éditeurs existants. Il faut plutôt voir cet article comme un pense-bête de manière à pouvoir choisir rapidement, sans vous perdre dans la masse de l’existant pour trouver celui qui correspond le mieux à vos besoins.

Lire la suite...

Catégories: Blog Société

Sous quelles conditions utiliser les microservices ?

Les microservices attirent de plus en plus l’attention des architectes. Il s’agit d’un pattern architectural semblable au SOA (architecture orientĂ©e services), la diffĂ©rence Ă©tant que les microservices ont tendance Ă  valoriser des services plus restreints. Dans cet article, nous allons dĂ©couvrir ce qui se cache derrière ce terme. Introduction L’idĂ©e principale est de dĂ©couper une […]
Catégories: Blog Société

Kafka 0.11.0 == ♥

Blog d’Ippon Technologies - mar, 07/11/2017 - 09:55

Le 22 juin dernier Kafka sortait sa dernière version : la 0.11. Je vais revenir sur les nouveautés de cette version, car elle introduit des concepts très intéressants voire innovants pour un outil distribué comme Kafka !

PS : pour ceux n’ayant pas de background avec Kafka je vous conseille de regarder la vidéo suivante qui constitue une bonne introduction, quelques modifications ont néanmoins eu lieu avec la nouvelle version ! #AutoPub

Headers de message

Allez, on commence doucement avec cette première fonctionnalité. La possibilité d’ajouter des headers à un message Kafka. La spec provient de la KIP-82. Comment ça marche ? L’ajout de headers se fait via une modification du protocole d’envoi vers le broker Kafka ainsi que d’ajouts d’interfaces de manipulation de ces headers pour les clients (producer / consumer). On a donc maintenant un champ spécifique comme décrit ci-dessous :

Message =>

       Length => varint

       Attributes => int8

       TimestampDelta => varlong

       OffsetDelta => varint

       KeyLen => varint

       Key => data

       ValueLen => varint

       Value => data

       Headers => [Header] <------------ NEW Added Array of headers

Header =>

       Key => string (utf8) <- NEW UTF8 encoded string (uses varint length)

       Value => bytes  <- NEW header value as data (uses varint length)

C’est assez pratique pour passer des informations en plus de votre contenu pour une utilisation par le consommateur par exemple. Ce n’est pas très révolutionnaire car commun pour les queues de messaging. Mais c’est un ajout sympathique. Je suis personnellement intéressé par cette feature à des fins de tracing de requêtes asynchrones… Je dérive &#x1f642;

Exactly once

Bon maintenant, on rentre dans le vif du sujet. Cet article est un peu une excuse pour vous parler de la fonctionnalité phare de cette version : le support de la garantie de délivrance d’un message une fois exactement (ça rend pas bien en français donc je parlerai de “exactly once”).

Avant, il y a bien 1 semaine, “exactly once” ça semblait être de la fiction. De nombreuses personnes considéraient la fonctionnalité impossible dans un environnement distribué. En effet, c’est un des problèmes très complexes de garantir l’envoi unique d’un message dans un outil distribué. Illustrons cela :

J’envoie un message Ă  Kafka, le broker le reçoit, mais met trop de temps Ă  rĂ©pondre. Typiquement c’est le genre de panne que l’on peut attendre du rĂ©seau (CF “Fallacies_of_distributed_computing” ). Kafka prĂ©voyait le coup et permettait (via des options) d’envoyer des messages de retry lorsque l’ACK n’arrivait pas. Ainsi on pouvait choisir entre le fait d’avoir “at most once” si on ne rĂ©essaie  pas et “at least once” si on rĂ©essaie jusqu’à la rĂ©ussite. Pourquoi “at most once” me direz vous ? Et bien si on reçoit un timeout lors de l’ACK, simplement Ă  cause d’une lenteur rĂ©seau et que l’on a rĂ©ellement Ă©crit le message dans le commit log, le producer renvoie et Badaboum, un doublon.

Alors comment contournent-ils cela ?

Idempotence

Ça veut dire que si on envoie deux fois la mĂŞme chose via un producer, on a tout le temps le mĂŞme rĂ©sultat. Le producer va avoir un petit ID dans ses batchs de message permettant de les dĂ©doublonner. Tant que l’on n’a pas de rĂ©ponse de Kafka on renvoie et si Kafka reçoit des doublons il gère ! Pour l’activer rien de plus simple, il suffit de mettre le paramètre enable.idempotence=true. En plus de tout ça, les fameux IDs sont Ă©crits dans un log, du coup c’est rĂ©silient en cas de panne.

C’est beau.

Support des transactions

Ça y est, on rentre dans des choses intéressantes. Kafka, c’est un log distribué : OK ! On peut produire et lire des messages dans un topic donné (streaming ou non). Avant on produisait un message et on continuait nos traitements sans avoir de garantie, en cas de précédence entre nos messages, que tous seraient envoyés. Avec le support des transactions, on a maintenant une syntaxe proche des transactions de nos bases de données :

producer.initTransactions();
try {
  producer.beginTransaction();
  producer.send(record1);
  producer.send(record2);
  producer.commitTransaction();
} catch(ProducerFencedException e) {
  producer.close();
} catch(KafkaException e) {
  producer.abortTransaction();
}
kafka-transactions.java affichage brut

On a donc la possibilitĂ© d’effectuer des Ă©critures atomiques sur diffĂ©rentes partitions d’un topic donnĂ©. C’est plutĂ´t cool et cela apporte de nouveaux use-cases pour Kafka. Vous savez Kafka Streams fait typiquement du “read => transform => send”. Tu fais ça dans une transaction et tu as du streaming en exactly once ! Encore une fois une simple propriĂ©tĂ© permet d’assurer cette garantie : processing.guarantee=exactly-once.

Performances ?

Le support de la fonctionnalité n’est pas automatique. Du coup si vous ne l’utilisez pas, même avec l’ajout des headers, vous aurez de meilleures performances. Un travail a été effectué de ce côté-là notamment au niveau de la compression des messages Kafka sur le réseau et sur disque. Du coup, on parle quand même de 50% d’augmentation en termes de débit !

Et là vous vous demandez, “et pour le exactly once ?”. En fait il y a bien un overhead sur l’utilisation de la fonctionnalité. On parle d’environ 3% ou 20% pour l’utilisation du ”exactly once” (en comparaison de “at-least“ ou “at-most” respectivement). Mais pas besoin d’être triste, en fait le but avoué est de faire du “exactly once” la norme et donc de l’activer par défaut. C’est possible grâce au gain de performance des autres parties du protocole décrit plus haut ! Alors mangez-en !

Pour conclure : Idempotence + Transactions multi partitions = Exactly once pour tous les usages de Kafka = ♥

Pour une description complète des nouvelles features, des améliorations ou des bug corrigés, les releases-notes sont disponibles ici : http://www.mirrorservice.org/sites/ftp.apache.org/kafka/0.11.0.0/RELEASE_NOTES.html. Les articles de Confluent, dont je me suis grandement inspiré, rentrent bien plus dans le détail que moi concernant le exactly-once et peuvent être trouvés dans la KIP-98 (attention c’est long), dans un article de lancement de @nehanarkhede ou dans un blog de @jaykreps pour les septiques.

L’article Kafka 0.11.0 == ♥ est apparu en premier sur Le Blog d'Ippon Technologies.

Catégories: Blog Société

Agile France 2017

Barre Verte ! - lun, 07/10/2017 - 23:00
nomadopen.eu

La non-conférence Nomad Open devrait traverser en train des zones montagneusesMa plus grande découverte lors de l’open space du premier jour est Nomad Open, une non-conférence sur le travail nomade : le vivre et l’expérimenter en continuant son travail depuis un train qui traverse la France, l’Espagne et l’Italie.

Pour ceux qui seraient intéressés, les dates de cette première édition sont en cours de discussion, n’hésitez pas à envoyer un mail pour vous manifester.

J’ai moi-même vécu récemment une situation extra-professionnelle de nomadisme qui avait provoqué beaucoup d’incompréhensions et de malentendus :

  • Eux: pourquoi tu nous as pas rĂ©pondu sur facebook messenger ?

  • Moi: mon opĂ©rateur m’a coupĂ© l’accès quand j’ai passĂ© la frontière italienne, malgrĂ© l’option onĂ©reuse que j’avais souscrite dans le train pour maintenir la continuitĂ© du service.

  • Eux: pourtant tu rĂ©pondais Ă  certains moments.

  • Moi: c’est quand j’étais Ă  l’hĂ´tel, c’est le seul endroit dans Milan oĂą j’ai rĂ©ussis Ă  avoir du wifi.

Ce défaut de connectivité a fait s’envenimer la situation. Une situation qui ne devrait plus se reproduire puisque ce même 15 juin 2017 entrait en vigueur une directive qui a vu globalisé par l’Europe l’accès aux données/SMS/appels aux tarifs locaux.

beta.gouv.fr

Comment mettre en oeuvre l’auto-organisation dans une bulle hébergée au sein d’une bureaucratie ? C’est le défi que tentent de relever les membres de beta.gouv.fr, l’incubateur des startups d’état. Deux éléments qui m’ont marqués :

  • Trouver comment obtenir un badge est tellement difficile que la page wiki de l’incubateur a Ă©tĂ© utilisĂ©e par un nouvel arrivant d’une autre entitĂ© qui Ă©tait tombĂ© dessus par hasard. Une fois Ă©prouvĂ©e, la procĂ©dure a Ă©tĂ© automatisĂ©e dans un robot sur slack (il s’agit juste d’un mail a envoyer Ă  la bonne personne avec les bonnes informations)

  • La moitiĂ© des Ă©changes sur slack restent privĂ©s. L’orateur, Matti Schneider, indiquait que les membres s’auto-censurent en pensant que la conversation n’intĂ©ressera pas d’autres personnes. Il s’agit d’un filtrage Ă  priori alors que le filtrage devrait se faire Ă  posteriori pour Ă©viter de recrĂ©er une hiĂ©rarchie liĂ©e Ă  la dĂ©tention de certaines informations.

Usage des canaux privés et public chez beta.gouv.fr

Dans mon travail, l’utilisation de slack est massive et l’information échangée précieuse. Précieuse dans le sens où quand je rencontre un problème déjà évoqué, je me souviens que la réponse y a été donnée quelque part. Tout le problème est sur quel channel. J’ai rarement en tête des mots clefs suffisament discriminants pour une recherche globale (on parle d’une vingtaine d’équipes qui échangent sur slack depuis plusieurs années). A l’inverse si l’échange s’est déroulé en privé, je me souviens très bien avec qui et je retrouve très vite l’information. Je sais aussi que ces échanges privés sont perdus lorsque la personne quitte l’entreprise. Reste à trouver un équilibre. Il m’arrive parfois de recopier une réponse donnée en privé sur un channel publique ou dans Jira.

Une des choses que j’apprécie à Agile France se sont les conversations en marge des conférences : assit sur un banc pendant que Laurent Bossavit finalise la newsletter de beta.gouv.fr, je tente de m’y abonner sur mon mobile. L’expérience utilisateur s’y avère difficile :

  • j’ai toutes les peines du monde Ă  trouver le formulaire : il n’est rĂ©vĂ©lĂ© que quand je glisse mon doigt jusqu’à l’extrème limite de la page mais une animation le masque jusqu’au dernier moment. Laurent aurait aimĂ© filmer ma tĂŞte.

Je tente de trouver le formulaire pour m'abonner à la newletter Le formulaire pour s'abonner à la newletter est révélé en faisant disparaître le reste de la page

  • quand je clique pour indiquer mon adresse Ă©lectronique, le clavier masque le formulaire et je dois taper en aveugle.

Cela étant dit, le mobile-first serait difficilement justifiable puisque les accès par mobile ne représentent qu’un quart de leur traffic (j’ai appris à cette occasion que ces données étaient publiques) :

Part des terminaux mobiles dans le traffic 2017 de beta.gouv.fr

La pourriture du code

Arnaud Lemaire propose d’appeler pourriture du code la dette technique subie. J’aime cette idée car le terme de dette technique (qui reste pertinent quand elle est choisie) donne à penser que des stratégies de couverture sont possibles alors qu’on est plus proche d’une entropie. Les astres étaient très alignés en ce 15 Juin 2017 puisque le même jour était soutenue en Finlande une thèse sur la dette technique.

Une conférence qui s’installe dans la durée

En conclusion je mesure tout le chemin parcouru par cette conférence depuis sa toute première édition en 2006 où elle s’appelait XP Day France (je me souviens encore avec émotion avoir été en reconnaissance avec Patrice Petit pour évaluer l’Espace Hamelin dans lequel elle s’était tenue). La conférence est maintenant tellement connue qu’elle se tient à guichet fermé sans que les organisateurs aient besoin de communiquer. Bien qu’étant devenue non marchande elle est aussi bénéficiaire tout en gardant un tarif relativement bas.

Catégories: Blog Individuel

DĂ©veloppement Agile et Craft

développement agile

Vous ĂŞtes dĂ©veloppeur mobile pour un journal d’information bien connu. Les articles paraissent sur un site web et l’application Android correspondante est utilisĂ©e par des centaines de milliers d’utilisateurs. Elle permet de rĂ©agir sur les articles, et les utilisateurs ne s’en privent pas : c’est le théâtre de dĂ©bats d’un haut niveau Ă©motionnel, si ce n’est orthographique.

Mais un matin, aucune rĂ©action postĂ©e depuis l’application ne paraĂ®t plus sur le site. Les avis dĂ©favorables s’accumulent sur le Play Store :

Impossible de rĂ©agir depuis l’application. Aucune rĂ©action envoyĂ©e depuis l’application ne parvient aux modĂ©rateurs, alors que les rĂ©actions envoyĂ©es depuis le site passent sans problème. –RaphaĂ«l H.

Je suis abonnĂ© mais aucun des messages que je dĂ©pose avec mon smartphone ne s’affiche lorsque je commente l’actualitĂ©… –Michel K.

[…] Censure des commentaires n’allant pas dans le sens des articles, je me suis donc dĂ©sabonnĂ©… […] –Adrien V.

Cette situation demande d’agir vite et bien. C’est l’occasion d’illustrer une approche de dĂ©veloppement qui mĂŞle agilitĂ© et savoir-faire (craftsmanship).

Voici le comportement de l’application en matière de commentaires :

  • L’application permet de poster un commentaire en rĂ©action Ă  l’article lui-mĂŞme (indicateur response à false)
  • Elle permet de rĂ©pondre au commentaire d’un autre utilisateur (indicateur response à true)

Avant de vous distraire de votre tâche en cours, votre leader technique a pris le temps d’analyser l’anomalie : l’application ne poste pas les commentaires correctement. Le mapping entre l’indicateur response et la valeur envoyĂ©e Ă  l’API est incorrect. C’est un « if » qui a Ă©tĂ© codĂ© Ă  l’envers.

Le code en question rĂ©vèle l’erreur de mapping concernant la valeur du paramètre responseFlag attendu par l’API.

sendReaction(message, item, response);
public void sendReaction(String message, String answeredItem, boolean response) {
 
    int responseFlag;
    if (response) responseFlag = 0;
    else responseFlag = 1;
                    
    api.postReaction(message, answeredItem, responseFlag);
}
Agilité

Compte tenu de l’importance du bug, vous mettez de cĂ´tĂ© vos dĂ©veloppements en cours. Vous committez vos changements et vous passez sur une nouvelle branche issue de la version de production.

Votre premier rĂ©flexe est d’ouvrir le test unitaire (TU) du code en question. Qui n’existe pas. Damned. Le bug aurait pu ĂŞtre repĂ©rĂ© si un test avait Ă©tĂ© rĂ©digĂ© lors du dĂ©veloppement initial.

Le code est dans une Activity Android. Vous Ă©valuez l’investissement que constitue la rĂ©daction d’un nouveau test unitaire dans cette situation, et vous prĂ©fĂ©rez laisser le TU de cĂ´tĂ© le temps de produire un correctif dĂ©montrable afin de rassurer votre client.

Vous appliquez le correctif qui consiste Ă  inverser les branches du if. Dans l’immĂ©diat, vous privilĂ©giez la correction du bug par rapport au refactoring.

public void sendReaction(String message, String answeredItem, boolean response) {
 
    int responseFlag;
    if (response) responseFlag = 1;
    else responseFlag = 0;
                    
    api.postReaction(message, answeredItem, responseFlag);
}

Vous testez le correctif sur votre poste de dĂ©veloppement, puis vous publiez le code sur une branche du dĂ©pĂ´t de votre organisation. Le leader technique valide vos changements, vous faites le merge dans la branche d’intĂ©gration.

Votre serveur d’intĂ©gration continue met automatiquement Ă  disposition du reste de l’Ă©quipe une version de recette. Votre Ă©quipe pratique le dogfooding : c’est quand les membres de l’Ă©quipe sont les premiers utilisateurs de leur propre application. Cette pratique permet de confirmer l’absence de rĂ©gression dans des conditions rĂ©elles d’utilisation. Vous montrez le correctif Ă  votre client qui confirme la correction.

Craftsmanship

Et maintenant ? Le processus minimal est respectĂ©, du point de vue de votre client, vous pourriez donc livrer une nouvelle version hotfix de votre application et passer au ticket suivant, mais votre travail n’est pas terminĂ©. Dans la mĂ©thode sendReaction, au moins un refactoring vous dĂ©mange. Et votre beau correctif n’est toujours pas testĂ© unitairement.

Compte tenu de la simplicité du correctif, vous pouvez tout reprendre du début.

Vous commencez par écrire un test automatisé. Ici, le plus approprié est un test unitaire qui vérifie la logique du if.

Mais avant de pouvoir écrire ce test unitaire, le code doit être repensé. La classe impactée par le correctif est fortement couplée avec le framework Android qui est difficile à simuler dans un test unitaire. Vous avez deux solutions :

  • Mettre en place le framework Robolectric pour simuler le framework Android dans votre TU
  • Appliquer le pattern Passive View pour sortir la logique du if dans une classe sĂ©parĂ©e, qui serait testable facilement car non dĂ©pendante du framework

Vous choisissez la Passive View car vous pensez que Robolectric ralentirait l’exĂ©cution de vos tests, et Ă  cause du dĂ©lai des mises Ă  jour de Robolectric suite Ă  celles du SDK Android.

Dès que le test passe, vous en profitez pour transformer le paramètre response en enum, petit refactoring qui vous démangeait :

public void sendReaction(String message, String answeredItem, CommentType commentType) {
 
    api.postReaction(message, answeredItem, commentType.getApiFlag());
} 
enum CommentType {

    INITIAL("0"), ANSWER("1");

    private String mApiFlag;

    CommentType(final String apiFlag) {
        mApiFlag = apiFlag;
    }

    public String getApiFlag() {
        return mApiFlag;
    }
}

Vous adaptez votre test unitaire au changement de signature de la méthode sendReaction().

Ensuite vous faites en sorte que votre développement puisse être repris et maintenu facilement par un autre développeur, grâce à une séance de revue de code. En support écrit, vous préparez une pull request détaillée sur GitHub dont la description rappelle :

Le besoin fonctionnel Correction d’un bug au niveau des rĂ©actions La spĂ©cification technique
  • Extraction de la logique dans une classe dĂ©couplĂ©e
  • Inversion du sens du if
Le scénario de test
  1. Brancher l’application sur un environnement de recette
  2. Poster un commentaire sur un article
  3. Poster une réaction à un autre commentaire
  4. Observer qu’ils sont bien reçus par le backend et que leur type est correct

Ce niveau de détail par écrit permet de garder une documentation écrite et indexée au sujet du correctif au cas où un autre besoin impacterait ce périmètre de code.

NB : l’idĂ©al serait d’intĂ©grer la documentation au code afin de la rendre plus « vivante » et pour qu’elle puisse Ă©voluer avec le code. Mais ce type d’approche est coĂ»teux Ă  mettre en place sur du code existant ; vous laissez donc de cĂ´tĂ© ce chantier pour l’instant.

Quelques heures plus tard, la version corrigĂ©e est publiĂ©e sur le Play Store, certains utilisateurs l’ont installĂ©e, et les premières rĂ©actions des utilisateurs arrivent sur les articles. Vous retrouvez enfin leur douce prose, les trolls, la crĂ©ativitĂ© orthographique.

Conclusion

Ă€ partir d’une situation vĂ©cue, dans le contexte du dĂ©veloppement mobile, cet article illustre l’application des valeurs agiles et craft.

Dans le contexte d’un bug sensible, cette approche s’appuie sur les valeurs agiles pour prendre en compte les attentes du client en termes de rapiditĂ© de mise au point d’un correctif.

Elle s’appuie aussi sur les valeurs craft pour permettre Ă  la base de code de rester saine et comprĂ©hensible par les autres dĂ©veloppeurs, prĂ©sents et futurs.

Références
Catégories: Blog Société

[Tribune] Money2020 Europe, ou le réveil des banques européennes

La conférence Money2020 Europe s’est tenue à Copenhague fin juin. Cet événement, arrivé l’année dernière des Etats-Unis, se présente comme le plus grand rendez-vous européen de l’innovation dans les services financiers. La keynote d’ouverture a donné la parole aux CEOs de trois grands acteurs bancaires européens qui ont détaillé leur vision des transformations en cours dans ce secteur. Compte rendu de ces discours qui pourraient inspirer les dirigeants français.

Retrouvez la suite de notre tribune sur Maddyness.com >

Articles suggested :

  1. Suivez la série OCTO Technology « La banque de demain »: quelles évolutions pour le modèle bancaire ?
  2. FinTech – Hugues Le Bret : « Nous sommes une entreprise technologique qui offre Ă  tous les moyens de se faire payer et de payer en temps rĂ©el »
  3. Faut-il être schizophrène pour Innover dans un grand groupe et en particulier dans les banques ?

Catégories: Blog Société

[Tribune] Money2020 Europe, ou le réveil des banques européennes

La conférence Money2020 Europe s’est tenue à Copenhague fin juin. Cet événement, arrivé l’année dernière des Etats-Unis, se présente comme le plus grand rendez-vous européen de l’innovation dans les services financiers. La keynote d’ouverture a donné la parole aux CEOs de trois grands acteurs bancaires européens qui ont détaillé leur vision des transformations en cours dans ce secteur. Compte rendu de ces discours qui pourraient inspirer les dirigeants français.

Retrouvez la suite de notre tribune sur Maddyness.com >

Articles suggested :

  1. Suivez la série OCTO Technology « La banque de demain »: quelles évolutions pour le modèle bancaire ?
  2. FinTech – Hugues Le Bret : « Nous sommes une entreprise technologique qui offre Ă  tous les moyens de se faire payer et de payer en temps rĂ©el »
  3. Faut-il être schizophrène pour Innover dans un grand groupe et en particulier dans les banques ?

Catégories: Blog Société

Jenkins Community Day 2017 : le plus grand rassemblement autour de Jenkins en France le 11 juillet

A Duchess Community Blog for France - lun, 07/10/2017 - 06:36

Pour la première fois en France, le Jenkins Community Day aura lieu à la Grande Crypte à Paris, le 11 juillet prochain.

La conférence sera articulé sous la forme d’une journée entière avec une seule « track ». Vous aurez l’occasion de rencontrer les meilleurs experts Jenkins, des leaders de la communauté CI/CD et des éditeurs à la pointe proposant des technologies complémentaires à Jenkins afin d’en apprendre plus sur les dernières nouveautés et leur poser vos questions surtout qu’une session dédiée questions et réponses sera organisée en fin de journée avec les différents speakers.

Les orateurs sont:

Cet article Jenkins Community Day 2017 : le plus grand rassemblement autour de Jenkins en France le 11 juillet est apparu en premier sur Duchess France.

Catégories: Association

Valiantys’ ShipIt 2017: a day of innovation

Le blog de Valiantys - jeu, 07/06/2017 - 14:00

At some point you probably have wanted to take the time to develop a project which you are passionate about. You may even have a really good idea that you think will be interesting for your company and has a direct link to making you better at your current role. Once a year at Valiantys, ...

The post Valiantys’ ShipIt 2017: a day of innovation appeared first on Valiantys - Atlassian Platinum Partner.

Catégories: Blog Société

Versionning d’API, Zero Downtime Deployment et migration SQL : théorie et cas pratique

Pour démythifier le Zero Downtime Deployment

Dans les patterns associés aux géants du web, le Zero Downtime Deployment (ZDD) partage une caractéristique avec l’auto-scaling : on en parle d’autant plus qu’ils sont peu mis en œuvre.

Le ZDD est victime d’un cercle vicieux : il a l’air très complexe car il est peu pratiqué, et comme il est peu pratiqué, on pense qu’il est très complexe.

Pour sortir de cette impasse, cet article présente un cas pratique, code à l’appui.

L’objectif n’est pas que tout le monde fasse du ZDD, car on verra qu’il ajoute du travail et de la complexité, mais que vous vous en ayez une vision claire. Cela vous permettra de pouvoir décider d’en faire ou pas en connaissance de cause.

Notre cas d’exemple

Notre exemple s’approche de celui décrit dans le premier article.

Soit une application exposée via une API REST.

Au départ cette application gère des personnes, chaque personne ayant zéro ou une adresse. Cette version est exposée sur le préfixe /v1 à l’aide d’un unique type de ressource /person.

La version suivante de l’application permettra d’associer plusieurs adresses à une personne, et sera exposée sur le préfixe /v2 en utilisant deux ressources, /person et /address.

Les deux versions

Cette application met en avant sa haute disponibilité, il est donc primordial que toutes les opérations soient effectuées sans interruption de service.

L’API est publique, nous ne maîtrisons donc pas l’utilisation qui en est faite. Il est donc impossible de faire une bascule de /v1 à /v2 en une seule fois. Les deux versions devront donc fonctionner ensemble le temps de permettre la migration de tous les utilisateurs. Cette période pouvant être très longue suivant les cas.

Les clients consomment les API via des intermédiaires, il est donc possible que pendant cette période ils utilisent à la fois les versions /v1 et /v2.

Dans la suite de l’article, /v1 et /v2 correspondent aux versions des services, et v1 et v2 correspondent aux deux manières dont les données seront stockées en base.

La stratégie Comment gérer la migration ?

Il est possible de se passer complètement de script de migration au sens traditionnel : vous exposez les services en /v2, et, lorsqu’ils sont appelés pour une donnée encore au format /v1, vous migrez la donnée à la volée. Cela permet de migrer les données petit à petit au fur et à mesure que les utilisateurs des services appelleront les APIs /v2. C’est l’approche qui est souvent prise avec les bases de données NoSQL.

Malheureusement, en procédant ainsi, il est possible que la migration ne se termine jamais, ou alors seulement dans très longtemps (si vous purgez les données trop anciennes). Pendant ce temps, vous devez maintenir le code supplémentaire permettant de prendre en charge ce cas.

L’autre approche est d’utiliser un script. Cela permet de faire en sorte que la migration se fasse rapidement. C’est le même type de script que vous utilisez pour vos migrations habituelles, sauf qu’il doit prendre en compte le fait qu’il s’exécute en même temps que le code. Ainsi toutes les opérations qui créent des verrous pendant plus de quelques millisecondes ne doivent pas être utilisées, et il faut s’assurer de ne pas créer d’interblocage.

La migration doit se faire de manière transactionnelle, pour éviter d’introduire des incohérences dans les données. En cas de problème, le script doit également pouvoir être interrompu et relancé sans que cela ne perturbe l’exécution du programme.

Dans l’article c’est cette approche que nous allons utiliser.

Quand migrer ?

Sans ZDD, le process de migration est classiquement le suivant :

  1. Fermer le service
  2. Arrêter l’application
  3. Faire un backup des données, pour pouvoir les restaurer en cas de problème
  4. Migrer les données
  5. Déployer la nouvelle version de l’application
  6. Démarrer la nouvelle version de l’application
  7. VĂ©rifier que tout fonctionne bien
  8. Ouvrir le service

En ZDD, plus question de fermer le service : la migration de données a lieu « à chaud ».

Il y a deux manières possibles de s’y prendre, suivant que la migration a lieu avant ou après l’ouverture des services /v2 :

Les deux manières de migrer

Numéro de l’étape Version du code Migration après l’ouverture de /v2 Migration avant l’ouverture de /v2

1

1

Application servant /v1 avec un modèle de de donnée v1

2

1

Modifier le schéma de BDD pour permettre de stocker les données nécessaires à /v2

3

2

Déployer une nouvelle version de l’application exposant /v1 et /v2 sur les modèles de donnée v1 ou v2

Déployer une nouvelle version de l’application exposant /v1 sur les modèles de donnée v1 ou v2

4

2

Migrer les données au modèle v2 sans interruption de service, en tenant compte du code /v1 et /v2

Migrer les données au modèle v2 sans interruption de service, en tenant compte du code qui sert /v1

5

3

Déployer une nouvelle version de l’application exposant /v1 et /v2 sur le modèle de donnée v2

6

3

Nettoyer le schéma de BDD des artefacts v1

7

4

Déployer une nouvelle version de l’application gérant /v2 sur le modèle de donnée v2

La première approche permet d’ouvrir les services /v2 plus rapidement car il n’y a pas besoin d’attendre la migration des données.

La seconde approche est plus simple :

  • la version exposant de l’application fonctionnant avec les modèles de donnĂ©es v1 et v2 n’expose que les services /v1, vous faites ainsi l’économie du cas oĂą un appel de service /v2 accède Ă  des donnĂ©es v1 ;
  • pendant la migration de donnĂ©es, les services /v2 ne sont pas encore exposĂ©s, cela veut dire moins de patterns d’accès aux donnĂ©es Ă  prendre en compte pour dĂ©signer une migration Ă©vitant les incohĂ©rences de donnĂ©es et les interblocages.

Sauf si votre process de migration est extrêmement long, la seconde approche est à privilégier, et c’est celle qui sera utilisée dans la suite de l’article.

/v1 et /v2 sont dans un bateau …

Les migrations d’APIs ouvertes posent deux problèmes métier et un problème technique.

Comment migrer les données ?

Le premier problème, valable aussi pour les API fermées, est de savoir comment migrer les données de /v1 à /v2. Je ne parle pas d’un point de vue technique mais bien d’un point de vue métier : la sémantique change entre les deux versions, il faut donc déterminer comment transformer les données de /v1 en /v2 d’une manière qui soit logique et qui ne surprenne pas les utilisateur·rice·s de l’API.

Dans notre cas la solution est immédiate : /v1 a au plus une seule adresse, et /v2 peut en avoir plusieurs, l’adresse de /v1 devient donc une des adresses de /v2.

Comment gérer la rétro-compatibilité ?

L’autre problème est de savoir comment interpréter en /v1 des données /v2. En effet si l’API est ouverte, vos utilisateur·rice·s peuvent appeler vos services /v1 alors que les données sont déjà au modèle /v2.

Il est souvent plus compliqué que le premier car au fur et à mesure des évolutions, les API ont tendance à devenir plus riches. Accéder à des données plus riches de la /v2 au travers du prisme plus étroit de l’API /v1 peut être un vrai casse-tête.

Si c’est le seul moyen que cette transition se passe bien, il est parfois nécessaire d’adapter le design de l’API /v2.

C’est un équilibre à trouver entre la facilité de transition, des restrictions possibles à ajouter pour les appelants de l’API, et le temps à investir.

Comment répondre vite et bien ?

Le problème technique est de parvenir à rendre les différents services, y compris la compatibilité, tout en s’assurant de toujours avoir des données cohérentes et sans (trop) pénaliser les performances. Si, entre les deux versions, les données ne sont plus structurées de la même manière, la gestion de la compatibilité peut demander de croiser les données de plusieurs tables.

Ainsi dans notre exemple, en v1 les adresses sont stockées dans la table person alors qu’en v2 elles sont dans une table address séparée. Pendant la période de compatibilité, il faut que les appels à v1 qui mettent à jour le nom de la personne et son adresse modifient les deux tables de manière transactionnelle pour éviter qu’une lecture v1 qui se produirait au même moment ne renvoie des données incohérentes. De plus, il faut parvenir à le faire sans avoir à poser trop de verrous en base de données, car cela raletit les accès.

La meilleure stratégie est de privilégier une approche que vous maîtrisez bien et qui donne des résultats acceptables plutôt qu’une solution plus efficace ou plus rapide mais plus complexe.

Dans tous les cas, des tests sont absolument essentiels.

Pour servir les deux versions de l’API, vous pouvez utiliser une application unique ou choisir de séparer votre code en deux applications, une par version de services. Cette question n’étant pas structurante pour la question du ZDD, nous choisissons de ne pas la traiter ici. Dans notre exemple, nous avons choisi de n’avoir qu’une seule application.

… et ZDD les rejoint à bord

Sans ZDD la situation est claire : on arrête l’application, les données sont migrées, et on redémarre l’application dans la nouvelle version. Il y a donc un avant et un après.

Avec ZDD la migration s’effectue à chaud pendant que les services sont disponibles, s’ajoute une situation intermédiaire.

Pendant cette période, les données peuvent donc être encore stockées au format /v1 ou migrées au format /v2.

Il faut alors parvenir à déterminer dans quel état sont les données : pour savoir quel code doit être appelé il faut savoir si la donnée a été migrée ou pas. De plus, le morceau de code en charge de cela va être exécuté très souvent, il doit donc être très efficace.

En cas de difficulté, la solution qui devrait fonctionner dans tous les cas est d’ajouter dans les tables impliquées un numéro indiquant la « version de schéma » de la donnée correspondante, et qui sera incrémenté lors de la migration de la donnée. Dans ce cas l’opération de vérification est très simple et rapide. L’opération d’ajout de colonne est alors à faire en avance de phase, ce qui augmente le travail nécessaire à la migration.

Si vous choisissez de faire la migration de données après l’ouverture de /v2, s’ajoute le cas où on appelle une api /v2 alors que la donnée est encore stockée au format v1. Il faut alors migrer la donnée à chaud, de manière transactionnelle en limitant les ralentissements induits.

Pour résumer, il y a quatre situations :

Appel /v1 Appel /v2

Données stockées au format v1

RĂ©pondre comme auparavant

(Seulement si migration après ouverture de /v2) Migrer les données à chaud

Données stockées au format v2

Compatibilité v1

Répondre avec la nouvelle sémantique

Bien ouvrir /v2, et bien décomissionner /v1

Lorsque vous ouvrez /v2 pour la première fois, faites-attention à la manière dont la bascule vers la nouvelle version est faite.

Avant de rendre les nouveaux endpoints accessibles, assurez-vous que tous les serveurs utilisent la dernière version de l’application. Dans le cas contraire, si vous appelez un /v1 alors que la donnée correspondante a été migrée en v2 le code ne saura pas la lire correctement et risque de planter ou de renvoyer une information fausse.

Un autre problème se pose suivant la manière dont vous avez implémenté les modifications de donnée lorsque vous appelez une API /v1.

Le premier cas consiste à sauvegarder la donnée au format v2, mais cela veut dire qu’à nouveau, les versions précédentes de l’application ne pourront pas la lire. La solution la plus simple est alors d’utiliser le feature flipping pour faire basculer le code.

Dans le cas contraire, votre code doit détecter sous quel format la donnée est stockée, et la resauvegarder sous ce même format : une donnée v1 reste en v1, et une donnée v2 reste en v2.
On Ă©vite le feature flipping, mais en Ă©change le code est plus complexe.

Pour décomissionner /v1 il suffit de rendre les endpoints inaccessibles, la suppression du code peut se faire plus tard.

À propos des verrous et des modifications de schémas

Comme on vient de le voir, le ZDD s’appuie beaucoup sur l’utilisation de la base de données, et notamment ses fonctionnalités d’accès concurrent. Si vos comportements métiers sont simples, que vous utilisez un ORM, et que vous avez des tests de performances automatisés, il s’agit d’un domaine auquel vous n’avez pas souvent à vous intéresser. Si vous vous y prenez mal, il est facile de bloquer la base, renvoyer des erreurs (en cas d’interblocage), ou des résultats incohérents.

Notre conseil est de bien vous documenter en amont voire de faire des POC pour éviter d’avoir à refaire un design parce que votre base de données ne fonctionne pas comme vous l’imaginiez. Ne faites pas confiance à des souvenirs ou à des rumeurs : lisez en détail la documentation correspondant à la version de l’outil que vous utilisez, et surtout testez !

Si vous n’avez jamais creusé ces sujets ou que vous êtes rouillé·e, la première migration vous demandera sûrement pas mal de travail, et vous donnera quelques sueurs froides lorsque vous l’exécuterez. Mais dites-vous que toutes les opérations suivantes manipuleront les mêmes concepts, et se passeront donc beaucoup mieux.

Il n’y a pas que le REST dans la vie

REST possède deux caractéristiques qui en font un candidat idéal pour le ZDD :

  • exposer plusieurs versions de services est une pratique standard ;
  • les appels sont supposĂ©s ĂŞtre sans Ă©tat.

Si vos services sont exposés d’une autre manière, il faudra donc vous intéresser à ces sujets. Les sessions, comme tous les types de cache, peuvent demander une attention particulière si les données qu’elles contiennent font l’objet d’un changement de structure entre versions.

Retour Ă  notre exemple

Nous prenons l’hypothèse où le modèle de données suit directement les ressources à exposer. L’adresse est initialement un champ de la table person, et est migrée dans une table address distincte.

L’évolution du schéma

Nous n’utilisons pas de colonne spécifique pour stocker la « version de schéma » des objet. À la place nous allons vérifier en base la manière dont les données sont stockées : si la table person contient une adresse, c’est qu’elle est en version v1, sinon il faut vérifier l’existence d’une adresse dans la table dédiée. Cela évite d’alourdir le schéma SQL, mais augmente le nombre de requêtes exécutées.

Les Ă©tapes Ă  suivre pour la migration :

  1. Version initiale : l’adresse est dans la colonne address de la table person, le code ne sait fonctionner que de cette manière.
  2. Ajout de la nouvelle table address dans la base de données, à cette étape le code ne connaît pas encore cette table.
  3. Déploiement du code qui fournit l’api /v1 et qui est compatible avec les deux manières de stocker l’adresse.
  4. Exécution du script de migration.
  5. Déploiement du code qui fournit les api /v1 et /v2 et qui est compatible avec la nouvelle manière de stocker l’adresse, la colonne address de la table person n’est plus utilisée par le code.
  6. Suppression de la colonne address de la table person.

Le ZDD a pour conséquence d’ajouter des versions de code et des migrations de schémas intermédiaires. Dans un environnement où les déploiements ne sont pas automatisés, cela signifie une augmentation de la charge de travail et donc du risque d’erreur. Mieux vaut donc s’outiller et disposer d’un pipeline de livraison fiable avant de se lancer.

Analyse détaillée La compatibilité des services

Dans notre exemple le problème de compatibilité est le suivant : une fois une personne migrée, elle peut avoir plusieurs adresses. Que faire quand on récupère cette même personne en passant par l’API /v1 ?

Ici il n’y a pas de réponse évidente : il n’y a pas de notion d’adresse préférée, ou de dernière adresse utilisée qui fournirait une manière de discriminer les différentes possibilités. Comme la réponse influe sur le comportement de l’API, c’est une décision à prendre par les personnes du métier.

La solution choisie ici est de renvoyer une adresse parmi celle dans la liste. Elle n’est pas parfaite, mais elle peut être acceptable suivant l’usage qui en est fait : il revient aux personnes du métier d’en décider.

La transactionnalité

Pour résoudre la question de transactionnalité, nous avons choisi la solution la plus simple : poser un verrou sur les entrées correspondantes de la table person.

Si toutes les opérations suivent le même principe, ce verrou joue le rôle d’une mutex en s’assurant que les appels s’exécutent bien l’un après l’autre : lorsqu’une opération pose un risque, elle commence par demander l’accès à ce verrou, et pour cela elle doit attendre son tour.

Exemple avec un appel à PUT /v1/people/127 alors que la personne correspondante est stockée au format v2 mais n’a pas encore d’adresse.

Exemple sans verrou :

Fil d’exécution 1 Fil d’exécution 2

PUT /v1/people/127/addresses

PUT /v1/people/127/addresses

BEGIN

BEGIN

SELECT * from person where id = 127 pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier

SELECT * from person where id = 127 pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, n’en trouve pas et déduit donc qu’il faut en insérer une

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, n’en trouve pas et déduit donc qu’il faut en insérer une

INSERT INTO address … pour insérer l’adresse

INSERT INTO address … pour insérer l’adresse

commit

commit

RĂ©sultat : la personne se retrouve avec deux adresses !

Exemple avec verrou :

Fil d’exécution 1 Fil d’exécution 2

PUT /v1/people/127/addresses

PUT /v1/people/127/addresses

BEGIN

BEGIN

SELECT address from person where id = 127 FOR UPDATE pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier et verrouille la ligne

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, n’en trouve pas et déduit donc qu’il faut en insérer une

INSERT INTO address … pour insérer l’adresse

commit qui relache le verrou sur person

SELECT address from person where id = 127 FOR UPDATE pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier et verrouille la ligne, attendait que le verrou sur person soit disponible

SELECT id, address FROM address WHERE id_person = 127 récupère l’adresse

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, trouve l’adresse insérée par l’autre fil d’exécution

UPDATE address set address = … where id = 4758 met à jour l’adresse

commit qui relâche le verrou sur person

RĂ©sultat : une seule adresse.

Le script de migration SQL

Le script de migration déplace les données par blocs de person à address.

Dans notre exemple, une fois le code basculé à la nouvelle version, toutes les données sont écrites au format v2, qu’il s’agisse des créations ou des modifications.

La migration est donc irréversible, nous savons qu’il suffit de migrer toutes les données une fois pour que le travail soit fait.

  • Il commence par rĂ©cupĂ©rer l’ id de person le plus Ă©levĂ©. Comme le script est lancĂ© après le dĂ©ploiement de la nouvelle version, toutes les personnes crĂ©Ă©es après ce moment le sont avec une adresse stockĂ©e dans address. Cela signifie que le script peut s’arrĂŞter Ă  cette valeur.
  • Le script itère par groupes de person de 0 Ă  l’ id qu’il vient de rĂ©cupĂ©rer. Le pas de l’itĂ©ration est Ă  dĂ©terminer expĂ©rimentalement : un pas plus grand permet de faire moins de requĂŞtes donc de diminuer le temps total de la migration, au dĂ©triment du temps unitaire de chaque itĂ©ration, et donc du temps oĂą les verrous existent en base.
    • Il dĂ©marre une transaction.
    • Il sĂ©lectionne les id des personnes qui ont une adresse, et les verrouille.
    • Il insère dans address les donnĂ©es correspondantes Ă  l’aide d’un INSERT … SELECT …`.
    • Il vide le champs address de ces entrĂ©es dans la table person.
    • Il valide la transaction, relâchant ainsi les donnĂ©es.

En cas d’arrêt du script, les données déjà migrées ne sont pas perdues, et relancer le script ne pose pas de problèmes, les données migrées n’étant pas retraitées.

Les Ă©tapes Ă  suivre
  1. Version initiale fournissant l’API /v1 et où l’adresse est stockée dans la colonne address de la table person.
  2. Ajout en base de la table address, non encore utilisée par le code. La création d’une table n’a en principe aucun impact sur la base mais il faut le vérifier.
  3. Fournit l’API /v1, stocke l’adresse dans la table address et sait la lire aux deux endroits. Lors d’une lecture en /v1 sur une donnée v1 la donnée n’est pas migrée en v2 pour garder le code plus simple.
  4. Migration des adresses vers la table address.
  5. Fournit les API /v1 et /v2, et ne sait la lire qu’au format v2, suppression de la colonne address de la table person du code, la colonne est alors toujours en base.
  6. Suppression en base de la colonne address de la table person. Dans certaines bases de données, supprimer une colonne déclenche la réécriture de toute la table et ne peut donc se faire en ZDD. On se contente donc d’une suppression logique, par exemple en ajoutant un underscore devant son nom, et en la « recyclant » lorsqu’on a besoin d’une nouvelle colonne.
L’implémentation

L’implémentation se trouve sur GitHub. Le code est en open source sous licence MIT, vous pouvez donc vous en servir.

Chaque Ă©tape de la migration est dans un module Ă  part, cela permet de facilement examiner ce qui se passe sans avoir Ă  manipuler git.

Le code est en Java et utilise la bibliothèque Dropwizard. La base de donnée est PostgreSQL, l’accès se fait via Hibernate, et les migrations SQL utilisent Liquibase.

Quelques éléments saillants :

Pour conclure

Faire du ZDD n’est pas magique : cela demande du travail et de la rigueur. Si vous pouvez faire sans, tant mieux pour vous, mais si vous en avez besoin, vous devriez maintenant avoir une idée un peu plus précise de ce que ça représente. Rappelez-vous que l’exemple développé ici est un cas simple : servez-vous en pour avoir une idée de la démarche à suivre, et pas comme un guide pour mesurer l’effort à fournir.

La première migration sera sûrement un peu un défi, mais les suivantes seront de plus en plus faciles. Dans tous les cas, n’oubliez pas de tester, tester, et encore tester !

Catégories: Blog Société

Versionning d’API, Zero Downtime Deployment et migration SQL : théorie et cas pratique

Pour démythifier le Zero Downtime Deployment

Dans les patterns associés aux géants du web, le Zero Downtime Deployment (ZDD) partage une caractéristique avec l’auto-scaling : on en parle d’autant plus qu’ils sont peu mis en œuvre.

Le ZDD est victime d’un cercle vicieux : il a l’air très complexe car il est peu pratiqué, et comme il est peu pratiqué, on pense qu’il est très complexe.

Pour sortir de cette impasse, cet article présente un cas pratique, code à l’appui.

L’objectif n’est pas que tout le monde fasse du ZDD, car on verra qu’il ajoute du travail et de la complexité, mais que vous vous en ayez une vision claire. Cela vous permettra de pouvoir décider d’en faire ou pas en connaissance de cause.

Notre cas d’exemple

Notre exemple s’approche de celui décrit dans le premier article.

Soit une application exposée via une API REST.

Au départ cette application gère des personnes, chaque personne ayant zéro ou une adresse. Cette version est exposée sur le préfixe /v1 à l’aide d’un unique type de ressource /person.

La version suivante de l’application permettra d’associer plusieurs adresses à une personne, et sera exposée sur le préfixe /v2 en utilisant deux ressources, /person et /address.

Les deux versions

Cette application met en avant sa haute disponibilité, il est donc primordial que toutes les opérations soient effectuées sans interruption de service.

L’API est publique, nous ne maîtrisons donc pas l’utilisation qui en est faite. Il est donc impossible de faire une bascule de /v1 à /v2 en une seule fois. Les deux versions devront donc fonctionner ensemble le temps de permettre la migration de tous les utilisateurs. Cette période pouvant être très longue suivant les cas.

Les clients consomment les API via des intermédiaires, il est donc possible que pendant cette période ils utilisent à la fois les versions /v1 et /v2.

Dans la suite de l’article, /v1 et /v2 correspondent aux versions des services, et v1 et v2 correspondent aux deux manières dont les données seront stockées en base.

La stratégie Comment gérer la migration ?

Il est possible de se passer complètement de script de migration au sens traditionnel : vous exposez les services en /v2, et, lorsqu’ils sont appelés pour une donnée encore au format /v1, vous migrez la donnée à la volée. Cela permet de migrer les données petit à petit au fur et à mesure que les utilisateurs des services appelleront les APIs /v2. C’est l’approche qui est souvent prise avec les bases de données NoSQL.

Malheureusement, en procédant ainsi, il est possible que la migration ne se termine jamais, ou alors seulement dans très longtemps (si vous purgez les données trop anciennes). Pendant ce temps, vous devez maintenir le code supplémentaire permettant de prendre en charge ce cas.

L’autre approche est d’utiliser un script. Cela permet de faire en sorte que la migration se fasse rapidement. C’est le même type de script que vous utilisez pour vos migrations habituelles, sauf qu’il doit prendre en compte le fait qu’il s’exécute en même temps que le code. Ainsi toutes les opérations qui créent des verrous pendant plus de quelques millisecondes ne doivent pas être utilisées, et il faut s’assurer de ne pas créer d’interblocage.

La migration doit se faire de manière transactionnelle, pour éviter d’introduire des incohérences dans les données. En cas de problème, le script doit également pouvoir être interrompu et relancé sans que cela ne perturbe l’exécution du programme.

Dans l’article c’est cette approche que nous allons utiliser.

Quand migrer ?

Sans ZDD, le process de migration est classiquement le suivant :

  1. Fermer le service
  2. Arrêter l’application
  3. Faire un backup des données, pour pouvoir les restaurer en cas de problème
  4. Migrer les données
  5. Déployer la nouvelle version de l’application
  6. Démarrer la nouvelle version de l’application
  7. VĂ©rifier que tout fonctionne bien
  8. Ouvrir le service

En ZDD, plus question de fermer le service : la migration de données a lieu « à chaud ».

Il y a deux manières possibles de s’y prendre, suivant que la migration a lieu avant ou après l’ouverture des services /v2 :

Les deux manières de migrer

Numéro de l’étape Version du code Migration après l’ouverture de /v2 Migration avant l’ouverture de /v2

1

1

Application servant /v1 avec un modèle de de donnée v1

2

1

Modifier le schéma de BDD pour permettre de stocker les données nécessaires à /v2

3

2

Déployer une nouvelle version de l’application exposant /v1 et /v2 sur les modèles de donnée v1 ou v2

Déployer une nouvelle version de l’application exposant /v1 sur les modèles de donnée v1 ou v2

4

2

Migrer les données au modèle v2 sans interruption de service, en tenant compte du code /v1 et /v2

Migrer les données au modèle v2 sans interruption de service, en tenant compte du code qui sert /v1

5

3

Déployer une nouvelle version de l’application exposant /v1 et /v2 sur le modèle de donnée v2

6

3

Nettoyer le schéma de BDD des artefacts v1

7

4

Déployer une nouvelle version de l’application gérant /v2 sur le modèle de donnée v2

La première approche permet d’ouvrir les services /v2 plus rapidement car il n’y a pas besoin d’attendre la migration des données.

La seconde approche est plus simple :

  • la version exposant de l’application fonctionnant avec les modèles de donnĂ©es v1 et v2 n’expose que les services /v1, vous faites ainsi l’économie du cas oĂą un appel de service /v2 accède Ă  des donnĂ©es v1 ;
  • pendant la migration de donnĂ©es, les services /v2 ne sont pas encore exposĂ©s, cela veut dire moins de patterns d’accès aux donnĂ©es Ă  prendre en compte pour dĂ©signer une migration Ă©vitant les incohĂ©rences de donnĂ©es et les interblocages.

Sauf si votre process de migration est extrêmement long, la seconde approche est à privilégier, et c’est celle qui sera utilisée dans la suite de l’article.

/v1 et /v2 sont dans un bateau …

Les migrations d’APIs ouvertes posent deux problèmes métier et un problème technique.

Comment migrer les données ?

Le premier problème, valable aussi pour les API fermées, est de savoir comment migrer les données de /v1 à /v2. Je ne parle pas d’un point de vue technique mais bien d’un point de vue métier : la sémantique change entre les deux versions, il faut donc déterminer comment transformer les données de /v1 en /v2 d’une manière qui soit logique et qui ne surprenne pas les utilisateur·rice·s de l’API.

Dans notre cas la solution est immédiate : /v1 a au plus une seule adresse, et /v2 peut en avoir plusieurs, l’adresse de /v1 devient donc une des adresses de /v2.

Comment gérer la rétro-compatibilité ?

L’autre problème est de savoir comment interpréter en /v1 des données /v2. En effet si l’API est ouverte, vos utilisateur·rice·s peuvent appeler vos services /v1 alors que les données sont déjà au modèle /v2.

Il est souvent plus compliqué que le premier car au fur et à mesure des évolutions, les API ont tendance à devenir plus riches. Accéder à des données plus riches de la /v2 au travers du prisme plus étroit de l’API /v1 peut être un vrai casse-tête.

Si c’est le seul moyen que cette transition se passe bien, il est parfois nécessaire d’adapter le design de l’API /v2.

C’est un équilibre à trouver entre la facilité de transition, des restrictions possibles à ajouter pour les appelants de l’API, et le temps à investir.

Comment répondre vite et bien ?

Le problème technique est de parvenir à rendre les différents services, y compris la compatibilité, tout en s’assurant de toujours avoir des données cohérentes et sans (trop) pénaliser les performances. Si, entre les deux versions, les données ne sont plus structurées de la même manière, la gestion de la compatibilité peut demander de croiser les données de plusieurs tables.

Ainsi dans notre exemple, en v1 les adresses sont stockées dans la table person alors qu’en v2 elles sont dans une table address séparée. Pendant la période de compatibilité, il faut que les appels à v1 qui mettent à jour le nom de la personne et son adresse modifient les deux tables de manière transactionnelle pour éviter qu’une lecture v1 qui se produirait au même moment ne renvoie des données incohérentes. De plus, il faut parvenir à le faire sans avoir à poser trop de verrous en base de données, car cela raletit les accès.

La meilleure stratégie est de privilégier une approche que vous maîtrisez bien et qui donne des résultats acceptables plutôt qu’une solution plus efficace ou plus rapide mais plus complexe.

Dans tous les cas, des tests sont absolument essentiels.

Pour servir les deux versions de l’API, vous pouvez utiliser une application unique ou choisir de séparer votre code en deux applications, une par version de services. Cette question n’étant pas structurante pour la question du ZDD, nous choisissons de ne pas la traiter ici. Dans notre exemple, nous avons choisi de n’avoir qu’une seule application.

… et ZDD les rejoint à bord

Sans ZDD la situation est claire : on arrête l’application, les données sont migrées, et on redémarre l’application dans la nouvelle version. Il y a donc un avant et un après.

Avec ZDD la migration s’effectue à chaud pendant que les services sont disponibles, s’ajoute une situation intermédiaire.

Pendant cette période, les données peuvent donc être encore stockées au format /v1 ou migrées au format /v2.

Il faut alors parvenir à déterminer dans quel état sont les données : pour savoir quel code doit être appelé il faut savoir si la donnée a été migrée ou pas. De plus, le morceau de code en charge de cela va être exécuté très souvent, il doit donc être très efficace.

En cas de difficulté, la solution qui devrait fonctionner dans tous les cas est d’ajouter dans les tables impliquées un numéro indiquant la « version de schéma » de la donnée correspondante, et qui sera incrémenté lors de la migration de la donnée. Dans ce cas l’opération de vérification est très simple et rapide. L’opération d’ajout de colonne est alors à faire en avance de phase, ce qui augmente le travail nécessaire à la migration.

Si vous choisissez de faire la migration de données après l’ouverture de /v2, s’ajoute le cas où on appelle une api /v2 alors que la donnée est encore stockée au format v1. Il faut alors migrer la donnée à chaud, de manière transactionnelle en limitant les ralentissements induits.

Pour résumer, il y a quatre situations :

Appel /v1 Appel /v2

Données stockées au format v1

RĂ©pondre comme auparavant

(Seulement si migration après ouverture de /v2) Migrer les données à chaud

Données stockées au format v2

Compatibilité v1

Répondre avec la nouvelle sémantique

Bien ouvrir /v2, et bien décomissionner /v1

Lorsque vous ouvrez /v2 pour la première fois, faites-attention à la manière dont la bascule vers la nouvelle version est faite.

Avant de rendre les nouveaux endpoints accessibles, assurez-vous que tous les serveurs utilisent la dernière version de l’application. Dans le cas contraire, si vous appelez un /v1 alors que la donnée correspondante a été migrée en v2 le code ne saura pas la lire correctement et risque de planter ou de renvoyer une information fausse.

Un autre problème se pose suivant la manière dont vous avez implémenté les modifications de donnée lorsque vous appelez une API /v1.

Le premier cas consiste à sauvegarder la donnée au format v2, mais cela veut dire qu’à nouveau, les versions précédentes de l’application ne pourront pas la lire. La solution la plus simple est alors d’utiliser le feature flipping pour faire basculer le code.

Dans le cas contraire, votre code doit détecter sous quel format la donnée est stockée, et la resauvegarder sous ce même format : une donnée v1 reste en v1, et une donnée v2 reste en v2.
On Ă©vite le feature flipping, mais en Ă©change le code est plus complexe.

Pour décomissionner /v1 il suffit de rendre les endpoints inaccessibles, la suppression du code peut se faire plus tard.

À propos des verrous et des modifications de schémas

Comme on vient de le voir, le ZDD s’appuie beaucoup sur l’utilisation de la base de données, et notamment ses fonctionnalités d’accès concurrent. Si vos comportements métiers sont simples, que vous utilisez un ORM, et que vous avez des tests de performances automatisés, il s’agit d’un domaine auquel vous n’avez pas souvent à vous intéresser. Si vous vous y prenez mal, il est facile de bloquer la base, renvoyer des erreurs (en cas d’interblocage), ou des résultats incohérents.

Notre conseil est de bien vous documenter en amont voire de faire des POC pour éviter d’avoir à refaire un design parce que votre base de données ne fonctionne pas comme vous l’imaginiez. Ne faites pas confiance à des souvenirs ou à des rumeurs : lisez en détail la documentation correspondant à la version de l’outil que vous utilisez, et surtout testez !

Si vous n’avez jamais creusé ces sujets ou que vous êtes rouillé·e, la première migration vous demandera sûrement pas mal de travail, et vous donnera quelques sueurs froides lorsque vous l’exécuterez. Mais dites-vous que toutes les opérations suivantes manipuleront les mêmes concepts, et se passeront donc beaucoup mieux.

Il n’y a pas que le REST dans la vie

REST possède deux caractéristiques qui en font un candidat idéal pour le ZDD :

  • exposer plusieurs versions de services est une pratique standard ;
  • les appels sont supposĂ©s ĂŞtre sans Ă©tat.

Si vos services sont exposés d’une autre manière, il faudra donc vous intéresser à ces sujets. Les sessions, comme tous les types de cache, peuvent demander une attention particulière si les données qu’elles contiennent font l’objet d’un changement de structure entre versions.

Retour Ă  notre exemple

Nous prenons l’hypothèse où le modèle de données suit directement les ressources à exposer. L’adresse est initialement un champ de la table person, et est migrée dans une table address distincte.

L’évolution du schéma

Nous n’utilisons pas de colonne spécifique pour stocker la « version de schéma » des objet. À la place nous allons vérifier en base la manière dont les données sont stockées : si la table person contient une adresse, c’est qu’elle est en version v1, sinon il faut vérifier l’existence d’une adresse dans la table dédiée. Cela évite d’alourdir le schéma SQL, mais augmente le nombre de requêtes exécutées.

Les Ă©tapes Ă  suivre pour la migration :

  1. Version initiale : l’adresse est dans la colonne address de la table person, le code ne sait fonctionner que de cette manière.
  2. Ajout de la nouvelle table address dans la base de données, à cette étape le code ne connaît pas encore cette table.
  3. Déploiement du code qui fournit l’api /v1 et qui est compatible avec les deux manières de stocker l’adresse.
  4. Exécution du script de migration.
  5. Déploiement du code qui fournit les api /v1 et /v2 et qui est compatible avec la nouvelle manière de stocker l’adresse, la colonne address de la table person n’est plus utilisée par le code.
  6. Suppression de la colonne address de la table person.

Le ZDD a pour conséquence d’ajouter des versions de code et des migrations de schémas intermédiaires. Dans un environnement où les déploiements ne sont pas automatisés, cela signifie une augmentation de la charge de travail et donc du risque d’erreur. Mieux vaut donc s’outiller et disposer d’un pipeline de livraison fiable avant de se lancer.

Analyse détaillée La compatibilité des services

Dans notre exemple le problème de compatibilité est le suivant : une fois une personne migrée, elle peut avoir plusieurs adresses. Que faire quand on récupère cette même personne en passant par l’API /v1 ?

Ici il n’y a pas de réponse évidente : il n’y a pas de notion d’adresse préférée, ou de dernière adresse utilisée qui fournirait une manière de discriminer les différentes possibilités. Comme la réponse influe sur le comportement de l’API, c’est une décision à prendre par les personnes du métier.

La solution choisie ici est de renvoyer une adresse parmi celle dans la liste. Elle n’est pas parfaite, mais elle peut être acceptable suivant l’usage qui en est fait : il revient aux personnes du métier d’en décider.

La transactionnalité

Pour résoudre la question de transactionnalité, nous avons choisi la solution la plus simple : poser un verrou sur les entrées correspondantes de la table person.

Si toutes les opérations suivent le même principe, ce verrou joue le rôle d’une mutex en s’assurant que les appels s’exécutent bien l’un après l’autre : lorsqu’une opération pose un risque, elle commence par demander l’accès à ce verrou, et pour cela elle doit attendre son tour.

Exemple avec un appel à PUT /v1/people/127 alors que la personne correspondante est stockée au format v2 mais n’a pas encore d’adresse.

Exemple sans verrou :

Fil d’exécution 1 Fil d’exécution 2

PUT /v1/people/127/addresses

PUT /v1/people/127/addresses

BEGIN

BEGIN

SELECT * from person where id = 127 pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier

SELECT * from person where id = 127 pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, n’en trouve pas et déduit donc qu’il faut en insérer une

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, n’en trouve pas et déduit donc qu’il faut en insérer une

INSERT INTO address … pour insérer l’adresse

INSERT INTO address … pour insérer l’adresse

commit

commit

RĂ©sultat : la personne se retrouve avec deux adresses !

Exemple avec verrou :

Fil d’exécution 1 Fil d’exécution 2

PUT /v1/people/127/addresses

PUT /v1/people/127/addresses

BEGIN

BEGIN

SELECT address from person where id = 127 FOR UPDATE pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier et verrouille la ligne

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, n’en trouve pas et déduit donc qu’il faut en insérer une

INSERT INTO address … pour insérer l’adresse

commit qui relache le verrou sur person

SELECT address from person where id = 127 FOR UPDATE pour récupérer la personne, vérifie qu’il n’y a pas d’adresse et que les autres champs ne sont pas à modifier et verrouille la ligne, attendait que le verrou sur person soit disponible

SELECT id, address FROM address WHERE id_person = 127 récupère l’adresse

SELECT * from address where id_person = 127 pour récupérer une adresse à mettre à jour, trouve l’adresse insérée par l’autre fil d’exécution

UPDATE address set address = … where id = 4758 met à jour l’adresse

commit qui relâche le verrou sur person

RĂ©sultat : une seule adresse.

Le script de migration SQL

Le script de migration déplace les données par blocs de person à address.

Dans notre exemple, une fois le code basculé à la nouvelle version, toutes les données sont écrites au format v2, qu’il s’agisse des créations ou des modifications.

La migration est donc irréversible, nous savons qu’il suffit de migrer toutes les données une fois pour que le travail soit fait.

  • Il commence par rĂ©cupĂ©rer l’ id de person le plus Ă©levĂ©. Comme le script est lancĂ© après le dĂ©ploiement de la nouvelle version, toutes les personnes crĂ©Ă©es après ce moment le sont avec une adresse stockĂ©e dans address. Cela signifie que le script peut s’arrĂŞter Ă  cette valeur.
  • Le script itère par groupes de person de 0 Ă  l’ id qu’il vient de rĂ©cupĂ©rer. Le pas de l’itĂ©ration est Ă  dĂ©terminer expĂ©rimentalement : un pas plus grand permet de faire moins de requĂŞtes donc de diminuer le temps total de la migration, au dĂ©triment du temps unitaire de chaque itĂ©ration, et donc du temps oĂą les verrous existent en base.
    • Il dĂ©marre une transaction.
    • Il sĂ©lectionne les id des personnes qui ont une adresse, et les verrouille.
    • Il insère dans address les donnĂ©es correspondantes Ă  l’aide d’un INSERT … SELECT …`.
    • Il vide le champs address de ces entrĂ©es dans la table person.
    • Il valide la transaction, relâchant ainsi les donnĂ©es.

En cas d’arrêt du script, les données déjà migrées ne sont pas perdues, et relancer le script ne pose pas de problèmes, les données migrées n’étant pas retraitées.

Les Ă©tapes Ă  suivre
  1. Version initiale fournissant l’API /v1 et où l’adresse est stockée dans la colonne address de la table person.
  2. Ajout en base de la table address, non encore utilisée par le code. La création d’une table n’a en principe aucun impact sur la base mais il faut le vérifier.
  3. Fournit l’API /v1, stocke l’adresse dans la table address et sait la lire aux deux endroits. Lors d’une lecture en /v1 sur une donnée v1 la donnée n’est pas migrée en v2 pour garder le code plus simple.
  4. Migration des adresses vers la table address.
  5. Fournit les API /v1 et /v2, et ne sait la lire qu’au format v2, suppression de la colonne address de la table person du code, la colonne est alors toujours en base.
  6. Suppression en base de la colonne address de la table person. Dans certaines bases de données, supprimer une colonne déclenche la réécriture de toute la table et ne peut donc se faire en ZDD. On se contente donc d’une suppression logique, par exemple en ajoutant un underscore devant son nom, et en la « recyclant » lorsqu’on a besoin d’une nouvelle colonne.
L’implémentation

L’implémentation se trouve sur GitHub. Le code est en open source sous licence MIT, vous pouvez donc vous en servir.

Chaque Ă©tape de la migration est dans un module Ă  part, cela permet de facilement examiner ce qui se passe sans avoir Ă  manipuler git.

Le code est en Java et utilise la bibliothèque Dropwizard. La base de donnée est PostgreSQL, l’accès se fait via Hibernate, et les migrations SQL utilisent Liquibase.

Quelques éléments saillants :

Pour conclure

Faire du ZDD n’est pas magique : cela demande du travail et de la rigueur. Si vous pouvez faire sans, tant mieux pour vous, mais si vous en avez besoin, vous devriez maintenant avoir une idée un peu plus précise de ce que ça représente. Rappelez-vous que l’exemple développé ici est un cas simple : servez-vous en pour avoir une idée de la démarche à suivre, et pas comme un guide pour mesurer l’effort à fournir.

La première migration sera sûrement un peu un défi, mais les suivantes seront de plus en plus faciles. Dans tous les cas, n’oubliez pas de tester, tester, et encore tester !

Catégories: Blog Société

Qu’est ce qu’un (bon) ScrumMaster?

Qualitystreet - Jean Claude GROSJEAN - jeu, 07/06/2017 - 02:14

Vous ĂŞtes de plus en plus nombreux Ă  vous intĂ©resser Ă  l’agilitĂ©, Ă  travailler dans un cadre de Scrum voire mĂŞme Ă  endosser le costume de ScrumMaster. Voici donc quelques Ă©lĂ©ments qui vont permettront d’y voir plus clair sur ce nouveau rĂ´le. ScrumMaster c’est un des 3 rĂ´les proposĂ©s dans Scrum (avec l’Equipe et le…

The post Qu’est ce qu’un (bon) ScrumMaster? appeared first on QualityStreet - Blog Agile depuis 2007.

Catégories: Blog Individuel

Migration de données avec Rails

L'actualité de Synbioz - mer, 07/05/2017 - 23:00

L’évolution. Sujet passionnant s’il en est ! Un jour ou l’autre, nous devons tous faire face à cette situation : le changement. Nos besoins — ou ceux de nos clients — évoluent, changent avec le temps ; et nous devons donc accompagner ce changement en adaptant le code de nos projets. Nous devons effectuer des migrations.

Nous avons tous une idée de ce qu’est ou ce que doit être une migration ; il s’agit d’adapter la structure de nos données ou nos données elles-mêmes à nos nouveaux besoins. Ainsi nous distinguons déjà deux formes de migration : d’une part les migrations de structure (on parlera de schema en anglais) et d’autre part les migrations de données. Voyons ensemble ce que Rails met à notre disposition pour réaliser nos migrations et comment utiliser ces outils au mieux, en évitant les pièges que nous pourrions rencontrer !

Lire la suite...

Catégories: Blog Société

The road to success: Why scoping is important

Le blog de Valiantys - mar, 07/04/2017 - 14:00

Imagine that your car is not working properly. For some reason when you push on the gas, your RPM’s don’t rev up and you can’t seem to get it going to the minimum speed needed to be riding safely on the highway. You would obviously take your car to the garage to get it fixed ...

The post The road to success: Why scoping is important appeared first on Valiantys - Atlassian Platinum Partner.

Catégories: Blog Société

Partagez la connaissance

Partagez BlogsdeDeveloppeurs.com sur les réseaux sociaux