Je suis ingénieur chez ApeeScape depuis à peu près un an maintenant, travaillant sur le même projet de cadre WebRTC depuis que j'ai rejoint le réseau: Ondello , un service qui relie médecins et patients sur WebRTC . Pensez aux Hangouts Google+ pour la santé.
( WebRTC est une technologie qui permet une communication en temps réel via un navigateur Web. Le meilleur exemple, encore une fois, est Google+ Hangouts: sans applet externe, vous obtenez un chat vidéo en temps réel. Il y a une bonne rédaction Ici . )
Lorsque j'ai rejoint Ondello pour la première fois, j'ai été embauché comme Développeur senior Ruby on Rails , chargé de construire un service à partir de zéro. Aujourd'hui, nous sommes une équipe de plusieurs développeurs travaillant sur un système assez vaste et complexe.
Avec ce post, j'aimerais partager l'histoire d'Ondello. Plus précisément, j'aimerais parler de:
Comme je l'ai mentionné précédemment, Ondello est tout au sujet de la plate-forme WebRTC. Mais, seulement Chrome, Firefox et Opera prennent actuellement en charge les appels WebRTC sans l'utilisation d'un plugin. Notre objectif était de prendre en charge tous les navigateurs (Safari et Internet Explorer sont les omissions évidentes dans la liste ci-dessus) et, à ce titre, nous avons dû utiliser un plugin qui était relativement jeune.
Quand j'ai commencé à travailler avec le plugin, les choses se sont bien déroulées car ils avaient une très bonne documentation et des tutoriels et guides WebRTC officiels. Mais à mesure que notre produit se développait et que nos exigences devenaient de plus en plus complexes, les choses ont empiré. Ce n’était pas aussi simple que de résoudre les problèmes de Rails.
Comme WebRTC est une technologie quelque peu récente et que ce plugin en particulier est assez nouveau (toujours sur invitation uniquement avec des frais d'utilisation raisonnablement élevés), ils n'ont pas attiré une tonne de développeurs, sans parler des développeurs WebRTC Rails pour écrire des guides et des tutoriels pour les gens. comme moi. Ces facteurs endommagent gravement la communauté de développeurs qui l'entoure, qui est essentiellement inexistante.
Je n’avais jamais considéré cela comme un problème majeur, jusqu’à ce que je l’ai manqué. Pour la plupart des plates-formes d'applications et des technologies, les cas généraux sont faciles à gérer, mais faire fonctionner les choses de manière très spécifique dans un délai très précis - cela nécessite une connaissance approfondie de la technologie ou accès à d'autres développeurs.
Imaginez la programmation dans un monde sans StackOverflow - dans quelle mesure votre productivité serait-elle entravée?
Bien sûr, nous avons eu accès aux développeurs du plugin, qui ont été aussi utiles que je pouvais m'y attendre. Cela a permis de résoudre certains problèmes, mais ce n'était pas la même chose que de simplement rechercher sur Google 'Le plugin WebRTC foo ne fonctionne pas en raison de la barre' .
Chaque logiciel comporte des bogues.
Mais dans le cas de ces nouvelles technologies WebRTC, il était difficile de savoir qui était le père et qui était l'enfant. En d'autres termes: lorsque nous avons trouvé un cas de test ayant échoué ou un bug apparent, il n'était pas clair si nous étaient en faute, ou s'il y avait un bogue dans la base de code que nous exploitions.
Ce qui pouvait être facilement recherché sur Google pour la plupart des technologies est devenu une énorme chaîne de messagerie suivie de révisions de code et, dans certains cas, d'une conférence avec les développeurs WebRTC.
Ce qui pouvait être facilement recherché sur Google pour la plupart des technologies est devenu une énorme chaîne de messagerie suivie de révisions de code et, dans certains cas, d'une conférence avec les développeurs.À ce sujet, je dirais que nous avons eu un taux de bogues d'environ 50 à 50 en raison de l'équipe de développement du plugin et de la nôtre.
Une autre conséquence de la relative petite enfance de ce plugin WebRTC est le taux de mise à jour . Les logiciels les plus récents sont mis à jour plus fréquemment et ces mises à jour sont souvent interrompues. Avec le plugin, nous ne pouvions pas continuer à utiliser des versions plus anciennes (en tant que technologie de télécommunications, tous les utilisateurs devaient utiliser la même version pour communiquer entre eux), donc chaque version nécessitait une refactorisation.
Ces mises à jour ont été douloureuses. Souvent, nous avons un code stable qui a dû être complètement réécrit pour se synchroniser avec les dernières modifications. Dans certains cas, les tests échouent sans explication - et s'il n'y a pas de communauté, vers qui demander de l'aide?
Dans certains cas, les tests échoueraient sans explication - et s'il n'y a pas de communauté, à qui vous adresser pour obtenir de l'aide?Au fur et à mesure que notre produit se développait, la plupart de nos clients ont commencé à poser des questions sur l'assistance mobile.
Si la bibliothèque JavaScript WebRTC était difficile, alors la bibliothèque Android l'était doublement. Il m’a fallu deux jours pour compiler l’exemple d’application et plus de cinq heures pour comprendre comment cela fonctionnait. L’ensemble du processus a donné un nouveau sens au mot «douloureux».
Après 10 heures de compilation infructueuse, j'ai eu une dépression nerveuse et j'ai pleuré un peu. En me ressaisissant, j'ai pu faire fonctionner les choses après deux heures de plus. Pff — et Obama dit que vous devriez créer vos propres jeux vidéo .
La bibliothèque WebRTC iOS était plus simple et l'équipe de développement y avait clairement passé plus de temps. Nous avons pu le mettre en œuvre en seulement quelques heures.
Au-delà du plugin WebRTC, notre base de code JavaScript m'a beaucoup appris sur la complexité. Comme la plupart des frameworks WebRTC sont basés sur JavaScript pour la configuration (par exemple, Framework Web de Plivo pour la VoIP ), c'était la seule langue que j'ai utilisée pendant mes trois premiers mois à Ondello.
Et à mesure que notre base de code se développait, elle devenait naturellement de moins en moins gérable. Nous avions des rappels profondément imbriqués, une mauvaise modularisation, et plus encore - c'était la première fois qu'une startup avait une application JavaScript WebRTC et, comme vous pouvez vous en douter, c'était un peu compliqué.
Finalement, nous sommes passés à CoffeeScript . Cela a réduit le Taille de notre base de code et augmenté son lisibilité de manière significative, mais cela n’a pas été suffisant pour résoudre nos vrais problèmes de complexité.
Ensuite, nous avons trouvé PubSub , une merveilleuse bibliothèque de publication / abonnement pour JavaScript que je ne saurais trop recommander. Ce petit gars nous a aidés à découpler une partie importante de notre logique JavaScript; notre processus de refactoring a pris un virage pour le mieux avec sa découverte.
Pourquoi PubSub était-il si utile? WebRTC est intrinsèquement lié aux médias et aux connexions, et regorge donc d'événements. Avec PubSub, nous pourrions facilement surveiller certains événements à un niveau d'abstraction élevé. C'était une solution merveilleuse et un excellent exemple de ne pas résoudre le problème résolu: lorsque vous avez des solutions Open Source (ou même propriétaires) bien écrites et bien documentées qui simplifieront votre base de code et accéléreront le développement, Utilise les .
Pour être plus précis: sans PubSub, chaque fois que la caméra d'un utilisateur s'éteignait, nous devions mettre à jour trois cases à cocher qui représentent l'état de la caméra:
camera_went_off = function() { $(''#checkbox1').removeAttr('checked'); $(''#checkbox2').removeAttr('checked'); $(''#checkbox3').removeAttr('checked'); }
Avec PubSub, je pourrais simplement déclencher l'événement «camera_went_off» et faire en sorte que les trois cases à cocher l'écoutent. De plus, si quelqu'un cliquait sur l'une de ces cases à cocher, il pourrait également publier cet événement pour informer les autres cases de se mettre à jour.
Comme mentionné précédemment, nous utilisions un plugin WebRTC pour prendre en charge un plus large éventail de navigateurs. Mais ce plugin doit se charger chaque fois qu'un utilisateur charge une nouvelle page. Cela peut avoir de terribles implications sur les performances, la fluidité, etc.
La seule réponse était de garder le plug-in chargé dès que l'utilisateur accédait au site et de s'assurer que l'utilisateur ne rechargeait pas ou n'entrerait pas sur une page Web différente. Cela semble impossible. Mais en fait, cela peut être accompli avec un application d'une seule page (SPA).
À ce point, AngularJS est entré en jeu.
Avec Angular, nous sommes passés à un SPA. Lorsqu'un utilisateur est entré sur le site, il a chargé le plugin une fois - et une seule fois. Les gains de performances ont été instantanés.Angular nous a permis de construire un SPA, ce qui nous a permis de charger le plugin une fois (lorsque l'utilisateur est entré dans le système) et une seule fois. Ensuite, tout appel effectué par l'utilisateur serait presque instantané, car le plugin serait déjà chargé. Cela a demandé beaucoup de travail, mais cela a porté ses fruits: les gains de performance ont été instantanés.
Angular a également amélioré notre code JavaScript dans son ensemble en imposant un MVC structure. Bien que la plupart du JavaScript ait dû être réécrit pour s'harmoniser avec le motif angulaire, c'était une entreprise qui en valait la peine.
Nous avons rencontré des problèmes de complexité similaires avec notre CSS: la modularisation n'était pas tout à fait correcte, nous avions des styles qui se chevauchaient, etc. Il ne serait pas juste de dire que notre base de code était massive par rapport à beaucoup d'autres systèmes, mais en tant que petite équipe travaillant dans une startup: 1) le temps est essentiel et 2) l'organisation est la clé.
La clé pour réduire la complexité avec notre CSS était l'utilisation de Toupet et Boussole .
La première fois que j'ai utilisé Sass, je n’étais pas très content. Mais aujourd'hui, je ne peux pas imaginer la vie sans elle. En bref, Sass est un langage d'extension CSS qui vous permet d'écrire des feuilles de style dans la syntaxe Sass et de les compiler en CSS.
Sass de nombreuses fonctionnalités spectaculaires: variables , directives de contrôle , SassScript en général, et plus encore. Mais ce qui m'a vraiment convaincu, et ce qui a vraiment fait une énorme différence pour Ondello, c’était Sass règles imbriquées .
Celles-ci sont mieux illustrées par l'exemple. Sans Sass, je pourrais avoir du code CSS qui ressemble à:
.container_div { float: left; height: 10px; width: 20px; } .container_div a { margin-left: 15px; }
Mais avec Sass, cela peut être simplifié à:
.container_div float: left height: 10px width: 20px a margin-left: 15px
Dans cet exemple trivial, je n'ai enregistré que quelques lignes. Mais imaginez si j'ai un code CSS au niveau de l'industrie qui pourrait être exprimé avec Sass comme:
.admin-section-menu width: 270px float: left margin-right: 8px padding-top: 30px ul padding-right: 10px li width: 230px a float: left text-align: right letter-spacing: 1px font-size: 20px color: #666 width: 220px margin-bottom: 20px &.active a width: 230px color: #52672d &:after content: '25b8' display: inline position: relative left: 10px
Boussole est un framework de création CSS qui s'appuie sur Sass et nous a vraiment aidés dans la conception d'interfaces. Nous avons utilisé Compass pour nous aider à faire sprites —Il y a un excellent tutoriel Ici , si vous êtes intéressé.
Avec Compass, nous pourrions accélérer la création de boutons complexes. C'était aussi simple que de placer les états d'image des boutons dans un dossier, à quel point Compass générerait un sprite pour les contenir.
Dans cet exemple, Compass lit tous les fichiers du administration_buttons dossier et mettez-les dans un seul fichier de sprite.
@import 'administration_buttons/*.png' @include all-administration_buttons-sprites .add-user-button width : 37px height : 37px cursor : pointer float: right @include administration_buttons-sprite(add_user) &:hover @include administration_buttons-sprite(add_user_rollover)
Via le @include administration_buttons-sprite(add_user)
commande, j'ajoute le fichier add_user.png comme image de fond pour le add-user-button
classe.
Avec Compass, tout ce que j'avais à faire était de mettre des images dans un dossier.
Sans Compass, j'aurais dû:
Pour un développeur comme moi qui n'est pas particulièrement Photoshop-savvy , c'était un gain de temps énorme. Et, encore une fois, le temps est crucial à ce stade.
Après plusieurs mois de JavaScript et CSS, nous sommes finalement passés à notre back-end Ruby on Rails.
Les modèles de rails sont parfaits pour garder les projets simples car il y a une division très claire avec la structure MVC. Si votre système commence à se développer, les modèles Rails seuls peuvent être insuffisants. Au lieu de cela, vous devez réfléchir à de nouveaux moyens de haut niveau pour résoudre vos problèmes - de nouveaux moyens d'abstraction.
Nous avons tous étudié les modèles de code, les idéologies, les tutoriels, les guides, etc. Nous savons tous comment diviser votre logique en classes et vos classes en fonctions et tout cela. Mais on nous apprend rarement solutions . Je n’ai jamais lu de livre à ce sujet et je n’ai jamais vu de cours à ce sujet.
Après avoir travaillé avec Rails pendant un certain temps, j'ai commencé à voir que le problème n'était pas le code, le problème était la solution pour résoudre le problème du client.
Retour à WebRTC pour Ondello: à titre d'exemple spécifique, nous avions un système de messagerie très simple construit sur Rails. Pendant un certain temps, cela a bien fonctionné pour nous. Mais finalement, nous avons eu besoin d'un type spécial de courrier électronique pour chaque client. Au fil du temps, les changements entre les e-mails ont commencé à devenir de plus en plus importants - à la fin, chaque client avait besoin d'un e-mail totalement différent.
Si votre système commence à se développer, les modèles Rails seuls peuvent être insuffisants. Au lieu de cela, vous devez réfléchir à de nouveaux moyens de haut niveau pour résoudre vos problèmes - de nouveaux moyens d'abstraction.J'ai commencé à voir qu'au fur et à mesure que ma base de code augmentait, ce type de fonctionnalité aurait un impact énorme sur l'ensemble de mon framework WebRTC et de mon système de messagerie. C'est à ce moment-là que nous avons décidé de créer un projet distinct uniquement pour le système de messagerie, chargé de gérer tous les types de messages. Le projet principal enverrait simplement (via DU REPOS ) certains paramètres et un identifiant client. Ensuite, le système de messagerie prendrait en charge l'assemblage et l'envoi des e-mails.
Cette approche, celle de diviser le projet en différents projets, a été utile lors du développement d'Ondello. Cela a permis au projet principal de rester simple et exempt de responsabilités inutiles.
Ce type de résolution de problèmes est ce que j'appelle un approche de solutions . Je trouve cela essentiel pour développer des applications complexes.
Peu importe si vous êtes un développeur Ruby, Java ou PHP, en matière de développement Web, il y a tellement de frameworks et de technologies, tellement d'outils différents que vous pouvez ou devriez utiliser pour faire fonctionner votre système, que dans mes yeux, c'est dur de voir n'importe qui comme juste un programmeur «Ruby» ou un programmeur «Java».
En ce qui concerne les gros systèmes, vous devez concevoir des solutions bien conçues qui répondent aux besoins de vos clients et qui ne s’adapteront pas toujours à vos technologies préférées ou même aux technologies avec lesquelles vous êtes à l’aise. Le thème commun dans mon développement d'Ondello était que je devais être flexible et agile, en utilisant les technologies les mieux adaptées disponibles à tout moment, quelles que soient mes préférences.
En développant Ondello, je me suis souvenu que, avant tout, nous devons être des ingénieurs, résoudre les problèmes avec les meilleurs outils possibles et faire le travail de manière efficace, évolutive et pratique.