tifyty

pure Java, what else ?

Használjunk assertion-t

A JPL_Coding_Standard_Java (google a barátod) R21 szerint a programunkban használjunk assertion-öket. Nem szoktunk. Tegye fel a kezét, aki szokott. Most az az egy hazudós meg ott hátul, tegye le a kezét, úgyse hisszük el.

Miért nem használjuk? Mert általában nem fordul bele a kódba. Ahhoz, hogy beleforduljon külön meg kell kérnünk a fordítót, és a release meg a test kód fordítása közötti különbséget nem szokták támogatni a fordítás menedzselők. Mert általában futtatás során ki van kapcsolva a végrehajtásuk. (java -ea) Persze a JUNIT teszteknél élnek az assert utasítások, de amikor magasabb szintű tesztelést végzünk, ad-hoc, esetleg selenium-mal vagy valami mással az egész alkalmazást támadjuk, akkor általában már nem.

Ezért a fenti standard (vannak benne érdekes dolgok, lesz belőle még blogbejegyzés), azt mondja, hogy érdemes egy kis saját Assert osztályt létrehozni:

public class Assert {
  public static final boolean CONTRACT = true;
  public static void preCondition(boolean b) {
    if (CONTRACT && !b) {
      // naplózzuk az eseményt, esetleg kivételt dobunk
    }
  public static void postCondition(boolean b) {
    if (CONTRACT && !b) {
      // naplózzuk az eseményt, esetleg kivételt dobunk
    }
  }
}

Ez a kód pedig emígyen használandó utána:

import static contract.Contract.*;
class MyMathClass {
  double sqrt(double x) {
    if (CONTRACT) preCondition(x >= 0);
    double result;
      ... // itt számoljuk ki a négyzetgyököt a speciális szuper új algoritmusunkkal
    result = ...;
    if (CONTRACT) postCondition(result >= 0 && Math.abs((result * result) - x) <= EPSILON);
    return result;
  }
}

Mi történik itt, mit kell észrevenni?

Ha a kódot lefordítjuk, akkor a preCondition és a postCondition metódusok meghívásra kerülnek, és teszik a dolgukat. Ha ellenben átírjuk a CONTRACT változó értékét false-ra, akkor a Java fordító valamelyik lépésben kitörli az összes olyan kódot, ami az Assert utility osztály statikus metódusait hívja. Mivel mindegyik előtt ott van az if utasítás, ezért ez dead-code-dá válik. Ilyenkor már nem akarjuk ellenőrizni azokat a feltételeket (pre és post) amelyek a tesztelés alapján amúgy mindig rendben vannak. Ezzel az éles rendszert nem lassítjuk. Ha pedig valahol véletlenül mégis bent maradt egy hívás, mert pl. a felelőtlen programozó nem írta a hívás elé az if(CONTRACT) utasítást, akkor sem történik tragédia, hiszen mivel CONTRACT értéke hamis, az ellenőrzés nem történik meg. Egyedül az Assert osztály marad benne feleslegesen a JAR-ban, ezt meg ki lehet szedetni például a yGUARD-dal.

Tetszik? Hát, ízlések, és pofonok különbözőek. Mindenesetre az ajánlás elég komoly helyről jön, még annak ellenére is, hogy a mintakód az R28 ajánlásuk ellen való, amelyik azt mondja, hogy mindig használjunk { és } zárójeleket az if után. Persze ez pont nem az a hely, ahol ez jól mutatna, és nem is az, ahol akár olvashatóságban, akár egyébben gondot okozna.

Ebből már azért érezhető, hogy nem vagyok elragadtatva a konstrukcióért. Persze működik, meg jó, meg minden, de emlékeztet a régi C programozásra, amikor nekem kellett csomó mindent megcsinálnom (pl. memória kezelés), és nem a nyelv volt értem, hanem fordítva. Nektek?

2 responses to “Használjunk assertion-t

  1. tamasrev szeptember 4, 2013 8:23 du.

    Néha-néha használok ám assert-et. Sokkal jobban mutat egy assert foo != null; mint hogy
    if (foo == null) { /*log warning */ } else { /* do the real thing*/ }
    Ehhez mondjuk meg kellett értenem, hogy miért is mire jó a fail-fast működés. A Pragmatic Programmer-ben van erre egy külön alfejezet: http://bit.ly/19j3lO0

    Szintén a Pragmatic Programmerben ajánlák, hogy hagyjuk csak bekapcsolva az assert-eket. Mégpedig azért, mert legtöbbször nem lassítják észrevehetően a rendszert. Ha meg mégis, akkor elég pont azt a részt hekkelni.

    Szóval, válaszolva a kérdésre, én inkább haszálnék assert-eket, mint ilyen C hangulatú okosságokat.

  2. Stivi szeptember 5, 2013 10:11 de.

    Az assert mindig belefordul a kódba, nem kell semmit tenni fordításkor. Futtatáskor kell megadni a JVM-nek (java, nem javac), hogy engedélyezzük-e őket vagy sem (-ea, -da, -esa, -dsa). Letiltott állapotban állítólagosan szinte nullához közeli többletterhelést jelentenek. Alapértelmezés a kikapcsolt állapot, teszt környezetben meg egyszer kell beállítani, hogy engedélyezve legyenek.

    Egyébként meg teljesen egyetértek Tamással, a fenti hekkelés nagyon csúnya, és igen könnyű elrontani. assert-eket nem lehet, a fordító ellenőrzi, hogy (szintaktikusan) helyes-e.

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

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: