Ich schreibe keine großen Projekte. Ich verwalte keine riesige Datenbank und beschäftige mich nicht mit Millionen von Codezeilen.
Mein Code ist in erster Linie "Skripting" - Dinge zum Testen von mathematischen Funktionen oder zum Simulieren von etwas - "wissenschaftliches Programmieren". Die längsten Programme, an denen ich bis jetzt gearbeitet habe, sind ein paar hundert Codezeilen, und die meisten Programme, an denen ich arbeite, sind ungefähr 150.
Mein Code ist auch Mist. Ich habe das neulich bemerkt, als ich versucht habe, eine Datei zu finden, die ich vor einiger Zeit geschrieben habe, die ich aber wahrscheinlich überschrieben habe und die ich nicht mit Versionskontrolle verwende.
Der Stil meines Codes ist verworren und mit veralteten Kommentaren gefüllt, die alternative Vorgehensweisen angeben, oder mit Codezeilen, die überschrieben werden. Während die Variablennamen immer sehr nett und beschreibend beginnen, wenn ich Dinge hinzufüge oder ändere, wie z. B. etwas Neues, das jemand testen möchte, wird Code darüber gelegt und überschrieben, und weil ich der Meinung bin, dass dieses Ding jetzt schnell getestet werden sollte Ich habe ein Framework, in dem ich anfange, beschissene Variablennamen zu verwenden, und die Datei geht in den Topf.
In dem Projekt, an dem ich gerade arbeite, bin ich in der Phase, in der all das zurückkommt, um mich großartig zu beißen. Aber das Problem ist (abgesehen von der Verwendung der Versionskontrolle und dem Erstellen einer neuen Datei für jede neue Iteration und dem Aufzeichnen aller Dateien in einer Textdatei, was die Situation wahrscheinlich dramatisch verbessern wird), dass ich nicht wirklich weiß, wie ich mit der Verbesserung fortfahren soll Mein eigentlicher Codierungsstil.
Ist ein Komponententest erforderlich, um kleinere Codeteile zu schreiben? Wie wäre es mit OOP? Welche Ansätze eignen sich, um bei "wissenschaftlichem Programmieren" guten, sauberen Code schnell zu schreiben, anstatt an größeren Projekten zu arbeiten?
Ich stelle diese Fragen, weil die Programmierung selbst oft nicht sehr komplex ist. Es geht eher um Mathematik oder Naturwissenschaften, die ich mit der Programmierung teste oder erforsche. Ist zB eine Klasse notwendig, wenn zwei Variablen und eine Funktion sich wahrscheinlich darum kümmern könnten? (Bedenken Sie, dass dies im Allgemeinen auch Situationen sind, in denen die Geschwindigkeit des Programms am schnellsten ist. Wenn Sie mehr als 25.000.000 Zeitschritte einer Simulation ausführen, möchten Sie, dass dies der Fall ist.)
Vielleicht ist das zu weit gefasst, und wenn ja, entschuldige ich mich, aber wenn ich mir Programmbücher anschaue, scheinen sie oft bei größeren Projekten angesprochen zu werden. Mein Code nicht braucht OOP, und es ist schon verdammt kurz , so ist es nicht wie „oh, aber die Datei wird von tausend Zeilen reduziert werden , wenn wir das tun!“ Ich möchte wissen, wie ich bei diesen kleineren, schnelleren Projekten von vorne anfangen und sauber programmieren kann.
Ich würde gerne genauere Angaben machen, aber je allgemeiner der Rat, desto nützlicher, denke ich. Ich programmiere in Python 3.
Jemand schlug ein Duplikat vor. Lassen Sie mich klarstellen, dass es nicht darum geht, Standard-Programmierstandards direkt zu ignorieren. Es gibt natürlich einen Grund, warum diese Standards existieren. Aber auf der anderen Seite macht es wirklich Sinn, Code zu schreiben, der besagt, OOP, wenn einige Standard-Dinge hätten erledigt werden können, viel schneller zu schreiben gewesen wären und aufgrund der Kürze des Codes eine ähnliche Lesbarkeit gehabt hätten Programm?
Es gibt Ausnahmen. Darüber hinaus gibt es wahrscheinlich Standards für die wissenschaftliche Programmierung, die über reine Standards hinausgehen. Ich frage auch danach. Hier geht es nicht darum, ob normale Codierungsstandards beim Schreiben von wissenschaftlichem Code ignoriert werden sollten, sondern darum, sauberen wissenschaftlichen Code zu schreiben!
Aktualisieren
Ich dachte nur, ich würde eine Art Update "nicht ganz eine Woche später" hinzufügen. Alle Ihre Ratschläge waren äußerst hilfreich. Ich benutze jetzt Versionskontrolle - git mit git kraken für eine grafische Oberfläche. Es ist sehr einfach zu bedienen und hat meine Dateien drastisch aufgeräumt - es müssen keine alten Dateien mehr herumstehen oder alte Codeversionen "nur für den Fall" auskommentiert werden.
Ich habe auch pylint installiert und auf meinem gesamten Code ausgeführt. Eine Datei wurde anfangs negativ bewertet. Ich bin mir nicht mal sicher, wie das möglich war. Meine Hauptdatei begann mit einer Punktzahl von ~ 1,83 / 10 und liegt jetzt bei ~ 9,1 / 10. Der gesamte Code entspricht nun ziemlich gut den Standards. Ich überflog es auch mit meinen eigenen Augen und aktualisierte Variablennamen, die ... ähm ... schief gelaufen waren, und suchte nach Abschnitten, die umgestaltet werden sollten.
Insbesondere habe ich kürzlich auf dieser Website eine Frage zum Refactoring einer meiner Hauptfunktionen gestellt, und jetzt ist sie viel übersichtlicher und viel kürzer: Statt einer langen, aufgeblähten, wenn / sonst gefüllten Funktion ist sie jetzt weniger als die Hälfte die Größe und viel einfacher herauszufinden, was los ist.
Mein nächster Schritt ist die Implementierung von "Unit-Tests". Damit meine ich eine Datei, die ich auf meiner Hauptdatei ausführen kann, die alle darin enthaltenen Funktionen mit assert-Anweisungen und try / excepts anzeigt, was wahrscheinlich nicht der beste Weg ist, dies zu tun, und zu einer Menge doppeltem Code führt. aber ich lese weiter und versuche herauszufinden, wie ich es besser machen kann.
Ich habe auch die Dokumentation, die ich bereits geschrieben habe, erheblich aktualisiert und dem Github-Repository zusätzliche Dateien wie eine Excel-Tabelle, die Dokumentation und ein zugehöriges Dokument hinzugefügt. Es sieht jetzt aus wie ein echtes Programmierprojekt.
Also ... ich denke, das ist alles zu sagen: Danke .
quelle
Antworten:
Dies ist ein ziemlich häufiges Problem für Wissenschaftler. Ich habe es oft gesehen, und es ist immer darauf zurückzuführen, dass Sie sich nebenbei für das Programmieren als Werkzeug für Ihre Arbeit entscheiden.
Ihre Skripte sind also ein Durcheinander. Ich werde gegen den gesunden Menschenverstand gehen und sagen, dass es nicht so schlimm ist , vorausgesetzt, Sie programmieren alleine ! Sie werden das meiste von dem, was Sie schreiben, nie wieder anfassen, also verbringen Sie zu viel Zeit damit, hübschen Code zu schreiben, anstatt "Wert" zu produzieren (das Ergebnis Ihres Skripts), wird Ihnen nicht viel antun.
Es wird jedoch eine Zeit geben, in der Sie zu etwas zurückkehren müssen, das Sie getan haben, und genau sehen müssen, wie etwas funktioniert hat. Wenn andere Wissenschaftler Ihren Code überprüfen müssen, ist es außerdem sehr wichtig, dass er so klar und präzise wie möglich ist, damit jeder ihn verstehen kann.
Ihr Hauptproblem wird die Lesbarkeit sein. Hier einige Tipps zur Verbesserung:
Variablennamen:
Wissenschaftler lieben es, prägnante Notationen zu verwenden. Alle mathematischen Gleichungen verwenden normalerweise einzelne Buchstaben als Variablen, und ich wäre nicht überrascht, wenn Ihr Code viele, viele sehr kurze Variablen enthält. Dies schadet der Lesbarkeit sehr. Wenn Sie zu Ihrem Code zurückkehren, werden Sie sich nicht daran erinnern, was y, i und x2 darstellen, und Sie werden viel Zeit damit verbringen, es herauszufinden. Versuchen Sie stattdessen, Ihre Variablen explizit zu benennen und Namen zu verwenden, die genau das darstellen, was sie sind.
Teilen Sie Ihren Code in Funktionen auf:
Nachdem Sie alle Variablen umbenannt haben, sehen Ihre Gleichungen schrecklich aus und sind mehrzeilig.
Verschieben Sie die Gleichung in eine andere Funktion, anstatt sie in Ihrem Hauptprogramm zu belassen, und benennen Sie sie entsprechend. Anstatt eine riesige und durcheinandergebrachte Codezeile zu haben, erhalten Sie jetzt eine kurze Anleitung, die Ihnen genau erklärt, was los ist und welche Gleichung Sie verwendet haben. Dies verbessert sowohl Ihr Hauptprogramm, da Sie sich nicht einmal die tatsächliche Gleichung ansehen müssen, um zu wissen, was Sie getan haben, als auch den Gleichungscode selbst, da Sie in einer separaten Funktion Ihre Variablen benennen können, wie Sie möchten, und zurück zu die bekannteren einzelnen Buchstaben.
Versuchen Sie auf dieser Gedankenlinie, alle Teile des Codes herauszufinden, die für etwas stehen, insbesondere, wenn es sich um etwas handelt, das Sie mehrmals in Ihrem Code ausführen müssen, und teilen Sie sie in Funktionen auf. Sie werden feststellen, dass Ihr Code schnell leichter zu lesen ist und Sie dieselben Funktionen verwenden können, ohne mehr Code schreiben zu müssen.
Icing on the cake, wenn diese Funktionen in mehr Ihrer Programme benötigt werden, können Sie einfach eine Bibliothek für sie erstellen, und Sie werden sie immer verfügbar haben.
Globale Variablen:
Als Anfänger dachte ich, dies sei eine großartige Möglichkeit, Daten weiterzugeben, die ich in vielen Punkten meines Programms benötigte. Es hat sich herausgestellt, dass es viele andere Möglichkeiten gibt, Dinge zu umgehen, und die einzigen Dinge, die globale Variablen tun, sind Kopfschmerzen, da Sie niemals wissen werden, wann dieser Wert zuletzt verwendet oder bearbeitet wurde, und wenn Sie zu einem zufälligen Punkt Ihres Programms gehen es aufzuspüren wird ein Schmerz sein. Versuchen Sie, sie nach Möglichkeit zu meiden.
Wenn Ihre Funktionen mehrere Werte zurückgeben oder ändern müssen, erstellen Sie entweder eine Klasse mit diesen Werten und übergeben Sie sie als Parameter, oder veranlassen Sie die Funktion, mehrere Werte (mit benannten Tupeln) zurückzugeben und diese Werte im Aufrufercode zuzuweisen.
Versionskontrolle
Dadurch wird die Lesbarkeit nicht direkt verbessert, Sie können jedoch alle oben genannten Aufgaben ausführen. Wenn Sie Änderungen vornehmen, müssen Sie sich an die Versionskontrolle halten (ein lokales Git-Repository reicht aus), und wenn etwas nicht funktioniert, sehen Sie sich an, was Sie geändert haben, oder machen Sie einfach einen Rollback! Dies erleichtert die Umgestaltung Ihres Codes und ist ein Sicherheitsnetz, wenn Sie versehentlich etwas kaputt machen.
Wenn Sie all dies berücksichtigen, können Sie klaren und effektiveren Code schreiben und mögliche Fehler schneller finden, da Sie sich nicht durch riesige Funktionen und chaotische Variablen wühlen müssen.
quelle
Physiker hier. War dort.
Ich würde argumentieren, dass es bei Ihrem Problem nicht um die Auswahl von Tools oder Programmierparadigmen geht (Unit Testing, OOP, was auch immer). Es geht um die Einstellung , die Denkweise. Die Tatsache, dass Ihre Variablennamen anfangs gut gewählt sind und am Ende Mist sind, ist aufschlussreich genug. Wenn Sie Ihren Code als "einmal ausführen, dann wegwerfen" betrachten, wird es unvermeidlich ein Durcheinander sein. Wenn Sie es als das Produkt von Handwerk und Liebe betrachten, wird es schön sein.
Ich glaube, es gibt nur ein Rezept für das Schreiben von sauberem Code: Schreiben Sie es für den Menschen, der es lesen wird, nicht für den Interpreter, der es ausführen wird. Dem Interpreter ist es egal, ob Ihr Code ein Chaos ist, aber der menschliche Leser kümmert sich darum.
Sie sind Wissenschaftler. Sie können wahrscheinlich viel Zeit damit verbringen, einen wissenschaftlichen Artikel zu polieren. Wenn Ihr erster Entwurf kompliziert aussieht, werden Sie ihn umgestalten, bis die Logik auf die natürlichste Art und Weise fließt. Sie möchten, dass Ihre Kollegen es lesen und die Argumente kristallklar finden. Sie möchten, dass Ihre Schüler in der Lage sind, daraus zu lernen.
Das Schreiben von sauberem Code ist genau dasselbe. Stellen Sie sich Ihren Code als detaillierte Erklärung eines Algorithmus vor, der nur gelegentlich maschinenlesbar ist. Stellen Sie sich vor, Sie werden es als Artikel veröffentlichen, den die Leute lesen werden. Sie werden es sogar auf einer Konferenz zeigen und das Publikum Zeile für Zeile durchlaufen lassen. Nun proben Sie Ihre Präsentation . Ja, Zeile für Zeile ! Peinlich, nicht wahr? Räumen Sie also Ihre Folien auf (äh ... ich meine, Ihren Code) und proben Sie noch einmal. Wiederholen, bis Sie mit dem Ergebnis zufrieden sind.
Es wäre immer noch besser, wenn Sie nach den Proben Ihren Code echten Menschen zeigen könnten, anstatt nur imaginären Menschen und Ihrem zukünftigen Selbst. Das zeilenweise Durchgehen wird als „Code Walk“ bezeichnet und ist keine dumme Übung.
All dies hat natürlich einen Preis. Das Schreiben von sauberem Code nimmt viel mehr Zeit in Anspruch als das Schreiben von Wegwerfcode. Nur Sie können beurteilen, ob der Nutzen die Kosten für Ihren speziellen Anwendungsfall überwiegt.
Was die Werkzeuge betrifft, sagte ich, bevor sie nicht so wichtig sind. Wenn ich jedoch eine auswählen müsste, würde ich sagen, dass die Versionskontrolle die nützlichste ist.
quelle
Die Versionskontrolle wird Ihnen wahrscheinlich den größten Gewinn bringen. Es ist nicht nur für die Langzeitspeicherung gedacht, sondern auch zum Nachverfolgen Ihrer kurzfristigen Experimente und zum Zurückkehren zur letzten funktionierenden Version, wobei Notizen auf dem Weg gemacht werden.
Als nächstes sind Unit-Tests am nützlichsten. Die Sache bei Unit-Tests ist, dass sogar Codebasen mit Millionen von Codezeilen eine Funktion nach der anderen Unit-getestet werden. Unit-Tests werden auf der kleinsten Abstraktionsebene durchgeführt. Das heißt, es gibt grundsätzlich keinen Unterschied zwischen Unit-Tests, die für kleine Codebasen geschrieben wurden, und solchen, die für große Codebasen verwendet werden. Es gibt nur mehr von ihnen.
Unit-Tests sind der beste Weg, um zu verhindern, dass etwas kaputt geht, das bereits funktioniert hat, wenn Sie etwas anderes reparieren, oder um Ihnen zumindest schnell mitzuteilen, wann Sie dies tun. Sie sind eigentlich mehr nützlich , wenn Sie nicht als qualifizierte Programmierer sind, oder nicht wissen , wie oder wollen nicht ausführlichen Code zu schreiben , das strukturiert ist , um Fehler weniger wahrscheinlich oder deutlicher zu machen.
Zwischen der Versionskontrolle und dem Schreiben von Unit-Tests wird Ihr Code natürlich viel sauberer. Andere Techniken zur saubereren Codierung können erlernt werden, wenn Sie ein Plateau erreichen.
quelle
Sie hätten das wahrscheinlich selbst herausgefunden, aber wenn Sie " alles irgendwo in einer Textdatei aufzeichnen müssen ", nutzen Sie das Versionskontrollsystem nicht in vollem Umfang. Verwenden Sie etwas wie Subversion, Git oder Mercurial und schreiben Sie bei jedem Commit eine gute Commit-Nachricht. Sie erhalten ein Protokoll, das dem Zweck der Textdatei dient, aber nicht vom Repository getrennt werden kann.
Abgesehen davon ist die Verwendung der Versionskontrolle das Wichtigste, was Sie aus einem Grund tun können, der in keiner der vorhandenen Antworten erwähnt wird: Reproduzierbarkeit der Ergebnisse . Wenn Sie entweder Ihre Protokollnachrichten verwenden oder den Ergebnissen eine Notiz mit der Versionsnummer hinzufügen können, können Sie sicher sein, dass Sie die Ergebnisse erneut generieren können, und Sie sind besser in der Lage, den Code mit dem Papier zu veröffentlichen.
Komponententests sind nie notwendig, aber es ist nützlich, wenn (a) der Code so modular ist, dass Sie Einheiten und nicht das Ganze testen können; (b) Sie können Tests erstellen. Im Idealfall können Sie die erwartete Ausgabe von Hand schreiben, anstatt sie mit dem Code zu generieren. Wenn Sie sie jedoch mit Code generieren, erhalten Sie zumindest Regressionstests, mit denen Sie feststellen können, ob sich das Verhalten von etwas geändert hat. Überlegen Sie sich nur, ob die Tests mit größerer Wahrscheinlichkeit fehlerhaft sind als der Code, den sie testen.
OOP ist ein Werkzeug. Verwenden Sie es, wenn es hilft, aber es ist nicht das einzige Paradigma. Ich gehe davon aus, dass Sie die prozedurale Programmierung nur wirklich kennen: Wenn dies der Fall ist, dann würden Sie in dem beschriebenen Kontext meiner Meinung nach mehr vom Studium der funktionalen Programmierung als von der OOP profitieren, insbesondere von der Disziplin, nach Möglichkeit Nebenwirkungen zu vermeiden. Python kann in einem sehr funktionalen Stil geschrieben werden.
quelle
In der Graduiertenschule habe ich selbst einen algorithmischen Code geschrieben. Es ist ein bisschen eine harte Nuss zu knacken. Um es grob auszudrücken: Viele Programmierkonventionen basieren auf der Idee, Informationen in eine Datenbank einzufügen, sie zum richtigen Zeitpunkt abzurufen und diese Daten dann zu massieren, um sie einem Benutzer zu präsentieren. In der Regel wird eine Bibliothek für mathematische Zwecke verwendet algorithmische Teile dieses Prozesses. Für diese Programme ist alles, was Sie über OOP gehört haben, Code in kurze Funktionen zu unterteilen und alles auf einen Blick leicht verständlich zu machen, wo dies möglich ist, ein ausgezeichneter Rat. Aber es funktioniert nicht ganz für algorithmischen Code oder Code, der komplexe mathematische Berechnungen implementiert und sonst nichts.
Wenn Sie Skripte schreiben, um wissenschaftliche Berechnungen durchzuführen, haben Sie wahrscheinlich Artikel mit den Gleichungen oder Algorithmen, die Sie verwenden. Wenn Sie neue Ideen verwenden, die Sie selbst entdeckt haben, werden Sie sie hoffentlich in eigenen Artikeln veröffentlichen. In diesem Fall lautet die Regel: Sie möchten, dass Ihr Code den veröffentlichten Gleichungen so gut wie möglich entspricht. Hier ist eine Antwort auf Software Engineering.SE mit über 200 positiven Stimmen, die sich für diesen Ansatz aussprechen und erklären, wie er aussieht: Gibt es eine Entschuldigung für kurze Variablennamen?
Als weiteres Beispiel gibt es in Simbody , einem Tool für die Physiksimulation, das für die Physikforschung und -entwicklung verwendet wird , einige großartige Codeausschnitte . Diese Ausschnitte enthalten einen Kommentar, der eine Gleichung zeigt, die für eine Berechnung verwendet wird, gefolgt von Code, der so genau wie möglich mit den implementierten Gleichungen übereinstimmt.
ContactGeometry.cpp
:ContactGeometry_Sphere.cpp
:quelle
λ
oderφ
anstelle der hässlichenlambda_
oderphy
...Mein Tagesjob ist also die Veröffentlichung und Speicherung von Forschungsdaten für das System der University of California. Einige Leute haben die Reproduzierbarkeit erwähnt, und ich denke, das ist wirklich das Kernproblem hier: Dokumentieren Sie Ihren Code so, wie Sie alles dokumentieren würden, was jemand zur Reproduktion Ihres Experiments benötigt, und schreiben Sie im Idealfall Code, der es für beide einfach macht um Ihr Experiment zu reproduzieren und Ihre Ergebnisse auf Fehlerquellen zu überprüfen.
Was ich jedoch noch nicht erwähnt habe und für wichtig halte, ist, dass Finanzierungsagenturen die Veröffentlichung von Software zunehmend als Teil der Datenpublikation betrachten und die Veröffentlichung von Software zu einer Voraussetzung für offene Wissenschaft machen.
Zu diesem Zweck kann ich die Software Carpentry- Organisation nicht genug empfehlen, wenn Sie etwas Bestimmtes wünschen, das sich eher an Forscher als an allgemeine Softwareentwickler richtet . Wenn Sie an einem ihrer Workshops teilnehmen können , ist das großartig. Wenn Sie nur Zeit haben, einige ihrer Artikel über bewährte Methoden für das wissenschaftliche Rechnen zu lesen , ist das auch gut. Aus letzterem:
Ein allgemeiner Überblick über die von ihnen empfohlenen Praktiken:
Das Papier geht auf jeden dieser Punkte sehr detailliert ein.
quelle
Persönliche Antwort:
Ich schreibe viel für wissenschaftliche Zwecke. Bei kleineren Skripten versuche ich einfach, allgemeine gute Programmierpraktiken zu befolgen (z. B. Versionskontrolle, Selbstkontrolle mit Variablennamen). Wenn ich nur etwas schreibe, um einen Datensatz schnell zu öffnen oder zu visualisieren, kümmere ich mich nicht um OOP.
Allgemeine Antwort:
"Es kommt darauf an." Wenn Sie jedoch Schwierigkeiten haben, herauszufinden, wann Sie ein Programmierkonzept oder -paradigma verwenden sollten, sollten Sie Folgendes bedenken:
# 1: Machen Sie sich mit den Neuerungen vertraut:
Auch wenn Sie "nur" Skripte schreiben (und sich wirklich nur für die Wissenschaftskomponente interessieren), sollten Sie sich etwas Zeit nehmen, um sich mit den verschiedenen Programmierkonzepten und -paradigmen vertraut zu machen . Auf diese Weise können Sie eine bessere Vorstellung davon haben, was und wann Sie verwenden sollten / sollten. Das klingt vielleicht ein bisschen entmutigend. Und Sie haben möglicherweise immer noch die Frage: "Wo fange ich an / was schaue ich mir an?" Ich versuche, einen guten Ausgangspunkt in den nächsten beiden Aufzählungspunkten zu erläutern.
# 2: Fange an zu reparieren, was du weißt, ist falsch:
Ich persönlich würde mit den Dingen beginnen, von denen ich weiß, dass sie falsch sind. Holen Sie sich etwas Versionskontrolle und fangen Sie an, sich zu disziplinieren, um mit diesen Variablennamen besser zu werden (es ist ein schwerer Kampf). Es mag offensichtlich klingen, wenn Sie wissen, dass das, was Sie wissen, falsch ist. Nach meiner Erfahrung habe ich jedoch festgestellt, dass das Reparieren einer Sache mich zu etwas anderem führt und so weiter. Bevor ich es weiß, habe ich 10 verschiedene Dinge enthüllt, die ich falsch gemacht habe, und herausgefunden, wie man sie behebt oder auf saubere Weise implementiert.
# 3: Holen Sie sich einen Programmierpartner:
Wenn Sie keinen formellen Unterricht absolvieren müssen, sollten Sie sich mit einem Entwickler zusammenschließen und ihn bitten, Ihren Code zu überprüfen. Auch wenn sie den wissenschaftlichen Teil Ihrer Arbeit nicht verstehen, können sie Ihnen möglicherweise sagen, was Sie getan haben könnten, um Ihren Code eleganter zu gestalten.
# 4: Konsortien
suchen : Ich weiß nicht, in welchem wissenschaftlichen Bereich Sie tätig sind. Aber je nachdem, was Sie in der wissenschaftlichen Welt tun, suchen Sie nach Konsortien, Arbeitsgruppen oder Konferenzteilnehmern. Überprüfen Sie dann, ob Standards vorhanden sind, an denen gearbeitet wird. Das kann zu einigen Codierungsstandards führen. Zum Beispiel mache ich viel Geodatenarbeit. Der Blick auf Konferenzpapiere und Arbeitsgruppen führte mich zum Open Geospatial Consortium . Sie arbeiten unter anderem an Standards für die räumliche Entwicklung.
Ich hoffe das hilft!
Randnotiz: Ich weiß, Sie haben gerade OOP als Beispiel verwendet. Ich wollte nicht, dass du denkst, dass ich mich nur mit dem Schreiben von Code mit OOP beschäftige. Es war nur einfacher, eine Antwort zu schreiben, die dieses Beispiel fortsetzt.
quelle
Ich würde empfehlen, am Unix-Prinzip festzuhalten : Keep It Simple, Stupid! (KUSS)
Oder anders ausgedrückt: Machen Sie eine Sache nach der anderen und machen Sie es gut.
Was bedeutet das? Zunächst einmal bedeutet dies, dass Ihre Funktionen kurz sein sollten. Jede Funktion, deren Zweck, Verwendung und Implementierung innerhalb weniger Sekunden nicht vollständig verstanden werden kann, ist definitiv zu lang. Wahrscheinlich macht es mehrere Dinge gleichzeitig, von denen jede eine Funktion für sich sein sollte. Also spalte es auf.
In Bezug auf Codezeilen ist meine Heuristik, dass 10 Zeilen eine gute Funktion sind und alles, was über 20 hinausgeht, höchstwahrscheinlich Mist ist. Andere Leute haben andere Heuristiken. Das Wichtigste ist, die Länge so gering wie möglich zu halten.
Wie teilt man eine lange Funktion? Nun, zuerst suchen Sie nach sich wiederholenden Codemustern. Dann sind Sie ausklammern diese Codemuster, so dass sie einen beschreibenden Namen geben, und Ihr Code sehen schrumpfen . Das beste Refactoring ist das Refactoring, das die Codegröße reduziert.
Dies gilt insbesondere dann, wenn die betreffende Funktion mit Copy-Paste programmiert wurde. Immer wenn Sie ein solches wiederholtes Muster sehen, wissen Sie sofort, dass dies wahrscheinlich in eine eigene Funktion umgewandelt werden sollte. Dies ist das Prinzip von Don't Repeat Yourself (DRY) . Wann immer Sie Copy-Paste drücken, machen Sie etwas falsch! Erstellen Sie stattdessen eine Funktion.
Einige Funktionen können lang sein, weil sie mehrere verschiedene Dinge nacheinander ausführen. Dies sind keine DRY-Verstöße, aber sie können auch aufgeteilt werden. Das Ergebnis ist häufig eine übergeordnete Funktion, die eine Reihe von Funktionen aufruft, die die einzelnen Schritte der ursprünglichen Funktionen implementieren. Dies erhöht im Allgemeinen die Codegröße, aber die hinzugefügten Funktionsnamen bewirken, dass der Code besser lesbar ist. Denn jetzt haben Sie eine Top-Level-Funktion mit allen explizit genannten Schritten. Nach dieser Aufteilung ist auch klar, welcher Schritt mit welchen Daten arbeitet. (Funktionsargumente. Sie verwenden keine globalen Variablen, oder?)
Eine gute Heuristik für diese Art der Aufteilung von Abschnittsfunktionen ist immer dann, wenn Sie versucht sind, einen Abschnittskommentar zu schreiben, oder wenn Sie einen Abschnittskommentar in Ihrem Code finden. Dies ist sehr wahrscheinlich einer der Punkte, an denen Ihre Funktion aufgeteilt werden sollte. Der Abschnittskommentar kann auch dazu dienen, einen Namen für die neue Funktion anzugeben.
Die Prinzipien von KISS und DRY können Sie weit bringen. Sie müssen nicht sofort mit OOP usw. beginnen. Oft können Sie große Vereinfachungen erzielen, indem Sie nur diese beiden anwenden. Langfristig lohnt es sich jedoch, sich mit OOP und anderen Paradigmen vertraut zu machen, da sie Ihnen zusätzliche Tools bieten, mit denen Sie Ihren Programmcode klarer gestalten können.
Notieren Sie abschließend jede Aktion mit einem Commit. Sie zerlegen etwas in eine neue Funktion, das ist ein Commit . Sie verschmelzen zwei Funktionen zu einer, weil sie wirklich dasselbe tun, das ist ein Commit . Wenn Sie eine Variable umbenennen , ist dies ein Commit . Legen Sie häufig fest. Wenn ein Tag vergeht und Sie sich nicht verpflichtet haben, haben Sie wahrscheinlich etwas falsch gemacht.
quelle
Ich stimme den anderen zu, dass die Versionskontrolle viele Ihrer Probleme sofort lösen wird. Speziell:
Ich würde sagen, überdenke es nicht: benutze einfach git. Halten Sie sich an einfache Befehle (z. B. nur einen
master
Zweig), verwenden Sie möglicherweise eine grafische Benutzeroberfläche, und es sollte Ihnen gut gehen. Als Bonus kannst du gitlab, github usw. für kostenlose Veröffentlichungen und Backups verwenden;)Der Grund, warum ich diese Antwort geschrieben habe, war, zwei Dinge anzusprechen, die Sie vielleicht versuchen, aber ich habe sie oben nicht gesehen. Die erste besteht darin, Behauptungen als einfache Alternative zu Unit-Tests zu verwenden. Unit-Tests tendieren dazu, sich "außerhalb" der Funktion / des Moduls / des zu testenden Objekts zu befinden: Sie senden normalerweise einige Daten an eine Funktion, empfangen ein Ergebnis zurück und überprüfen dann einige Eigenschaften dieses Ergebnisses. Dies ist im Allgemeinen eine gute Idee, kann jedoch aus folgenden Gründen unpraktisch sein (insbesondere, wenn Code weggeworfen werden soll):
Behauptungen haben diese Nachteile nicht, da sie während der normalen Ausführung eines Programms überprüft werden. Speziell:
Sie erwähnen die Geschwindigkeit als einen Faktor. In diesem Fall ist die Überprüfung von Zusicherungen in dieser Schleife möglicherweise unerwünscht (aber dennoch nützlich, um die Einrichtung und die nachfolgende Verarbeitung zu überprüfen). Fast alle Implementierungen von Zusicherungen bieten jedoch eine Möglichkeit, sie zu deaktivieren. Zum Beispiel können sie in Python anscheinend durch Ausführen mit der
-O
Option deaktiviert werden (das wusste ich nicht, da ich noch nie das Bedürfnis hatte, eine meiner Behauptungen zu deaktivieren). Ich würde empfehlen, dass Sie sie auf lassenstandardmäßig; Wenn sich Ihr Codierungs- / Debugging- / Testzyklus verlangsamt, ist es möglicherweise besser, mit einer kleineren Teilmenge Ihrer Daten zu testen oder während des Testens weniger Iterationen einer Simulation durchzuführen oder was auch immer. Wenn Sie Behauptungen in Nicht-Testläufen aus Leistungsgründen deaktivieren, ist das erste, was ich empfehle, zu messen, ob sie tatsächlich die Ursache für die Verlangsamung sind! (Es ist sehr leicht, sich zu täuschen, wenn es um Leistungsengpässe geht)Mein letzter Ratschlag wäre, ein Build-System zu verwenden, das Ihre Abhängigkeiten verwaltet. Ich persönlich benutze Nix dafür, habe aber auch gute Dinge über Guix gehört . Es gibt auch Alternativen wie Docker, die aus wissenschaftlicher Sicht weitaus weniger nützlich, aber vielleicht ein wenig vertrauter sind.
Systeme wie Nix werden erst seit kurzem (ein wenig) populär, und manche mögen sie für übertrieben halten, um Code, wie Sie ihn beschreiben, "wegzuwerfen", aber ihr Nutzen für die Reproduzierbarkeit des wissenschaftlichen Rechnens ist enorm. Betrachten Sie ein Shell-Skript zum Ausführen eines Experiments wie dieses (zB
run.sh
):Wir können es stattdessen wie folgt in eine Nix-Ableitung umschreiben
run.nix
:Das Zeug dazwischen
''...''
ist Bash-Code, derselbe wie zuvor, mit der Ausnahme, dass er${...}
verwendet werden kann, um den Inhalt anderer Zeichenfolgen zu "spleißen" (in diesem Fall./.
wird er auf den Pfad des Verzeichnisses erweitert, das ihn enthältrun.nix
). Diewith import ...
Zeile importiert die Standardbibliothek von Nix , in derrunCommand
Bash-Code ausgeführt werden kann. Wir können unser Experiment unter Verwendung von ausführennix-build run.nix
, wodurch sich ein Pfad wie ergibt/nix/store/1wv437qdjg6j171gjanj5fvg5kxc828p-output.csv
.Was bringt uns das? Nix wird automatisch eine "saubere" Umgebung einrichten, die nur Zugriff auf Dinge hat, nach denen wir ausdrücklich gefragt haben. Insbesondere hat es keinen Zugriff auf Variablen wie
$HOME
oder eine von uns installierte Systemsoftware. Dies macht das Ergebnis unabhängig von den Details unserer aktuellen Maschine, wie dem Inhalt~/.config
oder den Versionen von Programmen, die wir zufällig installiert haben. AKA das Zeug, das andere Leute davon abhält, unsere Ergebnisse zu replizieren! Deshalb habe ich das hinzugefügtcp
Befehl, da das Projekt standardmäßig nicht zugänglich ist. Es mag ärgerlich erscheinen, dass die Software des Systems für ein Nix-Skript nicht verfügbar ist, aber es geht auch in die andere Richtung: Auf unserem System muss nichts (außer Nix) installiert sein, um sie in einem Skript verwenden zu können. wir fragen einfach danach und Nix wird loslegen und alles Nötige holen / kompilieren / was auch immer nötig ist (die meisten Dinge werden als Binärdateien heruntergeladen; die Standardbibliothek ist auch riesig!). Wenn wir zum Beispiel eine Reihe bestimmter Python- und Haskell-Pakete für einige bestimmte Versionen dieser Sprachen und einige andere Junk-Dateien benötigen (warum nicht?):Der selbe
nix-build run.nix
wird dies ausführen und alles holen, wonach wir zuerst gefragt haben (und alles zwischenspeichern, falls wir es später wollen). Die Ausgabe (jede Datei / jedes Verzeichnis, das aufgerufen wird$out
) wird von Nix gespeichert. Dies ist der Pfad, den es ausgibt. Es wird durch den kryptografischen Hash aller von uns angeforderten Eingaben identifiziert (Skriptinhalte, andere Pakete, Namen, Compiler-Flags usw.). Diese anderen Pakete werden durch Hashes ihrer Eingaben usw. identifiziert , sodass wir eine vollständige Kette von Provinenzen für alles haben, zurück zu der Version von GCC, die die Version von GCC kompiliert hat, die die Bash kompiliert hat, und so weiter!Hoffentlich habe ich gezeigt, dass dies uns viel für wissenschaftlichen Code einkauft und einigermaßen einfach ist, damit anzufangen. Es wird auch von Wissenschaftlern sehr ernst genommen, zB (Top-Google-Hit) https://dl.acm.org/citation.cfm?id=2830172. Dies könnte eine wertvolle Fähigkeit sein, die man kultivieren kann (genau wie das Programmieren).
quelle
Ohne auf die vollständige Versionskontrolle + Verpackung + Einheitentests zurückgreifen zu müssen (das sind gute Programmierpraktiken, die Sie irgendwann versuchen sollten), besteht eine meiner Meinung nach passende Zwischenlösung in der Verwendung von Jupiter Notebook . Dies scheint sich besser in die wissenschaftliche Berechnung integrieren zu lassen.
Es hat den Vorteil, dass Sie Ihre Gedanken mit dem Code mischen können; Erklären, warum ein Ansatz besser ist als ein anderer, und Belassen des alten Codes in einem Ad-hoc-Abschnitt. Neben der richtigen Verwendung von Zellen werden Sie natürlich dazu gebracht, Ihren Code zu fragmentieren und in Funktionen zu organisieren, die das Verständnis erleichtern.
quelle
Die besten Antworten sind bereits gut, aber ich wollte einige Ihrer Fragen direkt beantworten.
Die Größe des Codes steht nicht in direktem Zusammenhang mit der Notwendigkeit von Komponententests. Dies hängt indirekt zusammen: In komplexen Codebasen sind Komponententests wertvoller , und kleine Codebasen sind im Allgemeinen nicht so komplex wie größere.
Unit-Tests überzeugen durch Code, bei dem es leicht ist, Fehler zu machen, oder wenn Sie viele Implementierungen dieses Codes haben werden. Unit-Tests helfen Ihnen wenig bei der aktuellen Entwicklung, verhindern jedoch, dass Sie in Zukunft Fehler machen, die dazu führen, dass sich vorhandener Code plötzlich schlecht verhält (obwohl Sie das Ding nicht angerührt haben).
Angenommen, Sie haben eine Anwendung, in der Bibliothek A das Quadrieren von Zahlen ausführt und Bibliothek B den Satz von Pythagoras anwendet. Offensichtlich hängt B von A ab. Sie müssen etwas in Bibliothek A korrigieren. Nehmen wir an, Sie führen einen Fehler ein, der Zahlen würfelt, anstatt sie zu quadrieren.
Bibliothek B verhält sich plötzlich schlecht und löst möglicherweise Ausnahmen aus oder gibt einfach eine falsche Ausgabe aus. Und wenn Sie sich die Versionshistorie von Bibliothek B ansehen, sehen Sie, dass sie unberührt bleibt. Das problematische Endergebnis ist, dass Sie keinen Hinweis darauf haben, was schief gehen könnte, und dass Sie das Verhalten von B debuggen müssen, bevor Sie erkennen, dass das Problem in A liegt. Das ist vergeblicher Aufwand.
Komponententests eingeben. Diese Tests bestätigen, dass Bibliothek A wie beabsichtigt funktioniert. Wenn Sie einen Fehler in Bibliothek A einführen, der zu schlechten Ergebnissen führt, werden Ihre Komponententests dies feststellen. Daher müssen Sie nicht länger versuchen, Bibliothek B zu debuggen.
Dies liegt außerhalb Ihres Bereichs. In einer kontinuierlichen Integrationsentwicklung werden Komponententests jedoch immer dann ausgeführt, wenn jemand Code festschreibt.
Insbesondere für komplizierte mathematische Operationen können Unit-Tests ein Segen sein. Sie führen einige Beispielberechnungen durch und schreiben dann Einheitentests, in denen Ihre berechnete Ausgabe und Ihre tatsächliche Ausgabe (basierend auf denselben Eingabeparametern) verglichen werden.
Beachten Sie jedoch, dass Sie mit Unit-Tests keinen guten Code erstellen , sondern ihn beibehalten können. Wenn Sie Code normalerweise einmal schreiben und ihn nie wieder aufrufen, sind Komponententests weniger vorteilhaft.
OOP ist eine Denkweise über verschiedene Entitäten, zum Beispiel:
Vergleichen Sie dies damit, wie ein funktionaler Programmierer über Dinge denkt:
Äpfel und Orangen. Keiner von ihnen ist objektiv besser als der andere. Eine interessante Sache zu beachten ist, dass für OOP,
Vendor
wird zweimal erwähnt, aber es bezieht sich auf die gleiche Sache. Doch für die funktionale Programmierung,talktoVendor()
undpayVendor()
sind zwei verschiedene Dinge.Dies zeigt den Unterschied zwischen den Ansätzen. Wenn zwischen diesen beiden Aktionen viele herstellerspezifische Gemeinsamkeiten bestehen, trägt OOP zur Reduzierung der Codeduplizierung bei. Wenn es jedoch keine gemeinsame Logik zwischen den beiden gibt, ist das Zusammenführen zu einer einzigen
Vendor
vergeblich (und daher ist funktionale Programmierung effizienter).In den meisten Fällen sind mathematische und wissenschaftliche Berechnungen unterschiedliche Operationen, die nicht auf impliziter gemeinsamer Logik / Formel beruhen. Aus diesem Grund wird funktionale Programmierung häufiger verwendet als OOP.
Ihre Frage impliziert, dass sich die Definition von "gutem, sauberem Code" ändert, unabhängig davon, ob Sie wissenschaftliche Programme ausführen oder an größeren Projekten (ich nehme an, Sie meinen Unternehmensprojekte) arbeiten.
Die Definition von gutem Code ändert sich nicht. Die Notwendigkeit, Komplexität zu vermeiden (was durch das Schreiben von sauberem Code erreicht werden kann), ändert sich jedoch.
Das gleiche Argument kommt hier zurück.
Ich verstehe die Unterscheidung, die Sie hier treffen, aber wenn Sie auf vorhandenen Code zurückblicken , betrachten Sie sowohl die Mathematik als auch die Programmierung. Wenn entweder erfunden oder komplex ist, werden Sie Schwierigkeiten haben, es zu lesen.
Abgesehen von den OOP-Prinzipien ist der Hauptgrund, warum ich Klassen schreibe, um einige Datenwerte aufzunehmen, die Vereinfachung der Deklaration von Methodenparametern und Rückgabewerten. Wenn ich zum Beispiel viele Methoden habe, die einen Ort verwenden (Lat / Lon-Paar), werde ich schnell müde zu tippen
float latitude, float longitude
und schreibe viel lieberLocation loc
.Dies wird noch weiter verschärft, wenn Sie berücksichtigen, dass Methoden im Allgemeinen einen Wert zurückgeben (es sei denn, es gibt sprachspezifische Features, um mehr Werte zurückzugeben), und wenn Sie beispielsweise bei einem Standort zwei Werte zurückgeben möchten (lat + lon). Dies ist ein Anreiz für Sie, eine
Location
Klasse zu erstellen , um Ihren Code zu vereinfachen.Eine weitere interessante Sache ist, dass Sie OOP verwenden können, ohne Datenwerte und Methoden zu mischen. Nicht jeder Entwickler stimmt dem zu (manche nennen es ein Antipattern), aber Sie können anämische Datenmodelle haben, in denen Sie separate Datenklassen (speichert Wertfelder) und Logikklassen (speichert Methoden) haben.
Dies ist natürlich ein Spektrum. Sie müssen nicht perfekt anämisch sein, Sie können es verwenden, wenn Sie es für angemessen halten.
Zum Beispiel kann eine Methode, die einfach den Vor- und Nachnamen einer Person verkettet, immer noch in der
Person
Klasse selbst enthalten sein, da es sich nicht wirklich um eine "Logik" handelt, sondern um einen berechneten Wert.Eine Klasse ist immer so groß wie die Summe ihrer Felder. Am Beispiel von
Location
again, das aus zweifloat
Werten besteht, ist zu beachten, dass ein einzelnesLocation
Objekt genauso viel Speicherplatz beansprucht wie zwei separatefloat
Werte.In diesem Sinne spielt es keine Rolle, ob Sie OOP verwenden oder nicht. Der Speicherbedarf ist der gleiche.
Die Performance selbst ist auch keine große Hürde zu überwinden. Der Unterschied zwischen der Verwendung einer globalen Methode oder einer Klassenmethode hat nichts mit der Laufzeitleistung zu tun, sondern mit der Generierung von Bytecode zur Kompilierungszeit.
Stellen Sie sich das so vor: Ob ich mein Kuchenrezept auf Englisch oder Spanisch schreibe, ändert nichts an der Tatsache, dass das Backen des Kuchens 30 Minuten dauert (= Laufzeitleistung). Die Sprache des Rezepts ändert sich nur dadurch, wie der Koch die Zutaten mischt (= den Bytecode zusammenstellt).
Für Python müssen Sie den Code nicht explizit vorkompilieren, bevor Sie ihn aufrufen. Wenn Sie jedoch nicht vorkompilieren, wird die Kompilierung ausgeführt, wenn Sie versuchen, den Code auszuführen. Wenn ich "Laufzeit" sage, meine ich die Ausführung selbst, nicht die Kompilierung, die der Ausführung vorausgehen könnte.
quelle
Vorteile eines sauberen wissenschaftlichen Codes
Es kann hilfreich sein, Ihren Code aus der Perspektive eines zukünftigen Codierers zu betrachten.
Meiner Erfahrung nach,
Sauberer Code sollte es einfach machen, Ihre Ergebnisse zu überprüfen
Möglicherweise möchten Sie Ihr Programm so aufteilen, dass einzelne Algorithmen separat verglichen werden können.
Vermeiden Sie das Schreiben von Funktionen mit kontraintuitiven Nebeneffekten, bei denen ein Vorgang ohne Beziehung zu einem anderen Vorgang führt, der sich anders verhält. Wenn Sie es nicht vermeiden können, dokumentieren Sie, was Ihr Code benötigt und wie Sie ihn einrichten.
Clean Code kann als Beispielcode für zukünftige Codierer dienen
Klare Kommentare (einschließlich solcher, die zeigen, wie Funktionen aufgerufen werden sollten) und gut getrennte Funktionen können einen großen Unterschied darin ausmachen, wie lange es dauert, bis jemand anfängt (oder Sie zukünftig), etwas Nützliches aus Ihrer Arbeit zu machen.
Darüber hinaus können Sie sich durch die Erstellung einer echten "API" für Ihren Algorithmus besser vorbereiten, wenn Sie Ihre Skripte in eine echte Bibliothek für andere Benutzer umwandeln möchten.
Empfehlungen
Mathematische Formeln mit Kommentaren "zitieren".
John Smith Method from Some Book 1st Ed. Section 1.2.3 Pg 180
, dass Sie die Formel auch auf einer Website oder in einer Zeitung gefunden haben.Verwenden Sie Kommentare mit Bedacht
Wenn Sie die Lesbarkeit Ihres Codes verbessern können, indem Sie gute Variablennamen / Funktionsnamen verwenden, tun Sie dies zuerst. Denken Sie daran, dass Kommentare für immer erhalten bleiben, bis Sie sie entfernen. Versuchen Sie daher, Kommentare zu verfassen, die nicht veraltet sind.
Verwenden Sie beschreibende Variablennamen
xBar_AverageVelocity
Schreiben Sie Code, um Ihr Programm gegen bekannte gute und bekannte schlechte Daten auszuführen.
Ich denke, Unit-Tests können hilfreich sein. Ich denke, die beste Form von Unit-Tests für wissenschaftlichen Code sind eine Reihe von Tests, die mit bekannten schlechten und guten Daten durchgeführt werden.
Schreiben Sie Code, um Ihren Algorithmus auszuführen, und überprüfen Sie, inwieweit das Ergebnis von Ihren Erwartungen abweicht. Dies hilft Ihnen, Probleme zu finden (möglicherweise sehr schlimm und schwer zu finden), bei denen Sie versehentlich etwas hart codieren, was zu einem falsch positiven Ergebnis führt, oder einen Fehler machen, der dazu führt, dass die Funktion immer den gleichen Wert zurückgibt.
Beachten Sie, dass dies auf jeder Abstraktionsebene möglich ist. Sie können beispielsweise einen gesamten Pattern-Matching-Algorithmus oder eine Funktion testen, die nur den Abstand zwischen zwei Ergebnissen in Ihrem Optimierungsprozess berechnet. Beginnen Sie mit den Bereichen, die für Ihre Ergebnisse am wichtigsten sind, und / oder mit den Teilen des Codes, die Sie am meisten interessieren.
Erleichtern Sie das Hinzufügen neuer Testfälle, erwägen Sie das Hinzufügen von "Hilfsfunktionen" und strukturieren Sie Ihre Eingabedaten effektiv. Dies kann bedeuten, dass möglicherweise Eingabedaten in einer Datei gespeichert werden, damit Sie die Tests problemlos wiederholen können. Achten Sie jedoch darauf, dass Sie keine falsch positiven oder voreingenommenen / trivial gelösten Testfälle erhalten.
Erwägen Sie die Verwendung einer Kreuzvalidierung. Weitere Informationen finden Sie in diesem Beitrag zur Kreuzvalidierung .
Verwenden Sie die Versionskontrolle
Ich würde empfehlen, die Versionskontrolle zu verwenden und Ihr Repository auf einer externen Site zu hosten. Es gibt Websites, auf denen Repositories kostenlos gehostet werden.
Vorteile:
Seien Sie vorsichtig beim Kopieren / Einfügen von Code
Das Kopieren / Einfügen von Code kann Ihnen Zeit sparen, ist jedoch eine der gefährlichsten Aktionen, die Sie ausführen können, insbesondere wenn es sich um Code handelt, den Sie nicht selbst geschrieben haben (z. B. wenn es sich um Code eines Kollegen handelt).
Sobald Sie den Code zum Laufen gebracht und getestet haben, empfehle ich Ihnen, ihn sorgfältig durchzuarbeiten, um alle Variablen umzubenennen oder etwas zu kommentieren, was Sie nicht verstehen.
quelle
Die Werkzeuge des Handels sind in der Regel erfunden, um ein Bedürfnis zu lösen. Wenn Sie die Notwendigkeit haben, verwenden Sie das Tool, wenn nicht, müssen Sie höchstwahrscheinlich nicht.
Insbesondere sind wissenschaftliche Programme nicht das Ziel, sondern das Mittel. Sie schreiben das Programm, um ein Problem zu lösen, das Sie jetzt haben - Sie erwarten nicht, dass dieses Programm in zehn Jahren von anderen verwendet wird (und gewartet werden muss). Das allein bedeutet , dass Sie nicht haben , in eines des Werkzeug zu denken , dass die aktuellen Entwickler aufzeichnen Geschichte für andere wie Versionskontrolle, oder Capture - Funktionalität in Code wie Unit - Tests ermöglichen.
Was würde dir dann nützen?
quelle
Zusätzlich zu den guten Ratschlägen hier möchten Sie vielleicht den Zweck Ihrer Programmierung und damit das berücksichtigen, was für Sie wichtig ist.
"Es geht mehr um Mathematik oder Naturwissenschaften, die ich mit der Programmierung teste oder erforsche."
Wenn der Zweck darin besteht, etwas zu experimentieren und zu testen, um Ihr eigenes Verständnis zu erlangen, und Sie wissen, was die Ergebnisse sein sollten, ist Ihr Code im Grunde genommen ein schneller Wegwerfvorgang, und Ihre derzeitige Vorgehensweise könnte ausreichen, könnte jedoch verbessert werden. Wenn die Ergebnisse nicht den Erwartungen entsprechen, können Sie sie erneut überprüfen.
Wenn die Ergebnisse Ihrer Codierung jedoch die Richtung Ihrer Forschung angeben und Sie nicht wissen, wie die Ergebnisse aussehen sollen, ist die Richtigkeit besonders wichtig. Ein Fehler in Ihrem Code könnte dazu führen, dass Sie aus Ihrem Experiment die falschen Schlussfolgerungen ziehen und eine Reihe von negativen Auswirkungen auf Ihre Gesamtrecherche haben.
In diesem Fall erhalten Sie durch Aufteilen Ihres Codes in leicht verständliche und überprüfbare Funktionen mit Komponententests stabilere Bausteine, die Ihnen mehr Vertrauen in Ihre Ergebnisse geben und Sie möglicherweise später vor viel Frust bewahren.
quelle
So wichtig Versionskontrolle und Komponententests auch sind, um den gesamten Code organisiert und funktionsfähig zu halten, sie helfen Ihnen auch nicht, saubereren Code zu schreiben.
Wenn Sie sich davon abhalten möchten, unordentlichen Code zu schreiben, benötigen Sie ein Tool, das dort funktioniert, wo die Probleme auftreten: beim Schreiben des Codes. Eine beliebte Art von Werkzeug ist ein Linter. Ich bin kein Python-Entwickler, aber es sieht so aus, als wäre Pylint eine gute Option.
Ein Linter überprüft den von Ihnen geschriebenen Code und vergleicht ihn mit einer konfigurierbaren Reihe von Best Practices. Wenn der Linter die Regel hat, dass Variablen sein müssen
camelCase
, und Sie einesnake_case
eingeben, wird dies als Fehler markiert. Gute Linters haben Regeln von "deklarierte Variablen müssen verwendet werden" bis "Die zyklomatische Komplexität von Funktionen muss kleiner als 3 sein".Die meisten Code-Editoren können so konfiguriert werden, dass bei jedem Speichern oder nur während der Eingabe ein Linter ausgeführt wird und Probleme inline angezeigt werden. Wenn Sie etwas wie eingeben
x = 7
,x
wird das hervorgehoben, mit der Anweisung, einen längeren, besseren Namen zu verwenden (sofern Sie dies konfiguriert haben). Dies funktioniert wie die Rechtschreibprüfung in den meisten Textverarbeitungsprogrammen, was das Ignorieren erschwert und zu besseren Gewohnheiten beiträgt.quelle
Alles, was Sie aufgelistet haben, ist ein Werkzeug in der metaphorischen Toolbox. Wie alles im Leben sind verschiedene Werkzeuge für verschiedene Aufgaben geeignet.
Im Vergleich zu anderen technischen Bereichen arbeitet Software mit einer Reihe von Einzelteilen, die für sich genommen recht einfach sind. Eine Zuweisungsanweisung wird in Abhängigkeit von Temperaturschwankungen des Raumes nicht unterschiedlich bewertet. Eine
if
Aussage korrodiert nicht und gibt nach einer Weile immer wieder dasselbe zurück. Aber weil die einzelnen Elemente so einfach und von Menschen erstellte Software sind, werden diese Elemente zu immer größeren Teilen kombiniert, bis das Ergebnis so umfangreich und komplex wird, dass es an die Grenzen dessen stößt, was Menschen mental verwalten können.Mit dem Anwachsen von Softwareprojekten haben die Menschen diese untersucht und Tools entwickelt, um diese Komplexität zu bewältigen. OOP ist ein Beispiel. Immer abstrakter werdende Programmiersprachen sind ein weiteres Mittel. Da ein Großteil des Geldes in Software mehr und mehr fließt, werden Sie Tools dafür sehen und lesen. Aber es scheint, dass diese Situationen nicht auf Sie zutreffen.
Also, nicht das Gefühl , wie Sie brauchen irgendetwas davon zu tun werden. Letztendlich ist der Code nur ein Mittel zum Zweck. Leider ist es für Sie am besten, an einigen größeren Projekten zu arbeiten, da es sehr viel schwieriger ist zu wissen, was fehlt, wenn Sie an der Toolbox interessiert sind.
In jedem Fall würde ich mir keine Sorgen machen, wenn ich kein OOP oder andere Techniken verwende, solange Ihre Skripte klein sind. Viele der Probleme, die Sie beschrieben haben, sind nur allgemeine berufliche Organisationsfähigkeiten. Das heißt, nicht eine alte Datei zu verlieren, ist etwas, mit dem sich alle Bereiche befassen müssen.
quelle
Zusätzlich zu all den guten Vorschlägen, die ich bisher gemacht habe, ist es eine Übung, die ich im Laufe der Zeit gelernt habe und die ich für wesentlich halte, Ihrem Code sehr großzügig detaillierte Kommentare hinzuzufügen. Es ist das Wichtigste für mich, wenn ich nach langer Zeit auf etwas zurückkomme. Erkläre dir selbst, was du denkst. Es dauert ein wenig, aber es ist relativ einfach und meistens schmerzfrei.
Ich habe manchmal zwei- oder dreimal so viele Kommentarzeilen wie ich, besonders wenn die Konzepte oder Techniken für mich neu sind und es ertragen, sich selbst zu erklären.
Führen Sie eine Versionskontrolle durch, verbessern Sie Ihre Praktiken usw. ... alles oben Genannte. Aber erkläre dir die Dinge, während du gehst. Es funktioniert wirklich gut
quelle
Welche Eigenschaften sind für diese Art von Programm wichtig?
Es spielt wahrscheinlich keine Rolle, ob es einfach zu warten oder weiterzuentwickeln ist, denn die Chancen stehen gut, dass dies nicht passieren wird.
Es ist wahrscheinlich egal, wie effizient es ist.
Es spielt wahrscheinlich keine Rolle, ob es eine großartige Benutzeroberfläche hat oder ob es gegen böswillige Angreifer sicher ist.
Es kann wichtig sein, dass es lesbar ist: Jemand, der Ihren Code liest, kann sich leicht davon überzeugen, dass er das tut, was er behauptet zu tun.
Es ist sicher wichtig, dass es richtig ist. Wenn das Programm falsche Ergebnisse liefert, sind das Ihre wissenschaftlichen Schlussfolgerungen aus dem Fenster. Es muss jedoch nur die Eingabe, die Sie tatsächlich verarbeiten möchten, korrekt verarbeiten. Es ist wirklich egal, ob es bei negativen Eingabedatenwerten umkippt, wenn alle Ihre Datenwerte positiv sind.
Es ist auch wichtig, dass Sie ein gewisses Maß an Änderungskontrolle beibehalten. Ihre wissenschaftlichen Ergebnisse müssen reproduzierbar sein. Das bedeutet, dass Sie wissen müssen, in welcher Version des Programms die Ergebnisse veröffentlicht wurden, die Sie veröffentlichen möchten. Da es nur einen Entwickler gibt, muss die Änderungskontrolle nicht sehr aufwendig sein, aber Sie müssen sicherstellen, dass Sie zu einem bestimmten Zeitpunkt zurückkehren und Ihre Ergebnisse reproduzieren können.
Machen Sie sich also keine Gedanken über Programmierparadigmen, Objektorientierung und algorithmische Eleganz. Sorgen Sie sich um Klarheit und Lesbarkeit sowie um die Nachvollziehbarkeit Ihrer Änderungen im Zeitverlauf. Mach dir keine Sorgen über die Benutzeroberfläche. Kümmern Sie sich nicht darum, jede mögliche Kombination von Eingabeparametern zu testen, sondern testen Sie genug, um sicher zu sein (und andere zu überzeugen), dass Ihre Ergebnisse und Schlussfolgerungen gültig sind.
quelle
Ich habe in einer ähnlichen Umgebung mit Akademikern gearbeitet, die viel (Mathematik- / Wissenschafts-) Code schreiben, aber ihre Fortschritte sind aus den gleichen Gründen, die Sie beschreiben, langsam. Eines ist mir jedoch aufgefallen, und ich denke, es kann Ihnen auch helfen: Eine Sammlung spezialisierter Bibliotheken aufzubauen und zu pflegen, die projektübergreifend verwendet werden können. Diese Bibliotheken sollten Dienstprogrammfunktionen bereitstellen und helfen daher, Ihr aktuelles Projekt spezifisch für die Problemdomäne zu halten.
Beispielsweise müssen Sie möglicherweise viele Koordinatentransformationen in Ihrem Bereich (ECEF, NED, Lat / Lon, WGS84 usw.) durchführen, sodass eine Funktion wie
convert_ecef_to_ned()
in ein neues Projekt mit dem Namen aufgenommen werden sollteCoordinateTransformations
. Stellen Sie das Projekt unter Versionskontrolle und hosten Sie es auf den Servern Ihrer Abteilung, damit andere Benutzer es verwenden (und hoffentlich verbessern) können. Dann sollten Sie nach ein paar Jahren eine robuste Sammlung von Bibliotheken mit Ihren Projekten haben, die nur Code enthalten, der für ein bestimmtes Problem / einen bestimmten Forschungsbereich spezifisch ist.Einige allgemeinere Ratschläge:
quelle
Das Folgende sind meine Meinungen und sehr stark von meinem eigenen Weg beeinflusst.
Das Codieren bringt oft dogmatische Perspektiven mit sich, wie Sie Dinge tun sollten. Anstelle von Techniken und Werkzeugen sollten Sie sich meines Erachtens die kumulierten Werte und Kosten ansehen, um eine geeignete Strategie zu finden.
Das Schreiben von gutem, lesbarem, debuggbarem, soliden Code erfordert viel Zeit und Mühe. In vielen Fällen lohnt es sich bei einem begrenzten Planungshorizont nicht, dies zu tun (Analyseparalyse).
Ein Kollege hatte eine Faustregel; Wenn Sie zum dritten Mal im Wesentlichen das Gleiche tun, investieren Sie Aufwand, andernfalls ist ein schneller und schmutziger Job angebracht.
Tests jeglicher Art sind unerlässlich, aber für einmalige Projekte kann das bloße Hinsehen ausreichend sein. Für alles Wesentliche sind Tests und Testinfrastrukturen unerlässlich. Der Wert ist, dass Sie beim Codieren davon befreit werden. Die Kosten sind, dass, wenn sich der Test auf eine bestimmte Implementierung konzentriert, auch die Tests gewartet werden müssen. Tests erinnern Sie auch daran, wie die Dinge funktionieren sollen.
Für meine eigenen einmaligen Skripte (oft für die Validierung einer Wahrscheinlichkeitsschätzung oder ähnliches) fand ich zwei kleine Dinge sehr nützlich: 1. Fügen Sie einen Kommentar ein, der zeigt, wie der Code verwendet wird. 2. Beschreiben Sie kurz, warum Sie den Code geschrieben haben. Diese Dinge sind schrecklich offensichtlich, wenn Sie den Code schreiben, aber die Zeit verschwendet die Offensichtlichkeit :-).
Bei OOP geht es darum, Code wiederzuverwenden, zu abstrahieren, zu kapseln, zu faktorisieren usw. Sehr nützlich, aber leicht zu verlieren, wenn die Erstellung von Qualitätscode und Design nicht Ihr Endziel ist. Es braucht Zeit und Mühe, um qualitativ hochwertige Produkte herzustellen.
quelle
Während ich denke, dass Unit-Tests ihre Vorzüge haben, sind sie für die wissenschaftliche Entwicklung von zweifelhaftem Wert - sie sind oft einfach zu klein, um viel Wert zu bieten.
Aber ich mag Integrationstests für wissenschaftlichen Code wirklich:
Isolieren Sie einen kleinen Teil Ihres Codes, der von sich aus funktionieren könnte, z. B. die ETL-Pipeline. Schreiben Sie dann einen Test, der die Daten liefert, führen Sie die etl-Pipeline (oder nur einen Schritt) aus und prüfen Sie dann, ob das Ergebnis Ihren Erwartungen entspricht. Während der getestete Block eine Menge Code sein kann, liefert der Test immer noch Wert:
Ich verwende diese Technik oft und habe oft eine relativ gut lesbare Hauptfunktion, aber Unterfunktionen sind oft recht lang und hässlich, können aber aufgrund robuster E / A-Grenzen schnell geändert und neu angeordnet werden.
quelle
Normalerweise arbeite ich auf einer sehr großen Quellbasis. Wir verwenden alle Werkzeuge, die Sie erwähnen. Vor kurzem habe ich begonnen, an einigen Python-Skripten für ein Nebenprojekt zu arbeiten. Es sind höchstens ein paar Dutzend bis ein paar Hundert Zeilen. Aus Gewohnheit habe ich meine Skripte der Quellcodeverwaltung übergeben. Dies war nützlich, da ich Zweige zum Ausprobieren von Experimenten erstellen kann, die möglicherweise nicht funktionieren. Ich kann angeben, ob ich den Code duplizieren und für einen anderen Zweck ändern muss. Dadurch bleibt das Original erhalten, falls ich es erneut herausbringen muss.
Für "Komponententests" habe ich nur einige Eingabedateien, die eine bekannte Ausgabe erzeugen sollen, die ich von Hand überprüfe. Ich könnte es wahrscheinlich automatisieren, aber es scheint, als würde es mehr Zeit in Anspruch nehmen, als ich dadurch sparen würde. Es hängt wahrscheinlich davon ab, wie oft ich die Skripte ändern und ausführen muss. So oder so, wenn es funktioniert, machen Sie es. Wenn es mehr Mühe ist als es wert ist, verschwende nicht deine Zeit.
quelle
Beim Schreiben von Code - wie beim Schreiben im Allgemeinen - lautet die Hauptfrage:
Dinge wie formale Kodierungsrichtlinien machen keinen Sinn, wenn Sie Ihr einziges Publikum sind.
Andererseits wäre es hilfreich, den Code so zu schreiben, dass Sie ihn in Ihrer Zukunft sofort verstehen können.
Ein "guter Stil" wäre also einer, der Ihnen am meisten hilft. Wie dieser Stil aussehen sollte, ist eine Antwort, die ich nicht geben kann.
Ich denke, Sie brauchen keine OOP- oder Unit-Tests für Dateien von 150 LOC. Ein dediziertes VCS wäre interessant, wenn Sie sich entwickelnden Code haben. Ansonsten
.bak
macht a den Trick. Diese Werkzeuge sind ein Heilmittel für eine Krankheit, die Sie vielleicht gar nicht haben.Vielleicht sollten Sie Ihren Code so schreiben, dass Sie ihn auch dann lesen, verstehen und ändern können, wenn Sie ihn betrunken lesen.
quelle