“Álmatlan éjszakáim voltak, amikor megpróbáltam funkciókat hozzáadni a kódhoz, amelyet egy másik cégtől szereztünk meg. A Legacy Code legtisztább formájával van dolgom”

“Nagyon nehéz dolgom van a kusza, strukturálatlan kóddal, amivel dolgoznom kell, de egy kicsit sem értem. Legacy Code !”

A Legacy Code egy olyan kifejezés, amelynek valószínűleg sokféle definíciója van, mint például -mástól szerzett kód, valaki más által írt kód, nehezen érthető kód vagy elavult technológiával írt kód. Bármi legyen is a definíció, a legtöbben úgy gondoljuk, hogy az örökölt kód ijesztő.

Kérdés> Ön hogyan definiálná az örökölt kódot?

Az örökölt kód meghatározása

Michael Feathers a “Working Effectively with Legacy Code” című könyvében úgy definiálja az örökölt kódot, mint tesztek nélküli kód.

A tesztek nélküli kód rossz kód. Nem számít, hogy milyen jól van megírva; milyen jól van strukturálva; milyen jól van kapszulázva. tesztek nélkül nem lehet megmondani, hogy a kódunk jobb vagy rosszabb lesz-e.

Nos, ennek a definíciónak egy kissé módosított változata a következő: “a unit tesztek nélküli kódot örökölt kódnak hívják”. Mindig jobb, ha a tesztek a lehető legközelebb vannak a kódhoz (egységtesztek > integrációs tesztek > UI tesztek). Tehát nem lenne igazságtalan az egységtesztek nélküli kódot örökölt kódnak nevezni.

Munka az örökölt kóddal

Kérdés> Milyen megközelítést alkalmazna, ha változtatást kellene végrehajtania az örökölt kódban?

A legtöbbünk azt mondaná, hogy “elvégzem a változtatást és kész, minek foglalkoznék a kód javításával”. Ennek a gondolatmenetnek az indoklása lehet –

  • Nincs elég időm a kód refaktorálására, Inkább elvégzek egy változtatást és befejezem a történetemet
  • Miért kockáztassam meg, hogy megváltoztassam annak a kódnak a szerkezetét, amely már régóta fut a termelésben
  • Mi az általános haszna az örökölt kód refaktorálásának

Michael Feathers ezt a változtatási stílust Edit and Pray-nek nevezi. Megtervezed és elvégzed a változtatásokat, majd amikor végeztél, imádkozol és még jobban imádkozol, hogy a változtatásokat jól végezd el.

Ezzel a stílussal csak a Legacy kód növeléséhez járulhatsz hozzá.

A változtatásoknak van egy másik stílusa is, ami a Cover and Modify. Építsünk egy biztonsági hálót, végezzünk változtatásokat a rendszerben, hagyjuk, hogy a biztonsági háló visszajelzést adjon, és dolgozzunk ezeken a visszajelzéseken.

Biztonsággal feltételezhető, hogy a Cover and Modify egy módja annak, hogy az örökölt kódot kezeljük.

Kérdés> De vajon érdemes-e egyáltalán időt tölteni tesztek írásával az örökölt kódban, vagy egyáltalán gondolkodni egy örökölt kód refaktorálásán?

Kell-e egyáltalán időt fordítania arra, hogy az örökölt kód refaktorálásán gondolkodjon?

A cserkészszabály

A Bob bácsi által megfogalmazott cserkészszabály mögött álló elképzelés meglehetősen egyszerű: Hagyd a kódot tisztábban, mint ahogyan találtad! Ha hozzányúlsz egy régi kódhoz, akkor tisztítsd meg rendesen. Ne csak egy rövidített megoldást alkalmazz, ami megnehezíti a kód megértését, hanem bánj vele gondosan. Nem elég jól megírni a kódot, a kódot idővel tisztán is kell tartani.

Egy nagyon erős üzenetet kapunk, amikor a cserkészszabályt alkalmazzuk a régi kódra: “hagyd magad után a megértés nyomát, hogy mások is követhessék”, ami azt jelenti, hogy refaktoráljuk a kódot, hogy érthetőbbé tegyük. És ahhoz, hogy refaktorálhassunk, Safety Netet építünk köré.

Most, hogy megértettük, hogy nem rövidíthetünk, az egyetlen lehetőség, ami maradt számunkra, hogy írunk néhány tesztet, refaktoráljuk a kódot, és folytatjuk a fejlesztést. Kérdések>

  • Milyen teszteket írjunk?
  • Mennyit refaktoráljunk?

Milyen teszteket írjunk

Szinte minden örökölt rendszerben fontosabb, hogy mit csinál a rendszer, mint hogy mit kellene csinálnia.

Karakterizációs teszteknek nevezzük azokat a teszteket, amelyekre akkor van szükségünk, ha meg akarjuk őrizni a viselkedést. A karakterizációs teszt olyan teszt, amely egy kódrészlet tényleges viselkedését jellemzi. Nincs olyan, hogy “Nos, ezt kellene csinálnia” vagy “szerintem ezt csinálja”. A tesztek a rendszer tényleges aktuális viselkedését dokumentálják.

Karakterizációs teszt írása

A karakterizációs teszt definíció szerint a rendszer tényleges aktuális viselkedését dokumentálja, pontosan úgy, ahogyan az a termelési környezetben fut.

Írjunk egy Karakterizációs tesztet egy Ügyfél objektumra, amely szöveges nyilatkozatot generál néhány, az ügyfél által kölcsönzött filmhez.

import static com.code.legacy.movie.MovieType.CHILDREN;
import static org.junit.Assert.assertEquals;public void shouldGenerateTextStatement(){ Customer john = new Customer("John");
Movie childrenMovie = new Movie("Toy Story", CHILDREN);
int daysRented = 3;
Rental rental = new Rental(childrenMovie, daysRented); john.addRental(rental); String statement = john.generateTextStatement();
assertEquals("", statement);
}

Ez a teszt megpróbálja megérteni (vagy jellemezni) a “Szöveges nyilatkozat” generálását egy ügyfél számára egy 3 napra kölcsönzött gyermekfilm esetében. Mivel nem értjük a rendszert (legalábbis egyelőre), azt várjuk, hogy a nyilatkozat üres vagy bármilyen dummy értéket tartalmazó legyen.

Futtassuk le a tesztet, és hagyjuk, hogy megbukjon. Ha ez megtörténik, akkor megtudtuk, hogy mit csinál valójában a kód az adott feltétel alatt.

java.lang.AssertionError: 
Expected :""
Actual :Rental Record for John, Total amount owed = 12.5. You earned 4 frequent renter points.

Most, hogy ismerjük a kód viselkedését, mehetünk előre, és módosíthatjuk a tesztet.

import static com.code.legacy.movie.MovieType.CHILDREN;
import static org.junit.Assert.assertEquals;public void shouldGenerateTextStatement(){
String expectedStatement = "Rental Record for John, Total amount owed = 12.5. You earned 4 frequent renter points"; Customer john = new Customer("John");
Movie childrenMovie = new Movie("Toy Story", CHILDREN);
int daysRented = 3;
Rental rental = new Rental(childrenMovie, daysRented);
john.addRental(rental); Sting statement = john.generateTextStatement();
assertEquals(expectedStatement, statement);
}

Várjunk csak, nem most másoltuk át a kód által generált és a tesztünkbe helyezett kimenetet? Igen, pontosan ezt tettük.

Most nem hibákat keresünk. Megpróbálunk egy olyan mechanizmust beépíteni, amellyel később hibákat találhatunk, olyan hibákat, amelyek a rendszer jelenlegi viselkedésétől való eltérésként jelennek meg. Ha elfogadjuk ezt a perspektívát, másképp tekintünk a tesztekre: nincs erkölcsi tekintélyük; csak ülnek ott, és dokumentálják, hogy a rendszer valójában mit csinál. Ebben a szakaszban nagyon fontos, hogy valahol legyen ez a tudás arról, hogy a rendszer valójában mit csinál.

Kérdés> Mennyi az összes teszt, amit egy rendszer jellemzésére írunk?

Válasz> Végtelen. Életünk egy jó részét arra fordíthatnánk, hogy esetet eset után írjunk egy örökölt kód bármelyik osztályára.

Kérdés> Mikor hagyjuk abba akkor? Van rá mód, hogy megtudjuk, mely esetek fontosabbak a többinél?

Válasz> Nézzük meg a kódot, amit jellemzünk. Maga a kód adhat ötleteket arról, hogy mit csinál, és ha kérdéseink vannak, a tesztek ideálisak arra, hogy feltehessük őket. Ekkor írjunk olyan tesztet vagy teszteket, amelyek a kód elég jó részét lefedik.

Kérdés> Ez mindent lefed a kódban?

Válasz> Lehet, hogy nem. De akkor megtesszük a következő lépést. Átgondoljuk a változtatásokat, amelyeket a kódban szeretnénk végrehajtani, és megpróbáljuk kitalálni, hogy a tesztek, amelyekkel rendelkezünk, érzékelnek-e bármilyen problémát, amit okozhatunk. Ha nem, akkor újabb teszteket adunk hozzá, amíg biztosak nem leszünk benne, hogy igen.

Mennyit kell refaktorálni?

Az örökölt kódban rengeteg refaktorálnivaló van, és nem tudunk mindent refaktorálni. Ahhoz, hogy erre válaszolhassunk, vissza kell térnünk ahhoz, hogy megértsük, mi a célunk az örökölt kód refaktorálásával.

Az örökölt kódot úgy akarjuk refaktorálni, hogy tisztább maradjon, mint amilyen volt, amikor hozzánk került, és hogy mások számára is érthető legyen.

Ezzel együtt a rendszert jobbá akarjuk tenni, a feladatra összpontosítva. Nem akarunk megőrülni a refaktorálással, hogy megpróbáljuk néhány nap alatt újraírni az egész rendszert. Amit tenni akarunk, az az, hogy “refaktoráljuk azt a kódot, ami az utunkba kerül minden új változtatás megvalósításakor”. Ezt egy példával próbáljuk majd jobban megérteni a következő cikkben.

Következtetés

Articles

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.