 Ja, danke für diese Einführung und die Organisatoren, dass ich heute hier stehen kann und mit euch reden kann. Mein Name ist Pete Sewell. Ich bin ein akademischer Informatiker. Und als solchen habe ich eine schwere Schuld zu tragen, wie wir alle. Wir teilen uns diese Schuld, um mal fair sein wollen, aber es ist trotzdem eine schwere Schuld, die wir tragen. Ich habe zwei Sachen über Computer gelernt. Das erste ist, es gibt verdammt viele davon. Das ist ziemlich schockierend. Und das zweite ist, dass viele Sachen schiefgehen. Sehr, sehr oft und wirklich oft, verdammt oft. Und es gibt auch viele verschiedene interessante Arten, wie was schiefgehen kann. Manchmal gehen sie auf eine sehr spektakuläre Art und Weise schief mit Feuer und Explosionen, wie wir zum Beispiel hier sehen. Hier sehen wir eine halbe Milliarde Dollar Feuerwerk. Das sieht man nicht jeden Tag. Und was ist da passiert? So wie ich das verstanden habe, was da passiert ist, das war die erste Flug der Ariane 5 Rakete. Und da wurde ein Teil der Steuerungssoftware von der Ariane 4 wiederverwendet. Das war natürlich Coach, der war eigentlich ganz gut getestet. Aber absichtlich wurde die Ariane 5 ein bisschen mehr auf die Seite gelenkt. Und die Kontrollsoftware, die dafür zuständig war, da fand ein Überlauf statt. Und das war schlecht. Und die Kontrollsoftware entschied dann, dass irgendwas schief gelaufen war. Und die Kontrollsoftware entschied sich dann dafür, dass diese Rakete bitte nicht auf den Köpfen der Zuschauer landen sollte. Und dann wurde diese Rakete absichtlich zerstört. Und manchmal geht das eben auf spektakuläre Weise schief. Es gibt davon wahrscheinlich mehr als ich. Es gibt manchmal sehr spektakuläre Probleme, die auch ausgenutzt werden von bösen Leuten. Und manchmal werden Sicherheitslücken auch von unserer netten Regierung ausgenutzt, um uns anzugreifen. Und es gibt sehr viele verschiedene Gründe dafür. Aber viele Gründe sind relativ trivial. Es gibt zum Beispiel manchmal eine Zeile Code, die einfach an der falschen Stelle steht. Und das kann dann sehr, sehr schlimm sein. Und wir müssen uns vor Augen führen, wie schlimm das ist. Aus meiner Sicht ist das noch nichts im Vergleich zu dem richtigen Disaster, was wir erleben und auch noch weiter erleben werden. Das eigentliche Disaster ist diese riesen Verschwendung von menschlichem Leben, Energie und Arbeit, weil wir uns eben mit diesen beschissenen Maschinen, die wir bauen, ständig auseinandersetzen müssen. Es ist ein bisschen hart, das in Zahlen auszudrücken, aber ich will es mal versuchen. Ich habe mal den Google eingegeben, Android-Problem und Windows-Problem. Und habe ungefähr 300 Millionen Treffer für jeden dieser beiden Suchtbegriffe gefunden. Das zeigt euch schon ein bisschen, wie viel da schief läuft. Das sollte für euch ja sehr bekannt aussehen. Ihr solltet euch mal zurück erinnern, als ihr noch jung wart, 19 Jahrhundert, als ihr damals als Community von Hackern und gab es die volle industrielle Revolution. Ihr habt damals wunderschöne Brücken aus geschmolzenem Metall gebaut, aus Guseisen und ab und zu die einfach zusammenfallen. Da hat dann halt mal jemand die Windbelastung falsch berechnet. Oder wir haben magische Dampfmaschinen gebaut, die uns einfach weggefegt haben. Aber ab und zu werden die auch einfach explodieren. Und diese Sachen passieren nicht mehr so häufig. Wir haben relativ gutes ziviles und mechanisches Engineering. Heißt das einfach, wir wissen genug Thermodynamic, Materialdesign und Qualitätskontrolle, um vorher sagen zu können, dass so was nicht mehr passiert. Ich habe irgendwie gerade die Angst, dass wir eine Optimatisierung in diesem Vortrag durchführen müssen. Zeit für lunch. Zeit für Mittagessen. Warum ist es so schwer für Computer, diesen Qualitätsstandard auch zu bekommen? Warum? Lass mich das kurz erklären, warum es so schwierig ist für Computer. Also der erste Grund ist, es ist einfach zu viel Code vorhanden. Das ist ein sehr gruseliger Graph, den ich gefunden habe. Es ist eine Messung in 100 Millionen Zeilen pro Code. Und in den kleinen Buchstaben gibt es Android und den Large Heidel & Collider, Vista, Facebook, die amerikanisches Militärkampfsystem Macro 6 oder Software in einem high-end Auto, ganz am unten, am Rand. Ich fliege heim. Das ist ein großes Problem, wir werden das niemals schaffen, das hinzubekommen. Außerdem haben wir noch viel, viel Komplexität einfach aufgrund der Legacy, aufgrund der Geschichte, wie es entstanden ist. Wir wollen vielmehr ein Hochhaus bauen, das ein solides Fundament hat und sauber konstruiert ist. Aber das ist leider nicht der Fall, es ist vielmehr so etwas wie dieses Ziel. Es ist halt Struktur, es hängt zusammen, aber es ist nicht sauber. Und dann denkt man kurz nach und sagt, aber Software ist doch bei schlauen Leuten gemacht. Bei großen Gruppen und normalerweise auch bei ganz intensiven Arten von externen Druck aufgebaut. Und das wird doch von Leuten gemacht, die alle Komponenten und Werkzeuge bestimmte Mögen und Präferenzen haben. Und jemand ruft rein, sie haben das Management vergessen. Und deswegen haben wir am Ende was Spektakulär Geniales. Und was man hier sehen kann, ist sehr gut, man kann alle Teile sehen. Das war ein Bild, was ich einfach am Internet gefunden habe. Aber man kann sehr gut sehen, dass man ganz viele Teile hat. Da unten hat man die Hardware, hier hat man 10 Kompiler mit den ganzen Phasen. Das ist das Dateisystem, diese Phasen hier. Hier ist ein TCP-Stack noch drin. Ein kleiner Stück hat auch zu der NSA. Hier ist ein JavaScript-Engine, ein TLS-Stack und natürlich ein Browser. Ganz oben ist eine Software, die die meisten Leute nutzen, um mit ihrer Bank zu reden. Es ist einfach nur Wahnsinn. Jetzt müssen wir mal schauen, wie wir diese Dinge eigentlich bauen. Normalerweise haben wir Spezifikationen und schreiben ein bisschen Code. Und dann haben wir ein paar Talk-Tests. Und schauen dann, testen und reparieren, testen und reparieren, bis es verkaufbar ist. Und dann testen und fixen wir es und exzenten ist, bis es nicht mehr verkaufbar ist. Und dann irgendwann wird das halt kaputt und unübersichtlich. Oder geht kaputt, zerstört die das Gerät und wird alt. Das Problem ist dann natürlich, dass man einfach zu viele Arten der Execution Path hat. Einfach zu viele Zustände, die skalieren so hoch. Sie wachsen exponentiell mit der Codegröße. Und da ist einfach keine Art, dieses Testen durchzuführen, aufgrund der vielen Zustände, die man reichen kann innerhalb des Programms. Außerdem sind Computer zu diskret. Wenn man zum Beispiel ein Stuhl nimmt, irgendwas, was man verbiegen kann, sobald man auf einem Stuhl ein bisschen mehr Kraft ausübt, mehr als es normal gewöhnt ist, dann deformiert es und biegt sich ein bisschen. Wenn man jetzt aber eine Brücke nimmt und eine der Schrauben etwas zu fest anzieht, kommt man ab und zu mal zu einem Punkt, wo eine Katastrophe passiert. Aber normalerweise ist die Brücke etwas schwächer als geplant. Bei Computersystemen ist es aber so, wenn man ein kleines Schraubchen zu weit dreht. Manchmal passiert nichts, aber verstörend oft zerbricht das ganze Programm daran. Das heißt, das ist ein Unterschied, wenn man das mit dieser traditionellen Ingenieurswissenschaft vergleicht. Okay, so. Dieser Kongress hat den Titel A New Dawn. Also was können wir machen dagegen? Ich wollte aber mehrere verschiedene Möglichkeiten sprechen. Eine Sache, die wir machen können, wir können mehr davon machen, was man traditionellerweise Software Engineering nennt. Es ist nicht wirklich eine Ingenieurswissenschaft, wenn ihr mich fragt, aber es sind ein paar nützliche Sachen dabei. Man kann also mehr Tests machen. Man kann Assertions in den Code einbauen, das Ganze besser managen. Das können wir alles machen und das sollten wir auch tun. Aber es wird keine große Veränderung bringen. Damit gehen wir nicht wirklich an die eigentlichen Gründe des Problems dran. Was können wir sonst noch machen? Als akademischer Informatiker, der mehrere Jahre meines Lebens mit Programmiersprachen gearbeitet hat, habe ich mir die Programmiersprachen angeschaut, die heutzutage so auf der Welt benutzt werden. Ah, es ist einfach nur widerlich, es ist schockierend. Die Gründe, dass Sprachen beliebt werden und Teil der Infrastruktur werden. Die Gründe haben fast nichts damit zu tun, wie gut diese Sprachen Designs sind. In der Tat, um genau zu sagen, ob sie überhaupt in irgendeiner Form Designs sind. Ich hoffe, ich kriege nicht zu viele Hatemails nach diesem Talk. Ich werde vermeiden, bestimmte Sprachen beim Namen zu nennen, aber ich bitte euch darum, euch diese Sprachen, die ich hier meine, mal im Kopf vorzustellen. Das Mindeste, was wir von einer Programmiersprache verlangen könnten, sind Ideen aus den 70er Jahren anstatt aus den 60er Jahren. Ich meine, Leute, kommt schon. Damals, 1967 oder 1969, wir hatten C und BCPL und ein paar Jahre später hatten wir Sprachen, die garantieren konnten, dass sie typischer und speichersicher waren und gewisse Abstraktionen forciert haben. Wir brauchten uns schon damals nicht mehr mit 23 Millionen Poindern rumschlagen. Und wenn wir auch nur einen davon vermasseln, dann geht alles schief. Viele Projekte in diesem Kontext, viele existierende Teile unserer heutigen Infrastruktur, da gibt es gute Gründe dafür, warum man nicht einfach die Sprache wechseln kann. Aber für uns gibt es eigentlich keine Ausrede mehr. Es ist das andere, was ihr noch seht, als jemand, der sich mit Programmiersprachen beschäftigt ist, um eine weitere Vergleich herzustellen. Wenn jeder, der in der Lage ist, ein Auto zu fahren, sich gleich als Experte im Automobil-Design ansehen würde. Es gibt eine eigene Wissenschaft, das Design von Programmiersprachen. Man kann spezifizieren, mathematisch präzise. Nicht nur die in den Sündtags, wie wir das in diesen Grammatiken mit der Bakus Nauer Form aus den 60ern hatten, sondern auch, wie sich diese Sprachen verhalten. Wir können also die Semantik und das Typsystem von diesen Sprachen spezifizieren. Und wir wissen, wie man mathematische Beweise führt und können beweisen, dass diese Sprachen konsistenz sind und dass wir gewisse Eigenschaften davon garantieren können und Aussagen machen können über die Programme, die man mit diesen Sprachen entwickelt. Und wenn wir das alles für JavaScript und C und PHP machen wollen, Gott hilft uns. Aber wir können sowas schon zu dem Zeitpunkt machen, wo wir Sprachen designen. Und wenn man das zu dem Designzeitpunkt macht, dann sieht man die Strukturen. Dadurch, dass man diese mathematische Spezifikation schreiben muss, wird man gezwungen, alle möglichen Randfälle zu betrachten. Man kann natürlich immer noch Fehler dabei machen. Aber man kann, sagen wir mal, so interessantere Fehler dabei machen. Jetzt gerade fangen die Leute an, sowas zu machen. Am ersten Tag gab es hier von Hannes und David hier ein Talk über System Software. Und was die hatten, wenn man das mit C vergleicht, das ist wie etwas, was von Windows gesandt wurde. Man hat eine WPeddy und seine Kollegen arbeiten sehr hart daran, System Software zu bauen, die funktioniert. Also, ich lehre an der Universität Cambridge und ich lehre auch über die Semantik von Programmiersprachen. Und meine Angst ist, dass ich irgendwann jemanden in die große Welt rauslasse, der irgendwann mal eine Skripsprache erfindet und diese Skripsprache dann zufälligerweise sehr populär wird. Und ich werde ihnen dann nicht erklären, was sie tun müssen oder was sie da verstehen müssen, denn da gibt es jede Menge Sachen, die ihr euch angucken könnt, Sachen, die andere Leute gemacht haben. Aber gehen wir mal in den Extremfall, wenn wir Software haben wollen, die tatsächlich funktioniert, dann sollten wir beweisen, dass sie korrekt ist. Das ist also was, was, Akademiker, speziell die, die sich in normalen Methoden befassen, die arbeiten daran, die halten sowas hoch, diese Idee, das schon seit Jahrzehnten, warum beweisen wir nicht einfach, dass unsere Programme korrekt sind. Und für einige Jahrzehnte war das nicht wirklich plausibel, als ich noch eine ganze Ecke jünger war, da war das eine ganz große Sache, dass man beweisen konnte, wenn man eine Linked-Liste benutzte und hat die zweimal in ihrer Reihenfolge umgedreht, dass man dann wieder dieselbe Liste rausbekam. Das war ganz schön schwierig zu beweisen. Aber ihr könnt euch vorstellen, dass wir das sowas nicht mit dem Linux-Körnel machen können. Aber wir können das erstaunlich oft mit kleineren Ausschnitten machen. Ich gebe euch mal ein paar Weispiele von modernen Verifikationswerkzeugen. Leute haben zum Beispiel diese Werkzeuge benutzt, um Compiler zu verifizieren. Und zwar alles von C ähnlichen Sprachen bis runter zu Assembler, aber auch funktionale und imperative Sprachen bis runter zu dem Binearmodell, wie ein Prozess, das sich dann verhält. Leute haben verifiziert, welche Optimisierungspfade der Compiler nimmt. Und teilweise ist dann die verifizierte Fassung sogar schneller, also das ist eine Win-Win-Situation. Und es wurden auch Hypervisors zum Beispiel formal bewiesen. Und auch kryptografische Protokolle wurden mathematisch bewiesen. Und da wurden diverse Annahmen natürlich gemacht, aber sinnvolle Annahmen über das darunter liegende mathematische Modell. Also wir können da schon eine ganze Menge machen. Ich muss natürlich vielleicht ein bisschen erklären, was ich mit dem Wort Beweis meine. Für manche Leute, die sich mit Computern befassen, wenn ich sage, ich beweise, dass etwas funktioniert, dann bedeutet es einfach nur, ich habe es ein bisschen getestet. Oder vielleicht noch extremer, es hat ohne Fehler kompiled. Für jemanden, der Programmanalyse betreibt, der nimmt sich dann vielleicht ein Analyse-Tool, was aber vielleicht aus einem etwas seltsamen Code geschrieben wurde und der macht dann irgendwelche Approximierungen. Also ich selber nenne das nicht wirklich Beweis. Ein Wissenschaftler benutzt das Wort Beweis eigentlich nicht, denn Wissenschaftler wissen, dass sie eigentlich keine Beweise machen. Sie machen kontrollierte Experimente, nicht mehr. Und daraus gewinnen sie dann Informationen, aufgrund deren sie Hypothesen aufstellen. Mathematiker, die schreiben Beweise. Diese Beweise sind im Grunde sehr grundlegende mathematische Argumente, die konsistent sind und dazu benutzt werden können, jemanden zu überzeugen, dass etwas so ist, wie man das behauptet. Aber was wir haben im Bereich der Computerwissenschaften, wir haben diese reichhaltigen mathematischen Strukturen nicht. Wir haben einen Riesenberg von dummen Artokannahmen und nicht diese schönen mathematischen Strukturen. Wir haben hunderte von Millionen Zeilen Code. Also damit kommen wir dann nicht wirklich weiter. Wenn wir das Wort Beweis nutzen wollen, dann das Einzige, was wir im Grunde machen können, ist, dass wir einen programmatischen Beweis führen können. Das heißt, wir brauchen also ein System, eine Maschine muss überprüfen, dass unser Beweis ein tatsächlicher Beweis ist. Also man kann sich von Maschinen ein bisschen helfen lassen. Manchmal wird es dadurch auch schwieriger, als ohnehin schon ist, aber da gibt es solche Systeme, HL4 und ähnliche, die man dazu benutzen kann. Und wenn wir diese Systeme benutzen, können wir beweisen, dass es einigen nicht trivialen Sachen gibt. Wir können nicht beweisen, dass ein Programm das macht, was wir von ihm wollen, aber zumindest, dass es eine Spezifikation erfüllt. Das können wir tun. Das ist ein bisschen trickreich. Also für diese Projekte hier, nach akademischen Standards sind das alles große Projekte. Da kann man zehn Leute für ein paar Jahre beschäftigen. Aber auf, sagen wir mal, nach Industriestandards sind das nicht wirklich große Projekte, aber man muss eine ganze Ecke Arbeit reinstecken. Es kann also tatsächlich ein paar Jahre dauern, bis man mit diesen Werkzeugen nicht umgehen kann. Und bisher, was bisher fehlt, ist noch so eine Art Bewegung, eine Open Source Zusammenarbeit. Vielleicht haben wir so was in fünf Jahren oder zehn Jahren. Ich weiß es nicht. Also wenn ihr auf der Suche nach einer Herausforderung seid, ist das eine für euch. Es ist wirklich schwer. Es ist auch nichts, was jetzt auf einmal euch eine Lösung geben würde für all die Probleme im Software- und Hardware-Design und der Software-Entwicklung. Also was können wir konkret tun, um die Qualität unserer Systeme zu verbessern? Das heißt, wir wollen ein bisschen diese mathematische Sauberkeit reinbringen, aber nicht so viel Arbeit damit haben. Also was wir machen können ist, wir können einige dieser Schnittstellen uns vornehmen und können sehr präzise sein, können sehr präzise darüber reden, was diese Schnittstellen machen. Wir müssen natürlich, im Grunde müssen wir eine Art Reverse Engineering betreiben, um erstmal die Spezifikationen überhaupt festzulegen. Aber wenn wir das machen, dann können wir das auf eine sehr viel sauberere Art und Weise machen. Und wir können dann auch Tests dafür schreiben und können in der Zukunft das sehr viel besser testen. Meine Kollegen haben das schon die letzten paar Jahre gemacht und ich will euch mal zwei kleine Sachen hier aufblitzen lassen, um euch mal zu zeigen, wie das funktioniert. Ich kann nicht zu sehr ins Detail gehen, aber hier arbeiten ganz offensichtlich eine ganze Reihe von sehr intelligenten Leuten zusammen und ein paar habe ich mal hier die Namen rausgeschrieben. Das da oben bin übrigens nicht ich, das ist die ganze Community, die daran arbeitet. Aber reden wir mal ein bisschen darüber, wie sich Prozessoren verhalten, also auf der Hardware-Ebene. Und dann reden wir noch ein bisschen darüber, wie sich TCP und Socket-Schnittstellen verhalten. Es gibt auch einige Ähnlichkeiten und auch einige Unterschiede zwischen diesen beiden Sachen. Multi-Prozessor-Systeme. Wahrscheinlich will jeder, dass seine Computer schnell arbeiten. Jeder will das. Das ist eine ganz offensichtliche Idee, auf die man kommen kann. Ein einzelner Prozessor kann nicht so schnell werden. Also verbinden wir mehrere Prozessoren miteinander und machen es so, dass die alle Prozessoren mit demselben Speicherbereich reden können. Das ist keine neue Idee, sondern das ist mindestens, also schon mal in 1962 gab es diese Ideen schon mal. Es gab damals den D825. Damals hatte der, glaube ich, zwei Prozessoren, die zu einem Speicherbereich Zugriff hatten. Es hatte also ganz erstaunliche Features für die damalige Zeit. Und das hat sich eigentlich bis heute, was ich bis heute nicht wirklich geändert hat, ist, dass die kompalten Sprachen dazu erweitert werden mussten, um all das auszunutzen. Also das ist schon 52 Jahre her, meine Güte. Okay, also wie verhalten sich diese Dinger? Ich, schauen wir mal, ich habe einmal ein Stückchen Code auf einer Hackerkonferenz gezeigt und ich will euch jetzt mal zwei Beispielprogramme zeigen. Es sind beides Programme mit jeweils zwei Threads, die auf zwei geteilten Variablen arbeiten. Und initial sind die also beide null. So, erstes Programm hier. In diesem Thread schreiben wir auf X und dann lesen wir Y. Und im anderen Thread schreiben wir auf Y und lesen dann X. Und diese Arbeiten verschränkt, sozusagen. Das heißt, es gibt also keine Synchronisierung zwischen diesen beiden Threads. Im Extremfall rennen wir den gesamten Thread null ab, bevor wir dann zu Schwert 1 kommen oder andersrum. Oder aber man macht erst eine Instruktion aus diesem Thread und dann aus dem anderen Thread. Also so oder so oder so. Also es gibt sechs verschiedene Arten, diese beiden Instruktionen, da beiden Threads auszuführen. Und in all diesen möglichen Ausführungsarten sieht man nie, dass das Read Y von dem Initialwert liest und Read X von dem Initialwert liest. Das sieht man also nie. Also was passiert, wenn man diesen Code wirklich ausführt, zum Beispiel auf meinem Laptop, zum Beispiel als Teil eines größeren Tests, dann sieht man manchmal nicht sehr oft, dass die Threads zuwilligerweise gut synchronisiert sind und jeder Thread liest das, was der andere reingeschrieben hat in die Variable. Sehr viel öfter sieht man, dass ein Thread komplett ausgeführt wird, bevor der andere überhaupt losläuft. Und manchmal sieht man, dass beide Threads null zurückgeben. Verdammt. Das ist doch irgendwie interessant. Okay, ich will euch noch ein weiteres Programm zeigen. Jetzt haben wir hier Thread Nr. 0, der schreibt jede Menge Daten, statt also eine ganze Menge Daten in X und dann setzt der, sagen wir mal, Y wäre ein Flag und er setzt dieses Flag um den anderen Thread zu signalisieren, dass die Daten jetzt gelesen werden können. Der andere Thread wartet bis Y das Flag gesetzt wird und liest dann X. Als Programmierer will man vielleicht eine Garantie haben, dass in dem zweiten Thread dieses Read X immer genau die Daten sieht, die bei einem ersten Thread reingeschrieben hat. Das wäre also so eine Art, dass man eine Message von einem Thread zu einem anderen weitergibt. Also wenn man das ausführt, nur auf einem X86 sieht man immer, dass X den Wert hat in der ersten Thread reingeschrieben hat. Also, der X86 führt diesen Code eigentlich ganz gut aus. Auf einem Arm und auf einem IBM Power Prozessor sieht man, dass manchmal das zweite Thread manchmal diesen Wert in der erste reingeschrieben hat, ignoriert. Und das ist also keine gute Messageweitergabe von Thread 1 zu Thread 2. Also was passiert hier? Dieses Verhalten ist vielleicht ein bisschen überraschend. Immer wenn man Überraschungsverhalten in einer Hardware sieht, dann hat man zwei Möglichkeiten. Entweder ist es ein Fehler in der Hardware und wir haben auch schon in der Hardware Fehler gefunden. So ist es nicht. Das ist immer eine schöne Sache, wenn man das findet. Oder man hat einfach die Erwartungen falsch gesetzt. Oder aber vielleicht ist auch der Test einfach falsch formuliert. Okay, was man dann so macht, man geht zu einem Prozessorarchitekt aus Vertrauens, von IBM oder von Arm. Wir haben mit einigen von diesen Leuten gearbeitet und man fragt, ist das hier ein Bug? Ist das ein Fehler? Und der Prozessorarchitekt ist eine Person, der sozusagen die Autorität hat zu entscheiden, ob das erwünschte Verhalten ist oder ein Bug. Das ist das, was diese Leute tun. Und meistens sagen sie, ja, das soll so sein. Das ist das erwartende Verhalten, das ist schon okay so. Wir haben, weil du und jeder andere wollte, dass die Prozessoren sehr, sehr schnell sind, haben wir jede Menge, jede Menge sehr cleverer Optimisierungen eingebaut. Wenn man sequenziellen Code laufen lässt, dann merkt man das überhaupt nicht. Aber wenn man etwas komplexeren Code, parallelläufigen Code ausführt, dann kann man die Effekte von dieser Optimisierung sehen. Und das ist also das beabsichtliche Verhalten. Und wenn man also Code schreiben will, mit Message-Weitergabe oder Sachen, die gegenseitig sich ausschließen, dann muss man spezielle Instruktionen einfügen, Speicherbarrieren. Und dann fragt man sich, was machen diese Dinger und man schaut das in der Dokumentation nach und dann sieht man sowas wie hier. Ich werde das mal vorlesen. Für jedes Paar A und B garantiert diese Speicherbarriere das A, genau dann ausgeführt wird, bevor B, das tut mir leider erst einfach zu schnell für mich im Augenblick. Ihr könnt das nachlesen auf den Folien und in Ruhe übersetzen. Habt ihr die Hand, wenn ihr verstanden habt, was das bedeutet? Hand hoch, wenn ihr das Gefühl habt, wenn ihr es in Ruhe lesen würdet oder vielleicht auch das ganze Buch, dass es verstehen würde. Hand hoch, der Menschen, der Menschen bitte, die denken, dass wir für immer verloren sind. Das tut mir sehr leid, aber nur die letzte Gruppe hatte tatsächlich recht. So, this looks like it really looks like so this looks like it really looks like so it really looks like... als ob es alles gut durchdacht ist und wir dachten das auch für eine lange Zeit und haben auch lange versucht, mathematische Modelle zu entwickeln. Irgendwann ist es dann doch rausgekommen, man kann es nicht machen. Es ist so unmöglich. So kann man es nicht durchführen. In so einem Fall muss man da etwas anderes machen, In dem Fall muss man ein Modell entwickeln. Es gibt ein fundamentales Problem, und zwar entwickeln wir das Software bei diesem Versuchen- und Fehlschlagprozess. Aber auf der anderen Seite haben wir diese eher losen Beschreibung, die durch mehrere Generationen von Prozeduren entstanden sind und sagen denen dann aber, sie müssen die Spezifikation benutzen. Aber die einzige Art, wie tatsächlich zu wissen, wie es am Ende rauskommen wird, ist tatsächlich durch das Laufenlassmann-Code, die das Verhältnis zwischen Beschreibung und tatsächlich Ausführen ist sehr illusionär. Man kann leider sein Programm nicht durch ein Buch herausfinden, sondern man muss tatsächlich die Hardware benutzen. Es ist ein ganz großes Problem. Was können wir dagegen tun? Das Beste, was wir dagegen tun können, ist empirische Wissenschaft. Wir könnten ein Modell einfach so in unserem Kopf entwickeln, indem wir versuchen, was für den Entwickler sichtbar ist, für ein Programmierer Entwickler ist. Wir können jetzt ein Werkzeug entwickeln, das Programme nimmt und dann ein Set von Verhalten, ausgibt, die erlaubt sind durch dieses Programm. Dann muss man das mit experimentellen Daten vergleichen und schauen, ob man das Modell vielleicht anpassen muss, um eine besser verheersergekraft produzieren zu können. Dann sollte man es vielleicht auch noch mit den Architekten der Architektur besprechen und dann auch noch die Korrektheit überprüfen. Und dann kann man noch einen vorn anfangen und weitermachen. Und dieses erfahren hat Modelle hervorgebracht, die vielleicht nicht unbedingt komplett richtig sind, aber nützlich. Nur um ein Beispiel zu zeigen, war ein kleines Auszug. So ein Modell ist eigentlich nur eine sehr abstrakte Maschine. Es hat eine thread-lokale Speicher und hier der gesamte Speicher kann für verschiedene threads hergegeben werden. Und das Modell hat dann verschiedene Listen und Sets, die dann überwachen, wo, wann, welche Daten sind. Das ist jetzt hier noch ein Beispiel. Wenn man quasi einen Schreibvorgang zu einem anderen thread übergeben möchte, dann gibt es verschiedene Aktionen und Abfolgen. Das ist nicht super kompliziert, aber man kann es sich aufschreiben. Es ist sehr präzise aufgeschriebener Text. Also man kann durch diese ganzen Punkte mit seinem Architektur, Freund gehen oder Experten. Die Definition kann man dann letztendlich in Mathematik machen, die dann furchtbar nah an Funktionalen kurz ist. Hier ist noch mal so ein Beispiel. Hier sind die drei Conditions von, die drei Bedingungen von Feuer. Wir können das nehmen, diese Mathematik. Und sie kompilieren. Und dann haben wir am Endo-Camel Bitecode und Ausführen. Für Batch-Shops. Und dann können wir diese OCamel in JavaScript umwandeln und dann ein Benutzer-Interface drauf machen. Und dann haben wir es auf einmal ein Web-Interface, was er erlaubt, dieses Modell wirklich kennenzulernen und zu erforschen. Das ist aber tatsächlich keine Raketenwissenschaft, das ist nicht kompliziert. Alles, was wir machen, ist zu spezifizieren, was die erwartete Verhalten, das erwartete Verfahren an dem System ist. Es ist noch nicht sehr technisch, aber es ist eine sehr besondere Art. Man kann eigentlich jede Sprache dafür benutzen, aber es ist einfach eine sehr seltene Sache, die viele Leute nicht machen. Man muss verstehen, dass es hier nicht darum geht, was zu implementieren, sondern dass es viel mehr darum geht, dass man, wenn man ein bestimmtes Verhalten sieht im Programm, ob man denkt, dass es eher das Verhalten, das man wünscht oder ein unerwünschtes Verhalten ist. Eine Schlüsselfrage für das ist auch, wie viel nicht der Terministisch tatsächlich in dem System ist oder wie lose die Spezifikation sind. Man kann natürlich immer eine Referenzimplementierung machen in der saubersten Sprache, die man kennt und dann vergleichen. Aber es hat einfach zu viel nicht der Terminismus und man kann das nicht machen. Zum Beispiel für TCP gibt es ganz viel nicht der Terminismus. Wir wissen ja hoffentlich all was TCP ist, es geht da um zuverlässig Verbindung. Wenn man sich den Standard für TCP anschaut, ist es auch so ein schrecklicher Text aus 1980 und dann schaut man sich den Code an und man findet einfach keinen Zusammenhang. Die Spezifikation definiert das Verhalten nicht und der Code macht das auch nicht so eindeutig. Das heißt, was wir eigentlich machen müssen, ist eine Spezifikation erstellen. Wir müssen also einen einzelnen Endpunkt nehmen, den beobachten und das Verhalten dann beschreiben. Wir müssen uns dann noch ein paar interne Debugging Vorfälle entscheiden und die dann in unser Verhaltensprofil aufnehmen und entscheiden, ob das richtig oder das schlechtes Verhalten ist und ob das aber wichtig ist, um das Verhalten zu beschreiben. Es gibt dann nicht der Terminismus, also zum Beispiel Variation zwischen Inputs und die, die das Programm aufgebaut ist. Das Problem ist auch häufig, dass man am Verhalten nicht gleich erkennen kann, was für interne Variabeln genutzt werden zum Beispiel bei TCP, weil das die Fenstergröße der Übertragung, die man erst dann erkennen kann, wenn das TCP Bruttdruckhol wirklich in vollem Einsatz ist. Damit das aber testbar ist, sollte man das eigentlich wissen. Es wäre viel einfacher, wenn man diese internen Variabeln wüsste und dann könnte man auch das Design und das Verhalten überprüfen. Das ist nur eine der vielen Regeln der Spezifikation, die wir da gemacht haben. Also, was hier wichtig ist, ist, dass es ganz klar strukturiert ist für Lesbarkeit und Verständlichkeit. Es geht hier nicht wirklich schnell zu arbeiten, sondern es geht darum, dass das wirklich präzise ist und gut lesbar und diskriminierendes Testen erlaubt. So, ich habe jetzt drei Dinge beschrieben, die man machen könnte. Das erste ist, verdammt nochmal, es ist no-brainer, es ist ganz einfach, benutzt, besser programmiert sprachen. Das zweite ist, also das ist die wirklich interessante Teil, wo man mit wenig Aufwand sehr große Erfolge zeigen kann. Und am besten macht man das schon während des Designs. Am besten geht hier darum, dass man reale Spezifikationen macht von Schlüsselabstraktionen. Das heißt, man sollte schon während des Designs überprüfen, dass das Verhalten irgendwie klar ist. Man sollte auch während man die Executable-Maus aufachten, dass man Testpunkte hast. Und das Ganze sollte auch im Design schon für Klarheit geschrieben sein, so dass man gleich versteht, was das Verhalten ist. Dass man die Komplexität gleich von vorne rein zeigt und nur falls auch darauf eingeht. Allein schon das Schreiben, dass das Ausschreiben aller möglichen Fälle, die dem Programm oder der Code treffen kann, dann muss man auch viel mehr darüber nachdenken und hat vielleicht dann auch eine bessere Idee, was die eigentlich im Planeton sein könnte. Auch das hier sollte man eigentlich nicht erwähnen müssen, es ist eigentlich eine Sache, die klar sein sollte, dass sie wichtig ist für gute Software. Und jetzt hier zur dritten Option. Und das sind die volle, formale Verifikationen von Schlüsselkomponenten. Und ich kann dir vorstellen, das ist dann quasi der Fall, in dem man mit einem komplett verifizierten Compiler und Hypervisor und TLS-Stack ein Programm hat, das dann schon auf Verifikation basiert, auf verifizierten Code basiert. Natürlich sind diese Methoden auch nicht anwandbar für alles. Wenn du zum Beispiel Word schreibst, muss das nicht unbedingt so geprüft sein. Aber umso wichtiger und vertrauenswürdiger die Aufgabe ist, umso eher muss man über solche Methoden nachdenken. Ist das ein neuer Morgen? Wenn man dann zurückdenkt, zum 1940, es war ziemlich dunkel damals, weil einfach das stabile, saubere Bauen von diesem System nicht von Anfang an möglich war, vielleicht könnte es sein, dass wir jetzt Blicklicht sehen und dass wir langsam Ideen bekommen, dass wir tatsächlich Modelle haben, die man wieder benutzen kann und dass wir tatsächlich auch einen guten Weg sind. Das ist natürlich erst der Beginn dieser Phase. Und dass es Qualitätskontrolle gibt und richtiges Software-Engineering auf Mathematik. Man darf aber nicht vergessen, dass wir keine Chance haben. Es kann von hier nur noch schlimmer werden. Man kann sich schon jetzt vorstellen, viele haben sich das bestimmt schon gemacht. Ich hoffe, ihr habt alle gestern den Talk auf den Apple Bootloader gesehen. Das ist basierend auf einem Feature, was damals in den 80ern eingeführt wurde. Jetzt müsst ihr euch einfach überlegen, in 100 Jahren von jetzt, solange die Menschen diese Zivilisation sich weiterentwickeln, die x86-Architektur und die Socket-API, wird in 100 Jahren in einem riesigen Stack von Virtualisierung für immer versteckt sein. Und all diese Fehler werden uns dann weiter begleiten. Vielen Dank an allen meinen Kollegen, mit denen ich mit mir gearbeitet habe. Ich möchte auch gerne unseren Spendern oder danken. Vielen Dank. Vielen Dank für diese interessanten Einsichten in unserer Art des Programmierens. Wir haben jetzt eine Frage-Anfahrt-Sektion. Also, falls ihr jetzt den Raum verlasst, seht ihr, dass ihr es leise macht und auch so schnell wie möglich. Wir wollen jetzt auch ein bisschen Frage und Antwort machen. So, was sind die Fragen? So, microphone 4 bitte. Hallo, danke für den tollen Talk. Wenn ihr ein Oracle bekommt, was die korrekte Eingabe zur Ausgabe ausgibt, wie kann das weniger fehlerhaft sein als die tatsächliche Implementierung? Das ist eine gute Frage. Ein solches Oracle muss den Output nicht produzieren. Es soll nur prüfen, dass input und output zusammenpassen. Und der zweite Punkt ist, im Allgemeinen hat es so, was zwar schon dieselbe Komplexität, aber dieses so ein Oracle soll sauber programmiert sein und nicht auf Geschwindigkeit optimiert sein. Das heißt, man hat eine komplett andere Struktur in dem Programm. Die Struktur einer echten Implementierung muss schnell sein und muss sehr viele komplizierte, miteinander verwobene Sachen machen. Und das erzeugt da eine ganz... eine zusätzliche Komplexität. Und das hat so ein Oracle nicht. Microphone 3, bitte. Ich wollte fragen, ob Sie mal darüber nachgedacht haben, ob Sie schon mal darüber nachgedacht haben, zu manipulieren, die abstrakten Sint-Tux direkt zu editieren, um dann Fehler schon beim Komplieren zu vermeiden. In der grand scheme of things, I think that's a very big thing. Großen Ganzen ist das eigentlich keine große Sache. Leute, die an strukturierten Editorien gearbeitet haben für viele Jahre, für die ist es keine große Sache, denn es ist sehr einfach für einen Compiler so was zu erkennen. Und es ist auch sehr leicht für einen Compiler, zum Beispiel Typfehler zu erkennen, selbst wenn man ein sehr komplexes Typ-System hat. Nur, dass das nicht... Ja, einige Leute finden das vielleicht hilfreich, aber es bringt uns im Großen Ganzen nicht weiter. So, noch ein paar Fragen aus dem IRC, von dem Signalengel. Das ist eine Frage. Das ist eine Frage. Das Repository ist so... Also Perry... What about them? I'm not quite sure what the question is, really. Ich glaube, ich habe die Frage nicht richtig verstanden. Es gibt einen Repository für dieses Isabel-System. Das heißt, the Archive of Form and Proof. Es ist nicht so, dass es keine Open Source Repositories gäbe. Also, ich kenne zum Beispiel auch eins. Und ich glaube, es ist Open Source. Aber es gibt nicht so wirklich eine Open Source Community, die das alles baut. Es ist immer noch so ein bisschen eine akademische Geschichte, und es kommt von den Unis. Micron 2, bitte. Hallo. Danke nochmal für den Talk. Ich wollte nur kurz was hinzufügen, was du nicht direkt das Ursus hast. Und zwar, dass wir dringend mehr neue Studien brauchen. Es gibt häufig viele Experten sagen genau das Gegenteil. Die sagen immer, Objektorientiers wollen wir nicht schlecht. Wir brauchen Funktionales programmieren. Ich denke, da ist schon Wahrheit drin. Aber wir brauchen viel mehr Studien, indem wir diese Behauptungen auch überprüfen. In anderen Felden, zum Beispiel Medizin, wenn da einfach jemand kommt und irgendwas behauptet, dass hier mal jemand im Opel funktioniert, dann glauben wir den normalerweise nicht, sondern wir machen Tests und Experimente und überprüfen das. Ich denke, wir sollten einfach weniger Mythen produzieren und die Tests, Mythen wie Statische, Typsystem, Impressor, gute Programmierungen sind produktiver. Ich finde nicht, dass das unserem Feld hilft. Ja, wieder im Großen und Ganzen hast du wahrscheinlich recht. Aber Informatik ist fast dahin ein Zweig der Psychologie oder Soziologie. Wir versuchen zu verstehen, wie eine große Gruppe von Leuten zusammenarbeiten kann, um eben ein Projekt fertig zu führen. Wäre es gut, wenn wir Beweise hätten, das in Sprache A zu programmieren, Beste ist, als in Sprache B zu programmieren? Ja, das wäre wahrscheinlich gut. Aber es ist um echte Experimente dazu durchzuführen, das ist unheimlich schwer. Man kann vielleicht für eine kleine Gruppe da so ein paar Experimente durchführen, aber ein paar diese Dinge, die ich gesagt habe, wenn jemand sich auskennt mit den verschiedenen Möglichkeiten, die man hat, dann gibt es manchmal sehr offensichtliche Gründe, warum diese Leute diese Sprache für ihre Programmierung benutzen. Es ist nicht so, dass jemand sagt, hey, Homöopathie ist funktioniert, sondern das Argument ist eigentlich, Homöopathie ist funktioniert nicht. So, Frage vom Mikrofon 5, bitte. Haben Sie zum Testen einen ECC-Ram benutzt? Das ist ein bisschen... Sehr gerne. Noch mal bitte. Haben Sie ECC-gebufferten Ram benutzt für ihre Resultate genutzt? Sogar selbst, wenn Sie das gemacht haben, könnte es ja auch einfach sein, dass es ein Bitflip jede Minute gibt, dass das schon das Ergebnis beeinflussen kann. Vielleicht müssen wir auch einfach machen, dass es ein Bitflip jede Minute gibt, dass das schon das Ergebnis beeinflussen kann. Wir müssen auch einfach mal anfangen, daran zu arbeiten, dass wenn etwas falsch geht auf einem niedrigen Level, dass wir da irgendwie schaffen, die Fehler zu noch abzufangen. Also, ich denke, es ist auch wichtig, gutes Ingenieurarbeit oder Design auf dem niedrigen Level zu machen, aber ich glaube nicht, dass das unbedingt hilft, das alles zu beweisen. Letztendlich sind Computerphysikalische Maschinen, die haben Fehler einfach aufgrund der Physik. Ja, das stimmt natürlich, dass es solche zufälligen Fehler manchmal gibt. Ich würde sogar argumentieren, dass man die Physik gut genug modellieren muss und man muss auch die Statistiken, die Wahrscheinlichkeiten, auch modellieren können. Das ist sicherlich notwendig und auch wichtig, aber wenn man sich diese Statistiken anschaut, die du gerade erwähnt hast, der Hauptgrund, warum Systeme Fehler haben und zusammenbrechen, das ist nicht der Hauptgrund. Wichtig, ja, das Wichtigste, aber worauf wir unsere Aufmerksamkeit richten sollten, ist das sicher nicht. Microphone 6, bitte. Hallo. Ich denke wirklich, das, was du vorschlägst oder was Sie vorschlagen, das ist sehr wertvoll wäre, Schlüsselkomponente besser zu evaluieren, aber wie stellt man sicher, dass die Spezifikationen dann letztendlich, die man dann neu schreibt, passen zu dem, was man erwartet? Na ja, wie ich beschrieben habe, wir machen als partielle Verifizierung, machen wir eine ganze Reihe Tests gegen die Implementierung oder gegen mehrere Implementierungen. Das ist eine weitere Art, das zu validieren ist, man redet eben mit den Architekten, mit den Designern und man will ja, dass die interne Struktur, das tut, was der Designer beabsichtigte. Eine weitere Validierung, die wir machen, ist, wir beweisen bestimmte Eigenschaften. Wir beweisen zum Beispiel, dass man mit einem, von einem mathematischen Modell, z.B. C++-11-Qualcode runterkompilen kann, auf IBM PowerPC Sprache. Nichts von alledem gibt dir eine 100-prozentige Garantie, aber das behaupten wir auch nicht, aber es gibt einem schon eine ziemlich gute Sicherheit. Micron 4, bitte. Noch mal vielen Dank. Sie haben vorgeschlagen, zufällige Tests zu machen. Ich finde allerdings, dass es schwierig ist, dass Teste haben, die nur manchmal Fehler verursachen und ich hätte viel lieber Tests, die sich an Bug produzieren. Wie schaffen wir es, das zu kombinieren Reproduzierbarkeit und Varianz in Imputdaten? Naja, wenn, was würde das TSP-Geschichte z.B., das Problem mit dieser Reproduzierbarkeit ist genau diese Indeterminismus, der da innen drin herrscht. Und man kann nicht wirklich sehen, was da vor sich geht, oder das Programm, was es überprüft, kann das nicht sehen. Also, was man machen kann, ist, man kann das Protokoll so designen, dass das eben adressiert wird. Die andere Sache über solche ganz allgemeinen Spezifikation, als Testprotokoll zu benutzen, ist, manchmal muss es nicht unbedingt reproduzierbar sein. Die Spezifikation gibt eine klare Antwort, ja oder nein, für einen bestimmten beliebigen Test und das bedeutet, dass man auch beliebige Tests nehmen muss. Und diese Unterschiede nachher herauszufrieren, das ist wahrscheinlich ziemlich tricky, aber... So, wir haben jetzt noch Zeit für zwei weitere Fragen. Mikrofon 1, bitte, Zest. Noch mal vielen Dank für den tollen Talk. Was Sie beschreiben haben, scheint ein Mittel zwischen formaler Verifikation und mehr praktikablen Tests zu sein. Wo sehen Sie die formalen Applikation? Denken Sie, wir werden irgendwann, man wird sich in der Mitte treffen oder was, was haben Sie da? Denken Sie da? Das ganze Thema der formalen Verifikation, wenn man sich das anguckt, über die letzten zehn Jahre ungefähr, das ist erstaunlich, wenn man das mit dem Vergleich, was wir noch in den 80ern und 90ern machen konnten. Das heißt also, der ganze Scope dieser ganzen Sachen, auf einmal wird es möglich für uns diese Verifikation zu machen und welche Programme wir verifizieren können, das wird immer mehr, wir können immer komplexere Sachen verifizieren. Wann man ein komplett verifizierten, sagen wir mal, Talkline haben werden, das kann ich nicht vorhersagen, aber so ganz unvorstellbar ist es nicht. Vor 20 Jahren hätte man das nicht vorstellen können, aber das Ganze wird also mehr, aber zur gleichen Zeit sehen wir viel mehr von diesen Spezifikationen, die auf einem Testoragel basieren. Wenn man ein Teil eines Systems verifiziert, dann muss man eben auch die Schnittstellen sehr gut definiert haben, damit das alles zusammenpasst. Noch die letzte Frage von Mikrofon 2, bitte. Hallo. Wir haben erwähnt, dass Sie häufig Bugs in den Hardware finden. Gibt es irgendeinen Grund, das vielleicht auch auf physischen Level zu machen? Ja, das ist eine ganz eigene Welt. Das war nicht so richtig mein Thema heute, aber die großen Prozessorhersteller haben eigene Teams, die daran arbeiten und viele davon beschäftigen sich mit diesen verhaltenen Prozessoren und was sie auch machen. Das ist auch sehr spektakulär, was sie machen, wenn man es noch mal vergleicht mit dem, was sie vor 10 Jahren ungefähr gemacht haben. Es gibt also Firmen, die komplette Ausführungseinheiten formal verifizieren und da ist jede Menge Arbeit reingesteckt worden. Und die Hardware aus ganzes wird vielleicht nicht verifiziert, aber die Beschreibung, dass die zu einer Low-Level-Beschreibung passt, das wird verifiziert und da wird ganz, ganz viel Arbeit reingesteckt. Noch mal vielen Dank für diesen tollen Tag. Noch bitte eine Runde Applaus und vielen Dank, Peter.