Koodin laadusta on paljon keskusteluja, artikkeleita ja blogeja. Ihmiset sanovat - käytä tekniikoita Testikäyttöinen ! Testaus on 'pakko' uudelleenkorjaamisen aloittamiseksi! Kaikki tämä on hienoa, mutta olemme vuonna 2016, ja kymmenen, viisitoista ja jopa kaksikymmentä vuotta sitten luotuja tuotteita ja koodipohjia on edelleen tuotannossa. Ei ole mikään salaisuus, että monilla heistä on vanha koodi, jolla on alhainen testipeitto.
Vaikka haluaisin aina olla teknisen maailman kärjessä tai jopa veressä - mukana uusissa projekteissa ja tekniikoissa, se ei valitettavasti ole aina mahdollista, ja minun on usein käsiteltävä vanhentuneita järjestelmiä. Haluan sanoa, että kun kehität tyhjästä, toimi luojana ja luo uutta ainetta. Mutta kun työskentelet vanhan koodin kanssa, olet kuin kirurgi - tiedät, miten järjestelmä toimii yleensä, mutta et ole koskaan varma, tuleeko potilas hyvin 'leikkauksesta'. Ja koska se on vanha koodi, ei ole monia päivitettäviä testejä, joihin voit luottaa. Tämä tarkoittaa, että usein yksi ensimmäisistä vaiheista on peittää se testauksella. Tarkemmin sanottuna, kattavuuden tarjoamisen lisäksi testausstrategian kehittäminen.
Pohjimmiltaan minun piti määrittää, mitkä järjestelmän osat (luokat / paketit) meidän on ensin katettava testeillä, missä tarvitsemme yksikkötestejä, missä kyselykokeet olisivat hyödyllisimpiä jne. On olemassa monia tapoja lähestyä tällaista analyysiä, ja käyttämäni analyysi ei ehkä ole paras, mutta se on samanlainen kuin automaattinen lähestymistapa. Kun lähestymistapani on toteutettu, itse analyysin tekeminen vie vähän aikaa, ja mikä tärkeintä, se tuo hauskaa vanhojen koodien analysointiin.
Pääajatuksena on analysoida kahta mittaria - kytkentä (esim. Afferentti kytkentä tai CA) ja monimutkaisuus (esim. Syklomaattinen monimutkaisuus).
Ensimmäinen mittaa kuinka monta luokkaa luokkamme mittaa, joten se kertoo meille periaatteessa, kuinka lähellä jokin tietty luokka on järjestelmän ytimeen; mitä enemmän luokkia on luokassa, sitä tärkeämpää on peittää ne testeillä.
Toisaalta, jos luokka on hyvin yksinkertainen (esim. Se sisältää vain vakioita), niin jos sitä käytetään monissa muissa järjestelmän osissa, ei ole niin tärkeää luoda testiä sille. Täällä toinen mittari voi auttaa. Jos luokka sisältää paljon logiikkaa, syklomaattinen monimutkaisuus on suuri.
Samaa logiikkaa voidaan soveltaa päinvastoin; Esimerkiksi, vaikka luokkaa ei käytetä monissa luokissa ja se edustaa vain yhtä tiettyä käyttötapausta, on silti järkevää peittää se testeillä, jos sen sisäinen looginen käyttö on monimutkaista.
On kuitenkin olemassa varoitus: sanotaan, että meillä on kaksi luokkaa - toisessa CA on 100 ja monimutkaisuus 2, ja toisessa CA on 60 ja monimutkaisuus 20. Vaikka mittareiden summa on suurempi ensimmäisessä, meidän pitäisi peitä toinen ensin. Tämä johtuu siitä, että ensimmäistä luokkaa käyttävät monet muut luokat, mutta se ei ole kovin monimutkainen. Toisaalta toista luokkaa käyttävät myös monet muut luokat, mutta se on suhteellisen monimutkainen kuin ensimmäinen luokka.
Yhteenvetona: meidän on tunnistettava luokat, joilla on korkea CA- ja syklomaattinen monimutkaisuus. Matemaattisesti sanottuna tarvitset kunto-funktion, jota voidaan käyttää luokituksena. - f (CA, monimutkaisuus) - joiden arvot kasvavat yhdessä CA: n ja monimutkaisuuden kanssa.
Yleensä luokilla, joilla on pienimmät erot kahden mittarin välillä, tulisi olla ensisijainen prioriteetti testien kattavuudessa.Työkalujen löytäminen CA: n ja monimutkaisuuden laskemiseksi koko koodipohjalle ja yksinkertaisen tavan tarjota nämä tiedot CSV-muodossa osoittautui haastavaksi. Haun aikana löysin kaksi ilmaista työkalua, joten olisi epäoikeudenmukaista olla mainitsematta niitä:
Suurin ongelma tässä on se, että meillä on kaksi kriteeriä - CA ja syklomaattinen monimutkaisuus - joten meidän on yhdistettävä ne ja muutettava ne yhdeksi skalaariarvoksi. Jos meillä olisi hieman erilainen tehtävä - esimerkiksi etsiä luokka, jossa kriteereidemme pahin yhdistelmä - meillä olisi klassinen monikäyttöinen optimointiongelma:
Meidän on löydettävä piste niin kutsutusta Pareto-rintamasta (punainen yllä olevassa kuvassa). Pareto-sarjan mielenkiintoinen asia on, että jokainen joukon piste on ratkaisu optimointitestiin. Joka kerta kun siirrymme alaspäin punaisella viivalla, meidän on sitoututtava kriteereihimme - jos toinen paranee, toinen huononee. Tätä kutsutaan skaalaukseksi ja lopputulos riippuu siitä, miten se tehdään.
Tässä on monia tekniikoita. Jokaisella on omat hyvät ja huonot puolensa. Suosituimmat ovat kuitenkin lineaarinen skalaarisointi ja joka perustuu a viitekohta . Lineaarinen on helpoin. Kuntotoimintomme näyttää lineaariselta CA: n ja monimutkaisuuden yhdistelmältä:
f (CA, monimutkaisuus) = A × CA + B × monimutkaisuus
missä A ja B ovat joitain kertoimia.
Piste, joka edustaa ratkaisua optimointiongelmallemme, on rivillä (sininen alla olevassa kuvassa). Juuri se on sinisen viivan ja punaisen Pareto-rungon leikkauspiste. Alkuperäinen ongelmasi ei ole tarkalleen optimointiongelma. Mutta meidän on luotava luokittelutoiminto. Tarkastellaan kahta luokitustoimintomme arvoa, pohjimmiltaan kahta arvoa Rank-sarakkeessa.
R1 = A ∗ CA + B ∗ Monimutkaisuus ja R2 = A ∗ CA + B ∗ Monimutkaisuus
Jotkut yllä kirjoitetuista kaavoista ovat viivojen yhtälöitä, vielä enemmän nämä linjat ovat yhdensuuntaisia. Kun otetaan huomioon enemmän luokitusarvoja, meillä on enemmän viivoja ja siten enemmän pisteitä, joissa Pareto-viiva leikkaa siniset viivat (pisteviivat). Nämä pisteet ovat luokkia, jotka vastaavat tiettyä luokiteltuja arvoja.
Valitettavasti tässä lähestymistavassa on ongelma. Millä tahansa rivillä (luokiteltu arvo) meillä on pisteitä, joilla on pieni CA ja erittäin suuri monimutkaisuus (ja päinvastoin). Tämä asettaa välittömästi pisteet, joilla on suuri ero metristen arvojen välillä, ensin luettelossa, mitä halusimme välttää.
Toinen tapa tehdä skalarisaatio perustuu vertailupisteeseen. Vertailupiste on piste, jolla on molempien kriteerien maksimiarvot:
(max (CA), max (monimutkaisuus))
Kuntotoiminto on vertailupisteen ja datapisteiden välinen etäisyys:
f (CA, monimutkaisuus) = √ ((CA - CA)2+ (Monimutkaisuus - monimutkaisuus)2)
Voimme ajatella tätä kunto-toimintoa ympyränä, jonka keskipiste on vertailupisteessä. Säde on tässä tapauksessa luokituksen arvo. Optimointiongelman ratkaisu on kohta, jossa ympyrä koskettaa Pareton etuosaa. Alkuperäisen ongelman ratkaisu on pistejoukot, jotka vastaavat eri ympyrän säteitä seuraavan kuvan mukaisesti (eri luokkien ympyröiden osat näytetään sinisinä katkoviivoin):
Tämä lähestymistapa käsittelee äärimmäiset arvot paremmin, mutta on kuitenkin kaksi ongelmaa: Ensinnäkin - haluaisin saada enemmän pisteitä lähelle vertailupisteitä ratkaisemaan paremmin lineaarisen yhdistelmän kanssa kohtaamamme ongelman. Toiseksi - CA ja syklomaattinen monimutkaisuus ovat luonnostaan erilaisia ja niillä on erilaiset arvosarjat, joten meidän on normalisoitava ne (esim. Niin, että molempien mittareiden kaikki arvot ovat 1: stä 100: een)
Tässä on pieni temppu, jota voimme soveltaa ensimmäisen ongelman ratkaisemiseen - sen sijaan, että tarkastelisimme CA: ta ja syklomaattista monimutkaisuutta, voimme tarkastella niiden käänteisiä arvoja. Vertailupiste on tässä tapauksessa (0,0). Toisen ongelman ratkaisemiseksi voimme normalisoida mittarit käyttämällä minimiarvoa. Näin se näyttää:
Normalisoitu ja käännetty monimutkaisuus - Normi monimutkaisuus :
(1 + min (monimutkaisuus)) / (1 + monimutkaisuus) ∗ 100
Käänteinen ja normalisoitu vaihtovirta - NormCA :
(1 + min (CA)) / (1 + CA) ∗ 100
Huomautus: Lisäsin 1 varmistaaksesi, ettei jakoa 0. t: llä
Seuraava kuva näyttää kaavion, jossa on käännetyt arvot:
Olemme päässeet viimeiseen vaiheeseen - luokituksen laskemiseen. Kuten mainitsin, käytän vertailumenetelmää, joten kaikki mitä meidän on tehtävä, on laskea vektorin pituus, normalisoida se ja tuoda se esiin luokan yksikkötestin luomisen tärkeydellä. Tässä on viimeinen kaava:
Sijoitus (NormComplexity, NormCA) = 100 - √ (NormComplexity2+ NormCA2) / √2
Haluaisin lisätä lisää ajatuksia, mutta tarkastellaan ensin joitain tilastoja. Tässä on histogrammi kytkimen mittareista:
Mielenkiintoista tässä kuvassa on niiden luokkien lukumäärä, joilla on alhainen CA (0-2). Luokat, joiden CA-arvo on 0, eivät ole lainkaan käytössä tai ovat korkean tason palveluita. Nämä edustavat päätepisteitä ANTAA POTKUT , joten on hyvä, jos meillä on paljon niitä. Mutta luokat, joissa CA on 1, ovat niitä, joita päätepisteet käyttävät suoraan, ja meillä on enemmän näitä luokkia kuin päätepisteitä. Mitä tämä tarkoittaa arkkitehtuurin / suunnittelun näkökulmasta?
Yleensä se tarkoittaa, että meillä on käsikirjoituskeskeinen lähestymistapa - kirjoitamme jokaisen liiketapauksen erikseen (emme voi käyttää koodia uudelleen, koska liiketoimintatapaukset ovat hyvin erilaisia). Jos näin on, niin se on ehdottomasti a hajukoodi ja meidän täytyy refraktoida. Jos ei, se tarkoittaa, että järjestelmämme koheesio on heikko, tässä tapauksessa tarvitsemme myös refaktorointia, mutta arkkitehtuurin refaktorointia tässä tapauksessa.
Ylimääräinen tieto, jonka voimme saada yllä olevasta histogrammista, on se, että voimme suodattaa täysin matalan kytkentäluokan (CA kohdassa {0,1}) luokkien luettelosta, joka on käytettävissä kattavuudelle yksikkötesteillä. Samat luokat ovat kuitenkin hyviä ehdokkaita integraatioon / toiminnalliseen testaukseen.
Löydät kaikki käyttämäni komentosarjat ja resurssit tästä GitHub-arkistosta: ashalitkin / code-base-stats .
Ei välttämättä. Ensinnäkin kyse on staattisesta analyysistä, ei ajonajasta. Jos luokka suodatetaan monista muista luokista, se voi olla merkki siitä, että sitä käytetään paljon, mutta se ei aina ole. Emme esimerkiksi tiedä, käyttävätkö loppukäyttäjät voimakkaasti toimintoja. Toiseksi, jos järjestelmän suunnittelu ja laatu ovat riittävän hyvät, varmasti järjestelmän eri osat / kerrokset irrotetaan rajapintojen yli, joten staattinen AC-analyysi ei anna meille oikeaa kuvaa. Luulen, että se on yksi tärkeimmistä syistä, miksi CA ei ole suosittu työkalu, kuten Sonar. Onneksi se on hienoa kanssamme, koska jos muistat, olemme kiinnostuneita soveltamaan tätä nimenomaan rumaan vanhaan koodipohjaan.
Yleisesti sanoisin, että ajonaika-analyysi antaisi parempia tuloksia, mutta valitettavasti se on paljon kalliimpaa, aikaa vievää ja monimutkaista, joten lähestymistapa on mahdollisesti hyödyllinen ja halvempi vaihtoehto.
Liittyvät: Ainutlaatuinen ensisijainen vastuu: Resepti erinomaiselle koodille