Ask HN: Was ist die beste Codebasis, um Softwaredesign zu lernen?
(news.ycombinator.com)- Ich versuche, meine Fähigkeiten im Softwaredesign zu verbessern, und mir wurde empfohlen, bestehende gut gestaltete Codebasen zu studieren
- Ich frage mich, welche öffentlich zugänglichen Codebasen als Goldstandard des Softwaredesigns gelten
1. Empfohlene Codebasen
- Große/maßgebliche Projekte
- Git, Postgres, CPython
- Das "Lieutenants Model" des Linux-Kernels
- UNIX v6, BSDs
- Frameworks/Bibliotheken
- Spring Framework
- Laravel
- Rust-
std-Bibliothek - Codemirror 6
- Systeme/Server
- Spiele/Sonderfälle
- Lehr-/Lernmaterialien
- xv6 (MIT-OS-Kurs)
- pytudes (Peter Norvig)
- Sonstiges
- Monocypher (Kryptografie-Bibliothek)
- Tcl-Sprachimplementierung
2. Code lesen vs. Dokumentation/Design lernen
- Grenzen von reinem Code
- Eine Codebasis zeigt die Implementierung, verbirgt aber die Designabsicht und Trade-offs
- Wichtigkeit von Designdokumenten
- Entscheidungsaufzeichnungen wie ADRs (Architectural Decision Records), Rust RFCs und Python PEPs sind für das Lernen von Design deutlich hilfreicher
- Schon das Schreiben von Designdokumenten kann selbst ein gutes Training sein
- Buch- und Literaturtipps
- The Architecture of Open Source Applications
- Code Reading (Spinellis)
- Beautiful Code (O’Reilly, ISBN-10: 0596510047)
- Bücher zu Refactoring / Legacy Code
3. Praxisorientierte Lerntheorie
- Erfahrung und Versuch-und-Irrtum
- Design lernt man, indem man Probleme wiederholt erlebt und lernt, sie zu vermeiden
- Allein durch das Lesen von Code lernt man nicht genug; man lernt im Prozess des eigenen Schreibens und des Lösens von Fehlschlägen
- Interessenbasiertes Lernen
- Man lernt tiefer, wenn man Projekte baut, die einen wirklich interessieren
- Niedrige Kosten des Scheiterns
- In Software sind die Kosten des Scheiterns geringer als im physischen Engineering, daher ist Lernen durch Ausprobieren und Scheitern besonders effektiv
4. Debatte über den Charakter von Software Engineering
- These vom unreifen Ingenieurwesen
- Wenn fünf Ingenieure zusammenkommen und fünf verschiedene Lösungen hervorbringen, sei das ein Zeichen dafür, dass das Fach als Ingenieurdisziplin noch unreif ist
- These der Experimentierfreundlichkeit
- Software hat wenige Einschränkungen, daher gibt es viele mögliche Lösungen; anders als im physischen Ingenieurwesen ist die richtige Antwort nicht fest vorgegeben
- Grenze zwischen Kunst und Ingenieurwesen
- Design ist auch ein künstlerischer Akt mit ästhetischen Elementen, zugleich aber Ingenieurarbeit, insofern funktionale Anforderungen erfüllt werden müssen
- Software liegt zwischen künstlerischer Flexibilität und ingenieurmäßiger Strenge
5. Alternative Lernmethoden
- Schlechten Code analysieren
- Nicht nur gut gestalteter Code, sondern auch das Verbessern schlechter Codebasen hat einen großen Lerneffekt
- Die eigene Codebasis als Lernmaterial
- Die interne Team-Codebasis wird oft als die lehrreichste Quelle genannt
- Falls der Team-Code jedoch schwach ist, sollte man ihn mit externen Beispielen ergänzen
- Domänenspezifisches Lernen
- Am effektivsten ist es, Codebasen zu lesen, die Problemen ähneln, die man selbst lösen möchte
Zentrale Erkenntnisse
- Gut gestaltete Codebasen helfen, aber Lernen muss mit dem Verständnis der Designabsicht und eigener Versuch-und-Irrtum-Erfahrung einhergehen
- Wichtiger als das reine Codelesen sind Designdokumente und Entscheidungsaufzeichnungen als Lernmaterial
- Repräsentative Qualitätsprojekte (Git, Postgres, CPython, Rust
stdusw.) haben hohen Lernwert - Nicht nur guter Code, sondern auch schlechter Code und der eigene Code sind langfristig oft die praktischere Lernquelle
Zusammenfassung wichtiger Kommentare
Empfehlung repräsentativer Codebasen (CraigJPerry)
- Postfix Mail Server
- Eine sicherheitszentrierte Architektur, die schon vor dem Begriff Microservices eine ähnliche Struktur zeigte
- Während moderne Microservices oft auf verteilte Skalierung in großen Organisationen abzielen, wurde Postfix für Sicherheit und Einfachheit entworfen
- Spring Framework
- Spiegelt eine Kultur wider, die die Anforderungen von Java-Entwicklern im Enterprise-Umfeld tief berücksichtigt
- Man kann daran einen nutzerzentrierten Designansatz lernen
- Git
- Versteht man die Konzepte der Objektdatenbank (Blobs, Trees, Commits) und der Referenzen, ist der Rest eine schrittweise Erweiterung
- Die konsistente Erweiterung von Kernkonzepten wird als gutes Designbeispiel genannt
- Varnish
- Ein Hochleistungs-Reverse-Proxy, dessen Codebasis zugleich so gut strukturiert ist, dass sie als Lernmaterial dienen kann
- Linux-Kernel-Lieutenants-Model
- Keine Codebasis, aber als Modell zur Verwaltung großer Softwareprojekte dennoch sehenswert
- Es geht nicht einfach um "gut designten Code", sondern um Beispiele, in denen Designentscheidungen einen starken Eindruck hinterlassen
Betonung des Lernens an realen Codebasen (crystal_revenge)
- Den größten Lernwert bietet die Codebasis des eigenen Teams
- Im chaotischen Zusammenhang zwischen realen Anforderungen und Implementierung erlebt man zugleich gute und schlechte Entscheidungen
- Der größte realistische Zwang ist Zeitdruck; entscheidend ist, das Gleichgewicht zwischen idealem Design und Realität zu lernen
- Gute Software bedeutet, Nutzeranforderungen zu lösen; durch Wiederholung lernt man Designs, die die Erfolgswahrscheinlichkeit erhöhen
Frühere Diskussionen und Materiallinks (sprobertson)
- Das Thema wurde auf HN bereits mehrfach behandelt
Code vs. Designdokumente (alphazard)
- Eine Codebasis ist nur das Ergebnis der Implementierung, nicht das Design selbst
- Für das Lernen von Design ist das Schreiben von Designdokumenten wirksamer
- Dokumente sollten so klar sein, dass jemand anders sie direkt implementieren könnte
- Wenn man Alternativen aufführt und festhält, warum sie verworfen wurden, ist das ein Beleg für die Designüberlegungen
- Gute Designer berücksichtigen einen breiteren Designraum und wählen daraus einen passenden Punkt
Betonung des Verständnisses des Gesamtsystems (RossBencina)
- Der Prozess, eine gesamte Codebasis zu verstehen, ist äußerst wertvoll
- Man trainiert nicht nur das Lesen gut gestalteten Codes, sondern auch den Blick auf das große Ganze des Systems
- Es hilft, Beziehungen mit Diagrammen wie UML zu visualisieren
- Lernansatz:
- Es ist effektiv, Code von Software zu lesen, die dem ähnelt, was man selbst entwickelt
- Als Einstieg werden Code aus bereits vertrauten Domänen empfohlen (Web-Frameworks, Webserver, Python-Standardbibliothek, VSCode usw.)
- Zu Beginn sollte man mit kleinen Programmen und vertrauten Domänen starten
Maßstäbe für gutes Design (mamcx)
- Gutes Design sind Ziele und Ideen, die Codebasis zeigt nur den Grad ihrer Umsetzung
- Gutes Design sollte nicht nur Schlagworte wie "schnell" oder "sicher" tragen, sondern konkrete Überlegungen und dokumentierte Trade-offs enthalten
- Beispiele dafür lassen sich bei Erlang, frühem Pascal und vielen RDBMS-Designs beobachten
- Rusts
std-Bibliothek ist ein gutes Lernmaterial, weil sie Sicherheit und Konsistenz betont und dies in Code und Dokumentation treu widerspiegelt
Unsichtbare Designentscheidungen (ben30)
- Beim Betrachten gut gestalteter Codebasen ist das Wichtigste oft das, was man nicht sieht
- Entscheidungen des Weglassens – das Ausschließen von Komplexität, das Vermeiden unnötiger Abstraktion, das Ablehnen bestimmter Muster – sind zentral
- Um diesen Kontext zu ergänzen, helfen ADRs (Architectural Decision Records)
- Sie dokumentieren Alternativen, Gründe für ihre Verwerfung und die Begründung der Auswahl und bewahren so den Kontext
- Das hilft sowohl künftigen Maintainer:innen als auch AI-Tools erheblich
- Beim Lernen ist es daher effektiv, nicht nur Code anzuschauen, sondern Projekte mit ADRs, RFCs, PEPs und ähnlichen Designentscheidungsdokumenten
5 Kommentare
Es gibt ein Interview mit Evan You (dem Entwickler von Vue.js und Vite), in dem er sagt, dass TJ Holowaychuks express.js sauber und schön entworfen sei. Deshalb habe ich den Code ein paarmal gelesen. Auch wenn ich das große Ganze nicht ganz verstehen konnte, hatte ich insgesamt stark den Eindruck, dass der Code nicht kompliziert ist und wirklich nur die nötige Logik sauber enthält.
Die Kommentare sind ebenfalls gut geschrieben, sodass man trotz des 10 Jahre alten Codes gut Typinferenz und DTO-Formate nachvollziehen konnte.
Sich auf einen Blogbeitrag von 2009 zu beziehen, der von Spam-Kommentaren überflutet ist …
Hacker-News-Kommentare
Ich weiß nicht, ob es nur mir so geht, aber ich habe das Gefühl, dass es am effektivsten ist, einem Problem tatsächlich mehrfach zu begegnen und selbst herauszufinden, wie man es umgeht. Mit der Zeit kann man dann im Kopf ganz natürlich simulieren, welche Probleme als Nächstes auftreten könnten, und am Ende ist Design auch nur ein Urteil darüber, verschiedene zukünftige Probleme im Voraus vorherzusehen und zu vermeiden, abzuwägen, welche Probleme man mit welchem Aufwand vermeiden will und ob sich mit einem einzigen Design mehrere Probleme zugleich lösen lassen
Geht mir genauso. Dinge wie „Übungsaufgaben lösen“ oder „eine Codebasis studieren“ haben für mich nie funktioniert. Ich lerne ganz natürlich, wenn ich etwas baue, das mich wirklich interessiert, und dabei im Beispiel auf Genauigkeit und Sorgfalt achte. Manchmal habe ich aber trotzdem das Gefühl, dass meine Fähigkeiten noch nicht ausreichen. Wenn ich Code so flüssig lesen könnte wie ein Buch und dabei direkt im Kopf sähe, wie er arbeitet, dann wäre auch das Lernen selbst deutlich interessanter
Was ich beim Hören dieser Aussage, dass man durch wiederholtes Auflaufen auf Probleme lernt, empfinde, ist, dass das Feld der Software Engineering noch nicht ausgereift ist. Man stelle sich nur vor, Brücken oder Häuser würden so gebaut, oder Chirurgen würden so ausgebildet — das wäre gefährlich. Mit der Zeit werden sich Standards und Normen etablieren, aber im Moment ist die Lage noch ausgesprochen fluide. Wenn man fünf Softwareingenieure zusammensetzt und ihnen ein Problem gibt, bekommt man nicht nur fünf völlig unterschiedliche Lösungen, sondern auch heftige Meinungsverschiedenheiten darüber, welche davon richtig ist. Ich glaube nicht, dass man mit einer Haltung wie „eine gute Lösung erkennt man, wenn man sie sieht“ zu echter Ingenieurskunst kommt
Auch ich habe bis jetzt auf diese Weise kontinuierlich gelernt und werde das wohl auch weiterhin tun. Aus echter Production-Code zu lernen, wäre für mich allerdings eine neue Herausforderung. Ich weiß nicht, wie wertvoll das wäre, aber Spaß machen würde es vermutlich auf jeden Fall
Ich finde, das ist ein bisschen so, als würde man Autofahren lernen, indem man sich zum ersten Mal ins Auto setzt, einen Unfall baut und dann darüber nachdenkt, damit es beim nächsten Mal nicht wieder passiert. In Wirklichkeit braucht man beides. Im normalen Straßenverkehr gerät man fast nie in Situationen, in denen man die Grenzen überschreitet, deshalb lässt sich das nicht direkt übertragen, aber beim Rennsport muss man ganz genau wissen, wo die absolute Grenze liegt. Natürlich muss man unseren Beruf nicht wie einen Wettkampf behandeln. Aber wenn man keine Bücher liest und nicht lernt, dauert es im Wortsinn sehr lange, und Pannen und Ausfälle hören nie auf. Deshalb würde ich immer sagen: lesen und noch mehr lesen. Vielleicht spürt man den Bedarf nicht sofort, aber irgendwann, wenn man Erfahrung gesammelt hat, wird dieses Wissen ganz sicher irgendwo nützlich sein, und man gerät nicht in Panik wie jemand, der zum ersten Mal lernt, beim Bergabfahren mit Motorbremse in einen niedrigeren Gang zu schalten
Genau das ist der Kernpunkt
Mein erster Gedanke bei dieser Frage ist: „die Codebasis des Teams“. Es gibt keinen wirksameren Weg, Softwaredesign zu lernen, als tief zu verstehen, warum bei realen Problemen gute und schlechte Lösungen jeweils übernommen wurden. Software ist ihrem Wesen nach genau diese komplexe Zwischenschicht zwischen Nutzeranforderungen und dem Verhalten von Maschinen. Wenn dieses Chaos nicht existierte, wäre es längst automatisiert und Software selbst unnötig geworden. In der Software trifft man oft gerade dann schlechte Entscheidungen, wenn man nur einem Idealbild hinterherläuft. In der Praxis reduziert man Versuch und Irrtum, indem man versteht, „warum unter diesem Druck diese Entscheidung getroffen wurde“. Gleichzeitig muss man praktische Methoden lernen, um schnell und effektiv zu arbeiten. Die größte Herausforderung in der Realität ist die Zeitbegrenzung. In theoretischen Betrachtungen zu Softwaredesign kommt das fast nie vor, aber real arbeitet man ständig unter dem Druck, Code schnell auszuliefern. Oft fehlt schlicht die Zeit, so zu arbeiten, wie man es gern hätte oder wie es am besten wäre. Gute Software ist Software, die echte Bedürfnisse der Nutzer löst. Es gibt Designlösungen, die in Zukunft häufiger zu erfolgreicher Ausführung führen, und der beste Weg, sie zu finden, ist, sich den Code, den man tatsächlich schreibt, sehr genau anzusehen
Was aber, wenn die fragende Person externe Ratschläge sucht, weil sie die Software ihres Teams für ein Chaos hält? Oder wenn die Frage einfach von einer Studentin oder einem Studenten kommt?
Dass auch die für die Umsetzung benötigte Zeit ein Maßstab für die Qualität eines Designs sein kann, hatte ich noch nicht bedacht, aber das erscheint mir sehr plausibel. Ich selbst lerne enorm viel aus der Codebasis meines Teams. Ein großer Teil davon besteht darin, bei gutem Design die guten Dinge mitzunehmen und bei den schwächeren Teilen durch eigenes Googeln weiter dazuzulernen
Es ist zwar schon ein paar Jahre alt, aber es gibt die Reihe „The Architecture of Open Source Applications“, zu der viele Leiter von Open-Source-Projekten beigetragen haben, und man kann sie kostenlos online lesen
https://aosabook.org/en/index.html
Diese Frage ist schon mehrfach gestellt worden, deshalb habe ich ein paar nützliche Links gesammelt
Yanderedev-Quellcode
Ich bin wahrscheinlich nicht qualifiziert genug, um die richtige Antwort zu geben, aber ich habe vor etwa 15 Jahren ein Buch namens „Code Reading“ mit großem Vergnügen gelesen. Es passt genau zu diesem Thema
https://www.spinellis.gr/codereading/
Inhaltsverzeichnis: https://www.spinellis.gr/codereading/toc.html
Ich meine, es gab auch noch ein Buch mit ähnlichem Namen, aber ich erinnere mich nicht mehr genau
In einer Codebasis steckt in der Praxis oft eher die Implementierung als das Design. Man kann zum Beispiel alles vollständig in einer anderen Sprache neu schreiben und trotzdem das Design beibehalten. Ich empfehle, das Schreiben von Designdokumenten zu üben. Mach dir keine Gedanken darüber, wie das Dokument aussehen soll, und hänge nicht an Templates. Am wichtigsten ist, dass jemand anderes dieses Dokument in die Hand nehmen und danach implementieren kann. Außerdem kann das Dokument selbst als „Spur der Überlegungen“ dienen. Man sollte klar festhalten, welchen Ansatz man gewählt hat, welche Alternativen es gab und warum man sie nicht gewählt hat. Wenn man Alternativen im Voraus anerkennt und vergleicht, vermittelt man den Leserinnen und Lesern das Vertrauen, dass gründlich nachgedacht wurde. Was „gute“ Systemdesigner tun, ist, einen größeren Designraum als andere zu überblicken und darin konsistent gute Punkte zu finden. Nimm ein Problem, erkunde verschiedene Designräume, erkläre, warum manche besser sind als andere, und dokumentiere alles
Man sollte zuerst bei der Frage anfangen: „Welches Problem will ich eigentlich lösen?“ Dann sucht man eine Codebasis, die dieses Problem gelöst hat, und analysiert gezielt, wie es tatsächlich umgesetzt wurde. Man muss sich klarmachen, dass gutes Design sehr eng mit der jeweiligen Domäne verknüpft ist. Ich glaube, dass Wonhams Internal Model Principle auch für Code gilt. Ich wollte zum Beispiel das Problem von Unit-Tests für Embedded Targets lösen, habe dazu relevante Open-Source-Projekte analysiert und kritisch betrachtet, warum der jeweilige Code so geschrieben wurde. Während ich meine eigene Lösung entwickle und dabei immer wieder auf den früheren Code zurückgreife, lerne ich umso mehr, je tiefer mein Verständnis der Domäne wird
Nach meiner Erfahrung (30 Jahre Software, 25 Jahre Architekturpraxis, Master in Systemarchitektur vom MIT) gibt es ein abstrakt „gutes“ Design eigentlich nicht. Es gibt eindeutig schlechte Entwürfe, also Designs, die zu schlechten Ergebnissen führen, aber was „gut“ ist, hängt vom Kontext ab. Was man baut, Anforderungen wie Sicherheit und Security und vor allem das Team, das es tatsächlich umsetzt, sowie dessen Struktur haben den größten Einfluss. Ein Team, das nur aus Juniors besteht, kann ein ausgefeiltes Design missverstehen und ruinieren. Wie bei Conways Gesetz spiegelt sich die Struktur des Entwicklungsteams direkt in der Software wider
Was ich beim Lernen von Softwaredesign definitiv erkannt habe, ist, dass es keine Universallösung gibt. Das wäre natürlich schön, aber zwischen verschiedenen Architekturen und Paradigmen die beste Lösung auszuwählen, kann frustrierend sein. Trotzdem reduziert sich die Auswahl schon deutlich, wenn man die Anforderungen sauber abbildet. Ich arbeite derzeit an einem Embedded-System, bei dem Sicherheit besonders wichtig ist, und gerade diese Umgebung führt oft zu Entscheidungen, die man in anderen Situationen überhaupt nicht treffen würde
Im Kern geht es also darum, wirklich absurde Kompromisse zu vermeiden und auch die schlimmsten Entscheidungen aus einer breiteren Perspektive zu umgehen. Mein Eindruck aus der Praxis ist immer wieder, dass es weniger ein Kampf um die beste Architektur ist als ein fortlaufender Kampf darum, „grundlegend schlechte Entscheidungen zu vermeiden“
Ich habe vor einiger Zeit einmal eine sehr einfache Empfehlungsliste erstellt, und sie ist immer noch gültig
https://medium.com/@012parth/what-source-code-is-worth-studying-8755f88f8de5
Der Haken liegt in der Mitte..
Ist das der Yanderedev-Quellcode ... lol