Tuomas Artman - Linear

Durée: 53m47s

Date de sortie: 31/07/2023

This week we have Tuomas Artman on from Linear. We talk about his background, building Linear, and the Linear Sync Engine. Linear is a modern issue tracking tool for software teams that want to build software better. It's characterized by its beautiful design, fast performance, and powerful features, including issues, projects, and sprints. Join us as we dive deep on how the Linear Sync Engine works and has evolved over time.

Become a paid subscriber our patreon, spotify, or apple podcasts for the full episode.

C'était l'une des études ici.
C'est pas...
C'est commencé avec performance, mais ça a été un sort de
secret source de la compagnie pour pouvoir évoquer ça rapidement
parce qu'on n'a pas besoin de faire toutes ces choses.
Hey, avant de commencer, j'aimerais vous rappeler que le tout épisode
est seulement disponible pour nos abonnés.
Les plateformes currentes que vous pouvez abonner
sont YouTube, Spotify, Apple et Patreon.
Et avec ça, on va commencer l'épisode.
Bonjour !
Bienvenue à l'Ontario de la devTools FM Podcast.
C'est un podcast de développeurs et des gens qui le font.
Je suis Andrew et je suis mon co-host, Justin.
Salut tout le monde !
Je suis vraiment, vraiment excité d'avoir Tommas Artman
sur l'Université.
Tommas, c'est un plaisir !
On a eu l'occasion de l'an dernier, l'épisode 44,
qui est vraiment fun.
Je suis excité d'avoir parlé de la Cink Engine,
qui est, je pense,
un des deux features complétants de l'Université
et aussi, un topic d'interessage technologique.
Mais avant de nous le dire,
pouvez-vous nous parler un peu plus de vous-même ?
Oui, bien sûr !
Je suis Tommas, si vous voulez le prononcer correctement.
Je ne peux pas, je vais à Tommas,
à n'importe quel point dans le monde.
Je suis un ingénieur de Hard's.
J'ai commencé ma career en 1996
en faisant des presentations sur la CDRM,
pour des clients de BigCulper ici en Finland.
Si vous avez eu un Nokia Phone,
que j'ai utilisé pour les instructions
et pour les applications que j'ai utilisé,
ce sont des chances,
ou même moi,
en fin de jour.
Et le intérieur est arrivé rapidement,
après 1996,
donc j'ai trouvé un couple de bonnes agences
avec mes amis,
en faisant des flash, des animations et des campaigns,
et ensuite, en faisant des web-agences,
et ça m'a pris 9 ans
pour comprendre que ce n'est pas vraiment ce que je veux faire,
avec ma vie.
Je pense que c'était un projet Nokia
qui m'a fait re-thinker ma vie.
Nous travaillions pour Nokia sur les witsets,
qui était un des plus grands services mobiles
dans le monde.
Et c'était la agence des designs.
J'ai travaillé sur le projet pour deux ans,
et ils m'ont juste arrêté,
parce qu'ils n'aient pas de savoir comment faire le ménage.
C'était la motivation pour moi
de re-thinker les choses
et de prendre le contrôle
de ce que je travaille sur.
Je me suis rendu compte
que je n'ai pas de la chance
de faire des startups en Finland
et de changer de chien en une année.
On voulait toujours
aller en train de faire un tour avec ma vie.
Et ça n'a jamais été possible
parce que je n'ai pas de la chance
et je suis venu à Shanghai
pour un an,
faire des jeux, des toits
et des animations pour le marché local.
Un petit startup
de 250 personnes,
c'était bizarre.
J'ai vraiment été en Chine.
La culture est super intéressante,
mais professionnellement,
peut-être, c'est assez.
Et ensuite, j'ai eu la possibilité
de changer de chien en Chine,
de rejoindre Groupon,
qui m'a bien sûr pris comme un ingénieur.
Ça n'a pas vraiment pas été un Groupon
ou quelque chose d'autre.
J'ai été à Silicon Valley
et c'était génial.
J'ai spent deux ans
en construisant un point de sale
pour les restaurants de la Chine.
Groupon n'était pas vraiment
l'ingénieur de Powerhouse
que j'ai voulu,
donc quand j'ai mon carré,
j'ai pu se sélectionner
où j'ai vécu à Tiberk.
J'ai sélectionné à Eber.
J'ai spent cinq ans
sur le plate-dame mobile
à Eberk.
J'ai essayé de scaleur de mobilisation.
Quand j'ai rejoint,
nous étions 15 mobilisateurs
à Eberk,
et quand j'ai sauté, nous étions 400.
C'était un très grand tour.
En voyant le hyper-grove,
en apprendre que je ne veux pas
aller à hyper-grove encore.
Et après Eberk,
nous avons commencé à l'inner,
à aller avec Kari and Jorri.
C'est un très petit intro
dans ce que j'ai fait.
Dans mon temps personnel,
je ne fais pas beaucoup.
J'ai une famille avec deux enfants
et je fais des pilotes glataires.
Je vais aller à la semaine
quand c'est bon à l'extérieur.
C'est drôle.
Comment était l'expérience
de scaleur à Eberk?
Comment a-t-il fait votre temps en ligne?
Comment est-ce que l'approche,
comment on va faire le hiring
et tout autre, est...
C'était une bonne expérience.
C'est bien de l'enlever.
Mais je ne sais pas si
il y a des problèmes
dans lesquels on a des problèmes.
Mais je pense que
Kari a pu faire
quelque chose
dans les années de l'Aire BNB
pour certainement
les mêmes choses.
Le problème avec la scaleur
est que quand
vous avez


un produit que vous ne savez pas
si vous allez trouver un marché productif,
vous essayez tout.
Vous ne vous inquiétez pas
de l'engineering,
de la technologie que vous travaillez.
La architecture est probablement
un total de crate.
Et tout ce que vous faites
est de l'enlever.
Et puis vous vous faites
le marché productif.
Et maintenant vous êtes en train de
aller avec quelqu'un d'autre
et vous avez besoin de scaleur rapidement.
Parce que si l'autre company
vous a pas le droit de l'enlever.
C'est la même chose qui s'est passé
avec Uber.
La architecture
qu'ils avaient était
vraiment craquante.
Tout le service s'est passé
tout le temps.
Et quand la vie s'est annulée,
c'était vraiment
de la fierté pour deux ans.
Je pense que ce n'était pas
sur le côté de l'arrière,
mais je vois
comment tout le monde
se dévouait.
Parce que,
pour deux ans,
c'était juste
une semaine après une semaine,
ils ont rencontré des problèmes
qu'ils avaient à fixer
pendant que tout le monde s'est créé.
Et après deux ans,
ils avaient suddenly
2000 ingénieurs.
Tout le monde s'est dévoué,
tout le monde s'est dévoué,
tout les équipes
ont été dévouées.
Et puis,
la vie s'est annulée.
Donc,
ils avaient un petit peu
de s'entraîner.
Et puis,
ils ont réalisé
que tous ces ingénieurs
ont été élevés,
parce qu'ils ont besoin
de la vie.
Ils n'ont rien
dans les termes d'inter structure,
parce que tout le monde
a été mis en place.
Et maintenant,
il y a un projet de
« let's redo everything,
let's start from scratch
and figure out what we actually
want to build in the next
four years »

c'est-à-dire ça.
C'est comme quand je suis
là,
quand je suis là pour l'année
plus tard,
pour voir mon équipe
de mon patron,
ils étaient toujours
en train de travailler
sur les mêmes choses
que j'ai commencé.
C'est
comme
un peu
fou,
que beaucoup de temps
se fait en
hypergrove.
Ça
fait certainement
que ça fait sens
pour beaucoup de entreprises
et Uber ne devrait pas
faire tout ça
différemment.
Si vous avez un
product,
c'est-à-dire
que vous ne savez
si vous allez
trouver des consommateurs
ou des clients,
oui,
ça ne fait pas
sens
pour la architecture,
mais le
fait que nous étions
en ligne,
c'était différent.
Nous savions
que le segment

était là,
et que le marché
était là.
Nous pensions
que nous serions
très heureux





sur
si nous pouvons
construire quelque chose
mieux que ce qu'il y a
là-bas.
Nous
avons
pris le temps
pour
construire
l'infrastructure
et
faire sure
qu'on peut
construire
l'infrastructure
de la GEDCO.
Et
depuis qu'on a
la même philosophie,
on ne veut pas
trop
trop trop plus
et nous serons
super
strictes
pour le
acheter.
Nous voulons
dire non
jusqu'à
trouver
quelqu'un
qui nous
est super
très heureux.
Et
jusqu'à
vraiment
avoir besoin
d'un certain
point.
Par exemple,
sur le site
de l'infrastructure,
nous
construisons
l'infrastructure
avec 3
personnes.
C'est moi
et les 2
personnes
qui travaillent
sur
l'infrastructure.
Nous
pensons
que
en fin de
année,
nous
avons
tout le temps
à
l'infrastructure.
Vous
pouvez
toujours
optimiser,
faire
plus
de

et
augmenter
l'expérience
de la GEDCO.
Nous
pensons
que nous serons
de la
grande
coiffeur
de l'année
et que
il y a
2
personnes
sur le site
d'infrastructure
pour
les
lignes.
Nous
devons
faire
plus

lignes.
Pour
les
listeners
qui ne savent
que
lignes,
pourquoi
ils ont
une




commençons
par
lignes.
Nous
voulons
faire
plus
de
lignes.
Nous
voulons
faire
plus


Nous



de lignes.
Nous
voulons
бес

płid
toca
les startups sont souvent super vocales pour lesquels ils veulent.
Ils sont facile à parler et ils vous donnent des réponses tout le temps.
Mais l'idée était de s'y gratter, comme les startups se produisent.
Donc, ils ont des besoins en termes de software,
pour qu'ils puissent construire un meilleur software.
Donc, en temps, nous avons fait le product footprint largeur
et sorti de l'échec de l'assistance de l'assistance de l'assistance
pour être un soutien de l'adaptation de l'adaptation de l'adaptation.
A l'âge de students,
et car on veut construire un souy habituel
d'une rigol jeopardisé pour le enhances une jete destäure d'appau Reason d'in ICI.
Fquest Creative
pour vous. Donc, construire un engine de sink où vous pouvez, comme, travailler en ligne ou,
ou, plus important, obtenir les updates optimistes que, comme Jory m'a mentionnée, est un problème non
réveillant technique, pour s'y battre, surtout quand vous êtes juste en train de commencer un produit.
Donc, pourquoi avez-vous fait cette décision et quel esprit de bénéfice avez-vous donné?
D'initialement, nous n'avons pas fait ça pour les raisons que nous voulons maintenant continuer à utiliser.
Initialement, l'idée était simplement de performance.
Nous n'avons jamais voulu faire le produit en plein état. Ce n'était pas l'intention.
Il s'est passé que ça fonctionne en plein état, si vous voulez l'utiliser.
Mais ce n'était pas l'intention. Nous pensons que les gens seraient connectés à la plupart du temps.
Nous avons pu construire une application très performante.
Et c'est initialement comment nous avons commencé à regarder dans l'engin de sink.
J'ai eu un peu d'expérience avec l'engin de sink, comme ceci est mon 4e, que je sais, que je l'ai déjà écrit avec Leonard.
Donc, je savais que ce que je voulais faire.
Et je n'avais jamais, vous savez, à groupe, le engin de sink est toujours en place, donc ça fonctionne.
Et ça a été aussi en ligne.
Donc, on a pu prendre des cartes créatives et prendre des ordres pendant que vous étiez en ligne et puis les éloigner.
En même temps, on a pu réagir les activités.
Mais je n'avais jamais, avant Leonard, construit une application très compliquée et compliquée sur sink.
Mais j'ai toujours l'idée que sink a fait, comme, optimiser le workflow de développement,
en faisant cela plus facilement pour construire les applications.
Parce que si vous avez le sink en place, avec un peu de technologie de la technologie,
ce que vous avez à l'aise est essentiellement un client local.
Vous avez une structure de data qui, de toute façon, est synchronisée à votre computer local,
d'une ligne d'index, ou d'une même en même temps.
Et tout ce que vous avez besoin, comme un ingénieur producteur,
vous avez besoin d'y manipuler cette structure de data local et tout le reste vous aurez à attention.
La synchronisation et les aspects de l'application sont vraiment un issue non-pensé,
car cela ne importa pas si vous faites ces changements ou quelqu'un d'autre sur la nette.
Si le sink en est juste un update de votre structure de data, comme, votre UI va juste se placer et le update.
Cela vous lead à avoir de la fonction de la fonction de l'application,
et que la fonction de l'application ne va pas se placer.
Et si vous vous gardez contre cela, il y a peut-être quelques cas où ils vont se placer,
ou que votre data va être update, si ça se plait.
Mais la plupart du temps, 99,9 % de toutes les opérations vont juste aller en place
comme ils sont appliqués sur le service.
Et le client va faire la validation et faire sure que le data soit correct
quand il a été envoyé comme une transaction pour le sink engine.
Donc, il y a un grand nombre de problèmes que vous pouvez prendre de l'engineer.
C'était la réalisation.
On ne commençait pas à construire le sink engine parce que nous voulions
envoyer des features plus vite, mais on a déjà réalisé très vite
que c'était le point principal qu'on a pu faire.
On a bien sûr obtenu la performance pour le client,
mais on a également pu pouvoir faire la fonction de la fonction de l'application
et juste interpréter le producte très rapidement
parce que vous n'avez pas à penser à la fonction network
ou à la fonction de la fonction de l'application,
ou à la fonction de l'application de l'air,
ou à l'étranger de l'exemple de l'alimentation,
vous avez votre structure de données locales, vous faites des changements,
et c'est tout.
C'est un modèle simple de construire des applications
que je ne pense pas que je ne voudrais qu'il y ait de retour à tout autre.
Il se lance, évidemment, à seulement des aspects de l'application,
si vous avez une app avec des tonnes de données,
vous ne pouvez pas mettre tout en place,
et il faut avoir un aspect de collaboration,
car ça ne fait pas du tout le sens de mettre tout en place
et de faire une synchronisation.
Mais si vous avez un set de données finie
dans votre workspace et que c'est collaborative,
je ne pense pas que je ferai de tout autre que ça,
que de là ou de là.
Vous avez mentionné que c'est votre 4e synchronisation,
c'est beaucoup de synchronisation.
Vous diriez que la différence entre l'envers synchronisation
et les plus anciens est la scope,
mais dans les dernières,
il semble que les deux features sont peut-être
seulement les deux,
mais avec l'envers,
tout le data est dirigé par cette synchronisation.
Non nécessairement.
La scope, dans le cas où nous avons beaucoup d'abus,
nous avons beaucoup de données dans le client.
Mais pour vous donner une idée de ce que j'ai construit avant,
mon 1er synchronisation était dans Jaina.
Quand je travaillais pour une company de jeu,
ils avaient un portail de jeu,
et ils se sont créé des flashs,
et des games Unity.
Et les plus grands,
ils voulaient créer des games de game de game.
Et c'est...
En fait, c'était assez difficile.
Les units n'avaient pas de bons servers multi-use,
qui ont utilisé beaucoup de services,
car ils ont construit tout pour vous.
Mais nous n'avons pas.
J'ai créé mon 1er synchronisation,
qui avait un client flash et un client Unity.
Et c'était essentiellement
là pour un jeu synchronisé.
Donc, des locations de temps réel
pour les utilisateurs,
pour interpréter les updates sparse,
cela pourrait travailler avec un netwerk slow,
et cela pourrait prendre
quelques hiccups en latence de network,
car le netwerk en Chine n'était pas très grand,
comme vous l'avez toujours créé,
un ping de 600-700 milliseconds,
pour le service.
C'était mon 1er,
une petite harine avec des utilisateurs de max16
qui se sont connectés à l'autre,
et qui ont donné des updates de propres
de la location de la base.
En groupant,
j'ai créé un client objective C
et un client de note de la back-end.
C'était beaucoup plus suffisant,
mais j'ai créé un client en un style
de manière très hacky.
Je ne pensais pas que je serais un bon engineer
quand j'ai créé le Coupon,
donc j'ai fait tous les erreurs,
pas de test unitel sur tout ça,
et c'était en javascript,
non plus,
donc, pas de type-safety,
à tout le monde.
C'était un peu
unstable à la fois.
Je pense que
peut-être qu'on l'a réveillé,
mais je me souviens
de la croire
qu'ils vont encore le faire.
C'était
synchronisation,
l'état entier de
votre POS entre un restaurant.
J'ai travaillé sur Bracgram,
un point de vue pour les restaurants de la haute,
mais il y avait plusieurs iPads,
il y avait des cartes de crédit,
il y avait des cartes de crédit,
et c'était important
que quand tu as
pris un carton de crédit,
tu n'auras pas de double charge,
donc les iPads ne devraient pas être en sync.
Et
c'était très similaire
à ce que
l'envers de la machine, mais un peu plus suffisamment
et il y avait des règles
sur qui on peut aborder ces objets,
parce que c'était important
pour retrainer
l'accès à un objet,
pour exemple, pour le billet,
avant de charger.
C'était un version plus compliquée,
et
à un point, le vignette de la machine
s'est utilisé
pour une autre iteration.
En entre,
j'ai pris un vignette de la machine
pour Uber,
mais c'était

comme l'un des produits en New York,
un peu de trial, mais on avait
des ambitions pour ça,
mais je pense que c'était un peu trop tard,
l'OMG s'est peut-être


很关神 ни

j'ai Vu une
cuisine à manger.
Je sais comment fixer ça et comment construire une meilleure version.
Donc construire un Sync Engine, c'était un petit équipe de gens qui ont construit ça.
Il y avait un go-back end, un Swift client, un Android client et un JavaScript client.
Donc trois clients, parce qu'on avait l'intention de bouger tout à l'auberage sur le Sync stack.
Nous étions dans le processus de faire le schema de données,
parce qu'il y a des aspects que vous avez besoin pour faire le works.
Et à ce point je n'ai pas compris que le hall de vue est trop fort,
il y a trop de gens qui n'ont pas pu forcer ça à personne.
Et il n'y a vraiment pas de casque pour les engineers de la back-end,
pour les prendre et beaucoup de gens n'ont pas compris pourquoi je faisais ça.
C'était une battle à l'alpil et j'ai commencé à faire des choses d'autre,
le mobile platform a été formé et j'ai commencé à faire ça.
C'était peut-être un peu tard pour la fête, si j'avais rejoint un an plus tard,
il y avait un Sync Engine dans les clients de l'Aber, et ça aurait été beaucoup mieux.
Ça a été 4 ans pour les concepts de tous les concepts,
pour faire ce petit ping, et en fin de l'an,
faire une réelle connexion de temps en réel,
et de la service pour les clients, c'était très léger et très brit,
ils n'ont pas pu avoir utilisé le Sync Engine.
Ça a été étendu, je pense que c'est encore là,
c'était par exemple Chetstream, si vous voulez avoir un look,
il n'y avait pas de fully développé, mais il y avait 3 clients de NAS.
Alors, je n'ai pas fait web engineering pour l'âge,
j'ai juste fait mobile engineering,
la première chose que j'ai voulu, c'est de construire un autre Sync Engine,
et maintenant sur un full web stack,
parce que je n'ai pas utilisé ça pour un moment,
et je n'étais pas obligé de essayer de voir comment la chaine s'est évoluée,
et comment rapidement vous pouvez venir avec le Sync Engine.
Et ça m'a pris une semaine, et j'ai eu un Sync Engine
sur le coach base, je pense, c'était la première implementation
sur le bas-de-bord, et ça a été incroyable pour le projet.
Il n'y avait pas vraiment de tracteur issu
que j'avais voulu faire, ou des management du projet.
Je pense que Jorri savait toujours que le tracteur issu
était un espace qui était en attaque,
et ça a été un moment pour comprendre
qu'on ne travaille pas vraiment sur le tracteur issu,
mais qu'on veut aider les entreprises à s'adresser à la construction des softwares.
mais je suis très excité à la technologie,
et à construire un GENGINE.
C'est génial.
La technologie a évolué beaucoup de temps,
juste la recherche a évolué beaucoup de temps.
Il y a beaucoup plus de répliquations de CRDT,
donc je pense que l'automarche peut changer ces jours.
Vous avez mentionné le CouchDB,
mais vous avez vraiment dû faire un peu de custom ?
Oui, nous avons fait construire tout.
Il n'y a rien à faire avec le GENGINE.
Maintenant, nous commençons à utiliser le YJS
pour le dernier outil qui n'a pas été réel,
qui est une édition d'édition ou d'édition de documents.
Nous allons maintenant mettre ça en place.
On va l'avoir en place,
pas bientôt, mais bientôt.
Mais, à part ça,
le premier outil était avec le coach,
le coach d'OB, pour avoir quelque chose à faire.
Il y avait des problèmes très rapidement.
Le CouchDB était un contrôle access,
ce n'était pas un contrôle access,
le CouchDB, à l'époque,
était vraiment décédé pour synchroniser les settings pour un utilisateur.
Ce n'était pas pour un environnement multi-usage.
Le deuxième outil était sur le Firebase.
Le Firebase aurait probablement travaillé bien,
mais j'ai fait des calculations en tant que
anticipateur, des comptes d'utilisation,
de la nombre d'updates,
de la qualité de la date,
et ça aurait pu coûter beaucoup de monnaie
pour nos intentions sur comment nous voulons manipuler le data.
Je pense que j'ai toujours l'intention de construire un custom,
parce que j'avais déjà fait 3x4,
tous ces sont des implementations customes.
Je n'étais pas vraiment fiers de commencer,
et de ne pas faire des choses contre quelqu'un,
comme si nous avons eu le temps,
et nous avons toujours travaillé sur nos jours,
nous avons pu faire des choses sur le côté,
et nous avons construit quelques prototypes.
Je pense que, aujourd'hui, si j'ai commencé,
je ne sais pas ce que je ferais.
Je pourrais probablement commencer avec une solution de la chelonne,
mais je pense que je ferais des problèmes,
à un moment, qui me sera pas réglé à un custom.
Si vous pensez à ce que nous avons fait à l'inertité,
pour optimiser l'adaptation des utilisateurs
dans l'application,
à ce que nous envoyons un start-up,
à ce que nous n'allons pas envoyer un start-up,
à ce que nous nous dédiculons tous ces problèmes,
que les solutions ne sont pas offertes,
ou elles ne sont pas vraiment offertes,
parce que ce sont vraiment customes pour notre application.
Il n'y a rien de généré que vous pouvez mettre en place
afin de créer une solution de la chelonne
qui ne fonctionne pas avec d'autres applications.
Peut-être que, à un moment, quelqu'un va faire le bon travail,
mais ils auraient probablement
un peu de stables sous leur bale,
ils ont vu tous les problèmes
afin de pouvoir anticiper ces problèmes.
Je ne pense pas que les solutions
qui sont maintenant, aujourd'hui, ne fonctionnent pas avec l'inertité.
Oui, à la curiosité.
Il y a l'engine,
qui est la solution comprehensive,
et il y a beaucoup de logiciel business
sur ce que vous portez à l'aise
et comment vous vous dédiculez les conflits.
Et beaucoup de ce genre de choses.
Mais il y a aussi une structure de data,
est-ce que vous utilisez les CRDTs pour ça,
ou est-ce que vous utilisez un structure custom,
une structure custom sematique
pour se dédiculer avec des conflits et des choses ?
Tout est custom, comme je l'ai dit.
Donc, il n'y a pas de CRDTs.
Les opérations que vous faites sur l'inertité,
les CRDTs ne l'entraient pas.
Les opérations atomiques,
si vous changez la priorité d'un problème,
c'est à dire ce ou ça.
Il n'y a pas de merging.
L'un de les merges est la dernière.
Si vous l'avez dit,
le deuxième personne vient après ça,
et le deuxième personne l'a gagné.
Il n'y a que quelques ressources
qui ont un input textuel
où vous pouvez utiliser les CRDTs
pour faire des résolutions de conflits.
C'est ce que nous mettons en place.
Nous faisons ça en addition.
Donc, si vous avez édité
la description d'un problème ou un projet,
pour trois ans, nous avons dit,
« On a vraiment besoin de fixer ça »
parce que nous ne sommes pas confortables
avec la solution que nous avons,
mais c'est comme si vous l'avez évoqué localement,
et que si vous ne faites pas attention
du secteur textuel,
il va être réveillé
et ne s'est pas réveillé
si quelqu'un d'autre n'a été évoqué.
Ce qui est horrible,
parce que vous pouvez faire des réveils
et vous pouvez en faire des réveils
pour donner une indication
que quelqu'un d'autre
peut être édité en même temps.
Mais vous pouvez encore plus facilement
dévoiler des réveils.
Mais ça n'est pas encore possible.
Juste comme dans un trac,
il n'y a pas que beaucoup de gens
qui vont évoquer un problème
en même temps,
pour que vous puissiez réveiller
la description de ce problème.
Ce n'est pas un problème.
On veut toujours le fixer,
parce que nous pensons
que l'édit de ce problème
serait un bon expérience.
Mais ça a été
sorti
parce que nous avons
des choses plus importantes
mais maintenant, on va le faire.
Nous voulons utiliser l'édit
pour des problèmes
où nous sommes anticipés
que beaucoup de gens
vont éditer en même temps.
Nous avons besoin d'un bon éditor.
Nous avons l'équipe d'un tout
et nous avons besoin de faire des édits
en même temps.
Et nous voulons voir que
ces problèmes sont parfaits.
Mais tout autre,
la structure de la date
qu'on a,
c'est juste
un tricot
de data,
d'objets JavaScript.
Nous faisons
un peu de travail
pour
mettre ce tricot
ensemble.
Si vous avez
écouté
mes deux talks
que j'ai fait sur le Sync Engine,
je vais vous donner
un peu d'idée
de comment ça se passe.
Vous avez des objets individuels
comme tous les objets model
c'est juste un objet
qui est envoyé.
Et
les décorateurs
sur les classes
qui représentent
ces objets modèles,
ils disent
où ils doivent être montés.
Donc, pour exemple,
un problème
va avoir une idée de team
associée
et un décorateur
qui dit
que ça devrait
aller dans l'issue des équipes.
Les collections.
Donc, quand vous recevez
cet objet,
le Sync Engine
va se voir
si on a déjà
l'aimé.
Et si on le fait,
ça va
aller dans l'issue
et ajouter
l'issue
dans l'issue.
Donc, ça built
ce fruit
en temps
que vous vous
réagissez
et c'est
ce que vous avez
pour le fruit.
Donc, vous pouvez
either
regarder
tous les objets
en Sync
comme objets individuels
qui sont
le Sync Engine.
Ou vous pouvez
construire un fruit
de modèles
de
ce que les
dégénères
utilisent.
Ou des
ingénieurs.
Donc, c'est
le
basic
de comment ça marche.
C'est comme
que vous avez
ce fruit de objets
qui est créé
dans un fruit
et qui est utilisé
pour
l'updater
l'UI.
Oui.
C'est un très
c'est
ce que ça marche.
Il n'y a rien
plus à l'autre.
Donc,
le Sync Engine
a deux objets.
C'est comme
ce que l'utilise
d'un objectif

le state de l'euro
ou les objets
que vous
l'utilise.
Et puis il vous
l'utilise.
Il y a
des complexités
sur les
problèmes.
Mais
dans le
effectuant
ce qui
s'affiche
c'est que
quand un
objectif
vient de l'un d'autre
et ne
n'a pas
rien à
le disc,
et il
l'intervient
pour l'un d'autre
pour l'autre.
Et puis,
il y a



le
C'est un
objectif
qui
s'affiche
et nous

Il y a
des objets
qui

C'est
le
objectif.
Il
s'affiche et

mais au moins, ça s'étend tout sur le disque.
Donc, le disque représentation a tout ce que l'utilise a reçu,
et puis, quand nous commençons à accéder à ce data,
c'est quand nous créons des objets modèles
sur le disque représentant,
et c'est ce qui est fondé à l'Ui.
Donc, nous faisons un peu de data à l'arrivée,
comme tous les objets qui ne sont pas assez,
mais qui sont importants, comme le workspace,
les équipes et les utilisateurs, les labels.
Tout, d'exception, et d'essuie d'attachement et de commentaire,
et d'essuie d'histoire,
que nous gardons sur le disque et la déploie,
quand nous avons besoin.
Et c'est comme ça qu'on arrive à la première représentation
et la première rendition de l'UEI.
Et maintenant, on peut réfléchir à un point de vue,
parce que sur le disque, nous avons déjà
le tout état de tous les objets,
et nous pouvons les déploier.
Et à ce point, nous faisons un connecteur web
pour notre engine de synch.
Et puis, nous commençons à recevoir le data
de l'envers du sénat de synch.
Comme nous le disons sur les bas-bordes,
ce n'est pas le dernier packet de synch que nous avons vu,
comme chaque packet dans l'organisation entière
a une idée, qui est un nombre d'accounts,
et puis, le sénat de synch
va vous envoyer tout le data que vous avez vu
et vous envoyer de l'argent.
Et comme ça,
les actions qui sont appliquées,
sont essentiellement des actions insurdes,
comme quand les objets sont créées,
ou quand les objets sont créés,
et puis, l'archive a été déploie.
En addition à quelques autres,
comme que vous avez dit, que vos groupes de synch
ont changé par exemple,
qui ont été utilisés pour accélérer le contrôle,
pour que le client le connaisse,
que vous avez besoin de plus de data
de l'envers du sénat,
car vous avez maintenant, par exemple,
ajouté à un équipe privé.
Et c'est en essence
ce que le sénat de synch nous fait.
Quand nous réfressons,
nous essayons de trouver de quoi nous devons charger,
nous l'aimons tout,
nous l'aimons tout sur le disque,
et nous l'aimons tout de suite
dans la mémoire, et c'est
ce que vous avez comme un ingénieur.
Et puis, il y a beaucoup de complexité
sur ces problèmes.
Parce que la première implementation que nous avons,
a-t-elle peut-être
une demi-année,
jusqu'à, je ne sais pas,
200, 300, 400,
400 issues
dans un sénat,
c'est pour lui, pour charger
tout le monde en mémoire,
quand nous nous sommes allés au sénat,
et nous avons commencé à voir
qu'il y a une très bonne operation
si vous avez beaucoup d'objets.
Donc, nous avons besoin de l'optimiser.
Et je pense que nous avons fait
10 très grandes optimisations
pour le sénat de synch,
afin de pouvoir avoir la performance
que nous sommes en train de faire.
Et nous n'avons pas sorti tout,
nous avons toujours vécu,
et on a encore, en plein,
les deux dernières optimisations
qui nous permettent de nous donner
en plus de deux ans,
pour penser à ce qu'il y a de la prochaine étape.
Le truc que nous faisons,
c'est que nous n'avons pas besoin
d'avoir des issues,
même sur le sénat.
Lorsque vous avez vécu au sénat,
vous avez beaucoup d'objets,
d'objets qui contiennent tout,
d'exeptes pour les commentaires
et l'histoire d'issues.
Ceux sont très facile à faire,
mais nous faisons le même
pour les issues et les attachments.
Parce que ce sont les objets
qui sont très grands,
et nous nous en mettons,
nous n'avons pas besoin de les autres,
et nous le faisons tout dynamiquement.
Et le problème, c'est que vous voyez
les issues, ils se rendent
sur chaque scénarie,
les calculations, les agrogates,
les comptes d'issues,
ou les items que vous avez dans votre inbox,
ou tout ça.
C'est tout le monde,
donc nous avons besoin de construire
un loader très compliqué
qui vous permet de streamer
tout le data que vous avez besoin.
Mais le UI peut juste vous demander
tout ce que vous pouvez dire,
tous les issues pour ce équipe,
et puis vous avez besoin de tous les issues pour cet utilisateur.
Et il y a un endroit centralisé
qui va ensuite déduire
toutes ces demandes,
et puis vous avez besoin de toutes les zones
de l'UI, et puis vous avez besoin
d'une réquestre optimale.
Vous pouvez faire ça pour la Network et vous avez
tout le monde en un go,
pour ne pas mettre le bas de la fin
à 200, 300 fois,
comme on l'a dit.
C'est intéressant, quand vous avez parlé
plus tard, vous avez mentionné
un packet et un ID,
et je pensais que vous avez
un log agrogate de packets,
qui sont peut-être des deltas
de choses qui ont changé en temps,
que vous pouvez dire, hey, c'est mon dernier state,
donne-moi les choses que je besoin.
Quand vous parlez d'un
dynamic streaming,
je pense que ce n'est pas
le stock state, c'est
que je veux préfetchir
des listes de x,
des choses de x,
et vous avez toujours
votre id de packet,
c'est mon dernier state,
c'est le monde que je sais.
Ce sont des séparations
des sortes de forcs.
Oui, c'est séparé,
les principaux database
ont la plus la plus la plus la plus de
ces modèles d'objets,
donc quand vous faites un query
pour la fin et la fin,
vous avez les plus la plus la plus
de la version, et c'est pour la complexité
de la kick-sin.
Vous avez un snapshot en temps,
mais après vous avez un snapshot,
vous avez des autres packets
ou des changements
qui sont exactement
mutés
en faisant ce request
pour le data.
Vous devez figure de la façon
de garder tout le bon,
pour ne pas déterminer
les changements que vous avez
en temps de streaming.
Ce n'est pas trop compliqué,
mais il faut nous trouver
ces problèmes et se figure de
toutes les places où nous avons des conditions de raise,
et ensuite prendre ces questions.
La solution
est,
oui, vous l'avez en batch,
vous l'avez en arbitrage,
mais vous ne vous arrêtez pas
sur le disk, si vous avez ça déjà
sur le disk.
Parce que quand quelque chose est commettis
sur le disk, ça signifie que ça a
été un call
ou un packet
plus récent,
qui a streamé, et que les gens
ne sont pas en train de faire des changements.
Si vous avez écrit ça sur le disk,
la discursion sera plus récente
que ce que vous avez
dans votre batch.
Ce sont des changements.
Parce que vous pouvez
prendre des snapshots
qui ne peuvent pas être plus ouverts,
qui ne vous paraissent pas.
Vous devez être conscients
de ce que le client a déjà vu en temps de synch.
Si le client a
seulement vu la dernière
20 minutes
de synch packets,
vous ne pouvez pas
charger de ce snapshot
plus ouverts que ça.
Parce que vous devez être en train de charger
tout le data, que ce soit incorrect,
parce que le client n'a pas vu tout ça.
Mais si nous savons que le client a vu
plus ou pas,
c'est pas important de comment
le snapshot est récent,
donc nous pouvons aller à un cash.
Nous n'avons pas de base de main,
et nous pouvons optimiser le backing
avec ça.
Je vous ai regardé
votre talk récent sur les changements
que vous avez faits pour ça.
C'est fun de vous regarder
les émotions du stack
de la question.
Je vous ai trouvé
quelques problèmes intéressants
dans les choix de technologie
que vous avez à faire pour fixer le problème.
Le premier était GraphQL.
En première version
de la Synch engine,
il a été élevé
beaucoup plus sur GraphQL
pour faire un peu de la fixation.
Vous pouvez expliquer
ce que GraphQL a fait,
pourquoi vous avez avancé et à quoi vous avez avancé?
Nous avons avancé
deux GraphQL pour fixer
les problèmes que nous avons.
La histoire de GraphQL
est que
nous pouvons
avoir la Synch engine
pour aussi réciter les mutations
par exemple, les connections web sockets.
Mais
ce que nous savions déjà dans le début,
c'est qu'on veut que la public API
soit aussi utilisée
pour atteindre
ceci et qu'on veut que nous voulons
faire avec GraphQL.
Nous avons donc construit toutes les mutations
sur le type GraphQL.
Ce n'est pas vraiment le sens
de construire toutes les logics de la business
à deux fois, comme la Synch client
et la GraphQL.
Nous avons terminé avec la solution
de dire que le client
va juste mettre le même point GraphQL
comme un user public API.
Et puis,
d'ici, vous avez un deuxième pipeline
de toutes les changements
qui sont streamés dans le client.
Si vous faites un changement sur le client,
il va être élevé un point GraphQL API.
Ce point API
va
élevé toutes les mutations
ou toutes les changements sur le client.
Et comme résultat,
qui est aussi une partie de l'application public
de la public, vous pouvez vérifier que
ça va envoyer la dernière Synch ID,
qui est essentiellement le même changement
que la suite
que les changements qui ont été faits
avec cette mutation.
Parce que la mutation peut faire
plusieurs changements en même temps.
Votre input peut s'affronter
à d'autres propriétés.
Et ça va envoyer au client
une réponse.
Et le client commence à attendre sur Synch
et se déclare
jusqu'à ce que nous nous collons
ce numéro.
Et à ce point, on peut dire
que la transaction a été complète
et que la question est terminée
et qu'on appris à la base local.
Il y a un peu de jouement
avec GraphQL pour envoyer les mutations
et de l'écouter sur les résultats
sur le Synch Engine.
Mais c'est ce que nous avons choisi
depuis le début.
Et
dans la première situation, ce que nous avons fait
c'est que de toutes ces conditions
que vous avez quand vous vous collons
avec un utilisateur.
Donc si vous avez un peu de state
dans votre base local et vous connectez
à la service de socket, vous devez
être derrière 1 000 packets,
par exemple. Et vous devez coller
avec ceux avant de vous connecter
au livestream des packets pour
vous appeler tous les packets
pour que vous puissiez s'occuper
d'une réplique.
Vous devez vous écrire un update
que vous avez fait avant
sur les changements.
Vous devez vous écrire
avec ces packets.
Ce que nous avons fait
quand le client connecte
à la socket web,
le socket web va ensuite
mettre toutes les changements que le client
doit voir pour s'occuper
et puis envoyer le client et continuer
les normales opérations.
Mais le socket web va devoir
arrêter le monde pendant que le client
attendait ces changements.
Parce que sinon, nous devrions
avoir des questions pour chaque client
pour savoir si on peut
envoyer ces updates à ce client
ou si le client se fait sur le point
et que ça serait juste un complication
du sainte-génier.
C'était la première réplique.
Tout le premier problème que nous avons
était que de ne pas arrêter
les changements que nous avons faits,
et que le client s'est répliqué
avec des packets de 1000,
qui sont bien bien,
mais que vous avez ensuite
mis à l'aide de 10 000 packets.
Et maintenant, vous vous rappelez







que le sainte-génier a été

des services graphiques,
et que les packets
consommentent la mémoire,
parce que vous avez les 3
fois, la base d'un database,
la chacune, et tout ce que vous avez
mis dans le papier.
Donc, nous avons ensuite
une réplique de Graphkill,
et nous avons répliqué un point restant,
parce que nous pouvions
impliquer la streaming sur ce point.
Nous avons donc moved
les deux,
et puis les deux d'un tel,
qui sont en train de
streamer le point restant.
Donc, le client a été dépassé
au point restant,
qui va ensuite prendre une connecteur
pour le database avec la query,
et que le database
respond avec des objets
qui ont effrayé la query,
le point restant
va les streamer à la client,
et ils vont l'inquiéter.
Donc, ils vont juste les contrôler
au database,
et ça fait que les choses sont plus
plus efficaces, car
dans Graphkill, vous devez
attendre l'exemple de la réponse,
et reposer le message
pour les clients.
Ça ne marche pas si vous avez
beaucoup de données à envoyer.
Vous avez beaucoup de problèmes
d'interessants,
donc, depuis que vous avez un API
et
vous avez un peu d'agriculture
d'événements qui sont venus des clients,
et vous avez probablement
normalisé les clients de manière normale.
Donc, si les gens sont en train de l'appli,
ils peuvent dire que je veux la liste des
problèmes, les problèmes les plus vus
de ce projet ou d'autres. Vous devez
pouvoir servir ça.
Ce qui, en fin de compte,
signifie que la base de votre database
de l'envers a de la représentation
normalisée de votre état de business
et de la situation de l'exemple.
Vous avez mentionné que
le client a sa propre vue
de la data, donc beaucoup de
ingénieurs sont en train de penser
que comment est le client en train
de déclencher cette data et que
je peux l'accessiver
et juste oublier que c'est un
bas-de-bac, le sync en train de
prendre soin de ça.
Comment avez-vous
pu déclencher la complexité
de la définition de ce data
dans plusieurs places?
Est-ce que...
Comment
ai-je pu le faire?
Est-ce que vous essayez de faire la même schéma
dans votre data store sur le service que vous avez
fait sur le client? Ou vous vous
vous déclenchez de la case-by-case?
Comment vous vous avoient de la inconsistency?
Oui, c'est tout le même.
La
représentation de la data est
la même que la représentation
d'un objet sur l'API,
la même que la représentation de la

la même que la schema client.
Avec des différences,
donc
on utilise les typescripts pour tout.
Donc,
sur l'API, c'est facile, on a une définition
pour ce que nous appelons
une entité client.
Et
il y a un bunch de décorateurs.
Une est la représentation de la data,
une est la représentation de la représentation graphique.
Et de cela, on peut générer
les deux schémas.
Vous l'avez déjà écrit, et c'est tout.
Nous voulions qu'on puisse
automatiquement impliquer
la représentation de la client.
Mais, comme ça,
ce n'est pas vraiment un grand chose
de l'écrire deux fois.
Nous avons juste de la copies,
nous avons de la synchronisation,
nous avons les propres, et
sur le client, vous avez des différents décorateurs
parce qu'on doit le sécher dans une manière différente.
Et l'accent de la business logic peut être
très différent entre la client et l'API.
Mais
la représentation de la data et les propres détenus sont les mêmes.
Donc, nous ne fais pas
aucune translation.
Si vous regardez la graphique de l'API,
cela signifie que ce n'est pas le meilleur
de l'API graphique, c'est très rire.
Et c'est
le bad side
de ceci.
Mais cela fait que les choses sont plus simples.
Et cela fait que nous voulons plus vite
de la production de la data
sans avoir de la transformation
de la data ou de la production de la data
pour que nous puissions
pouvoir le faire.
C'est comme nous le management.
Le type script nous aide
énormément.
Nous avons des décorateurs
sur le site de l'API
où nous pouvons dire que
ceci n'est pas un part de la synchronisation.
Ce n'est pas un part de la synchronisation.
Donc, ce n'est pas un part de la synchronisation.
Ce n'est pas un part de la synchronisation.
Donc, un autre part que je vous ai trouvé
intéressant sur votre tour de combat
était ce que vous avez choisi de faire avec la database.
À l'un des deux, vous avez eu
une réplique et vous avez
suivi une seconde technologie
que je ne m'ai probablement pas choisi.
Mais je l'ai trouvé assez intéressant.
Comment avez-vous fixé les problèmes de la database ?
Cachant, oui.
C'est généralement
un problème
avec la full world strap.
Parce que
la représentation logique
de la database
est juste une base de relation.
On utilise les postcards pour cela.
Si vous voulez qu'on enquête
tous les données pour les clients,
c'est une grande enquête.
Le client peut recevoir tout.
Si vous vous enzippez tout,
il peut y avoir même 100MB de données
que vous avez en full bootstrap.
Donc, enquêtez-vous
avec d'autres utilisateurs
sur la database de relation.
On n'a pas assez de mémoire
pour qu'on puisse mettre tout en mémoire.
Pour faire cela très vite.
Nous voulions cacher les données.
Nous savons
que les clients peuvent déjà s'en prendre.
Ils peuvent faire un Delta Sync,
je l'ai vu
jusqu'ici.
Nous pouvons prendre un Snapshot
tout le temps.
S'en prendre un cache.
Il faut que les clients individuels
puissent encore recevoir les données
que ils ont eu.
Et puis,
faire cela le plus vite possible.
Nous avons essayé de faire 2 technologies.
Nous sommes tous sur le GCP.
La première implementation
que nous avons faite
en utilisant la table.
Nous voulions normalement
que tout le data soit déjà
serialisé dans ces rôles.
Nous étions juste en train de mettre les strings.
La table de table a eu un bon idea.
Et puis,
il a été un peu plus lent.
Pourquoi est-ce
cela en train de prendre?
Nous avons fait toutes les choses correctes.
Nous n'avons pas encore que beaucoup de données.
Nous avons fait une seconde implementation
sur le type de Mongo.
Un d'entre nous a utilisé le Mongo before.
Il a dit que je pouvais juste en mettre un peu.
Nous voulions initialement
avoir un benchmark de
comment plus lent nous sommes
et comment plus lent nous sommes.
Nous avons utilisé le Mongo
pour un cache.
C'est un cache
de version serialisée
de ces modèles.
Et maintenant aussi,
des packets de Delta Sync
pour que ce soit très facile
et facile à courir.
Nous pouvons les cluster plus bien
et plus vite.
Nous pouvons les cluster plus bien
et plus vite.

C'est super.
C'est un cas d'usage très intéressant.
Je pense que
vous pouvez en avoir un peu de
des sortes de mongos
si vous avez
un usage relativement
de plus en plus.
C'est une base très facile
quand vous le faites.
Nous avons parlé
de toutes les complexes techniques
de la Sync et la Bac.
Mais nous n'avons pas touché
sur ce que c'est
comme un développeur de front-end
pour consommer de ceci.
Mes deux principales questions
sont, comment se fait-il
de l'usage de la Ui?
Est-ce que je dois le faire
comme un engineer de front-end?
Oui,
les deux questions sont super simples.
Vous n'avez pas besoin de
l'usage de la Ui.
Nous utilisons des MobX
pour les updates de l'Ui.
L'un des choses
que vous devez en souvenir,
c'est de mettre un observer
fonctionnel autour de vos compétences.
Et c'est ça.
Lorsque la change de date,
vos compétences seront réparées.
Il n'y a rien à faire
au-delà de cela.
Toutes les propres
sur les objets que vous toucherez
sont des gétters ou observables.
Si l'Ui touchera ces propres
et les updates sont either
d'une utilisateur
ou d'un call rémodel,
l'Ui
va juste s'éteindre.
Il n'y a rien à faire.
Vous vous rendez les choses.
Si vous voulez changer les choses,
vous pouvez changer.
Et puis vous devez les sauver.
C'est ça.
Il y a des cas
qui ne sont pas très bien
en mode offline.
C'est comme si
vous étiez en mode offline
parce que vous ne savez pas
combien de temps vous allez être en mode offline.
Il y a un autre équipe
avec le même nom.
Il y a des questions
qui ne sont pas faites.
Il y a des moyens
pour vous détecter.
Vous avez une transaction
et vous pouvez entendre
si vous avez des offlines.
Si vous avez des offlines,
vous pouvez consulter.
Il y a des paraings
et des débiles.
Constipation de swing
göstère tous ces erreurs
parce qu'ils sont gesehen 밥
qui archaeological
et je sais
Alémothique
Finish
enche
Extrait
d
nous avons beaucoup de faboards,
mais il est important que l'éducation soit sur le reaporteён



on a des gonna ett titte,

Et puisqu'il率 une rés janvier de 100 enblance de risques


et on ne peut pas deslder qui rit.
Pour nous,
il faut PPE,
j'ai travaillé sur le mobile depuis longtemps, je suis sûr que vous avez ressenti ça très fortement,
c'est que, en pensant sur comment vous interfacez avec votre API et comment vous changez votre API,
et ces interactions, surtout avec le mobile, comme versioning et quelque chose comme ça,
devient une vraiment, vraiment complétie d'épaisseur.
Donc, c'est juste un rapprochement vraiment intéressant et réfréchissant.
Nous avons vu beaucoup plus de fonds-en-front-en-en-en,
qui tentent de faire l'appli plus et plus semblable.
Je ne sais pas, c'est juste un perspective intéressant d'un moment
de comment l'envers-en-front-en-en-en-en peut vous aider à donner plus de features,
mais aussi de faire l'intégration à l'UI beaucoup plus semblable.
Oui, je l'ai très apprécié.
C'était l'une des sciences,
c'est pas...
C'est commencé avec performance, mais ensuite,
c'est devenu un secret source de la compagnie pour pouvoir s'assurer rapidement,
parce que vous n'avez pas besoin de faire toutes ces choses.
C'est génial, avec ça, on va changer les conseils.
Et ça nous rapproche pour cette semaine des conseils.
Merci pour nous accueillir, c'était un très intéressant,
un deep dive sur comment le sync linéaire fonctionne,
et je suis inspiré par ça.
Merci beaucoup pour avoir mis le nom de Justin Andrew.
C'était génial, de partager un peu de ce truc.
Et j'espère que les gens vont vraiment être intéressés en sync,
et vont être inspirés, et vont commencer à construire leur propre sync.
Ou utiliser des tools existants.
Juste le sync, c'est beaucoup plus facile à construire.
Si vous avez le correct...
Si vous avez construit l'application correcte,
que vous l'aurez pour le sync, vous n'aurez pas de regret en le mettre sur le sync.
Oui, c'est aussi bien entendu.
Et ça me renforce le care et l'excellence technique
que l'on trouve derrière le sync linéaire.
Ça nous montre dans le produit.
C'est superbe.

Episode suivant:


Les infos glanées

Je suis une fonctionnalité encore en dévelopement

Signaler une erreur

devtools.fm:DeveloperTools,OpenSource,SoftwareDevelopment

A podcast about developer tools and the people who make them. Join us as we embark on a journey to explore modern developer tooling and interview the people who make it possible. We love talking to the creators front-end frameworks (React, Solid, Svelte, Vue, Angular, etc), JavaScript and TypeScript runtimes (Node, Deno, Bun), Languages (Unison, Elixor, Rust, Zig), web tech (WASM, Web Containers, WebGPU, WebGL), database providers (Turso, Planetscale, Supabase, EdgeDB), and platforms (SST, AWS, Vercel, Netlify, Fly.io).
Tags
Card title

Lien du podcast

[{'term': 'Technology', 'label': None, 'scheme': 'http://www.itunes.com/'}]

Go somewhere