Frage

Als ich einem Kollegen den Unterschied zwischen der Strenge von Sprachen und Paradigmen erklärte, behauptete ich schließlich:

    Tolerante Sprachen wie dynamische und interpretierte Sprachen werden am besten für Prototypen und kleine Projekte oder mittelgroße Webanwendungen verwendet.Bei der Auswahl eleganter dynamischer Sprachen wie Python oder JavaScript mit Node.js sind die Vorteile: Schnelle Entwicklung, Reduzierter Boilerplate-Code, Fähigkeit, junge, kreative Programmierer anzuziehen, die „Unternehmenssprachen“ wie Java entfliehen. Statisch typisierte/kompilierte Sprachen eignen sich am besten für Anwendungen, die eine höhere Strenge erfordern, wie z. B. geschäftskritische Apps oder Apps für mittelgroße bis große Apps. Bekannte Paradigmen und Muster, die über Jahrzehnte entwickelt wurden, Einfache statische Überprüfung, Fähigkeit, viele professionelle Entwickler mit jahrzehntelanger Erfahrung zu finden. Strenge Sprachen wie Haskell, Ada oder Techniken wie Code Contracts in C# sind besser für Systeme, die Sicherheit gegenüber Flexibilität bevorzugen (auch wenn Haskell extrem flexibel sein kann), wie z. B. lebenskritische Systeme und Systeme, von denen erwartet wird, dass sie extrem stabil sind.Die Vorteile sind: Fähigkeit, so viele Fehler wie möglich zur Kompilierzeit zu finden, Einfache statische Überprüfung, Einfache formale Beweise.

Wenn ich mir jedoch die Sprachen und Technologien ansehe, die von großen Unternehmen für Großprojekte verwendet werden, scheint meine Behauptung falsch zu sein .Beispielsweise wird Python erfolgreich für große Systeme wie YouTube oder andere Google-Anwendungen verwendet, die ein wichtiges Maß an Strenge erfordern.

Gibt es noch einen Zusammenhang zwischen dem Umfang des Projekts und der Strenge der zu verwendenden Sprache/des Paradigmas?

Gibt es einen dritten Faktor, den ich vergessen habe zu berücksichtigen?

Wo liege ich falsch?

War es hilfreich?

Lösung

Ein interessantes Fallstudie zu Skalierungsprojekten, die dynamische und interpretierte Sprache verwenden, findet sich in Anfang Scala von David Pollak.

Ich begann nach einer Möglichkeit zu suchen, den Code in meinem Gehirn einfacher und direkter auszudrücken.Ich habe Ruby und Rails gefunden.Ich fühlte mich befreit.Ruby erlaubte mir, Konzepte in viel weniger Codezeilen auszudrücken.Rails war so viel einfacher zu verwenden als Spring MVC, Hibernate und die anderen „stromlinienförmigen“ Java-Webframeworks.Mit Ruby und Rails konnte ich in kürzerer Zeit viel mehr von dem ausdrücken, was in meinem Kopf vorging.Es war ähnlich wie die Befreiung, die ich empfand, als ich von C++ zu Java wechselte...

Als meine Ruby- und Rails-Projekte über ein paar tausend Codezeilen hinauswuchsen und ich Teammitglieder zu meinen Projekten hinzufügte , wurden die Herausforderungen dynamischer Sprachen deutlich.

Wir verbrachten mehr als die Hälfte unserer Programmierzeit mit dem Schreiben von Tests, und ein Großteil der Produktivitätsgewinne, die wir sahen, gingen beim Schreiben von Tests verloren .Die meisten Tests wären in Java unnötig gewesen, da die meisten von ihnen darauf ausgerichtet waren, sicherzustellen, dass wir die Aufrufer aktualisiert haben, wenn wir den Code umgestaltet haben, indem wir Methodennamen oder Parameterzahlen geändert haben.Außerdem stellte ich fest, dass bei der Arbeit in Teams, in denen es zwischen zwei bis vier Teammitgliedern Gedankenverschmelzungen gab, die Dinge in Ruby gut liefen, aber als wir versuchten, neue Mitglieder in das Team zu bringen, waren die mentalen Verbindungen schwer auf neue Teammitglieder zu übertragen .

Ich suchte nach einer neuen Sprache und Entwicklungsumgebung.Ich suchte nach einer Sprache, die so ausdrucksstark wie Ruby, aber so sicher und performant wie Java ist...

Wie Sie sehen, stellten sich die größten Herausforderungen bei der Projektskalierung für den Autor in der Testentwicklung und im Wissenstransfer heraus.

Insbesondere geht der Autor in Kapitel 7 näher auf die Unterschiede beim Schreiben von Tests zwischen dynamisch und statisch typisierten Sprachen ein.

Why the Lucky Stiff... führt einige von Rubys Metaprogrammierungskonzepten in Dwemthy's Array ein, in dem ein Hase gegen eine Reihe von Kreaturen kämpft.N8han14 hat das Beispiel aktualisiert, damit es in Scala funktioniert ...

Im Vergleich zum Ruby-Code waren die Bibliotheksteile des Scala-Codes komplexer.Wir mussten viel Arbeit leisten, um sicherzustellen, dass unsere Typen korrekt waren.Wir mussten die Eigenschaften von Creature in den Klassen DupMonster und CreatureCons manuell umschreiben.Das ist mehr Arbeit als method_missing. Wir mussten auch eine Menge Arbeit leisten, um die Unveränderlichkeit unserer Kreaturen und Waffen zu unterstützen.

Andererseits war das Ergebnis viel leistungsfähiger als die Ruby-Version.Wenn wir Tests für unseren Ruby-Code schreiben müssten, um zu testen, was uns der Scala-Compiler zusichert, bräuchten wir viel mehr Codezeilen.Zum Beispiel können wir sicher sein, dass unser Hase keine Axt führen konnte.Um diese Zusicherung in Ruby zu erhalten, müssten wir einen Test schreiben, der sicherstellt, dass der Aufruf von |^ auf einem Rabbit fehlschlägt.Unsere Scala-Version stellt sicher, dass nur die für eine bestimmte Kreatur definierten Waffen von dieser Kreatur verwendet werden können, was in Ruby viel Reflexion zur Laufzeit erfordern würde ...


Wenn man das oben Gesagte liest, könnte man denken, dass das Schreiben von Tests unerschwinglich umständlich werden könnte, wenn Projekte noch größer werden.Diese Argumentation wäre falsch, wie Beispiele erfolgreicher sehr großer Projekte belegen, die in dieser Frage erwähnt wurden ("Python wird erfolgreich für ... YouTube verwendet").

Die Skalierung der Projekte ist nicht wirklich einfach.Sehr große, langlebige Projekte können sich verschiedene Testentwicklungsprozesse "leisten", mit Testsuiten in Produktionsqualität, professionellen Testentwicklungsteams und anderen schwergewichtigen Dingen.

Youtube-Testsuiten oder Java-Kompatibilitätskit leben sicher ein anderes Leben als Tests in einem kleinen Tutorial-Projekt wie Dwemthy's Array .

Andere Tipps

Deine Behauptung ist nicht falsch.Sie müssen nur etwas tiefer graben.

Einfach gesagt, große Systeme verwenden mehrere Sprachen, nicht nur eine Sprache.Es kann Teile geben, die mit "strikten" Sprachen erstellt wurden, und es kann Teile geben, die mit dynamischen Sprachen erstellt wurden.

Was Ihr Google- und YouTube-Beispiel betrifft, so habe ich gehört, dass sie Python hauptsächlich als "Klebstoff" zwischen verschiedenen Systemen verwenden.Nur Google weiß, womit diese Systeme aufgebaut sind, aber ich wette, dass viele der kritischen Systeme von Google mit strengen und "Unternehmens"-Sprachen wie C++ oder Java oder vielleicht etwas, das sie selbst erstellt haben, wie Go, gebaut werden.

Es ist nicht so, dass Sie keine toleranten Sprachen für große Systeme verwenden können.Viele Leute sagen, dass Facebook PHP verwendet, aber sie vergessen zu erwähnen, dass Facebook extrem strenge Programmierrichtlinien erstellen musste, um es in diesem Umfang effizient zu nutzen.

Also ja, bei Großprojekten ist ein gewisses Maß an Strenge erforderlich.Dies kann entweder auf die Strenge der Sprache oder des Frameworks oder auf Programmierrichtlinien und Codekonventionen zurückzuführen sein.Man kann sich nicht einfach ein paar Hochschulabsolventen schnappen, ihnen Python/Ruby/JavaScript geben und von ihnen erwarten, dass sie Software schreiben, die sich für Millionen von Benutzern eignet.

Meine Erfahrung mit großen Systemen ist, dass sie nicht mit der Wahl der Sprache stehen oder fallen, sondern mit Fragen des Designs/der Architektur oder der Testabdeckung .Ich hätte lieber ein talentiertes Python-Team für mein großes Unternehmensprojekt als ein mittelmäßiges Java-Team.

Allerdings muss jede Sprache, mit der Sie deutlich weniger Code schreiben können, einen Blick wert sein (z. B. Python vs. Java).Vielleicht liegt die Zukunft in cleveren, statisch typisierten Sprachen mit fortgeschrittener Typinferenz (z. B. in der Scala-Form).Oder Hybrid, wie C # es mit seinem dynamic-Qualifizierer versucht ...?

Und vergessen wir nicht den "anderen" statischen Typisierungsvorteil: richtige IDE-Codevervollständigung/intellisense, was meiner Meinung nach ein wesentliches Feature ist, kein Nice-to-have.

Es gibt zwei Arten von Fehlern, auf die geprüft werden muss: Tippfehler (Verkettung einer Ganzzahl + Liste von Gleitkommazahlen) und Geschäftslogikfehler (Geld auf ein Bankkonto überweisen, prüfen, ob das Quellkonto Geld hat).

Der "dynamische" Teil einer dynamischen Programmiersprache ist genau der Ort, an dem die Typprüfung stattfindet.In einer „dynamisch typisierten“ Programmiersprache erfolgt die Typprüfung während der Ausführung jeder Anweisung, während in einer „statisch typisierten Sprache“ die Typprüfung zur Kompilierzeit erfolgt.Und Sie können einen Interpreter für eine statische Programmiersprache schreiben (wie es Einschreiben tut), und Sie können auch einen statischen Compiler für eine dynamische Programmiersprache schreiben (wie es gcc-python oder Schuppenhaut tut).

In einer dynamischen Programmiersprache wie Python und Javascript müssen Sie Komponententests nicht nur für die Geschäftslogik des Programms schreiben, sondern auch, um zu überprüfen, ob Ihr Programm keine Syntax- oder Typfehler aufweist.Wenn Sie beispielsweise "+" eine ganze Zahl zu einer Liste von Gleitkommazahlen hinzufügen (was keinen Sinn macht und einen Fehler ausgibt), wird in einer dynamischen Sprache der Fehler zur Laufzeit ausgelöst, während versucht wird, die Anweisung auszuführen.In einer statischen Programmiersprache wie C++, Haskell und Java wird diese Art von Typfehler vom Compiler abgefangen.

Eine kleine Codebasis in einer dynamisch geprüften Programmiersprache lässt sich leichter nach Tippfehlern durchsuchen, da es einfacher ist, einen 100%-Abdeckung-Quellcode zu haben.Das war's, Sie führen den Code ein paar Mal von Hand mit unterschiedlichen Werten aus und fertig.Eine 100%ige Abdeckung des Quellcodes gibt Ihnen einen guten Hinweis darauf, dass Ihr Programm möglicherweise nicht über Tippfehler verfügt.

Mit einer großen Codebasis in einer dynamisch überprüften Programmiersprache ist es schwieriger, jede Anweisung mit jeder möglichen Typkombination zu testen, insbesondere wenn Sie nachlässig sind und eine Funktion schreiben, die je nach Argumenten einen String, eine Liste oder ein benutzerdefiniertes Objekt zurückgeben kann.

In einer statisch geprüften Programmiersprache fängt der Compiler die meisten Typfehler zur Kompilierzeit ab.Ich sage am meisten, weil ein Division-durch-Null-Fehler oder ein Array-out-of-bounds-Fehler ebenfalls Typfehler sind.

Meistens dreht sich die eigentliche Diskussion nicht um Programmiersprachen, sondern um die Menschen, die diese Sprachen verwenden.Und das ist wahr, weil zum Beispiel die Assemblersprache so leistungsfähig ist wie jede andere Programmiersprache, aber wir schreiben Code auf JavaScript.Wieso den?Weil wir Menschen sind.Erstens machen wir alle Fehler und es ist einfacher und weniger fehleranfällig, ein spezielles Tool zu verwenden, das auf eine bestimmte Aufgabe spezialisiert ist.Zweitens gibt es eine Ressourcenbeschränkung.Unsere Zeit ist begrenzt, und das Schreiben von Webseiten über die Montage würde ewig dauern, bis sie fertig sind.

Eine weitere Überlegung ist , wer hinter dem Schreiben umfangreicher Anwendungen steht.Ich habe an vielen Stellen gearbeitet, die Ruby oder Python für einige große Projekte im Unternehmensstil verwenden wollten, aber immer wieder von IT-Managern und Sicherheitsteams des Unternehmens "abgeschossen" wurden, gerade wegen der Open-Source-Natur der Projekte.

Mir wurde gesagt: "Wir können Ruby on Rails nicht verwenden, weil es Open Source ist und jemand dort Hacks einfügen könnte, die kritische oder geschützte Informationen stehlen."Es tut mir leid, aber sobald jemand diese Denkweise hat, dass Open Source == böse ist, ist es fast unmöglich, sie zu ändern.Diese Denkweise ist eine Unternehmenskrankheit.

C# und Java sind vertrauenswürdige Sprachen mit vertrauenswürdigen Plattformen.Ruby und Python sind keine vertrauenswürdigen Sprachen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
scroll top