1) Au cours des 4-5 dernières années, j'ai expérimenté de nombreuses architectures d'applications Solana, et j'ai pensé qu'il était grand temps que je rédige mes conclusions. Je commence par la moins compliquée et j'ajoute progressivement plus de complexité. Voici donc : Architecture d'application Solana, un fil.
2) Commençons par le mode facile. C'est probablement à quoi ressemble votre première application Solana. Un frontend react simple, établit une connexion à un RPC. Il n'y a pas besoin de serveur API. Le RPC est votre serveur. Dans les premiers jours, ceux-ci étaient remplis de getAccountInfos, de logique de construction de tx sur mesure, etc. Plus tard, lorsque les performances commencent à souffrir, vous ajoutez des couches de mise en cache et de regroupement. Entrez getMultipleAccounts. Peut-être que vous ajoutez également des abonnements websocket + du polling pour mettre à jour l'interface utilisateur en direct. Cette architecture permet un prototypage extrêmement rapide. Il n'y a pratiquement aucun devops. Coûts serveurs négligeables (il suffit de déployer sur vercel, etc). Cependant, elle présente quelques défauts majeurs.
3) Le premier problème que vous rencontrez est celui des requêtes complexes. Dans cette architecture, tout ce que vous avez est le RPC Solana classique. Cela signifie que vous devez traiter Solana comme un RPC l'expose -- comme une base de données NoSQL avec un problème d'attitude. Les requêtes ponctuelles ne posent pas de problème. Vous pouvez même être très créatif avec les PDA pour parcourir vos données de programme comme si c'était une base de données graphique. Mais dès que vous devez effectuer votre premier gPA, vous êtes en proie à une douleur maximale. L'interface n'est pas du tout ergonomique. Si vous avez des données de longueur dynamique, elles ne peuvent pas du tout être utilisées. Selon votre fournisseur de RPC, cela peut être incroyablement lent. Même sans gPA, cette approche a tendance à être beaucoup plus lente que votre application web2 typique avec rendu côté serveur et une base de données normale.
4) Le deuxième problème que vous rencontrez est la portabilité de la logique de construction des transactions. Avec cette configuration, toute la logique pour construire des transactions est soit (a) dans votre code frontend, soit (b) dans des bibliothèques que votre code importe. Dans le cas de (a), quiconque souhaite construire des transactions en dehors de votre frontend s'expose à un maximum de douleur (cela vous inclut, lorsque vous aurez inévitablement besoin de plus d'applications). Dans le cas de (b), tout changement dans la logique de construction des transactions nécessite des publications de bibliothèques, tout le monde doit mettre à jour ses paquets, puis il y a des mises à jour de l'interface utilisateur. S'appuyer fortement sur des outils comme Anchor, tels que la résolution de compte, peut minimiser la quantité de logique qui doit être portée -- mais le problème demeure. Cela vous prive d'agilité et rend difficile le changement des points de terminaison des contrats intelligents tout en garantissant que toutes les versions de votre logique de construction de TX continuent de fonctionner.
5) Le troisième problème auquel vous êtes confronté est le fait que les interfaces utilisateur sont généralement mauvaises pour soumettre des transactions, en particulier avec la logique de réessai. Un utilisateur peut quitter la page, la TX cesse de réessayer. De grandes quantités de transactions ont tendance à avoir du mal à aboutir. Il est difficile de déboguer à distance pourquoi les choses n'aboutissent pas.
6) Le dernier problème ici est que vous n'êtes pas le seul à avoir cette architecture. Un RPC est précieux, et vous devez essentiellement exposer votre URL RPC dans votre frontend. Maintenant, vous vous retrouvez dans un jeu du chat et de la souris pour vous assurer que personne ne vole votre RPC et n'augmente vos coûts.
7) Alors, quelle est la suite ? Typiquement, même si vous ne vous occupez pas de la portabilité des transactions, vous finissez par devoir traiter les requêtes de liste. gPA est nul, et nous le savons tous. Donc, vous pouvez construire une architecture hybride. Dans cette architecture, vous conservez la capacité de prototyper rapidement, mais vous poussez les requêtes difficiles et peu esthétiques dans une API. Un bel exemple concret de cela est la gouvernance : vous avez des propositions qui sont créées avec un ensemble d'étiquettes ("Économique", "Technique", etc). gPA ne peut pas filtrer par étiquette.
8) Cette architecture n'a pas résolu la portabilité des transactions, ni le fait que des personnes retirent votre RPC. Mais à grande échelle, vous pouvez au moins résoudre le problème des gPAs lents/impossibles. Cela introduit un nouveau problème -- les indexeurs. Plus d'informations à ce sujet plus tard.
9) Enfin, vous avez ce que j'appellerais la pile "entreprise" de Solana. Vous ne traitez plus Solana comme une base de données NoSQL. Au lieu de cela, vous la traitez comme un bus d'événements. Le frontend ne sait rien du modèle de données de Solana. Le serveur construit des transactions et les passe à l'interface utilisateur pour signature, puis les envoie à Solana lui-même. Il traite cela comme un événement et attend qu'il se propage aux indexeurs qui changeront les données sous-jacentes. Cette configuration offre une grande portabilité des transactions - n'importe qui peut interroger votre API avec des paramètres propres et obtenir des transactions/instructions en retour. Cela permet d'avoir une interface utilisateur extrêmement réactive -- en ce qui concerne l'interface utilisateur, c'est essentiellement du web2. Vous pouvez tirer pleinement parti du SSR. Le RPC est abstrait -- personne ne peut voler vos crédits. Mais cette configuration a ses problèmes.
10) Le premier problème auquel vous serez confronté est la douleur de l'indexeur. Bien que cela ait été atténué ces dernières années (grâce aux équipes de Triton, Helius et StreamingFast), je finis toujours par frapper notre indexeur avec une clé à molette régulièrement. Vous allez manquer des messages. Lorsque vous manquez un message, votre interface utilisateur se retrouve dans un état étrange (exemple : je vous ai envoyé un NFT, sur la chaîne vous l'avez reçu, ma base de données dit que je le possède toujours). Ce type de problèmes est exaspérant à déboguer. Est-ce de votre faute ? Est-ce de la faute de votre fournisseur de données ? Qui sait ! Voilà votre après-midi.
11) Le prochain problème auquel vous serez confronté est le timing. Lorsque vous utilisez directement le RPC pour tout, ils vous permettent de passer des engagements et de traiter les données les plus récentes. Avec un indexeur, tout cela est manuel. Cela signifie que lorsque vous construisez des transactions, vous pourriez les construire sur la base de données obsolètes. Vous renvoyez une transaction qui est vouée à l'échec. Vous pouvez résoudre le problème des données obsolètes en utilisant des fournisseurs de données qui vous donnent des données extrêmement rapides (ex Helius laser stream). Mais ensuite, vous devez gérer manuellement les reorgs. C'est-à-dire que les données que vous indexez doivent être désindexées si cette tx n'a finalement pas été validée. C'est un cauchemar.
12) Vous pouvez "pirater" les problèmes de timing en construisant toujours des transactions en utilisant des données provenant de l'RPC, et en utilisant uniquement vos données indexées pour alimenter l'interface utilisateur. Mais alors, les utilisateurs auront toujours des problèmes d'incohérences potentielles entre l'interface utilisateur et la chaîne. Par exemple, l'interface frontend dit que je possède ce NFT et que je peux le transférer, puis le backend me crie dessus et dit que je ne peux pas.
13) Le dernier problème que vous rencontrez avec cette configuration est le coût, et si nous sommes un peu mélodramatiques, "la mort de la décentralisation." Le rêve du web3 était de ne pas avoir à déployer des tonnes de serveurs centralisés. Maintenant, vous avez déployé suffisamment d'infrastructure pour obtenir un poste d'architecte principal dans une entreprise web2. Cela coûte de l'argent. Cela prend du temps. Et c'est tout très centralisé. Quelle est la décentralisation de votre protocole si le meilleur moyen d'interagir avec lui est via une API web2 ? Et il y a environ 72 développeurs sur Solana qui sauraient comment interagir avec lui sans cette API.
14) En fin de compte, je ne vais pas mourir sur la colline de la décentralisation. Ce qui est le mieux pour les utilisateurs tend à être le meilleur choix. La configuration "entreprise" conduit à des applications web modernes et rapides et à une séparation claire des préoccupations. En revanche, cela augmente les coûts de devops et vous rend moins agile. Je recommande à la plupart des startups de commencer avec la méthode directe vers rpc, à moins que vous ne construisiez quelque chose qui nécessite explicitement d'être rapide ou d'avoir des sémantiques de requête complexes. Le temps de mise sur le marché est essentiel. Vous pouvez toujours embaucher un ingénieur de niveau intermédiaire plus tard et le jeter dans le donjon d'indexation.
15) Fin. Si l'un d'entre vous a trouvé une meilleure configuration, faites-le moi savoir. Voici toutes les choses que j'ai essayées. J'apprécie beaucoup de jouer avec la configuration d'entreprise ces derniers temps.
40,06K