Entwicklung kritischer Algorithmen: Implementierung

  1. Design
  2. Implementierung
  3. Integration


Als ich gerade meine Karriere in der beruflichen Entwicklung begann, verstand ich nicht, warum Open Source benötigt wurde. Nebenprojekte habe ich auch nicht verstanden. Warum wertvolle Arbeit kostenlos geben? Im Laufe der Jahre habe ich durch die Arbeit an Open Source-Projekten sowie durch die Arbeit mit Apex.AI, ROS 2 und Autoware.Auto ein gewisses Verständnis für Open Source gewonnen.



Ingenieure lieben es zu kreieren. Die Menschen wollen Anerkennung und Dankbarkeit.



Wenn Sie diese Faktoren miteinander kombinieren, haben Sie den Weg zu Open Source. Wenn ich etwas baue, das meinen kreativen Bedürfnissen entspricht, warum nicht alle anderen meine Arbeit schätzen lassen und darin praktischen Nutzen und Wert finden? Immerhin mache ich das nicht für das Geld.



Nebenprojekte erkannte ich ihren Charme erst, als ich anfing, mich professionell zu entwickeln und verschiedene Aspekte meiner Arbeit sorgfältiger anzugehen. Um ein zuverlässiges Produkt zu schaffen, für das die Menschen bezahlen, ist es häufig erforderlich, Arbeitsabläufe künstlich einzuschränken. Entwurfsanalyse. Code-Review. Codierungsstandards, Styleguides, Testabdeckungsmetriken usw. Versteh mich nicht falsch - all dies sind gute Dinge, die höchstwahrscheinlich notwendig sind, um ein Qualitätsprodukt zu entwickeln. Es ist nur so, dass ein Entwickler manchmal ein wenig Freiheit will. Ein Entwickler möchte möglicherweise erstellen, was er will, wie er will und wann er will. Keine Besprechungen, Überprüfungen oder Geschäftsfälle.



Wie kombinieren Sie diese Aspekte, wenn Sie sichere oder qualitativ hochwertige Algorithmen entwickeln? Ein großer Teil der Faszination der Open Source-Welt ist die Freiheit, und Praktiken, die dazu beitragen, dass zuverlässigerer Code entwickelt wird, schränken diese Freiheit ein.



Die Antwort, die ich gefunden habe, ist, einer offenen und konsequenten Disziplin zu folgen und viele coole Tools, die aus der Open-Source-Welt stammen, großzügig einzusetzen.



Open Source Projekte planen



Ingenieure benötigen spezielle Fähigkeiten, um diese Probleme anzugehen. Ingenieure müssen konzentriert sein, sie brauchen gute Fähigkeiten zur Problemlösung. Ingenieure müssen auch in der Lage sein, Bedenken zu trennen und über die erforderlichen soliden Grundkenntnisse zu verfügen, um Kenntnisse über alle oben genannten Punkte zu erlangen.



Diese besonderen Fähigkeiten können dazu führen, dass wir Ingenieure etwas überfordert sind.



Bei allen technischen Fähigkeiten der Ingenieure sind ihre Fähigkeiten letztendlich begrenzt. Ich würde argumentieren, dass die meisten Entwickler nicht in der Lage sind, das gesamte Projekt im Auge zu behalten, während sie einzelne Codezeilen schreiben. Darüber hinaus würde ich argumentieren, dass die meisten Entwickler ein umfassenderes Projekt nicht programmieren und im Kopf behalten können, ohne die allgemeinen Geschäftsziele zu vergessen.



Hier kommt die schwarze Magie des Projektmanagements ins Spiel.



Während wir Entwickler möglicherweise etwas kontroverse Beziehungen zu Personal-, Technik- oder Projektmanagern haben, sollte anerkannt werden, dass all diese Leute wichtige Arbeit leisten. Die besten Vertreter des Managementberufs sorgen dafür, dass Entwickler wichtige Aufgaben nicht aus den Augen verlieren, und nervige Irritationen hindern uns nicht daran, Probleme mit allen Waffen zu lösen.



Und obwohl wir die Bedeutung verschiedener Manager verstehen, beteiligen sich Menschen mit diesen Fähigkeiten normalerweise nicht an einem typischen Open-Source-Projekt, dessen Ziel es ist, Spaß zu haben.



Was sollen wir dann tun?



Nun, wir Entwickler können uns die Hände schmutzig machen und ein wenig Zeit im Voraus planen.



Ich werde nicht auf diese Gespräche eingehen , da ich im vorherigen Beitrag ausführlich auf die Planungsphasen für Design und Entwicklung eingegangen bin . Unter dem Strich bilden Sie unter Berücksichtigung des Designs und der Architektur, die in der Regel aus vielen Komponenten bestehen und einige Abhängigkeiten bilden, in Ihrem eigenen Projekt das Design selbst und sammeln seine Komponenten separat.



Um auf den Aspekt der Projektplanung zurückzukommen, beginne ich gerne mit den Komponenten mit den geringsten Abhängigkeiten (denken Sie eine Minute nach!) und arbeiten Sie dann weiter und fügen Sie bei Bedarf Implementierungsstubs hinzu, um die Entwicklung fortzusetzen. Mit dieser Arbeitsreihenfolge können Sie normalerweise viele Tickets erstellen (mit einigen Abhängigkeiten, die Ihren architektonischen Abhängigkeiten entsprechen - sofern Ihr Task-Tracker über solche Funktionen verfügt). Diese Tickets können einige allgemeine Hinweise enthalten, die Sie beachten sollten, bevor Sie sich eingehender mit einer Aufgabe befassen. Tickets sollten so klein und spezifisch wie möglich sein. Seien wir ehrlich - unser Fokus und unsere Fähigkeit, den Kontext zu halten, sind begrenzt. Je detaillierter die Entwicklungsaufgaben aufgeschlüsselt sind, desto einfacher. Warum also nicht versuchen, schwierige Aufgaben so einfach wie möglich zu gestalten?



Während sich Ihr Projekt weiterentwickelt, besteht Ihre Aufgabe darin, Tickets in der Reihenfolge ihrer Priorität zu nehmen und die ihnen zugewiesenen Aufgaben zu erledigen.



Dies ist offensichtlich eine stark vereinfachte Version des Projektmanagements. Es gibt viele andere Aspekte des echten Projektmanagements, wie Ressourcen, Planung, konkurrierende Geschäftsfälle und so weiter. Das Projektmanagement in Open Source kann einfacher und freier sein. Vielleicht gibt es in der Welt der Open Source-Entwicklung Fälle von vollwertigem Projektmanagement.



Offene Entwicklung



Nachdem wir einen Stapel Tickets getippt, einen Arbeitsplan erstellt und alle Details verstanden haben, können wir mit der Entwicklung fortfahren.



Viele der Freiheitsfaktoren, die im wilden Westen der offenen Entwicklung vorhanden sind, sollten jedoch nicht in der Entwicklung von sicherem Code liegen. Sie können viele Fallstricke vermeiden, indem Sie Open-Source-Tools verwenden und etwas Disziplin anwenden (und Freunde haben).



Ich bin ein großer Befürworter von Disziplin als Mittel zur Verbesserung der Arbeitsqualität (schließlich belegt Disziplin in meiner Bewertung zu StrengthsFinder den 6. Platz) Mit genügend Disziplin, um Open-Source-Tools zu verwenden, anderen zuzuhören, auf Ergebnisse zu reagieren und sich an Workflows zu halten, können wir viele der Fehler überwinden, die sich bei den Cowboy-Ansätzen der Open-Source-Welt einschleichen.



Kurz gesagt, die Verwendung der folgenden Tools und Vorgehensweisen (die mit einigen Einschränkungen problemlos in jedem Projekt angewendet werden können) trägt zur Verbesserung der Codequalität bei:



  1. Tests (oder noch besser, testgetriebene Entwicklung)
  2. Statische Analyse
  3. Kontinuierliche Integration (CI / CD)
  4. Code-Review


Ich werde auch eine Reihe von Grundsätzen angeben, die ich beim direkten Schreiben von Code befolge:



  1. TROCKEN
  2. Volle Nutzung von Sprache und Bibliotheken
  3. Der Code sollte lesbar und blendend offensichtlich sein.


Ich werde versuchen, diesen Text mit der tatsächlichen Implementierung des NDT-Lokalisierungsalgorithmus in Beziehung zu setzen , der in 10 Zusammenführungsanfragen von meinem guten Kollegen Yunus abgeschlossen wurde . Er ist zu beschäftigt mit direkter Arbeit, so dass ich mir einige imaginäre Medaillen anhängen kann, indem ich über seine Arbeit schreibe.



Um einige der Prozesse und Praktiken zu veranschaulichen, werde ich ein Beispiel für die Entwicklung eines Open-Source-Algorithmus für den MPC-Controller geben . Es wurde in einem etwas lockeren (Cowboy-) Stil in mehr als 30 Zusammenführungsanfragen entwickelt , ohne zusätzliche Änderungen und Verbesserungen, die nach Abschluss der Hauptarbeit vorgenommen wurden.



Testen



Lassen Sie uns über das Testen sprechen.



Ich hatte eine lange und nach meinen Maßstäben schwierige Beziehung zum Testen. Als ich zum ersten Mal eine Stelle als Entwickler bekam und das erste Projekt übernahm, glaubte ich absolut nicht, dass mein Code funktioniert, und deshalb war ich der erste im Team, der anfing, zumindest einige aussagekräftige Komponententests zu schreiben. Ich hatte jedoch absolut Recht, dass mein Code nicht funktionierte.



Seitdem hat meine turbulente Beziehung zum Testen viele Wendungen durchgemacht, die es wert sind, über Nacht gedreht zu werden. Manchmal hat es mir gefallen. Manchmal hasste ich alles. Ich habe zu viele Tests geschrieben. Zu viel Kopieren und Einfügen, zu viele redundante Tests. Dann wurde das Testen zu einer Routinearbeit, ein weiterer Teil der Entwicklung. Zuerst habe ich den Code geschrieben und dann habe ich Tests dafür geschrieben, das war die Reihenfolge der Dinge.



Jetzt habe ich eine normale Beziehung zum Testen. Es ist ein wesentlicher Bestandteil meines Workflows, unabhängig davon, an welcher Anwendung ich arbeite.



Was sich für mich geändert hat, sind die testgetriebenen Entwicklungstechniken, die ich in meinem mpc-Projekt verwendet habe.



Ich habe im vorherigen Text kurz über die testgetriebene Entwicklung gesprochen , aber hier ist eine andere Beschreibung des Prozesses:



  1. Entwickeln Sie eine Spezifikation (Anwendungsfälle, Anforderungen usw.).
  2. Implementieren Sie die API / Architektur
  3. Schreiben Sie Tests basierend auf API und Designspezifikation. sie müssen scheitern.
  4. Logik implementieren; Tests müssen bestehen


Es gibt einige Iterationen in diesem Prozess (Tests schlagen nicht auf Stubs fehl, Implementierung schlägt fehl, Tests können umständlich sein usw.), aber insgesamt denke ich, dass dies äußerst nützlich sein kann.



Ich habe vor der Implementierung viel über Planung gesprochen, und die testgetriebene Entwicklung bietet Ihnen diese Möglichkeit. Der erste Punkt wurde notiert. Dann denken Sie über Architektur und APIs nach und ordnen sie Anwendungsfällen zu. Dies gibt Ihnen eine großartige Gelegenheit, näher an den Code heranzukommen, aber dennoch umfassender über das Problem nachzudenken. Der zweite Punkt wurde zur Kenntnis genommen.



Dann schreiben wir Tests. Es gibt mehrere Gründe für die Vorteile, Tests vor der Implementierung zu schreiben, und ich denke, sie sind alle wichtig:



  1. Tests sollten als Objekte mit erster Priorität geschrieben werden, nicht als Add-Ons.
  2. , – .
  3. API , .
  4. , , , , .


Insgesamt denke ich, dass die Vorteile einer testgetriebenen Entwicklung enorm sind, und ich empfehle jedem erneut, es zumindest einmal auszuprobieren.



Kehren wir zu Autoware.Auto zurück. Yunus hielt sich zwar nicht an testgetriebene Entwicklungsmethoden, schrieb jedoch Tests für jede Zusammenführungsanforderung während der NDT-Entwicklung. Gleichzeitig war das Volumen des Testcodes gleich (und manchmal sogar größer) als das Volumen des Implementierungscodes, und das ist gut so. Im Vergleich dazu verfügt SQLite , das wahrscheinlich der Maßstab für Tests ist (nicht nur nach den Standards von Open Source-Projekten), über 662-mal mehr Testcode als Implementierungscode. Bei Autoware.Auto sind wir noch nicht ganz in diesem Stadium, aber wenn Sie sich den Verlauf der Zusammenführungsanforderungen im Zusammenhang mit NDT ansehen, werden Sie feststellen, dass das Volumen des Testcodes langsam hochgekrochen ist, bis es eine Abdeckung von 90% erreicht hat (obwohl es seitdem gesunken ist aufgrund anderer Designs und externer Codes).



Und das ist cool.



Ebenso hat mein mpc-Projekt Tests für alles, einschließlich der Tests selbst . Außerdem führe ich Regressionstests immer sorgfältig durch, um sicherzustellen, dass der Fehler behoben ist und nicht wieder auftritt.



Ich bin gut.



Statische Analyse



Viele Konzepte sind insofern neugierig, als die darin enthaltenen Definitionen erheblich erweitert werden können. Zum Beispiel geht das Testen weit über handgeschriebene Funktionstests hinaus. Tatsächlich kann die Stilprüfung oder die Fehlersuche auch als eine Form des Testens angesehen werden (es handelt sich im Wesentlichen um eine Inspektion, aber wenn Sie die Definition erweitern, kann dies als Testen bezeichnet werden).



Solche "Tests" sind etwas schmerzhaft und mühsam zu bearbeiten. Immerhin Validierung, Validierung für Tabs / Leerzeichen in Ausrichtung? Nein Danke.



Eines der unterhaltsamsten und wertvollsten Dinge beim Programmieren ist jedoch die Fähigkeit, schmerzhafte und zeitaufwändige Prozesse zu automatisieren. Gleichzeitig kann der Code schneller und genauer Ergebnisse erzielen als jede andere Person. Was ist, wenn wir dasselbe mit Fehlern und problematischen oder fehleranfälligen Konstrukten in unserem Code tun können?



Nun, wir können - mit statischen Analysewerkzeugen.



Ich habe in einem früheren Blog-Beitrag lange genug über statische Analysen geschrieben , damit ich nicht näher auf die Vorteile und die Tools eingehen kann, die Sie verwenden können.



In Autoware.Auto verwenden wir eine etwas kleinere Version des ament_lint- Setsvon unseren engen Freunden bei ROS 2. Diese Tools tun uns viel Gutes, aber vielleicht ist das Wichtigste, dass unser Code automatisch formatiert wird, um Stilstreitigkeiten zu beseitigen - unparteiische Tools sagen uns, was richtig und was falsch ist. Wenn Sie interessiert sind, werde ich feststellen, dass das Clang-Format strenger als nicht krustifizieren ist .



Im mpc-Projekt bin ich etwas weiter gegangen. Darin habe ich das Weverything- Flag des Clang-Compilers verwendet, zusätzlich zu allen Warnungen von clang-tidy und dem statischen Clang- Analysator . Überraschenderweise erforderte die kommerzielle Entwicklung die Deaktivierung mehrerer Optionen (aufgrund redundanter Warnungen und konzeptioneller Verwirrung)). Bei der Interaktion mit externem Code musste ich viele Überprüfungen deaktivieren - sie führten zu unnötigem Rauschen.



Letztendlich wurde mir klar, dass die Verwendung einer umfassenden statischen Analyse die normale Entwicklung nicht stark beeinträchtigt (beim Schreiben von neuem Code und nach Übergabe eines bestimmten Punkts auf der Lernkurve).



Es ist schwierig, den Wert der statischen Analyse zu quantifizieren, insbesondere wenn Sie sie von Anfang an verwenden. Der Punkt ist, dass es schwierig ist zu erraten, ob der Fehler vor der Einführung der statischen Analyse bestand oder nicht.



Ich glaube jedoch, dass die Verwendung von Warnungen und statischen Analysen eines der Dinge ist, bei denen man selbst bei korrekter Verwendung nicht sicher sein kann, dass sie überhaupt etwas getan haben.. Mit anderen Worten, Sie können sich nicht sicher sein, welchen Wert ein statischer Analysator hat, wenn er eingeschaltet ist, aber Sie werden feststellen, dass er nicht sofort verfügbar ist.



CI / CD



So sehr ich strenge Tests und statische / dynamische Code-Analysen liebe, sind alle Tests und Überprüfungen wertlos, wenn sie nicht ausgeführt werden. CI kann diese Herausforderungen mit minimalem Aufwand bewältigen.



Ich denke, alle sind sich einig, dass eine CI / CD- Infrastruktur ein wesentlicher Bestandteil der modernen Entwicklung ist sowie ein Versionskontrollsystem und Entwicklungsstandards (zumindest Styleguides). Der Wert einer guten CI / CD-Pipeline besteht jedoch darin, dass ihre Operationen reproduzierbar sein müssen.



Die CI / CD-Pipeline sollte mindestens Code erstellen und Tests ausführen, bevor der Code in Ihr Repository übertragen wird. Schließlich möchte niemand der Typ (oder das Mädchen oder die Person) sein, der eine Versammlung oder eine Art Test gebrochen hat und alles schnell und beschämend reparieren muss. CIs (und damit Ihre lieben DevOps-Ingenieure) schützen Sie vor dieser Schande.



Aber CI kann noch viel mehr für Sie tun.



Mit einer robusten CI-Pipeline können Sie eine beliebige Anzahl von Kombinationen von Betriebssystemen, Compilern und Architekturen testen (mit einigen Einschränkungen, wenn Sie Kombinationstests in Betracht ziehen ). Sie können auch Builds ausführen, Tests ausführen und andere Vorgänge ausführen, die für einen Entwickler zu ressourcenintensiv oder umständlich sein können, um sie manuell auszuführen. Du kannst nicht über deinen Kopf springen.



Wenn Sie zur ursprünglichen Aussage zurückkehren und eine CI / CD-Pipeline (die wir in Autoware.Auto verwenden ) in Ihrem Open-Source-Projekt haben, können Sie die unüberschaubare Entwicklung vorantreiben . Der Code kann nicht in das Projekt gelangen, wenn keine Tests erstellt oder bestanden werden. Wenn Sie strenge Testdisziplinen einhalten, können Sie immer sicher sein, dass der Code funktioniert.



In Autoware.Auto, CI:



  1. Sammelt Code
  2. Führt Tests aus (Stil, Linterprüfungen, Funktionstests).
  3. Misst die Testabdeckung
  4. Überprüft, ob der Code dokumentiert ist




Im Gegenzug meines hastig zusammengestellt CI im mpc Projekt:



  1. Sammelt Code
  2. Führt einen Scan durch (statische Clang-Analyse)
  3. Führt Tests aus (stoppt CI jedoch nicht, wenn Tests fehlschlagen).


Eine CI-Pipeline, die von einem erfahrenen DevOps-Ingenieur (wie unserem J.P. Samper oder Hao Peng !) Zusammengestellt wurde, kann viel mehr. Schätzen Sie also Ihre DevOps-Ingenieure. Sie machen unser Leben (als Entwickler) viel einfacher.



Code-Review



Benchmarks, Analysatoren und CI sind großartig. Sie können Tests ausführen, alles analysieren und sicherstellen, dass diese Tests mit CI durchgeführt werden, oder?



Leider gibt es keine.



Auch hier sind alle Tests auf der Welt wertlos, wenn sie schlecht sind. Wie stellen Sie sicher, dass Ihre Tests gut sind?



Leider habe ich keine magischen Antworten. Tatsächlich kehre ich zur alten Technik zurück, Peer Review. Insbesondere zur Codeüberprüfung.



Es wird allgemein angenommen, dass zwei Köpfe besser sind als einer. In der Tat würde ich argumentieren, dass dieses Konzept nicht nur von der Literatur, sondern auch von der Theorie unterstützt wird.



Ensemble von Methodenim maschinellen Lernen veranschaulicht diese Theorie. Es wird angenommen, dass die Verwendung eines Methodenensembles eine schnelle und einfache Möglichkeit ist, die Leistung statistischer Modelle zu verbessern (die bekannte Boosting- Methode ist ein Beispiel ). Aus rein statistischer Sicht ist die Varianz (mit Annahmen) umso geringer, je mehr Stichproben Sie haben. Mit anderen Worten, Sie sind eher der Wahrheit näher, wenn Sie mehr Mitarbeiter verbinden.



Sie können diese Technik anhand eines Live-Beispiels ausprobieren, indem Sie eine Teambuilding-Übung durchführen . Eine weniger unterhaltsame Version kann das Erraten zufälliger Statistiken einzeln und in einer Gruppe beinhalten.



Abgesehen von Theorie und Teambildung ist die Codeüberprüfung ein wichtiges und leistungsfähiges Werkzeug. Es überrascht nicht, dass die Codeüberprüfung ein wesentlicher Bestandteil jedes beruflichen Entwicklungsprozesses ist und sogar von der Norm ISO 26262 empfohlen wird.



All dies deutet darauf hin, dass immer die Gefahr besteht, dass ein Kind sieben Kindermädchen hat. Darüber hinaus kann die Codeüberprüfung manchmal bestimmte Schwierigkeiten verursachen.



Ich denke jedoch, dass Codeüberprüfungen Spaß machen und schmerzlos sein können, wenn sich sowohl der Prüfer als auch der Peer-Review an Folgendes erinnern:



  1. Du bist nicht dein Code.
  2. Sie sprechen mit einer anderen Person.
  3. Höflich sein
  4. Jeder arbeitet auf dasselbe Ziel hin; Code - Review stellt keine Konkurrenz (obwohl es manchmal geschieht in der Programmierung )


Viele klügere und nettere Leute als ich haben darüber geschrieben, wie man Codeüberprüfungen richtig durchführt, und ich lade Sie ein, sich ihre Arbeit anzusehen . Das Letzte, was ich sagen kann, ist, dass Sie Codeüberprüfungen durchführen sollten, wenn Sie möchten, dass Ihr Code zuverlässiger ist.



TROCKEN



Ich ging detailliert auf die Prozesse und Tools ein, mit denen eine Entwicklungsumgebung erstellt werden kann: Überprüfungen und Tools, die Überprüfungen durchführen und sicherstellen, dass der Code gut genug ist.



Als nächstes möchte ich kurz auf die Programmierkenntnisse eingehen und einige Gedanken zu den Prozessen und Absichten beim Schreiben einzelner Codezeilen austauschen.



Es gibt einige Konzepte, die mir geholfen haben, meinen Code erheblich zu verbessern. Eines dieser Konzepte war die Fähigkeit, sich an Absicht, Semantik und Lesbarkeit zu erinnern, worüber ich etwas später sprechen werde. Ein weiterer Grund ist das Verständnis von OOP und die Trennung von Bedenken . Die letzte wichtige Idee ist DRY ( Wiederholen Sie sich nicht ) oder das Prinzip "Wiederholen Sie sich nicht".



DRY ist das, was in der Schule gelehrt wird, und wie bei vielen anderen Dingen stellen wir diesen Gedanken in den Hintergrund und messen ihm außerhalb der Prüfungen (zumindest für mich) keine große Bedeutung bei. Aber wie bei vielen anderen Dingen in der Schule lernen wir so etwas nicht. In der Tat ist dies eine gute Praxis.



Einfach ausgedrückt, wenn Sie häufig Code kopieren und einfügen oder häufig sehr ähnlichen Code schreiben, ist dies ein sehr guter Hinweis darauf, dass wiederholbarer Code eine Funktion oder ein Teil einer Abstraktion werden sollte.



DRY geht jedoch noch weiter als zu überprüfen, ob Code in eine Funktion verschoben werden soll. Dieses Konzept kann auch als Grundlage für einige architektonische Entscheidungen dienen.



Obwohl sich dieser Ansatz mit einigen Architekturkonzepten überschneidet (wie Aliasing, Konnektivität und Trennung von Bedenken), ist in meinem mpc-Projekt ein Beispiel dafür zu sehen, wie DRY auf Architektur angewendet wird. Während der Entwicklung des MPC-Controllers habe ich festgestellt, dass ich Code duplizieren muss, wenn ich jemals einen anderen Controller schreibe. Es geht um Boilerplate-Code zum Verfolgen von Status, Posts, Abonnements, Conversions und dergleichen. Mit anderen Worten, es schien eine vom MPC-Controller getrennte Aufgabe zu sein.



Dies war ein guter Hinweis darauf, dass ich die allgemeinen Designs und Funktionen in eine separate Klasse unterteilen sollte . Die Amortisation war zweifach: Der MPC-Controller konzentriert sich zu 100% auf den Code, der sich auf MPC bezieht, und mitDas damit verbundene Modul ist nur eine Konfigurationsvorlage. Mit anderen Worten, aufgrund architektonischer Abstraktionen muss ich nicht alles neu schreiben, wenn ich mit einem anderen Controller arbeite.



Die Welt besteht aus Graustufen, daher sollten diese Designentscheidungen mit Sorgfalt und der richtigen Einstellung getroffen werden. Andernfalls können Sie zu weit gehen und Abstraktionen erstellen, wo sie nicht benötigt werden. Wenn der Entwickler jedoch die Konzepte berücksichtigt, die diese Abstraktionen modellieren, ist DRY ein leistungsstarkes Werkzeug zur Gestaltung von Architekturentscheidungen. Meiner Meinung nach ist DRY das Hauptkonzept, um Ihren Code sauber und dicht zu halten.



Schließlich ist einer der Hauptvorteile von Code die Fähigkeit, sich wiederholende Aufgaben auszuführen. Warum also nicht die Wiederholung auf gut gestaltete Funktionen und Klassen verlagern?



Volle Nutzung von Sprache und Bibliothek



DRY ist meiner Meinung nach ein so wichtiges und allgegenwärtiges Konzept, dass dieser Punkt wirklich nur eine Fortsetzung des DRY-Gesprächs ist.



Wenn Ihre Sprache etwas unterstützt, sollten Sie im Allgemeinen die Inline-Implementierung verwenden, es sei denn, Sie haben sehr gute Gründe, sich abzumelden. Und in C ++ sind viele Dinge eingebaut .



Programmieren ist eine Fähigkeit und es gibt einen großen Unterschied in den Fähigkeiten. Ich habe nur einen Blick darauf erhascht, wie hoch der Berg dieser Fähigkeit ist, und im Allgemeinen finde ich, dass die Leute, die Standards schaffen, gemeinsame Muster besser umsetzen können als ich.



Ein ähnliches Argument kann für die Funktionalität der Bibliotheken angeführt werden (wenn auch möglicherweise nicht so kategorisch). Jemand anderes hat das bereits getan und ist wahrscheinlich auf einem guten Niveau. Es gibt also keinen Grund, das Rad neu zu erfinden.



Trotzdem ist dieser Absatz, wie viele andere, eine Empfehlung und keine starre und dringende Regel. Es lohnt sich zwar nicht, das Rad neu zu erfinden, und während Standardimplementierungen im Allgemeinen sehr gut sind, macht es keinen Sinn, ein quadratisches Stück in ein rundes Loch zu drücken. Denk mit deinem Kopf nach.



Lesbarer Code



Das letzte Konzept, das mir geholfen hat, meine Programmierkenntnisse zu verbessern, war, dass es beim Programmieren weniger um das Schreiben von Code als vielmehr um Kommunikation geht. Wenn nicht Kommunikation mit anderen Entwicklern, dann Kommunikation mit sich selbst aus der Zukunft. Natürlich müssen Sie über Gedächtnis, Mathematik und die Komplexität des Big O nachdenken, aber sobald Sie dies erledigt haben, müssen Sie über Absicht, Semantik und Klarheit nachdenken.



Es gibt ein sehr berühmtes und weithin empfohlenes Buch zu diesem Thema, Clean Code , daher kann ich zu diesem Thema nicht viel hinzufügen. Hier sind einige allgemeine Informationen, auf die ich mich beziehe, wenn ich Code schreibe und Codeüberprüfungen durchführe:



  1. Versuchen Sie, Ihren Unterricht klar und konzentriert zu halten:

    • Minimieren Sie das Hängenbleiben
    • ()



      • const, noexcept? ? (, )




    • , (, , ).
    • (, )
    • .
  2. -



    • «», , .
    • (, ).
    • ( ) ().
  3. ? ()



    • , ().
    • , , , (, ).


Eine weitere großartige Ressource, die sich mit dieser Art von Problem befasst, sind die ISO C ++ - Kernrichtlinien .



Ich werde wiederholen, dass keines dieser Prinzipien revolutionär, neu oder einzigartig ist, aber wenn das Schreiben der Prinzipien einen Wert hat (oder jemand beim Lesen „Aha“ sagt ), habe ich keine Teile und keinen Verkehr verschwendet, um diesen Beitrag zu schreiben. ...



Zurückblicken



Dies waren einige der Tools, Prinzipien und Prozesse, die wir bei der Entwicklung und Implementierung des NDT-Lokalisierungsalgorithmus sowie bei der Arbeit am MPC-Controller verwendet haben. Es wurde viel gearbeitet, es hat Spaß gemacht, es ist nicht so interessant, darüber zu sprechen.



Insgesamt haben wir die von mir erwähnten Tools und Praktiken sehr gut genutzt, aber wir waren nicht perfekt.



So haben wir zum Beispiel bei der Arbeit am NDT nicht den Redewendungen der testgetriebenen Entwicklung gefolgt (obwohl wir alles perfekt getestet haben!). Im Gegenzug habe ich auf MPC testgetriebene Entwicklungstechniken angewendet, aber dieses Projekt profitierte nicht von dem leistungsstärkeren CI, das in Autoware.Auto integriert ist. Darüber hinaus war das MPC-Projekt nicht öffentlich und erhielt daher nicht die Vorteile einer Codeüberprüfung.



Beide Projekte könnten von der Einführung einer statischen Analyse, detaillierteren Tests und mehr Feedback profitieren. Wir sprechen jedoch über Projekte, die von einer Person erstellt wurden. Ich denke, dass die durchgeführten Tests und das erhaltene Feedback ausreichen. Wenn es um statische Analysen geht, fallen bessere und fokussiertere Formen im Allgemeinen in den Bereich der Produktentwicklungsinteressen und entfernen sich von der Open-Source-Entwicklergemeinschaft (obwohl interessante Ideen am Horizont auftauchen können ).



Ich kann nichts über die gleichzeitige Entwicklung von zwei Algorithmen sagen - wir haben nach besten Kräften gearbeitet und uns an die oben beschriebenen Prinzipien gehalten.



Ich denke, wir haben hervorragende Arbeit geleistet, um große Probleme in kleinere Teile zu zerlegen (obwohl die MR-Komponente im NDT-Algorithmus kleiner sein könnte) und umfangreiche Tests durchgeführt. Ich denke, die vorläufigen Ergebnisse sprechen für sich.



Vorwärtsbewegung



Nach der Implementierung ist es Zeit für die Integration. Es ist erforderlich, eine Verbindung zu einem größeren System mit eigenen komplexen Komponenten herzustellen. Dieses System nimmt Ihre Eingaben auf, verarbeitet sie und erstellt die Ergebnisse Ihres Algorithmus. Die Integration ist möglicherweise der schwierigste Teil bei der Entwicklung eines Algorithmus, da Sie den Gesamtsystemplan verfolgen und Probleme auf niedriger Ebene beheben müssen. Jeder Fehler in einer Ihrer vielen Codezeilen kann die Integration Ihres Algorithmus verhindern.



Ich werde dies im dritten und letzten Beitrag dieser Serie behandeln.



Als Vorschau möchte ich sagen, dass während des Entwicklungsprozesses kein einziger großer Fehler bei der Verwendung und Integration des MPC-Controllers gefunden wurde. Es stimmt, es gab einige Probleme beim Schreiben von Skripten , beim Zusammenstellen,Tests , die Validierung der Eingabedaten wurde übersprungen , und es gab auch Probleme mit der Inkompatibilität der QoS-Einstellungen , aber der Code enthielt nichts Schreckliches.



Tatsächlich konnte es fast sofort ausgeführt werden (unter Umgehung von QoS-Inkompatibilitäten und Einstellungsoptionen) .



Gleiches gilt für den NDT-Algorithmus, bei dem eine Reihe kleinerer Probleme aufgetreten sind , z. B. Instabilität der Kovarianz , Fehler bei der Suche nach Zeichenfolgen in vorhandenem Code und falsch ausgerichtete Karten. Unabhängig davon war es auch in der Lage, sofort zu arbeiten .



Nicht schlecht für Produkte, die jeder sehen kann.



Abonnieren Sie Kanäle:

@TeslaHackers — Tesla-, Tesla

@AutomotiveRu — ,







Bild



- automotive . 2500 , 650 .



, , . ( 30, ), -, -, - (DSP-) .



, . , , , . , automotive. , , .


:






All Articles