Von der Nutzung zur Erfahrung
Ein Bericht nennt ein Symptom. Die Arbeit ist die Erfahrung dahinter. „Der Kunde verschwindet, wenn das Gespräch auf die Sache kommt“ ist ein Fehler. „Ein Gespräch sammelt, worum es geht: Der Kunde bleibt, wenn seine Sache hinzugefügt wird“ ist das, was gebaut, geprüft und gefilmt werden soll. Schreiben Sie diesen Satz zuerst. Beheben Sie die Struktur, die das Symptom ermöglicht hat, und beweisen Sie dann den Satz, indem Sie das Produkt nutzen.
Der Kreislauf
- Nutzung sammeln. Lesen Sie den Bericht, dann die Spuren der tatsächlichen Nutzung: die Unterhaltungen der Person, Journale, Protokolle, Anwesenheit, die von ihr berührten Dateien. Sie enthalten Erwartungen, die niemand aufgeschrieben hat („ils en sont où ?“ erwartet die Punkte selbst, nicht eine Zusammenfassung).
- Die Erfahrung schreiben. Ein Satz pro Bericht, Präsens, aus der Sicht der Person, keine Implementierungswörter. Führen Sie die Liste. Sie wird zur Filmerzählung und zu den Botschaften der Ansprüche.
- Die strukturelle Ursache finden. Fragen Sie, warum das Produkt dies überhaupt tun konnte. Eine Ursache erklärt normalerweise mehrere Berichte (Identität aus einem Anzeigenamen übernommen; zwei Zählungen, die ein Wort teilen; ein Renderer, der eine Klasse beim Einfügen verwirft). Beheben Sie die Ursache, nicht den Bildschirm, der sie gezeigt hat.
- Selbst nutzen. Steuern Sie die echte App als jede beteiligte Person, bei Desktop- und Telefonbreite, über den Browser-Namensraum (unten). Betrachten Sie Screenshots. Zählen Sie, was die Seite sagt, nicht, was der Code beabsichtigt.
- Festhalten. Heben Sie die manuellen Schritte in ein Szenario: Aktionen werden zu Ereignissen, Prüfungen zu Ansprüchen, der Erfahrungssatz wird zur Erzählung der Szene. Legen Sie Modell-Durchläufe auf Band, damit der Film in Sekunden und kostenlos wieder abgespielt werden kann.
- Die Erfahrung melden, nicht den Patch. Führen Sie in der Zusammenfassung mit dem, was die Person jetzt vorfinden wird, dann der Ursache, dann dem Film und wie er wieder abgespielt werden kann.
Hausgeschmack (was Othman wiederholt verlangt hat)
- Weniger Text. Der Zustand wird gezeichnet: Ton, Gewicht, Platzierung, ein Ring, eine Markierung. Ein Satz, der einen Bildschirm erklärt, bedeutet, dass der Bildschirm falsch ist.
- Ein Wort pro Idee. Führen Sie ein Glossar und halten Sie es ein: Ein „critère“ (gegen das Verfahren beurteilt) ist niemals ein „point“ (was eine Person entscheidet). Wenn zwei Zählungen ein Wort teilen, wird sie jemand zusammenzählen.
- Dinge sammeln sich. Tags summieren sich (Art, dann Kunde, dann Sache). Der aktuelle wird ausgefüllt und die anderen bleiben als Umrisse. Ersetzen Sie niemals den Kontext, den die Person bereits gesehen hat.
- Zahlen vor Text gezeichnet. Ein Verlauf öffnet sich mit Diagrammen, jeweils einer Reihe, Werten beschriftet. Der Text sitzt darunter, eine Zeile pro Ereignis, und öffnet sich auf Anfrage.
- Jeder Verweis führt zu seinem Ort. Eine Absatznummer scrollt zum Absatz und beleuchtet ihn. Ein Zitat findet seine Passage. Die Scrollleiste markiert, wo Dinge sind, in ihren Farben.
- Standardmäßig live. Keine vollständigen Neuladungen. Eine von einer Person vorgenommene Änderung wird auf allen geöffneten Seiten gleichzeitig angezeigt. Wiederholte Tippen auf einer langsamen Seite darf den Effekt nicht wiederholen: Gesten sind idempotent.
- Steuerelemente dort, wo das Ding ist, und nur für diejenigen, die sie verwenden dürfen. Schreibgeschützte Personen sehen den Zustand ohne das Steuerelement.
- Wissen, wer da ist. Identität und Rolle erreichen jeden Bildschirm und jeden Agenten. Sagen Sie einem Partner nicht, dass „ein Partner bestätigen muss“.
- Ehrliche Kanten. Sagen Sie klar, was das Produkt noch nicht tut. Zeigen Sie niemals auf einen Bildschirm, der es nicht kann.
- Telefonbreite ist ein erstklassiger Leser: 16 Pixel Ränder, kein horizontaler
Scroll (
minmax(0,1fr), nicht1fr), und das Konto immer erreichbar. - Mockups und Erzählung in der Sprache des Produkts (Französisch für Knowledger).
Manuelles Testen mit dem Browser-Namensraum
Beam Lisp's nativer Browser (optional/browser-port im beam-lisp-Baum) führt
geköpftes Chromium in einem privaten, kopflosen Sway aus, mit vertrauenswürdiger
Eingabe und einer kontinuierlichen Bildschirmaufnahme. Es ist dasselbe Objekt, das ein
Szenario steuert, sodass eine manuelle Sitzung zu einem Test wird, ohne neu geschrieben
zu werden. Verwenden Sie agent-browser für einen schnellen Blick. Verwenden Sie den
Browser-Namensraum für alles, was aufbewahrenswert ist.
Einmal pro Maschine
cd ~/projects/beam-lisp/optional/browser-port
nix develop --command cargo build --release --locked --features native-browser
nix build .#runtime-wayland --out-link ~/.local/share/bl-browser/runtime-wayland # chromium, sway, wayvnc
command -v ffmpeg || nix profile add nixpkgs#ffmpeg
Führen Sie alles, was es verwendet, mit bl run -p ~/projects/beam-lisp/optional/browser-port/bl … aus
(oder bl test -p …).
Ein Test: eine Datei, eine Person, reale Eingabe
templates/probe.bl ist der Ausgangspunkt. Sein Kern:
(ns probe (:require [browser.page :as page]))
(def rt (str (System/get_env "HOME") "/.local/share/bl-browser/runtime-wayland/bin/"))
(def p (page/open! {:executable (str (System/get_env "HOME") "/projects/beam-lisp/optional/browser-port/target/release/bl-browser-port")
:width 1440 :height 860
:launch {"profile" "/tmp/probe/profile" "runtime" "/tmp/probe/runtime"
"chromium" (str rt "chromium") "compositor" (str rt "sway") "vnc" (str rt "wayvnc")
"width" 1440 "height" 960}}))
(try
;; wer schaut: die Identität, die der Proxy hinzufügen würde (hier Tailscale-Header); sie erreicht auch den Live-Socket
(page/cdp! p "Network.enable" {})
(page/cdp! p "Network.setExtraHTTPHeaders" {"headers" {"tailscale-user-login" "[email protected]" "tailscale-user-name" "timinou"}})
(page/record! p "/tmp/probe/take.mp4" {:fps 24}) ; optional: die gesamte Sitzung als Film
(page/navigate! p "http://127.0.0.1:24025/a/sahel-…")
(page/wait! p "document.documentElement.dataset.live==='1'") ; ein JS-Prädikat, Standard-Timeout 30 s
(page/click! p ".rv-rail a.para[data-goto]") ; vertrauenswürdiger Zeiger: bewegt, drückt, loslässt
(println (page/evaluate! p "scrollY")) ; die Seite fragen, was eine Person sehen würde
(page/screenshot! p "/tmp/probe/after.png") ; dann ANSCHAUEN
(page/stop-recording! p)
(finally (page/close! p)))
Die Verben sind navigate! wait! click! hover! fill! key! drag! evaluate! screenshot! record! stop-recording! show-cursor! cdp!. cdp! erreicht alles andere, was Chromium
bietet: Viewport, Netzwerk, Cookies, Emulation (Emulation.setDeviceMetricsOverride
für ein Telefon).
Gewohnheiten, die einen Test aufbewahrenswert machen
- Die Seite fragen, nicht den Code. Jede Prüfung ist ein JS-Ausdruck, der
truezurückgibt, wenn eine Person das Ding sehen würde: Zeilenanzahlen, der Text eines Tags,scrollY, eine Klasse auf dem Element unter dem Zeiger. Diese Ausdrücke werden unverändert zu Ansprüchen. - Nach Bedeutung auswählen. Geben Sie der App stabile Datenattribute, wo Tests sie
benötigen (
button.cell[data-person='Karim Saadi'][data-team='Associés']), niemals „der fünfte Button“. - Jede Person sein. Öffnen Sie eine Seite pro Person mit ihrer Identität. Zwei Seiten nebeneinander zeigen, wie „live“ bewiesen wird: eine handelt, die andere ändert sich ohne Neuladen.
- Ersten Bildaufbau und gepatchte Seite prüfen. Live-Apps rendern HTML einmal, patchen dann von Daten. Fehler verstecken sich im Unterschied (eine beim Einfügen verworfene Klasse, eine Liste, die mit Text beginnt, der als Tag-Name gelesen wird). Jeden Bildschirm einmal per URL und einmal durch Navigation dorthin erreichen.
- Warten, bis die Seite live ist, nicht nur verbunden. Ein Live-Client kann die
servergerenderte Seite durch das erste Rendern seines Sockets ersetzen. Zwischendrin
getippter Text geht verloren, sowohl für einen Test als auch für eine Person, die
kurz nach dem Laden schnell tippt. Die App sollte das Getippte über diesen Mount
hinweg behalten und dann sagen, dass sie live ist (
data-mounted). Tests warten auf dieses Flag. - Telefonbreite ansehen. Prüfen Sie
document.documentElement.scrollWidth === innerWidthbei 390px, dann sehen Sie sich den Screenshot an. - Niemals echte Daten berühren, und beweisen Sie es. Richten Sie die App auf eine
Reflink-Kopie ihrer Daten (
cp -a --reflink=auto) und einen freien Port. Beweisen Sie dann die Isolation, bevor Sie ihr vertrauen: Benennen Sie ein Ding in der Kopie um (ein Kanarienvogel: ein Team „AssociésX“), handeln Sie danach, und prüfen Sie, dass sich die Kopie geändert hat und der Zeitstempel der echten Datei nicht. Tun Sie dies einmal pro Art von Prozess, der schreibt (Seiten-Handler, Live-Sockets, Hintergrundjobs). In Beam Lisp erreichtSystem/put_envvon einem Test aus Seiten-Handler, aber nicht Live-Sockets: Ein Socket, der keinen konfigurierten Datenordner liest, fällt auf den Standard zurück, der die echten Daten sind. Die App muss ihre Konfiguration VM-weit beim Start des Servers festlegen (persistent_term) und von dort lesen. Wenn Sie echte Daten berühren müssen, machen Sie einen Snapshot der Datei, handeln Sie, vergleichen Sie per Diff, um nur Ihre Änderung zu bestätigen, und stellen Sie wieder her.
Vom Test zum Film
Ein scenario.demo/defdemo ist ein gewöhnlicher Test (bl test). Die Schritte
entsprechen eins zu eins:
| Test | Szenario |
|---|---|
(page/navigate! p url) | (s/does :othman [:navigate url]) |
(page/wait! p js) | (s/does :othman [:wait js]) |
(page/click! p sel) / hover! / fill! / key! | [:click sel] [:hover sel] [:fill sel text] [:key "Enter"] |
| eine Pause für das Auge | [:pause ms] |
(page/evaluate! p js), das wahr sein muss | (s/sees :othman (fn [p _] (= true (page/evaluate! p js))) "die Erfahrung") |
| eine Person | ein Schauspieler in browser.film/owned-worlds, der seine Identität beim Öffnen setzt |
| ein Absatz Erzählung | (demo/scene :id {:title … :say … :capture :video} events…) |
templates/feature-demo.bl ist eine vollständige Datei: eine isolierte Kopie der
App-Daten, die in der Test-VM auf einem freien Port gestartete App, aufgenommene
Welten mit Identitäten, stille Tracks, wenn kein Sprachschlüssel existiert, und ein
Demo mit drei Szenen. Arbeitsbeispiel: knowledger-interface-review/apps/practice/test/features-demo.bl
(fünf Filme: Überprüfung, Verlauf, Stücke, ein Team live über zwei Personen geändert,
ein aufgezeichnetes Gespräch).
Schreiben Sie Szenen als die Erfahrung, nicht die Behebung: „Jeder Punkt führt zu seinem Platz“, niemals „beheben Sie den §-Link-Handler“. Die Erzählung ist die Dokumentation.
Modell-Durchläufe auf Band
Alles, was ein Agent tut, sollte durch die eigene Tool-Tür der App gehen, sodass nur die Entscheidungen des Modells die des Modells sind. Ein Band speichert für einen Modell-Durchlauf die von ihm getätigten Tür-Aufrufe in der Reihenfolge und seine endgültige Antwort, gehasht nach Modell, System-Prompt und Prompt (mit Uhren, epochenartigen Zahlen und maskierten Hex-IDs).
record: Wiederholen, was auf Band ist; das Modell für das ausführen, was nicht da ist; es aufbewahren.replay(Standard): Ein Durchlauf, der nicht auf Band ist, ist ein Fehler-Durchlauf. Ein Replay fällt niemals stillschweigend auf das Modell zurück.- Replay tätigt dieselben Aufrufe durch dieselbe Tür, zeitlich gestaffelt, sodass das Produkt die Arbeit erneut erledigt und der Bildschirm es zeigt, in Sekunden und kostenlos.
Fixieren Sie alles, was den Prompt erreicht (den Firmennamen, das Datum, falls
vorhanden) in den Testdaten, sonst driftet der Schlüssel ab. Übergeben Sie die Bänder.
Referenzimplementierung: apps/practice/src/practice/cassette.bl und seine zwei
Hooks in conversation.bl (der Durchlauf und die Tür).
Ausführen und Rendern
bl test -p ~/projects/beam-lisp/optional/browser-port/bl app/test/features-demo.bl # Wiederholung, Beweis, Aufnahme
DEMO_RECORD=1 bl test -p … # fehlende Modell-Durchläufe auf Band legen (benötigt Modell-Anmeldedaten)
BL_DEMO_EXPORT=1 bl test -p … # auch MP4 + Untertitel + Kapitel pro Film rendern
Jeder Film löscht seine letzte Aufnahme in seiner Testumgebung, da eine Aufnahme
niemals eine überschreibt. Halten Sie jede Erzählung innerhalb von zwei
Untertitelzeilen (etwa 130 Zeichen), sonst lehnt das Rendern sie ab. Ein
ausgelasteter Rechner kann den Bildschirmaufnahme-Encoder aushungern: Überprüfen Sie
frames/recordings.json, wo encodedFrames etwa Sekunden × fps betragen sollte,
und führen Sie es erneut aus, wenn eine Aufnahme kurz ist.
Rendern (scenario.film/export!) benötigt Python 3 und FFmpeg mit libass. Die
Erzählung wird gesprochen, wenn DEEPGRAM_API_KEY gesetzt ist. Andernfalls erhält
jede Szene eine stille Spur, die genauso lang ist, wie das Lesen ihrer Untertitel
dauert. Gehen Sie niemals davon aus, dass ein Sprachschlüssel existiert. Durchsuchen
Sie die Filme mit (scenario.demo/serve! dir {:port 4163}) auf Loopback, oder
veröffentlichen Sie das mit work serve.
Bevor Sie sagen, es sei fertig
- Jeder gemeldete Punkt hat seinen Erfahrungssatz, seine Ursache und einen Anspruch, der ihn in einem echten Browser beweist, für jede betroffene Person.
- Desktop- und Telefonbreite wurde betrachtet, in Screenshots, nicht nur behauptet.
- Erster Bildaufbau und gepatchte Seite wurden für jeden berührten Bildschirm geprüft.
- Live-Verhalten wurde mit zwei Personen bewiesen, wo es darauf ankommt.
- Es wurden keine echten Daten durch das Testen geändert. Alles Berührte ist wiederhergestellt, mit dem angezeigten Diff.
- Filme werden vom Band ohne Netzwerk wieder abgespielt. Bänder und Szenarien sind übergeben, Renderings nicht.
- Die Zusammenfassung führt mit dem, was die Person jetzt vorfinden wird.