AVOID PRIMARY KEY-ASSISTANT

Viele 4D-Anwendungen draußen haben den Update auf die V14 noch vor sich. Die V14 erwartet Primärschlüssel für jede Tabelle oder weigert sich ein Logbuch zwischen den Backups zu führen. Kein Logbuch ist keine Option.

Eine frisch nach V14 konvertierte Datenbank meldet die Tabellen, denen der Primärschlüssel fehlt. Nicht weil ihnen einer fehlt, sondern weil 4D nicht weiß, welches Feld als Primärschlüssel verwendet wird.

Vergessen Sie den Assistenten. → weiter

Automatisches Testen

MarioS

Ein Gastbeitrag von Mario Schulz

Meine Situation unterschiedet sich nicht von der anderer 4D-Entwickler.

Kaum habe ich ein Modul fertig, schon kommen die nächsten Ideen. Dies könnte man noch einflechten oder jenes oder zu einem fertigen Modul möchte ein Kunde eine Erweiterung haben. Soweit ist das kein Problem. Dann geht es ans Testen. Die meisten Fehler sind schon dadurch gefunden, daß man sich sein neues Interface anschaut und einmal durchklickt, ohne auf Werte zu achten. 4D meldet die Laufzeitfehler von allein. Der Rest ist dann akribisches Nachrechnen, Ausprobieren und Testlisten abarbeiten. Ein Problem sind die Seiteneffekte. Diese tauchen dort auf, wo man sie nicht erwartet und werden übersehen. Meine Anwendung ist groß. Diese komplett von A bis O zu testen, ist alleine kaum zu schaffen.

Andere Sprachen sind in diesem Thema bereits weiter. Das weckt in mir (teilweise) Begehrlichkeiten. 4D ist nicht das Problem, sondern die monolithischen Architekturen, die mit derlei Sprachfamilien geschaffen werden. Wie sollen diese automatisch getestet werden, wenn in einer Objektmethode die gesamte Logik von Eventhandling, Geschäftslogik und Datenbankzugriff steckt.

Für das Testen lassen sich drei Bereiche unterscheiden.

1) Das Interace

Die GUI lässt sich von allen Bereichen am schwersten automatisch testen. So gibt es etliche Frameworks/Programme die einem das abnehmen. Die Natur der Frameworks/Programme ist ziemlich identisch. Sie feuern eine Sequenz von Events ab (vornehmlich Mausklicks), immer an der vordefinierten Position. Ziehen dann von einem Bereich ein Bildschirmfoto und vergleichen das mit einem hinterlegten Bild oder versuchen mittels OCR einen Text einzulesen. Bei einigen lässt sich noch eine Art delta hinterlegen, eine Abweichung die nicht bemängelt wird.

Alles in allem sehr aufwendig. Das Interface in meinen Anwendungen ist der Bereich, der sich am häufigsten und schnellsten ändert. Apple liefert alle ein bis anderthalb Jahre ein neues Interface und Windows zieht ebenfalls an.
Anschließend alle Tests anzupassen kann schnell in mehr Arbeit ausarten als eine eigene Testliste abzuarbeiten.

2) Funktionen

Ist der mit Abstand am Besten zu testende Bereich. Hierfür gibt es UnitTests. In Wakanda ist das YUI-Framework enthalten. Für fast jede Sprache gibt es mittlerweile ein xUnit-Framework. Für 4D hatte sich Mark Schaarke mal dran probiert: UnitTester for 4D v11 and v12.

Wie der Name bereits sagt, sind UnitTests für Units. In 4D gibt es keine Units. Vom Prinzip her hat es sich damit bereits erledigt. 4D verhindert aber nicht, das man sich über Präfixe Units schafft. Oder man sieht die Projektmethoden als Unit an, daran ist auch nichts falsch. Seitdem es Komponenten gibt, hat sich die Sache für mich geändert. In den Komponenten hab ich viel Funktionalität hinterlegt/ausgelagert
– Kommunikation mit diversen Servern
– Berechnung von Prüfziffern
– einlesen und parsen eines Dokumentes und dazugehörende Hilfsfunktionen.
Gleiches gilt für Methoden/Funktionen der HostDB, die noch nicht in Komponenten ausgelagert sind.

Bei Funktionen kann ich ein erwartetes Ergebnis mit dem Ergebnis vergleichen, den mir die Funktion liefert. Um diese zu überprüfen leg ich normalerweise ein Trace bzw. Breakpoint an die Stelle und überprüfe im Debugger, ob genau das Ergebnis kommt, das ich erwartet habe. Oder ich schreibe mir eine Dummy-Methode in der ich der Funktion die Testparameter fest übergebe, um mir dann die Ausgabe anzuschauen. Mit der Zeit sammeln sich diese Testmethoden an.

Kaum habe ich sie gelöscht muss ich sie anschließend neu schreiben, weil ich genau an dieser Funktion etwas ändern möchte. Ist alles in allem sehr zeitaufwändig. Also warum nicht die Testmethoden einmal schreiben und für den Test automatisch in die Host-DB eintragen und ausführen lassen. Mein Vorteil liegt darin, ich kann alle Tests auf einmal ausführen und erhalte nach wenigen Millisekunden das Ergebnis.

3) Datenbankzugriffe

Kann man ebenfalls mit UnitTests zugrunde rücken, setzen aber oft einen vordefinierten Zustand der Datenbank voraus. So kann ich hier auch die Konsistenz der Datenbank prüfen, also ob ein Feld in Abhängigkeit von einem oder zwei anderen Felder einen bestimmten Wert hat. Geht aber sehr schnell über in Tests die ich in einem Wartungsmodul erwarten würde. Wo der Kunde die Konsistenz seiner eigenen Datendatei überprüfen kann. Zum Beispiel haben alle Felder eine UUID zum synchronisieren und wenn nein dann aktualisiere den Datensatz. Brauch also nicht ich, sondern der Kunde/Support.

Schon eher wird für mich ein Schuh draus, wenn ich hier die hinterlegten Geschäftslogiken überprüfen kann. Ist in Tabelle y ein Datensatz vorhanden, wenn Methode z auf Tabelle x ausgeführt wird? Und wenn ja, haben bestimmte Felder die richtigen Werte?

Oder ich führe eine Aktualiserung der DB durch und will wissen, ob es funktioniert. Diese in die Tests aufzunehmen, macht meistens dann Sinn, wenn man erwarten kann, das durch einen Seiteneffekt – neues Betriebssystem, neue 4D Version – sich das Verhalten ändern kann.

Aber zurück zum Thema UnitTests.
Wer hier den heiligen Gral sucht, ist schnell enttäuscht. Aber einen Teil meiner Arbeit kann ich durchaus automatisieren bzw. vereinfachen.
– ich muss ein erwartetes Ergebnis mit einem Ergebnis vergleichen können, das ich nach Ausführen einer Methode/Funktion erwarte
– ich will den Testcode nicht in meiner Host-DB aufbewahren
– ich will es einfach haben: Komponente reinwerfen, starten, ausführen, Ergebnis sehen.

Komponente UnitTests

Die Komponente ist eine für 4D v14 aber alle Techniken gibt es bereits ab V13.
Zum Ausführen muss eine Callback-Methode hinterlegt werden. Selber anlegen brauch man sie nicht, das macht die Komponente. In der Callback-Methode wird der Testcode geladen (METHOD SET CODE), ausgeführt (EXECUT METHODE) und anschließend die angelegte Methode wieder gelehrt. Das Löschen einer Methode wird von 4D nicht unterstützt.

Ein anders Manko: hat man die Callback-Methode über den Explorer manuell geöffnet, ist sie schreibgeschützt und kann nicht für die Komponente verwendet werden. Damit die Komponente aber nicht nach dem Compilieren mit der Host-DB verknüpft ist, wird die Callback-Methode gelehrt. Ich brauche diese zum Testen nicht zum Ausliefern.

Um die Komponente zu starten reicht es, über Start/Methode ausführen „UnitTest_interface“ zu wählen. Man wird nach einem Arbeitsverzeichnis gefragt, hier werden alle Testsuites samt Tests gespeichert. Eine Testsuite zum importieren und Ausführen liegt der Beispiel-DB bei.

test_Suite

Wollen Sie eigene UnitTests anlegen, brauchen Sie eine Anleitung. In der Beispiel-Anwendung werden Sie beim Start gefragt, ob Sie das Tutorial sehen wollen. Machen Sie das.

UnitTestTutorial

 

Vorher laden Sie sich die  Testanwendung. Die Komponente entnehmen Sie der Testanwendung oder laden sie hier UnitTest-component.

Benutzen so wie ist für jedermensch, Source-Code auf Nachfrage.

David Dancy: Apple Purchased FoundationDB

Ab und an stolpere ich über aufhebenswerte Texte anderer. Hier David Dancy über Apples Kauf der FoundationDB. Lesenswert!

Sometimes I stumble across a text from somebody I want to archive. In this case it’s from David Dancy aboutApple purchasing FoundationDB. Good read!

I’ve been tracking FoundationDB for a few years now.

The important thing about it is that it’s a distributed database – i.e. the data resides on lots of servers all at once, with no one server having all of it. They have a layer in front of the database engine that manages all the servers automatically, handling failovers and adding new servers to clusters etc.

This is not particularly new. There are several other databases in the market that do this (I know a bit about MongoDB and Couchbase, for example, but others exist too).

What’s different about FoundationDB is that the database engine as a whole is ACID compliant.

I’m not sure if anyone else makes this claim about their engine.

Couchbase doesn’t, and I don’t think MongoDB does either. They call their engines „eventually consistent“, with parameters you can tune to say whether you require data to be persisted to the disk (it gets written to RAM first) _and_ replicated to other servers and/or clusters before the write operation returns to the client. If you choose not to require this, data can be inconsistent for a brief period while the replicas synchronise their changed data. You as designer can allow this because (say) fast writing may be more important in your particular application than having all data exactly the same at all times.

FoundationDB is a game-changer because it promises horizontally-scalable clustered data that maintains the consistency requirement while still remaining fast. This is really important for people with databases the scale of Apple’s.

Also, internally FoundationDB is implemented as a key-value store (basically a dictionary, so there’s no inherent requirement for a schema). But on top of that they have various API layers, including a nice one that does SQL. So in effect you end up with a distributed database that you can query using SQL with ACID compliance in the storage engine.

That’s really nice!

Funny thing is it used to be open source, but after Apple bought it the GitHub account was emptied out and there’s nothing there now. But there’s probably a few guys wandering around Silicon Valley seeing which helicopters and private jets they’re going to buy for their collection…

David Dancy
Sydney, Australia

Date: Fri, 27 Mar 2015 17:07:21 +1100
To: 4D iNug Technical <4d_tech@lists.4d.com

Und ein Nachtrag. As a addendum

You could follow it up with a link to this Achitecture.pdf

It’s a classic example of the „solve problems by using an extra layer of indirections“ methodology.

DBZ_SIGNWIDGET

Signieren lassen

Kommt ein Paket an, hält mir der Auslieferer sein Gerät vor die Nase und bittet mich mit einem Stift auf diesem Gerät zu unterschreiben. x-mal gemacht und die Unterschrift ist mehr oder weniger die meine.

Kann ich das auch in 4D haben? Yep – hier ein Screenshot.
DBZ_SignWidget
… mehr

Assign a value to a form local variable

there is a 4D forums-thread Array to hierarchical list, need code. Main interest is converting a paths-array into a hierarchical-list.

Keisuke Miyako build a demonstration. Again using regex to split the path-elements
Match regex(„([^/]+)/(.*)“;$item;1;$pos;$len)
The Gem for me are these two lines in the object-method for the form-list.
//because we can’t directly assign to a form local variable
VARIABLE TO VARIABLE(Current process;Self->;$list)

    I learned two things

  • we can use hierarchical list without an attached longint-variable, i.e. object-name only
  • we can’t directly assign to a form local variable, unless we force 4D to call itself, even inexplicit