Blog: Latest Entries (15):


CoreUI: Ein Admin-Template für Vue

Schon als ich mit React arbeiten musste, war ich sehr von den vorgefertigten Admin-Templates angetan. Jetzt darf ich auch mal damit rumspielen und meine ersten Erfahrungen damit sind schon relativ positiv. Da ich mit meinem Job synchron bleiben wollte habe ich mit CoreUI angefangen.

Die Installation über GitHub ist einfach und schnell.

Um ein eigens View anzulegen muss man an sich drei Dinge tun.

1. Die View anlegen:

bbcode-image


bbcode-image


2. In router/index.js die Component importieren und in die Router-Config einfügen:

bbcode-image


3. In containers/_nav.js einen Link für die Sidebar einfügen:

bbcode-image


4. Dann den Server starten:

npm run serve


Und unter http://localhost:8080 angucken.

bbcode-image


Geht an sich alles ganz einfach.

Git State Konzept

Am Freitag hat mir mein Kollege 2 Links zu Blogposts geschickt, die sich mit der Frage beschäftigen ob Git-Flow in der heutigen Zeit überhaupt noch funktioniert oder ob Git-Flow veraltet ist. Der 1. Blogpost zeigt erstmal nur Probleme auf und enthält keine Lösungen. Es passiert zu leicht das Release-Branches zu lange leben und dann darin selbst Entwicklung geschieht. Es dauert relativ lange bis eine Änderung durch die verschiedenen Branches im Master ankommen und am Schlimmsten ist noch, dass bei parallelen Entwicklungen ein nicht releaster Branch einen anderen aktuelleren, der einfach schneller war, blockiert.

Ja. Das ist jetzt nicht neu. Über diese Probleme habe ich 2009 schon im dem damaligen ERP-Team diskutiert (mein Gott waren wir damals schon modern...). Die Lösung hier ist einfach dass man harte Feature- und Code-Freezes braucht. Auch darf die Fachabteilung nicht erst im Release-Branch das erste Mal die neuen Features sehen. Ich habe es so erlebt. Dann kamen die neuen Anforderungen, Änderungen der gerade erst implementierten Features. Das soll aber so sein. Wenn das so ist braucht man aber auch noch das. Das ist falsch und muss so funktionieren... Alles Dinge die schon viel früher hätten klar sein müssen und erst dann hätte es zu einem Release-Branch kommen dürfen. Der Stand eines Feature-Branchs muss genau so auf einem System für Test und Abnahmen deploybar sein wie ein Release-Branch. Anders gesagt jeder Stand muss einfach immer präsentierbar sein!

Der 2. Blogpost brachte jetzt auch nicht wirklich neue Erkenntnisse, was am Ende der Author auch selbst schreibt.

Ich halte die Darstellung von Branches in parallelen Slots oder Lanes, die in dem Sinne ein Rennen um die Aktualität austragen für vollkommen falsch. Es darf auch nicht den develop-Branch oder den einen Release-Branch geben, der auch dann immer deckungsgleich mit dem Stand des Deployments auf einem System ist. In Zeiten von Docker und Reverse-Proxies zusammen mit Wildcard-Subdomains sind feste Systeme sowie so überholt. Jeder Branch kann ein System haben, auf dem Test, Abnahmen und Dokumentation stattfinden kann.
Das gilt auch für Tags. Branches sind variabel und ändern sich immer wieder. Tags sind statisch und damit perfekt für Zwecke, wo man kontrolliert bestimmte Stände deployen möchte. Tags persitieren einen bestimmten State/Zustand des gesamten Git-Repositories. Branches bilden einen State/Zustand aus der Sicht eines bestimmten Entwicklers oder eines bestimmten Features ab.

Deswegen halte ich feste Branches wie mit festen Aufgaben für komplett falsch. Ein Feature = ein Branch und am Ende steht ein Tag, der den gewünschten State/Zustand persitiert.

Ein einfacher Feature Branch:
bbcode-image


Ja es gibt noch einen Master-Branch, der aber in dem Sinne nur ein 2D Abbild des wilden mehr dimensionallen Feature Raum ist. Wenn wir jeden Feature-Branch als Vektor der auf das einzelne Feature/Tag als Ziel zeigt versteht, ist der Master einfach die Projektion aller Vektoren auf eine Fläche. Diese vereinfachte Projektion hilft Feature-Branches vor dem Release auf den aktuellen Stand (was andere Features und Fixes angeht) zu bringen.

Es gibt auch immer mal Abstimmungsprobleme bei Features, die auf einander aufbauen. Interfaces haben minimale Abweichungen oder ein kleiner Satz in der Dokumentation wurde falsch verstanden. Was also wenn ein Feature doch noch eine kleine Änderung braucht, weil Entwicklungen parallel liefen?

Beides wird gleichzeitig fertig (ein extra Release-Branch wäre möglich):
bbcode-image


Das Basis-Feature ist schon fertig:
bbcode-image


Gibt es einen Unterschied zwischen Fixes und Features? Nein. Beides sind Improvements des aktuellen States/Zustands. Wenn einem in einem Feature-Branch ein allgemeines Problem auffällt, fixt man das Problem und merged den Master mit der neuen Version erneut in den Feature-Branch.

Zwischenzeitlicher Fix:
bbcode-image


Der Master ist immer stable, weil nur Release-Tags darauf abgebildet sind.

Dieses Herangehen macht es sehr einfach jeden State/Zustand auf System abzubilden. Jeder Branch ist unter seinem Namen zu finden und Tags werden nach Typ auf Systeme gemappt.

Tag auf System:
- release-XXX auf das produktive System
- staging auf das Staging-System (1:1 Namenabbildung)
- demo1-n auch 1:1 per Namen abbilden

Bei staging muss man den Tag löschen und neu anlegen, so kann jeder Zustand auf dem Staging-System deployt werden oder besser gesagt, wird ein Deployment durchgeführt das dann unter der Staging-Domain erreichbar ist. Hier gibt es toll Anleitungen wie man solche Systeme mit Traefik oder Kubernetes ganz einfach bauen kann. Ich werde das aber vielleicht auch noch mal genauer beschreiben, wie ich es für gut halte.

Denn Branches halte ich persönlich es nicht für wert wo anders als lokal in einem Docker-Container zu laufen. Da kann ich um es der Fachabteilung lieber schnell einen Tag erstellen und diesen nach dem Input der Abteilung auch wieder unter selben Namen neu anlegen oder unter einen neuen wenn zwei mögliche Umsetzungen verglichen werden sollen (macht das mal mit Git-Flow!).

Home Office

Arbeiten und nebenbei Folding At Home auf der Workstation laufen lassen.

MS Teams läuft wirklich nicht immer ganz so rund. Aber im Gegensatz zu den Berichten vieler anderer habe ich mit meiner kleinen 1Gbit Kabel Internetleitung und VPN keine Probleme. Also alles super so weit.

bbcode-image

Lenovo IdeaPad z570 und Win10

Bis jetzt hatte ich nie Probleme Windows 10 auf einem PC oder Notebook zu installieren, dass ursprünglich mit Vista, Win7 oder Win8 lief. Aber es gibt immer ein erstes mal. Hier bei handelte es sich um ein Lenovo IdeaPad z570, das ungefähr Jahrgang 2011/2012 ist. Es ist also noch gar nicht so alt. Ein Lenovo T61 aus dem Jahr 2007 und zwei T500 aus dem Jahr 2008 hatten keine Probleme mit Windows 10. Das z570 hatte auch nur ein Problem mit Windows 10: Es ging nicht aus. Auch bei einem Neustart fuhr es zwar runter, aber verblieb dann in einem undefinierten Zustand in dem die LEDs der Zusatztasten und des Power-Switch weiter leuchteten und der Lüfter voll aufdrehte.
Schon bei der Installation musste ich beim ersten Neustart das Notebook per Hand ausschalten. Als Windows 10 dann installiert war führte es dazu, dass sich das WLAN danach ausgeschaltet hatte und nicht wieder einzuschalten war. Windows verwies immer auf den Schalter am Gehäuse, aber der war eingeschaltet. Als erstes befürchtete ich, dass ich ein BIOS-Update machen müsste, aber nach vielen Herumprobieren und Versuchen, wich der Vermutung eine klare Sicherheit, dass es so sein musste.
Also BIOS-Update herunter geladen, gestartet und direkt in einen Bluescreen gelaufen. Selbst mit Adminrechten kam wieder der Bluescreen.
Zum Glück hatte ich die Festplatte mit Windows 7 noch daneben liegen (das mich auch direkt beim letzten Herunter fahren mit ein paar Updates beglückt hatte). Also die Festplatte wieder eingebaut.

bbcode-image


bbcode-image


Da merkte man erst mal wie schnell doch die neue SSD war, auch wenn es die billigste SSD war, die ich bei Amazon gefunden hatte. Windows bootete wieder und das Programm für das BIOS-Update lief sofort einmal sauber und schnell durch.

bbcode-image


Dann wieder Festplatte gegen die SSD getauscht. Windows 10 gestartet und wieder herunter gefahren. Die Lichter leuchteten, leuchteten und gingen dann doch aus. Der Lüfter stoppte.

Fazit: Immer Windows 7 für Notfälle weiter vorhalten und vielleicht mal ein BIOS-Update einplanen.

Das z570 war aber auch sonst schon leicht mitgenommen. Das Gehäuse des Lüfters war so eingedrückt, dass der Lüfter fest saß und alles extrem heiß wurde. Mit etwas Gewalt und biegen, war der Lüfter wieder frei zu bekommen und lief sogar direkt wieder. Ich war mir nicht sicher gewesen, dass er nicht doch dadurch kaputt gegangen war.

bbcode-image


Da ich ihn ja sowie so ausbauen musste, wurde auch gleich die total
eingetrocknete Wärmeleitpaste für CPU und GPU ersetzt und auch der Chipsatz bekam welche ab. Der hatte zwar eine Verbindung zum Kühlkörper der CPU aber selbst keine Wärmeleitpaste.

Noch die 2x 2GB gegen ein 8GB Modul ausgetauscht und alles lief so schnell, dass das Notebook sicher noch 3-4 Jahre ohne Probleme seine Aufgaben erledigen kann.

Mini-USB Kamera brauchbar machen

Kleine USB-Kameras sind sehr praktisch, wenn man mit ihnen 3D-Drucke überwachen, Bilderkennung oder auch kleine IoT-Projekte mit QR-Code Scans realisieren will.

bbcode-image


Ich hatte mir eine sehr kleine Kamera aus China bestellt, war aber mit der Bildqualität nie wirklich zufrieden. Das Bild war immer unscharf und Lichter bildeten immer unschöne Ränder um alles.

bbcode-image


Am Ende habe ich mir jetzt das Objektiv genauer angesehen und den IR-Filter endeckt, der einfach als kleine Plättchen hinten rauf geklebt war. Mit Hilfe eines feinen Schraubenziehers und viel Gewalt gelang es mir den IR-Filter zu entfernen/weg zu brechen.

bbcode-image


Nun ist zwar mein graue Jacke etwas lila, aber das Bild ist sehr scharf und und hell. mit einen IR720 Filter kann bestimmt gute Aufnahmen im IR-Bereich machen und bei Kunstlicht sind die leichten Verfärbungen sowie so kein Problem mehr.

PHP Tests mit Code-Coverage

Wenn man Code-Coverage bei Unittests mit PHP haben will benötigt man extra Erweiterungen, wie z.B. XDebug. XDebug ist aber sehr langsam und deswegen gibt es Alternativen wie PCOV. Wenn man das nun installieren will kann es zu Problemen bei "docker-php-ext-install" auf den offiziellen PHP-Docker-Images kommen. Um es dort zu installieren, muss man


pecl install pcov && docker-php-ext-enable pcov


ausführen. Dann funktioniert die Installation und es steht für Unit-Tests zur Verfügung.



M2-Adapter mit PCIe 1x

Es begab sich zur Weihnachtszeit, dass Notebookswieneu günstige SSDs hatte und ich eine SSD brauchte. Zusätzlich waren die WOW-Ladezeiten bei dem PC meiner Frau nicht wirklich toll, da WOW von der HDD geladen wurde, weil die SSD zu voll war. Also gleich mal 2 SSDs gekauft. Knapp 16 EUR für eine 256GB Samsung NVMe SSD konnte man ja nicht viel falsch machen.

Das Problem kam als ich fest stellen musste, dass das "alte" AM4-Mainboard nur einen PCIe 1x Slot frei hat. Also einen entsprechenden Adapter gekauft.

bbcode-image


PCIe 1x limitiert bei ca. 450MB/s. Alles andere läuft normal, nur die Lesegeschwindigkeit limitiert. Schreibt also an sich genau so schnell wie sie liest.

Aber abschließend ist zu sagen: Selbst mit PCIe 1x ist die SSD noch bedeutend schneller als die HDD.


Selbstversuch: Ein 300 EUR PC

300 Euro ist bei PCs ein seltsames schwarzes Loch. Man kann gut was darunter bauen, in dem man APUs verbaut und man kann noch viel einfacher ein einen teureren PC zusammen bauen. Bei 300 Euro ist die Grenze zwischen "einfachen" PC und "leistungsfähigen" PC, der auch für Spiele und mal ein paar Docker-Container mehr geeignet ist. Bei neuwertigen Komponenten kommt man nicht um die APUs von AMD herum. Ein Ryzen 3 3200G kostet um die 90 Euro und bringt eine brauchbare 4-Core CPU (ohne SMT) und eine GPU (die viel schneller als die Intel iGPUs ist) mit. Ein günstiges Mainboard und man hat einen netten kleinen PC. Aber er ist eben nur nett und nicht gut. Da fehlt ein klein wenig dazu und dann ist man schon wieder gleich bei um die 500 Euro.

Also dachte ich mir, ich versuche es mit zu meist gebrauchten Komponenten und will etwas was über einem 3200G liegt. Er sollte schneller sein als mein PC von 2010. Klingt leicht, ist aber am Ende gar nicht so einfach, weil gute Komponenten von 2012-2014 auch heute noch sehr gut mit günstigen modernen Komponenten mithalten können. Es ist echt deprimierend wie wenig Mehrleistung man für doch relativ viel Geld nur bekommt.

Basis des ganzen PC ist ein Proof-Of-Concept Versuch mit einem chinesischen X99 Mainboard mit Sockel 2011-3. Alle Boards mit diesem Sockel sind noch extrem teuer. Selbst von Gigabyte oder Asus bekommt man nichts günstiges... von Supermicro und Intel brauchen wir erst gar nicht reden. Ich wollte einfach mal wissen, ob diese Mainboards aus China wirklich laufen, da sie vieles kombinieren, was es sonst so teilweise nicht gab. M.2-Slots auf solchen Boards zum Beispiel.

bbcode-image


bbcode-image


Dann hatte ich noch eine alte HP x4000 Workstation, deren Gehäuse ich schon immer sehr gemocht habe und gerne weiter benutzen wollte. Der Lack war teilweise ab und der Frontpanel-Anschluss passt wohl nur auf ein Tyan Thunder i860. Aber es gibt ja Lack im Baumarkt und Kabel beim Amazon um den Frontpanel-Connector Kabel für Kabel zu adaptieren. Die Belegung konnte ich einfach im Handbuch des Mainboard nachlesen.

bbcode-image


Nach viel hin und her kam dann ein E5-2620 v3 für 20 Euro aus China hinzu. War relativ günstig und ich hatte etwas Angst einen teureren Prozessor zu verwenden, weil ich mir nicht sicher war, wie sich das alte Netzteil aus der x4000 verhalten würde. Ich ging einfach davon aus, dass es ein normales ATX-Netzteil ist. Später stellte sich heraus, dass der 8pin 12V Anschluss nicht lang genug war und anstelle eines weiteren Adapters zusätzlich zu den Adaptern für die Grafikkarte, kaufte ich für 20 Euro einfach ein älteres BeQuiet Netzteil, wo ich alles ohne zusätzliche Adapter anschließen konnte. Bei der Grafikkarte wollte ich eigentlich eine RX480 oder RX570 haben, aber am Ende wurde es eine GTX 970 für 60 Eur. 32GB DDR4 ECC Speicher kam auch hinzu. 16GB ist für heutige Anwendungen einfach zu wenig. Als Kühler für den Sockel 2011-3 hab ich einen ARCTIC Freezer 33 eSports ONE der wohl auch seine Arbeit ganz gut erledigt.

bbcode-image


Eine Geschichte von viel Glück und Inkompetenz brachte mir zwei Samsung 512GB NVMe SSDs für je 16,20 Euro ein. Echt schnell und ausreichend groß... gerade für den Preis. Ist zwar Lenovo-OEM aber scheinen trotzdem nicht die langsamsten zu sein.

bbcode-image


Bis jetzt läuft der PC sehr gut und ist ungefähr so schnell wie mein alter 2x L5639, nur die Grafikkarte ist bei dem neuen schneller als die alte Radeon 7950. Eine CPU leistet also an sich so viel wie vorher zwei, hat aber auch nur den Stromverbrauch einer der CPUs. Wer also mit China-Boards ein günstiges System bauen möchte, sollte nicht mehr mit dem Sockel 1366 anfangen, sondern eher dual 2011 oder ein single CPU 2011-3 System mit aktuelleren CPUs aufbauen. Aber mit den modernen Ryzen Zen2 CPUs von AMD ist es echt schwer geworden mit gebrauchten Komponenten preismäßig mithalten zu können. Man bekommt einfach heute extrem viel Leistung für extrem wenig Geld.

bbcode-image


Specs:
Mainboard 70 EUR
Zubehör 20 EUR
32GB RAM 85 EUR
E5-2620 v3 22 EUR
Kühler 16 EUR
Gehäuselüfter 9 EUR
SSD 512GB NVMe 16 EUR
GTX 970 60 EUR
Gehäuse 0 EUR
Netzteil 20 EUR


Best Gehäuse Ever!!!111

Ich bin gerade dabei eine alte HP x4000 Workstation mit neuen Innenleben zu füllen. Das alte dual Netburst Xeon-System wird einem einfachen E5 v3 Single-CPU System weichen. Wenn man sich aktuelle HP Workstations der Z-Serie ansieht, sind die Gehäuse so speziell, dass man keine normalen Komponenten verbauen kann. Deswegen bin ich auch so von dem alten x4000er Gehäuse begeistert. Egal was man hat, es passt rein. Ich habe das alte Delta Electronics Netzteil gegen eines von BeQuiet getauscht. Das alte war natürlich höher. Aber man kann zum Glück die Stütze für das Netzteil nach oben versetzen, so dass
keine Lücke entsteht.

bbcode-image


Auch längere Netzteile sind kein Problem, da für alle Längen eine zusätzliche Schiene eingebaut werden kann, mit der man das Netzteil verschrauben und so stabilisieren kann.

bbcode-image


Leider hat das kleine BeQuiet Netzteil keine Möglichkeit es so fest zu schrauben. Bei der Größe ist es zum Glück auch nicht wirklich nötig.

bbcode-image


Und mit das Tollste überhaupt: Bohrungen für Schrauben, die man gerade nicht braucht und so im Gehäuse aufbewahren kann.

bbcode-image

Twig und Plugins

Aus Shopware kennt man das Prinzip, dass man beim Erweitern von Templates einfach "parent:" angeben muss und es wird immer das vorher gehende Template mit dem selben Pfad erweitert. So kann man ein Template mehrmals durch eine unbekannte Anzahl von Plugins erweitern lassen. Twig will aber immer einen Namespace haben. Also muss man heraus finden, mit welchen Plugin man anfängt und welches Plugin dann auf das aktuelle folgt oder man auf das Basis-Template gehen muss. Ich hab mich von der Shopware 6 Implementierung inspirieren lassen und ein kleines Beispiel gebaut, bei dem man die ein Template erweitern kann und die Plugin-Namespaces immer dynamisch ergänzt werden.

Die Verzeichnisstruktur des Beispiels ist sehr einfach:

bbcode-image


Diese drei Templates leiten von einander ab:

{% base_extends "index.twig" %}
{% block blubb %}
{{ parent() }}
3<br/>
{% endblock %}



{% base_extends "index.twig" %}
{% block blubb %}
2<br/>
{% endblock %}



<strong>
{% block blubb %}
1
{% endblock %}
</strong>


Am Ende wollen wir folgendes Ergebnis haben:

<strong>
2<br/>
3<br/>
</strong>


Die Basislogik habe ich in einer einfachen Function zusammen gefasst. Hier wird entweder das Plugin heraus gesucht mit dem angefangen werden muss oder das Plugin, das auf das aktuelle folgt und auch dieses Template mitbringt.


function findNewBase($template, $list = [], $currentBase = null) {
$result = 'base';
$found = $currentBase == null; //if null, took the first one
foreach($list as $key => $path) {
if($key == $currentBase) {
$found = true;
}
else if ($found && file_exists($path . '/' . $template)) {
$result = $key;
break;
}
}
return $result;
}


Die Integration wird über ein Token-Parser implementiert.


final class ExtTokenParser extends AbstractTokenParser {
/**
* @var Parser
*/
protected $parser;

private $list = [];

public function __construct(array $list)
{
$this->list = $list;
}

public function getTag(): string
{
return 'base_extends';
}

/**
* @return Node
*/
public function parse(Token $token)
{
$stream = $this->parser->getStream();
$source = $stream->getSourceContext()->getName();
$template = $stream->next()->getValue();

$parts = preg_split("/\//i", preg_replace("/@/", '', $source));
$newBase = findNewBase($template, $this->list, $parts[0]);
$parent = '@' . $newBase . '/' . $template;

$stream->next();

$stream->injectTokens([
new Token(Token::BLOCK_START_TYPE, '', 2),
new Token(Token::NAME_TYPE, 'extends', 2),
new Token(Token::STRING_TYPE, $parent, 2),
new Token(Token::BLOCK_END_TYPE, '', 2),
]);

return new Node();
}
}


Das eigentliche Beispiel sieht dann so aus:

$list = [
'plugin2' => 'templates/path3',
'plugin1' => 'templates/path2',
'base' => 'templates/path1'
];

$loader = new \Twig\Loader\FilesystemLoader();
foreach($list as $plugin => $path) {
$loader->addPath($path, $plugin); //plugin as namespace
}

$twig = new \Twig\Environment($loader);
$twig->addTokenParser(new ExtTokenParser($list));
echo $twig->render('@' . findNewBase('index.twig', $list) . '/index.twig', []);


Und am Ende kommt raus:

bbcode-image


Jetzt fehlt nur noch eine passende include-Funktion und man kann sich selbst ein System bauen, desen Templates sich über Plugins ohne Probleme erweitern lassen. Ich arbeite daran....

Edit: Die vollständige Implementierung mit extends und include ist jetzt auf GitHub zu finden.


Older posts:

Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?