Softwareprojekt und OOP Evolution

Als ich die Rezepte für die effektive Entwicklung eines Softwareprojekts beherrschte, versuchte ich selbst herauszufinden, warum es nützlich ist, die Prinzipien der Entwicklung der SOLID-Architektur zu verwenden (Artikel Wie man die Prinzipien der Entwicklung der SOLID-Architektur nicht versteht ).


Eine Analyse dieser Prinzipien ermöglichte es, mehrere Schlüsselmuster und Grundelemente zu identifizieren, die in der Entwicklung existieren. Sie ermöglichten es uns, SOLID in der realen Arbeit mit einem Softwareprojekt zu beschreiben, zu verstehen und zu implementieren.


Es wurde interessant, eine Analyse der Anwendbarkeit dieser Konzepte für allgemein akzeptierte Programmierparadigmen durchzuführen, beispielsweise für OOP. Nun, wenn das Ergebnis dieser Arbeit für Sie nützlich sein wird.


Bild


Heute gibt es viele Ansätze für das Design und die anschließende Implementierung von Softwareprojekten. Die gefragtesten bei der Arbeit mit großen Softwareprojekten sind: Strukturprogrammierung , funktionale Programmierung , objektorientierte Programmierung .


Für mich wurde es interessant, die Ursachen dieser Designansätze zu analysieren. Und während des Analyseprozesses war die unerwartete Entdeckung die Tatsache, dass sie alle implizit auf der folgenden Prämisse beruhen:


          ,      . 

Software-Projektentwicklung


Was ist ein Projekt ohne Entwicklungsbedarf? Solche Projekte werden selten gefunden und zeichnen sich hauptsächlich durch eine schnelle Stücklohnzahlung ohne spätere Verpflichtungen des Programmierers aus, zum Beispiel:


  • ein kleines Projekt, das mit einem Ansatz geschrieben werden kann;
  • Ein Projekt ohne strukturell komplexen Code, das mit einer Vielzahl von Beziehungen belastet ist.
  • Softwareprodukt ohne die Notwendigkeit seiner Unterstützung und Benutzerunterstützung.

In solchen Situationen werden die Bemühungen des Programmierers, beispielsweise einen objektorientierten Ansatz beizubehalten, verschwendet. Es kommt oft vor, dass ich mich während der Entwicklung eines einmaligen Konsolendienstprogramms in einer so bedeutungslosen Lektion befinde, wenn mir plötzlich klar wird, dass das Schreiben des Textes der 4. Klasse in diesem Projekt mich um 15 Minuten verzögert und mich dem Ergebnis nicht näher gebracht hat. Das Traurigste ist, dass alle Klassen, die in solchen Projekten kaum geschrieben wurden, vergessen und nicht wiederverwendet werden, das heißt, sie erleichtern unsere Arbeit in Zukunft nicht.


In allen anderen Situationen muss der Programmierer, um seine Arbeit zu minimieren, ein strukturell komplexes Projekt entwickeln, dh:


  • Korrigieren Sie Fehler, indem Sie den Code analysieren und die Stellen suchen, an denen diese Fehler generiert werden.
  • Einführung neuer Funktionen unter Beibehaltung der Funktionalität aller zuvor verfügbaren Funktionen. Verwenden Sie dabei vorhandenen Code (geschrieben und getestet) für die Implementierung dieser neuen Aufgaben.
  • Bieten Sie Unterstützung bei der Verwendung eines Softwareprodukts.
  • Führen Sie eine Beschreibung und Koordination der Funktionalität aller Versionen des Projekts durch.
  • Halten Sie alle vom Projekt verwendeten Datenformate (auch veraltet) betriebsbereit.
  • Und führen Sie viele andere Aufgaben aus, die in der Konfrontation mit Wettbewerbern auftreten, die durch sich ändernde Frameworks oder das Ende der Unterstützung für veraltete Betriebssysteme verursacht wird ...

Wenn Sie nach Analogien zur Entwicklung eines Softwareprojekts suchen, können Sie sich an die Entwicklung einer biologischen Spezies erinnern.


      "".     -       .       -  . 

Die Arbeit des Programmierers ist nicht einfach, aber der Programmierer hat einen "Helfer". Dieser Helfer ist irgendwo tief in der Struktur unserer Welt versteckt, in der es zwei Merkmale gibt:


  • die Fähigkeit, einen nützlichen Algorithmus zu schreiben und ihn für viele ähnliche Aufgaben zu verwenden,
  • das Vorhandensein einer Vielzahl von Aufgaben ähnlich in ihrer Lösung.

Dieser in vielen Bereichen nützliche Algorithmus wird der Kürze halber als universeller Algorithmus bezeichnet. Die Implementierung für ein bestimmtes Anwendungsgebiet kann als Spezialisierung bezeichnet werden, da der Prozess der Verfeinerung des Algorithmus zur Verwendung in einem engen Anwendungsbereich der evolutionären Spezialisierung von Zellen in einem lebenden Organismus ähnelt.


Um einen Algorithmus zu erstellen, müssen natürlich Merkmale identifiziert werden, die die Anwendbarkeit des Algorithmus sicherstellen. Diese Zeichen müssen in den Eingabedaten und in der Beschreibung der Ausgangssituation (Kontext) gesucht werden. Um einen universellen Algorithmus zu erstellen, ist es in jedem Themenbereich, der seine eigenen Sätze von Daten- und Situationszeichen aufweist, erforderlich, Zeichen der Anwendbarkeit zu identifizieren, die für alle Bereiche identisch sind. Alle anderen Zeichen, die keine Anwendbarkeit bieten, werden vom universellen Algorithmus ignoriert. Bei der Formalisierung des universellen Algorithmus sind wir zur Notwendigkeit gekommen, die Abstraktion zu verwenden - eines der wichtigsten Prinzipien von OOP. Darüber hinaus zeichnet sich OOP durch eine Betonung nur der Datenabstraktion aus.


Hier werde ich versuchen, Beispiele für die Verwendung von Abstraktion aus verschiedenen Bereichen zu schreiben.


AbstraktionAlgorithmenAnwendungsgebiet
Natürliche ZahlenQuantitative BerechnungsalgorithmenAufgaben der Bilanzierung wirtschaftlicher Werte
Masseeigenschaft des materiellen KörpersAlgorithmen zum Vergleichen der SubstanzmengeAufgaben zum Vergleichen des Wertes eines nicht rechenschaftspflichtigen Produkts
Schnittstelle zu Operationen für eine Sammlung von Elementen: vollständiges Crawlen, Vergleichen und Austauschen von PositionenSortieralgorithmen für SammlungenProgrammierung
Die Schnittstelle der gleichen Operationen für den "Endknoten" und den "Verzweigungsknoten" im BaumAlgorithmen basierend auf dem Layout-EntwurfsmusterEntwicklung eines komplexen Softwareprojekts
Schlüsselkonzept "Mitarbeiter"Formulierung im Abschnitt "Arbeitsvertrag"Arbeitsgesetzbuch

Baustein eines Softwareprojekts


Unter Verwendung verschiedener Abstraktionstechniken implementiert der Programmierer den Algorithmus in Form eines Codeabschnitts, der ein separates und vollständiges Element seiner Arbeit darstellt. Dieses Element kann abhängig von der verwendeten Programmiersprache eine Funktion, ein Objekt und eine Folge von Anweisungen sein. Zur Vereinfachung der weiteren Diskussion werden wir dieses Codefragment das Wort " Komponente " nennen.


Komponente - ein Code (Prozedur, Klasse, Bereitstellungskomponente usw.):


  • welches einen vollständigen Algorithmus implementiert, der in bestimmten Ausgangssituationen und mit bestimmten Eingabedaten funktioniert,
  • die mehrmals in einem Projekt verwendet werden kann (noch besser viele Male in verschiedenen Projekten),
  • Alle Anweisungen befinden sich in der Nähe und werden angezeigt, ohne dass zusätzliche Suchvorgänge in der Entwicklungsumgebung erforderlich sind.
  • Änderungen, bei denen der Programmierer relativ unabhängig vom Rest des Codes arbeitet.

Muster bei der Entwicklung eines Softwareprojekts


Mit dem Begriff Komponente wird es möglich, eine Reihe einfacher Gesetze zu formulieren, die bei der Entwicklung eines Softwareprojekts existieren. Ich werde diese Muster in Form der folgenden Aussagen präsentieren, die in drei Kategorien unterteilt sind.


  1. Anweisungen, die die Eigenschaften einer Komponente beschreiben .
    1.1. Eine korrekt geschriebene Komponente wird notwendigerweise und häufiger mehrmals verwendet.
    1.2. An jedem Ort, an dem die Komponente verwendet wird, wird ein konstantes Verhalten erwartet, was zu einem wiederholbaren Ergebnis führt.
    1.3. Wenn Sie die Komponente an mehreren Stellen verwenden, sollte das Ergebnis jedem Verwendungsort entsprechen.
    1.4. Das in die Komponente eingebettete Verhalten führt zu Einschränkungen bei den Verwendungsorten dieser Komponente .
    1.5. An jedem Verwendungsort der Komponente können alle Einschränkungen auftreten.
    1.6. Jede Änderung an einer Komponente ändert ihre Einschränkungen und erfordert die Überprüfung aller Verwendungsorte, wodurch ein Programmierer Zeit verschwendet.
    1.7. Es ist ratsam, die Komponente in einer Instanz in Form von Code zu schreiben, dh es ist erforderlich, die Duplizierung desselben Codes zu vermeiden. Dadurch wird die Anzahl der Änderungen beim Ändern einer Komponente verringert.
  2. Anweisungen, die Muster bei der Implementierung einer neuen Aufgabe durch den Programmierer beschreiben.
    2.1 Es ist ratsam, eine Option zum Implementieren einer neuen Aufgabe zu wählen und gleichzeitig den Zeitaufwand des Programmierers zu minimieren.
    2.2. Um eine neue Aufgabe zu implementieren, kann ein Programmierer neue Komponenten hinzufügen oder das Verhalten alter Komponenten ändern.
    2.3. Das Hinzufügen einer Komponente erfordert grundsätzlich die Überprüfung nur am Ort der neuen Verwendung und generiert nur minimale Zeit für den Programmierer.
    2.4. Gemäß Aussage [1.6] erfordert eine durch eine neue Aufgabe verursachte Änderung des Verhaltens einer Komponente eine Überprüfung am Ort der neuen Verwendung und an allen Orten der alten Verwendung, was im Vergleich zur Situation in Aussage [2.3] zusätzliche Zeitkosten für Programmierer verursacht. Bei einer veröffentlichten Komponente erfordert dies die Arbeit aller Programmierer, die die geänderte Komponente verwenden .
  3. Aussagen, die Muster im Zusammenspiel universeller Algorithmen und ihrer Spezialisierungen beschreiben:
    3.1. Es besteht die Möglichkeit, eine Basiskomponente zu schreiben (der Name wird in Analogie zur Basisklasse eingeführt und der Kürze halber wird das Wort " Basis " verwendet). Die Basis erfüllt nur die wichtigsten Merkmale eines universellen Algorithmus.
    3.2. Es ist möglich, eine Komponentenspezialisierung zu schreiben (im Folgenden wird der Kürze halber das Wort " Spezialisierung " verwendet). Die Spezialisierung ergänzt den universellen Algorithmus der Basis und macht sie in einem bestimmten Anwendungsbereich anwendbar.
    3.3. Die Basis hat , wie aus den Aussagen [3.1], [3.2] hervorgeht, eine geringere Komplexität und weniger Anwendungsbeschränkungen als die Spezialisierung .
    3.4. Gemäß der Aussage [1.7] ist es ratsam, eine Spezialisierung zu entwickeln , ohne den universellen Algorithmuscode aus der Datenbank zu duplizieren.
    3.5. Verwendungsorte der Datenbank müssen nicht überprüft werden, nachdem Änderungen an der korrekt geformten Spezialisierung vorgenommen wurden .

Objektorientierte Programmierkonzepte


Ich werde versuchen, anhand der obigen Aussagen die Grundkonzepte der objektorientierten Programmierung zu analysieren. Diese Analyse umgeht das Konzept der Abstraktion , da es bereits früher in der Formalisierung der Methode zur Konstruktion eines universellen Algorithmus beschrieben wurde.


Klasse, Objekt


Diese OOP-Konzepte verstärken die Machbarkeit der Verwendung eines speziellen Komponententyps , der durch eine Kombination einiger interner Daten und Methoden zum Arbeiten mit diesen Daten beschrieben wird. Alle Aussagen der Gruppe [1] und [2] werden in OOP übersetzt, wobei der Begriff Komponente durch den Klassenbegriff ersetzt wird .


Gleichzeitig werden auf den ersten Blick die Beziehungen einer Klasse und eines Objekts durch die Gruppe von Aussagen [3] erschöpft, in der die Basis durch das Konzept einer Klasse und die Implementierung durch das Konzept eines Objekts ersetzt wird . Darüber hinaus ist die Implementierung dynamisch, dh während der Ausführung des Programms veränderbar.


Kapselung


Das Konzept der " Einkapselung " kann von zwei "Seiten" betrachtet werden.


Die erste Seite des Konzepts der " Kapselung " ist die Isolierung der Komponente von anderen Teilen des Codes. Mit dieser Eigenschaft kann der Programmierer Operationen in Bereichen des Codes ausführen, die sich "in der Nähe" befinden, um Änderungen an der Komponente vorzunehmen. Das heißt, um den Zeitaufwand des Programmierers zu minimieren, indem die Suche und Analyse unterschiedlicher interagierender Elemente des Programms von der Arbeit ausgeschlossen wird. Diese Seite wird durch die Eigenschaften der Komponente definiert, die sich aus ihrer Definition ergeben.


Die zweite Seite des Konzepts der " Kapselung " ist die Verschleierung der internen Implementierung der Komponente . Diese Verschleierung ist mit den in der Gruppe der Aussagen [3] beschriebenen Konzepten der Basis und Implementierung möglich. Zu diesem Zweck werden öffentliche Klassenmethoden mit der Basis und private und geschützte Klassenmethoden mit der Implementierung identifiziert. An Verwendungsorten werden die von der Basis gebildeten Einschränkungen verwendet , und daher wird es möglich, Änderungen an der Implementierung vorzunehmen, die nicht mit den grundlegenden Einschränkungen zusammenhängen. Und diese Implementierungsänderungen müssen nicht an den Stellen überprüft werden, an denen die Datenbank verwendet wird [3.5], wodurch der Arbeitsaufwand des Programmierers minimiert wird.


Es ist bemerkenswert, dass das Konzept der " Einkapselung " eine Analogie in der Biologie hat. Dieser erste Prozess ähnelt den biologischen Funktionen der " Zellmembran ".


Vererbung


Das Konzept der " Vererbung " unterstreicht weiterhin die Bedeutung der Verwendung einer Kombination aus Basis + Implementierung . Dazu ist es in der Gruppe der Anweisungen [3] erforderlich, die Methoden der übergeordneten Klasse mit der Basis und die Methoden der Nachfolgerklasse mit der Implementierung zu identifizieren.


In seiner Implementierung erlaubt das Konzept der „ Vererbung “ die Verwendung der Anweisung [2.3], dh das Hinzufügen von Code, anstatt ihn zu ändern und zu duplizieren. In diesem Fall muss die Duplizierung des Basisalgorithmus ausgeschlossen werden. Ein Ansatz, bei dem die Vererbung zur Spezialisierung eines universellen Algorithmus verwendet wird, weist jedoch ein signifikantes Minus auf. Dieser Nachteil ist das Vorhandensein von zwei stark verbundenen Komponenten , die sich nur schwer unabhängig voneinander ändern lassen. Diese Abhängigkeitsbeziehungen werden von der Eltern-Kind-Beziehung generiert.


Es gibt viele alternative Möglichkeiten, das Base + -Implementierungspaket zu verwenden. Ich werde weitere Beispiele für solche Methoden geben.


BasisImplementierungAnwendungsgebiet
Methoden der öffentlichen KlassePrivate KlassenmethodenKapselung
Geschützte Methoden der übergeordneten KlasseMethoden der VererbungsklasseVererbung
Dynamische BibliotheksschnittstelleDynamische BibliotheksfunktionalitätKomponente = dynamische Bibliothek
Vorlagen (verallgemeinerte) Methoden und Klassen (Vorlage, generisch)Instanziieren einer Vorlage mit angegebenen ArgumentenAllgemeine Programmierung
Generische Methoden, die Delegaten akzeptierenSpezialisierung von Methoden zur Angabe spezifischer VerarbeitungsverfahrenVerfahren zum Sortieren oder Bilden eines Baums, die die Methode zum Bewerten der Reihenfolge der Elemente angeben
Klassen, die die Interaktion mit der Besuchervorlage ermöglichenBildung von "Besucher" mit der erforderlichen FunktionalitätBesucher-Design-Muster
KKW-BedienfeldDas Set der Automatisierung und Ausrüstung von KernkraftwerkenVerschleierung der Systemkomplexität vor dem KKW-Betreiber

Gleichzeitig stelle ich fest, dass man für das Konzept der " Vererbung " von der PLO auch eine Analogie in den Prozessen der biologischen Evolution finden kann. In der Biologie wird hierfür der Begriff " Vererbung " verwendet.


Polymorphismus


Meiner Meinung nach ist das Konzept des " Polymorphismus " die zweite Seite, wenn man das Verfahren zur Erstellung eines universellen Algorithmus betrachtet. Die erste Seite ( Abstraktion ) ist eine Ansicht unter dem Gesichtspunkt, wie ein universeller Algorithmus erstellt werden kann. Wenn wir den universellen Algorithmus aus der Sicht des Benutzers betrachten, erhalten wir gleichzeitig eine Aufzeichnung des Konzepts des Polymorphismus . Das heißt, Polymorphismus ist eine nützliche Fähigkeit einer Funktion ( Komponente ), Daten verschiedener Typen zu verarbeiten. Das Hinzufügen dieses Konzepts zu OOP verstärkt die Nützlichkeit der Verwendung eines universellen Algorithmus bei der Entwicklung eines Softwareprojekts.


Polymorphismus-Implementierungen in verschiedenen Programmiersprachen sind sehr unterschiedlich. Im Wikipedia-Artikel für Polymorphismus gibt es je nach Implementierung 4 Untertypen: parametrisch, Einschluss (oder Untertypen), Überladung, Typumwandlung. Diese Implementierungen weisen erhebliche Unterschiede auf, aber alle sind durch ein Ziel verbunden - dies ist das Schreiben eines universellen Algorithmus, der für seine spezifische Spezialisierung nicht dupliziert werden muss.


Und diesmal fand er fast ohne Überraschung eine Analogie zum Konzept des " Polymorphismus " in der Biologie. Der Name dieses biologischen Begriffs stimmt vollständig mit dem Konzept der OOP überein. " Polymorphismus " - die Fähigkeit eines Organismus, in Zuständen mit unterschiedlichen inneren Strukturen oder in unterschiedlichen äußeren Formen zu existieren.


Fazit


Somit können fast alle Grundkonzepte von OOP als eine Reihe einfacher Aussagen dargestellt werden, die auf der Grundlage der Entwicklungsgesetze eines Softwareprojekts gebildet werden. Darüber hinaus wird für OOP der Begriff Komponente mit dem Konzept einer Klasse identifiziert. Wenn wir eine andere Bedeutung für den Begriff Komponente herausgreifen , zum Beispiel eine Funktion , ist es möglich, die Grundkonzepte der funktionalen Programmierung zu formulieren.


Beim Schreiben des Artikels wurden biologische Analogien für Konzepte gefunden, die in der Programmierung verwendet werden. Diese Analogien ergeben sich aus der Ähnlichkeit der Entwicklungsmethoden eines Softwareprodukts und einiger Prozesse der biologischen Evolution.


IMHO ist es ratsam, diese beiden wissenschaftlichen Bereiche zusammen zu betrachten. In diesem Fall kann es möglich sein, die Übertragung von Gesetzen von einer Branche in eine andere durchzuführen und dadurch die Entwicklung sowohl der Informationstechnologie als auch der formalen Beschreibung biologischer Prozesse sicherzustellen.


Vielen Dank für Ihre Aufmerksamkeit.


Bewertungen


Ich wäre sehr dankbar für das Feedback, die Vorschläge und Vorschläge, da sie mir helfen, die Richtung der Entwicklung der Arbeit in diesem Bereich anzupassen.


Referenzen



Herausgegeben von Borisova M.V.

Source: https://habr.com/ru/post/de448026/


All Articles