Kaip pašalinti vienos lentelės paveldėjimą iš jūsų bėgių monolito

Paveldėjimas yra lengvas - kol teks susitvarkyti su techninėmis skolomis ir mokesčiais.

Kai prieš penkerius metus atsirado pagrindinė „Learn“ pagrindinė bazė, gana populiarus buvo vieno stalo paveldėjimas. Tuo metu „Flatiron Labs“ komanda ėmėsi visa ko - naudodama ją viskuo, pradedant įvertinimais ir mokymo programa, baigiant veiklos sklaidos renginiais ir turiniu mūsų augančioje mokymosi valdymo sistemoje. Ir tai buvo puiku - darbas buvo atliktas. Tai leido instruktoriams pateikti mokymo programą, sekti studentų pažangą ir sukurti patrauklų vartotojo patirtį.

Tačiau, kaip pažymėjo daugelis internetinių dienoraščių įrašų (šis, šis, ir, pavyzdžiui, šis), VMI nepatenkina labai gerai, ypač didėjant duomenims ir naujiems poklasiams pradedant labai skirtis nuo jų superklasių. Kaip jau galėjote atspėti, tas pats atsitiko mūsų kodų bazėje! Mūsų mokykla plėtėsi ir palaikėme vis daugiau funkcijų ir pamokų tipų. Laikui bėgant, modeliai pradėjo pūstis ir mutuoti ir nebeatitinka tinkamos domeno abstrakcijos.

Mes kurį laiką gyvenome toje erdvėje, suteikdami šiam kodui plačią prieplauką ir pataisydami jį tik prireikus. Ir tada atėjo laikas reaguoti.

Per pastaruosius keletą mėnesių aš ėmiausi misijos pašalinti vieną ypač niūrų LTI atvejį, kuris apėmė šiek tiek dviprasmiškai pavadintą „Content“ modelį. Taip paprasta, kaip iš pradžių nustatyti VMI, iš tikrųjų gana sunku pašalinti.

Taigi šiame įraše šiek tiek papasakosiu apie VMI, pateiksime tam tikrą kontekstą apie mūsų sritį, apibūdinsime darbo apimtį ir aptarsime strategijas, kurias įgyvendinau saugiai diegdamas pokyčius, tuo pačiu sumažindamas rimtos žalos paviršiaus plotą, kol išsigryninau branduolį. mūsų programos.

Apie vieno stalo paveldėjimą (VMI)

Trumpai tariant, vienos lentelės paveldėjimas bėgiuose leidžia vienoje lentelėje laikyti kelių tipų klases. Aktyviajame įraše klasės pavadinimas saugomas kaip tipas lentelėje. Pvz., Turėtumėte, kad visi „Lab“, „Readme“ ir „Project“ visi pateikiami turinio lentelėje:

klasė Lab 

Šiame pavyzdyje laboratorijos, skaitymas ir projektai yra visų tipų turinys, kuris gali būti susietas su pamoka.

Turinio lentelės schema atrodė šiek tiek taip, todėl galite pamatyti, kad tipas tiesiog saugomas lentelėje.

sukurti_tabletą „turinys“, jėga:: kaskados padaryti | t |
  t.integer „curriculum_id“,
  t.string "tipas",
  t.tekstas „markdown_format“,
  t.string "title",
  t.integer „track_id“,
  t.integer „github_repository_id“
pabaiga

Darbo apimties nustatymas

Turinys išplatintas visoje programoje, kartais klaidinantis. Pavyzdžiui, taip buvo aprašyti santykiai pamokos modelyje.

klasės pamoka  {order (ordinal:: asc)}
  has_one: turinys, užsienio_raktas:: mokymo programa_id
  has_many: readmes, Foreign_key:: curriculum_id
  „has_one“: laboratorija, užsienio_raktas:: mokymo programa_id
  has_one: readme, Foreign_key:: curriculum_id
  has_many: paskirti_atsakymai per:: turinys
pabaiga

Sumišęs? Taip buvo ir aš, ir tai buvo tik vienas iš daugelio modelių, kuriuos aš turėjau pakeisti.

Taigi su savo genialiais ir talentingais komandos draugais (Kate Travers, Steven Nunez ir Spencer Rogers) sumaniau sukurti geresnį dizainą, kuris padėtų sumažinti painiavą ir palengvintų šios sistemos plėtrą.

Naujas dizainas

Sąvoka, kurią „Content“ bandė reprezentuoti, buvo tarpininkas tarp „GithubRepository“ ir „Pamoka“.

Kiekvienas „kanoninio“ pamokos turinio fragmentas yra susietas su „GitHub“ saugykla. Kai pamokos yra skelbiamos ar „dislokuojamos“ studentams, mes pasidarome to „GitHub“ saugyklos kopiją ir suteikiame studentams nuorodą į ją. Ryšys tarp pamokos ir įdiegtos versijos yra vadinamas AssignedRepo.

Taigi abiejuose pamokų galuose yra „GitHub“ saugyklos: kanoninė versija ir įdiegta versija.

klasės turinys 
klasė AssignedRepo 

Vienu metu pamokose galėjo būti daug turinio, tačiau dabartiniame pasaulyje to nebėra. Vietoj to, yra įvairių rūšių pamokų, kurios gali apžvelgti save, žiūrint į failus, įtrauktus į susijusias saugyklas.

Taigi, mes nusprendėme pakeisti „Content“ nauja koncepcija, vadinama „CanonicalMaterial“, ir suteikti „AssignedRepo“ tiesioginę nuorodą į su ja susijusią pamoką, užuot perėję turinį.

Senos ir naujos sistemos diagrama, kurioje raudonos punktyrinės linijos žymi nusidėvėjimo takus

Jei tai atrodo painu ir patinka daug darbo, taip yra, nes taip yra. Vis dėlto svarbiausias pasirodymas yra tas, kad mes turėjome pakeisti modelį gana didelėje kodų bazėje ir galų gale pakeitėme 6000 kodo eilučių sritį.

Vis dėlto svarbiausias pasirodymas yra tas, kad mes turėjome pakeisti modelį gana didelėje duomenų bazėje ir galų gale pakeitėme 6000 kodo eilučių sritį.

STI reagavimo ir pakeitimo strategijos

Naujasis modelis

Pirmiausia mes sukūrėme naują lentelę pavadinimu canonical_materials ir sukūrėme naują modelį ir asociacijas.

klasės „CanonicalMaterial“ 

Taip pat prie mokymo programos lentelės pridėjome svetimą „canonical_material_id“ raktą, kad pamoka galėtų išlaikyti nuorodą į jį.

Į priskirtų_repozitų lentelę pridėjome stulpelį „lec_id“.

Dvigubi raštai

Kai naujos lentelės ir stulpeliai buvo vietoje, mes pradėjome rašyti prie senų ir naujų lentelių tuo pačiu metu, kad mums nereikėtų pakartoti pildymo užduoties daugiau nei vieną kartą. Kiekvieną kartą, kai kas nors bandė sukurti ar atnaujinti turinio eilutę, mes taip pat sukūrėme ar atnaujiname „canonical_material“.

Pavyzdžiui:

lesson.build_content (
  'repo_name' => repo.name,
  'github_repository_id' => repo_id,
  'markdown_format' => repo.readme
)

lesson.canonical_material = repo.canonical_material
pamoka.save

Tai leido mums paruošti pagrindą, kad galutinai pašalintume Turinį.

Užpildymas

Kitas proceso žingsnis buvo pakartotinis duomenų užpildymas. Mes rašėme grėblio užduotis, kad galėtume užpildyti savo lenteles ir įsitikinti, kad kiekvienoje „GithubRepository“ yra „CanonicalMaterial“ ir kad kiekviena pamoka turėtų „CanonicalMaterial“. Tada mes vykdėme užduotis savo gamybos serveryje.

Šiame pertvarkymo etape mes teikėme pirmenybę turintiems galiojančius duomenis, kad galėtume aiškiai atsipūsti naudodamiesi paliktu būdu. Tačiau kita perspektyvi galimybė yra rašyti kodą, kuris vis dar palaiko senesnius modelius. Mūsų patirtis rodo, kad išlaikyti seną mąstymą palaikantį kodą buvo painiau ir brangiau, nei buvo užpildyti ir įsitikinti, kad duomenys teisingi.

Mūsų patirtis rodo, kad išlaikyti seną mąstymą palaikantį kodą buvo painiau ir brangiau, nei buvo užpildyti ir įsitikinti, kad duomenys teisingi.

Pakeitimas

Ir tada prasidėjo linksmoji dalis. Norėdami, kad pakeitimas būtų kuo saugesnis, mes panaudojome funkcijų vėliavas, kad gabentume tamsųjį kodą mažesniuose PR, kurie leido mums sukurti greitesnį grįžtamojo ryšio ciklą ir greičiau žinoti, ar viskas nutrūko. Norėdami tai padaryti, mes panaudojome perleidimo perlą, kurį taip pat naudojame standartinėms funkcijoms kurti.

Ko ieškoti

Viena sunkiausių pakeitimo dalių buvo daugybė ieškomų dalykų. Žodis „turinys“, deja, yra labai bendras, todėl nebuvo įmanoma atlikti paprastos, globalios paieškos ir pakeisti, todėl aš buvau linkęs atlikti platesnę paiešką, bandydamas atsižvelgti į variantus.

Pašalindami LTI, turėtumėte ieškoti šių dalykų:

  • Vienaskaitos ir daugiskaitos modelio formos, įskaitant visus jo poklasius, metodus, naudingumo metodus, asociacijas ir užklausas.
  • Kietojo kodo SQL užklausos
  • Valdikliai
  • Serializatoriai
  • Peržiūrėjo

Pvz., Dėl turinio tai reiškė, kad reikia ieškoti:

  • : turinys - asociacijoms ir užklausoms
  • : turinys - asociacijoms ir užklausoms
  • .joins (: turinys) - prisijungimo užklausoms, kurias turėtų sugauti ankstesnė paieška
  • .incalls (: turinys) - norintiems pakrauti antrosios eilės asociacijas, kurios taip pat turėtų būti įtrauktos į ankstesnę paiešką
  • turinys: - įdėtoms užklausoms
  • turinys: - vėlgi daugiau įdėtų užklausų
  • content_id - užklausoms tiesiogiai pagal ID
  • .content - metodo skambučiai
  • .turinys - rinkimo metodo skambučiai
  • .build_content - naudingumo metodas, pridėtas asociacijos „has_one“ ir „priklauso_“
  • .create_content - naudingumo metodas, kurį prideda „has_one“ ir priklauso_to asociacija
  • .content_ids - naudingumo metodas, kurį prideda asociacija „has_many“
  • Turinys - pats klasės pavadinimas
  • turinys - paprasta bet kokių užkoduotų nuorodų ar SQL užklausų eilutė

Manau, kad tai gana išsamus turinio sąrašas. Tada aš padariau tą patį darbą laboratorijoms, skaitymui ir projektui. Galite pastebėti, kad „Rails“ yra toks lankstus ir prideda daugybę naudingumo metodų, todėl sunku rasti visas vietas, kur galiausiai bus naudojamas modelis.

Kaip iš tikrųjų pakeisti įgyvendinimą, kai radote visus skambinančius asmenis

Kai iš tikrųjų rasite visas modelio, kurį bandote pakeisti ar pašalinti, skambučių svetaines, jūs turite perrašyti dalykus. Apskritai procesas, kurio mes sekėme, buvo

  1. Pakeiskite metodo elgseną apibrėžime arba pakeiskite metodą skambučio vietoje
  2. Parašykite naujus metodus ir paskambinkite jiems už funkcijų vėliavos skambučių svetainėje
  3. Nutraukite priklausomybę nuo asociacijų su metodais
  4. Padidinkite klaidas po funkcijos vėliava, jei nesate tikri dėl metodo
  5. Keiskite objektus, turinčius tą pačią sąsają

Čia pateikiami kiekvienos strategijos pavyzdžiai.

1a. Pakeiskite metodo elgseną ar užklausą

Kai kurie pakeitimai yra gana nesudėtingi. Jūs įdėjote objekto vėliavą, sakydami „skambinkite šiuo kodu, o ne kitu kodu, kai ši vėliava įjungta“.

Taigi, užuot pateikę užklausas pagal turinį, čia pateikiame užklausą remdamiesi „canonical_material“.

1b. Pakeiskite metodą skambučių svetainėje

Kartais skambučių svetainėje yra lengviau pakeisti metodą, kad būtų standartizuojami vadinami metodai. (Atlikdami testą, turėtumėte paleisti savo testų rinkinį ir (arba) parašyti testus.) Tai atlikę galite atverti kelią tolesniam reagavimui.

Šis pavyzdys parodo, kaip nutraukti priklausomybę nuo stulpelio „canonical_id“, kurio netrukus nebebus. Atminkite, kad metodą pakeitėme skambučių vietoje, neišleisdami jo už objekto vėliavos. Atlikdami šį pertvarkymą, pastebėjome, kad „canonical_id“ išplėšėme ne vienoje vietoje, todėl mes sugalvojome logiką tai padaryti kitu metodu, kurį galėjome sujungti į kitas užklausas. Metodas skambučių svetainėje buvo pakeistas, tačiau elgesys nepasikeitė, kol nebuvo įjungta funkcijos vėliava.

2. Parašykite naujus metodus ir paskambinkite jiems už funkcijų vėliavos skambučių svetainėje

Ši strategija yra susijusi su metodo pakeitimu, tik šiame, mes parašome naują metodą ir vadiname jį už funkcijos vėliavos skambučio vietoje. Tai buvo ypač naudinga metodui, kuris buvo vadinamas tik vienoje vietoje. Tai taip pat leido mums suteikti metodą geresnį parašą - visada naudingą.

3. Nutraukite priklausomybes nuo asociacijų su metodais

Šiame kitame pavyzdyje takelyje yra daugybė laboratorijų. Kadangi žinome, kad asociacija has_many prideda naudingumo metodus, pakeitėme dažniausiai vadinamą ir pašalinome eilutę has_many: labs. Šis metodas atitinka tą pačią sąsają, todėl viskas, kas paskambino metodu prieš įjungiant funkciją, ir toliau veiks.

4. Padidinkite klaidas po funkcijos vėliava, jei nesate tikri dėl metodo

Kartais buvo netikėta, ar praleidome skambučių svetainę. Taigi, užuot iš pradžių sunkiai pašalinę metodus, mes sąmoningai kėlėme klaidas, kad galėtume jas sugauti rankinio bandymo etape. Tai leido mums geriau atsekti, kur buvo vadinamas metodas.

5. Keiskite objektus, turinčius tą pačią sąsają

Kadangi norėjome atsikratyti laboratorijos asociacijos, mes perrašėme laboratorijos įgyvendinimą? metodas. Užuot patikrinę, ar yra laboratorijos įrašas, mes apsikeitėme kanonine_materija, delegavome kvietimą ir privertėme tą objektą atsakyti tuo pačiu metodu.

Tai buvo naudingiausios priklausomybių pašalinimo ir naujų objektų keitimo strategijos mūsų Rails monolite. Peržiūrėję šimtus apibrėžimų ir skambučių svetainių, mes jas pakeitėme arba perrašėme po vieną. Tai yra varginantis procesas, kurio niekam ne linkiu, tačiau galiausiai jis buvo labai naudingas, kad mūsų kodų bazė būtų labiau įskaitoma ir pašalinamas senas kodas, kuris sėdėjo nieko nedarydamas. Pabaigai prireikė kelių varginančių ir plaukus traukiančių savaičių, tačiau, pakeitę didžiąją dalį nuorodų, pradėjome atlikti rankinius bandymus.

Testavimas ir testavimas rankiniu būdu

Kadangi pakeitimai paveikė visos kodo bazės funkcijas, kai kurios iš jų nebuvo išbandytos, buvo sunku užtikrintai tikrinti kokybę, tačiau mes padarėme viską. Mes atlikome rankinius bandymus savo QA serveryje, kuriame buvo užfiksuota daug klaidų ir atvejų. Tada mes ėjome į priekį ir kritiškesniais keliais rašėme naujus testus.

Sukurkite, pradėkite gyventi ir tvarkykitės

Praėję QA, mes užklijavome savo funkcijų vėliavą ir leidome sistemai įsitvirtinti. Įsitikinę, kad jis stabilus, iš kodų bazės pašalinome funkcijų vėliavas ir senus kodų kelius. Deja, tai buvo sunkiau, nei tikėtasi, nes reikėjo perrašyti daugybę testų rinkinio, daugiausia gamyklų, kurios netiesiogiai rėmėsi turinio modeliu. Žvelgdami atgal, mes galėjome padaryti du testų rinkinius, kol mes reagavome, vieną dabartiniam kodui, kitą kodą už ypatybės vėliavos.

Kaip paskutinį žingsnį, kurį dar reikia padaryti, turėtume sukurti atsarginę duomenų kopiją ir mesti nenaudojamas lenteles.

Tai, draugai, yra vienas iš būdų atsikratyti vieno stalo paveldėjimo jūsų „Rails“ monolite. Galbūt šis atvejo tyrimas padės ir jums.

Ar turite kitų būdų, kaip pašalinti LPL ar reaguoti? Mums įdomu sužinoti. Praneškite mums komentaruose.

Be to, mes samdome! Prisijunkite prie mūsų komandos. Mes šaunūs, pažadu.

Šaltiniai ir papildomi skaitiniai

  • Bėgiai vadovauja paveldėjimui
  • Kaip ir kada naudoti Eugene'o Wango („Flatiron Grad!“) Vienos lentelės paveldėjimą bėgiais
  • Mūsų bėgių programos refaktorius negali būti paveldimas iš vieno stalo
  • Vienos lentelės paveldimumas ir bėgių polimorfinės asociacijos
  • Vieno stalo paveldėjimas naudojant bėgius 5.02

Norėdami sužinoti daugiau apie „Flatiron“ mokyklą, apsilankykite svetainėje, stebėkite mus „Facebook“ ir „Twitter“ ir apsilankykite artėjančiuose renginiuose šalia jūsų.

„Flatiron“ mokykla yra išdidi „WeWork“ šeimos narė. Peržiūrėkite mūsų seserų technologijų tinklaraščius „WeWork Technology and Making Meetup“.