Ștergerea Soft

13

martie 2019

Ștergerea Soft

De: Tree Web Solutions | Etichete: stergere soft, stergere obiecte, recuperare date, implementare stergere soft

În acest articol mă voi concentra în primul rând pe una dintre cele mai populare opțiuni de implementare a ștergerii soft într-un proiect Ruby on Rails-acts_as_paranoid, care se bazează pe adăugarea unei coloane deleted_at la fiecare model care are nevoie de suport pentru ștergerea softă. Unele alternative vor fi discutate și spre sfârșit.

Obiective

Utilizatorii au motive diferite de a dori ștergerea soft, de la restaurarea unui obiect șters accidental, la recuperarea de la ștergerea răuvoitoare sau neautorizată, la recuperarea unui obiect care a fost șters în mod intenționat, dar recuperarea devenită necesară din cauza unor circumstanțe noi. Unii utilizatori doresc, de asemenea, o funcție de "reciclare" sau "arhivă" care să permită separarea obiectelor active de cele neactivate, iar ștergerea soft este o modalitate de a realiza acest lucru. Capacitatea de a șterge și restabili datele trebuie să fie disponibilă pentru utilizatorii finali cu rolul adecvat, nu numai administratorii ACL sau personalul de asistență. În plus, pentru a permite recuperarea, obiectele șterse soft rămân în sistem și continuă să utilizeze resursele sistemului până când sunt șterse definitiv.

Un exemplu simplu de interfață pentru gestionarea obiectelor șterse Soft.

Metoda de implementare

Strategia de ștergere Soft

Una dintre cele mai populare biblioteci pentru a implementa ștergerea Soft este acts as paranoid gem. Abordarea sa generală este:

  • Adăugați o coloană deleted_at la fiecare tabel care acceptă ștergerea Soft. Orice înregistrare în care coloana respectivă are o valoare care nu este NULL este considerată a fi eliminată soft. Când o înregistrare este ștearsă prin Active Record (biblioteca ORM implicită, ambalată cu Ruby on Rails), în loc de a șterge efectiv înregistrarea din baza de date, apare coloana deleted_at cu momentul ștergerii.
  • Adăugați o dimensiune implicită la modelul care acceptă ștergerea soft, astfel încât interogările "normale" să excludă înregistrările marcate ca fiind șterse, ceea ce face ca înregistrările șterse (în cea mai mare parte) să fie invizibile aplicației.
  • Furnizați metode speciale pentru a interacționa cu înregistrările șterse soft, inclusiv: .with_deleted și .only_deleted - pentru a căuta înregistrări șterse soft, .destroy_fully pentru a șterge definitiv o înregistrare și .recover pentru a restabili înregistrările șterse (prin anularea domeniul lor deleted_at.

Strategia de recuperare

Cu orice abordare de ștergere Soft, trebuie să echilibrăm dorința unor clienți de a permite recuperarea obiectelor (inclusiv acele obiecte care au fost "șterse definitiv"), cu dorința altor clienți de a face o ștergere permanentă, de fapt, irecuperabilă.

O abordare este o capacitate de ștergere pe bază de roluri, unde unii utilizatori (administratorii) au capacitatea de a șterge irecuperabil un obiect, în timp ce ceilalți utilizatori pot șterge numai soft. Acest lucru limitează spațiul provocării, dar nu îl elimină complet, deoarece chiar administratorii de sistem ar putea dori să recupereze obiectele "permanent" șterse de alți administratori.

O altă abordare este colectarea de "gunoi" în funcție de timp, în care toate obiectele sunt șterse (și plasate în "coșul de gunoi") pentru o perioadă de timp prestabilită, în timpul căreia pot fi recuperate. Orice obiecte care nu au fost recuperate în acest timp vor fi șterse definitiv de sistem.

Provocări tehnice

Abordarea oferită de acts_as_paranoid este ușor de înțeles și implementată și oferă funcționalitate rapidă de ștergere Soft. Prin urmare, este destul de popular, în special în aplicațiile mai mici. Cu toate acestea, abordarea ștergerii implicite a soft-ului are unele neajunsuri, care devin mai serioase pe măsură ce aplicația crește într-o complexitate.

Relații ierarhice

Cele mai multe aplicații au un fel de ierarhizare semantică în unele dintre modelele lor. De exemplu, modulul Proiecte noastre are modele "proiecte" care conțin multe "obiective", care la rândul lor conțin multe "controale". Dacă ar fi nevoie să oferim suport pentru toate aceste modele, logica noastră de afaceri ar implica faptul că ștergerea softului ar trebui să facă ca toate obiectivele sale să pară șterse (dar nu invers), iar ștergerea soft a unui obiectiv ar trebui să facă ca toate comenzile sale să pară a fi șterse soft. Unele obiecte au mai mult de un părinte, adăugând în plus complexitatea.

Alegerea este, așadar, să stocați coloana delete_at pe toate modelele sau numai pe cea parentală. Ambele abordări au dezavantaje. Să presupunem că stocăm doar pavilionul șters pe proiect. Dacă orice parte a codului dvs. accesează direct un control (de la o solicitare de utilizator la un lucrător cu sarcină de întârziere), codul dvs. trebuie acum să verifice dacă controlul trebuie tratat "implicit" soft eliminat, deoarece proiectul său a fost șters. Aceasta ar trebui să fie o logică personalizată, care nu este furnizată de acte_as_paranoid, deoarece controlul nu are propriul flag deleted_at (deci o interogare normală de înregistrare activă o va încărca), iar act_as_paranoid nu este conștient de ierarhia aplicațiilor sau de regulile logicii de afaceri.

Dacă delete_at nu este sincronizat pe modele dependente, interogarea din pasul 2 trebuie construită manual pentru a evita încărcarea modelului dependent când părintele este șters.

Alternativ, puteți alege să adăugați coloana deleted_at și la modelele dependente, care vor fi populate automat dacă modelul părinte a fost configurat dependent::distruge, evitând problemele discutate în paragraful anterior. Cu toate acestea, această abordare nu este, de asemenea, lipsită de dezavantaje. Dacă utilizați orice SQL personalizat pentru a șterge înregistrările sau dacă vă bazați pe nivel de bază de date ON DELETE CASCADE (mai degrabă decât dependent::destroy) pentru performanță sau din alte motive, obiectele dependente deleted_at nu vor fi populate automat dacă părintele este șters. Este posibil să trebuiască să scrieți comenzi personalizate SQL sau baze de date pentru a rezolva acest lucru, adăugând mai multă complexitate și sarcină de întreținere.

Mai mult, luați în considerare următoarea secvență de evenimente: (1) obiectul dependent este șters soft, (2) obiectul său parent este șters soft și (3) obiectul parental este restabilit. În care caz obiectul dependent va fi restabilit sau nu? S-ar putea argumenta că nu ar trebui - pentru că a fost ștearsă în mod explicit înaintea părintelui - dar cum veți diferenția această secvență de cea în care nu s-a întâmplat pasul (1)? Nu este posibil dacă există o singură coloană delete_at pe tabelă, deoarece baza de date nu va urmări diferența în ștergerea explicită vs. cascadă. Acest lucru ar putea fi rezolvat prin adăugarea unor drapele de baze de date diferite - cum ar fi deleted_at vs cascade_deleted_at, dar din nou, aceasta adaugă o complexitate suplimentară și depășește domeniul de aplicare al actului_as_paranoid gem (care ar trebui modificat pentru a verifica ambele coloane pentru a determina dacă înregistrarea a fost ștearsă.)

Dacă ștergerea_at este sincronizată pe modele dependente, ștergerea și restaurarea modelului părinte pot pierde istoricul dacă delegația a fost șters în mod explicit mai devreme (pasul 1) sau nu.

Validări și constrângeri

Înregistrările grafice șterse au, de asemenea, provocări de validare. De exemplu, să presupunem că logica dvs. de afaceri impune o constrângere privind unicitatea unui nume de proiect. În care caz constrângerea include obiecte șterse? În acest caz, un nume care a fost utilizat anterior pentru un obiect șters soft va fi indisponibil pentru utilizare ulterioară, ceea ce poate surprinde un utilizator care nu vede proiecte cu ștergere soft și pune la îndoială motivul pentru care numele ales nu este disponibil. Dacă constrângerea dvs. este aplicată la nivelul bazei de date utilizând un index unic, mai degrabă decât o validare Rails, atunci se va aplica în mod implicit înregistrărilor șterse (cu excepția cazului în care construiți un index parțial care exclude înregistrările șterse soft).

Pe de altă parte, în cazul în care constrângerea de validare nu acoperă obiecte moștenite, ce se va întâmpla dacă (1) un proiect a fost șters cu ușurință, (2) a fost creat un nou proiect cu același nume și (3) proiectul vechi este încercat să fie restaurat? Acum există un conflict de validare care împiedică restaurarea, deoarece acest lucru ar introduce o coliziune a numelui. Va trebui să ocoliți validarea (sau să o eliminați în întregime) sau să efectuați o logică personalizată, cum ar fi redenumirea vechiului proiect, pentru a avea un sufix "(vechi)" la sfârșitul numelui său.

Performanță și scalabilitate

O problemă importantă este luarea în considerare a performanței și a impactului de scalabilitate pe care le au înregistrările moștenite pe sistem. Chiar dacă astfel de înregistrări pot fi invizibile pentru majoritatea utilizatorilor, aceștia rămân în aceeași bază de date cu celelalte înregistrări, si (cel puțin) vor continua să preia spațiu. În cazul în care înregistrările șterse sunt incluse în indexarea dvs. (care va fi comportamentul implicit, cu excepția cazului în care faceți indici parțiali care le exclud), astfel de indici va afecta latența dvs. de scriere pe măsura creșterii setului de date, ceea ce va fi deosebit de important dacă așteptați raportul mare de ștergere la activ (de exemplu, dacă utilizați ștergerea soft ca mijloc de funcționalitate de arhivare).

Pe de altă parte, dacă indexurile dvs. exclud înregistrările șterse, atunci nu veți putea beneficia de ele în nicio parte a codului care trebuie efectiv să le caute (cum ar fi cadrele de clonare sau de logare care trebuie să funcționeze cu toate înregistrările, inclusiv cele cu ștergere soft).

Alternative

Export and reimport

În afară de abordarea referitoare la baza de date furnizată de acte_as_paranoid, puteți lua în considerare alte alternative la ștergerea soft. Este posibil să exportați obiecte șterse (în CSV, JSON, dump SQL sau alt format) și să le stocați pe S3 sau în altă parte. Eliminarea elementelor șterse din baza de date se poate adresa unor preocupări legate de performanță și scalabilitate.

Cu toate acestea, orice logică personalizată de import și export ar fi probabil mai complexă decât o simplă bază de date delete_at, în timp ce încă mai trebuie să se facă față acelorași provocări legate de integritatea referențială, relațiile ierarhice și alte reguli de logică de afaceri. Unele provocări pot fi și mai complexe - de exemplu, dacă schema dvs. a fost migrată după un export, va trebui să vă asigurați că datele exportate din schema veche pot fi importate mai târziu.

Event sourcing

O altă abordare este apariția evenimentului. O bază de date pentru achiziționarea de evenimente este o bază de date imuabilă care înregistrează toate evenimentele ca fiind tranzacții - modificarea sau ștergerea înregistrărilor creează o nouă tranzacție (la fel ca în contabilitate, unde inversarea unei tranzacții face o intrare în jurnal nouă). Într-o bază de date pentru achiziționarea de evenimente, nu este necesar să implementăm manual ștergerea soft, deoarece o versiune veche ar putea fi întotdeauna restaurată dintr-o revizuire anterioară.

Sursa: https://medium.com

Distribuie această postare