Depuis son annonce, la technologie
WebAssembly a immédiatement attiré l'attention des développeurs front-end. La communauté Web a accepté avec enthousiasme l'idée d'exécuter du code dans un navigateur écrit dans des langues autres que JavaScript. L'essentiel est que WebAssembly garantit une vitesse beaucoup plus élevée que JavaScript.
Nos ingénieurs ont suivi de près l'évolution de la norme. Dès que le support de WebAssembly 1.0 a été implémenté dans tous les principaux navigateurs, les développeurs ont immédiatement voulu l'essayer.
Mais il y avait un problème. Bien que de
nombreuses applications bénéficient de WebAssembly, la portée de la technologie dans le commerce électronique est encore primitive. Nous n'avons pas pu trouver immédiatement la version correcte de son utilisation. Il y avait quelques suggestions, mais JavaScript était meilleur dans toutes les variantes. Lorsque nous évaluons les nouvelles technologies sur eBay, la première question est: "Quels sont les avantages potentiels pour nos clients?" S'il n'y a pas de clarté ici, nous ne passerons pas à l'étape suivante. Il est très facile de se laisser emporter par les nouvelles technologies à la mode, même si cela n'a pas d'importance pour les clients et ne fait que compliquer le flux de travail existant. L'expérience utilisateur est toujours plus importante que l'expérience développeur. Mais avec WebAssembly différemment. Cette technologie a un énorme potentiel, nous n'avons tout simplement pas pu trouver le bon cas d'utilisation. Cependant, à la fin, ils l'ont toujours trouvé.
Scanner de codes à barres
Dans les applications natives eBay sur iOS et Android, il existe une fonction de
lecture de codes-barres
UPC pour entrer automatiquement dans le formulaire. Il ne fonctionne que dans les applications et nécessite un traitement intensif des images sur l'appareil afin de reconnaître les chiffres du code-barres dans le flux d'images de la caméra. Le code résultant est ensuite envoyé au service serveur qui, à son tour, remplit le formulaire. Cela signifie que la logique de traitement d'image sur l'appareil doit être très efficace. Pour les applications natives, nous avons compilé notre propre bibliothèque C ++ en code natif pour iOS et Android. Il reconnaît exceptionnellement bien les codes-barres. Nous passons progressivement aux API natives dans iOS et Android, mais notre bibliothèque C ++ est toujours fiable.
Le scanner de codes à barres est une fonction intuitive pour les vendeurs, il simplifie considérablement le remplissage du formulaire. Malheureusement, cette fonction n'a pas fonctionné sur la version mobile du site, et les vendeurs ont dû saisir manuellement l'UPC, ce qui n'est pas pratique.
Scanner de codes à barres Web
Nous cherchions une option pour scanner les codes-barres sur le Web. Il y a deux ans, ils ont même sorti un prototype basé sur la bibliothèque JavaScript open source
BarcodeReader . Le problème était que cela ne fonctionnait bien que dans 20% des cas. Les 80% restants, le scanner fonctionnait extrêmement lentement ou ne fonctionnait pas du tout. Dans la plupart des cas, c'était un délai d'attente. C'est tout à fait normal: JavaScript ne peut être comparé en vitesse avec du code natif que s'il est «à chaud», c'est-à-dire qu'il est hautement optimisé par les compilateurs
JIT . L'astuce est que les moteurs JavaScript utilisent de nombreuses heuristiques pour déterminer si un chemin est "chaud" sans garantir un résultat. Cette divergence a évidemment conduit à la frustration des utilisateurs, et nous avons dû désactiver cette fonctionnalité. Mais maintenant, tout est différent. Avec le développement rapide de la plate-forme Web, la question s'est posée: «Est-il possible de mettre en place un scanner de codes-barres fiable sur le Web?»
Une option consiste à attendre la fin de l'
API Shape Detection avec ses fonctionnalités intégrées de détection d'image, y compris les
codes-barres . Mais ces interfaces sont encore à un stade très précoce de développement et sont loin d'être compatibles avec plusieurs navigateurs. Et même dans ce cas, le travail sur toutes les plateformes n'est
pas garanti . Par conséquent, vous devez considérer d'autres options.
C'est là que WebAssembly entre en jeu. Si un scanner de codes-barres est implémenté sur WebAssembly, il est garanti qu'il fonctionne. La forte structure de typage et de bytecode de WebAssembly vous permet de toujours garder le "hot path" de l'exécution. De plus, nous avons déjà une bibliothèque C ++ pour les applications natives. Les bibliothèques C ++ sont des candidats idéaux pour la compilation dans WebAssembly. Nous pensions que le problème était résolu. Il s'est avéré, pas vraiment.
L'architecture
L'architecture du prototype de travail pour le scanner de codes à barres sur WebAssembly était assez simple.
- Compilez la bibliothèque C ++ avec Emscripten . Il produira le middleware et le fichier .wasm.
- Sélectionnez un thread de travail dans le thread principal. Le code JavaScript du travailleur importe le code de liaison JavaScript généré, qui crée à son tour le fichier .wasm.
- Le flux principal envoie un instantané du flux de la caméra au flux du travailleur, et il appellera l'API WASM correspondante via le code de connexion. La réponse de l'API est transmise au thread principal. La réponse peut être une chaîne UPC (qui est transmise au backend) ou une chaîne vide si aucun code-barres n'est détecté.
- Pour une réponse vierge, l'étape ci-dessus est répétée jusqu'à ce qu'un code-barres soit détecté. Ce cycle s'exécute pendant l'intervalle de temps spécifié en secondes. Une fois le seuil atteint, nous afficherons un message d'avertissement «Code produit invalide. Essayez un code à barres ou une recherche de texte différent . " Soit l'utilisateur n'a pas focalisé l'appareil photo sur un vrai code-barres, soit le scanner n'est pas suffisamment efficace. Nous suivons les statistiques sur les délais d'attente comme indicateur de la qualité du scanner.

Flux de travail WebAssemblyCompilation
La première étape de tout projet WebAssembly consiste à définir un pipeline de compilation clair. Emscripten est devenu la norme de facto pour la compilation de WebAssembly, mais il est important d'avoir un environnement cohérent qui produit un résultat déterministe. Notre frontend est basé sur Node.js, nous devons donc trouver une solution compatible avec le workflow npm. Heureusement, à cette époque,
Surma Das a publié un article
intitulé «Emscripten and npm» . L'approche
Docker pour la compilation de WebAssembly est logique car elle élimine une tonne de surcharge. Comme recommandé dans l'article, nous avons pris l'
image docker
d'Emscripten de
trzeci . Pour activer la compilation dans WebAssembly, la bibliothèque native C ++ a dû être légèrement modifiée. Fondamentalement, nous avons agi au hasard, par essais et erreurs. À la fin, j'ai réussi à le compiler et à mettre en place un workflow WebAssembly soigné dans le pipeline d'assemblage existant.
Ça marche vite, mais ...
Les performances du scanner sont mesurées par le nombre d'images traitées par l'API Wasm par seconde. L'API Wasm prend une image du flux vidéo de la caméra, effectue des calculs et renvoie une réponse. Cela se fait sur une base continue jusqu'à ce qu'un code-barres soit détecté. Les performances sont mesurées en FPS.
Notre implémentation de test de WebAssembly a montré une vitesse incroyable de 50 FPS. Cependant, cela n'a fonctionné que dans 60% des cas, et dans le reste, il s'est écrasé par le timeout. Même avec un FPS aussi élevé, ils ne pouvaient pas détecter rapidement le code-barres pour les 40% de scans restants, donnant un message d'avertissement à la fin. En comparaison, l'implémentation JavaScript précédente fonctionnait généralement à 1 FPS. Oui, WebAssembly est beaucoup plus rapide (50 fois), mais pour une raison quelconque, il ne fonctionne pas dans presque la moitié des cas. Il convient également de noter que dans certaines situations, JavaScript a très bien fonctionné et a immédiatement trouvé le code-barres. L'une des options évidentes était d'augmenter le délai d'attente, mais cela ne fera qu'augmenter la frustration des utilisateurs, et donc nous ne résolvons pas le vrai problème. Par conséquent, nous avons abandonné cette idée.
Au début, nous ne pouvions pas comprendre pourquoi la bibliothèque native C ++, qui fonctionnait parfaitement dans les applications natives, ne montrait pas le même résultat sur le Web. Après de longs tests et débogages, nous avons constaté que la vitesse de reconnaissance dépend de l'angle de mise au point de l'objet et de l'ombre d'arrière-plan. Mais comment alors tout fonctionne dans les applications natives? Le fait est que dans les applications natives, nous utilisons les API intégrées pour la mise au point automatique et offrons à l'utilisateur la possibilité de se concentrer manuellement en pointant un doigt sur le code-barres. Par conséquent, les applications natives fournissent toujours à la bibliothèque des images claires de haute qualité.
Réalisant l'essentiel de ce qui se passe, nous avons décidé d'essayer une autre bibliothèque native: un scanner de code à barres
ZBar open source assez populaire et stable. Plus important encore, cela fonctionne bien avec des images floues et granuleuses. Pourquoi ne pas essayer? Comme nous avions déjà le workflow WebAssembly, la compilation et le déploiement de ZBar dans WebAssembly se sont bien déroulés. Les performances se sont avérées décentes, environ 15 FPS, bien que pas aussi bonnes que celles de notre propre bibliothèque C ++. Mais le taux de réussite était proche de 80% pour le même timeout. Une nette amélioration par rapport à notre bibliothèque C ++, mais toujours pas à 100%.
Le résultat ne nous a pas encore satisfaits, mais nous avons remarqué quelque chose d'inattendu. Là où Zbar s'est écrasé, notre propre bibliothèque C ++ a fait le travail très rapidement. Ce fut une agréable surprise. Il semble que les bibliothèques aient traité les images de différentes qualités de différentes manières. Cela nous a conduit à l'idée.
Multithreading et course de vitesse
Vous avez probablement déjà compris. Pourquoi ne pas créer deux threads de travail: un pour Zbar et un pour notre bibliothèque C ++, et ne pas les exécuter en parallèle. Celui qui a gagné (celui qui envoie d'abord un code-barres valide) envoie le résultat au flux principal, et les deux travailleurs s'arrêtent. Nous avons mis en œuvre un tel scénario et avons commencé à nous tester, en essayant de simuler autant de scénarios que possible. Ce paramètre a montré 95% des analyses réussies. Beaucoup mieux que les résultats précédents, mais toujours pas à 100%.
L'une des suggestions étranges était d'ajouter la bibliothèque JavaScipt originale à la compétition. Ce sera trois volets. Honnêtement, nous ne pensions pas que cela changerait quoi que ce soit. Mais un tel test n'a nécessité aucun effort, car nous avons standardisé l'interface de travail. À notre grande surprise, avec trois volets, le taux de réussite s'est vraiment approché de 100%. C'était encore une fois complètement inattendu. Comme mentionné précédemment, JavaScript a très bien fonctionné dans certaines situations. Apparemment, il a comblé l'écart. Ainsi, la sagesse populaire de la loi est
«JavaScript gagne toujours» . Si sans blagues, l'illustration suivante donne un aperçu de l'architecture finale que nous avons implémentée.
Scanner de codes-barres d'architecture WebLa figure suivante montre un diagramme fonctionnel de haut niveau:
Diagramme fonctionnel d'un lecteur de codes-barresRemarque sur le chargement des ressources
Les ressources nécessaires au fonctionnement du scanner sont préchargées après le rendu de la page principale. De cette façon, la page de destination se charge rapidement et est prête à interagir. Les ressources WebAssembly (fichiers wasm et scripts middleware) et la bibliothèque du scanner JavaScript sont préchargées et mises en cache à l'aide de
XMLHttpRequest après le chargement de la page principale. Il est important ici qu'ils ne soient pas exécutés immédiatement afin de laisser le thread principal libre pour l'interaction de l'utilisateur avec la page. L'exécution ne se produit que lorsque l'utilisateur clique sur l'icône du code-barres. Si l'utilisateur a cliqué sur l'icône avant de charger les ressources, elles seront chargées à la demande et immédiatement exécutées. Le gestionnaire d'événements du lecteur de codes-barres et le contrôleur de travail sont chargés avec la page, mais ils sont très petits.
Résultats
Après des tests rigoureux et une utilisation interne par les employés, nous avons lancé des tests A / B sur les utilisateurs. L'icône du scanner (capture d'écran ci-dessous) a été montrée au groupe de test, mais pas au groupe de contrôle.
Produit finalPour mesurer le succès, nous avons introduit la mesure du taux d'achèvement provisoire. C'est le temps entre le début de la modification d'un brouillon et la soumission d'un formulaire. La métrique doit montrer comment un lecteur de codes-barres aide les gens à remplir des formulaires. Le test a duré plusieurs semaines et les résultats ont été très agréables. Ils sont parfaitement cohérents avec notre hypothèse d'origine.
Le temps de réalisation du brouillon a diminué de 30% pour un flux avec un lecteur de code-barresRésultats du test A / BNous avons également ajouté un profilage pour évaluer l'efficacité de tous les types de scanners. Comme prévu, la plus grande contribution a été apportée par Zbar (53% des scans réussis), puis notre bibliothèque C ++ (34%) et, enfin, la bibliothèque JavaScript avec 13%.
Conclusion
L'expérience de la mise en œuvre de WebAssembly est devenue très informative pour nous. Les ingénieurs sont très heureux de l'émergence de nouvelles technologies et souhaitent immédiatement les expérimenter. Si la technologie est également utile pour les clients, c'est une double joie. Reprenons la pensée exprimée au début de l'article. La technologie évolue à un rythme très rapide. Chaque jour, quelque chose de nouveau apparaît. Mais seules quelques technologies comptent pour les clients, et WebAssembly en fait partie. Notre plus grande conclusion de cet exercice est de dire «non» dans 99 situations et «oui» dans le seul cas où c'est vraiment important pour les clients.
À l'avenir, nous prévoyons d'étendre l'utilisation d'un lecteur de codes-barres et de l'introduire du côté des acheteurs, afin qu'ils puissent numériser les codes de produits hors ligne pour les rechercher et les acheter sur eBay. Nous envisagerons également d'étendre la fonction à l'aide de l'API de détection de forme et d'autres fonctions du navigateur. Mais nous sommes heureux d'avoir trouvé le bon cas d'utilisation pour WebAssembly sur eBay et d'avoir appliqué avec succès la technologie dans le commerce électronique.
Un merci spécial à Surma Das et
Lin Clark pour leurs nombreux articles sur WebAssembly. Ils nous ont vraiment aidés à sortir de l'impasse plusieurs fois.