Serveur d'impression

Nous avons mis en place une édition collaborative pour le système de gestion de contenu de notre salle de presse. Voici comment. – Bien choisir son serveur d impression

Le 3 août 2019 - 12 minutes de lecture

L'équipe Times Open

Par Sophia Ciocca et Jeff Sisson

Il faut beaucoup de gens pour publier un article dans le New York Times, et parfois les choses se compliquent. Plusieurs reporters et rédacteurs peuvent participer à la rédaction, à la révision et à la publication d’un même récit, et cette collaboration est souvent non linéaire, ce qui peut amener les gens à se marcher sur les pieds.

Cela est particulièrement vrai dans les situations de grande actualité où de nombreux types de collaborateurs (rédacteurs de photos, rédacteurs, journalistes, producteurs) doivent modifier un document en même temps. Lors de la création de Oak, l’interface d’édition d’articles de nouvelle génération de The Times, une seule personne pouvait travailler sur un document à la fois. Oak utilisait le «verrouillage de champ» pour faciliter certaines fonctionnalités de collaboration simultanées, comme permettre à différentes personnes d’éditer des champs de métadonnées distincts, mais une seule personne pouvait éditer le corps d’un article à la fois.

Pour nous, il était clair qu'un éditeur d'article plus parfait permettrait aux collaborateurs de travailler dans un document simultanément et de manière transparente. Oak avait besoin d'une fonctionnalité d'édition collaborative.

Mais l’édition collaborative est un difficile problème à résoudre. Il présente de nombreux nouveaux casse-tête, notamment comment incorporer les mises à jour en direct, comment remédier aux modifications conflictuelles et comment gérer les erreurs résultant d'un accès wifi irrégulier. Un produit tel que Google Docs dispose d’énormes équipes et de ressources consacrées à la résolution de ce type de problèmes à grande échelle. Notre équipe n’a eu que deux mois pour résoudre ces énigmes d’une manière qui convient au flux de travail éditorial de The Times. Heureusement, la prise en charge de ce type de problèmes techniques était l’une des raisons originales pour lesquelles nous avons choisi ProseMirror, une bibliothèque d’édition de texte à code source ouvert, en tant que substrat technique de Oak.

Pour qu'un article Oak soit collaboratif, chaque personne y ayant accès doit disposer de la version la plus récente en temps réel. Cela signifie que chaque fois qu'une modification est effectuée, elle doit être visible depuis l'ordinateur de chaque collaborateur. Traduire des éditions individuelles en un formulaire pouvant être envoyé sur Internet est quelque chose que ProseMirror fait à un niveau bas; chacune de ces modifications est appelée «étape». Lorsqu'un utilisateur tape une lettre, c’est une étape. Appuyez sur la touche Entrée pour passer à une nouvelle ligne? Aussi une étape. Tout ce qui manipule le document – ajouter une image, éditer le titre, supprimer un paragraphe – compte pour une étape.

A quoi ressemble exactement les données d'une étape? Nous décrivons les étapes en tant qu'objets JSON qui agissent comme des indications pour déterminer comment exactement l'étape modifie le document. Voici à quoi cela ressemble de placer la lettre «H» en deuxième position dans un document:

{
«StepId»: 1,
"étape": {
«StepType»: «replace»,
"À partir de": 2,
"À": 2,
"Tranche": {
"contenu":[[[[
"Type": "texte",
"Texte": "h"
]

,
«ClientID»: «1111–42783748297342»,
“Horodatage”: “Dim 10 février 2019 12h31:32 GMT-0500 (heure normale de l'Est)”

Lorsqu'un utilisateur tape des mots, modifie une image ou ajoute un commentaire, les étapes de ces actions sont ajoutées au document local de l'utilisateur, mais ces étapes n'ont pas encore été envoyées à qui que ce soit. Pour que les étapes à suivre apparaissent sur les ordinateurs d’autres personnes, elles doivent être envoyées et confirmées par un serveur distant, que nous appelons le «serveur d’autorité».

Le serveur d'autorité agit comme un videur dans un club: lorsqu'il reçoit les étapes d'un utilisateur, il doit décider s'il souhaite laisser ces étapes dans sa base de données. S'il constate qu'aucune étape n'a été enregistrée depuis la dernière conversation du navigateur de l'utilisateur avec le serveur d'autorité, il les enregistre dans sa base de données. Sinon, le navigateur de cet utilisateur sera invité à récupérer toutes les étapes qu’il n’a pas encore vues.

Une conversation typique entre le document local et le serveur d'autorité distant pourrait ressembler à ceci:

1. Local: «Bonjour, j'ai les étapes un, deux et trois.
2 Télécommande: "Très bien, j'ai mémorisé les étapes un, deux et trois."
3 Section locale: «Bonjour à nouveau… j'ai les étapes quatre, cinq et six.»
4 Télécommande: «Ah! Quelqu'un d'autre a inséré les étapes quatre et cinq. S'il te plaît, va les chercher.
5 * La section locale va chercher les étapes quatre et cinq, et rebase ses étapes précédentes quatre, cinq et six en six, sept et huit pour refléter les étapes confirmées quatre et cinq. *
6 Local: "Hey ... J'ai maintenant les étapes six, sept et huit."
7. Télécommande: "Cool, j’ai mémorisé les étapes six, sept et huit."

Notez que, dans la ligne quatre, le document local tente d'envoyer les étapes quatre, cinq et six, mais que le serveur distant indique au navigateur que des étapes existent déjà. Le navigateur doit extraire les étapes, créer une nouvelle base et essayer de renvoyer les étapes. Que se passe-t-il ici?

Le changement de base est le processus qui se produit lorsque deux utilisateurs ont inséré des étapes à peu près au même moment et que le code doit négocier la manière dont elles s’assemblent. Il implique l’une des parties les plus importantes du support de l’édition collaborative de ProseMirror: un algorithme appelé Transformation opérationnelle, qui détermine comment placer les étapes d’un utilisateur sur une version plus récente du document.

Bien que ProseMirror fournisse d'excellents blocs de construction (et une démonstration complète) pour implémenter un serveur d'édition collaboratif, il ne précise pas comment stocker les étapes dans une base de données. Nous avons dû concevoir et mettre en œuvre notre propre solution répondant à nos besoins spécifiques. Parmi les questions que nous avons examinées au cours de notre phase de prototypage, citons: Comment pouvons-nous adapter le serveur d'autorités pour permettre de nombreuses modifications – jusqu'à 25 000 par article? Comment pouvons-nous préserver l'historique d'édition d'un document collaboratif? Enfin, comment pouvons-nous prendre en charge une multitude de fonctionnalités, telles que l'intégration du dernier document dans nos systèmes de production imprimée, propres aux besoins de notre salle de rédaction?

Après avoir esquissé quelques prototypes différents, nous avons utilisé la base de données en temps réel Firestore pour stocker nos étapes et servir de videur pour les étapes à venir. Firestore prend en charge les transactions de base de données, ce qui signifie que les étapes soumises par plusieurs personnes seront retentées par la bibliothèque Firestore jusqu’à ce que l’insertion d’une personne “gagne” et soit écrite dans la base de données. En commandant de cette manière les étapes à plusieurs personnes, Firestore est un bon choix en tant que serveur d’autorité.

Lorsqu'une opération d'écriture dans la base de données a réussi, Firestore informera les utilisateurs distants que de nouvelles étapes ont été ajoutées à la base de données, ce qui permet à l'application d'extraire les étapes récemment confirmées et de mettre à jour leur copie du document.

Maintenir le document collaboratif à jour est important, mais il est également important de savoir qui d'autre se cache dans un document. Nous voulions que tout le monde dans un document puisse voir où se trouvent les curseurs de leurs collaborateurs, ou si leurs collaborateurs mettent en surbrillance un passage avec une souris. En exploitant les API de ProseMirror et Firebase (un frère de Firestore), nous avons ajouté à Oak une fonctionnalité qui indique qui se trouve dans le document et où il a laissé son curseur.

Les curseurs de couleurs différentes indiquent où se trouve la sélection de chaque utilisateur dans le document, ce qui permet aux utilisateurs d’éviter de s’appuyer sur les modifications des autres utilisateurs.

Chaque fois qu'un utilisateur modifie sa sélection dans l'éditeur Oak en tapant, en cliquant ou en faisant glisser, ProseMirror observe la modification de l'état actuel de la sélection de son navigateur et crée une structure de données Sélection avec ces informations. Ces données reflètent des informations sur l'emplacement du curseur d'un utilisateur dans le texte et contiennent la position de départ (ou la tête) et la position de fin (l'ancre).

Si un utilisateur effectue une sélection dans un document, la sélection est rendue pour chaque ordinateur sur lequel le document est ouvert et affiche le nom de l'utilisateur à côté. Lorsque l'utilisateur modifie sa sélection dans son navigateur, cette modification doit être reflétée dans le document. Nous transmettons donc les données de sélection mises à jour (positions de tête et d'ancrage) dans Firebase.

Pour gérer ces sélections, nous devons parfois prédire l'avenir. Étant donné que les données de sélection et les modifications apportées au document sont envoyées à des serveurs distincts, l'application Oak peut recevoir des modifications de sélection pour les versions du document que le navigateur n'a pas encore reçues. Si l'application Oak reçoit une modification du document avant une modification correspondante dans une sélection, elle doit simuler comment elle considère cette sélection. aurait changement. De même, s’il reçoit une modification apportée à une sélection liée à une modification qui n’a pas encore été livrée, l’application attend qu’elle parvienne à cette modification pour rendre la modification apportée à la sélection. Pour ce faire, nous utilisons Redux Sagas pour attendre, puis appliquer ces mises à jour de sélection du futur.

Il convient de noter que nous avons choisi d’utiliser Firebase pour stocker ces sélections, par opposition à Firestore (que nous utilisons pour stocker les étapes), car Firebase rend disponible un hook onDisconnect, ce qui nous permet d’effectuer des modifications de la base de données même si le l'utilisateur ferme l'onglet. Cela permet de garantir que lorsqu'un utilisateur quitte l'éditeur Oak, son curseur sera nettoyé après lui.

Une fois que toutes les modifications ou étapes de l'article ont été insérées dans Firestore, chaque fenêtre du navigateur ouverte à cet article est mise à jour avec les dernières étapes. Lorsqu'un article est prêt à être publié, le service backend qui gère la publication reçoit également les données de l'article à jour, qu'il envoie au pipeline de publication utilisé par notre site Web et nos applications pour rendre les articles à l'utilisateur.

Avant la mise en œuvre de l’édition collaborative, ce flux était plus simple: le service backend pouvait aller directement à notre base de données MySQL où vivaient le contenu et les métadonnées de l’article. Cependant, pour les nouveaux articles édités en collaboration, nous avons créé un service App Engine (surnommé le «service collab») qui transfère le contenu d'un article de Firestore à notre service d'édition. Lorsqu'un utilisateur appuie sur le bouton de publication, le navigateur envoie une demande à ce service de collaboration, qui copie les données de Firestore sur le pipeline de publication.

Après avoir cliqué sur «Publier» sur un article, l'application de publication communique avec le service Collab, qui s'intègre à Firestore, pour s'assurer que la version la plus récente de l'article est publiée sur le site.

Une fois qu'un article édité en collaboration a été publié numériquement, il peut nécessiter une mise au point avant impression. Avant qu'un article puisse être envoyé à l'imprimerie, les rédacteurs en chef de la salle de presse doivent supprimer les liens hypertexte et le contenu incorporé, et éventuellement raccourcir l'article pour l'imprimer.

L'interface permettant d'effectuer ces éditions d'impression s'appuie sur la base de données MySQL existante. Les articles collaboratifs étant stockés dans Firestore et, par conséquent, déconnectés de cette base de données imprimée, nous avons développé un système qui copie l'état de collaboration d'un article dans notre base de données MySQL principale à intervalles réguliers. Ce système se compose d'un ensemble de fonctions Google Cloud et de tâches Google Cloud, et permet de prévisualiser les modifications collaboratives à la seconde près au fur et à mesure de leur impression dans le journal – une fonctionnalité utile pour nos éditeurs d'impression.

Une fois qu'un article publié en collaboration dans Oak a été publié et imprimé, il a finalement atteint la ligne d'arrivée! Certains articles peuvent être mis à jour avec des corrections après publication, et les étapes resteront stockées dans Firestore à des fins de suivi des modifications, mais la publication numérique est le lieu où l'histoire se termine pour nos articles et leurs étapes. Nous disposons désormais d'un éditeur collaboratif fonctionnel qui fonctionne de manière transparente avec notre flux de travail d'actualités existant, offrant une expérience utilisateur considérablement améliorée aux collaborateurs de la salle de rédaction.

Commentaires

Laisser un commentaire

Votre commentaire sera révisé par les administrateurs si besoin.