Hallo, ich wollte meine Erfahrungen bei der Entwicklung eines Testfalls für Aviasales teilen.
Ich bin kürzlich auf einen React-Entwicklerjob bei Aviasales gestoßen. Ich schickte eine Bewerbung, woraufhin mir die Personalabteilung am nächsten Tag antwortete und mir mitteilte, dass ich eine Testaufgabe durchführen müsste. Ich mache wirklich keine Testaufgaben, da ich ziemlich viel Zeit für deren Implementierung aufwenden muss, und im Falle eines Fehlers wird dies verschwendet. Aber ich stimmte zu ...
Die Testaufgabe finden Sie hier unter dem Link .
Hier ist ein Link zu meinem Repository der abgeschlossenen Aufgabe.
Ich habe mich darauf beschränkt, die Aufgabe an einem Tag abzuschließen (obwohl ich nach der Veröffentlichung geringfügige Verbesserungen vorgenommen habe: Ich habe die Skizze sozusagen fertiggestellt).
Was ich für die Entwicklung gewählt habe:
- Ich habe NextJS als Basis gewählt, weil ich nicht am Einrichten der Umgebung für Webpack basteln wollte und Sie das Projekt selbst mit ein paar Klicks bereitstellen können.
- Ich wollte schnell schreiben und entschied mich für das React-IOC-Paket in Verbindung mit MobX anstelle von Redux. Dies ist ein Paket, mit dem Sie Anwendungen über Dienste schreiben können, die Winkeldiensten ähneln.
- Ich habe Web Worker verwendet, damit beim Sortieren einer großen Datenmenge keine Verzögerungen in der Benutzeroberfläche auftreten.
- Ich habe Typescript nicht verwendet, um keinen zusätzlichen Code mit unnötiger Zeitverschwendung für eine Testaufgabe zu schreiben.
- Aufgrund von Absatz 4 habe ich auch keine Tests geschrieben.
- Ich habe dem Projekt zwei zusätzliche Pakete hinzugefügt: debounce, RxJS. Der erste wird benötigt, um einfache Rückrufe zu erstellen, z. B. um den Download-Status so zu ändern, dass der Spinner die Last nicht anzeigt, wenn der Download sehr wenig Zeit in Anspruch nimmt. Ich verwende immer das zweite Paket, um ein Aktionsskript zu erstellen, um beispielsweise Zustände im Fehlerfall beim Senden einer Anforderung an den Server zu verarbeiten.
Das Verfahren für die erste Entwicklungsstufe:
- Initialisiertes Repository.
- Initialisiertes NextJS-Projekt.
- Eine Index-Basisseite mit einer Hello World-Nachricht wurde hinzugefügt.
- Erstellt einen ticket.provider-Dienst, der mit dem API-Server interagiert.
- Erstellt den ticket.service-Dienst, der ticket.provider injiziert und den Observator mit einem Array angezeigter Tickets füllt
- Ticket.filter.service erstellt, in dem gefilterte Daten gespeichert werden, die von ticket.service über @computed eingespeist wurden
Die zweite Entwicklungsstufe:
- Erstellt Komponenten und gemalte Stile für sie unter Verwendung des im Aufgaben-Repository bereitgestellten Layouts.
- Ich habe den Download zum Spinner gemacht und seinen Wert aus den Diensten herausgeschrieben.
- Verbunden alle Servicelogik mit Komponenten.
- Hilfsprogramme mit Datenformatierung hinzugefügt, z. B. Zeit und Geld.
Dann habe ich mich für die Touch-Oberfläche entschieden und bei der Verwendung der Anwendung Fehler festgestellt:
- Es gibt Schnittstellenverlangsamungen beim Ändern des Filters und beim Sortieren, daher habe ich das Speichern, Abrufen und Filtern von Daten an Web Worker übertragen, wonach die Verzögerungen vollständig verschwunden sind.
- Spinner hat die Sprunglinienanimation nicht korrigiert, daher habe ich sie durch eine visuelle Anzeige von Linien mit flackernder Animation ersetzt.
- Um das Rendern von Daten zu vereinfachen, habe ich die Datenformatierungsaufrufe an Web Worker übertragen. Dies reduziert die Belastung beim Rendern von Komponenten
Dann beendete ich meine Arbeit und schickte am Ende des Tages eine Aufgabe zur Überprüfung.
Da ich mich zeitlich begrenzt habe, habe ich die Anwendung nicht weiter optimiert, nämlich React.memo (...) nicht verwendet. Ich habe auch nicht begonnen, Fenster und Router durch Injektoren in Diensten zu ersetzen. Verzeih mir das, das ist ein Fehler.
Aber am nächsten Tag habe ich die Funktion hinzugefügt, den Status des Filters in der URL-Zeile des Browsers zu speichern. Danach war ich bereits mit der geleisteten Arbeit zufrieden.
Ich habe 7 Tage auf eine Antwort von ihnen gewartet, sie haben auf keine meiner Nachrichten geantwortet. Es war sozusagen eine unangenehme Erfahrung. Trotzdem antworteten sie und die Antwort war äußerst beunruhigend zu lesen. Die Nachricht ist unten zu sehen.
Werfen wir einen Blick auf die Punkte:
[1]. "Die Arbeit wurde sehr sorgfältig gemacht"
Ich sehe nicht wo, kein Argument, da es keine Beispiele gibt.
[2]. "Es scheint, dass die Entwicklung die Ziele" es funktioniert "verfolgte und" wie es funktioniert "ignorierte.
Kein Argument, keine Beispiele.
[3]. „Aufgrund unserer Anforderungen an die Kandidatenstufen erreicht die erledigte Aufgabe kaum die Mitte.“
Was sind die Anforderungen? Wo sind sie?
[4]. „Wir erwarten, dass die Filter nicht fest codiert werden und sich an die Daten anpassen. Wenn Sie zu Aviasales gehen, können Sie sehen, dass die Tickets sofort angezeigt werden, wenn die erste Rate angezeigt wird, und wir warten nicht darauf, dass alle geladen werden. "
Diese Anforderung war in der beigefügten Aufgabe nicht enthalten. Und die Aviasales-Anwendung selbst hat meiner Meinung nach keine Referenzschnittstelle, und das Springen von Tickets ist nicht die beste Lösung.
[5]. „Warum kennt filter.service Router und Fenster? Er sollte den Status der Anwendung nicht kontrollieren und überhaupt solche Abhängigkeiten haben. “
Weil die Dienste erstellt werden, um den Status der gesamten Anwendung oder des Moduls, in dem sie vorhanden sind, zu steuern. Hier schlägt der Autor klar vor, die gesamte Logik in die Komponenten zu schreiben.
[6]. „Web Worker. Was ist der Gewinn? In diesem Fall wird viel Zeit für asynchrone Vorgänge aufgewendet, und die gespeicherte Last im Hauptthread wird für das Serialisieren / Deserialisieren von Objekten (und beobachtbaren Objekten) aufgewendet. Wenn es um Optimierungen geht, hat es sich gelohnt, nicht mit dem Entfernen im Web Worker zu beginnen, sondern die Probleme im Hauptthread zu beheben. “
Wie kann ich mit der Verarbeitung großer Datenmengen im Hauptthread und gleichzeitig ohne Schnittstellenverzögerungen umgehen? Es wird für mich äußerst interessant sein, herauszufinden, ob jemand ein Beispiel hat, und dann in die Kommentare zu schreiben. Anscheinend fehlt mir etwas.
[7]. "Es macht keinen Sinn, dem Projekt rxjs hinzuzufügen, nur um Wiederholungsversuche und sequentielles Laden zu implementieren."
Warum macht es keinen Sinn? Sie können unbedingt erforderliche Funktionen in RxJS importieren. Wenn Tree Shaking-Pakete und -Funktionen nicht ordnungsgemäß funktionieren, wird die Größe der Anwendung nicht erhöht.
[8]. „Das Projekt kann nicht skaliert und gewartet werden. Konstrukte wie (ticket.segments || [{}, {}]).map((ticket) => ...)
sehr umständlich. “
Lassen Sie uns die Kriterien für Skalierung und Support durchgehen: Barrierefreiheit (Dienste lösen dieses Problem), Risiken ( ticket.segments || [{}, {}]
sind nur ein Beispiel für den Umgang mit Fällen, in denen die Eingabe keine Daten enthält. Ein Beispiel ist jedoch schlecht Zumindest der Nullable-Struktur-Ansatz, aber ich versuche ihn einzuhalten), sauberer Code (naja, zumindest weiß ich, was es ist :), obwohl ich versucht habe, alles so zu schreiben, wie es sollte). Es scheint, dass alles erfasst ist, wieder kein Argument.
[9]. „Ich hatte den Eindruck, dass es absolut kein Verständnis dafür gibt, wie React unter der Haube funktioniert. Es gibt viele kritische Fehler bei der Arbeit mit Requisiten für Komponenten, die sich sehr negativ auf die Leistung auswirken. Reaktionsoptimierungsmechanismen werden ignoriert. “
Ich kann nicht verstehen, wo diese beschriebenen Probleme liegen. Welche Art von Mechanismen?
[10]. "Erstellen von Handlerfunktionen in Render."
Ich habe überhaupt keine Handlerfunktionen beim Rendern. Versteht jemand, was hier geschrieben steht? Ich habe sogar die Formatierungsverarbeitung auf Web Worker übertragen
[11]. „Ein neues leeres Objekt erstellen und auf das Ticket übertragen. ticket-list-loading.jsx:10
oder Ticket.tsx:24
”
Hier gibt es nichts Kritisches, außer meiner Faulheit, die Ladekartenkomponente separat herauszunehmen. Das Übergeben eines leeren Objekts verstößt nicht gegen ein Programmierprinzip, außer dass dies hier über ticket = ticket || {};
erforderlich war ticket = ticket || {};
Dies ist jedoch ausschließlich auf die Tatsache zurückzuführen, dass die Entwicklungszeit auf einen Tag begrenzt war und die Behebung aller geringfügigen Fehler länger dauern würde.
[12]. "Array-Indizes als Schlüssel auf der Ticketliste"
Es ist eher eine Frage, warum API keine Elemente mit id zurückgibt. Daher müsste ich beim Empfang von Daten vom Server eindeutige Schlüssel für jedes Element generieren, was ich im Rahmen der Testaufgabe nicht getan habe, da dies selbst in einem realen Projekt ein zweifelhafter Ansatz ist.
Und schließlich die Schlussfolgerung: „Im Allgemeinen hat React nicht funktioniert (
Insgesamt: Für die mittlere Ebene erwarten wir, dass es keine kritischen Probleme mit der Reaktion geben wird, aber es gibt viele davon in der geleisteten Arbeit. “
Es gibt bereits keine Kommentare ...
Vielen Dank, wenn Sie bis zum Ende lesen. Ich habe eine sehr negative Meinung zu Aviasales, daher poste ich alles hier, damit Sie selbst beurteilen können, ob Sie sie kontaktieren sollten oder nicht.
Volltext der Nachricht:
Die Arbeit wird sehr sorgfältig durchgeführt. Es scheint, dass während der Entwicklung die Ziele "es funktioniert" waren und "wie es funktioniert" ignoriert wurden. Aufgrund unserer Anforderungen an die Kandidatenstufen erreicht die erledigte Aufgabe kaum die Mitte.
Leistung und Struktur:
Wir erwarten, dass die Filter nicht fest codiert werden und sich an die Daten anpassen. Wenn Sie zu Aviasales gehen, können Sie sehen, dass die Tickets sofort angezeigt werden, wenn die erste Rate angezeigt wird, und wir warten nicht darauf, dass alle geladen werden.
Weitere technische Punkte.
- Warum
filter.service
Router und Fenster? Es sollte den Status der Anwendung nicht kontrollieren und überhaupt solche Abhängigkeiten aufweisen. - Web Worker. Was ist der Gewinn? In diesem Fall wird viel Zeit für asynchrone Vorgänge aufgewendet, und die gespeicherte Last im Hauptthread wird für das Serialisieren / Deserialisieren von Objekten (und beobachtbaren Objekten) aufgewendet. Wenn es sich um Optimierungen handelt, hat es sich gelohnt, nicht mit dem Entfernen im Web Worker zu beginnen, sondern die Probleme im Hauptthread zu beheben.
- Es macht keinen Sinn, dem Projekt nur rxjs hinzuzufügen, um Wiederholungsversuche und sequentielles Laden zu implementieren.
- Das Projekt kann nicht skaliert und gepflegt werden. Konstrukte wie (
ticket.segments || [{}, {}]).map((ticket) => ticket
) sind sehr umständlich.
Reaktion:
Ich hatte den Eindruck, dass es absolut kein Verständnis dafür gibt, wie React unter der Haube funktioniert. Es gibt viele kritische Fehler bei der Arbeit mit Requisiten für Komponenten, die sich sehr negativ auf die Leistung auswirken. Reaktionsoptimierungsmechanismen werden ignoriert. Kurz zu den Problemen: - Erstellen von Handlerfunktionen innerhalb des Renderings.
- Erstellen Sie ein neues leeres Objekt und übertragen Sie es auf das Ticket.
ticket-list-loading.jsx:10
oder Ticket.tsx:24
. - Array-Indizes als Schlüssel in einer Ticketliste.
Im Allgemeinen hat React nicht funktioniert :(
Insgesamt: Für die mittlere Ebene erwarten wir, dass es mit der Reaktion keine kritischen Probleme geben wird, aber es gibt viele davon in der geleisteten Arbeit.