upgrade to 0.8; added Opinion-section
This commit is contained in:
@ -2,9 +2,9 @@
|
||||
title: About me
|
||||
---
|
||||
|
||||
# Stefan Dresselhaus
|
||||
# Drezil
|
||||
|
||||
<img align="right" style='border:1px solid #000000; float:right; margin-left:20px' height='300px' src="/About/DresselhausStefan_klein2.jpg"/>
|
||||
<img class="border border-solid w32 rounded-xl lg:rounded-3xl lg:w64 float-right" style=" border-color: rgb(217 70 239);" src="/About/avatar_neu.png"/>
|
||||
|
||||
## Work
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 87 KiB |
BIN
content/About/avatar_neu.png
Normal file
BIN
content/About/avatar_neu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 170 KiB |
@ -11,6 +11,11 @@ Die meisten Services haben offensichtliche Anforderungen (Schnittstellen nach
|
||||
draußen, Schnittstellen intern, ...). Diese kann man immer sehr gut in einem
|
||||
`Request -> Response`-Model erfassen.
|
||||
|
||||
Um die Anforderungen und Möglichkeiten des jeweiligen Services sauber zu
|
||||
erfassen und automatisiert zu prüfen, dummy-implementationen zu bekommen und
|
||||
vieles andere mehr, empfiehlt es sich den #[[OpenAPI|openapi-generator]] zu
|
||||
nutzen.
|
||||
|
||||
Diese Definition läuft über openapi-v3 und kann z.b. mit Echtzeit-Vorschau im
|
||||
http://editor.swagger.io/ erspielen. Per Default ist der noch auf openapi-v2
|
||||
(aka swagger), kann aber auch v3.
|
||||
@ -19,7 +24,7 @@ Nach der Definition, was man am Ende haben möchte, muss man sich entscheiden, i
|
||||
welcher Sprache man weiter entwickelt. Ich empfehle aus verschiedenen Gründen
|
||||
primär 2 Sprachen: Python-Microservices (weil die ML-Libraries sehr gut sind,
|
||||
allerdings Änderungen meist schwer sind und der Code wenig robust - meist nur 1
|
||||
API-Endpunkt pro service) und Haskell (stabilität, performace, leicht zu ändern,
|
||||
API-Endpunkt pro service) und Haskell (Stabilität, Performace, leicht zu ändern,
|
||||
gut anzupassen).
|
||||
|
||||
Im folgenden wird (aus offensichtlichen Gründen) nur auf das Haskell-Projekt eingegangen.
|
||||
@ -28,15 +33,15 @@ Im folgenden wird (aus offensichtlichen Gründen) nur auf das Haskell-Projekt ei
|
||||
|
||||
### Erstellen eines neuen Projektes
|
||||
|
||||
Zunächst erstellen wir in normales Haskell-Projekt ohne funktionalität & firlefanz:
|
||||
Zunächst erstellen wir in normales Haskell-Projekt ohne Funktionalität & Firlefanz:
|
||||
|
||||
```bash
|
||||
stack new myservice
|
||||
```
|
||||
|
||||
Dies erstellt ein neues Verzeichnis und das generelle scaffolding.
|
||||
Nach einer kurzen anpassung der stack.yaml (resolver auf unserer setzen;
|
||||
aktuell: lts-17.4) fügen wir am Ende der Datei
|
||||
Nach einer kurzen Anpassung der `stack.yaml` (resolver auf unserer setzen;
|
||||
aktuell: `lts-17.4`) fügen wir am Ende der Datei
|
||||
|
||||
```yaml
|
||||
allow-newer: true
|
||||
@ -51,7 +56,7 @@ das git mittels `git init; git add .; git commit -m "initial scaffold"`
|
||||
### Generierung der API
|
||||
|
||||
Da die API immer wieder neu generiert werden kann (und sollte!) liegt sich in
|
||||
einem unterverzeichnis des Haputprojektes.
|
||||
einem unterverzeichnis des Hauptprojektes.
|
||||
|
||||
Initial ist es das einfachste ein leeres temporäres Verzeichnis woanders zu
|
||||
erstellen, die `api-doc.yml` hinein kopieren und folgendes ausführen:
|
||||
@ -61,29 +66,29 @@ openapi-generator generate -g haskell -o . -i api-doc.yml
|
||||
```
|
||||
|
||||
Dieses erstellt einem dann eine komplette library inkl. Datentypen.
|
||||
Wichtig: Der Name in der api-doc sollte vom Namen des Services (oben myservice)
|
||||
Wichtig: Der Name in der `api-doc` sollte vom Namen des Services (oben `myservice`)
|
||||
abweichen - entweder in Casing oder im Namen direkt. Suffixe wie API schneidet
|
||||
der Generator hier leider ab.
|
||||
(Wieso das ganze? Es entstehen nachher 2 libraries, foo & fooAPI. Da der
|
||||
(Wieso das ganze? Es entstehen nachher 2 libraries, `foo` & `fooAPI`. Da der
|
||||
generator das API abschneidet endet man mit foo & foo und der compiler meckert,
|
||||
dass er nicht weiss, welche lib gemeint ist).
|
||||
dass er nicht weiß, welche lib gemeint ist).
|
||||
|
||||
danach: wie gewohnt `git init; git add .; git commit -m "initial"`. Auf dem
|
||||
Server der Wahl (github, gitea, gitlab, ...) nun ein Repository erstellen (am
|
||||
Besten: myserviceAPI - alles auf API endend ist autogeneriert!) und den
|
||||
Anweisungen nach ein remote hinzufügen & pushen.
|
||||
Besten: `myserviceAPI` - nach Konvention ist alles auf API endend autogeneriert!)
|
||||
und den Anweisungen nach ein remote hinzufügen & pushen.
|
||||
|
||||
#### Wieder zurück im Haskell-Service
|
||||
|
||||
In unserem eigentlichen Service müssen wir nun die API einbinden.
|
||||
Dazu erstellen wir ein Verzeichnis `libs` (konvention) und machen ein `git
|
||||
Dazu erstellen wir ein Verzeichnis `libs` (Konvention) und machen ein `git
|
||||
submodule add <repository-url> libs/myserviceAPI`
|
||||
|
||||
Git hat nun die API in das submodul gepackt und wir können das oben erstellte
|
||||
temporäre verzeichnis wieder löschen.
|
||||
temporäre Verzeichnis wieder löschen.
|
||||
|
||||
Anschließend müssen wir stack noch erklären, dass wir die API da nun liegen
|
||||
haben und passen wieder die stack.yaml an, indem wir das Verzeichnis unter
|
||||
haben und passen wieder die `stack.yaml` an, indem wir das Verzeichnis unter
|
||||
packages hinzufügen.
|
||||
|
||||
```yaml
|
||||
@ -92,9 +97,9 @@ packages:
|
||||
- libs/myserviceAPI # <<
|
||||
```
|
||||
|
||||
nun können wir in der `package.yaml` (oder `myservice.cabal`, falls kein hpack
|
||||
verwendet wird) unter den dependencies unsere api hinzufügen (name wie die
|
||||
cabal-datei in libs/myserviceAPI).
|
||||
Nun können wir in der `package.yaml` (oder `myservice.cabal`, falls kein `hpack`
|
||||
verwendet wird) unter den dependencies unsere API hinzufügen (name wie die
|
||||
cabal-Datei in `libs/myserviceAPI`).
|
||||
|
||||
### Einbinden anderer Microservices
|
||||
|
||||
@ -146,7 +151,7 @@ Es gibt 2 wichtige Pfade im Browser:
|
||||
|
||||
Wenn man einen lokalen Webserver startet kann man mittels "s" auch die
|
||||
interaktive Suche öffnen (Suche nach Typen, Funktionen, Signaturen, etc.). In
|
||||
Bash mit python3 geht das z.b. einfach über:
|
||||
Bash mit `python3` geht das z.b. einfach über:
|
||||
|
||||
```bash
|
||||
cd $(stack path --local-doc-root)
|
||||
@ -160,38 +165,41 @@ firefox "http://localhost:8000"
|
||||
|
||||
Generelles Vorgehen:
|
||||
|
||||
- in app/Main.hs:
|
||||
- in `app/Main.hs`:
|
||||
Hier ist quasi immer nur eine Zeile drin: `main = myServiceMain`
|
||||
|
||||
Grund: Applications tauchen nicht im Haddock auf. Also haben wir ein
|
||||
"src"-Modul, welches hier nur geladen & ausgeführt wird.
|
||||
- in src/MyService.hs:
|
||||
- in `src/MyService.hs`:
|
||||
`myServiceMain :: IO ()` definieren
|
||||
|
||||
Für die Main kann man prinzipiell eine Main andere Services copy/pasten. Im
|
||||
folgenden eine Annotierte main-Funktion - zu den einzelnen Vorraussetzungen
|
||||
folgenden eine Annotierte main-Funktion - zu den einzelnen Voraussetzungen
|
||||
kommen wir im Anschluss.
|
||||
|
||||
![[Main.hs#]]
|
||||
|
||||
#### Weitere Instanzen und Definitionen, die der Generator (noch) nicht macht
|
||||
|
||||
In der `Myservice.Types` werden ein paar hilfreiche Typen und Typinstanzen
|
||||
In der `Myservice.Types` werden ein paar hilfreiche Typen und Typ-Instanzen
|
||||
definiert. Im Folgenden geht es dabei um Dinge für:
|
||||
|
||||
- Envy
|
||||
- Laden von \$ENV_VAR in Datentypen
|
||||
- `Envy`
|
||||
- Laden von `$ENV_VAR` in Datentypen
|
||||
- Definitionen für Default-Settings
|
||||
- ServerConfig
|
||||
- `ServerConfig`
|
||||
- Definition der Server-Konfiguration & Benennung der Environment-Variablen
|
||||
- ExtraTypes
|
||||
- `ExtraTypes`
|
||||
- ggf. Paketweite extra-Typen, die der Generator nicht macht, weil sie nicht
|
||||
aus der API kommen (z.B. cache)
|
||||
- Out/BSON-Instanzen
|
||||
- Der API-Generator generiert nur wenige Instanzen automatisch (z.B. Aeson),
|
||||
- `Out`/`BSON`-Instanzen
|
||||
- Der API-Generator generiert nur wenige Instanzen automatisch (z.B. `aeson`),
|
||||
daher werden hier die fehlenden definiert.
|
||||
- BSON: Kommunakation mit MongoDB
|
||||
- Out: pretty-printing im Log
|
||||
- `BSON`: Kommunikation mit `MongoDB`
|
||||
- `Out`: pretty-printing im Log
|
||||
- Nur nötig, wenn man pretty-printing via `Out` statt über Generics wie z.b.
|
||||
`pretty-generic` oder die automatische Show-Instanz via `prerryShow`
|
||||
macht.
|
||||
|
||||
![[MyService_Types.hs#]]
|
||||
|
||||
@ -201,7 +209,7 @@ Den Service implementieren. Einfach ein neues Modul aufmachen (z.B.
|
||||
`MyService.Handler` oder
|
||||
`MyService.DieserEndpunktbereich`/`MyService.JenerEndpunktbereich`) und dort die
|
||||
Funktion implementieren, die man in der `Main.hs` benutzt hat.
|
||||
In dem Handler habt ihr dann keinen Stress mehr mit validierung, networking,
|
||||
In dem Handler habt ihr dann keinen Stress mehr mit Validierung, networking,
|
||||
logging, etc. pp. weil alles in der Main abgehandelt wurde und ihr nur noch den
|
||||
"Happy-Case" implementieren müsst.
|
||||
Beispiel für unseren Handler oben:
|
||||
@ -226,7 +234,7 @@ myApiEndpointV1Post sc calls amqPost log req = do
|
||||
|
||||
Diese dummy-Antwort führt auf, wie gut man die ganzen Sachen mischen kann.
|
||||
|
||||
- Logging in die Dateien/stdout nach config
|
||||
- Logging in die Dateien/`stdout` - je nach Konfiguration
|
||||
- Logging von Statistiken in Kibana
|
||||
- Speichern der Antwort in der MongoDB
|
||||
- Generieren einer Serverantwort und ausliefern dieser über die Schnittstelle
|
||||
@ -235,14 +243,14 @@ Diese dummy-Antwort führt auf, wie gut man die ganzen Sachen mischen kann.
|
||||
|
||||
##### Dateien, die statisch ausgeliefert werden sollen
|
||||
|
||||
Hierzu erstellt man ein Verzeichnis `static/` (konvention; ist im generator so
|
||||
Hierzu erstellt man ein Verzeichnis `static/` (Konvention; ist im generator so
|
||||
generiert, dass das ausgeliefert wird). Packt man hier z.b. eine `index.html`
|
||||
rein, erscheint die, wenn man den Service ansurft.
|
||||
|
||||
##### Wie bekomme ich diese fancy Preview hin?
|
||||
|
||||
Der Editor, der ganz am Anfang zum Einsatz gekommen ist, braucht nur die
|
||||
`api-doc.yml` um diese Ansicht zu erzeugen. Daher empfielt sich hier ein
|
||||
`api-doc.yml` um diese Ansicht zu erzeugen. Daher empfiehlt sich hier ein
|
||||
angepasster Fork davon indem die Pfade in der index.html korrigiert sind. Am
|
||||
einfachsten (und von den meisten services so benutzt): In meiner Implementation
|
||||
liegt dann nach dem starten auf http://localhost:PORT/ui/ und kann direkt dort
|
||||
@ -265,11 +273,11 @@ Was tut das?
|
||||
WIRKLICH alles ist )
|
||||
- `-Wcompat`: Warnungen für Sachen, die in der nächsten Compilerversion kaputt
|
||||
brechen werden & vermieden werden sollten
|
||||
- `--interleaved-output`: stack-log direkt ausgeben & nicht in dateien schreiben
|
||||
- `--interleaved-output`: stack-log direkt ausgeben & nicht in Dateien schreiben
|
||||
und die dann am ende zusammen cat\'en.
|
||||
|
||||
Um pro Datei Warnungen auszuschalten (z.B. weil man ganz sicher weiss, was man
|
||||
tut -.-): `{-# OPTIONS_GHC -Wno-whatsoever #-}` als Pragma in die Datei.
|
||||
tut -.-): `{-# OPTIONS_GHC -Wno-whatsoever #-}` als pragma in die Datei.
|
||||
|
||||
**Idealerweise sollte das Projekt keine Warnungen erzeugen.**
|
||||
|
||||
@ -277,18 +285,18 @@ tut -.-): `{-# OPTIONS_GHC -Wno-whatsoever #-}` als Pragma in die Datei.
|
||||
|
||||
Als Beispiel sei hier ein einfaches Docker-Build mit Jenkins-CI gezeigt, weil
|
||||
ich das aus Gründen rumliegen hatte. Kann man analog in fast alle anderen CI
|
||||
übrsetzen.
|
||||
übersetzen.
|
||||
|
||||
#### Docker
|
||||
|
||||
Die angehängten Scripte gehen von einer Standard-Einrichtung aus (statische
|
||||
sachen in static, 2-3 händische Anpassungen auf das eigene Projekt nach
|
||||
Sachen in static, 2-3 händische Anpassungen auf das eigene Projekt nach
|
||||
auspacken). Nachher liegt dann auch unter static/version die gebaute
|
||||
Versionsnummer & kann abgerufen werden. In der Dockerfile.release und der
|
||||
Jenkinsfile müssen noch anpassungen gemacht werden. Konkret:
|
||||
Versionsnummer & kann abgerufen werden. In der `Dockerfile.release` und der
|
||||
`Jenkinsfile` müssen noch Anpassungen gemacht werden. Konkret:
|
||||
|
||||
- in der Dockerfile.release: alle `<<<HIER>>>`-Stellen sinnvoll befüllen
|
||||
- in der Jenkinsfile die defs für "servicename" und "servicebinary" ausfüllen.
|
||||
- in der `Dockerfile.release`: alle `<<<HIER>>>`-Stellen sinnvoll befüllen
|
||||
- in der `Jenkinsfile` die defs für "servicename" und "servicebinary" ausfüllen.
|
||||
Binary ist das, was bei stack exec aufgerufen wird; name ist der Image-Name
|
||||
für das docker-repository.
|
||||
|
||||
@ -296,11 +304,12 @@ Jenkinsfile müssen noch anpassungen gemacht werden. Konkret:
|
||||
|
||||
Änderungen die dann noch gemacht werden müssen:
|
||||
|
||||
- git-repository url anpassen
|
||||
- Environment-Vars anpasses ($BRANCH = test & live haben keine zusatzdinger im
|
||||
docker-image-repository; ansonsten hat das image $BRANCH im namen)
|
||||
- git-repository URL anpassen
|
||||
- Environment-Vars anpassen (\$BRANCH = test & live haben keine zusatzdinger im
|
||||
docker-image-repository; ansonsten hat das image \$BRANCH im Namen)
|
||||
|
||||
Wenn das durchgebaut ist, liegt im test/live-repository ein docker-image namens `servicename:version`.
|
||||
Wenn das fertig gebaut ist, liegt im test/live-repository ein docker-image
|
||||
namens `servicename:version`.
|
||||
|
||||
### OMG! Ich muss meine API ändern. Was mache ich nun?
|
||||
|
23
content/Coding/OpenAPI.md
Normal file
23
content/Coding/OpenAPI.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Openapi-generator
|
||||
|
||||
## Idee hinter einem API-Generator
|
||||
|
||||
[[TODO]] Idee hinter einem API-Generator
|
||||
|
||||
## Theorie und Praxis
|
||||
|
||||
[[TODO]] Theorie und Praxis
|
||||
|
||||
## Spezialfall in Haskell
|
||||
|
||||
[[TODO]] Veraltet
|
||||
|
||||
Wie im [[Webapp-Example]] kurz angerissen wird in Haskell nicht zwischen Server
|
||||
und Client unterschieden. Daher können hier sehr viele Optimierungen bei
|
||||
Änderungen passieren, die in anderen Sprachen nicht so einfach möglich sind.
|
||||
|
||||
Die generierte Library hat die Funktionen, die ein Client braucht direkt dabei
|
||||
und man muss lediglich die Verbindung initialisieren (Callback für
|
||||
Network-Requests, Serveradresse etc.) und kann dann direkt alle Funktionen
|
||||
benutzen. Partial Application hilft hier massiv und man bekommt z.b. Für die
|
||||
Beispiel-Tierhandlung aus dem ursprünglichem `getPet :: ` direkt so etwas wie `getPet :: PetID -> IO Pet`
|
9
content/Opinions/Editors.md
Normal file
9
content/Opinions/Editors.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Editors
|
||||
|
||||
Better said: "why neovim is currently my favorite editor" :wink:
|
||||
|
||||
## Current Config
|
||||
|
||||
You can find my current Config along with other things in my [gitea snippet-git](https://gitea.dresselhaus.cloud/Drezil/snippets).
|
||||
|
||||
[[TODO]]: write more awesomesauce :wink:
|
35
content/Opinions/Layout.md
Normal file
35
content/Opinions/Layout.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Keyboard-Layouts
|
||||
---
|
||||
|
||||
# My Keyboard-Layout
|
||||
|
||||
Since around 2006 i basically write only using the
|
||||
[NEO2](https://neo-layout.org)-Layout. There are many advantages that are not obvious to
|
||||
an onlooker right away.
|
||||
|
||||
Don't get me wrong. I still can type QWERTZ - just because you learn an
|
||||
additional layout does not mean that you forget everything from before.
|
||||
|
||||
The secret sauce lies in the deeper layers. Especially layer 3 having all the
|
||||
"hard to reach" things like brackets, braces, etc. right on the home row.
|
||||
And the 4th layer is *magic* for text-navigation. Left hand has the full
|
||||
navigation, right hand has the complete Numpad - even on laptop-keyboards that
|
||||
are lacking those.
|
||||
|
||||
For me as a person having the usual German Keyboard with AltGr this just means:
|
||||
|
||||
- Putting the thumb down on AltGr - it is above there anyway.
|
||||
- Use left hand as normal arrow-keys (that work EVERYWHERE because they are just
|
||||
arrow keys)
|
||||
- Also use Home/End/PgUp/PgDown/...
|
||||
|
||||
Before i always had to switch over or hope that a thing had support for
|
||||
vi-style "hjkl".
|
||||
|
||||
Thats why i also prefer [[Opinions/Editors|Neovim]] as my primary editor - just not having to
|
||||
touch your mouse at any time for anything is such a godsend :smile:
|
||||
|
||||
Best thing: If you don't want to switch, there is also a "Neo-QWERTZ"-variant ..
|
||||
where you can just try the deeper layers while not leaving your QWERTZ-layout
|
||||
behind. But i have just seen and never tried it. Your experience may be sub-par.
|
5
content/TODO.md
Normal file
5
content/TODO.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Todo
|
||||
---
|
||||
|
||||
Todo List in backlinks below vvv
|
Reference in New Issue
Block a user