Wie hat sich eine Zunahme der Komplexität von Systemen auf nachfolgende Generationen von Programmierern ausgewirkt?


127

Als "neuer" Programmierer (ich habe 2009 zum ersten Mal eine Codezeile geschrieben) ist mir aufgefallen, dass es relativ einfach ist, ein Programm zu erstellen, das heutzutage recht komplexe Elemente aufweist, beispielsweise mit .NET Framework. Das Erstellen einer visuellen Benutzeroberfläche oder das Sortieren einer Liste ist jetzt mit nur wenigen Befehlen möglich.

Als ich programmieren lernte, lernte ich parallel auch Computertheorie. Dinge wie Sortieralgorithmen, Prinzipien, wie Hardware zusammenarbeitet, Boolesche Algebra und Maschinen mit endlichen Zuständen. Aber wenn ich jemals ein grundlegendes Prinzip testen wollte, das ich in der Theorie gelernt hatte, war es immer schwieriger, anzufangen, da so viel Technologie durch Dinge wie Bibliotheken, Frameworks und das Betriebssystem verdeckt wird.

Die Erstellung eines speichereffizienten Programms war vor 40/50 Jahren erforderlich, da nicht genügend Speicher vorhanden und teuer war. Daher achteten die meisten Programmierer genau auf die Datentypen und den Umgang mit den Anweisungen durch den Prozessor. Heutzutage könnten einige argumentieren, dass diese Bedenken aufgrund der erhöhten Verarbeitungsleistung und des verfügbaren Speichers keine Priorität haben.

Meine Frage ist, ob ältere Programmierer Innovationen wie diese als Geschenk des Himmels oder als zusätzliche Ebene zum Abstrahieren ansehen und warum sie das vielleicht denken? Und profitieren jüngere Programmierer davon, dass sie das Programmieren auf niedrigem Niveau besser erlernen, BEVOR sie die Bereiche der umfangreichen Bibliotheken erkunden? Wenn ja, warum dann?


24
Joel Spolskys Artikel aus dem Jahr 2002 ist relevant: joelonsoftware.com/articles/LeakyAbstractions.html Wie gesagt / formuliert, könnte diese Frage jedoch in erster Linie als meinungsbasiert angesehen werden.
BrianH

Ich beklage den Mangel an einfacheren Optionen für die Erforschung grundlegender Programmiertechniken.
GroßmeisterB

1
Das ist relevant. Art von. (Ich meine, ich hoffe, dass das Bild ein Witz ist, aber mit etwas, was auf StackOverflow kommt ...)
Izkata

1
Es hat seine Vor- und Nachteile. Es öffnet die Programmierwelt für viele neue Programmierer, die keine so hohen Fähigkeiten benötigen, um erfolgreich zu sein - entgegen dem, was manche Leute sagen, ist das eine gute Sache. Und wir schreiben immer noch effiziente Programme, die sich nie geändert haben - es ist nur so, dass sich die Ziele geändert haben. Das Speichern eines Bytes für ein Jahr im Datum ist keine gute Sache mehr - der Speicherunterschied macht normalerweise kaum einen Unterschied, und die Verwendung von z. Zwei Bytes sind flexibler und zukunftssicherer. Die Kosten für Programmierer im Vergleich zu den Kosten für Software und Hardware sind ebenfalls ein wichtiger Faktor. Die Nachfrage nach neuer Software ist enorm. Codierer gibt es nur wenige.
Luaan

1
Die Zeitskala von 40/50 Jahren ist falsch. Die speichereffiziente Programmierung war in 16-Bit-Windows (vor weniger als 20 Jahren) und (leider) in den meisten Embedded- / Robotik-Anwendungen von entscheidender Bedeutung.
david.pfx

Antworten:


174

Aufgrund der höheren Rechenleistung und des höheren verfügbaren Speichers ist dies nicht erforderlich.

Billiger Speicher, enorme Festplatten und schnelle Prozessoren sind nicht das Einzige, was die Menschen von der Notwendigkeit befreit hat, jedes Byte und jeden Zyklus zu durchlaufen. Compiler sind jetzt weitaus besser als Menschen darin, hochoptimierten Code zu erstellen, wenn es darauf ankommt.

Darüber hinaus dürfen wir nicht vergessen, worauf wir tatsächlich hin optimieren möchten. Dies ist der Wert, der für bestimmte Kosten erzielt wird. Programmierer sind viel teurer als Maschinen. Alles, was wir tun, um Programmierer dazu zu bringen, funktionierende, korrekte, robuste und voll funktionsfähige Programme schneller und billiger zu produzieren, führt zur Schaffung von mehr Wert in der Welt.

Meine Frage ist jedoch, wie sich die Leute über dieses "Verstecken" von Elementen auf niedrigerer Ebene fühlen. Sehen Sie ältere Programmierer es als ein Glücksfall oder eine unnötige Ebene, um durchzukommen?

Es ist absolut notwendig, alle Arbeiten zu erledigen. Ich schreibe Code-Analysatoren für den Lebensunterhalt; Wenn ich mir Gedanken über die Zuweisung von Registern, die Prozessorplanung oder einige dieser Millionen anderer Details machen müsste, würde ich nicht meine Zeit damit verbringen, Fehler zu beheben, Leistungsberichte zu überprüfen, Funktionen hinzuzufügen und so weiter.

Bei der gesamten Programmierung geht es darum, die unter Ihnen liegende Ebene zu abstrahieren, um darauf eine wertvollere Ebene zu erstellen. Wenn Sie ein "Layer-Cake-Diagramm" erstellen, in dem alle Subsysteme und deren Aufbau dargestellt werden, gibt es buchstäblich Dutzende von Layern zwischen der Hardware und dem Benutzererlebnis. Ich denke, im Windows-Layer-Cake-Diagramm gibt es etwa 60 Ebenen der erforderlichen Subsysteme zwischen der Rohhardware und der Fähigkeit, "Hallo Welt" in C # auszuführen.

Glauben Sie, dass jüngere Programmierer mehr davon profitieren würden, wenn sie Programmieren auf niedrigem Niveau lernen, BEVOR sie die Bereiche der expansiven Bibliotheken erkunden?

Sie legen Wert auf VORHER, daher muss ich Ihre Frage verneinen. Ich helfe einem 12-jährigen Freund, gerade das Programmieren zu erlernen, und Sie sollten besser glauben, dass ich sie in Processing.js und nicht in x86-Assembler starte. Wenn Sie einen jungen Programmierer in etwas anfangen, werden Processing.jssie in ungefähr acht Stunden ihre eigenen Shoot-Em-Up-Spiele schreiben. Wenn Sie sie in Assembler starten, multiplizieren sie in etwa acht Stunden drei Zahlen. Welches ist Ihrer Meinung nach das Interesse eines jüngeren Programmierers?

Wenn nun die Frage lautet: "Profitieren Programmierer, die die Schicht n des Kuchens verstehen, vom Verständnis der Schicht n - 1?" Die Antwort lautet ja, aber das ist unabhängig von Alter oder Erfahrung. Es ist immer so, dass Sie Ihre übergeordnete Programmierung verbessern können, indem Sie die zugrunde liegenden Abstraktionen besser verstehen.


12
+1 lustiges Zitat: Dunbars Number ist ein gutes Beispiel (es gibt andere) für untersuchte kognitive Kapazitätsquotienten, die bei vielen Menschen zu sehen sind und zeigen, dass wir einen festen mentalen Raum haben. Die Zusammenfassung mehrerer Dinge zu singulären Verallgemeinerungen ist die einzige Möglichkeit, die Anzahl der Dinge in unserem mentalen Raum kohärent zu erhöhen, und das ist es, was die Programmierung auf höherer Ebene ausnutzen möchte.
Jimmy Hoffa

18
@Euphoric: Deine Frage macht Sinn aber wo hörst du auf? Angenommen, ich sage "Nun, anstatt Processing.js zu lernen, lernen wir, wie man Videospiele in C ++ mit DirectX schreibt". OK, gut. Was hält Sie davon ab zu sagen, dass "es keine Probleme schafft, wenn sie etwas weniger Abstraktes tun wollen?" und vielleicht wollen wir mit dem Schreiben eines Grafikkartentreibers beginnen. Aber dann stellen Sie die Frage noch einmal und bevor Sie es wissen, geben wir den Maschinencode in einen Altair mit Kippschaltern ein. Sie müssen sich irgendwo eine Abstraktionsebene aussuchen !
Eric Lippert

35
@Euphoric: Würden Sie dasselbe Argument zum Beispiel für die Buchhaltung vorbringen? Wir brauchen nicht mehr Leute, die die einfachen Bücher für ein neues kleines Unternehmen führen können. Wir brauchen großartige, erstklassige Buchhalter. Wenn Einführungskurse in das Rechnungswesen so schwierig sind, dass sie Leute abschrecken, die nur danach streben, produktiv zu sein, fachmännische Buchhalter, GUT. Wir brauchen diese Leute in der Buchhaltungsbranche nicht! Wie wäre es mit Pianisten? Wenn einführende Klavierstunden Leute abschrecken, die keine GROSSEN Pianisten sein werden, ist das gut; Wir wollen nur großartige Pianisten auf der Welt. Stimmt etwas mit diesem Argument nicht?
Eric Lippert

25
@Euphoric: Die kurze Antwort lautet GOOD HEAVENS YES wir brauchen mehr anständige Programmierer! Wir brauchen mehr Programmierer auf jeder Ebene der Fähigkeiten und Erfahrungen. Die Welt läuft mit Software . Je mehr Menschen , die haben alle Verständnis davon , wie in ihre Welt der Arbeit, die besser zu machen.
Eric Lippert

6
@Euphoric (und andere) - wir stoßen in Bezug auf die Konstruktivität von Kommentaren an die Grenzen. Bitte besuchen Sie uns im Software Engineering Chat, wenn Sie dieses Gespräch fortsetzen möchten.

50

Ich hatte Ideen zu diesem Thema und habe sie vor 20 Jahren in ein Buch geschrieben . Es ist schon lange vergriffen, aber Sie können immer noch gebrauchte Exemplare bei Amazon kaufen .

Eine einfache Antwort auf Ihre Frage ist so alt wie Aristoteles: Die Natur verabscheut ein Vakuum . So viel wie Maschinen schneller und größer geworden sind, ist Software langsamer und größer geworden.

Um konstruktiver zu sein, schlug ich vor, dass die Informationstheorie und ihre direkte Relevanz für Software Teil des Informatikunterrichts sind. Es wird erst jetzt, wenn überhaupt, auf sehr tangentiale Weise gelehrt.

Zum Beispiel kann das Big-O-Verhalten von Algorithmen sehr gut und intuitiv verstanden werden, wenn Sie sich ein Programm als einen Informationskanal vom Shannon-Typ mit Eingabesymbolen, Ausgabesymbolen, Rauschen, Redundanz und Bandbreite vorstellen.

Andererseits kann die Produktivität eines Programmierers unter Verwendung der Kolmogorov-Informationstheorie auf ähnliche Weise verstanden werden. Die Eingabe ist eine symbolische konzeptionelle Struktur in Ihrem Kopf, und die Ausgabe ist der Programmtext, der mit den Fingerspitzen ausgegeben wird. Der Programmiervorgang ist der Kanal zwischen den beiden. Wenn Rauschen in den Prozess eintritt, entstehen inkonsistente Programme (Bugs). Wenn der ausgegebene Programmtext ausreichend redundant ist, können die Fehler abgefangen und korrigiert werden (Fehlererkennung und -korrektur). Wenn es jedoch zu redundant ist, ist es zu groß, und seine Größe in Kombination mit der Fehlerrate führt zur Einführung von Fehlern. Aufgrund dieser Überlegungen habe ich einen Großteil des Buches damit verbracht, zu zeigen, wie man Programmierung als einen Prozess des Sprachdesigns behandelt, mit dem Ziel, die für einen Bedarf geeigneten domänenspezifischen Sprachen definieren zu können. Domain-spezifische Sprachen in der CS-Ausbildung sprechen wir zwar als Lippenbekenntnis aus, aber auch dies ist tangential.

Sprachen bauen ist einfach. Jedes Mal, wenn Sie eine Funktion, Klasse oder Variable definieren, fügen Sie der Sprache, mit der Sie begonnen haben, Vokabeln hinzu und erstellen eine neue Sprache, mit der Sie arbeiten können. Was nicht allgemein anerkannt wird, ist, dass das Ziel darin bestehen sollte, die neue Sprache näher an die konzeptionelle Struktur des Problems heranzuführen. In diesem Fall wird der Code gekürzt und weniger fehleranfällig, da idealerweise eine 1: 1-Zuordnung zwischen Konzepten und Code besteht. Wenn die Zuordnung 1: 1 ist, machen Sie möglicherweise einen Fehler und codieren ein Konzept falsch als ein anderes Konzept. Das Programm stürzt jedoch niemals ab. Dies ist der Fall, wenn keine konsistente Anforderung codiert wird .

Wir bekommen das nicht. Bei aller Tapferkeit in Bezug auf das Design von Softwaresystemen wird das Verhältnis von Code zu Anforderungen immer größer, viel größer.

Es ist wahr, wir haben sehr nützliche Bibliotheken. Ich denke jedoch, wir sollten bei der Abstraktion sehr umsichtig sein. Wir sollten nicht annehmen, wenn B auf A aufbaut und das ist gut so, dass wenn C auf B aufbaut, es noch besser ist. Ich nenne es das Phänomen "Prinzessin und Erbse". Das Anhäufen von Schichten über etwas Schwieriges behebt es nicht unbedingt.

Um einen langen Beitrag zu beenden, habe ich einen Programmierstil entwickelt (der mich manchmal in Schwierigkeiten bringt)

  • Erfindung ist keine schlechte Sache. Es ist eine gute Sache, wie es auch in anderen Bereichen der Technik der Fall ist. Sicher, es kann eine Lernkurve für andere schaffen, aber wenn das Gesamtergebnis eine bessere Produktivität ist, lohnt es sich.
  • Minimalistischer Code im Haiku-Stil. Das gilt insbesondere für das Datenstrukturdesign. Meiner Erfahrung nach ist das größte Problem bei Software heutzutage die aufgeblähte Datenstruktur.

9
Das klingt sehr nach dem, was Chuck Moore (Erfinder von Forth ) immer befürwortet hat. Zum Beispiel aus Chuck Moores Kommentaren zu Forth : "Ich glaube nicht, dass es in der Natur von Software liegt, dass sie groß, sperrig und fehlerhaft sein muss. Es liegt in der Natur unserer Gesellschaft. ... Es gibt so viel wirtschaftliche Motivation für die Herstellung dieses ... Bloatware, dass ich mich irgendwie unverantwortlich fühle, wenn ich aufstehe und sage, der Kaiser habe keine Kleider. "
Peter Mortensen

3
@PeterMortensen: Einverstanden. Es ist einsam. Dafür gibt es ein Wort - Cassandra-Komplex .
Mike Dunlavey

2
Während das Schreiben von Code-Artefakten zum "Erweitern" von Sprachen kein schwieriges Unterfangen ist, sollte eine gute API erstellt werden, die die Problemdomäne genau und intuitiv widerspiegelt .
Robert Harvey

3
@MikeDunlavey: Übrigens: Du bist auch der "No-Profiler" (das ist positiv gemeint). Vor einigen Monaten habe ich Ihre Technik erneut in der Praxis eingesetzt, um die Ladezeit einer Dokumentdatei schnell von normalerweise 25 Sekunden auf 1 Sekunde zu reduzieren (eine Ladezeit, die der Benutzer direkt erlebt). Es dauerte ein paar Iterationen, und 10-20 Samples in allen Iterationen waren mehr als ausreichend. Die Leistungsprobleme waren natürlich an unerwarteten Stellen.
Peter Mortensen

2
@Izkata und Peter: Ja, ich bin so komisch. FWIW, ich habe ein paar (extrem amateurhafte) Videos zusammengestellt, um das Verständnis zu erleichtern. Zufällige Pause. Differenzielle Ausführung. Prost.
Mike Dunlavey

35

Eine Abstraktion auf hoher Ebene ist unerlässlich, um fortlaufende Fortschritte im Bereich der Datenverarbeitung zu erzielen.

Warum? Weil der Mensch zu jedem Zeitpunkt nur so viel Wissen im Kopf haben kann. Moderne Großsysteme sind heute nur möglich, weil Sie solche Abstraktionen nutzen können. Ohne diese Abstraktionen würden Softwaresysteme einfach unter ihrem eigenen Gewicht zusammenbrechen.

Jedes Mal, wenn Sie eine Methode schreiben, erstellen Sie eine Abstraktion. Sie erstellen eine Funktionalität, die sich hinter einem Methodenaufruf verbirgt. Warum schreibst du sie? Sie können die Methode testen, beweisen, dass sie funktioniert, und diese Funktionalität dann jederzeit aufrufen, indem Sie einfach den Methodenaufruf ausführen, und müssen nicht mehr über den Code nachdenken, der in dieser Methode enthalten ist.

In den Anfängen des Computings verwendeten wir Maschinensprache. Wir haben sehr kleine Bare-Metal-Programme geschrieben, die sich mit der Hardware auskennen, für die wir sie geschrieben haben. Es war ein sorgfältiger Prozess. Es gab keine Debugger; Ihr Programm hat normalerweise entweder funktioniert oder es ist abgestürzt. Es gab keine GUI; Alles war entweder ein Kommandozeilen- oder ein Batch-Prozess. Der von Ihnen geschriebene Code funktioniert nur auf diesem bestimmten Computer. Auf einem Computer mit einem anderen Prozessor oder Betriebssystem würde dies nicht funktionieren.

Also haben wir Hochsprachen geschrieben, um all diese Details zu abstrahieren. Wir haben virtuelle Maschinen erstellt, damit unsere Programme auf andere Maschinen portierbar sind. Wir haben eine Garbage Collection erstellt, damit Programmierer nicht so fleißig mit dem Speicher umgehen müssen, wodurch eine ganze Reihe schwieriger Fehler beseitigt wurden. Wir haben unseren Sprachen die Überprüfung von Grenzen hinzugefügt, damit Hacker sie nicht mit Pufferüberläufen ausnutzen können. Wir haben die Funktionale Programmierung erfunden, um unsere Programme auf eine andere Weise zu bewerten, und sie kürzlich neu entdeckt, um die Vorteile der Parallelität besser nutzen zu können.

Isoliert Sie all diese Abstraktion von der Hardware? Sicher tut es das. Isoliert Sie das Leben in einem Haus, anstatt ein Zelt aufzubauen, von der Natur? Absolut. Aber jeder weiß, warum er in einem Haus statt in einem Zelt lebt, und ein Haus zu bauen ist ein völlig anderes Ballspiel als ein Zelt aufzubauen.

Sie können jedoch trotzdem ein Zelt aufschlagen, wenn dies erforderlich ist, und beim Programmieren können Sie (wenn Sie dazu geneigt sind) noch näher an der Hardware herabfallen, um Leistung oder Speichervorteile zu erzielen, die Sie möglicherweise nicht haben sonst erreichen Sie in Ihrer Hochsprache.


Kannst du zu viel abstrahieren? "Überholen Sie die Klempnerarbeit", wie Scotty sagen würde? Natürlich kannst du. Gute APIs zu schreiben ist schwierig. Noch schwieriger ist es, gute APIs zu schreiben, die die Problemdomäne korrekt und umfassend auf intuitive und erkennbare Weise abbilden. Das Anhäufen neuer Softwareschichten ist nicht immer die beste Lösung. Software Design Patterns haben diese Situation bis zu einem gewissen Grad verschlimmert, da unerfahrene Entwickler manchmal zu ihnen greifen, wenn ein schärferes und schlankeres Tool besser geeignet ist.


1
+1, obwohl ich denke, dass Sie die Geschichte der funktionalen Programmierung rückwärts verstanden haben (die Lambda-Rechnung geht auf elektronische Computer zurück, und viele funktionale Sprachen gehen auf die gleichzeitige Programmierung zurück).
amon

1
Ich habe eine kleine Klarstellung hinzugefügt.
Robert Harvey

2
"In den Anfängen des Computerbetriebs haben wir Maschinensprache verwendet. Wir haben sehr kleine Bare-Metal-Programme geschrieben, die sich mit der Hardware auskennen, für die wir sie geschrieben haben." Einige von uns in der Embedded-Programmierung tun dies gelegentlich immer noch auf 8-But-Mikrocontrollern, die weniger als 1 KB Programmspeicher, 64 Byte RAM und rund ein Viertel der Kosten haben. Kein C-Compiler da. (Normalerweise arbeite ich jedoch mit 32-Bit-Mikrocontrollern mit normalerweise 1/2 MB Programmspeicherplatz.)
tcrosley

9

Wirklich gutes Training beinhaltet beide Extreme sowie eine Brücke zwischen ihnen.

Auf der unteren Ebene: Wie ein Computer Code von Grund auf ausführt *, einschließlich Kenntnissen der Assemblersprache und was ein Compiler tut.

Auf der höheren Ebene: allgemeine Konzepte, z. B. die Verwendung von assoziativen Arrays, Verschlüssen usw., ohne Zeit damit zu verschwenden, sich Gedanken darüber zu machen, wie es unter der Haube funktioniert.

IMHO sollte jeder Erfahrung mit beiden haben, einschließlich ihrer Nachteile, und einen Vorgeschmack darauf haben, wie man von Konzepten auf niedriger Ebene zu Konzepten auf hoher Ebene gelangt. Liebst du assoziative Arrays? Großartig, versuchen Sie es jetzt mit einem 50-Cent-Embedded-Prozessor mit 1 KB RAM. Wie schnell Code mit C schreiben? Gut, jetzt haben Sie drei Wochen Zeit, um eine Web-App zu schreiben. Sie können Ihre Zeit damit verbringen, sich mit Datenstrukturen und Speicherverwaltung mit C zu beschäftigen, oder Sie können Ihre Zeit damit verbringen, ein neues Webframework zu erlernen und die Web-App in wenigen Tagen zu implementieren.

Was die Komplexität betrifft: Ich denke, es ist heutzutage zu einfach, komplexe Systeme ohne ein klares Verständnis der Kosten dafür zu erstellen . Infolgedessen haben wir als Gesellschaft eine enorme technische Verschuldung aufgebaut , die uns von Zeit zu Zeit beißt. Es ist wie bei Erdbeben (nur die Lebenshaltungskosten in der Nähe eines geologischen Defekts, oder?), Nur wird es allmählich schlimmer. Und ich weiß nicht, was ich dagegen tun soll. Im Idealfall würden wir lernen und die Komplexität verbessern, aber ich denke nicht, dass dies passieren wird. Eine verantwortungsbewusste Ingenieurausbildung muss viel mehr Diskussionen über die Folgen von Komplexität beinhalten, als die meisten unserer Universitäten derzeit anbieten.


* und überhaupt, wo ist der "Grund" dafür, wie ein Computer Code ausführt? Ist es Assemblersprache? Oder Computerarchitektur? Oder digitale Logik? Oder Transistoren? Oder Gerätephysik?


7

Ich bin der Meinung, dass High-Level-Programmierung viele Vorteile hat und ein wesentlicher Bestandteil einer Programmiersprache ist. Einer der Gründe für den Erfolg von Java war, dass es über eine umfassende Bibliothek verfügt. Mit weniger Code erreichen Sie mehr - rufen Sie einfach eine vordefinierte Funktion auf.

Wir können nun Programmiersprachenbenutzer von Programmiersprachenautoren (Compilerautoren) unterscheiden. Die Optimierungen überlassen wir den Compilern. Wir konzentrieren uns mehr auf Wartbarkeit, Wiederverwendung usw


7

Die zunehmende Komplexität von Systemen ist unerbittlich, bedrückend und letztendlich lähmend. Für mich als Programmierer älterer Generationen ist es auch bitter enttäuschend.

Ich programmiere seit mehr als 40 Jahren, habe Code in 50-100 verschiedenen Sprachen oder Dialekten geschrieben und bin Experte in 5-10. Der Grund, warum ich so viele behaupten kann, ist, dass es sich meistens nur um dieselbe Sprache handelt, mit Verbesserungen. Die Anpassungen erhöhen die Komplexität und machen jede Sprache ein wenig anders.

Ich habe die gleichen Algorithmen unzählige Male implementiert: Sammlungen, Konvertierungen, Sortieren und Suchen, Codieren / Decodieren, Formatieren / Parsen, Puffer und Zeichenfolgen, Arithmetik, Speicher, E / A. Jede neue Implementierung erhöht die Komplexität, da jede einzelne nur ein bisschen anders ist.

Ich wundere mich über die Magie der hochfliegenden Trapezkünstler der Web-Frameworks und mobilen Apps, wie sie in so kurzer Zeit etwas so Schönes produzieren können. Dann wird mir klar, wie viel sie nicht wissen, wie viel sie über Daten oder Kommunikation, Tests oder Threads oder was auch immer lernen müssen, bevor das, was sie tun, nützlich wird.

Ich habe mein Handwerk in der Ära der Sprachen der vierten Generation gelernt, in der wir aufrichtig davon ausgegangen sind, dass wir eine Abfolge von Sprachen höherer und höherer Ebenen produzieren werden, um immer mehr sich wiederholende Teile von Schreibsoftware nach und nach zu erfassen. Wie ist das genau ausgegangen?

Microsoft und IBM beendeten diese Idee, indem sie zu C zurückkehrten, um Apps für Windows und OS / 2 zu schreiben, während dBase / Foxpro und sogar Delphi nachließen. Dann hat es das Web mit seinem ultimativen Trio von Assemblersprachen wieder geschafft: HTML, CSS und JavaScript / DOM. Es war alles bergab von dort. Immer mehr Sprachen und mehr Bibliotheken und mehr Frameworks und mehr Komplexität.

Wir wissen, dass wir es anders machen sollten. Wir kennen uns mit CoffeeScript und Dart aus, mit Less und Sass, mit Templates, um nicht HTML schreiben zu müssen. Wir wissen es und machen es trotzdem. Wir haben unsere Rahmenbedingungen voller undichter Abstraktionen und wir sehen, welche Wunder die wenigen Auserwählten vollbringen können, die die arkanen Zaubersprüche lernen, aber wir und unsere Programme sind von den in der Vergangenheit getroffenen Entscheidungen gefangen. Es ist zu kompliziert, um es zu ändern oder von vorne zu beginnen.

Das Ergebnis ist, dass Dinge, die einfach sein sollten, nicht einfach sind und Dinge, die möglich sein sollten, aufgrund der Komplexität nahezu unmöglich sind. Ich kann die Kosten für Änderungen abschätzen, um eine neue Funktion in einer etablierten Codebasis zu implementieren, und bin zuversichtlich, dass ich in etwa richtig liegen werde. Ich kann schätzen, aber ich kann es nicht rechtfertigen oder erklären. Es ist zu kompliziert.

Zur Beantwortung Ihrer letzten Frage empfehle ich jüngeren Programmierern nachdrücklich, so weit wie möglich mit dem Layer Cake zu beginnen und nur in die unteren Schichten abzutauchen, wenn Bedarf und Wunsch den Anstoß dazu geben. Ich bevorzuge Sprachen ohne Schleifen, ohne Verzweigung und ohne expliziten Status. Lisp und Haskell kommen mir in den Sinn. In der Praxis beende ich mich immer mit C # / Java, Ruby, Javascript, Python und SQL, da sich dort die Communities befinden.

Letzte Worte: Komplexität ist der ultimative Feind! Schlagen Sie das und das Leben wird einfach.


Meine über 30-jährige Erfahrung in der Programmierung hat mich gelehrt, die höchste verfügbare Programmiersprache zu verwenden, die das Notwendige leistet und die bei Bedarf auch die Verwendung niedrigerer Programmiersprachen zulässt. Die einfachste Umgebung dafür ist Shell-Scripting, mit dem Module aufgerufen werden können, die in einer beliebigen Sprache geschrieben sind. Der schwierige Teil ist, die vorherrschende Einstellung zu brechen, dass alle Funktionen eines Projekts in derselben Sprache implementiert werden müssen.
DocSalvager

@dicsalvage: Ich stimme zu und meine große Enttäuschung ist das Fehlen immer höherer Level. Was awk in den 1980er Jahren in 10 Zeilen tun konnte, ist jetzt in Ruby oder Python in 15 Zeilen, aber ich suche nach einer Möglichkeit, dies in 3 zu tun Shell-Skripte gibt!
david.pfx

Google "bash for android" zeigt eine Menge Leute, die an Ports arbeiten. Es gibt auch Versionen von Python wie Kivy
DocSalvager

@DocSalvage: Früher oder später wird die Telefonumgebung der Zivilisation beitreten (wie wir es kennen). Meine Beschwerde ist die Zeit, die benötigt wird, um die Dinge, die fertig zu sein scheinen, immer wieder zu tun. Wenn ich Wolkenkratzer bauen will, müssen wir immer wieder Fundamente, Mauerwerk, Entwässerungssysteme und Hütten legen.
david.pfx

4

Meine Frage ist jedoch, wie sich die Leute über dieses "Verstecken" von Elementen auf niedrigerer Ebene fühlen. Sehen Sie ältere Programmierer es als ein Glücksfall oder eine unnötige Ebene, um durchzukommen?

Wirklich auch nicht.

Eine Schichtung ist erforderlich, da Sie ohne sie einen Punkt erreichen, an dem Ihr System zu nicht mehr zu wartenden Spaghetti wird. Dies ist auch einer der Grundsätze der Wiederverwendbarkeit: Wenn der Entwickler einer Bibliothek gute Arbeit geleistet hat, sollten sich die Benutzer nicht um die Details der Implementierung kümmern müssen. Die Menge an Dosencode, die wir in unseren Systemen verwenden, ist um ein Vielfaches größer geworden, als ich vor 35 Jahren mein erstes Programm geschrieben habe. Dieses Wachstum bedeutet, dass wir im Laufe der Zeit leistungsfähigere Dinge tun können. Das ist gut.

Der Ort, an dem es für mich ein Problem war, ist rein kulturell. Meiner pragmatischen Hälfte ist klar, dass es nicht mehr möglich ist, mich um jedes Detail zu kümmern und die Dinge zu erledigen, die ich erledigen möchte. (Älter werden hilft auch nicht.) Meine freche graubärtige Hälfte hatte es schwer, viele Jahre loszulassen, um ein so feinkörniges Verständnis für alles zu haben, woran ich gearbeitet habe.

Glauben Sie, dass jüngere Programmierer mehr davon profitieren würden, wenn sie Programmieren auf niedrigem Niveau lernen, BEVOR sie die Bereiche der expansiven Bibliotheken erkunden?

Wie bereits in anderen Antworten erwähnt, besteht ein Gleichgewicht zwischen der Gewinnung und Aufrechterhaltung der Aufmerksamkeit von Neophyten und ihrer idealen Grundbildung. Wenn Sie das erstere nicht können, kann das letztere nicht passieren.

Ich sehe Dinge in unserer Branche, die mit dem Rest der Gesellschaft vergleichbar sind. Früher bauten fast alle ihr eigenes Essen an und verbrachten viel Zeit damit. Seitdem haben wir Spezialisten hervorgebracht, die Bauern genannt werden, die diese Arbeit erledigen und andere für andere Dinge freigeben, die zur Gesellschaft beitragen. Ich kaufe mein Essen in einem Lebensmittelgeschäft und könnte das meiste nicht selbst herstellen, wenn ich müsste. Wir haben etwas Ähnliches vor uns, wenn auch auf einer viel komprimierteren Zeitskala. Programmierer spezialisieren sich auf einige Ebenen und nicht auf andere. Der Durchschnittsbürger, der GUIs schreibt, weiß vielleicht, dass es so etwas wie Swap Space gibt, weiß aber wahrscheinlich nicht viel darüber, wie das Betriebssystem es verwaltet oder kümmert.

Das Ergebnis ist, dass es nicht mehr nur um Entwicklung geht. Fortgesetzte Spezialisierung bedeutet, dass Entwickler ihre Kommunikations- und Integrationsfähigkeiten weiter verbessern müssen.


3

Wie bei allem tut ein bisschen gut, aber zu viel tut weh. Das Problem ist, dass zu viele Systeme nicht wissen, wann sie anhalten sollen - nur eine weitere Abstraktion, um schneller programmieren zu können ... aber am Ende codieren Sie in der realen Welt, in der die Dinge nie so einfach sind, wie Sie möchten und Sie Verbringen Sie mehr Zeit damit, an den Rändern zu arbeiten, als Sie es mit einer weniger ausgeprägten Abstraktion getan hätten.

Es ist hier geschickt beschrieben

oder hier - "mit einer einzigen Codezeile könnten Sie der Domain 500 Benutzer hinzufügen" ...

Ihre Abstraktionen versuchen, die Komplexität vor Ihnen zu verbergen, aber wirklich alles, was sie tun, ist, diese Komplexität zu verbergen. Die Komplexität ist immer noch da, es ist nur so, dass Sie viel weniger Kontrolle darüber haben - und das ist der Grund, warum Sie in eine solche Situation geraten.


2

Profitieren jüngere Programmierer davon, dass sie das Programmieren auf niedrigem Niveau besser erlernen, bevor sie die Bereiche der umfangreichen Bibliotheken erkunden? Wenn ja, warum dann?

Ich glaube nicht. Es gibt immer noch viele Situationen, in denen es von Vorteil ist, sich bewusst zu sein, dass die untere Ebene funktioniert, z

  • Wenn Sie ein Problem auf einer Ebene debuggen n, kann dies häufig durch die Berücksichtigung der Ereignisse auf der Ebene n-1(dh der Ebene darunter) erklärt werden. Ich denke, Schicht 0 wäre "Transistoren", aber wenn Sie ein Problem mit Transistoren erklären möchten, würden Sie wahrscheinlich über Physik (z. B. Wärme) sprechen, also ist Physik möglicherweise wirklich Stufe 0.

  • Bei der Optimierung von Code hilft es (leider) manchmal, die Abstraktionsebene zu senken, dh einen Algorithmus im Sinne einer untergeordneten Ebene zu implementieren. Die Compiler konnten dies jedoch sehr gut für Sie tun, wenn sie tatsächlich den gesamten Code sehen. Dieser Grund wurde in letzter Zeit mit dem Boom mobiler und eingebetteter Geräte populärer, die tendenziell schwächere Prozessoren haben und bei denen die "Leistung pro Watt" viel relevanter ist als beispielsweise bei Desktop-Systemen.

Im Allgemeinen wurde es jedoch viel einfacher, Computer dazu zu bringen, Dinge zu erledigen (auch wenn dies auf etwas ineffiziente Weise geschieht), was bedeutet, dass es viel mehr Programmierer gibt als früher. Dies wiederum machte den Faktor "Mensch" umso wichtiger: In der Antwort von Robert Harvey wurde bereits erwähnt, dass "Menschen zu einem bestimmten Zeitpunkt nur so viel Wissen im Kopf haben können", und ich denke, dass dies heutzutage ein sehr relevanter Aspekt ist.

Eine Hauptmotivation beim Design von Programmiersprachen und Bibliotheken (APIs) ist es, das menschliche Gehirn zu entlasten. Bis heute wird alles auf Maschinencode kompiliert. Dies ist jedoch nicht nur fehleranfällig, sondern auch notorisch schwer zu verstehen. Also ist es sehr wünschenswert zu

  • Lassen Sie sich von Ihrem Computer helfen, logische Fehler in den von Ihnen geschriebenen Programmen zu finden. Dinge wie statische Typsysteme oder Quellcode-Analysatoren (ich höre, dass Eric Lippert heutzutage an einem ziemlich populären arbeitet) helfen dabei.

  • Eine Sprache haben, die von einem Compiler effizient verarbeitet werden kann und die anderen Programmierern die Absicht des Programmierers mitteilt , die Arbeit am Programm zu erleichtern. Stellen Sie sich als absurdes Extrem vor, es wäre möglich, Programme in einfachem Englisch zu schreiben. Mitprogrammierer könnten sich leichter vorstellen, was vor sich geht, aber es wäre sehr schwierig, die Beschreibung in Maschinenlehrer zu übersetzen, und sie ist notorisch mehrdeutig. Sie benötigen also eine Sprache, die ein Compiler verstehen kann, die aber auch verständlich ist.

Angesichts der Tatsache, dass viele (die meisten?) Compiler noch sehr universell einsetzbar sind, verfügen sie über einen sehr allgemeinen Befehlssatz. Es gibt keine Anweisung zum Zeichnen einer Schaltfläche oder zum Abspielen dieses Films. Wenn Sie sich also in der Abstraktionshierarchie bewegen, werden Sie mit Programmen konfrontiert, die nur schwer zu verstehen und zu warten sind (obwohl sie sich nur trivial kompilieren lassen). Die einzige Alternative besteht darin, die Hierarchie nach oben zu schieben, was zu immer abstrakteren Sprachen und Bibliotheken führt.



1

"Wenn ältere Programmierer Innovationen wie diese als ein Geschenk des Himmels oder eine zusätzliche Ebene zum Abstrahieren betrachten, warum denken sie das dann?"

Ich habe programmiert, seit ich in der Highschool war, ungefähr 34 Jahre, angefangen mit Basic und Z80 Assembler, und bin zu C übergegangen, verschiedenen 4GL-Sprachen, Schema, SQL und jetzt verschiedenen Web-Sprachen. Umfang, Ausmaß und Tiefe der Probleme, mit denen sich der Beruf befasste, erlebten in dieser Zeit, insbesondere in den neunziger Jahren, eine Inflationsperiode. Konstrukte wie Bibliotheken, Frameworks und Betriebssystemdienste sind alles Geräte, die der Komplexität des erweiterten Raums von Problemen gerecht werden sollen. Sie sind weder ein Geschenk Gottes noch eine Last für sich selbst - nur eine fortgesetzte Erforschung eines riesigen Lösungsraums.

Aber, meiner Meinung nach, "Innovation" wird in Bezug auf neuartige Formen besser verstanden und nicht mit Seitwärtsbewegung verwechselt - Wiedereinführung von Formen, die wir bereits eingeführt haben. In gewisser Weise leidet die Fruchtbarkeit eines Ökosystems, wenn sich die primitiven Formen nicht zusammensetzen, wenn sie Entscheidungen fixieren, die zu Beginn der Evolution getroffen wurden, oder wenn sie ihren eigenen Abfall nicht erneut verarbeiten können. Einige, wenn nicht die meisten Konstrukte, auf die wir uns weiterhin konzentrieren, priorisieren die langfristige Werterhaltung nicht als Anliegen. Das hat sich geändert - Ansätze wie Service Orientation und Domain Driven Design, aber auch Hypertext- und Graph-basierte Modelle verändern die Landschaft. Wie jedes Ökosystem werden die vorherrschenden Formen irgendwann neuen Formen weichen. Wir werden am besten bedient, indem wir Vielfalt zulassen,

"Und profitieren jüngere Programmierer davon, dass sie das Programmieren auf niedriger Ebene besser erlernen, bevor sie die Bereiche der umfangreichen Bibliotheken erkunden? Wenn ja, warum?"

Ich würde argumentieren, dass die meisten menschlichen Sprachen auf Metaphern basieren, die längst vergessen wurden. Während ich das Erlernen von Low-Level-Programmen vom Standpunkt der wissenschaftlichen / numerischen Alphabetisierung aus unterstützen würde, ist es wichtiger, dass wir nach Grundelementen suchen, die das Ausmaß und den Umfang von unterstützen die Probleme, die wir so angehen, dass wir den niedrigeren Detaillierungsgrad ignorieren können. Ein Framework ist weder ein Primitiv noch ein Betriebssystem oder eine Bibliothek - sie sind ziemlich schlecht darin, die Art von Abstraktion auszuführen, die wir wirklich brauchen. Wirklicher Fortschritt erfordert Menschen, die (a) wissen, was vorher war, und (b) neu genug denken können, um etwas Anderes zu finden, um einen Lösungsraum zu erkunden, der zuvor noch nicht erforscht wurde oder der erforscht und vergessen wurde.

OTOH, auch wenn es Ihr Ziel ist, als Techniker / Mechaniker zu arbeiten, wird ein gewisses Maß an Programmierkenntnissen auf niedriger Ebene weiterhin hilfreich sein, um Ihre Fähigkeiten zur Problemlösung zu entwickeln.


1

Mein erstes Programm (als 15-jähriger Teenager) war 1974 in PL / 1 auf Lochkarten für einen IBM 370 / 168-Mainframe. Mein Vater arbeitete bei IBM und ich hatte das Glück, sonntags ins Rechenzentrum gehen zu können.

Zu dieser Zeit war ein Programm mit mehreren tausend Aussagen (dh gelochte Karten) ein großes Programm (und ein schweres auch, da viele tausend gelochte Karten viele Kilogramm wogen). Es gab keine visuellen Schnittstellen (ein typisches Programm, das mit einem Lochkartenbefehl, der mit //GO.SYSIN DD *IIRC beginnt, von seiner "Standardeingabe" gelesen wurde, aber ich beherrschte JCL nicht ). Algorithmik war wichtig, und IIRC, die Standardbibliothek, war nach heutigem Standard recht klein.

Heutzutage werden Programme mit mehreren tausend Zeilen im Allgemeinen als klein angesehen. Der GCC- Compiler verfügt beispielsweise über mehr als zehn Millionen Quellcodezeilen, und niemand versteht sie vollständig.

Meines Erachtens unterscheidet sich die Programmierung heute erheblich von den 1970er Jahren, da Sie viel mehr Ressourcen benötigen (insbesondere vorhandene Bibliotheken und Software-Frameworks). Ich vermute jedoch, dass die Entwickler von Rechenzentrums-Software (z. B. Suchmaschinen bei Google) oder einer eingebetteten Software mehr Wert auf Algorithmen und Effizienz legen als der durchschnittliche Programmierer der 1970er Jahre.

Ich denke immer noch, dass das Verstehen von Low-Level-Programmierung auch heute noch wichtig ist (auch wenn sich die meisten Programmierer nicht selbst grundlegende Container-Algorithmen wie ausgeglichene Bäume, dichotomisch aufgerufene sortierte Arrays usw. codieren), da es immer noch wichtig ist, das Gesamtbild zu verstehen.

Ein Hauptunterschied zwischen den 1970ern und heute ist das Verhältnis der Kosten zwischen den (menschlichen) Anstrengungen des Entwicklers und der Computerleistung.

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.