Select Page

NETWAYS Blog

The way to Go

Lange Zeit waren die Auftragnehmer der Raumfahrt große Rüstungskonzerne mit eingefahrenen Strukturen und dem entsprechenden Produkten. Die Raketen waren bspw. nicht gerade dazu gedacht, sie wieder zu verwenden. Wahrscheinlich konnte sich kaum einer der Auftraggeber vorstellen, dass das auch ganz anders geht. Und dann kam Elon Musk und hat “mal eben” SpaceX auf die Beine gestellt… und dann gingen viele Dinge auf einmal viel besser. So ähnlich auch in unserer Branche…
Lange Zeit gab es zwar maschinennahe Programmiersprachen, aber diese waren umständlich in der Handhabung – insbesondere im Hinblick auf die parallele Ausführung mehrerer Aufgaben. Die konstante Größe der Thread-Stacks limitierte zusätzlich die Anzahl der Threads, so dass bspw. das in C++ geschriebene Icinga 2 aktuell die E/A auf einige wenige Threads verteilen muss. Seit 2009 gibt es immerhin NodeJS, das gut und gerne viele E/A-Aufgaben parallel ausführt, aber auch nur diese – für Rechenoperationen steht nur ein Thread zur Verfügung. Zudem sind die Typen und Funktionen dynamisch und damit nicht so maschinennah und performant wie bspw. in C++. Und da saßen die Programmierer bis 2012 zwischen diesen zwei Stühlen. Und dann hat Google 2012 die erste stabile Version von Go veröffentlicht… und damit gingen viele Dinge auf einmal viel besser. So auch mittlerweile bei NETWAYS

Und was macht dieses Go jetzt besser als alle anderen?

Wie mein Kollege Florian sagen würde: “So einiges.” Aber Scherz beiseite…
Go ist maschinennah – d.h. die Typen und Funktionen sind allesamt statisch und werden wie auch bei bspw. C++ im voraus in Maschinencode umgewandelt – mehr Performance geht nicht.
Go ist einfach (obwohl es maschinennah ist). Die Datentypen sind zwar statisch, also explizit, aber deren Angabe ist nur so explizit wie nötig:

type IcingaStatus struct {
   Name, Description string
}
var IcingaStatusSet = map[uint8]IcingaStatus{
   0: {"OK",       "Alles im grünen Bereich"},
   1: {"WARNING",  "Die Ruhe vor dem Sturm"},
   2: {"CRITICAL", "Sämtliche Infrastruktur im Eimer"},
   3: {"UNKNOWN",  "Mein Name ist Hase, ich weiß von nichts"},
}

Im gerade gezeigten Beispiel muss der Datentyp der Map-Variable nur einmal angegeben werden. Weder die Typen der enthaltenen Werte, noch deren Felder müssen angegeben werden – sie werden vom Typ der Map abgeleitet. Wer befürchtet, den Überblick zu verlieren, kann auf die IDE GoLand zurückgreifen:

Go ist relativ sicher vor Unfällen (obwohl es maschinennah ist). Bei Zugriff auf eine Stelle eines Arrays, die gar nicht existiert oder unzulässiger Umwandlung von Zeiger-Datentypen wirft Go einen Fehler, um Schäden durch Programmierfehler abzuwenden:

type Laptop struct {
    DvdDrive uint32
}
func (l *Laptop) DoSomethingUseful() {
}
type SmartPhone struct {
    SimSlot uint16
}
func (s *SmartPhone) DoSomethingUseful() {
}
type Computer interface {
    DoSomethingUseful()
}
func main() {
    var computers = []Computer{&Laptop{}, &Laptop{}, &Laptop{}}
    _ = computers[3]
    var computer Computer = &Laptop{}
    _ = computer.(*SmartPhone)
}

Go erledigt von sich aus E/A-Aufgaben effizient (obwohl es nicht NodeJS ist). Aufgaben werden in Go nicht über Threads parallelisiert, sondern über sog. Go-Routinen (das gleiche in grün). Diese werden von Go selbst auf die eigentlichen Threads verteilt. Wenn eine Go-Routine eine blockierende E/A-Operation ausführt, wird diese transparent im Hintergrund vollzogen und eine andere Go-Routine beansprucht währenddessen den Thread.
Der Himmel ist die Grenze der Parallelisierung dank Scheduler und dynamischer Stack-Größe. Die o.g. Verteilung von Go-Routinen auf Threads verantwortet der sog. Scheduler von Go. Dies führt dazu, dass “zu” viele parallele Aufgaben sich und dem Rest des Systems nicht im Weg stehen. Zudem beansprucht jede Go-Routine nur soviel RAM wie sie auch wirklich braucht, d.h. eigentlich kann ein Programmierer so viele Go-Routinen starten wie er lustig ist (Beispiel). “Eigentlich” ist genau das richtige Stichwort, denn trotzdem sollte jeder Einzelfall für sich betrachtet werden. Ansonsten macht das OS irgendwann git push --feierabend (Beispiel).
Go geht einfach (daher kommt wahrscheinlich auch der Name). Im Gegensatz zu etablierten maschinennahen Sprachen muss ich mich nicht darum kümmern, dass libfoobar23.dll an der richtigen Stelle in der korrekten Version vorliegt. Das Ergebnis eines Go-Kompiliervorgangs ist eine Binary, die nichtmal gegen libc gelinked ist:

root@576214afd7e6:/# cat example.go
package main
func main() {
}
root@576214afd7e6:/# go build -o example example.go
root@576214afd7e6:/# ./example
root@576214afd7e6:/# ldd ./example
not a dynamic executable
root@576214afd7e6:/#

Alles kann, nichts muss. Go muss ja nicht von heute auf Morgen in sämtlichen Applikationen Anwendung finden. Man kann auch mit einem einzigen Programm anfangen, das nicht heute, jetzt und eigentlich schon vorgestern fertig sein muss. Und selbst wenn nicht alles beim ersten Mal klappt, bieten wir Ihnen gerne maßgeschneidertes Consulting an.

Alexander Klimov
Alexander Klimov
Senior Developer

Alexander hat 2017 seine Ausbildung zum Developer bei NETWAYS erfolgreich abgeschlossen. Als leidenschaftlicher Programmierer und begeisterter Anhänger der Idee freier Software, hat er sich dabei innerhalb kürzester Zeit in die Herzen seiner Kollegen im Development geschlichen. Wäre nicht ausgerechnet Gandhi sein Vorbild, würde er von dort aus daran arbeiten, seinen geheimen Plan, erst die Abteilung und dann die Weltherrschaft an sich zu reißen, zu realisieren - tut er aber nicht. Stattdessen beschreitet er mit der Arbeit an Icinga Web 2 bei uns friedliche Wege.

NodeJS HA mit PM2…

ich hatte in Vergangenheit bereits einen Blog Post über NodeJS in Verbindung mit dem NodeJS ‘Cluster’ Modul geschrieben ( siehe hier ), nun möchte ich euch zeigen wie Ihr eure NodeJS Anwendung auch ohne Programmierarbeit (also als reine Ops Tätigkeit) zum Cluster umfunktioniert und wie ihr diese anschließend verwalten könnt.
nodejs-logo-2015
Legen wir los, wir benötigen hierzu NodeJS, am besten 4.4 LTS und 4 zusätzliche Module/Helper, fangen wir also mit der Installation an…

$ npm install -g pm2
$ npm install -g express-generator
$ mkdir ~/project && cd project
$ npm install --save express
$ npm install --save sleep

…nun generieren wir das Express Anwendungsgerüst…

$ express -f .
   create : .
   create : ./package.json
   create : ./app.js
   create : ./public
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css
   create : ./routes
   create : ./routes/index.js
   create : ./routes/users.js
   create : ./views
   create : ./views/index.jade
   create : ./views/layout.jade
   create : ./views/error.jade
   create : ./bin
   create : ./bin/www
   install dependencies:
     $ cd . && npm install
   run the app:
     $ DEBUG=project:* npm start
$

… danach löschen wir in der Datei app.js alles von Zeile 13 bis 58, wir benötigen nur das Gerüst selbst und ein paar Zeile selbst geschriebenen Code, um diesen kommen wir leider nicht herum, da wir ja auch was sehen wollen.
Fügt nun ab Zeile 14 folgenden Code hinzu…

var crypto = require( 'crypto' );
var util = require( 'util' );
var sleep = require( 'sleep' ).sleep;
function getRandHash() {
    var current_date = (new Date()).valueOf().toString();
    var random = Math.random().toString();
    return crypto.createHash('sha1').update(current_date + random).digest('hex');
}
var myID = getRandHash();
app.get( '/', function( req, res ) {
    sleep( Math.floor( (Math.random() * 3) + 1 ) );
    res.send({
        "ID": myID,
        "PID": process.pid,
        "ENV": process.env
    });
});

…nun starten wir die App über PM2 im Cluster Mode, hier bitte dem Parameter ‘-i’ nur einen Wert gleich der Anzahl der CPU Cores mitgeben. Dann testen wir das Ganze doch gleich mal…

$ cd project
$ pm2 start bin/www -i 4

…ihr solltet nun folgende Ausgabe zu sehen bekommen…
pm2-start-www-cluster
…ihr könnt eure Anwendung auch auf Fehler überprüfen, dafür gibt euch PM2 einen Parameter ‘logs’ mit, der wiederum einige Flags kennt. Wenn ihr nur ‘pm2 logs’ eingebt dann bekommt ihr die Standardausgabe unserer Anwendung zu sehen, wenn ihr zusätzlich das Flag ‘–err’ mit angebt, bekommt ihr die Standard Fehlerausgabe, was für das Debugging recht hilfreich ist.
pm2-logs-examine
So, nun könnt ihr in eurem Browser mal die Anwendung aufrufen. Der Listener der Anwendung horcht auf dem Port 3000. Ein Aufruf auf http://127.0.0.1:3000 sollte ein JSON liefern, ähnlich zu dieser Ausgabe hier…
pm2-cluster-test1
Da wir in unserem Code eine künstliche Verzögerung eingebaut haben, könnt ihr nun mit 2 direkt Aufeinander folgenden Browser Reload sehen das sich die ID u. PID Werte gelegentlich ändern, dies bedeutet, dass unsere Cluster Anwendung funktioniert.
pm2-logo
Ich hoffe ich konnte euch nun zum Spielen und Experimentieren animieren. PM2 wird von der Firma Kissmetrics als OpenSource Project stetig weiter entwickelt und hat noch so viel mehr zu bieten, ganz findige unter euch werden die Monitoring API zu schätzen wissen und diese vmtl. in Icinga2, Graphite, Kibana und anderen Lösungen integrieren wollen.
Dann bis demnächst 🙂

Monthly Snap October: All news about Icinga, NodeJs, Events & Training Portfolio 2016

October was mainly characterized by Icinga – the release of the new webinterface Icinga Web 2.0.0, followed by the Icinga Camp in Portland and many tips and tricks how to use Icinga with Windows.
Tom announced the release of Icinga´s new web interface and Micheal reported from the Icinga Camp in Portland where it has been introduced.weekly snap
On events, Bernd counted 28 days to the OSMC with Jochen Lillich´s talk on “MonitoringLove with Sensu” while Bernd Ahlers, one of this year´s speaker at the conference, explained why we should pay more attention to logs on servers.
Lennart followed with a migration scenario to monitor windows with Icinga as Gunnar followed with a post to better understand commands on Icinga 2.
On clusters, Enrico looked at NodeJs as Micheal showed how to build packages with Icinga 2 on Windows.
Finally, Silke announced the new training portfolio for 2016.
 
 

Stephanie Kotilge
Stephanie Kotilge
Accountant

Steffi ist seit 2011 bei NETWAYS. Sie fing als Office Managerin an und unterstützt seit 2017 als Accountant das Finance & Administration Team in allen buchhalterischen Belangen. In ihrer Freizeit ist sie mit ihrem Sohn immer auf der Suche nach den schönsten Spielplätzen in Nürnberg oder plant den nächsten Familientrip.

Improved NodeJS Events durch Cluster …


… jeder von euch kennt das Problem, der Kollege kommt um die Ecke und möchte wenn möglich sofort, dass ein neues geiles Tools mit in den Infra Stack aufgenommen wird, gesagt getan.
In diesem Bespiel eine besonders cooles in NodeJS geschriebenes Dashboard für… lass es hier ein DockerManagement Tool sein. Dabei stößt man bei der großen Akzeptanz durch die Kollegen, auch auf einmal auf noch ganz andere Probleme (Stichwort: Performance Bottlenecks wie DDoS durch eigene Leute).
Hierbei könnte euch das NodeJS Modul Cluster behilflich sein, hier ist die Doku zu finden.
Cluster macht dabei nicht viel, es erweitert den NodeJS Stack insbesondere das Event Driven Modell von NodeJS ( so Arbeitet Google(s) v8 Engine ) um eine Art Interprocess Schnittstelle zu forked Child NodeJS Prozessen, die sich dabei Filesystem Elemente/Typen wie Sockets, Filedeskriptoren etc. teilen können und somit gemeinsam auf diesen operieren können.
Hier wollen wir eine schon bestehende Express Framework Anwendung mit einigen wenigen Zeilen Code um die Fähigkeit erweitern, dem System zur Verfügung stehenden CPU Cores effizienter ausnutzen zu können, damit sich die Events schneller abarbeiten lassen.
Ich werde hier allerdings nicht Express selber beschreiben, sondern setzte hier voraus das der Leser dieses Framework kennt. Wenn nicht könnt ihr die Infos unter diesem Link abrufen, so let’s beginn …

$ sudo -i                                  # <- da meine Workstation ein Ubuntu ist sollten wir zumindest was die Essentials sind kurz zu 'root' werden um diese Problemlos installiert zu bekommen
$ npm install express -g                   # <- installiert uns das Express Framework samt CLI Tools
express@4.13.3 /usr/lib/node_modules/express
├── escape-html@1.0.2
├── merge-descriptors@1.0.0
├── cookie@0.1.3
├── array-flatten@1.1.1
├── cookie-signature@1.0.6
├── utils-merge@1.0.0
├── content-type@1.0.1
├── fresh@0.3.0
├── path-to-regexp@0.1.7
├── content-disposition@0.5.0
├── vary@1.0.1
├── etag@1.7.0
├── serve-static@1.10.0
├── range-parser@1.0.2
├── methods@1.1.1
├── parseurl@1.3.0
├── depd@1.0.1
├── qs@4.0.0
├── on-finished@2.3.0 (ee-first@1.1.1)
├── finalhandler@0.4.0 (unpipe@1.0.0)
├── debug@2.2.0 (ms@0.7.1)
├── proxy-addr@1.0.8 (forwarded@0.1.0, ipaddr.js@1.0.1)
├── send@0.13.0 (destroy@1.0.3, statuses@1.2.1, ms@0.7.1, mime@1.3.4, http-errors@1.3.1)
├── type-is@1.6.9 (media-typer@0.3.0, mime-types@2.1.7)
└── accepts@1.2.13 (negotiator@0.5.3, mime-types@2.1.7)
$ npm install express-generator -g
/usr/bin/express -> /usr/lib/node_modules/express-generator/bin/express
express-generator@4.13.1 /usr/lib/node_modules/express-generator
├── sorted-object@1.0.0
├── commander@2.7.1 (graceful-readlink@1.0.1)
└── mkdirp@0.5.1 (minimist@0.0.8)
$ exit                                     # <- ab hier geht es ohne 'root' Rechte weiter
$ mkdir cool-app && cd cool-app            # <- Projekt Verzeichnis anlegen und in dieses wechseln
$ pwd                                      # <- vergewissern das wir uns auch in diesem wirklich befinden
/home/enzo/nodejsProjects/cool-app
$ express --git .                          # <- wir provisionieren uns unser Projekt from Scratch, dieses ist somit direkt Lauffähig ohne das wir einen Zeile Code schreiben müssen, haben hier leider keine Zeit zu 😉
   create : .
   create : ./package.json
   create : ./app.js
   create : ./.gitignore
   create : ./public
   create : ./routes
   create : ./routes/index.js
   create : ./routes/users.js
   create : ./views
   create : ./views/index.jade
   create : ./views/layout.jade
   create : ./views/error.jade
   create : ./bin
   create : ./bin/www
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css
   install dependencies:
     $ cd . && npm install
   run the app:
     $ DEBUG=cool-app:* npm start
$

Ab hier können wir das ganze mal kurz testen, um uns zu vergewissern das die Anwendung auch läuft ...

$ npm start
> cool-app@0.0.0 start /home/enzo/nodejsProjects/cool-app
> node ./bin/www

Nicht wundern die Applikation bleibt im Vordergrund hängen, was ist Ok ist, somit können wir diese schneller terminieren und relaunchen. Weiter geht es mit einem Test im Browser, die Anwendung lauscht standardmäßig am Port 3000, somit rufen wir hier einmal http://localhost:3000 auf und lassen uns überraschen was da so schönes kommt ...

Geil es läuft also, nun gut machen wir das ganze mit Cluster noch skalierbarer, let's go ...
Öffnet hierzu im Projekt Verzeichnis einmal die bin/www Datei, diese stellt laut package.json unseren Eintrittspunkt in die Anwendung dar, wir kopieren uns diese als Backup weg bevor wir anfangen hier Änderungen vorzunehmen.
Kommentiert bitte folgende Zeilen einmal aus ...

/**
 * Get port from environment and store in Express.
 */
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
 * Create HTTP server.
 */
var server = http.createServer(app);
/**
 * Listen on provided port, on all network interfaces.
 */
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

... nun fügt ihr ab Zeile 10 bitte folgendes hinzu ...

// cluster requirements
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if( cluster.isMaster ) {
  for( var i = 0; i < numCPUs; i++ ) {
    cluster.fork();
  }
  cluster.on( 'listening', function( worker ){
    console.log( 'worker ' + worker.process.pid + ' is now listen for incoming connections ... ' );
  });
  cluster.on( 'exit', function( worker, code, signal ) {
    console.log( 'worker ' + worker.process.pid + ' died' );
  });
} else {
    // Workers can share any TCP connection
    // In this case it is an HTTP server
    /**
    * Get port from environment and store in Express.
    */
    var port = normalizePort(process.env.PORT || '3000');
    app.set('port', port);
    /**
    * Create HTTP server.
    */
    var server = http.createServer(app);
    /**
    * Listen on provided port, on all network interfaces.
    */
    server.listen(port);
    server.on('error', onError);
    server.on('listening', onListening);
}

.. jetzt sollte das ganze auch schon funktionieren, probieren wir es doch einmal aus.

$ npm start
> cool-app@0.0.0 start /home/enzo/nodejsProjects/cool-app
> node ./bin/www
worker 31979 is now listen for incoming connections ...
worker 31974 is now listen for incoming connections ...
worker 31985 is now listen for incoming connections ...
worker 31996 is now listen for incoming connections ...
GET / 304 840.784 ms - -
GET /stylesheets/style.css 304 31.416 ms - -

Jetzt könnte man denken das sich hier nichts geändert hat, dem ist aber nicht so, der Beweis ist in der Prozess Tabelle zu finden, gucken wir doch kurz einmal hinein ...

$ ps auxf | grep node
enzo     31969  0.1  0.4 901264 33004 pts/7    Sl+  14:47   0:00          |   |       \_ node ./bin/www
enzo     31974  0.1  0.4 901256 32324 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31979  0.4  0.6 946192 47560 pts/7    Sl+  14:47   0:01          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31985  0.1  0.4 902668 32736 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31996  0.1  0.4 901256 32168 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www

Whoop whoop, 4 neue NodeJS Prozesse die hier ihre Arbeit verrichten, somit lassen sich auch die beschäftigsten Web Anwendungen wieder beschleunigen.
Das ist aber nur der Anfang wie sich NodeJS Applications aller Art verbessern lassen, für weiter Themen habe ich heute allerdings keine Zeit daher heben wir uns den Rest einfach für ein anderes mal auf.
Ich wünsche euch hiermit noch viel Spaß, ich hoffe ihr habt nun mehr Lust auf NodeJS bekommen.

Visual Studio Code für Node.js unter Linux ausprobiert

Wenn man es genau nimmt hätte dieses Jahr ja eigentlich die Hölle zufrieren müssen, denn Microsoft hat tatsächlich einen Ableger von Visual Studio für Linux veröffentlicht: den Texteditor Visual Studio Code. Bei VSCode handelt es sich allerdings um keinen vollwertigen IDE, wie man beim Namen eigentlich vermuten könnte, sondern um einen Texteditor, der aber immerhin einen Debugger, Autocompletion und GIT-Support mitbringt. Der Editor untersützt C#, HTML, CSS, JS und Node.JS.
Da ich für das Projekt NETRP Node.JS mit dem Express-Webserver verwende und dafür schon länger auf der Suche nach einem guten Editor bin, habe ich die Preview-Version des Microsoft-Editor gleich mal ausprobiert. Meine Erfahrungen dabei möchte ich euch nicht vorenthalten.

Installation

Die Installation ist denkbar einfach und besteht daraus ein Zip zu entpacken und das Binary im Programmordner auszuführen.

Autocompletion

Wie bei anderen Texteditoren, muss man in VSCode keine Projekte anlegen, sondern öffnet einfach den Ordner im Editor. Wenn man eine beliebige JavaScript-Datei öffnet funktioniert grundlegende Autocompletion, Compiler-Warnungen und das Syntax-Highlighting bereits automatisch.
Ohne jegliche Konfiguration kennt die Autocompletion aber momentan nur die Symbole die direkt im Code definiert wurden oder die Built-In-Objects. Beim Hovern über ein unbekanntes Symbol wird einem aber gleich ein Quick Fix angeboten um dieses Problem zu beheben: VSCode fragt im Hintergrund die Datenbank Definitely Typed ab, die Typskriptdefinitionen für sehr viele übliche JavaScript-Libraries bereitstellt. Diese Dateien können dann direkt in eingebunden und vom Autocompleter verwendet werden um das Interface der verfügbaren Funktionen nachzuschlagen.

Debugging

Fürs Debuggen benötigen wir mindestens die Version 3.12 der Mono-Runtime. Da ich aber noch Fedora20 verwende und es hier im Repository relativ düster aussieht, installiere ich die Version direkt vom Mono-Project.
Die Dokumentation von VSCode sagt uns, dass wir zuerst launch.json auf den Einstiegspunkt zeigen lassen müssen, bei NETRP liegt diese Datei in: src/netrp_server/netrp.js. Die launch.json wird automatisch generiert und ins Projekt eingefügt, sobald man die Debugging-Konfiguration des erste mal öffent.
Der Dokumentation zu folge, sollte nach F5 jetzt eigentlich bereits die Anwendung und den Debugger starten, stattdessen überrascht VSCode mit dem wenig aussagekräftigen Fehler “Connection failed“.
connection-failed
Eventuell existiert irgendein Problem mit der Run-Konfiguration, aber aufgrund der fehlenden Fehlerbeschreibung versuche ich lieber einfach direkt einen anderen Ansatz: den Debugger an den vorhandenen Prozess anhängen. Wenn man die Anwendung mit node –debug-brk netrp selbst startet und den Debugger stattdessen über einen TCP-Port and den Prozess anhängt, funktioniert es auch schon einwandfrei:
VSC - Debugger
In der aktuellen Vorabversion unterstützt der Debugger nur die typischen Kernfeatures, also das Setzen von Breakpoints und das manuelle Stepping. Zumindest in der Linuxversion wirkt das Stepping in der Preview aber noch etwas träge und es gibt ein spürbare Verzögerung beim Bedienen des Debuggers.

Git

Das Git-Repository wird automatisch erkannt und der Reiter “Git” zeigt alle Änderungen an. Es ist möglich komplette Dateien zu stagen und Commits zu erstellen, für feinere Aktionen ist weiterhin die CLI notwendig.
git

Fazit

Der Editor lässt sich schnell einrichten und verwenden und besonders das einfache beschaffen von TypeScript-Definitionen für JS-Libraries hat mich beeindruckt. Sobald das Projekt in einer finalen Version ist werde ich es wohl definitiv als Editor für meine Node-Projekte in Betracht ziehen.