Șablon de cerere de funcție care devine changelog
6 min de citit
Un șablon de cerere de funcție e un formular cu patru întrebări: ce încearcă persoana să facă, ce o oprește, ce a încercat în loc de asta, și cum vrea să fie anunțată când e gata. Tot restul care apare de obicei pe unul, selectoare de prioritate, estimări de efort, scoruri de valoare de business, e pentru echipa care primește cererea, și e completat greșit de cel care o trimite.
Cererile ordonate sunt testul greșit pentru un șablon. Cel corect: șase luni mai târziu, când funcția e lansată, poate cineva găsi cererea, s-o înțeleagă, și să anunțe persoana care a scris-o? Majoritatea șabloanelor sunt proiectate pentru admisie. Ăsta e proiectat pentru ziua în care se închide bucla.
Ce ar trebui să includă un șablon de cerere de funcție?
Ar trebui să includă obiectivul, blocajul, soluția temporară, și o cale înapoi la solicitant. Patru câmpuri, în această ordine, fiecare răspunde la o întrebare pe care echipa o va pune mai târziu.
| Câmp | Întrebarea la care răspunde mai târziu | De ce e pe formular |
|---|---|---|
| Ce încerci să faci? | Funcția construită a fost cea necesară? | Obiectivul supraviețuiește oricărei propuneri concrete |
| Ce te oprește azi? | Cum arată “gata”? | Numește lipsa fără a prescrie corecția |
| Ce faci în loc de asta? | Cât de urgent e cu adevărat? | O soluție temporară dureroasă e un semnal mai puternic decât un selector de prioritate |
| Cum ar trebui să te anunțăm? | Cine primește mesajul “lansat”? | Câmpul pe care majoritatea șabloanelor îl omit |
Ce lipsește deliberat: o soluție propusă ca un câmp obligatoriu (binevenită ca un comentariu, greșită ca un cadru), un selector de prioritate (fiecare persoană care trimite alege ridicat), și orice estimare de efort sau valoare (treaba echipei, după triaj). Un șablon care cere o soluție primește cereri de butoane; un șablon care cere un obiectiv primește cereri de rezultate, iar despre rezultate se scrie o intrare de changelog.
Șablonul
Ăsta e șablonul de issue GitHub pe care-l folosim, ca formular. Lipiți-l în
.github/ISSUE_TEMPLATE/feature_request.yml și se randă ca un formular structurat pe pagina de
issue nou. Cererile depuse prin el ajung ca issue-uri cu aceleași câmpuri ca cele depuse dintr-un
widget de feedback, ceea ce contează pentru secțiunea următoare.
name: Feature request
description: What you are trying to do, and what stops you.
labels: ["feature-request"]
body:
- type: textarea
id: goal
attributes:
label: What are you trying to do?
description: >-
The outcome, not the button. "Export a month of invoices as one
PDF" beats "add a PDF export".
validations:
required: true
- type: textarea
id: blocker
attributes:
label: What stops you today?
description: >-
Where the product runs out. An error, a missing option, a limit.
validations:
required: true
- type: textarea
id: workaround
attributes:
label: What do you do instead?
description: >-
The spreadsheet, the script, the manual step. "Nothing, I gave
up" is a valid answer.
- type: input
id: contact
attributes:
label: How should we tell you when it ships?
description: >-
An email address, or leave blank to be notified only on this
issue.
Două detalii fac treaba. labels: ["feature-request"] înseamnă că cererea e clasificată la
creare în loc să aștepte ca cineva s-o trieze. Iar ultimul câmp există pentru că “vă vom anunța”
e o promisiune, și o promisiune are nevoie de o adresă.
Ce etichete ar trebui să poarte o cerere de funcție?
O cerere de funcție ar trebui să poarte o etichetă pentru ce este, una pentru cât de urgentă e, și una pentru de unde vine. Trei etichete, trei axe, și fiecare e citită de o cititoare diferită.
| Etichetă | Valori | Cine o citește |
|---|---|---|
| Tip | feature-request, bug | Cine decide în ce coadă intră |
| Prioritate | priority:low, priority:medium, priority:high | Cine planifică următorul ciclu |
| Sursă | from-widget, from-form, from-support | Cine măsoară de unde vin cererile |
Widget-ul aplică primele două axe și from-widget atunci când depune o trimitere ca issue;
from-form și from-support sunt sugestii pentru cererile care vin pe alte căi. Etichetele
widget-ului sunt un tip (bug sau feature-request, decis de un clasificator doar din
mesaj), o prioritate (un raport de eroare calm, specific e ridicat; un duplicat al a ceva deja
cerut e scăzut; orice sugerează măcar o problemă de securitate e bug și ridicat, indiferent de
formulare), și from-widget. Aceleași trei axe funcționează pentru cererile care vin manual prin
șablonul de mai sus, și ăsta e punctul: o cerere e o cerere, indiferent pe unde a intrat.
Încă o convenție: widget-ul elimină adresa de e-mail a persoanei care trimite din corpul issue-ului înainte de a-l depune, pentru că issue-ul trăiește într-un repository care poate fi public, și o înlocuiește cu o referință de trimitere. Adresa rămâne în afara issue-ului; persoana care a trimis urmărește rezultatul în widget. Faceți același lucru cu câmpul de contact dacă tracker-ul vostru e vizibil pentru oameni din afara echipei.
Cum devine o cerere de funcție o intrare de changelog?
O cerere de funcție devine o intrare de changelog când un pull request închide issue-ul, iar
intrarea redactată din acel pull request leagă înapoi. Mecanismul sunt propriile cuvinte cheie de
închidere ale GitHub: un PR a cărui descriere spune Fixes #142 închide issue-ul 142 la merge.
Dacă intrările voastre de changelog sunt redactate din pull request-uri integrate, ciorna poate
purta numărul issue-ului cu ea, iar intrarea știe cine a cerut.
Ăsta e motivul pentru care șablonul cere obiectivul în loc de soluție. Când intrarea e scrisă, obiectivul e propoziția de care are nevoie scriitorul: “Acum puteți exporta o lună de facturi ca un singur PDF” e o intrare de changelog. “Adăugat export PDF” e un mesaj de commit. Uneltele de changelog care redactează din pull request-uri pot face colectarea și link-ul; formularea încă are nevoie de o persoană, iar persoana are nevoie de obiectiv.
Ce se întâmplă când e lansat?
Solicitantul e anunțat, cu un link către intrare. În configurarea noastră asta e automat pentru cererile venite prin widget: un comentariu care spune “Shipped — <titlul intrării>” cu un link către intrarea publicată, postat pe issue de îndată ce o persoană aprobă intrarea, în timp ce widget-ul îi arată celui care a trimis aceeași intrare. Un issue depus manual din acest șablon nu primește niciun comentariu automat; închideți voi acea buclă, după aceeași regulă. Comentariul e postat deliberat la aprobare, nu la merge: un comentariu care spune că ceva e live înainte de a fi e o promisiune ruptă cu marcaj temporal. Fiecare cerere e notificată cel mult o dată; o a doua aprobare a aceleiași intrări nu produce un al doilea comentariu.
Dacă faceți asta manual, aceeași regulă se aplică. Nu închideți bucla din pull request. Închideți-o din intrarea publicată, și închideți-o o dată. Fluxul și widget-ul poartă aceeași intrare tuturor celor care n-au cerut, care sunt majoritatea; comentariul e pentru cei care au cerut.
De ce eșuează majoritatea șabloanelor de cerere de funcție
Sunt proiectate să ușureze triajul și reușesc, cu prețul singurului moment care contează pentru solicitant. Un șablon cu douăsprezece câmpuri primește mai puține cereri, iar cele pe care le primește provin de la oameni cu răbdarea de a completa douăsprezece câmpuri, ceea ce nu e aceeași populație ca cea care are nevoie de funcție. Un șablon cu patru câmpuri, dintre care unul e “cum vă contactăm”, primește mai multe cereri și le poate onora pe toate.
FAQ
Ar trebui un șablon de cerere de funcție să întrebe despre prioritate? Nu. Întrebați în schimb despre soluția temporară. “Export într-o foaie de calcul și retastez în fiecare vineri” spune mai mult despre prioritate decât un meniu derulant pe care persoana care a trimis l-a pus pe ridicat.
Ar trebui solicitanții să propună o soluție? Pot, în textul liber. Nu faceți din asta cadrul. Cererile scrise ca soluții sunt mai greu de fuzionat unele cu altele și mai greu de transformat într-o intrare de changelog.
Ar trebui cererile de funcții să apară pe o roadmap publică? Odată planificate, da: o etichetă pe același issue îl pune în coloana planificat, iar solicitantul poate vedea cum se mișcă. Articolul roadmap publică e mecanismul.
Cum gestionez duplicatele?
Legați cererea nouă de issue-ul existent și etichetați-o cu prioritate scăzută; nu-l închideți.
Fiecare duplicat e încă o persoană de anunțat când e lansat. Cu comentariul automat al Changeloop,
acea persoană e anunțată doar dacă pull request-ul numește și issue-ul ei (Fixes #142, fixes #187).
Unde ar trebui să trăiască șablonul? În repository-ul care va primi pull request-ul, ca să funcționeze cuvântul cheie de închidere. O cerere într-un tracker separat trebuie legată manual la merge, și ăsta e pasul care e sărit.
Afirmațiile tehnice din acest articol nu au fost verificate independent. Dacă ceva nu e corect, spune-ne și vom corecta.