Einführung

TypeScript ist JavaScript das skaliert. Eine Sprache, die designt ist, komplexe Anwendungsfälle umzusetzen. Es erlaubt das Schreiben von JavaScript mit Typen, die bei dem Kompilieren geprüft und entfernt werden. Diese dadurch entstehende Typensicherheit erlaubt das einfachere Schreiben und Warten von komplexen Anwendungen. Genau das ist unter anderem, was TypeScript so populär gemacht hat: Es erlaubt das Finden von Fehlern im Code insbesondere in großem Maßstab viel schneller und einfacher als würde das mit reinem JavaScript möglich sein - und arbeitet dabei nicht gegen, sondern mit JavaScript.

Deepkit ist TypeScript das skaliert. Ein Framework geschrieben in TypeScript für TypeScript, das designt ist, sehr komplexe Software in TypeScript zu entwickeln. Es bringt viele Design-Muster bekannt aus den Enterprise zu TypeScript und führt komplett neue Features ein, die so nur mit TypeScript’s neuem Typensystem möglich sind, um so die Entwicklungsgeschwindigkeit vor allen in Teams zu erhöhen. Auch kleine Anwendungen können von diesem neuen Ansatz profitieren, da Deepkit viele Libraries für sehr gängige Anwendungsfälle mitbringt, die einzeln oder in Kombination genutzt werden können. Das Framework selbst ist dabei so agil wie möglich und komplex wie nötig designt, um nicht nur schnell erste Ergebnisse zu erhalten, sondern auch langfristig die Entwicklungsgeschwindigkeit aufrechtzuerhalten.

JavaScript ist mittlerweile die größte Entwicklercommunity weltweit und liefert dem Entwickler eine entsprechend große Auswahlmöglichkeit von vielen Libraries und Tools, um die Bedürfnisse eines Projektes abzudecken. Dabei ist es nicht immer ganz einfach, die richtige Library zu finden. Oft unterscheiden sich die Philosophien, API und Code-Qualitäten dieser so stark, dass viel Klebecode und zusätzliche Abstraktionen vom Entwickler eingeführt werden müssen, damit diese Libraries überhaupt untereinander einwandfrei funktionieren. Das Bereitstellen von Kernfunktionen, die so gut wie jedes Projekt benötigt, in schön abstrahierten Libraries zusammengeführt in einem Framework durch eines Herstellers beziehungsweise einer Community hat sich in den letzten Jahrzehnten immer wieder bewährt: Java Spring, PHP Symfony/Laravel, und C++ QT sind nur einige sehr bekannte und erfolgreiche Beispiele dazu. Diese Frameworks bieten dem Entwickler oft weit verbreitete und jahrzehnte bewährte Konzepte, die in Libraries oder Komponenten umgesetzt sind, um so bequem untereinander harmonierend bedarfsgerecht angewendet werden zu können. Die angebotene Funktionalitäten und Design-Patterns sind dabei nicht gewürfelt, sondern basierend auf mitunter über jahrzehnte alte Konzepte, die sich durch den Kampf im Wettbewerb mit alternativen Ideen bewährt haben.

JavaScript hat über die Jahre hinweg massive Fortschritte verzeichnet, sodass mittlerweile auch immer mehr Design-Muster aus dem Enterprise-Umfeld angewendet werden können. Design-Muster, die sich vermehrt in immer mehr Libraries, Framework, und Tools finden lassen. Dabei hat JavaScript und auch TypeScript jedoch das Problem, dass um viele bewährte Enterprise-Muster effizient anzuwenden, entscheidende Funktionen in der Sprache selbst fehlen. Das heisst nicht, dass diese Design-Muster generell nicht angewendet werden können, sondern dass diese weniger effizient als in anderen aktuellen Sprachen sind.

TypeScript entfernt bei der Kompilierung, sobald TypeScript in JavaScript umgewandelt wird, seine Typeninformationen vollständig, sodass keine Informationen darüber in dem erzeugten JavaScript oder zur Laufzeit existiert. Es ist unstrittig, dass Typen sehr wertvoll während der Entwicklung und beim Prüfen der Korrektheit des Programs sind. Typen haben jedoch auch einen enormen Wert zur Laufzeit. Dieser Wert spiegelt sich da wider, wo zur Laufzeit Daten umgewandelt (konvertiert/serialisiert), Daten validiert, Meta-Informationen an Objekte hinzugefügt, oder Interface-Informationen benötigt werden. Bei diesen und vielen anderen Anwendungsfällen können Typeninformationen zur Laufzeit sehr nützlich sein, da sie den Libraries die notwendigen Informationen zu verfügung stellen, um Funktionalitäten effizient bereitzustellen. Aktuell nutzen viele dieser Anwendungsfälle stattdessen Alternativen, die das Typensystem von TypeScript unvollständig nachahmen und den Entwickler zwingen, Typen auf eine neue Art und Weise zu schreiben, die mit der Syntax von TypeScript nichts mehr zu tun hat. Das Resultat ist, dass TypeScript’s mächtiges Typensystem hier nicht mehr seine Stärke ausspielen kann und weniger ergonomische und weniger effizientere Arbeitsweisen stattdessen genutzt werden müssen.

Deepkit Framework

Deepkit hat einen Type-Compiler entwickelt, der die Typen-Informationen bestehen lässt und es so erlaubt, zur Laufzeit dynamische Typen zu berechnen und existierende Typeninformationen zur Laufzeit auszulesen. Mit diesem Paradigmenwechsel sind komplett neue Arbeitsweisen möglich, die den genannten Anwendungsfällen die benötigten Informationen bereitstellen, die das Entwickeln von komplexer Software radikal vereinfachen, und dem Code mehr Aussagekraft verleiht. Es ist damit zum ersten mal möglich, die volle Stärke und Aussagekraft von TypeScript auch zur Laufzeit zu nutzen.

Basierend auf diesem Paradigmenwechsel hat Deepkit eine ganze Reihe von Libraries für Anwendungsfälle entwickelt, die in so gut wie jedem Program zu finden sind: Validierung, Serialisierung, Datenbank Abstraktion, CLI parser, HTTP Router, RPC Framework, Logger, Template-System, Event-System und vieles mehr. Der grundlegende Unterschied zu anderen Libraries ist, dass Typeninformationen im Zentrum der Funktionalität stehen und soviel TypeScript wie möglich zur Laufzeit wiederverwendet werden soll, sodass weniger Boilerplate vom Entwickler geschrieben werden muss und auch komplexen Programmen auf einen Blick anzusehen ist, was sie machen. Eines der Schlüsselfunktionen von TypeScript ist es schließlich, auch komplexem Code einen Ausdruck zu verleihen und Deepkit bringt diese Vorteile der Ausdrucksstärke in die Laufzeit in Form eines mächtigen Frameworks, um nun auch die Applikation-Architektur mit entsprechenden Enterprise-Patterns besser zu skalieren.

Deepkit besteht dabei aus zwei großen Bereichen: Zum einen die Deepkit Libraries und das Deepkit Framework. Die Deepkit Libraries sind eine ganze Familie alleinstehender TypeScript Libraries (NPM Pakete), die ein Thema gut können und optimiert, gut getestet, sowie ausgelegt sind, sich gegenseitig optimal zu ergänzen. Ein Projekt kann einzelne Deepkit Libraries benutzen, oder das gesamte Deepkit Framework, welches alle Fähigkeiten der Libraries zusammenbringt und durch zusätzliche Tools wie den Debugger ergänzt. Alles zusammen gesehen erlaubt es dem Entwickler komplexe, schnelle, und produktionsbereite Anwendungen zu entwickeln. Deepkit unterstützt dabei eine ganze Reihe von Anwendungsfällen. Von einfachen Command-Line Tools (CLI Programmen) zu Web-Anwendungen und Micro-Services bis hin zu Desktop- oder Mobile-Anwendungen. Dabei ist der Code so ausgelegt, dass er in jeder bekannten JavaScript-Engine läuft (Browser wie auch NodeJS) und sich wunderbar auch in andere Frameworks wie Angular, React, und Vue integrieren lässt. Der Anspruch hinter Deepkit Framework ist es Clean-Code, SOLID-Prinzipien, und Enterprise Design-Muster anzuwenden, um entsprechend hohe Code-Qualität nicht nur anbieten zu können, sondern dem User erlauben, diese ebenfalls anzuwenden. Auch versucht Deepkit in seiner Dokumentation und Beispielen dieselben Prinzipien zu bewerben, zwingt den Entwickler jedoch nicht, diese selbst zu verfolgen.

High-Performance

Eines der schwierigsten Probleme in der Software-Entwicklung ist es, eine hohe Entwicklungsgeschwindigkeit auch nach Monaten oder Jahren aufrechtzuerhalten, insbesondere, wenn der Code und das Team wachsen. Es gibt viele Frameworks, die einem einen schnellen Einstieg versprechen und mit denen man in kürzester Zeit auch alleine schon komplexere Anwendungen zusammenschraubt. Diese haben jedoch meist gemeinsam das Problem, dass die Entwicklungsgeschwindigkeit drastisch abnimmt umso älter das Projekt oder umso größer das Team wird. Hierbei ist es nicht selten, das selbst nach bereits wenigen Monaten und nur einer Handvoll Entwicklern die Entwicklungsgeschwindigkeit dermaßen einbricht, dass diese auf 1 % der ursprünglichen Geschwindigkeit abfällt. Um diesem Phänomen entgegenzuwirken ist es notwendig etablierte Design-Patterns anzuwenden und im Voraus das richtige Framework und Libraries zu verwenden. Enterprise Design-Patterns haben sich aus dem Grunde etabliert, da sie auch bei größeren Anwendungen und großen Teams exzellent skalieren. Korrekt angewendet entfalten sie ihre Fähigkeiten besonders dann, wenn ein Projekt über längere Zeit (mehrere Monate bis Jahre) entwickelt werden soll.

Design-Patterns haben zwar in der Theorie ihre Vorzüge, doch gibt es in der Praxis zu fast jedem Pattern auch seine Nachteile. Diese Nachteile sind unterschiedlich je nach Sprache und Framework ausgeprägt, da die Sprache und das Framework selbst festlegt wie ergonomisch ein Pattern angewendet werden kann. Nur weil ein bestimmtes Pattern in einer Sprache angewendet werden kann, bedeutet das nicht, dass man damit auch automatisch besser und schneller entwickelt. Manche Sprachen sind besser geeignet als andere, um gewisse Patterns anzuwenden. Mit JavaScript oder gar TypeScript selbst sind diverse Design-Patterns zwar oft im Kern nutzbar, doch gibt es hierbei Limitierungen, die die User-Experience und damit Schnelligkeit massiv beeinträchtigen. Zum Beispiel können Typescript-Decorators mit all seinen Eigenheiten notwendig werden, wenn ein Dependency Injection Framework dies so festlegt und darauf basiert. Deepkit stellt mit dem Runtime-Typensystem sicher, dass auf maximal ergonomische Art und so wenig Boilerplate wie möglich diese Design-Patterns angewendet werden können und schaltet damit ihre Kraft erst so richtig frei, sodass die hohe Entwicklungsgeschwindigkeit nicht nur initial, sondern auch langfristig aufrechterhalten wird.

Isomorphic TypeScript

Eines der größten Vorteile von TypeScript ist es, dass komplexer Code in vielen Anwendungsfällen besser geschrieben werden kann. Das schließt Frontend, Backend, CLI tools, Mobile und Desktop-Apps, und vieles andere ein. Wenn ein Projekt diese Anwendungsfälle umfasst und fast ausschließlich auf TypeScript setzt, nennt man dies Isomorphic TypeScript. Durch das Verwenden von TypeScript in soviel Code wie möglich kann massiv an Entwicklungsgeschwindigkeit zugelegt werden. So sind folgende Vorteile dann plötzlich vorhanden:

  • Code kann zwischen den Abteilungen geteilt werden (Frontend, Backend, Microservice, etc).

    • Models, Typen und Interfaces

    • Validation

    • Business logic

  • Ein einheitliches Audit-System eines einzigen Paketmanagers.

  • Wiederverwendung von bekannten third-party Libraries in allen Abteilungen.

  • Wissensteilung innerhalb der Teams.

  • Recruitment vereinfacht sich auf eine Gruppe (und auch noch die Größte: JavaScript-Entwickler).

Deepkit Framework und sein Runtime-Typensystem sind darauf ausgelegt diese und mehr Vorteile von Isomorphic TypeScript auf das äußerste auszunutzen, so dass seine maximale Kräfte zum Vorschein kommen.

Alte Vorgehensweisen wie der Dual-Stack (Frontend und Backend in verschiedenen Sprachen) können hier bei weitem nicht mehr mithalten, da alleine der Kontextswitch zwischen den Sprachen bereits enorm Energie und Zeit kostet. Alle weiteren Vorteile, die bereits erläutert wurden, lässt es sogar zu einem unfairen Vergleichen werden. Ein isomorpher Techstack wie TypeScript ist, richtig angewendet, auf fundamentaler Ebene um ein vielfaches schneller in der Entwicklungszeit als jede Kombination aus einem Dual-Stack für Backend/Frontend wie Java/JavaScript, PHP/JavaScript, oder gar JavaScript/JavaScript. Da eine höhere Entwicklungsgeschwindigkeit auch bedeutet für dieselben Features weniger Zeit zu benötigen, heisst das auch, dass Isomorphic TypeScript bares Geld einspart. Neben all den bereits vorgestellten Vorteilen ist dies das Killer-Argument, um Isomorphic TypeScript in all den nächsten insbesondere kommerziellen Projekten anzuwenden.