home
erste Version am 20.11.2020
letzte Änderung am 10.01.2021

ERMzilla

In der Firma werkeln wir schon seit einiger Zeit -parallel zum Tagesgeschäft- intensiv am Redesign unserer Datenbank bzw. an deren zukünftigen Stukturen rum. Bisher wurde zum Zeichnen der ERMs das Programm Dia genutzt.
Man kann das Ding auch so einstellen, dass man damit ERMs (halbwegs brauchbar) zeichnen kann - aber leider kommen da nur Binär-Dateien raus. Und damit lassen sich Änderungen an den Modellen praktisch nicht via GitHub verfolgen.
Exakt das möchte ich aber eigentlich unbedingt können!
Dann ging einige Zeit ins Land und in meinem Hirn lief immer mal wieder eine Art Background-Prozess zu diesem Thema. Will heißen: eine Idee reifte.
Letztes Wochenende habe ich dann meinen Ausschalttimer endlich fertiggestellt und direkt danach angefangen, meine Idee in einem Prototypen umzusetzen.
Bereits am Montag stand ein nutzbarer Entwurf. Dank der Corona-bedingten Arbeit aus dem Homeoffice spare ich derzeit jeden Tag 40 Minuten Fahrzeit und durchschnittlich 60 Minuten Outdoor-Rauch-Pausen-Zeit. Jedenfalls habe ich dadurch auch nach Feierabend noch Lust und Muße, an eigenen Programmen rumzubasteln. Und damit bin ich jetzt nach noch nicht ganz einer Woche Freizeit-Zeit soweit, eine V1.01 zu veröffentlichen.


Inhaltsverzeichnis

Version 1.01 - erste veröffentlichte Version
Version 1.02 - Export des ERMs als PNG
Version 1.03 - Attribut-Umzug und neues Keyword TABCOLOR
Version 1.04 - mini-Fix und ToDo-Liste
Version 1.05 - Tastatur-Abfrage und Markieren/Verschieben von ganzen Bereichen
Version 1.06 - Aufräumarbeiten und Kommentare
Version 1.07 - Kommentare überleben einen save, Auto-Positionierung v0.01
Version 1.08 - Änderungs-Historie, Verarbeitung von Strg-Z bzw. undo und got/lost-Focus-Magie
Überlegungen #1 - ...zu Service-Scripten zwecks Interaktion mit MySQL
Version 1.09 - neues Keyword CONSTRAINT für in SQL abbildbare Beziehungen
Version 1.10 - neues Keyword NOTE für im ERM sichtbare Kommenare
Version 1.11 - Fenster-Größe/Position speicherbar, Align-ERM, ZoomIn/ZoomOut, Seitenwechsel für Tabellen-Andock-Punkt mit Auswahl
Version 1.12 - Anpassungen für wxPython v3 und v4, Footer im Snapshot, neues Keyword ZOOMLVL
Version 1.13 - diverse kleine Korrekturen, DPI-Wert-Unabhängigkeit
Version 1.14 - LoadFile-Dialog, Menü-Hotkeys, Farben änderbar
Version 1.15 - Anzeige der zugehörigen Zeilennummer bei Klick auf ein Objekt
Version 1.16 - Kleinkram (Speicher-Abfrage in onClose(), spezieller Verschiebe-Cursor, ...)


Version 1.01

Die (sehr simple) Idee ist, Tabellen- und Relations-Definitionen mit einem Text-Editor zu erfassen und im GUI-Programm lediglich Änderungen an den Positionen der Tabellen und der Linienführung der Relationen zu erlauben. Diese Daten werden von ERMzilla am Ende der Text-Datei in Menschen-lesbarem Format gesammelt.
Es ist eine bewusste und grundlegende Design-Entscheidung, dass per GUI ausschließlich die Optik des ERMs verändert werden kann.
Strukturelle Änderungen müssen grundsätzlich in der Text-Datei per Tastatur vorgenommen werden.
Damit sollten sich strukturelle Änderungen leicht von Positions-Änderungen unterscheiden lassen, wenn man sich die Änderungen später auf GitHub ansieht.
Nebenbei wird dadurch auch erreicht, dass Beziehungen nicht aus Versehen eine Spalte rauf- oder runter-rutschen können - wie es bei Dia gerne mal passiert.

Eine ERM-Datei sieht beispielsweise im ersten Ansatz so aus:
TABLE Company
id int PK
name varchar
desc varchar
addr varchar
RELATION Company.Company2Project 1-n Company.id Company2Project.company_id
RELATION Company.Company2Person 1-n Company.id Company2Person.company_id

TABLE Project
id int PK
name varchar
desc varchar
RELATION Project.Company2Project 1-n Project.id Company2Project.project_id
RELATION Project.Project2Person 1-n Project.id Project2Person.project_id

TABLE Person
id int PK
name varchar
addr varchar
RELATION Person.Company2Person 1-n Person.id Company2Person.person_id
RELATION Person.Project2Person 1-n Person.id Project2Person.person_id
RELATION Person.Person2Skill 1-n Person.id Person2Skill.person_id

TABLE Skill
id int PK
name varchar
RELATION Skill.Person2Skill 1-n Skill.id Person2Skill.skill_id

TABLE Company2Project
company_id int PK
project_id int PK

TABLE Project2Person
project_id int PK
person_id int PK
from_dt datetime
to_dt datetime

TABLE Company2Person
person_id int PK
company_id int PK
from_dt datetime
to_dt datetime

TABLE Person2Skill
person_id int PK
skill_id int PK

Nach dem Load und erster Vor-Positionierung der Tabellen sieht es dann etwa so aus:
Screenschot von ERMzilla - roh

Nach dem hübsch-Machen dann etwa so:
Screenschot von ERMzilla - hübsch gemacht

Und die ERM-Datei danach so:
TABLE Company
id int PK
name varchar
desc varchar
addr varchar
RELATION Company.Company2Project 1-n Company.id Company2Project.company_id L L
RELATION Company.Company2Person 1-n Company.id Company2Person.company_id R L

TABLE Project
id int PK
name varchar
desc varchar
RELATION Project.Company2Project 1-n Project.id Company2Project.project_id L R
RELATION Project.Project2Person 1-n Project.id Project2Person.project_id R L

TABLE Person
id int PK
name varchar
addr varchar
RELATION Person.Company2Person 1-n Person.id Company2Person.person_id L R
RELATION Person.Project2Person 1-n Person.id Project2Person.person_id R R
RELATION Person.Person2Skill 1-n Person.id Person2Skill.person_id R L

TABLE Skill
id int PK
name varchar
RELATION Skill.Person2Skill 1-n Skill.id Person2Skill.skill_id R R

TABLE Company2Project
company_id int PK
project_id int PK

TABLE Project2Person
project_id int PK
person_id int PK
from_dt datetime
to_dt datetime

TABLE Company2Person
person_id int PK
company_id int PK
from_dt datetime
to_dt datetime

TABLE Person2Skill
person_id int PK
skill_id int PK



TABPOS Company (42,28)
RELPOS Company.Company2Project (14,70) (14,266)
TABPOS Project (224,238)
TABPOS Person (462,14)
RELPOS Person.Project2Person (602,84) (602,294)
TABPOS Skill (686,224)
RELPOS Skill.Person2Skill (826,266) (826,70)
TABPOS Company2Project (42,224)
TABPOS Project2Person (406,238)
TABPOS Company2Person (224,14)
TABPOS Person2Skill (672,14)

Derzeit werden Dateien per Kommandozeilen-Parameter oder per Drag&Drop geladen.
Der virtuelle Arbeitsbereich ist quasi unendlich groß. Die Bewegung darin geschieht im openstreetmap- bzw. GoogleMaps-Style - zumindest solange, wie man nicht auf eine Tabelle oder einen Relations-Eckpunkt klickt. In diesem Fall werden die jeweils angeklickten Elemente verschoben.

Was bisher noch fehlt, ist der Export des ERMs als Bild-Datei. Sofern das ERM komplett auf den Bildschirm passt, kann man sich derzeit mit einem Tool für Bildschirmfotos behelfen.
Vielleicht werde ich die Syntax der ERM-Datei auch noch insofern erweitern, dass die Farbe des Tabellen-Headers steuerbar wird - und dadurch leichter zwischen echten Entitäten und Beziehungstabellen unterschieden werden kann.
Weiterhin stehen noch Tests mit anderen DPI-Werten oder Font-Größen aus.

Aber jetzt ist schon seit einer Stunde Samstag...daher hier erstmal die v1.01.


Version 1.02

Es ist immer noch Samstag und gerade 19:00 Uhr durch. Ärgerlicherweise hat mein Jüngster heute seinen Aldi-Windows-PC geschrottet. Meine Wiederbelebungsversuche waren nicht erfolgreich, haben mir aber trotzdem mindestens zwei Stunden Lebenszeit geraubt .... bzw. mich an der Weiterentwicklung von ERMzilla gehindet.

Mittlerweile hat der Code trotzalledem bewiesen, dass er unter folgenden wxPython-Versionen (gemäß wx.version()) läuft:
2.8.12.1 (gtk2-unicode)unter "Python 2.7.12"opensuse 13.02
3.0.2.0 gtk3 (classic)unter "Python 2.7.17"ubuntu 18.04
4.1.0 gtk3 (phoenix) wxWidgets 3.1.4unter "Python 3.8.5"ubuntu 20.04
Für die 4'er-Version habe ich den Shebang in allen Scripten [zurück] auf python3 geändert.
Ursprünglich war die Zielplattform eigentlich sowieso python3 und phoenix unter ubuntu 20.04 gewesen.
Allerdings hat die Installation von phoenix (bzw. der make via pip3) zu gefühlten zwei Stunden Volllast auf zwei (virtuellen) CPUs geführt.
Das wollte ich meinen Kollegen einfach nicht zumuten .... wenn sie ERMzilla schließlich irgendwann nutzen sollen/müssen.  ;-)

Erst danach hatte ich erkannt, dass die 3'er-Version von wxPython unter ubuntu 18.04 offenbar binär vorliegt und per "apt install python-wxtools" ratzfatz installiert ist. Allerdings dann eben nicht python3 - sondern python (2.7).
Und als ich dann noch erkannt hatte, dass der 4'er-Code mit python (2.7) auch vollkommen warning-free auf meinem uralt-opensuse läuft, habe ich einfach dort weitergemacht.

Nach dem Versions-Kompatibilitäts-Test habe ich den Export von ERMs als PNG-Bild implementiert.
Egal, wie groß das ERM ist und egal, welchen Ausschnitt man sich davon gerade in ERMzilla ansieht - im Export wird es immer vollständig dargestellt. Und ich musste am bestehenden Code kaum was ändern und die Export-Funktion hat lächerliche 19 Zeilen. wxPython ist einfach geil!
Das exportierte Original-Bild hatte eine Auflösung von 3775×2422 Pixeln:
ERM mit etwas größeren Abmessungen

Wenn morgen nix Unvorhergesehenes dazwischen kommt, werde ich die unsäglichen LR-Attribute in den RELATION-Sätzen in die RELPOS-Sätze umziehen lassen.
Auch sollen Kommentare in der *.ERMzilla-Datei zukünftig durch einen save nicht einfach gelöscht werden.
Und wegen des regelmäßig nötigen Fokus-Wechsels zwischen Text-Editor und ERMzilla könnte etwas got/lost-fokus-Automatik bezüglich reload und save ganz praktsich sein.
Wir werden sehen.... für heute langts jedenfalls.


Version 1.03

So. Die LR-Attribute sind vom RELATIONS-Satz in den RELPOS-Satz umgezogen. Schließlich sind das Attribute, die aus ERMzilla heraus (per MouseWheel...btw.) geändert werden können. Damit gehören sie zu den dynamischen Daten und sollen auch dort gespeichert werden.

Ebenfalls gibt es jetzt das neue Keyword TABCOLOR, mit dem die Hintergrundfarbe der einzelnen Tabellen-Header angepasst werden kann.

Mit den neusten Änderungen sieht es jetzt so aus:
ERMzilla v1.03

Die ERM-Datei danach so:
TABLE Company
id int PK
name varchar
desc varchar
addr varchar
TABCOLOR Company #0088ff
RELATION Company.Company2Project 1-n Company.id Company2Project.company_id
RELATION Company.Company2Person 1-n Company.id Company2Person.company_id

TABLE Project
id int PK
name varchar
desc varchar
TABCOLOR Project #0088ff
RELATION Project.Company2Project 1-n Project.id Company2Project.project_id
RELATION Project.Project2Person 1-n Project.id Project2Person.project_id

TABLE Person
id int PK
name varchar
addr varchar
TABCOLOR Person #0088ff
RELATION Person.Company2Person 1-n Person.id Company2Person.person_id
RELATION Person.Project2Person 1-n Person.id Project2Person.person_id
RELATION Person.Person2Skill 1-n Person.id Person2Skill.person_id

TABLE Skill
id int PK
name varchar
TABCOLOR Skill #0088ff
RELATION Skill.Person2Skill 1-n Skill.id Person2Skill.skill_id

TABLE Company2Project
company_id int PK
project_id int PK

TABLE Project2Person
project_id int PK
person_id int PK
from_dt datetime
to_dt datetime

TABLE Company2Person
person_id int PK
company_id int PK
from_dt datetime
to_dt datetime

TABLE Person2Skill
person_id int PK
skill_id int PK



TABPOS Company (42,28)
RELPOS Company.Company2Project LL (14,70) (14,266)
RELPOS Company.Company2Person RL
TABPOS Project (224,238)
RELPOS Project.Company2Project LR
RELPOS Project.Project2Person RL
TABPOS Person (462,14)
RELPOS Person.Company2Person LR
RELPOS Person.Project2Person RR (602,84) (602,294)
RELPOS Person.Person2Skill RL
TABPOS Skill (686,224)
RELPOS Skill.Person2Skill RR (826,266) (826,70)
TABPOS Company2Project (42,224)
TABPOS Project2Person (406,238)
TABPOS Company2Person (224,14)
TABPOS Person2Skill (672,14)

Hier dann noch die v1.03.


Version 1.04

Gerade habe ich aus gegebenem Anlass einen mini-Fix für den Fall eingebaut, dass der Tabellenname länger ist, als die Summe aus dem jeweils längsten Element von Spaltenname + Datentyp + Attribut[e].
Parallel sind bei der Nutzung von ERMzilla ein paar fehlende Features aufgefallen.
Dementsprechend brauche ich jetzt erstmal eine ToDo-Liste für die kommenden Freizeiten.
In zwei Wochen werden ich nämlich meinen 2020'er-Resturlaub abbauen (der durch die Feiertage und meine bisherige Sparsamkeit diesmal über vier Wochen geht).
Bis dahin will ich möglichst viele ToDo's identifiziert haben.
Weil: eine Woche Sippschaft, eine weitere Woche 37C3-Videos ... folglich müssen die ToDo's für mindestens zwei Wochen Hobby langen. ;-)

Bisherige ToDo's:


Version 1.05

Es ist mal wieder Samstag und ich habe größere strukturelle Umbauten vornehmen müssen, um das [zunächst] wichtigste ToDo "Markieren/Verschieben von ganzen Bereichen" implementieren zu können.
Im ersten Schritt mussten Tastatur-Events aktiviert werden. Offenbar hat wxPython damit Probleme, wenn es nur einen wx.Frame gibt. Mit einem wx.Window in einem wx.Frame klappt alles bestens ... kenne ich schon von diversen anderen wxPython-Projekten (konkret habe ich hier bei tun0graf gespickt).
Im zweiten Schritt mussten quasi sämtliche Maus-Events dahingehend geändert werden, dass jetzt auf mehreren Objekten operiert wird und außerdem der Status der Shift- und Strg-Tasten berücksichtigt wird.
Dazu war die unterschiedliche Darstellung von markierten und nicht markierten Objekten vergleichsweise schnell implementiert.

Jedenfalls ist jetzt die Strg-Taste gedrückt zu halten, wenn man den angezeigten Ausschnitt auf der virtuellen Arbeitsfläche verschieben will.
Das war nötig, damit bei der exakt gleichen Maus-Aktion (dann aber natürlich ohne gedrückte Strg-Taste) stattdessen ein Rechteck aufziehbar wird, mit dem Tabellen und Relations-Eckpunkte im Stück markiert werden können.
Alternativ bzw. zusätzlich kann man bei gedrückter Shift-Taste mehrere Objekte einzeln anklicken, um diese damit der Menge der markierten Objekte hinzuzufügen.
Final kann man dann eins der markierten Objekte anklicken und -zusammen mit allen anderen markierten Objekten- an einen anderen Ort ziehen.

Noch ist das Haupt-Script zwar ziemlich pfuschig und enthält deaktivierte Bereiche mit altem Code-Stand - weil aber schon alles recht gut klappt und ich für heute Feierabend machen will, anbei die v1.05.


Version 1.06

Heute habe ich die gestrige Script-Version lediglich hübsch gemacht. Will heißen: Kommentare zugefügt, Code ausgedünnt und ein/zwei mini-Bugfixes.
Hier dann noch die v1.06.


Version 1.07

Diesen Sonntag will ich ein paar der o.g. ToDo's implementieren.

Zuerst sollen Kommentare die save-Operation überleben. Da die LR-Attribute ja bereits bei der v1.03 zu den dynamischen Daten umgezogen sind, war dazu nicht mehr zu tun, als die Eingangsdatei solange in die Ausgangsdatei zu kopieren, bis das erste TABPOS- oder RELPOS-Kommando erkannt wird. Danach werden einfach die neuen/veränderten Daten angehängt ... und fertig.

Dann sollen Tabellen, für die noch keine Position definiert ist, nicht sämtlich auf der Position (0, 0) landen. Leichte Probleme bereitete zunächst der Umstand, dass die Abmessungen einer Tabelle erst ermittelt werden können, wenn es bereits einen DeviceContext dafür gibt. Weil der aber auch ein MemoryDC sein darf, war es dann doch kein Problem. Die Funktion versucht jetzt für jede unpositionierte Tabelle eine Position zu finden, an der diese keine andere Tabelle überdeckt. Es werden bis zu 20 zufällig gewählte Koordinaten durchprobiert und jeweils gegen alle bereits positionierten Tabellen geprüft. ...Nicht schön... aber zumindest besser als vorher.

Für die "got/lost-fokus-Magie" braucht es erstmal eine Änderungserkennung. Und die sollte idealerweise gleich so gebaut sein, dass damit ebenfalls eine Strg-Z-Funktion (letzte Änderung[en] rückgängig machen) realisiert werden kann.
Weil ich heute zuoft abgelenkt wurde und zusätzlich noch meine vier Wochen Urlaub mittlerweile in greifbarer Nähe sind, werde ich mir das bis dahin aufsparen. :-)

Daher enthält die v1.07 jetzt nur zwei Erweiterungen.



Mit der Version 1.08 geht es auf der nächsten Seite weiter.