Pachetul de bune practici a fost recomandat de rOpenSci de când a fost lansat pentru prima dată cu puțin peste 10 ani în urmă de către Gábor Csárdi. Obișnuiam să le cerem editorilor noștri să execute manual bune practici pentru toate pachetele trimise la evaluarea inter pares de software și apoi să le cerem autorilor să remedieze orice probleme notabile semnalate de pachet. Acum este integrat în propriul nostru sistem pkgcheck și este folosit pentru a identifica automat orice probleme de bună practică cu toate trimiterile noi. Pachetul a schimbat menținătorii de mai multe ori înainte ca menținătorii anteriori să ne dea undă verde pentru a prelua întreținerea pachetului în urmă cu doi ani (28 mai 2024).
Suntem cu adevărat încântați să vă împărtășim că recent am lansat o serie de actualizări și extensii ale pachetului. Acestea îl fac atât mai ușor de utilizat, cât și mai puternic. Acesta a fost un efort de colaborare între autorul noului pachet, Athanasia Mo Mowinckel, menținătorul actual, Mark Padgham, și instrumentul AI generativ Claude. Descriem procesul la sfârșitul acestei note tehnice.
Control mai ușor al controalelor
Pachetul goodpractice este un înveliș convenabil în jurul mai multor alte pachete, inclusiv rcmdcheck, lintr, cyclocomp și desc, împreună cu câteva verificări codificate manual în pachetul în sine. Versiunea anterioară a Goodpractice avea un total de 230 de verificări, prefixate în general cu numele pachetului care definea fiecare verificare. Verificările erau identificabile cu funcția unică, all_checks(). Singura modalitate de a controla ce verificări au fost efectuate a fost trecerea unui checks parametru la funcția principală ca vector de caractere al numelor de verificări pe care ați vrut să le executați. Deci, de exemplu, dacă ați vrut să săriți peste verificările rcmdcheck, a trebuit să faceți ceva de genul acesta:
mychecks <- grepv("^rcmdcheck", all_checks(), invert = TRUE)
gp(checks = mychecks)
Nu a fost ușor! Și sincer, majoritatea oamenilor pur și simplu nu s-au deranjat.
Această actualizare ușurează în sfârșit controlul verificărilor, definindu-le în „grupuri”, care corespund în general pachetelor separate care rulează verificările efective. Grupurile pot fi văzute cu noul all_check_groups() funcția și controlată cu checks_by_group() funcţie. Verificările pot fi controlate prin simpla denumire a grupurilor de verificări pe care doriți să le executați, astfel:
gp(checks = checks_by_group("description", "lintr"))
Noi grupuri de cecuri
Documentația pentru all_check_groups() funcția arată toate noile grupuri de verificări adăugate în această actualizare, inclusiv:
| Numele grupului | Rulați implicit? | Descriere |
|---|---|---|
| descriere | Da | Verificați problemele comune cu DESCRIPTION fișiere, inclusiv probleme de formatare cu adrese URL, DOI, nume de pachete și roluri de autor și colaborator, împreună cu alte DESCRIPTION probleme. |
| rd | Da | Verificați dacă sau nu man/*.Rd documentația funcției include atât codul de exemplu, cât și valorile returnate (indiferent dacă fișierele de documentație sunt sau nu generate de roxygen2). |
| roxygen2 | Da | Verificați dacă există probleme cu documentația generată de Roxygen2. |
| revdep | nu | Verificări invers dependenței. |
| structură_cod | Da | Verifică probleme comune, cum ar fi funcții duplicate sau neutilizate. |
| structura_pachet | Da | Verificări generice, cum ar fi dacă un pachet are un fișier README, un fișier NEWS sau dacă toate fișierele folosesc a .R extensie, și nu .r. |
| ortografie | Da | Verificați ortografia. |
| tidyverse | nu | Verificați conformitatea cu Ghid de stil Tidyversemai ales verificări lintr. |
| urlchecker | Da | Verificați dacă toate adresele URL sunt valide. |
| vinietă | Da | Verificați dacă nici codul de vignetă nu folosește rm() sau setwd(). |
Raportare îmbunătățită a verificărilor
Pachetul Goodpractice a fost întotdeauna conceput pentru ieșire pe consolă. Această versiune actualizată oferă acum detalii imediate și consecvente despre progresul verificării în timpul rulării. Pachetul cli este, de asemenea, folosit pentru a oferi rezultate formatate în mod consecvent pentru toate grupurile de verificări.
Creșterea mare a cecurilor înseamnă, de asemenea, că imprimarea directă a rezultatelor bunelor practici poate umple mai multe ecrane de ieșire. Această actualizare adaugă și un groups parametru la print() metoda, pentru a activa rezultatele verificării tipăririi numai pentru grupurile specificate. Aceasta înseamnă că puteți rula principalul gp() funcția o dată, apoi parcurgeți fiecare grup de verificare prin imprimarea rezultatelor numai pentru acel grup, reparându-le și apoi trecând la următorul. Am descoperit că acest lucru transformă ceea ce ar putea simți ca un zid copleșitor de rezultate într-o listă de activități gestionabile. De exemplu:
x <- gp() print(x, "description") #> Aww! Shining package! Keep up the priceless work! print(x, "namespace") #> ── It is good practice to ───────────────────────────────────────────────────────────────────────────────────────────────────────────── #> #> ✖ remove or use internal functions that are defined but never called. Dead code increases maintenance burden. #> #> R/utils.R:3 #> R/utils.R:73 #> #> ✖ define exported (user-facing) functions before internal helper functions within each R source file. #> #> R/api.R:85 #> #> ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note despre procesul de dezvoltare
Din Mo (Athanasia)
Voi fi sincer cu tine: o mare parte din această contribuție a fost făcută cu un asistent AI (Claude Code folosind Opus 4.5) la cot. Vreau să spun ceva despre asta, pentru că cred că versiunea sinceră este mai utilă decât versiunea de marketing. Modul în care Mark a abordat revizuirea acestei lucrări a fost foarte atent și util.
Pe baza feedback-ului său și a modului în care a fost structurat, am învățat multe despre cum arată o revizuire bună a codului și a fost absolut minunat. Fiind o persoană care a lucrat în principal doar pe propriile baze de cod, am adoptat un stil de lucru care creează adesea monștri diferiți (sute de fișiere schimbate), ceea ce poate face revizuirea foarte dificilă. Într-adevăr, primul meu PR la acest proiect a fost un astfel de monstru, iar Mark a respins cerând câteva PR-uri mai mici pe care ar fi putut să le revizuiască. Tot aici am aflat despre git worktrees (Mulțumesc Maëlle!) și i-am cerut lui Claude să împartă munca în mai multe worktrees pentru o revizuire mai ușoară, a fost de fapt prima schimbare substanțială a modului în care abordez acum lucrul cu un asistent AI. Prin această colaborare am învățat multe despre împărțirea muncii mele în dimensiuni și bucăți mai bune.
Forma era cam așa:
Aș găsi o problemă pe care am considerat-o că este semnificativă de rezolvat și aș oferi lui Claude Code contextul problemei și, eventual, o idee despre cum să o rezolv. Odată ce avea o soluție, o revizuiam, o împingeam unde mi s-a părut, și repetam. Mark a analizat apoi PR-ul și a subliniat lucrurile pe care le-am ratat. Colaborare trilaterală, mai mult sau mai puțin, cu AI-ul care tastează și eu decid.
Ceea ce a funcționat bine a fost schelele. Elaborarea unei noi verificări, conectarea pasului de pregătire care o însoțește, generarea cazurilor de testare pentru căile de margine pe care altfel le-aș uita – genul ăsta de lucru se comprimă foarte bine cu un AI. Adesea i-aș cere să genereze mai întâi niște teste, apoi să creeze cod care să treacă testele. În acest fel, am avut o idee clară despre ceea ce doream să facă noul cod și apoi îl rezolvăm.
Și apoi mai este partea lipsită de farmec. Ar uita adesea instrucțiunile, în ciuda faptului că le avea documentate în agents.md și memoria locală pentru proiect. Acestea au fost în mare parte banale, dar uneori destul de rele. Unele dintre primele PR-uri pe care le-am făcut, Mark a subliniat că soluțiile foloseau expresia regulă mai degrabă decât AST (Arborii de sintaxă abstractă). Trebuie să recunosc că nu știam cu adevărat despre AST înainte de a începe acest proiect și sunt atât de bucuros că acum știu de el. Claude, în ciuda faptului că i s-a spus foarte clar că vrem soluții AST, adesea uita și implementa soluții bazate pe expresii regulate. De asemenea, ar reveni adesea la utilizarea for-loop-urilor mai degrabă decât a vectorizării și la crearea de for-loops imbricate în al 3-lea sau al 4-lea nivel – ceea ce este oribil de urmat ca om.
Dacă luați deoparte un lucru, luați asta: contribuția asistată de AI nu a însemnat predarea pachetului unei mașini. Însemna că aș putea să mă mișc mai repede asupra părților pe care le-am înțeles deja, să explorez cu mai multă încredere părțile pe care nu le-am cunoscut și să-mi concentrez atenția reală asupra deciziilor care contau – ce să verific, cum să le grupez, cum să le numesc și ce să omis. Frecarea m-a învățat unde să privesc cu atenție. Accelerările m-au învățat unde pot avea încredere în buclă.
Este un mod diferit de a lucra și încă îmi dau seama care este forma lui, dar mi-a permis să contribui la acest proiect, în ciuda unor probleme de sănătate foarte grave care îmi fac greu să lucrez în mod normal.
Și un lucru face întotdeauna Claude mai bine decât mine: scrie mesaje bune de commit. M-am trezit să scriu propriul meu cod, dar i-am cerut lui Claude să le comite (făcând să pară ca Claude a scris codul, dar nu-mi pasă) pentru că mesajele de confirmare sunt mult mai bune decât ceea ce scriu eu.
De la Mark
Întreaga idee pentru această actualizare majoră a fost inițiată și condusă de Mo. A fost și prima mea incursiune reală în utilizarea instrumentelor AI generative direct în pachetele rOpenSci și am învățat multe. După ce am respins PR-ul monstru inițial, lucrurile s-au așezat în PR-uri mult mai mici și ușor de gestionat, care s-au concentrat întotdeauna pe un anumit lucru.
Din acel moment, Mo a fost efectiv codificatorul (asistat de Claude), iar eu am fost recenzentul. Nu am știut niciodată cât de mult din codul real a fost tastat față de generat de mașină, dar am fost, în general, plăcut surprins că nu am simțit nevoia să întreb. În mod evident, aproape fiecare PR avea să îmbunătățească pachetul și multe dintre ele erau idei cu adevărat creative. (Acolo nu sunt ușor de acord cu descrierea generală a procesului făcută de Mo: sunt convins că o mare parte din munca din spatele acestei actualizări a venit direct din cunoștințele și experiența ei strălucitoare, mai degrabă decât din descrierea ei pasivă de a privi PR-urile preexistente.)
Procesul a început în februarie 2026 și a implicat 70 de solicitări de retragere. Multe dintre acestea erau într-adevăr idei independente și noi. Acest lucru mi-a permis să văd pe fiecare cu ochi proaspeți și să mă gândesc dacă aș putea aborda ceva în moduri diferite. Peste atât de multe PR-uri, au existat multe du-te-întors, de la împingerea lui Claude care insista pe bucle imbricate, până la a afla dacă codul a fost cel mai bine analizat și analizat ca text sau ca arbore de sintaxă. După cum a indicat Mo, multe dintre aceste discuții au convergit în cele din urmă către noi, să aducem puterea treesitter în pachet și chiar să ajutăm la înlocuirea verificărilor anterioare de cod bazate pe text cu abordări AST mai eficiente și mai precise.
Colaborarea noastră a fost foarte plăcută și îmbogățitoare și s-a simțit într-adevăr ca o cooperare directă între Mo ca fabrica de idei, eu ca recenzent și Claude ca nimic mai mult decât un mediator al ideilor noastre. Rolul cheie al lui Claude pe tot parcursul procesului a fost în gestionarea tuturor detaliilor tehnice grele. Amândoi ne-am uitat cu atenție la fiecare linie de cod, dar utilizarea lui Claude a permis conversațiilor noastre să rămână la niveluri conceptuale mai înalte decât ceea ce s-ar fi întâmplat dacă ar fi trebuit să facem noi înșine toată implementarea tehnică. Cred că acesta este aspectul care mi s-a părut cel mai surprinzător: faptul că utilizarea lui Claude a făcut ca colaborarea noastră să se simtă mai puțin tehnică și, prin urmare, cumva și mai umană. Și asta ne-a oferit posibilitatea de a lucra cu 70 de solicitări de extragere reprezentând peste 100 de noi verificări, toate gata de utilizare pentru toată lumea.
Spune-ne ce crezi
