Datenübertragung per animiertem QR an Gomobile und GopherJS

In diesem Artikel möchte ich über ein kleines und lustiges Wochenendprojekt zum Übertragen von Dateien über animierte QR-Codes sprechen. Das Projekt wurde in Go mit Gomobile und Gopherjs geschrieben - der neuesten Version einer Webanwendung zur automatischen Messung der Datenübertragungsraten. Wenn Sie an der Idee interessiert sind, Daten über visuelle Codes zu übertragen, Webanwendungen zu entwickeln, die nicht auf JS oder dem echten plattformübergreifenden Go - to Wellcome to Cat basieren.


txqr Demo


Die Idee des Projekts entstand aus einer bestimmten Aufgabe für eine mobile Anwendung - wie ein kleiner Teil der Daten (~ 15 KB) unter Bedingungen der Netzwerkblockierung am einfachsten und schnellsten auf ein anderes Gerät übertragen werden kann. Der erste Gedanke war, Bluetooth zu verwenden, aber es ist nicht so praktisch, wie es scheint - der relativ lange und nicht immer funktionierende Prozess zum Erkennen und Koppeln von Geräten ist für die Aufgabe zu schwierig. Eine gute Idee wäre die Verwendung von NFC (Near Field Communication), aber es gibt immer noch zu viele Geräte, bei denen die NFC-Unterstützung eingeschränkt oder nicht vorhanden ist. Wir brauchten etwas Einfacheres und Erschwinglicheres.


Was ist mit QR-Codes?


QR-Codes


QR-Code (Quick Response) ist die weltweit beliebteste Art von visuellem Code. Es ermöglicht Ihnen, bis zu 3 KB beliebige Daten zu codieren, und verfügt über verschiedene Fehlerkorrekturstufen, mit denen Sie selbst ein Drittel eines geschlossenen oder verschmutzten Codes sicher lesen können.


Bei QR-Codes gibt es jedoch zwei Probleme:


  • 3KB reichen nicht aus
  • Je mehr Daten codiert sind, desto höher sind die Qualitätsanforderungen für das zu scannende Bild

Hier ist der QR-Code der 40. Version (die höchste Aufzeichnungsdichte) mit 1276 Bytes:


qrv40


Für meine Aufgabe musste ich lernen, wie man ~ 15 KB Daten auf Standardgeräten (Smartphones / Tablets) überträgt. Daher stellte sich die Frage von selbst: Warum nicht die Reihenfolge der QR-Codes animieren und die Daten in Teilen übertragen?


Eine schnelle Suche nach vorgefertigten Implementierungen führte zu mehreren solchen Projekten - hauptsächlich Projekten zu Hackathons (obwohl es auch eine These gab ) -, aber alle wurden in Java, Python oder JavaScript geschrieben, was den Code leider praktisch unportabel und unbenutzt machte. Angesichts der großen Beliebtheit von QR-Codes und der geringen technischen Komplexität der Idee wurde beschlossen, in Go - einer plattformübergreifenden, lesbaren und schnellen Sprache - von Grund auf neu zu schreiben. Normalerweise impliziert plattformübergreifend die Möglichkeit, Binärcode für Windows, Mac und Linux zu erstellen. In meinem Fall war es jedoch auch wichtig, ihn für das Web (gopherjs) und für mobile Systeme (iOS / Android) zu erstellen. Go bietet alles sofort einsatzbereit mit minimalen Kosten.


Ich habe auch alternative Optionen für visuelle Codes in Betracht gezogen - wie HCCB oder JAB-Code , aber für sie müsste ich einen OpenCV-Scanner schreiben, einen Encoder / Decoder von Grund auf neu implementieren und dies war zu viel für ein Projekt für ein Wochenende. Mit Round-Robin- QR-Codes ( Shotcodes ) und ihren auf Facebook, Kik und Snapchat verwendeten Gegenstücken können Sie viel weniger Informationen codieren. Apples unglaublich cooler patentierter Ansatz zum Koppeln von Apple Watch und iPhone - einer animierten Wolke aus bunten Partikeln - ist ebenfalls für den Wow-Effekt optimiert nicht unter maximaler Bandbreite. QR-Codes sind in die nativen SDK-Kameras des mobilen Betriebssystems integriert, was die Arbeit mit ihnen erheblich erleichtert.


TXQR


So entstand das txqr- Projekt (aus Tx - Transmission und QR), das eine Bibliothek zum Codieren / Decodieren von QR auf Pure Go und ein Protokoll zum Übertragen von Daten implementiert.


Die Hauptidee lautet wie folgt: Ein Client wählt eine Datei oder Daten aus, die gesendet werden sollen, das Programm auf dem Gerät zerlegt die Datei in Teile, codiert sie jeweils in QR-Frames und zeigt sie in einer Endlosschleife mit einer bestimmten Framerate an, bis der Empfänger alle Daten empfängt. Das Protokoll ist so erstellt, dass der Empfänger von jedem Frame aus starten und QR-Frames in beliebiger Reihenfolge empfangen kann - dies vermeidet die Notwendigkeit, die Animationsfrequenz und die Scanfrequenz zu synchronisieren. Der Empfänger kann ein altes Gerät sein, mit dessen Leistung Sie 2 Bilder pro Sekunde dekodieren können, und der Absender mit einem neuen Smartphone, das 120-Hz-Animationen erzeugt, oder umgekehrt. Dies ist kein grundlegendes Problem für das Protokoll.


Dies wird wie folgt erreicht - wenn die Datei in Teile ( Frames weiter) unterteilt ist, ein Präfix mit Informationen über den Versatz relativ zu allen Daten und die Gesamtlänge - OFFSET/TOTAL| (wobei OFFSET und TOTAL ganzzahlige Werte für Offset bzw. Länge sind). Binärdaten werden in Base64 weiterhin codiert, dies ist jedoch nicht unbedingt erforderlich. Die QR-Spezifikation ermöglicht nicht nur die Codierung von Daten als Binärdaten, sondern auch die Optimierung verschiedener Teile der Daten für unterschiedliche Codierungen (z. B. kann ein Präfix mit geringfügigen Änderungen als alphanumerisch codiert werden, und der Rest des Inhalts - wie binär ), aber der Einfachheit halber hat Base64 seine Funktion perfekt ausgeführt.


Darüber hinaus können die Bildgröße und -frequenz sogar dynamisch geändert werden, um sie an die Fähigkeiten des Empfängers anzupassen.


Protokoll


Das Protokoll selbst ist sehr einfach, und sein Haupt-Minus ist, dass bei großen Dateien (obwohl dies den Rahmen der Aufgabe sprengt, aber immer noch) ein beim Scannen übersprungener Frame die Scanzeit verdoppelt - der Empfänger muss erneut auf den vollständigen Zyklus warten. In der Codierungstheorie gibt es Lösungen für solche Fälle - Brunnencodes , aber ich werde dies für einige der folgenden freien Tage belassen.


Der interessanteste Punkt war, eine mobile Anwendung zu schreiben, die dieses Protokoll verwenden kann.


Gomobile


Wenn Sie noch nichts von gomobile gehört haben , ist dies ein Projekt, mit dem Sie Go-Bibliotheken in iOS- und Android-Projekten verwenden können und das dies zu einem obszönen einfachen Verfahren macht.


Der Standardprozess ist wie folgt:


  • Sie schreiben regulären Go-Code
  • laufen gomobile bind ...
  • Kopieren Sie die resultierenden Artefakte ( yourpackage.framework. oder yourpackage.aar ) in Ihr mobiles Projekt
  • Importieren Sie yourpackage und arbeiten Sie damit wie mit einer normalen Bibliothek

Sie können versuchen, wie einfach es ist.


Daher habe ich schnell eine Anwendung auf Swift geschrieben, die QR-Codes (dank dieses wunderbaren Artikels ) scannt und dekodiert, zusammenklebt und beim Empfang der gesamten Datei im Vorschaufenster anzeigt.


Als Neuling bei Swift (obwohl ich das Swift 4-Buch gelesen habe) gab es einige Momente, in denen ich mich auf etwas Einfaches festgelegt hatte, um herauszufinden, wie man es richtig macht, und am Ende bestand die beste Lösung darin, diese Funktionalität auf Go and Use zu implementieren über gomobile. Verstehen Sie mich nicht falsch, Swift ist in vielerlei Hinsicht eine wunderbare Sprache, aber wie die meisten anderen Programmiersprachen bietet es zu viele Möglichkeiten, dasselbe zu tun, und es gibt bereits eine anständige Geschichte rückwärts inkompatibler Änderungen. Zum Beispiel musste ich eine einfache Sache tun - um die Dauer eines Ereignisses mit Millisekundengenauigkeit zu messen. Eine Suche bei Google und StackOverflow führte zu einer Vielzahl unterschiedlicher, widersprüchlicher und oft veralteter Lösungen, von denen am Ende keine für mich schön oder für den Compiler korrekt aussah. Nach 40 Minuten habe ich gerade eine andere Methode im Go-Paket erstellt, die time.Since(start) / time.Millisecond und das Ergebnis von Swift direkt verwendet hat.


Ich habe auch das Konsolendienstprogramm txqr-ascii für schnelle Anwendungstests geschrieben. Es codiert die Datei und animiert die QR-Codes im Terminal. Alles in allem funktionierte es überraschend gut - ich konnte in wenigen Sekunden ein kleines Bild senden, aber als ich anfing, verschiedene Werte der Bildrate, die Anzahl der Bytes in jedem QR-Rahmen und den Grad der Fehlerkorrektur im QR-Encoder zu testen, wurde klar, dass die Terminallösung dies nicht war kommt mit der hohen Frequenz (mehr als 10) der Animation zurecht, und das manuelle Testen und Messen der Ergebnisse ist eine katastrophale Sache.


TXQR-Tester



Um die optimale Kombination aus Bildrate, Datengröße in einem QR-Rahmen und dem Grad der Fehlerkorrektur unter den angemessenen Grenzen dieser Werte zu finden, musste ich mehr als 1000 Tests durchführen, die Parameter manuell ändern, mit dem Telefon in der Hand auf einen vollständigen Zyklus warten und die Ergebnisse auf eine Platte schreiben. Dies muss natürlich automatisiert werden!


Hier kam die Idee der nächsten Anwendung txqr-tester - txqr-tester . Ursprünglich wollte ich x / exp / shiny verwenden - ein experimentelles UI-Framework für native Desktop-Anwendungen unter Go, aber es scheint aufgegeben zu werden. Vor ungefähr einem Jahr habe ich es versucht, und der Eindruck war nicht schlecht - es passte perfekt für Dinge auf niedrigem Niveau. Aber heute ist die Hauptniederlassung noch nicht einmal kompiliert worden. Es scheint, dass es keinen Anreiz mehr gibt, in die Entwicklung von Desktop-Frameworks zu investieren - eine komplexe und umständliche Aufgabe, bei der heutzutage fast keine Nachfrage mehr besteht. Alle UI-Lösungen sind vor langer Zeit ins Web gewechselt.


Wie Sie wissen, haben Programmiersprachen in der Webprogrammierung dank WebAssembly gerade erst begonnen, aber dies sind immer noch die ersten Schritte für Kinder. Natürlich gibt es immer noch JavaScript und Add-Ons, aber Freunde erlauben Freunden nicht, Anwendungen in JavaScript zu schreiben. Deshalb habe ich mich für meine jüngste Entdeckung entschieden - das Vecty- Framework, mit dem Sie Frontends auf reinem Go schreiben können, die automatisch mit einem sehr erwachsenen und überraschend gut funktionierenden JavaScript konvertiert werden GopherJS- Projekt.


Vecty und GopherJS


vecty


In meinem Leben hat mich die Entwicklung von Front-End-Schnittstellen nicht so begeistert.


Wenig später habe ich vor, ein paar weitere Artikel über meine Erfahrungen bei der Entwicklung von Frontends auf Vecty zu schreiben, einschließlich WebGL-Anwendungen. Unter dem Strich ist das Schreiben eines Frontends in einer durchdachten und einfachen Programmiersprache nach mehreren Projekten in React, Angulars und Ember ein Hauch von Frische Luft! Ich kann in kurzer Zeit ziemlich schöne Frontends schreiben, ohne eine einzige Zeile in JavaScript zu schreiben!


Für den Anfang starten Sie auf diese Weise ein neues Projekt auf Vecty (keine Codegeneratoren für "Erstprojekte", die Tonnen von Dateien und Ordnern erstellen) - nur main.go:


 ackage main import ( "github.com/gopherjs/vecty" ) func main() { app := NewApp() vecty.SetTitle("My App") vecty.AddStylesheet(/* ... add your css... */) vecty.RenderBody(app) } 

Eine Anwendung ist wie jede UI-Komponente nur ein Typ: eine Struktur, die den Typ vecty.Core und die Schnittstelle vecty.Component (bestehend aus einer Render() -Methode) implementieren muss. Und das ist alles! Dann arbeiten Sie mit Typen, Methoden, Funktionen, Bibliotheken für die Arbeit mit dem DOM usw. - keine versteckte Magie und neue Begriffe und Konzepte. Hier ist der vereinfachte Code für die Hauptseite:


 / App is a top-level app component. type App struct { vecty.Core session *Session settings *Settings // any other stuff you need, // it's just a struct } // Render implements the vecty.Component interface. func (a *App) Render() vecty.ComponentOrHTML { return elem.Body( a.header(), elem.Div( vecty.Markup( vecty.Class("columns"), ), // Left half elem.Div( vecty.Markup( vecty.Class("column", "is-half"), ), elem.Div(a.QR()), // QR display zone ), // Right half elem.Div( vecty.Markup( vecty.Class("column", "is-half"), ), vecty.If(!a.session.Started(), elem.Div( a.settings, )), vecty.If(a.session.Started(), elem.Div( a.resultsTable, )), ), ), vecty.Markup( event.KeyDown(a.KeyListener), ), ) } 

Sie schauen sich jetzt wahrscheinlich den Code an und denken - wie viel unbegründete Arbeit mit dem DOM ist! Das habe ich auch zuerst gedacht, aber als ich anfing zu arbeiten, wurde mir klar, wie bequem es war:


  1. Es gibt keine Magie - jeder Block (Markup oder HTML) ist nur eine Variable des gewünschten Typs, mit klaren Grenzen, an die Sie dank statischer Typisierung etwas setzen können.
  2. Es gibt keine öffnenden / schließenden Tags, die Sie entweder beim Refactoring ändern müssen, oder die IDE verwenden, die dies für Sie erledigt.
  3. Die Struktur wird plötzlich klar - zum Beispiel habe ich nie verstanden, warum es in React bis zur 16. Version unmöglich war, mehrere Tags von einer Komponente zurückzugeben - dies ist "nur eine Zeichenfolge". Als man sah, wie dies in Vecty gemacht wird, wurde plötzlich klar, wo die Wurzeln dieser Einschränkung in React wuchsen. Trotzdem ist nicht klar, warum es nach Reaktion 16 möglich, aber nicht notwendig wurde.

Sobald Sie diesen Ansatz für die Arbeit mit dem DOM ausprobieren, werden seine Vorteile im Allgemeinen sehr offensichtlich. Natürlich gibt es auch Nachteile, aber nach den Nachteilen der üblichen Methoden sind sie unsichtbar.


Vecty wird als reaktionsähnliches Framework bezeichnet, dies ist jedoch nicht ganz richtig. Es gibt eine native GopherJS-Bibliothek für React - myitcv.io/react , aber ich halte es nicht für eine gute Idee, die Architekturlösungen von React für Go zu wiederholen. Wenn Sie ein Frontend auf Vecty schreiben, wird plötzlich klar, wie viel einfacher es wirklich ist. Plötzlich werden all diese verborgene Magie und die neuen Begriffe und Konzepte, die jedes JavaScript-Framework erfindet, überflüssig - sie sind nur noch komplexer , nichts weiter. Alles, was benötigt wird, ist, die Komponenten und ihr Verhalten klar und deutlich zu beschreiben und miteinander zu verbinden - Typen, Methoden und Funktionen, und das ist alles.


Für CSS habe ich ein überraschend anständiges Bulma- Framework verwendet - es hat eine sehr klare Klassennamen und eine gute Struktur, und der deklarative UI-Code ist sehr gut lesbar.


Die wahre Magie beginnt jedoch, wenn Sie Go-Code in JavaScript kompilieren. Es klingt sehr einschüchternd, aber in der Tat rufen Sie einfach gopherjs build und in weniger als einer Sekunde haben Sie eine automatisch generierte JavaScript-Datei, die bereit ist, in Ihre grundlegende HTML-Seite aufgenommen zu werden (eine reguläre Anwendung besteht nur aus einem leeren Body-Tag und dessen Aufnahme JS-Skript). Als ich diesen Befehl zum ersten Mal ausführte, erwartete ich viele Meldungen, Warnungen und Fehler, aber nein - er funktioniert fantastisch schnell und leise. Er druckt nur Einzeiler bei Kompilierungsfehlern, die vom Go-Compiler generiert werden. Das ist also sehr klar. Es war jedoch noch cooler, Fehler in der Browserkonsole zu sehen, da Stapelspuren auf .go-Dateien und die richtige Zeile verweisen! Das ist sehr cool.


Testen von QR-Animationsparametern


Mehrere Stunden lang hatte ich eine Webanwendung bereit, mit der ich die Parameter zum Testen schnell ändern konnte:


  • FPS - Bildrate
  • QR-Frame-Größe - Wie viele Bytes sollten in jedem Frame sein?
  • QR-Wiederherstellungsstufe - QR-Fehlerkorrekturstufe

und führen Sie den Test automatisch aus.


Die App


Die mobile Anwendung musste natürlich auch automatisiert werden - sie musste verstehen, wann die nächste Runde mit neuen Parametern beginnt, wann der Empfang zu lange dauert und die Runde abbricht, die Ergebnisse an die Anwendung senden und so weiter.


Der Haken war, dass die Webanwendung, während sie in der Browser-Sandbox ausgeführt wird, keine neuen Verbindungen erstellen kann. Wenn ich mich nicht irre, besteht die einzige Möglichkeit einer echten Peer-to-Peer-Verbindung zum Browser nur über WebRTC (ich muss NAT nicht durchschlagen ), aber es war zu umständlich. Die Webanwendung kann nur ein Client sein.


Die Lösung war einfach: Der Go-Webdienst, der die Webanwendung bereitstellte (und den Browser unter der gewünschten URL startete), startete auch den WebSocket-Proxy für zwei Clients. Sobald zwei Clients beitreten, werden Nachrichten transparent von einer Verbindung an eine andere gesendet, sodass Clients (Webanwendung und mobiler Client) direkt kommunizieren können. Sie müssen dafür natürlich in einem WIFI-Netzwerk sein.


Es gab ein Problem, wie einem mobilen Gerät mitgeteilt werden konnte, wo tatsächlich eine Verbindung hergestellt werden soll, und es wurde mithilfe von ... QR-Code gelöst!


Der Testprozess sieht folgendermaßen aus:


  • Eine mobile Anwendung sucht nach einem QR-Code mit einer Startmarkierung und einem Link zu einem WebSocket-Proxy
  • Sobald das Token gelesen wurde, stellt die Anwendung eine Verbindung zu diesem WebSocket-Proxy her
  • Die Webanwendung (die bereits mit dem Proxy verbunden ist) versteht, dass die mobile Anwendung bereit ist, und zeigt einen QR-Code mit der Markierung "Bereit für die nächste Runde?" an.
  • Die mobile Anwendung erkennt das Signal, setzt den Decoder zurück und sendet über WebSocket die Nachricht „yep“.
  • Nachdem die Webanwendung eine Bestätigung erhalten hat, generiert sie eine neue QR-Animation und dreht sie, bis sie die Ergebnisse oder das Zeitlimit erhält.
  • Die Ergebnisse werden einer Platte hinzugefügt, neben der Sie sie sofort als CSV herunterladen können

Design


Infolgedessen blieb mir nur noch das Telefon auf ein Stativ zu stellen, die Anwendung zu starten, und dann erledigten die beiden Programme selbst die ganze Drecksarbeit und kommunizierten höflich über QR-Codes und WebSocket :)


Tester Demo


Am Ende habe ich die CSV-Datei mit den Ergebnissen heruntergeladen, sie an RStudio und Plotly Online Chart Maker gesendet und die Ergebnisse analysiert.


Ergebnisse


Der vollständige Testzyklus dauert ungefähr 4 Stunden (leider musste der schwierigste Teil des Prozesses - das Generieren eines animierten GIF-Bildes mit QR-Frames - im Browser ausgeführt werden, und da sich der resultierende Code noch in JS befindet, wird nur ein Prozessor verwendet) Sie mussten darauf achten, dass der Bildschirm nicht plötzlich leer wurde oder eine Anwendung das Fenster mit der Webanwendung nicht schloss. Folgende Parameter wurden getestet:


  • FPS - 3 bis 12
  • Die Größe des QR-Rahmens beträgt 100 bis 1000 Byte (in Schritten von 50).
  • Alle 4 Stufen der QR-Fehlerkorrektur (niedrig, mittel, hoch, am höchsten)
  • Übertragene Dateigröße - 13 KB zufällig generierte Bytes

Einige Stunden später lud ich CSV herunter und begann, die Ergebnisse zu analysieren.


Ein Bild ist wichtiger als tausend Wörter, aber interaktive 3D-Visualisierungen sind wichtiger als tausend Bilder. Hier ist eine Visualisierung der Ergebnisse (anklickbar):


qr_scan_results


Das beste Ergebnis war 1,4 Sekunden, was ungefähr 9 KB / s entspricht! Dieses Ergebnis wurde mit einer Frequenz von 11 Bildern pro Sekunde, einer Bildgröße von 850 Bytes und einem durchschnittlichen Fehlerkorrekturniveau aufgezeichnet. In den meisten Fällen übersprang der Kameradecoder jedoch bei dieser Geschwindigkeit einige Bilder und musste auf die nächste Wiederholung des fehlenden Bilds warten, was sich sehr negativ auf die Ergebnisse auswirkte - anstelle von zwei Sekunden konnte es leicht 15 oder eine Zeitüberschreitung von 30 Sekunden geben.


Hier sind die Diagramme der Abhängigkeit der Ergebnisse von variablen Variablen:


Bildzeit / Größe


Zeit gegen Größe


Wie Sie sehen können, ist bei niedrigen Werten der Anzahl von Bytes in jedem Rahmen die überschüssige Codierung zu groß bzw. die Gesamtlesezeit zu groß. Es gibt ein lokales Minimum von 500-600 Bytes pro Frame, aber die Werte daneben führen immer noch zu verlorenen Frames. Das beste Ergebnis wurde bei 900 Bytes beobachtet, bei 1000 und mehr ist jedoch fast ein Frame-Verlust garantiert.


Zeit / FPS


Zeit gegen FPS


Der Wert der Anzahl der Bilder pro Sekunde hatte zu meiner Überraschung keinen sehr großen Effekt - kleine Werte erhöhten die Gesamtübertragungszeit zu stark und große die Wahrscheinlichkeit eines fehlenden Bilds. Nach diesen Tests liegt der optimale Wert für die Geräte, auf denen ich getestet habe, im Bereich von 6 bis 7 Bildern pro Sekunde.


Zeit- / Fehlerkorrekturstufe


Zeit gegen Lvl


Die Fehlerkorrekturstufe zeigte eine klare Beziehung zwischen der Dateiübertragungszeit und der Redundanzstufe, was nicht überraschend ist. Der klare Gewinner ist hier die niedrige (L) Korrekturstufe - je weniger redundante Daten, desto besser lesbar ist der QR-Code für den Scanner mit derselben Datengröße. Tatsächlich ist für dieses Experiment überhaupt keine Redundanz erforderlich, aber der Standard bietet keine solche Option.


Für objektivere Daten sollte dieser Test natürlich hunderttausend Mal auf verschiedenen Geräten und Bildschirmen ausgeführt werden, aber für mein Wochenendexperiment war es mehr als genug Ergebnis.


Schlussfolgerungen


Dieses amüsante Projekt hat bewiesen, dass eine einseitige Datenübertragung durch animierte Codes durchaus möglich ist. Für Situationen, in denen Sie eine kleine Menge ohne Netzwerke übertragen müssen, ist dies durchaus geeignet. Obwohl mein maximales Ergebnis etwa 9 KB / s betrug, betrug die tatsächliche Geschwindigkeit in den meisten Fällen 1-2 KB / s.


Ich habe es auch sehr genossen, Gomobile und GopherJS mit Vecty als routinemäßiges Werkzeug zur Problemlösung zu verwenden. Dies sind sehr ausgereifte Projekte mit ausgezeichneter Arbeitsgeschwindigkeit und in den meisten Fällen Erfahrung "es funktioniert einfach".


Schließlich bewundere ich immer noch, wie produktiv Sie mit Go sein können, wenn Sie genau wissen, was Sie implementieren möchten - der extrem kurze Zyklus „Ändern“ - „Zusammensetzen“ - „Prüfen“ ermöglicht es Ihnen, viel und häufig mit einfachem Code und dem Fehlen einer Klassenhierarchie in der Struktur zu experimentieren Programme ermöglichen es, sie unterwegs einfach und schmerzlos umzugestalten. Dank der fantastischen plattformübergreifenden Integration in die Sprache von Anfang an können Sie den Code einmal schreiben und auf dem Server, auf dem Webclient und in der nativen mobilen Anwendung verwenden. Gleichzeitig gibt es trotz mehr als ausreichender Leistung immer noch viel Platz für Optimierung und Beschleunigung.


Wenn Sie also noch nie Gomobile oder GopherJS ausprobiert haben, empfehle ich Ihnen, es bei der nächsten Gelegenheit zu versuchen. Es wird eine Stunde Ihrer Zeit dauern, aber es kann eine ganz neue Ebene von Möglichkeiten in der Web- oder Mobilentwicklung eröffnen. Fühlen Sie sich frei zu versuchen!


Referenzen


Source: https://habr.com/ru/post/de430688/


All Articles