Was ist "vorzeitige Abstraktion"?

10

Ich habe gehört, wie der Satz herumgeworfen wurde, und für mich klingen die Argumente völlig verrückt (sorry, wenn ich hier Strohmann bin, es ist nicht meine Absicht), im Allgemeinen geht es etwas in der Art von:

Sie möchten keine Abstraktion erstellen, bevor Sie den allgemeinen Fall kennen. Andernfalls (1) können Sie Dinge in Ihre Abstraktionen einfügen, die nicht dazu gehören, oder (2) wichtige Dinge weglassen.

(1) Für mich klingt dies so, als ob der Programmierer nicht pragmatisch genug ist. Sie haben Annahmen getroffen, dass Dinge im endgültigen Programm existieren würden, die dies nicht tun. Sie arbeiten also mit einem zu geringen Abstraktionsgrad, das Problem ist es nicht vorzeitige Abstraktion, es ist vorzeitige Konkretion.

(2) Das Weglassen wichtiger Dinge ist eine Sache. Es ist durchaus möglich, dass etwas in der Spezifikation weggelassen wird, das sich später als wichtig herausstellt. Die Lösung hierfür besteht nicht darin, Ihre eigene Konkretion zu finden und Ressourcen zu verschwenden, wenn Sie es herausfinden falsch geraten, um mehr Informationen vom Kunden zu erhalten.

Wir sollten immer von Abstraktionen bis hin zu Konkretionen arbeiten, da dies die pragmatischste Art ist, Dinge zu tun, und nicht umgekehrt.

Wenn wir dies nicht tun, riskieren wir, Kunden falsch zu verstehen und Dinge zu schaffen, die geändert werden müssen. Wenn wir jedoch nur die Abstraktionen erstellen, die die Kunden in ihrer eigenen Sprache definiert haben, sind wir diesem Risiko nie ausgesetzt (zumindest bei weitem nicht so wahrscheinlich wie das Eingehen ein Schuss in die Dunkelheit mit einer gewissen Konkretion), ja, es ist möglich, dass Kunden ihre Meinung über die Details ändern, aber die Abstraktionen, mit denen sie ursprünglich kommunizierten, was sie wollen, sind in der Regel immer noch gültig.

Angenommen, ein Kunde möchte, dass Sie einen Artikelverpackungsroboter erstellen:

public abstract class BaggingRobot() {
    private Collection<Item> items;

    public abstract void bag(Item item);
}

Wir bauen etwas aus den Abstraktionen auf, die der Kunde verwendet hat, ohne näher auf Dinge einzugehen, die wir nicht kennen. Dies ist äußerst flexibel. Ich habe gesehen, dass dies als "vorzeitige Abstraktion" bezeichnet wird, obwohl es in Wirklichkeit verfrüht wäre anzunehmen, wie das Absacken implementiert wurde. Nehmen wir beispielsweise an, dass nach der Besprechung mit dem Kunden mehr als ein Gegenstand gleichzeitig verpackt werden soll . Um meine Klasse zu aktualisieren, muss ich nur die Signatur ändern, aber für jemanden, der von unten nach oben gestartet ist, kann dies eine umfassende Systemüberholung bedeuten.

Es gibt keine vorzeitige Abstraktion, nur vorzeitige Konkretion. Was ist falsch an dieser Aussage? Wo sind die Fehler in meiner Argumentation? Vielen Dank.

James
quelle
1
Das Gegenteil von vorzeitiger Abstraktion ist YAGNI - Du wirst es nicht brauchen, was meiner Meinung nach fast immer falsch ist. Fast. Ich habe es gesehen, aber es ist selten. Ich stimme größtenteils dem zu, was Sie hier sagen.
user1118321

Antworten:

19

Zumindest meiner Meinung nach ist vorzeitige Abstraktion ziemlich häufig und war besonders früh in der Geschichte von OOP.

Zumindest nach dem, was ich gesehen habe, bestand das Hauptproblem darin, dass die Leute die typischen Beispiele objektorientierter Hierarchien durchgelesen haben. Sie bekamen viel gesagt über bereit machen alles mit zukünftigen Änderungen zu befassen , die möglicherweise entstehen (auch wenn es keinen besonders guten Grund zu glauben , sie würden). Ein anderes Thema, das vielen Artikeln für eine Weile gemeinsam war, waren Dinge wie das Schnabeltier, das sich einfachen Regeln über "Säugetiere sind alle so" oder "Vögel sind alle so" widersetzt.

Infolgedessen haben wir Code erhalten, der sich wirklich nur mit Aufzeichnungen von Mitarbeitern befassen musste, aber sorgfältig geschrieben wurde, um bereit zu sein, falls Sie jemals ein Spinnentier oder vielleicht ein Krebstier eingestellt haben.

Jerry Sarg
quelle
Vorzeitige Abstraktion ist also nicht der Akt der Abstraktion, sondern der Akt der Abstraktion über die spezifizierte Abstraktionsebene hinaus. Das macht viel mehr Sinn, und ich konnte sehen, dass das tatsächlich passiert. Ich denke, ich muss meinen Kollegen nur klarer machen, dass ich auf der von meinem Manager beschriebenen Abstraktionsebene arbeite.
James
1
@James: Es kann auch bedeuten, "zu viel" über die Spezifikationen von Version 1.0 hinaus zu abstrahieren, da Sie glauben, eine neue Anforderung in der Spezifikation einer späteren Version zu kennen und daher Version 1.0 bereits allgemeiner zu implementieren als notwendig. In manchen Fällen ist es gut, sich vorzustellen, was in einer späteren Version passieren könnte, aber es besteht auch ein gewisses Risiko einer Überentwicklung.
Doc Brown
@ DocBrown Ich würde das vorzeitige Konkretion nennen. Der Akt der Abstraktion besteht darin, Informationen zu entfernen, nicht hinzuzufügen. Wenn Sie der Abstraktion mehr hinzufügen, als erforderlich ist, gehen Sie von niedrigeren Abstraktionsebenen aus. Ich möchte zwischen den beiden unterscheiden, da ich denke, dass "Abstraktion" nicht viel Sinn macht, da die Definition von Abstraktion "der Prozess des Extrahierens der zugrunde liegenden Essenz" ist, wobei "als Konkretion" durch unmittelbare Erfahrung gekennzeichnet ist oder zu dieser gehört von tatsächlichen Dingen oder Ereignissen ".
James
6

Es ist wichtig, sich daran zu erinnern, dass Abstraktion ein Mittel zum Zweck ist. Sie verwenden die Abstraktion, um das Verhalten in Ihrem Programm zu vereinheitlichen und das Hinzufügen neuer Klassen zu vereinfachen, wenn Sie erwarten, dass neue Klassen hinzugefügt werden, jedoch nur dann, wenn die Abstraktion in diesem Moment benötigt wird.

Sie würden keine Abstraktion hinzufügen, nur weil Sie sie möglicherweise benötigen (ohne echte Grundlage für die Annahme, dass Sie in Zukunft neue Klassen hinzufügen müssen). Eine richtige Metapher hier könnte Sanitär sein. Hoffentlich stimmen Sie zu, dass ein 6-Richtungsrohr, mit dem Wasser nach oben / unten, Ost / West, Nord / Süd fließen kann, der flexibelste Rohrtyp ist, den Sie haben könnten. Sie könnten theoretisch ein 6-Richtungsrohr überall dort verwenden, wo ein Rohr benötigt wird, und die nicht benötigten Richtungen blockieren, oder?

Wenn Sie versucht haben, ein Problem mit einem Leck unter Ihrem Waschbecken zu beheben, und festgestellt haben, dass alle Rohrabschnitte 6-Richtungs-Rohrstücke sind, möchten Sie dem Mann, der es so entworfen hat, frustriert die Haare ausreißen. Sie wissen nicht nur nicht, wo das Problem liegt, sondern es wäre mit ziemlicher Sicherheit einfacher, einfach von vorne zu beginnen und es richtig zu machen.

Natürlich ist Codierung kein Sanitär, aber die Metapher steht immer noch. Die Abstraktion ähnelt der Verwendung dieser 6-Richtungs-Rohrstücke. Verwenden Sie sie, wenn Sie ehrlich glauben, dass Sie eines Tages in naher Zukunft Rohre aus allen 6 Richtungen anschließen müssen. Ansonsten ist Abstraktion einfach eine Komplikation, nicht viel anders als die Verwendung eines Musters, bei dem keines erforderlich ist, oder die Verwendung einer Gottklasse, die versucht, alles zu tun. Wenn es nicht verwendet wird und wahrscheinlich nie verwendet wird, fügen Sie letztendlich eine zusätzliche Klasse für nichts hinzu.

Zugegeben, die Kunst, Programme zu schreiben, ist konzeptionell sehr, sehr abstrakt. Es ist nur erwähnenswert, dass Abstraktionen nicht existieren, um eine Abstraktion zu sein, sondern weil sie auf echte Weise praktisch sind . Wenn Sie das Bedürfnis haben, Abstraktion zu verwenden, sollten Sie es tun, aber bitten Sie mich nicht, Ihre Installation anschließend zu überprüfen. ;)

Neil
quelle
Sie scheinen ein bisschen classzentriert zu sein ... Selbst wenn es viele Klassen gibt, ist die Abstraktion nicht darauf beschränkt, in ihnen verwendet zu werden.
Deduplikator
1
@Deduplicator Fair genug, aber das ändert nichts an meinem Standpunkt. Wenn Abstraktion verwendet wird, sollte dies sofort von Vorteil sein oder in naher Zukunft eine geplante Änderung sein. Es ist nicht wichtig, dass wir uns auf Klassen oder funktionale Programmierung beziehen.
Neil
3

Als ich vor vielen Jahren etwas über objektorientierte Analyse und Design erfuhr, begannen wir mit einer einfachen englischen Beschreibung des Systems, das der Kunde benötigte.

Wenn man das durchschaut, wird jedes Substantiv (oder jede Nominalphrase) als mögliche Klasse betrachtet. Alle Verben (oder Verbalphrasen) wären mögliche Methoden für Klassen. "Bagging Robot" könnte also eine Klasse sein BaggingRobot. "Öffnen Sie eine Tasche" könnte Methode werden OpenBag.

Nach einigen Iterationen würde dies zu einem Klassendiagramm.

Zu diesem Zeitpunkt gibt es keine abstrakten Klassen. Der Kunde möchte kein abstraktes Konzept eines Absackroboters. Sie wollen einen Roboter, der Dinge in Taschen packt. Alle Klassen sind konkret und haben eine Reihe von Methoden.

Abstrakte Klassen werden nur eingeführt, wenn klar wird, dass:

  • Es gibt mehrere ähnliche Klassen, die eine Hierarchie bilden könnten.
  • Sie haben tatsächlich etwas gemeinsam, sodass eine Basisklasse einen nützlichen Zweck erfüllt.

Für mich bedeutet "vorzeitige Abstraktion", dass jeder von einigen erben BaggingRobot mussBaseRobot und, schlimmer noch, versucht, eine Reihe von Methoden zu entwickeln, BaseRobotbevor Sie überhaupt wissen, was allen Robotern gemeinsam ist.

Simon B.
quelle
Abstraktion ist nicht gleichbedeutend mit abstrakten Klassen. Eine Schnittstelle ist eine Abstraktion. Ich spreche von Abstraktionen im Allgemeinen, nicht nur von abstrakten Klassen. Vielleicht hätte ich dies durch die Verwendung einer Schnittstelle klarer machen können. Wenn Sie Ihr System auf derselben Abstraktionsschicht wie Ihr Client entwickeln, werden Sie wahrscheinlich einige abstrakte Klassen haben, die erweitert werden müssen, da die Sprache von Natur aus abstrakt ist. Niedriger zu arbeiten ist das, was ich als "vorzeitige Konkretion" bezeichne, bei der Sie naiv davon ausgehen, dass die Vorstellungen des Kunden über die Funktionsweise des Systems dieselben sind wie Ihre.
James
Ein BaggingRobot-Objekt, das Item-Objekte in Bag-Objekte legt, ist bereits eine Abstraktion eines echten Bagging-Roboters, der Dinge in Taschen packt.
user253751
1

Es hört sich ein bisschen so an, als ob Sie ein Problem lösen möchten, das noch nicht existiert, und dass Sie keinen guten Grund haben anzunehmen, dass es auftreten wird, es sei denn, Sie glauben nur, dass der Client in dem, was er anfordert, falsch liegt. In diesem Fall würde ich mehr Kommunikation empfehlen, als eine abstrakte oder sonstige Vermutungslösung zu implementieren. Es mag zwar harmlos erscheinen, nur "abstrakt" auf die Klassendefinition zu setzen und sich sicher zu fühlen, dass Sie sie später erweitern können, aber Sie werden feststellen, dass Sie dies niemals tun müssen, oder Sie werden feststellen, dass Sie sie auf eine Weise erweitern, die das Design zu kompliziert macht die Linie, indem man die falschen Dinge abstrahiert.

Stellen Sie sich anhand Ihres Beispiels vor, dass es der Roboter selbst , die verpackten Gegenstände oder die Art des Absackens ist , die sich später ändern werden?

Vorzeitige Abstraktion bedeutet wirklich nur, dass Sie keinen guten Grund haben, die Abstraktion durchzuführen, und da Abstraktionen in vielen Sprachen weit davon entfernt sind, kostenlos zu sein, können Sie ohne Begründung Overhead verursachen.

Bearbeiten Um einige Punkte aus OP in den Kommentaren zu beantworten, aktualisiere ich dies, um dies zu verdeutlichen und so zu beantworten, dass keine lange Kommentarkette erforderlich ist, während die Punkte (1) und (2) genauer angesprochen werden.

(1) Für mich klingt dies so, als ob der Programmierer nicht pragmatisch genug ist. Sie haben Annahmen getroffen, dass Dinge im endgültigen Programm existieren würden , die dies nicht tun. Sie arbeiten also mit einem zu geringen Abstraktionsgrad, das Problem ist es nicht vorzeitige Abstraktion, es ist vorzeitige Konkretion.

(Hervorhebung von mir). Angenommen, im endgültigen Programm gibt es Dinge, die nicht genau das sind, was ich in Ihrem Beispiel sehe. Der Kunde bat um einen Roboter zum Absacken von Gegenständen. Dies ist eine sehr spezifische Anfrage, wenn auch in ihrer Sprache etwas vage. Der Kunde wünscht sich einen Roboter, der Gegenstände einpackt, sodass Sie ein Paar Objekte herstellen können

public class Item {
/* Relevant item attributes as specified by customer */
}
public class BaggingRobot {
  private Collection<Item> items;

  public void bag(Item item);
}

Ihr Modell ist einfach und präzise. Es folgt den vom Kunden gestellten Anforderungen, ohne die Lösung komplexer zu gestalten und ohne davon auszugehen, dass der Kunde mehr wollte, als er wollte. Wenn dies die Notwendigkeit eines austauschbaren Absackmechanismus des Roboters verdeutlicht, verfügen Sie nur dann über genügend Informationen, um die Erstellung einer Schnittstelle oder einer anderen Abstraktionsmethode zu rechtfertigen, da Sie jetzt auf einen bestimmten Mehrwert verweisen können , der hinzugefügt wird das System durch die Abstraktion.

Im Gegenteil, wenn Sie mit der Abstraktion vom reinen Pragmatismus beginnen, verbringen Sie entweder Zeit damit, eine separate Schnittstelle zu erstellen und diese in einer Konkretion zu implementieren, oder erstellen eine abstrakte Klasse oder eine beliebige Art der Abstraktion, die Sie mögen. Sollte sich dann herausstellen, dass der Kunde damit zufrieden ist und keine weitere Erweiterung erforderlich ist, haben Sie Zeit und Ressourcen vergeblich aufgewendet und / oder Overhead und Komplexität ohne Gewinn in das System eingeführt.

In Bezug auf (2) stimme ich zu, dass das Weglassen wichtiger Dinge kein Zeichen vorzeitiger Abstraktion ist. Abstraktion oder nicht, Sie können etwas Wichtiges weglassen, und wenn es nicht weit unten in einer Abstraktionskette gefunden wird, wird es nicht schwieriger oder einfacher sein, dies so oder so zu klären.

Stattdessen würde ich das so interpretieren, dass jede Abstraktion das Risiko birgt, Ihr Domain-Modell zu verschleiern. Eine falsche Abstraktion kann es sehr schwierig machen, über ein System nachzudenken, da Sie Beziehungen erstellen, die das weitere Wachstum des Domänenmodells und des Domänenverständnisses drastisch beeinflussen können. Sie laufen Gefahr, nicht wichtige Informationen über das zu abstrahierende Objekt , sondern über das gesamte System wegzulassen , indem Sie Ihr Modell in das falsche Kaninchenloch bringen.

JimJam
quelle
"Es hört sich ein bisschen so an, als ob Sie ein Problem lösen möchten, das noch nicht existiert, und dass Sie keinen guten Grund haben anzunehmen, dass es auftreten wird, es sei denn, Sie glauben nur, dass der Kunde in dem, was er anfordert, falsch liegt." - Dies ist überhaupt nicht das, was ich gesagt habe. Tatsächlich habe ich klargestellt, dass ich nur auf der Grundlage der vom Kunden verwendeten Wörter gebaut habe. Es ist der Akt, dies nicht tun zu wollen, was mich dazu veranlasste, Abstraktionen zu verwenden.
James
"Ich würde mehr Kommunikation über die Implementierung einer Schätzlösung empfehlen" - Sie meinen, wie ich vorgeschlagen habe? Um zu zitieren, was ich in OP gesagt habe: "Die Lösung hierfür besteht nicht darin, Ihre eigene Konkretion zu finden und Ressourcen zu verschwenden, wenn Sie herausfinden, dass Sie falsch geraten haben, sondern mehr Informationen vom Kunden zu erhalten."
James
"Während es harmlos erscheinen mag, einfach 'abstrakt' auf die Klassendefinition zu setzen und sich sicher zu fühlen, dass Sie sie später erweitern können" - Wenn ich "Abstraktion" sage, meine ich "Abstraktion", meine ich nicht "abstraktes Schlüsselwort". Schnittstellen könnten Abstraktionen sein, Abstraktionen sind Fuzzy-Logik, darum geht es in diesem gesamten Beitrag. Der Client kommuniziert in Bezug auf Abstraktionen, daher sollten wir abstrakt programmieren, bis wir mehr über die Domäne wissen.
James
1
"Sie werden vielleicht feststellen, dass Sie es nie brauchen" - Das macht keinen Sinn. Ein Kunde sagt "Ich möchte einen Roboter, der Gegenstände einpackt". Sie erstellen eine Abstraktion, die diese Kriterien erfüllt. Alle weiteren Informationen, die Sie vom Kunden erhalten, sind detaillierte Informationen darüber, wie das Absacken erfolgen soll. Dies macht Ihre Abstraktion nicht ungültig, der Kunde ändert nicht plötzlich seine Meinung über eine Kernidee hinter dem, was er kauft. Der Roboter wird immer noch Gegenstände einpacken. Die von Ihnen erstellte Abstraktion gilt weiterhin.
James
"Oder Sie erweitern es auf eine Weise, die das Design auf der ganzen Linie überkompliziert, indem Sie die falschen Dinge abstrahieren." ... Haben Sie ehrlich gelesen, was ich gesagt habe, oder nur den Titel? Ernsthaft? Lesen Sie Punkt (1) & (2)
James