Die moderne wissenschaftliche Methode und gute Softwareentwicklungspraktiken haben viel gemeinsam. Die gleichen Grundsätze, die die Wissenschaft in den letzten Jahrhunderten erfolgreich gemacht haben, scheinen auch für die erfolgreiche Softwareentwicklung grundlegend zu sein.
Lassen Sie mich einige Beispiele nennen.
Hat ein Chefarchitekt irgendwo festgelegt, welchen Rahmen Sie für Ihr Projekt verwenden müssen, ein Projekt, das er nie sehen würde? Und gab es keine Möglichkeit, diese Idee in Frage zu stellen?
Die Ablehnung von Autoritäten ist ein Schlüsselelement in der Entwicklung der modernen Wissenschaft. Früher folgten die Menschen einfach dem, was Aristoteles, Galen oder andere große philosophische Persönlichkeiten der Geschichte sagten oder taten. Medizinische Studien gingen oft nicht weiter als das Studium des Ahnenerbes. Hinterfragen war nicht erlaubt. Wenn man diese Lehren in Frage stellte, bedeutete das, dass man sie nicht vollständig verstand und man musste mehr studieren. Es herrschte eine Kultur des Nacheiferns gegenüber den Meistern.
Nullius in verba - nichts von Autorität - wurde zum Motto der Royal Society, die 1660 gegründet wurde und eine wichtige Rolle für den Erfolg der modernen Wissenschaft spielte. Wir verwenden die Newtonschen Bewegungsgesetze heute nicht aus Respekt vor diesem Mann. Wir verwenden sie, weil wir bei der Wiederholung der gleichen Experimente die gleichen Ergebnisse erhalten und die Theorie immer wieder korrekte Vorhersagen in der Mechanik liefert (natürlich mit bekannten Grenzen).
In unserer Softwareentwickler-Gemeinschaft bei Aliz ist es ein wichtiges kulturelles Fundament, dass wir uns in technischen Diskussionen die Gründe der anderen anhören, nicht die Positionen. Und das geht über technische Diskussionen hinaus. Sogar neue, jüngere Mitglieder können uns auf Probleme in den Plänen unserer erfahrensten Architekten hinweisen. Natürlich haben unsere Architekten in der Regel gute Pläne, und wir arbeiten in der Regel mit diesen Plänen, aber das liegt nicht daran, dass wir sie nur aufgrund ihrer Autorität akzeptieren. Sondern weil sie in der Regel richtig sind. Normalerweise.
Am Anfang kann es sich unangenehm anfühlen, dass man die Kritik anderer berücksichtigen und akzeptieren muss, wenn sie richtig ist. Es könnte bedeuten, dass Sie viele hundert Zeilen Code und mehrere Tage Arbeit rückgängig machen müssen. Aber am Ende ist es befreiend. Es befreit Sie von dem Stress, immer Recht haben zu müssen. Es befreit Sie davon, mit Entscheidungen leben zu müssen, die Sie hätten vermeiden können, mit falschen Entscheidungen. Und es lässt Sie bessere Software schreiben.
Ich finde, der Geist des nullius in verba spiegelt sich auch in Code-Reviews wider. Niemand kann Code einfach mit den Worten "Hey, glaub mir, wir brauchen das schnell in der Produktion, danke" übertragen. So funktioniert es einfach nicht.
Ihr Kollege kommt zu Ihnen und teilt Ihnen mit, dass er den Leistungsengpass untersucht hat und ein bestimmtes Dienstprogramm durch ein neueres, leistungsfähigeres ersetzt werden muss. Das Beste, was Sie jetzt tun können, ist zu fragen, wie er zu diesem Ergebnis gekommen ist. Was genau wurde gemessen und untersucht, und wie wurde es gemacht? Wie lauten die genauen Zahlen? Selbst wenn das Dienstprogramm bereits ausgetauscht wurde und die Software besser funktioniert, sollten Sie überprüfen, ob die verbesserte Leistung tatsächlich auf die Umstellung und nicht auf eine andere untergeordnete Änderung zurückzuführen ist.
In der Wissenschaft akzeptieren wir nicht das Wort eines anderen. Wir wiederholen Experimente, um zu sehen, ob sie die gleichen Ergebnisse liefern. Selbst die am besten klingenden Ideen werden verworfen, wenn sie nicht durch geeignete, reproduzierbare Experimente gestützt werden. Selbst die grundlegendsten Dinge werden immer wieder in Frage gestellt. Ich war überrascht, als ich kürzlich erfuhr, dass die Äquivalenz von Trägheits- und Schwerkraftmasse immer noch in neuen Experimenten mit erstaunlicher Präzision getestet wird.
Aber bei der Reproduzierbarkeit geht es nicht nur um Experimente, sondern um den gesamten Prozess.
Wahrscheinlich haben Sie schon einmal mit altem Code gearbeitet, einem Code, von dem Sie vermutet haben, dass er bei seiner Entstehung meist schlecht war und erst seit einigen Jahren gepatcht wird. Sie wissen nicht, was Sie anfassen können, was geändert werden kann. Ist dies ein Fehler oder ist dies eine Funktion? Wird dieser Pfad überhaupt ausgeführt? Ist dies hier überhaupt eine sinnvolle Bedingung? Ist das noch eine Anforderung? Ah, das funktioniert nur, weil drei Bugs tatsächlich ein Feature ergeben.
Anforderungen und Ausführungsumgebungen ändern sich. Technologien entwickeln sich weiter, ganz zu schweigen vom Web. Selbst wenn alle Entscheidungen zum jetzigen Zeitpunkt richtig sind, werden Sie diese Entscheidungen wahrscheinlich eines Tages neu bewerten müssen. Wenn Sie genau wissen, wie und warum bestimmte Entscheidungen getroffen wurden, können Sie sie in einer veränderten Umgebung getrost neu bewerten. Framework X war in Java EE großartig, aber in der neuen Cloud-Umgebung, in der Server schnell hoch- und heruntergefahren werden, funktioniert es nicht gut. Framework Y war für die Verwaltungsbildschirme des Kunden gut geeignet, aber jetzt braucht er eine öffentliche Website.
Die Replizierbarkeit bezieht sich darauf, wie Sie Hypothesen und Theorien aufstellen. Sie müssen Referenzen zu den Experimenten, Theorien und praktisch allem, worauf Sie Ihre Schlussfolgerungen aufbauen, angeben. Andere werden nicht nur prüfen, ob ihnen Ihre Schlussfolgerung gefällt oder nicht. Sie werden auch prüfen, ob Ihre Schlussfolgerung wirklich auf den Grundlagen beruht, auf denen Sie aufgebaut haben. Sollte sich eine dieser Grundlagen später als falsch erweisen, können Sie alle anderen Theorien, die auf ihnen aufgebaut wurden, neu bewerten, um zu sehen, ob sie noch richtig sind.
Es ist gut, wenn diese Entscheidungen aus dem Code ersichtlich sind. Das Verfassen von sauberen Commits mit beschreibenden Meldungen hilft schon sehr. Bei komplexeren Änderungen hilft der Verweis auf das Ticketing-System, den Hintergrund der Änderungen zu finden. Die Reviewer müssen auch überprüfen, ob alle Änderungen im Pull Request aus dem Issue abgeleitet werden können, auf das sich der Pull Request bezieht, so dass die Änderungen später zu den Entscheidungen zurückverfolgt werden können.
(Wenn jemand behauptet, Web-Framework X sei das beste und er würde nichts anderes verwenden, oder Sprache Y sei die beste und alle anderen seien schlecht, wissen Sie, dass er höchstwahrscheinlich an etwas Bestimmtes glaubt und durch seine Vorlieben und Gewohnheiten voreingenommen ist.
Theorien müssen falsifizierbar sein. Man muss in der Lage sein, Bedingungen zu nennen, unter denen es für jeden klar ist, dass die Theorie nicht stimmt. Phlogiston ist ein gutes Beispiel dafür in der Wissenschaft, aber darauf kommen wir später zurück.
Haben Sie schon einmal eine Lösung gefunden, die alles nur noch schlimmer gemacht hat, weil sich herausstellte, dass Sie das Problem nicht ganz verstanden hatten?
Die Falsifizierbarkeit wird wichtig, wenn man versucht, Fehler zu finden oder Probleme beim Betrieb einer Anwendung anzugehen. Einige Fehler sind ziemlich einfach aufzuspüren. Man kann einen direkten logischen Weg durch den Code finden, um den problematischen Teil des Codes ausfindig zu machen. Andere Fehler sind subtiler und werden oft nicht eindeutig durch bestimmte Teile des Codes verursacht, sondern sind das Ergebnis eines unglücklichen Zusammenwirkens von kleinen Fehlern in vielen Teilen des Codes. Bei der Lösung von Problemen ist eine Denkweise wichtig, die immer versucht, falsifizierbare Theorien aufzustellen.
Bei der Lösung von Problemen ist eine Denkweise wichtig, die stets versucht, falsifizierbare Theorien aufzustellen. Wenn Sie glauben, das Problem zu kennen, suchen Sie nicht nach anderen Anzeichen, die Ihre Theorie stützen. Suchen Sie nach Anzeichen, die sie definitiv widerlegen würden, wenn sie wahr wären.
Nehmen wir folgendes Szenario. Ihr Auto springt nicht an. Sie vermuten, dass es an der alten Batterie liegt. Bitten Sie lieber einen Freund, Ihr Auto mit dessen Batterie zu starten, bevor Sie eine neue kaufen. Oder was ist mit dieser? Die Leistung der Anwendung wird im Durchschnitt schlechter. Sie sind sich ziemlich sicher, dass dies an der neuen Funktion liegt, die gerade eingeführt wurde. Bevor Sie sich darauf stürzen, sollten Sie einige andere Dinge überprüfen. Hat die Leistung schon vor der Veröffentlichung nachgelassen? Kann die Nutzung der neuen Funktion mathematisch gesehen auf den beobachteten durchschnittlichen Leistungsabfall zurückgeführt werden? Sie verstehen, worum es geht.
Beim Versuch, eine bestimmte Art von Anfrage zu optimieren, stößt man auf hässlichen Code: Es ist nicht nötig, das Array zu kopieren. Das könnte in linearer Zeit erledigt werden. Wir berechnen diesen Wert mehrere Male, oh je. Wenn man dann ein Profiling durchführt, stellt sich heraus, dass man durch eine Änderung der Abfrage die Anfrage um 70 % beschleunigen kann, und dann ist sie ziemlich weit oben auf der Liste der langsamen Anfragen, die man optimieren muss. Der Code, der beim Anschauen wirklich weh tut, ist nur für etwa 0,5 % der CPU-Zeit verantwortlich. Kommt Ihnen das bekannt vor? Natürlich gibt es noch andere Gründe, hässlichen Code zu korrigieren, aber das ist jetzt nicht der Punkt.
Messung ist entscheidend. In der Wissenschaft war die Phlogistontheorie ein Meilenstein in dieser Hinsicht. Sie besagt, dass ein feuerähnliches Element namens Phlogiston in brennbaren Körpern enthalten ist und bei der Verbrennung freigesetzt wird. Sie wurde jedoch durch Experimente widerlegt, bei denen das Volumen und die Masse der an bestimmten Reaktionen beteiligten Gase gemessen wurden. Um eine gute Theorie der Schwerkraft zu haben, reicht es nicht aus, zu messen, wie fallende Objekte beschleunigt werden; es ist wichtig, genau zu messen, wie sie beschleunigt werden. Die Kultur der genauen und reproduzierbaren Messungen ist erst ein paar Jahrhunderte alt, aber sie ist für die moderne Wissenschaft von grundlegender Bedeutung. Die Bedeutung quantitativer Messungen ist in der Softwareentwicklung etwas umstritten. Im Entwicklungsprozess selbst kämpfen die meisten Teams mit Sprint-Punkten, Komplexitätsschätzungen, einer angemessenen Kontrolle des Zeitaufwands, ganz zu schweigen von der Codeabdeckung und Komplexitätsmetriken. Und ja, die wissenschaftliche Kultur hat auch ihre eigenen Probleme mit P-Werten und Impact-Faktoren. Aber im Anwendungsbetrieb ist die Messung vieler Aspekte der Anwendung entscheidend. Wir messen Antwortzeiten, Fehlerraten, Nutzungsraten, Protokollvolumen, Datenbankleistung, Cache-Trefferrate und so weiter. Das ist nicht nur für die Betriebsüberwachung wichtig. Genaue Daten darüber, wie bestimmte Funktionen der Anwendung genutzt werden, können auch als empirische Daten für die Gestaltung der Zukunft eines Produkts verwendet werden. Man darf sich nicht davon täuschen lassen, wie sehr einem eine bestimmte Idee gefällt; die gemessenen Daten könnten ernüchternd sein.
Ich habe festgestellt, dass diese Grundsätze Schlüsselelemente unseres Softwareentwicklungsprozesses sind. Wir stellen uns diese Fragen regelmäßig und sie könnten auch für Sie hilfreich sein: