Wie kann man unter bestimmten Bedingungen die Aufmerksamkeit des Programmierers auf sich ziehen?


13

Beginnen wir mit einem Beispiel.

Nehmen wir an, ich habe eine Methode namens export, die stark vom DB-Schema abhängt. Und mit „stark abhängig“ meine ich, dass das Hinzufügen einer neuen Spalte zu einer bestimmten Tabelle oft (sehr oft) zu einer entsprechenden exportMethodenänderung führt (normalerweise sollten Sie das neue Feld auch zu den Exportdaten hinzufügen).

Programmierer vergessen oft, die exportMethode zu ändern , da nicht klar ist, ob man sich das überhaupt ansehen sollte. Mein Ziel ist es, den Programmierer zu einer expliziten Entscheidung zu zwingen, um festzustellen, ob er die exportMethode vergessen hat oder einfach kein Feld zu den Exportdaten hinzufügen möchte. Und ich suche nach einer Designlösung für dieses Problem.

Ich habe zwei Ideen, aber beide haben Fehler.

Intelligenter Wrapper "Alles lesen"

Ich kann den Smart Wrapper erstellen, der sicherstellt, dass alle Daten explizit gelesen werden.

Etwas wie das:

def export():
    checker = AllReadChecker.new(table_row)

    name    = checker.get('name')
    surname = checker.get('surname')
              checker.ignore('age') # explicitly ignore the "age" field

    result = [name, surname] # or whatever

    checker.check_now() # check all is read

    return result

Bestätigt also, checkerwenn table_rowandere Felder enthalten, die nicht gelesen wurden. Aber all das sieht irgendwie schwer aus und beeinflusst (vielleicht) die Leistung.

„Überprüfen Sie, dass die Methode“ Unittest

Ich kann gerade das unittest verursachen, das sich das letzte Tabellenschema erinnert und jedes Mal fehlschlägt, wenn die Tabelle geändert wird. In diesem Fall würde der Programmierer so etwas wie "Vergiss nicht, die exportMethode zu überprüfen " sehen. Das Ausblenden der Warnung Programmierer würde (oder würde nicht - das ist ein Problem) auschecken exportund manuell (das ist ein anderes Problem) den Test beheben, indem neue Felder hinzugefügt werden.

Ich habe ein paar andere Ideen, aber sie sind zu mühsam umzusetzen oder zu schwer zu verstehen (und ich möchte nicht, dass das Projekt zu einem Rätsel wird).


Das obige Problem ist nur ein Beispiel für die größere Gruppe von Problemen, auf die ich von Zeit zu Zeit stoße. Ich möchte einige Teile des Codes und / oder der Infrastruktur binden, sodass das Ändern eines davon den Programmierer sofort darauf hinweist, einen anderen zu überprüfen. Normalerweise haben Sie einige einfache Tools wie das Extrahieren allgemeiner Logik oder das Schreiben zuverlässiger Unittest, aber ich suche das Tool für komplexere Fälle: Vielleicht sind mir einige Entwurfsmuster bekannt.


Können Sie vielleicht exportbasierend auf dem Schema generieren ?
Coredump

Es kann nicht automatisch generiert werden, deshalb sollte ich den Programmierer bitten , sich den Code anzusehen und eine Entscheidung zu treffen.
Vadim Pushtaev

Wäre es eine Lösung, der Exportklasse zwei Listen mit Feldnamen (export und dont-export) hinzuzufügen und einen Komponententest durchzuführen, der prüft, ob diese beiden Listen zusammen den vollständigen Satz von Feldern aus der Datenbank umfassen?
Sjoerd Job Postmus

Können Sie einen Test automatisch generieren, der prüft, ob exportalles vorhanden ist, was Sie wirklich benötigen?
Biziclop

1
ein Kommentar im Quellcode zu vereinfachend eine Lösung? Normalerweise werden Dinge übersehen, weil es keine Erinnerung gibt, ein Kommentar würde das beheben.
gbjbaanb

Antworten:


11

Sie sind mit Ihrer Unit-Test-Idee auf dem richtigen Weg, aber Ihre Implementierung ist falsch.

Wenn sich das exportauf das Schema bezieht und das Schema geändert wurde, gibt es zwei mögliche Fälle:

  • Entweder exportfunktioniert das noch einwandfrei, da es von einer leichten Änderung des Schemas unberührt blieb,

  • Oder es bricht.

In beiden Fällen ist es das Ziel des Builds, diese mögliche Regression aufzuspüren. Eine Reihe von Tests - seien es Integrationstests oder Systemtests oder Funktionstests oder etwas anderes - stellen sicher, dass Ihre exportProzedur mit dem aktuellen Schema funktioniert , unabhängig davon, ob sie sich seit dem vorherigen Commit geändert hat oder nicht. Wenn diese Tests erfolgreich sind, ist das großartig. Wenn sie fehlschlagen, ist dies ein Zeichen für den Entwickler, dass er möglicherweise etwas verpasst hat, und ein klarer Hinweis darauf, wo er suchen muss.

Warum ist Ihre Implementierung falsch? Aus mehreren Gründen.

  1. Es hat nichts mit Unit-Tests zu tun ...

  2. ... und eigentlich ist es nicht einmal ein Test.

  3. Das Schlimmste ist, dass das Beheben des „Tests“ tatsächlich ein Ändern des „Tests“ erfordert, dh eine Operation, die mit dem überhaupt nicht zusammenhängt export.

Indem Sie tatsächliche Tests für die exportProzedur durchführen, stellen Sie stattdessen sicher, dass der Entwickler das Problem behebt export.


Im Allgemeinen ist dies ein gutes Zeichen dafür, dass Sie bei einer Situation, in der eine Änderung in einer Klasse immer oder normalerweise eine Änderung in einer völlig anderen Klasse erforderlich macht, Ihr Design falsch gemacht haben und gegen das Prinzip der einheitlichen Verantwortung verstoßen.

Während ich speziell über Klassen spreche, gilt dies mehr oder weniger auch für andere Entitäten. Beispielsweise sollte eine Änderung des Datenbankschemas entweder automatisch in Ihrem Code widergespiegelt werden, beispielsweise durch Codegeneratoren, die von vielen ORMs verwendet werden, oder zumindest leicht zu lokalisieren sein: Wenn ich eine DescriptionSpalte zur ProductTabelle hinzufüge und keine ORMs oder Codegeneratoren verwende, Ich erwarte zumindest eine einzelne Änderung innerhalb der Data.ProductKlasse der DAL, ohne die gesamte Codebasis durchsuchen zu müssen und einige Vorkommen der ProductKlasse beispielsweise in der Präsentationsebene zu finden.

Wenn Sie die Änderung nicht vernünftigerweise auf einen Ort beschränken können (entweder weil es dort einfach nicht funktioniert oder weil es sehr viel Entwicklung erfordert), besteht das Risiko von Regressionen . Wenn ich die Klasse ändere Aund die Klasse Birgendwo in der Codebasis nicht mehr funktioniert, ist das eine Regression.

Testen senkt das Risiko von Regressionen und zeigt Ihnen, was viel wichtiger ist, den Ort einer Regression. Wenn Sie wissen, dass Änderungen an einem Ort Probleme in einem ganz anderen Teil der Codebasis verursachen, sollten Sie daher sicherstellen, dass Sie über genügend Tests verfügen, die Alarme auslösen, sobald auf dieser Ebene eine Regression auftritt.

Verlassen Sie sich in solchen Fällen auf keinen Fall nur auf die Kommentare. Etwas wie:

// If you change the following line, make sure you also change the corresponding
// `measure` value in `Scaffolding.Builder`.

funktioniert nie In den meisten Fällen wird es nicht nur von Entwicklern nicht gelesen, sondern oft auch entfernt oder weit von der betroffenen Zeile entfernt und ist nicht mehr zu verstehen.


Ja, dieser „Test“ ist in der Tat kein Test, es ist eine Art Falle, eine Art If you change the following line..., die automatisch funktioniert und nicht einfach ignoriert werden kann. Ich habe noch nie jemanden gesehen, der solche Fallen benutzt hat, daher der Zweifel.
Vadim Pushtaev

1
Das Problem ist, dass die Klasse Bnicht aufhört zu arbeiten, sondern möglicherweise nicht mehr richtig funktioniert. Aber ich kann keine Zukunft vorhersagen und keine Tests schreiben, die die Zukunft vorhersagen. Deshalb versuche ich, den Entwickler daran zu erinnern, diesen neuen Test zu schreiben.
Vadim Pushtaev

@VadimPushtaev: Wenn es um das Testen geht, ist es genau dasselbe, wenn „möglicherweise nicht mehr richtig funktioniert“ und „nicht mehr funktioniert“ . Sie können die Zukunft nicht vorhersagen, aber Sie sollten in der Lage sein, die Anforderungen genau zu kennen und zu testen, ob diese Anforderungen von Ihrem tatsächlichen Produkt erfüllt werden.
Arseni Mourzenko

Ja, das ist eine Sache. Eigentlich möchte ich den Entwickler daran erinnern , über neue Anforderungen nachzudenken . Ich möchte nur eine Handbewegung machen: „Hallo, bist du sicher, dass du den Export nicht vergisst? Fragen Sie den Manager oder so, es ist ein häufiges Problem.
Vadim Pushtaev

Trotzdem vielen Dank, Ihre Antwort hat mir geholfen, meine Gedanken zu ordnen, und ich habe jetzt einen bestimmten Plan.
Vadim Pushtaev

3

Es hört sich für mich so an, als wären Ihre Änderungen nicht genau festgelegt. Angenommen, Sie wohnen an einem Ort ohne Postleitzahlen, sodass in der Adresstabelle keine Postleitzahlenspalte vorhanden ist. Dann werden Postleitzahlen eingeführt, oder Sie fangen an, sich mit Kunden zu befassen, die dort leben, wo Postleitzahlen existieren, und Sie müssen diese Spalte der Tabelle hinzufügen.

Wenn das Arbeitselement nur "Postleitzahlenspalte zur Adresstabelle hinzufügen" lautet, wird der Export abgebrochen oder es werden zumindest keine Postleitzahlen exportiert. Wie sieht es aber mit dem Eingabebildschirm für Postleitzahlen aus? Der Bericht, der alle Kunden und deren Adressen auflistet? Es gibt Unmengen von Dingen, die geändert werden müssen, wenn Sie diese Spalte hinzufügen. Das Erinnern an diese Dinge ist eine wichtige Aufgabe - Sie sollten sich nicht auf zufällige Code-Artefakte verlassen, um Entwickler zum Erinnern zu "verleiten".

Wenn die Entscheidung getroffen wird, eine aussagekräftige Spalte hinzuzufügen (d. H. Nicht nur eine zwischengespeicherte Gesamtsuche oder eine denormalisierte Suche oder einen anderen Wert, der nicht zu einem Export oder Bericht oder einem Eingabebildschirm gehört), sollten die erstellten Arbeitselemente ALLE Änderungen enthalten Erforderlich - Hinzufügen der Spalte, Aktualisieren des Füllskripts, Aktualisieren der Tests, Aktualisieren des Exports, der Berichte, der Eingabebildschirme usw. Diese dürfen nicht alle derselben Person zugewiesen (oder von ihr abgeholt) werden, aber sie müssen alle erledigt werden.

Manchmal entscheiden sich Entwickler, Spalten selbst hinzuzufügen, um größere Änderungen zu implementieren. Beispielsweise könnte jemand ein Arbeitselement geschrieben haben, um einem Eingabebildschirm und einem Bericht etwas hinzuzufügen, ohne darüber nachzudenken, wie es implementiert wird. Wenn dies häufig vorkommt, müssen Sie entscheiden, ob Ihr Workitem-Addierer Implementierungsdetails kennen muss (um alle richtigen Workitems hinzufügen zu können) oder ob Entwickler sich bewusst sein müssen, dass das Workitem- Addierer lässt manchmal Dinge aus. Wenn es das letztere ist, brauchen Sie eine Kultur von "Ändern Sie nicht nur das Schema, sondern denken Sie darüber nach, was sich sonst noch darauf auswirkt."

Wenn es viele Entwickler gäbe und dies mehr als einmal passieren würde, würde ich eine Check-in-Benachrichtigung für den Teamleiter oder eine andere leitende Person einrichten, um über Schemaänderungen informiert zu werden. Diese Person könnte dann nach verwandten Arbeitselementen suchen, um mit den Folgen einer Schemaänderung umzugehen, und wenn die Arbeitselemente fehlen, sie nicht nur hinzufügen, sondern auch darüber informieren, wer sie aus dem Plan herausgelassen hat.


2

Fast immer erstelle ich beim Erstellen eines Exports auch einen entsprechenden Import. Da ich andere Tests habe, die die zu exportierende Datenstruktur vollständig ausfüllen, kann ich einen Roundtrip-Unit-Test erstellen, bei dem ein vollständig ausgefülltes Original mit einer exportierten und importierten Kopie verglichen wird. Wenn sie identisch sind, ist der Export / Import abgeschlossen. Wenn sie nicht identisch sind, schlägt der Komponententest fehl und ich weiß, dass der Exportmechanismus aktualisiert werden muss.


Dies kann überprüfen, ob jedes Objekt von db gespeichert und neu geladen wurde. Es deckt nicht den Fall ab, dass ein vorhandenes DB-Feld kein entsprechendes Objektfeld hat.
k3b

@ k3b wahr. Zumindest in meinen Systemen tritt dies in der Regel auf, wenn etwas nicht mehr verwendet wird, aber nicht aus dem Schema entfernt wurde, was außerhalb des Geltungsbereichs des Exportmechanismus liegt. Die Einheit prüft, ob jedes Feld eines Objekts persistent ist beharrte, aber ich teste nicht auf unbenutzte Spalten, da dies keine beobachtbaren Auswirkungen auf die Systemfunktion hätte.
Pete Kirkham
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.