Wie große Nicht-OO-Codebasen werden verwaltet?


27

Ich sehe immer, dass Abstraktion eine sehr nützliche Funktion ist, die OO für die Verwaltung der Codebasis bietet. Aber wie werden große Nicht-OO-Codebasen verwaltet? Oder werden diese irgendwann einfach zu einem " Big Ball of Mud "?

Update:
Anscheinend denkt jeder, dass 'Abstraktion' nur Modularisierung oder Verstecken von Daten ist. Aber meiner Meinung nach bedeutet dies auch die Verwendung von 'Abstract Classes' oder 'Interfaces', was ein Muss für die Abhängigkeitsinjektion und damit für das Testen ist. Wie verwalten Nicht-OO-Codebasen dies? Neben der Abstraktion hilft die Kapselung auch bei der Verwaltung großer Codebasen, da sie die Beziehung zwischen Daten und Funktionen definiert und einschränkt.

Mit C ist es sehr gut möglich, Pseudo-OO-Code zu schreiben. Ich weiß nicht viel über andere Nicht-OO-Sprachen. Ist es also DER Weg, große C-Code-Basen zu verwalten?


6
Beschreiben Sie bitte sprachunabhängig ein Objekt. Was ist es, wie wird es modifiziert, was soll es erben und was soll es liefern? Der Linux-Kernel ist voll von zugewiesenen Strukturen mit vielen Hilfs- und Funktionszeigern, aber das würde wahrscheinlich nicht der Definition von objektorientiert für die meisten genügen. Es ist jedoch eines der besten Beispiele für eine sehr gut gepflegte Codebasis. Warum? Weil jeder Subsystembetreuer weiß, was in seinem Verantwortungsbereich liegt.
Tim Post

Beschreiben Sie sprachunabhängig, wie Sie die Verwaltung von Codebasen sehen und was OO damit zu tun hat.
David Thornley

@Tim Post Ich bin an der Quellcodeverwaltung des Linux-Kernels interessiert. Würden Sie das System bitte näher beschreiben? Vielleicht als Antwort mit einem Beispiel?
Gulshan

7
Früher haben wir für Unit-Tests separate Verknüpfungen für Mocks und Stubs verwendet. Abhängigkeitsinjektion ist nur eine Technik unter mehreren. Bedingte Kompilierung ist eine andere.
Macneil

Ich denke, es ist eine Strecke, große Codebasen (OO oder anderweitig) als "verwaltet" zu bezeichnen. Es wäre gut, eine bessere Definition des zentralen Begriffs in Ihrer Frage zu haben.
Tottinge

Antworten:


43

Sie scheinen zu glauben, dass OOP das einzige Mittel ist, um eine Abstraktion zu erreichen.

Während OOP das sicherlich sehr gut kann, ist es keineswegs der einzige Weg. Große Projekte können auch durch kompromisslose Modularisierung verwaltet werden (siehe Perl oder Python, die sich beide ausgezeichnet haben, ebenso wie funktionale Sprachen wie ML und Haskell) und durch die Verwendung von Mechanismen wie Vorlagen (in C ++).


27
+1 Es ist auch möglich, mit OOP einen "Big Ball of Mud" zu schreiben, wenn Sie nicht wissen, was Sie tun.
Larry Coleman

Was ist mit C-Code-Basen?
Gulshan,

6
@ Gulshan: Viele große C-Code-Basen sind OOP. Nur weil C keine Klassen hat, heißt das nicht, dass OOP nicht mit ein wenig Aufwand erreicht werden kann. Darüber hinaus erlaubt C eine gute Modularisierung unter Verwendung von Headern und der PIMPL-Sprache. Nicht annähernd so komfortabel oder leistungsfähig wie Module in modernen Sprachen, aber wieder einmal gut genug.
Konrad Rudolph

9
C ermöglicht die Modularisierung auf Dateiebene. Die Schnittstelle befindet sich in der .h-Datei, öffentlich verfügbare Funktionen in der .c-Datei und private Variablen und Funktionen erhalten den staticangehängten Zugriffsmodifikator.
David Thornley

1
@Konrad: Ich stimme zu, dass OOP nicht der einzige Weg ist, dies zu tun, aber ich glaube, OP hatte wahrscheinlich ausschließlich C im Sinn, was weder eine funktionale noch eine dynamische Sprache ist. Daher bezweifle ich, dass die Erwähnung von Perl und Haskell für ihn / sie von Nutzen sein wird. Ich finde Ihren Kommentar tatsächlich relevanter und nützlicher für OP ( bedeutet nicht, dass OOP nicht mit ein wenig Aufwand erreicht werden kann ); Sie können es als separate Antwort mit zusätzlichen Details hinzufügen, möglicherweise mit einem Code-Snippet oder einigen Links unterstützt. Zumindest würde es meine Stimme und möglicherweise die der OPs gewinnen. :)
Groo

11

Module, (externe / interne) Funktionen, Unterprogramme ...

Wie Konrad sagte, ist OOP nicht die einzige Möglichkeit, große Codebasen zu verwalten. Tatsächlich wurde viel Software davor geschrieben (vor C ++ *).


* Und ja, ich weiß, dass C ++ nicht das einzige ist, das OOP unterstützt, aber irgendwie begann dieser Ansatz, Trägheit zu zeigen.
Turm

8

Das Modularitätsprinzip ist nicht auf objektorientierte Sprachen beschränkt.


6

Realistisch gesehen sind dies entweder seltene Änderungen (siehe Berechnungen zur Altersvorsorge bei der Sozialversicherung) und / oder tief verwurzeltes Wissen, da die Leute, die ein solches System aufrechterhalten, dies bereits seit einiger Zeit tun (zynische Haltung ist Arbeitsplatzsicherheit).

Bessere Lösungen sind wiederholbare Validierungen, dh automatisierte Tests (z. B. Komponententests) und menschliche Tests, die vorgeschriebenen Schritten folgen (z. B. Regressionstests), "anstatt herumzuklicken und zu sehen, was kaputt geht".

Um zu einer Art automatisiertem Testen mit einer vorhandenen Codebasis überzugehen, empfehle ich, Michael Feathers Working Effectively with Legacy Code zu lesen , in dem die Herangehensweisen beschrieben werden, um vorhandene Codebasen bis zu einer Art reproduzierbarem Testframework (OO) zu bringen oder nicht. Dies führt zu den Ideen, auf die andere geantwortet haben, wie z. B. Modularisierung, aber das Buch beschreibt den richtigen Ansatz, um dies zu tun, ohne die Dinge zu beschädigen.


+1 für Michael Feather`s Buch. Wenn Sie sich wegen einer großen hässlichen Codebasis deprimiert fühlen, lesen Sie sie (erneut) :)
Matthieu

5

Die Abhängigkeitsinjektion auf der Basis von Interfaces oder abstrakten Klassen ist zwar eine sehr gute Methode zum Testen, aber nicht erforderlich. Vergessen Sie nicht, dass fast jede Sprache entweder einen Funktionszeiger oder ein Eval hat, das alles kann, was Sie mit einer Schnittstelle oder einer abstrakten Klasse tun können (das Problem ist, dass sie mehr können , einschließlich vieler schlechter Dinge, und dass sie nicht funktionieren). selbst Metadaten bereitstellen). Ein solches Programm kann mit diesen Mechanismen tatsächlich eine Abhängigkeitsinjektion erzielen.

Ich habe festgestellt, dass der strikte Umgang mit Metadaten sehr hilfreich ist. In OO-Sprachen werden die Beziehungen zwischen Codebits (bis zu einem gewissen Grad) durch die Klassenstruktur definiert, und zwar auf eine Weise, die standardisiert genug ist, um Dinge wie eine Reflection-API zu haben. In prozeduralen Sprachen kann es hilfreich sein, diese selbst zu erfinden.

Ich habe auch festgestellt, dass die Codegenerierung in einer prozeduralen Sprache (im Vergleich zu einer objektorientierten Sprache) viel hilfreicher ist. Dies garantiert, dass Metadaten mit dem Code synchron sind (da sie zum Generieren verwendet werden) und Ihnen so etwas wie die Schnittpunkte der aspektorientierten Programmierung geben - eine Stelle, an der Sie Code einfügen können, wenn Sie ihn benötigen. Manchmal ist es die einzige Möglichkeit, DRY-Programmierung in einer solchen Umgebung durchzuführen, die ich herausfinden kann.


3

Wie Sie kürzlich herausgefunden haben , sind Funktionen erster Ordnung alles, was Sie für die Inversion von Abhängigkeiten benötigen.

C unterstützt Funktionen erster Ordnung und bis zu einem gewissen Grad sogar Abschlüsse . C-Makros sind eine leistungsstarke Funktion für die allgemeine Programmierung, wenn sie mit der erforderlichen Sorgfalt behandelt werden.

Es ist alles da. SGLIB ist ein gutes Beispiel dafür, wie man mit C wiederverwendbaren Code schreiben kann. Und ich glaube, da draußen gibt es noch viel mehr.


2

Auch ohne Abstraktion sind die meisten Programme in Abschnitte unterteilt. Diese Abschnitte beziehen sich normalerweise auf bestimmte Aufgaben oder Aktivitäten, und Sie arbeiten auf die gleiche Weise, wie Sie auf die spezifischsten Teile der abstrahierten Programme arbeiten würden.

In kleinen bis mittelgroßen Projekten ist dies mitunter einfacher mit einer puristischen OO-Implementierung.


2

Abstraktion, abstrakte Klassen, Abhängigkeitsinjektion, Kapselung, Schnittstellen usw. sind nicht die einzige Möglichkeit, große Codebasen zu steuern. das ist gerecht und objektorientiert.

Das Hauptgeheimnis ist zu vermeiden, OOP zu denken, wenn Sie Nicht-OOP codieren.

Modularität ist der Schlüssel in Nicht-OO-Sprachen. In C wird dies erreicht, so wie David Thornley es gerade in einem Kommentar erwähnt hat:

Die Schnittstelle befindet sich in der .h-Datei, öffentlich verfügbare Funktionen in der .c-Datei und private Variablen und Funktionen erhalten den statischen Zugriffsmodifikator als Anhang.


1

Eine Möglichkeit zum Verwalten von Code besteht darin, ihn gemäß der MVC-Architektur (Model-View-Controller) in die folgenden Codetypen zu zerlegen.

  • Eingabehandler - Dieser Code behandelt Eingabegeräte wie Maus, Tastatur, Netzwerkanschluss oder übergeordnete Abstraktionen wie Systemereignisse.
  • Ausgabehandler - Dieser Code behandelt die Verwendung von Daten zur Manipulation externer Geräte wie Monitore, Anzeigen, Netzwerkanschlüsse usw.
  • Modelle - Dieser Code behandelt die Deklaration der Struktur Ihrer persistenten Daten, Regeln für die Validierung persistenter Daten und das Speichern persistenter Daten auf der Festplatte (oder einem anderen persistenten Datengerät).
  • Ansichten - Dieser Code behandelt die Formatierung von Daten, um die Anforderungen verschiedener Anzeigemethoden zu erfüllen, z. B. Webbrowser (HTML / CSS), GUI, Befehlszeile, Kommunikationsprotokolldatenformate (z. B. JSON, XML, ASN.1 usw.).
  • Algorithmen - Dieser Code wandelt einen Eingabedatensatz so schnell wie möglich in einen Ausgabedatensatz um.
  • Controller - Dieser Code nimmt Eingaben über die Eingabehandler entgegen, analysiert die Eingaben mithilfe von Algorithmen und transformiert die Daten anschließend mit anderen Algorithmen, indem er wahlweise Eingaben mit persistenten Daten kombiniert oder nur die Eingaben transformiert und die transformierten Daten optional über das Modell persistent speichert Software und optional Umwandlung der Daten über die Ansichtssoftware zum Rendern auf ein Ausgabegerät.

Diese Methode der Code-Organisation eignet sich gut für Software, die in einer beliebigen OO- oder Nicht-OO-Sprache geschrieben wurde, da in allen Bereichen häufig gemeinsame Entwurfsmuster verwendet werden. Außerdem sind diese Arten von Codegrenzen mit Ausnahme von Algorithmen häufig am lockersten gekoppelt, da sie die Datenformate von den Eingaben zum Modell und dann zu den Ausgaben verknüpfen.

Systementwicklungen haben oft die Form, dass Ihre Software mehr Arten von Eingaben oder mehr Arten von Ausgaben handhabt, aber die Modelle und Ansichten sind die gleichen und die Controller verhalten sich sehr ähnlich. Oder ein System muss im Laufe der Zeit immer mehr verschiedene Arten von Ausgaben unterstützen, obwohl die Eingaben, Modelle und Algorithmen identisch sind und die Steuerungen und Ansichten ähnlich sind. Oder ein System kann erweitert werden, um neue Modelle und Algorithmen für denselben Satz von Eingaben, ähnlichen Ausgaben und ähnlichen Ansichten hinzuzufügen.

Eine Möglichkeit, wie die OO-Programmierung die Code-Organisation erschwert, besteht darin, dass einige Klassen stark an die persistenten Datenstrukturen gebunden sind und andere nicht. Wenn die persistenten Datenstrukturen in engem Zusammenhang mit Dingen wie kaskadierenden 1: N-Beziehungen oder m: n-Beziehungen stehen, ist es sehr schwierig, Klassengrenzen zu bestimmen, bis Sie einen wichtigen und aussagekräftigen Teil Ihres Systems codiert haben, bevor Sie wissen, dass Sie es richtig verstanden haben . Jede Klasse, die an die persistenten Datenstrukturen gebunden ist, kann nur schwer entwickelt werden, wenn sich das Schema der persistenten Daten ändert. Klassen, die Algorithmen, Formatierungen und Parsing verarbeiten, sind weniger anfällig für Änderungen im Schema der persistenten Datenstrukturen. Durch die Verwendung einer MVC-Art von Codeorganisation werden die unordentlichsten Codeänderungen im Modellcode besser isoliert.


0

Wenn Sie in Sprachen arbeiten, denen eingebaute Struktur- und Organisationsfunktionen fehlen (z. B. wenn Namespaces, Pakete, Assemblys usw. fehlen) oder wenn diese nicht ausreichen, um eine Codebasis dieser Größe unter Kontrolle zu halten, ist die natürliche Reaktion die Entwicklung unsere eigenen Strategien, um den Code zu organisieren.

Diese Organisationsstrategie enthält wahrscheinlich Standards, die sich darauf beziehen, wo verschiedene Dateien aufbewahrt werden sollen, was vor / nach bestimmten Arten von Vorgängen geschehen muss und Namenskonventionen und andere Codierungsstandards sowie vieles, was so eingerichtet ist - Leg dich nicht damit an! " Typenkommentare - die gültig sind, solange sie erklären, warum!

Da die Strategie höchstwahrscheinlich auf die spezifischen Anforderungen des Projekts zugeschnitten sein wird (Menschen, Technologien, Umgebung usw.), ist es schwierig, eine einheitliche Lösung für die Verwaltung großer Codebasen zu finden.

Aus diesem Grund denke ich, der beste Rat ist, die projektspezifische Strategie zu übernehmen und ihre Verwaltung zu einer Schlüsselpriorität zu machen: Dokumentieren Sie die Struktur, warum dies so ist, die Prozesse für die Vornahme von Änderungen, prüfen Sie sie, um sicherzustellen, dass sie eingehalten werden. und entscheidend: Ändern Sie es, wenn es geändert werden muss.

Wir sind in der Regel mit dem Umgestalten von Klassen und Methoden vertraut, aber mit einer großen Codebasis in einer solchen Sprache ist es die Organisationsstrategie selbst (einschließlich Dokumentation), die nach Bedarf umgestaltet werden muss.

Die Überlegungen sind die gleichen wie beim Refactoring: Sie entwickeln eine mentale Blockade für die Arbeit an kleinen Teilen des Systems, wenn Sie der Meinung sind, dass die gesamte Organisation des Systems durcheinander ist, und lassen es schließlich zu, dass es sich verschlechtert (zumindest ist das meine Einstellung) es).

Die Vorbehalte sind auch die gleichen: Verwenden Sie Regressionstests, stellen Sie sicher, dass Sie leicht zurücksetzen können, wenn das Refactoring fehlschlägt, und gestalten Sie dies so, dass das Refactoring an erster Stelle erleichtert wird (oder Sie tun es einfach nicht!).

Ich bin damit einverstanden, dass dies viel schwieriger ist als das Umgestalten von direktem Code, und es ist schwieriger, die Zeit für Manager / Kunden zu validieren / zu verbergen, die möglicherweise nicht verstehen, warum dies getan werden muss, aber dies sind auch die Arten von Projekten, die am anfälligsten für Softwarefäule sind verursacht durch unflexible Top-Level-Designs ...


0

Wenn Sie nach der Verwaltung einer großen Codebasis fragen, möchten Sie wissen, wie Sie Ihre Codebasis auf einer relativ groben Ebene gut strukturieren können (Bibliotheken / Module / Aufbau von Subsystemen / Verwendung von Namespaces / Verwendung der richtigen Dokumente an den richtigen Stellen) etc.). OO-Prinzipien, insbesondere "abstrakte Klassen" oder "Schnittstellen", sind Prinzipien, um Ihren Code intern auf einer sehr detaillierten Ebene sauber zu halten. Daher unterscheiden sich die Techniken zum Verwalten einer großen Codebasis nicht für OO- oder Nicht-OO-Code.


0

Wie es gehandhabt wird, ist, dass Sie die Grenzen der Elemente herausfinden, die Sie verwenden. Zum Beispiel haben die folgenden Elemente in C ++ einen klaren Rand und alle Abhängigkeiten außerhalb des Randes müssen sorgfältig durchdacht werden:

  1. freie Funktion
  2. Mitgliedsfunktion
  3. Klasse
  4. Objekt
  5. Schnittstelle
  6. Ausdruck
  7. Konstruktoraufruf / Erstellen von Objekten
  8. Funktionsaufruf
  9. Vorlagenparametertyp

Durch die Kombination dieser Elemente und das Erkennen ihrer Grenzen können Sie in c ++ nahezu jeden gewünschten Programmierstil erstellen.

Ein Beispiel hierfür ist, dass eine Funktion erkennen soll, dass es schlecht ist, andere Funktionen von einer Funktion aufzurufen, da dies zu Abhängigkeiten führt. Stattdessen sollten Sie nur Mitgliedsfunktionen der Parameter der ursprünglichen Funktion aufrufen.


-1

Die größte technische Herausforderung ist das Namespace-Problem. Eine teilweise Verknüpfung kann verwendet werden, um dies zu umgehen. Der bessere Ansatz ist das Entwerfen unter Verwendung von Codierungsstandards. Ansonsten werden alle Symbole zu einem Durcheinander.


-2

Emacs ist ein gutes Beispiel dafür:

Emacs Architektur

Emacs-Komponenten

Emacs Lisp-Tests verwenden skip-unlessund let-bind, um Feature-Erkennung und Test-Fixtures durchzuführen:

Manchmal ist es aufgrund fehlender Voraussetzungen nicht sinnvoll, einen Test durchzuführen. Ein erforderliches Emacs-Feature wird möglicherweise nicht kompiliert. Die zu testende Funktion kann eine externe Binärdatei aufrufen, die auf dem Testcomputer möglicherweise nicht verfügbar ist. In diesem Fall kann skip-unlessder Test mit dem Makro übersprungen werden:

 (ert-deftest test-dbus ()
   "A test that checks D-BUS functionality."
   (skip-unless (featurep 'dbusbind))
   ...)

Das Ergebnis der Ausführung eines Tests sollte nicht vom aktuellen Zustand der Umgebung abhängen, und jeder Test sollte seine Umgebung in dem Zustand belassen, in dem er sich befunden hat. Insbesondere sollte ein Test nicht von Emacs-Anpassungsvariablen oder -Hooks abhängen Wenn es Änderungen am Status von Emacs oder außerhalb von Emacs (wie dem Dateisystem) vornehmen muss, sollte es diese Änderungen rückgängig machen, bevor es zurückkehrt, unabhängig davon, ob sie bestanden oder fehlgeschlagen sind.

Tests sollten nicht von der Umgebung abhängen, da solche Abhängigkeiten den Test spröde machen oder zu Fehlern führen können, die nur unter bestimmten Umständen auftreten und schwer reproduzierbar sind. Natürlich kann der getestete Code Einstellungen haben, die sich auf sein Verhalten auswirken. In diesem Fall ist es am besten, let-bindalle diese Einstellungsvariablen zu testen , um eine bestimmte Konfiguration für die Dauer des Tests einzurichten. Der Test kann auch eine Reihe verschiedener Konfigurationen einrichten und den zu testenden Code mit jeder Konfiguration ausführen.

Wie ist SQLite. Hier ist das Design:

  1. sqlite3_open () → Öffnet eine Verbindung zu einer neuen oder vorhandenen SQLite-Datenbank. Der Konstruktor für sqlite3.

  2. sqlite3 → Das Datenbankverbindungsobjekt. Erstellt von sqlite3_open () und zerstört von sqlite3_close ().

  3. sqlite3_stmt → Das vorbereitete Anweisungsobjekt. Erstellt von sqlite3_prepare () und zerstört von sqlite3_finalize ().

  4. sqlite3_prepare () → Kompilieren Sie SQL-Text in Bytecode, um die Datenbank abzufragen oder zu aktualisieren. Der Konstruktor für sqlite3_stmt.

  5. sqlite3_bind () → Anwendungsdaten in Parametern des ursprünglichen SQL speichern.

  6. sqlite3_step () → Bringt ein sqlite3_stmt zur nächsten Ergebniszeile oder zum Abschluss.

  7. sqlite3_column () → Spaltenwerte in der aktuellen Ergebniszeile für einen sqlite3_stmt.

  8. sqlite3_finalize () → Destruktor für sqlite3_stmt.

  9. sqlite3_exec () → Eine Wrapper-Funktion, die sqlite3_prepare (), sqlite3_step (), sqlite3_column () und sqlite3_finalize () für eine Zeichenfolge aus einer oder mehreren SQL-Anweisungen ausführt.

  10. sqlite3_close () → Destruktor für sqlite3.

sqlite3 architektur

Mit den Komponenten Tokenizer, Parser und Code Generator werden SQL-Anweisungen verarbeitet und in ausführbare Programme in einer Sprache der virtuellen Maschine oder in Bytecode konvertiert. Grob gesagt implementieren diese drei obersten Ebenen sqlite3_prepare_v2 () . Der von den oberen drei Schichten erzeugte Bytecode ist eine vorbereitete Anweisung. Das Virtual Machine-Modul ist für die Ausführung des SQL-Anweisungsbytecodes verantwortlich. Das B-Tree-Modul organisiert eine Datenbankdatei in mehreren Schlüssel- / Wertspeichern mit geordneten Schlüsseln und logarithmischer Leistung. Das Pager-Modul ist dafür verantwortlich, Seiten der Datenbankdatei in den Speicher zu laden, Transaktionen zu implementieren und zu steuern sowie Journaldateien zu erstellen und zu verwalten, die eine Beschädigung der Datenbank nach einem Absturz oder Stromausfall verhindern. Die Betriebssystemschnittstelle ist eine schlanke Abstraktion, die eine Reihe von Routinen zur Anpassung von SQLite für die Ausführung auf verschiedenen Betriebssystemen bereitstellt. Grob gesagt implementieren die unteren vier Ebenen sqlite3_step () .

sqlite3 virtuelle Tabelle

Eine virtuelle Tabelle ist ein Objekt, das bei einer offenen SQLite-Datenbankverbindung registriert ist. Aus der Sicht einer SQL-Anweisung sieht das virtuelle Tabellenobjekt wie jede andere Tabelle oder Sicht aus. Hinter den Kulissen rufen Abfragen und Aktualisierungen einer virtuellen Tabelle jedoch Rückrufmethoden des virtuellen Tabellenobjekts auf, anstatt die Datenbankdatei zu lesen und zu schreiben.

Eine virtuelle Tabelle kann eine speicherinterne Datenstruktur darstellen. Oder es kann eine Ansicht von Daten auf der Festplatte darstellen, die nicht im SQLite-Format vorliegen. Oder die Anwendung berechnet den Inhalt der virtuellen Tabelle nach Bedarf.

Hier sind einige existierende und postulierte Verwendungen für virtuelle Tabellen:

Eine Volltextsuchoberfläche
Raumindizes mit R-Bäumen
Untersuchen Sie den Festplatteninhalt einer SQLite-Datenbankdatei (die virtuelle Tabelle dbstat).
Lesen und / oder schreiben Sie den Inhalt einer CSV-Datei (Comma-Separated Value)
Greifen Sie auf das Dateisystem des Host-Computers zu, als wäre es eine Datenbanktabelle
Aktivieren der SQL-Manipulation von Daten in Statistikpaketen wie R

SQLite verwendet eine Vielzahl von Testtechniken, darunter:

Drei unabhängig voneinander entwickelte Prüfgurte
100% Zweigstellentestabdeckung in einer Konfiguration im Bereitstellungszustand
Millionen und Abermillionen von Testfällen
Out-of-Memory-Tests
E / A-Fehlertests
Crash- und Power-Loss-Tests
Fuzz-Tests
Grenzwertprüfungen
Optimierungstests deaktiviert
Regressionstests
Fehlerhafte Datenbanktests
Umfangreiche Verwendung von assert () und Laufzeitprüfungen
Valgrind-Analyse
Undefinierte Verhaltensüberprüfungen
Checklisten

Verweise

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.