Warum der Einstieg ins Programmieren nicht einfach sein muss
Sowohl Studenten als auch Lehrende der Informatik kennen die Frage, ob der Einstieg in die Programmierung lieber mit einer systemnahen Sprache wie C oder einer höher angesiedelten Sprache wie Java erfolgen sollte. Während die einen für Java plädieren, weil es aufgrund der Vielzahl an Bibliotheken, dem umfangreichen Ökosystem und weiteren Faktoren schnell produktiv einsetzbar ist, verfechten andere wiederum den „schwierigeren“ Einstieg mit Sprachen wie C oder Pascal.
Der Trend entwickelt sich immer in Richtung der abstrakteren Systemkonzepte, bei denen viel „Magie“ im Hintergrund passiert und die immer weniger Verständnis für die Funktionsweise eines Computers – den man ja nun mal programmieren will, das zu tun, was man möchte – erfordern. Das ist soweit auch nicht schlimm, weil man im Berufsleben oft weniger mit dem Innenleben eines Rechners zu tun hat. Warum nun aber an der Hochschule oder Universität einen Unterschied machen? Man benötigt das Wissen ja eh nie wieder. Richtig? Falsch.
Imperativ, prozedural und objektorientiert
Zunächst schadet es nicht, einmal kurz den Unterschied in der Entwicklung mit C und Java erläutern. C verfolgt den Ansatz der imperativen und prozeduralen Programmierung. Dabei werden eine Reihe von Anweisungen in kleinere Programmteile zusammengefasst, die die zu behandelnden Teilprobleme darstellen. Die Übergabe von Daten erfolgt mit Parametern in Prozeduren. Im Unterschied dazu versieht die sogenannte objektorientierte Programmierung, die Java zugrunde liegt, die Software mit Strukturen, wie sie in der „Wirklichkeit“ existieren. Man arbeitet also mit Objekten, konkreten Instanzen von Klassen, die mit Attributen und Methoden versehen sind. Sie definieren den Zustand von Objekten und deren Verhalten und ermöglichen auch den Austausch von Nachrichten zwischen verschiedenen Objekten über ihre Schnittstelle. Ein Beispiel ist eine Klasse „Auto“ mit den Attributen „Bezeichnung“, „aktuelle Geschwindigkeit“ und „maximale Geschwindigkeit“ und der Methode „Fahren“. Ein Objekt dazu könnte etwa den Zustand „Tesla Model S“, „90km/h“ und „250km/h“ haben. Soweit erst mal zum Paradigmenbegriff.
Jedes Programm benötigt Speicherplatz, um seinen Zustand zwischenzuspeichern und zu ermöglichen, dass nachfolgende Anweisungen auf die vorher abgelegten Daten zugreifen können. Und gerade hier liegt die Krux: Während Programmiersprachen wie C eben diese Speicherverwaltung nicht vom Benutzer wegabstrahieren, tut Java genau das. Es verbirgt die Art und Weise, wie mit Daten auf niedriger Ebene gearbeitet wird, vor dem Benutzer. Die Speicherverwaltung wird im Fall von Java durch die Java-Laufzeitumgebung, genauer durch die JVM, Java Virtual Machine, gehandhabt. Dabei wird Speicher für Objekte automatisch freigeschaufelt (allokiert) und auch wieder automatisch freigegeben (Garbage-Collection).
Das ist eine erhebliche Vereinfachung für den Programmierer im späteren Berufsalltag. Leider verleitet aber gerade dieser Fakt dazu, wild mit Objekten hin und her zu jonglieren und somit zu vergessen oder zu ignorieren, was man dort eigentlich tut. Der Einblick in die hardware-nahe Programmierung mit C erlaubt, sich darüber klar zu werden, wie etwa die nützlichen Konzepte hinter der JVM erst funktionieren. Warum also studiert man Informatik? Weil man die Dinge verstehen will.
Manuelle und automatische Speicherverwaltung
Wer schon etwas länger dabei ist, kennt noch Programmiersprachen wie Pascal. Das daraus bekannte Prinzip der Zeiger liegt auch C zugrunde. Bei Java gibt es dieses Konzept nicht wirklich, zumindest wird es vor dem Benutzer verborgen. Zur kurzen Erläuterung: Bei Zeigern handelt es sich im Grunde um spezielle Datentypen, die eine Speicheradresse abbilden, die de-referenziert werden kann. Das bedeutet, dass auf den Wert hinter einer Speicheradresse zurückgegriffen wird. Man kann sich das als Wegweiser auf einen Datenbereich vorstellen.
Stellen wir uns vor, dass wir als Parametertypen in unserem C-Programm eine Struktur haben, die sehr viel Speicher belegt. Der entsprechende Prozeduraufruf wird mehrere tausend Male durchgeführt. Die Verwendung eines Parameters ohne Zeiger in der Funktion sorgt nun dafür, dass jedes Mal diese Struktur kopiert und somit der Speicher belastet wird, da für jeden Aufruf diese Struktur kopiert und wieder zum Ende der Funktion gelöscht wird. Außerdem verhindert es, dass die Struktur, die von außen in die Prozedur übergeben wird, selbst verändert wird: Man arbeitet ja schließlich auf einer Kopie. Nun übergibt man bei der Verwendung von Zeigern aber eine Speicheradresse, von der man (durch die Vorgabe des Datentyps) weiß, wie viel Speicher sie belegt. Das ist das Geheimnis zur Implementierung dynamischer Datenstrukturen wie Bäume oder Listen: Zeiger sind die Möglichkeit, in C- oder Pascal-Programmen dynamisch Speicher zu allokieren, da zu Beginn einer Programmausführung nicht unbedingt feststeht, wie viel Speicher benötigt wird. Das Problem ist, dass das Vergessen der Freigabe von angefordertem Speicher aber auch sogenannte Speicher-Lecks ermöglicht, die zu Problemen führen können. Ein mächtiges, allerdings auch sehr fehleranfälliges Konstrukt also.
Innovation vorantreiben
Java verschleiert diesen essenziellen Bestandteil, indem die Sprache selbst all diese Funktionalitäten handhabt. Für Geschäftsanwendungen und viele andere Applikationen ist das auch sinnvoll, da es einfacher und schneller leistungsstarke und robuste Programme ermöglicht. Vergessen wir nun aber nicht, dass es um das Studium geht. Was ist mit den ganzen anderen Faktoren? Wie soll ein Software-Entwickler später hardware-nahe Programme wie auf Micro-Controllern schreiben, wenn er schon grundlegende Konzepte der Computer-Technik nicht auf die Programmierung übertragen kann? Wer schreibt denn nun eigentlich mein Betriebssystem und wer programmiert meine Videospiele? Dafür ist C gut, um zu verstehen, wie ein Computer ein Programm eigentlich ausführt. In einem Informatikstudium lernt man auf theoretische Art und Weise das Verarbeiten von Informationen und daher ist es an erster Stelle nicht wichtig, Code möglichst schön zu gestalten (etwa mit Entwurfsmustern) oder direkt Wert auf Software-Architektur zu legen, sondern erst einmal zu verstehen, wie und wieso das Programm überhaupt funktioniert. Man sollte nicht nur nicht den Blick fürs Wesentliche verlieren, sondern ihn erst einmal gewinnen.
Man darf nie vergessen, dass die Programmierung zwei Seiten hat: Gerade durch die dank moderner Compiler recht gute Übersetzung in Maschinensprache ist es auch heute nur möglich, in einer hardware-nahen Programmiersprache das letzte Fünkchen an Rechenleistung herauszuholen. Der immense Ressourcenverbrauch großer, nicht effizienter Anwendungen hat außerdem Auswirkungen auf den Stromverbrauch und damit die Umwelt. Natürlich scheint das in Zeiten der heutigen Rechenleistung eher irrelevant, aber wer sonst soll denn darüber Bescheid wissen und es in Zukunft noch besser machen, wenn nicht ein Informatiker?
Der Artikel bekommt meine vollste Zustimmung. Ich habe im Fachabi C++ gelernt und aktuell im Studium Java. Teilweise verstehen selbst die Profs nicht richtig was da alles im Hintergrund passiert und wie es funktioniert. Die Profs für Programmierung sind leider oft Mathematiker, die sich mehr für Algorithmen interessieren, aber nicht für die Technik hinter ihrem Werkzeug. Mein Studium würde mir deutlich mehr Spaß machen, wenn ich mich nicht mit Java herumschlagen müsste.
Sehr ich völlig anders. Als Java und Python Entwickler bin ich froh dass mir genau das abgenommen wird. Wenn interessierts denn was da genau passiert mit dem Speicher, ich kann auch Mikrocontroller mit Java und Python programmieren. Python ist sogar die beste Sprache dafür. Bei Spielen wird es auch in eine andere Richtung gehen als C++.
Wie kommst du denn darauf, dass Python die beste Sprache ist? Ich weiß, dass es Bücher gibt, die genau das suggerieren, aber in meinen Augen gibt es einen Unterschied zwischen Microcontroller-Programmierung im Hobby-Bereich und im professionellen Bereich. In letzterem wirst du aus gutem Grund nach wie vor Embedded C finden. Mit diesem Artikel möchte ich übrigens nur sagen, was für das Studium (!) relevant sein sollte und das ist in meinen Augen definitiv nicht Java, da es Konzepte, die du im Studium (!) eigentlich erlernen solltest, wegabstrahiert. Aus gutem Grund hat sich auch Rust bspw. noch nicht durchgesetzt. Aus gutem Grund wurde Minecraft nicht in Java neu geschrieben. Garbage Collection etwa hat definitiv seine Daseinsberechtigung, aber wie viele Leute kennst du, die tatsächlich _verstehen_, wie und warum die Garbage Collection funktioniert? Gerade ein möglichst vollständiges und intrinsisches Verständnis für solche abstrakten Technologien, die man täglich im Einsatz hat, sind relevant, um effiziente Softwaresysteme in etwa Java zu erstellen und damit spreche ich nicht von kleineren bis mittelgroßen Webapplikationen, die so etwas wie ein Echtzeitverhalten nicht fordern und ein gewisses Lastverhalten: übrigens auch der Grund, warum Python und Java in professionellen Microcontroller-Applikationen eher selten zum Einsatz kommen – weil man damit wesentlich weniger granular arbeiten kann – wie gesagt geht es hier aber um das Studium der Informatik.
Ich stimme dem vollkommen zu. Nicht nur bezüglich low level Zeugs sondern allgemein dazu, dass die Hintergründe und nicht nur die Anwendung gelehrt wird.
Wenn die Unis das nicht mehr unterrichten, dann tut das schließlich keiner mehr. Schließlich gibt es zumindestens in der DACH region mehr als genug Alternativen um „nur“ anwendungsorientiertes Programmieren zu lernen.
Die Unis sind nahezu die einzigen Lehranstalten in denen man noch die Möglichkeit hat, zu lernen wie ein alles von Grund auf funktioniert und auch daran zu arbeiten – egal ob Betriebssystem, Compiler oder neue Programmiersprache, 3D renderer oder raytracer. Auch wenn das wenige tun, irgendwer muss diese Bereiche auch weiterbringen.
Abgesehen davon hatte ich bis jetzt praktisch in jedem Job noch die Situation dass irgendwann etwas C oder C++ notwendig wurde aufgrund irgendwelcher Constraints in Bezug auf Performance oder Portabilität. Oder schlicht einfach nur die Libraries modifiziert werden mussten, die dann in Java oder was auch immer konsumiert werden.
Abgesehen natürlich von den vielen Bereichen in denen C und C++ sowieso noch dominieren… embedded, gaming, signal processing, high performance computing, high frequency trading, machine learning Infrastruktur, driver, audio processing…
Hey Thomas,
Eigentlich müsste ich jetzt eine Praktikumsaufgabe für die Uni mit Java schreiben aber ich antworte jetzt lieber auf deinen Artikel. Ich finde du hast Recht und Unrecht. Man sollte einfach beides können, maschinennah und abstrakt.
Ich habe nicht so viel Kontakt mit Informatikstudenten an anderen Unis und weiss nicht ob die dort ausschliesslich Java oder ausschiesslich C lernen.
Um dir das Gewissen zu beruhigen möchte Ich dir eine gute Nachricht überbringen.
Bei mir an der Hochschule lernen wir zuerst Java und gleichzeitig Assembler, im Semester danach haben wir dann Java weiter gemacht und C angefangen. Ganz nebenbei mussten wir auch noch ohne irgendeinen Programmierkurs Adruinos programmieren können, Matlab und Latex uns selbst beibringen.
Ich denke am Ende sollte man sicherlich ein zwei Programmiersprachen sicher können aber vorallem muss man doch das Wissen haben wie man sich egal welche Sprache schnell aneignet um an sein Ziel zu kommen.
Wir benötigen abstrahierende Plattformen, um effizient Software entwickeln zu können, im Sinne einer Industrialisierung der IT. Java ist hier nur eine, und wenn ich die grafischen Generatoren sehe, die gleichfalls durch Informatiker bedient werden, eine sehr bodenständige. Jedoch, wie auch in anderen Bereichen, entkoppeln solche Plattformen den Entwickler von dem, was schlussendlich auf der Maschine geschieht. Bin ich nun nicht in der Lage, nachzuvollziehen, was passiert, bin ich Fehlern und Bedrohungen ausgeliefert. Genau das passiert aber, wenn Business Analysts Software mit grafischen Toolboxen Software bis in Produktionsnähe entwerfen. Funktionierende Software ist eben mehr als die Implementierung einer Business-Logik.
Ergo: Wir benötigen also, zumindest als Informatiker beides – und noch mehr, nämlich grundsätzliches Verständnis, was es bedarf, damit eine Software produktiv laufen kann und weiter läuft. Es reicht aus meiner Sicht nicht aus, in immer kürzer werdenden CI/CD Schleifen Code herauszusprudeln, wenn es gleichzeitig an Instrumentierung, am Capacity Management und am Verständnis mangelt, wie in einer IT Produktion Änderungen und Störungen behandelt werden müssen – eben nicht durch Korrektur zweier Codezeilen und neue Delivery.
Bottom Line: Die Konzepte, die seit Jahrzehnten die IT prägen werden durch neue Plattformen nicht einfach obsolet, sondern zur Effizienzsteigerung komplementiert. Informatiker tun gut daran, Bescheid zu wissen, wie es läuft – oder warum nicht…
Titel des Beitrags: „Warum der Einstieg ins Programmieren nicht einfach sein muss“. Es geht also um den Einstieg, nicht das komplette Studium.
Auch wenn mein Studium ein paar Jahre zurück liegt (gegen Ende gab es Java auch unter MacOS, dass damals auch noch nicht so hieß) ;-) und wir mit Scheme, einen LISP-Derivat begonnen haben („Weil es keine kennt und alle auf dem gleichen Stand anfangen.“) finde ich, dass es im Informatikstudium eben nicht darum geht, jedes Register beim Vornamen zu kennen.
Meiner Meinung geht es in der Informatik primär darum zu lernen, wie man Probleme systematisch löst.
Jede Programmierplattform (Sprache, Umgebung, Bibliotheken) ist nur mittel zum Zweck, ein Handwerkszeug. Die Geschichte zeigt, dass nicht nur Programmiersprachen, sondern sogar die darunter liegenden Konzepte einem Wandel, einer Mode unterliegen.
Ich finde es gut, wenn man in seinem Studium zuerst lernt, wie man Programme schreibt, die Menschen dabei unterstützen, Ihre Probleme einfach zu lösen.
Und für den Einstieg (zurück zum Thema) darf das aus meiner Sicht auch eine verbreitete, „bequeme“ Programmiersprache sein – solange es nicht die einzige bleibt… ;-)
Ich hätte den ‚Mittelweg‘ zwischen C++ und Java vorgeschlagen: C++, weil dessen OO sowie die const-Möglichkeit meines Erachtens die beste Aufgaben- und Verantwortungsaufteilung in einem Softwaresystem erlauben und so das grösste Problem des Softwareengineering überhaupt, Komplexität, bestmöglich lösen.
Meine Quintessenz wäre: bei Informatikstudenten ist die Antwort auf die Frage Java oder C: beides (und noch mehr). Aber nicht notwendigerweise bis auf Profi-Niveau, sondern nur so tief, dass die Abstraktioneneb sichtbar und möglichst nachvollziehbar werden. Nicht jeder wird später Mikro-Controller programmieren, daher muss das auch nicht jeder Absolvent können. Spezialisierung ist bei dem heutigen Marktbedarf erlaubt.
Ich habe in Bezug auf den Text eine dringende Bitte:
Bitte vermeidet die Trivialbeispiele, die immer wieder zur Erklärung von objektorientierter Programmierung herangezogen werden (‚Ein Beispiel ist eine Klasse „Auto““), da sie IMO extrem irreführend gerade für Neulinge sind.
OO ist in der Hauptsache NICHT die Übersetzung „realer“ Konzepte in Code-Klassen (auch wenn Anwendungssoftware sicherlich Datenklassen wie „Sales Order“ enthalten kann).
Wenn man gern ein sprachliches Bild aus der Realität verwenden will, dann finde ich es viel hilfreicher, OO-Software wie eine Organisation oder einen Betrieb zu verstehen. Klassen sind dabei Stellenbeschreibungen, die Aufgaben (Methoden) und Arbeitsmittel (Attribute) enthalten. So lassen sich hilfreiche Entwicklungsprinzipien (z.B. Separation of Concerns, Integration Operation Segregation Principle etc.) innerhalb dieser Analogie viel besser vermitteln.
als Einstiegssprache Python!
und danach Modulspezifisch weitere Programmiersprachen, zB:
– OOP-Müll mit Java oder einer anderen OOP-Sprache, von denen es soviele wie sand am meer gibt
– hardeware-nahe Module mit C, C++ oder rust
– Web-zeug… selbstredend Javascript
– und bei funktionaler Programmierung Haskell, oder ggf OCaml
Die einzige Programmiersprache, wo ich wirklich das Gefühl hatte, meinen Horizont multipel zu erweitern, war Haskell. Keine andere Sprache bringt so radikal neue und geistreiche Konzepte auf den Tisch (allein die generische Programmierung in Haskell fühlt sich so natürlich an und ist einfach allen anderen Sprachen weit überlegen).
Es ist geradezu lächerlich, dass man sich heute noch mit Absurditäten wie Java oder C++ beschäftigt, wohl auch deshalb, weil bisher kaum echte Alternativen bestehen; schuld daran sind jedoch auch die Hochschulen, welche ihre Studenten auf OOP drillen; obwhl gerade in dem Umfeld alternativen viel leichter zu fördern sind.
Bis man in DE zur Erkenntnis gelangt, dass Java eine denkbar schlechte Einsteigersprache ist, werden noch zahlreiche IT-Generationen verbraten.
In jedem Falle wäre es ratsam Studenten mit einer Scriptsprache wie Python heranzuführen und dann über verschiedene Module verschiedene andere Sprachen zu vermitteln, sowohl maschinennahe als auch hoch abstrakte.