Nachdem ich meine Geschichte über „Beschäftigung“ bei Yandex
im Kommentar zum sensationellen Hinweis „Wie ich 3 Monate bei Y. Market gearbeitet und gekündigt habe“ dargelegt habe, wäre es unfair, den Nutzen zu verbergen, den ich aus meiner Erfahrung mit Yandex.Message gezogen habe.
Zu meinen beruflichen Aufgaben gehört die technische Befragung von Kandidaten für die Position des Fullstack-JavaScript- / TypeScript-Entwicklers. Ich war aktiv in diesem Geschäft tätig (ist es erwähnenswert, dass ich etwas satt habe?). Seit mehr als einem Jahr habe ich über 30 technische Befragungen.
Früher in einem technischen Interview stellte ich dem Kandidaten ziemlich dumme Fragen wie "Was ist ein Abschluss?", "Wie wird Vererbung in JavaScript implementiert?", "Hier ist eine solche Tabelle in einer Datenbank mit solchen Indizes. Bitte sagen Sie uns, wie Sie dies und das beschleunigen können." Anfrage “, die zwar dazu beitrug, die technischen Fähigkeiten des Bewerbers zu ermitteln, es ihm jedoch nicht ermöglichte, zu schließen, wie gut eine Person Probleme lösen und wie schnell sie einen vorhandenen Code herausfinden kann. Was konnte nur zu traurigen Konsequenzen führen ...
Aber alles änderte sich, nachdem ich vier Runden technischer Interviews bei Yandex durchlaufen hatte.
Normalerweise fliegen Steine in den Garten der Yandex-Interviewer, um:
1. Aufgaben, die keinen praktischen Wert haben;
2. Die Notwendigkeit, diese Probleme auf Papierstücken mit einem Bleistift oder auf einer Tafel zu lösen.
Bereits im Jahr 2019 ist es an der Zeit, eine separate Produktionslinie für das Gießen von Kesseln in der Hölle für diejenigen zu starten, die Menschen dazu zwingen, Text von Hand zu schreiben, ganz zu schweigen vom Code. Jede Person schreibt auf unterschiedliche Weise, und bei der Vorbereitung des Textes für diese Notiz musste ich beispielsweise diesen bestimmten Absatz sechsmal umschreiben. Wenn ich Notizen für Habr auf Papier schreiben würde, würde ich keine Notizen für Habr schreiben.
Aber ich stimme der These über die praktische Sinnlosigkeit von Yandex-Aufgaben nicht zu. Sogar die Routineentwicklung ist nein, nein, aber es wird Ihnen eine Aufgabe stellen, die mehrere Lösungen hat. Sie müssen nicht lange darüber nachdenken, aber es ist nicht optimal in Bezug auf Codegröße, Leistung oder Ausdruckskraft. Das andere ist genau das Gegenteil, erfordert jedoch vom Programmierer einige Erfahrung in der Erstellung effizienter und verständlicher Algorithmen. Hier ist ein Beispiel aus einem Interview:
getRanges([0, 1, 2, 3, 4, 7, 8, 10])
Bei diesem Problem habe ich ernsthaft abgestumpft und festgestellt, dass es nicht der schönste Weg ist. Die Lösung ist leider nicht erhalten geblieben, daher werde ich einem unserer Kandidaten eine Lösung geben:
function getRanges(arr: number[]) { return arr.map((v, k) => { if (v - 1 === arr[k - 1]) { if (arr[k + 1] === v + 1) { return '' } else { return `-${v},` } } else { return v + ',' } }).join('').split(',-').join('-') }
Von den Minuspunkten: Zugriff auf das Array an einem nicht vorhandenen Index und hässliche String-Manipulation: Join-Split-Join. Diese Lösung ist auch falsch, da im Beispiel getRanges ([1, 2, 3, 5, 6, 8]) "1-3,5-6,8" zurückgegeben wird und Sie das Komma am Ende "töten" müssen die Bedingungen weiter zu erhöhen, indem die Logik kompliziert und die Lesbarkeit verringert wird.
Hier ist eine Lösung im Yandex-Stil:
const getRanges = arr => arr .reduceRight((r, e) => r.length ? (r[0][0] === e + 1 ? r[0].unshift(e) : r.unshift([e])) && r : [[e]], []) .map(a => a.join('-')).join(',')
Wird Google beim Schreiben solch eleganter Lösungen helfen? Um einen solchen Code zu erstellen, benötigen Sie zwei Komponenten: Erfahrung mit vielen Algorithmen und ausgezeichnete Sprachkenntnisse. Und genau davor warnen Yandex-Personalvermittler: Sie werden Sie nach Algorithmen und Sprache fragen. Yandex bevorzugt es, Entwickler einzustellen, die coolen Code schreiben können. Solche Programmierer sind effektiv, aber vor allem austauschbar: Sie schreiben über dieselben Lösungen. Weniger theoretisch versierte Entwickler bei einer Aufgabe können Dutzende verschiedener, manchmal einfach erstaunlicher Lösungen herausgeben: Einer der Kandidaten für unsere Stelle hat eine solche Krücke eingewickelt, dass meine Augen auf meine Stirn gerichtet waren.
UPD: Wie der Benutzer
MaxVetrov feststellte , ist meine Lösung falsch:
getRanges([1,2,3,4,6,7])
Daher konnte ich dieses Problem bisher selbst nicht richtig lösen.
UPD2: Im Allgemeinen haben mich die Kommentare davon überzeugt, dass sich dieser Code als schlecht herausgestellt hat, auch wenn er richtig funktioniert hat.
Es war nicht umsonst, dass ich Zeit damit verbracht habe, im Yandex-Büro Papier zu übersetzen, weil ich in dieser Lektion verstanden habe, wie man selbst ein effektiver Interviewer wird. Ich habe die Idee und das Format ihrer Aufgaben als Grundlage genommen, aber:
- Ich habe nicht angeboten, Code auf Papier zu schreiben, sondern darum gebeten, in code.yandex-team.ru zu schreiben. Dies ist ein Mehrbenutzer-Online-Code-Editor ohne die Möglichkeit seiner Ausführung. Vielleicht gibt es eine andere, bequemere Option, aber es gab eine Suche und es war noch Faulheit übrig;
- Er brauchte keine ideale Lösung, bat aber darum, sie irgendwie zu lösen;
- Er brauchte keine Sprachkenntnisse auswendig, die gewünschte Funktion oder Methode konnte gefragt werden;
- Er reduzierte die Zeit für ein technisches Interview auf 30 Minuten.
Eines der Ziele unseres technischen Interviews:
let n = 0 while (++n < 5) { setTimeout(() => console.log(n), 10 + n) }
Ich denke, dies ist ein sehr wichtiger Test für den JavaScript-Entwickler. Und hier geht es nicht darum, die Unterschiede zwischen Vor- und Nachinkrementierung zu schließen und zu verstehen, sondern darum, dass aus unerklärlichen Gründen ein Viertel der Befragten glaubt, dass console.log vor Ablauf des Zyklus ausgeführt wird. Ich übertreibe nicht. Diese Personen haben einen Lebenslauf und eine Berufserfahrung von mindestens zwei Jahren und haben andere Aufgaben, die nicht an Rückrufe gebunden waren, erfolgreich gelöst. Entweder handelt es sich um eine neue Generation von JavaScript-Entwicklern, die mit async / await aufgewachsen sind und etwas anderes über Promise gehört haben, aber Rückrufe für sie - wie ein Festplattentelefon für einen modernen Teenager - werden die Nummer wählen, auch wenn dies nicht das erste Mal ist, aber nicht verstehen wie es funktioniert und warum.
Diese Aufgabe hat eine Fortsetzung: Sie müssen den Code hinzufügen, damit console.log auch in setTimeout ausgeführt wird, aber die Werte 1, 2, 3, 4 werden in der Konsole angezeigt. Das Sprichwort „leben, lernen“ ist hier angebracht, da einmal einer der Befragten schlug eine solche Lösung vor:
setTimeout(n => console.log(n), 10 + n, n)
Und dann fand ich heraus, dass setTimeout und setInterval das dritte und nachfolgende Argument an den Rückruf übergeben. Es ist eine Schande, ja. Wissen hat sich übrigens als nützlich erwiesen: Ich habe diese Funktion mehr als einmal verwendet.
Aber ich habe diese Aufgabe so wie sie ist von Yandex ausgeliehen:
fetchUrl('https://google/com') .then(...) .catch(...)
Hier sind getestete Fähigkeiten mit Promise. Normalerweise bitte ich, dieses Problem mit reinen Versprechungen zu lösen und dann async / await zu verwenden. Mit async / await ist die Lösung intuitiv einfach:
function async fetchUrl(url) { for (let n = 0; n < 5; n++) { try { return await fetch(url) } catch (err) { } } throw new Error('Fetch failed after 5 attempts') }
Sie können das Sprichwort "leben, lernen" auch auf diese Entscheidung anwenden, aber in Bezug auf meinen Yandex-Interviewer: Er hat nicht angegeben, dass asynchron / warten verwendet werden kann / nicht verwendet werden kann, und als ich diese Lösung schrieb, war er überrascht: "Ich habe nicht gearbeitet Mit async / await hätte ich nicht gedacht, dass es so einfach gelöst werden kann. " Er hatte wahrscheinlich erwartet, so etwas zu sehen:
function fetchUrl(url, attempt = 5) { return Promise.resolve() .then(() => fetch(url)) .catch(() => attempt-- ? fetchUrl(url, attempt) : Promise.reject('Fetch failed after 5 attempts')) }'error'
Dieses Beispiel kann zeigen, wie gut eine Person Versprechen versteht. Dies ist besonders wichtig auf der Rückseite. Als ich den JavaScript-Code eines Entwicklers sah, der die Versprechen nicht vollständig verstand, bereitete ich ein Versprechen für die Folgetransaktion wie folgt vor:
const transaction = Promise.resolve() for (const user of users) { transaction.then(() => { return some_action... }) }
Und ich frage mich, warum nur ein Benutzer in seiner Transaktion erscheint. Man könnte Promise.all verwenden, aber man könnte wissen, dass Promise.prototype.then keinen weiteren Rückruf hinzufügt, sondern ein neues Versprechen erstellt und es wird so sein:
let transaction = Promise.resolve() for (const user of users) { transaction = transaction.then(() => { await perform_some_operation... return some_action... }) }
In diesem Fall habe ich darüber nachgedacht, die Aufgabe, Versprechen zu verstehen, zu verkomplizieren, aber der Kandidat hat mir geholfen, eine neue Aufgabe zu formulieren. gab ihm im Quellcode eines unserer Projekte den richtigen Code:
public async addTicket(data: IAddTicketData): Promise<number> { const user = data.fromEmail ? await this.getUserByEmail(data.fromEmail) : undefined let category = data.category if (category === 'INCIDENT' && await this.isCategorizableType(data.type)) { category = 'INC_RFC' } const xml = await this.twig.render('Assyst/Views/add.twig', { from: data.fromEmail, text: data.text, category, user, }) const response = await this.query('events', 'post', xml) return new Promise((resolve, reject) => { xml2js.parseString(response, (err, result) => { if (err) { return reject(new Error(err.message)) } if (result.exception) { return reject(new Error(result.exception.message)) } resolve(result.event.id - 5000000) }) }) }
Und gebeten, die Schlüsselwörter async / await loszuwerden. Seitdem war diese Aufgabe die erste und in der Hälfte der Fälle die letzte beim Interview - er ist oft wirklich überfordert.
Ich selbst habe dieses Problem noch nie gelöst, bevor ich diese Notiz geschrieben und
zum ersten Mal zum dritten Mal geschrieben habe (die
erste ist zu lang, und bei der
zweiten habe ich nicht bemerkt, dass noch eine wartet):

Welche Schlussfolgerung kann daraus gezogen werden? Interviews sind interessant und nützlich ... Natürlich, wenn Sie nicht dringend Arbeit suchen.
Am Ende werde ich Ihnen eine weitere Aufgabe aus der Geschichte mit Yandex geben. Ich habe sie noch niemandem gezeigt
* . Ich habe mich um einen sogenannten Sonderfall gekümmert. Es gibt eine Reihe von Bannern. Jedes Banner hat ein „Gewicht“, das angibt, wie oft das Banner im Vergleich zu anderen Bannern angezeigt wird:
const banners = [ { name: 'banner 1', weight: 1 }, { name: 'banner 2', weight: 1 }, { name: 'banner 3', weight: 1 }, { name: 'banner 4', weight: 1 }, { name: 'banner 5', weight: 3 }, { name: 'banner 6', weight: 2 }, { name: 'banner 7', weight: 2 }, { name: 'banner 8', weight: 2 }, { name: 'banner 9', weight: 4 }, { name: 'banner 10', weight: 1 }, ]
Wenn beispielsweise drei Banner mit den Gewichten 1, 1, 2 vorhanden sind, beträgt deren kombiniertes Gewicht 4 und das Gewicht des dritten 2/4 des Gesamtgewichts. Daher sollte es in 50% der Fälle angezeigt werden. Es ist erforderlich, die Funktion getBanner zu implementieren, die zufällig, jedoch unter Berücksichtigung der Gewichte, ein Banner zur Anzeige zurückgibt. Die Lösung kann
in diesem Snippet überprüft werden,
in dem die erwartete und tatsächliche Verteilung angezeigt wird.
UPD: Sie haben angefangen, nicht nur den Artikel selbst zu vermindern, sondern auch Karma sprunghaft zu verbrennen, und ich habe es in verstecktem Material versteckt, was in Bezug auf Kommentatoren hässlich ist. Ich korrigiere diesen Mudachismus meinerseits.