tifyty

pure Java, what else ?

Havi archívumok: december 2013

Turing kegyelmet kapott

Alan Turing kegyelmet kapott. A részletekről, hogy ki volt Turing (aki ezt a blogot olvassa valószínűleg tudja) és, hogy miért ítélték el itt lehet bővebbet
olvasni. Itt most a véleményem következik ebben a témában:

Kegyelmet kapott Turing. Ez jó? Nem. Ez nem jó, csak éppen nem rossz.

Egyrészről nem kapta meg azt az elismerést, sok más munkatársával együtt, akik a Bletchley parkban dolgoztak. Ez azonban nem tragédia.

Másrészről viszont nem kegyelmet kellene posztumusz kapnia, hanem ki kellene mondania az angol igazságszolgáltatásnak, hogy emberiesség ellenes volt a homoszexuálisok kémiai kasztrálása. Arra hivatkozni, hogy az akkori törvényeknek megfelelően jártak el elég álságos, és rossz szájízt hagy maga után Nürnberg óta.

Turing nem azért kell, vagy kellett volna annak idején, hogy kegyelmet kapjon, mert egy hős volt, tehát megbocsátható volt a homoszexualitása. A hősöknek sem lehetnek ilyen “előjogai”: nem törhetnek be, ölhetnek, rabolhatnak jogszerűen büntetlenül. Tehát ha bűnös volt, nem lenne szabad kegyelmet kapnia. A homoszexualitás viszont mai felfogásunk szerint nem is bűn, nem is kellett volna, hogy elítéljék.

Nem jó tehát, hogy Turing kegyelmet kapott. A jó az lenne, ha azt mondanák ki, hogy annak ellenére, hogy akkor a homoszexualitás bűncselekmény volt, a kémiai kasztrálás embertelen eljárás, és minden ilyen ítéletet visszamenőleg hatályon kívül kellene helyezni.

Ez nem csak jó, hanem fontos is lenne. Nem Turing és a többi hasonló módon elítélt számára: nekik már mindegy, még ha néhányan élnek is. A mi számunkra, akik szeretnénk szabadon élni, és megtartani saját kezünkben azokat a döntéseket, amelyekhez semmi köze nem lehet sem államnak, sem más hatalmi szervnek. Még Angliában sem.

A mi számunkra akik olyan világban akarunk élni, ahol a körülvevő hatalom szembe tud nézni a realitásokkal. Első lépésként azzal, hogy 60 éve a hatalom, hogy mi magunk: hibáztunk. Ahol nem csak a vesztesek torkán lehet lenyomni (pl. Nürnberg) – amúgy mai erkölcsi értékrendünk szerint teljesen helyénvalóan -, hogy bár a törvények szerint cselekedtek, mégis bűnösök voltak, hanem ahol ezt az uralkodó hatalom maga magáról is ki tudja mondani.

Ezt követően pedig, amikor szembenézünk saját múltunkkal nem Turingnak, hanem az igazságszolgáltatásnak kellene kegyelmet kapnia. Bűnösök vagyunk, de megbocsátunk, és tanulunk.

Tudom, hogy ami most történt az egy lépés ebbe az irányba, és ez nem rossz.

Tervezési minta: belső építő megváltoztathatatlan objektumokhoz

A múlt héten a Javax0 blogon jelentettem meg egy kis agymenést arról, hogy jók-e egyáltalán a tervezési minták. Ezen a héten pedig ezt cikket írtam, aminek ez kb. a (félre)fordítása.

Ez a cikk egy egyszerű (vagy nem is olyan egyszerű) tervezési mintát ír le, amelyikkel módosíthatatlan (immutable) objektumokat lehet létrehozni belső építővel.

Az építő minta az, amikor egy osztály egy másik objektumot épít fel. Az eredeti szándék, hogy elválasszuk az objektum létrehozási fázisát, és a használatát. A létrehozás egyszerű esetben csak egy new Object(), de általában ennél jóval összetettebb folyamat. Sokszor az építő az építés során dönti el, hogy milyen objektumot hozzon létre, így a folyamat végén a felépített objektum akár különböző osztályok példánya is lehet. Ez jó példája az aggódások szétválasztásának (separation of concerns).

A megváltoztathatatlan objektumok, mint a nevük is mutatja nem változtathatóak miután felépítettük őket.

Az építők, és a megváltoztathatatlan objektumok a legnagyobb természetességgel illenek össze.

Mivel az építők és az épített osztályok nagyon erősen kötődnek egymáshoz, ezért általában egy csomagba szoktuk őket rakni. De miért vannak külön osztályban? Természetesen külön osztályoknak kell lenniük, különben nem válna szét az építő és az épített. De miért nem lehet az építő osztály az épített osztályon belül? Az építő az építési folyamat során gyűjti az információt arról, hogy milyen objektumot kell építenie, és amikor minden információ megvan, akkor ezeket arra használja, hogy elkészítse az épített objektumot. Ez a “használat” általában azt jelenti, hogy az értékeket bemásolja az épített objektumba. Ha az építő az épített osztály belső osztálya, akkor az információt nem kell bemásolnia, hanem rögtön az épített objektum mezőváltozóiban tárolhatja azokat az építés során. Ha ezek a mező privátak az sem baj, hiszen az építő belül van. Az építő létrehoz egy félkész objektumot, amit nem ad át senkinek, amíg el nem készül, és amikor a build() metódust meghívjuk (általában ez szokott a neve lenni, de nevezhetnénk Jakab-nak is) akkor csak a végső simításokat kell elvégeznie.

Ezt a mintát követi például a Google Guava projektje is a megváltoztathatatlan gyűjteményeknél (immutable collections). Az építők statikus belső osztályok. Ha megnézed a kódot a ImmutableList oldalon, láthatod, hogy a Builder egy belső osztály az absztrakt osztályon belül.

De nem ez az egyetlen lehetőség. Mi lenne ha megfordítanánk az egészet, és nem az építőt raknánk az épített osztályba, hanem az épített osztályt raknánk bele az építőbe? (8. utas a halál, megvan?) Csak az építő az egyetlen, amelyiknek hozzá kell férnie az épített osztály módosító metódusaihoz, mezőihez, kezelőorvosához, gyógyszerészéhez. Ha van olyan felületünk (interfész), amelyik definiálja a lekérdező metódusokat akkor annak elégnek kell lennie mindenki más számára. És ha már eljutottunk idáig, és van egy lekérdező interfészkünk, egy építőnk, és abban az interfész implementációja, az épített objektum osztálya, akkor miért nem csinálunk egy teljes matrjoschka baba sorozatot?

Legyen interfész. Legyen az építő ebben az interfészben egy belső osztály (publikus és statikus, mert ugye más nem is lehet). Legyen az interfész implementációja az építőn belül egy privát statikus belső osztály. És lőn:

public interface Knight {
    boolean saysNi();

    class Builder {
        private Implementation implementation = new Implementation();

        public Builder setState(String say) {
            implementation.say = say;
            return this;
        }

        public Implementation build() {
            Implementation knight = implementation;
            implementation = null;
            return knight;
        }

        private static class Implementation implements Knight {
            private String say;

            public boolean saysNi() {
                return say.indexOf("ni") != -1;
            }
        }
    }
}

Lefordul? De le ám! Ami talán meglepő lehet, az az, hogy az implementation.say = say működik, hiszen a say privát változó a belső osztályon belül, de ha elolvassuk a Java szabvány 6.6.1 fejezetét, akkor világossá válik a dolog (JLS1.7, section 6.6.1 Determining Accessibility). A privát változókat a top level osztályon (interfészen) belül egyenértékűen lehet látni. Mindegy, hogy azon belül alosztály, alosztályának az alosztályában vagyunk-e. Ebben nincs a Java-ban hierarchia, ha egy fájlon belül vannak (persze lehet egy fájlban több top level osztály, de ha valaki még egyszer ezzel veszi el másfél napomat, azt …) akkor látják egymást.

Az implementációhoz nem fér hozzá más, csak az építő (eltekintve a reflection, és egyéb byte kód abuzálástól, amitől most a karácsonyra való tekintettel eltekintek), és amint egyszer elkészült, többet már nem tud rajta változtatni. Az implementáció megváltoztathatatlan és garantáltan megtartja az állapotát.

Na akkor ez most pattern, vagy antipattern? Van annyira bonyolult, hogy átlagprogramozó elbaltázza, vagy szuper jó, és biztonságos (maraton)?

Boldog karácsonyt, és jövőre folytatjuk.

Szabadság

Ez nem lesz túl technikai. Egyrészt nyár van (ezt se ma írtam), és ezért azon a néhány napsütéses napon, amikor a véletlen úgy hozza, hogy éppen szombat vagy vasárnap van, inkább kimegyek a szabadba. Persze lesznek technikai cikkek is, mert ami késik az nem múlik. Szokták mondani, hogy ami késik az az órám, de ez itt Svájcban annyira nem jellemző. Itt Schaffhausen nem óra, és Winterthur nem nyugdíjbiztosító: mind a kettő város. Persze tudtam, de mégis furcsa volt látni. És furcsák egy kicsit az emberek is: mi nagyobb szabadsághoz szoktunk. Persze kérdés az, hogy mi a szabadság. Amikor a szabályok pontosan meghatározzák, hogy mit szabad, és mit nem, olyankor kisebb a szabadságunk. Amikor nincsenek szabályok, akkor nagy a szabadság. Itt nincs olyan nagy szabadság, itt majdnem mindent szabályoznak. A nagy különbség, hogy ezt a szabályozást magukénak érzik az emberek, nem érzik úgy, hogy valami külső hatalom erőltette rájuk.

Ha perl-ben programozunk, nagy a szabadság. Nagyokat is lehet bukni vele. Ha Java-ban programozunk, sokkal kisebb a szabadság. Rosszul éljük meg? Általában nem (persze van, aki igen, de ő nem is programoz Java-ban). Mi választottuk ezt a nyelvet, és élvezzük a szabályokkal járó előnyöket. Mert a szabályok nem csak arra jók, hogy betartsuk, hanem arra is, hogy mások is betartják, és ez az igazi előny. Persze az lenne a legjobb, ha a szabályokat csak másoknak kellene betartaniuk, és nekem nem, de ez nem megy. És nem csak azért, mert nem vagyunk egyedül a társadalomban (szerencsére), hanem azért sem, mert ha nem tartom be a szabályokat, akkor nem csak másokkal tolok ki, akik csak nehezen tudják majd a kódomat karbantartani, hanem magammal is, amikor fél év múlva elém kerül. Ezért kell fegyelmezettnek lenni, és betartani a sebességkorlátozást, mert nem csak a kisgyerekek halhatnak meg az úton az autód alatt, hanem te is fának mehetsz, akár egyedül is.

A szabályok egy része adott. Rétegekben, mint a hagyma, vagy mint az ogre. Minél lejjebb haladunk, annál több a szabadságunk abban, hogy mennyi szabályt alkotunk és tartunk be. Például elég kevés hatásunk van arra, hogy hat-e ránk a gravitáció. Ez általános fizikai szabály, amin a mindenható esetleg tud változtatni, és érdekes lehet azon filozofálni, hogy elképzelhető-e olyan univerzum, amelyben mások a fizikai törvények, és mégis “konzisztens” az egész, de nem tudom, hogy a szellemi felfrissülésen kívül van-e értelme. Egyébként elárulom: a válasz igen. Elképzelhető. Mert az ember sok mindent el tud képzelni. De csak ezért.

Aztán vannak olyan szabályok, mint az, hogy ha elégetjük a föld szénkészletét, akkor pont olyan lesz a légkör, mint amilyen akkor volt, mielőtt a széndioxidot elkezdték baktériumok felzabálni, és megmérgezték magukat a zoxigénnel. Ezen elvileg tudna az emberiség változtatni, de nem fog, és mivel nincs statisztikai sokaság, hogy azt mondhassuk, hogy van olyan emberiség, amelyik megteszi, van amelyik nem, ezért értelmetlen azt mondani, hogy megtehetnénk, de nem tesszük meg. Mert nincs különbség aközött, hogy megtehetnénk, meg aközött, hogy nem tehetjük meg, mert ilyen a természetünk. Mint a skorpiónak. Ezen a folyón nem jutunk keresztül.

És mehetünk tovább: vannak törvények, regionális, országos szinten, amit magunk hozunk magunknak, jó esetben. És vannak még alacsonyabb szintű szabályok, amiket kis közösségben hozunk, és végül hozunk szabályokat magunknak. Például nem veszek bérletet, és inkább rossz időben is küzdök a kerékpárral, mert ha vennék, akkor jó időben is vonatra szállnék. Ezért, ismerve magam: nincs bérlet. Persze ebben a döntésben sokat segít a bérlet ára is, ami a budapesti négyszerese, miközben a fizetés meg nem. (Azért nem kell sajnálni.) Kellemetlenek a szabályok? Amikor felfelé tekerek, és ki akar ugrani a tüdőm, meg a szívem a helyéről, akkor igen. Amikor meg kell írni a unit tesztet, meg a dokumentációt, akkor igen. De van értelme. Egy idő után már nem kell annyira küzdeni, és egyre jobban megy a unit teszt, meg a dokumentáció készítés is. És érdekes módon a unit teszt készítése visszahat a kód minőségére, amíg észrevétlenül eljutunk arra a szintre, hogy előbb írjuk a unit tesztet, mint a kódot. És nem kell küzdeni, amikor lehajolok bekötni a cipőmet, és nem kell azon gondolkoznom, hogy a harmadikra lifttel menjek-e vagy sem: nincs lelkiismeret furdalásom, mert mozgok eleget a napi 16km kerékpározással (mire gondoltál, hogy gyalog megyek fel by default?). Persze nem gond, ha gyalog kell felmenni 🙂

Mennyi szabály kell? Minél fegyelmezettebbek, és minél belátóbbak (okosabbak) az emberek a közösségben annál kevesebb kell. Csupa kiemelkedő programozóból álló csapatban, ahol nem gond, hogy a kiemelkedő képességű embereknek kiemelkedő fizetést kell általában adni ragyogó alkalmazásokat lehet készíteni JavaScript-ben, PHP-ban, Perl-ben, és után a jönnek a nagy megmondások, hogy lám lám. De nem mindenki zseni, és még kevesebb a fegyelmezett zseni. Mostani környezetemben minden kód átmegy a review-n és bizony szembe kell néznem néha magammal: több fegyelem kell(ene). Aztán persze a review fenyegetése megteremti a több fegyelmet, mert ha meg is engednék magamnak némi pongyolaságot, tudom, hogy úgyse megy át a review-n, nem kerül bele a master-be, a master halad tovább, és egyre nagyobbat fogok szívni, mire a kódot szebbre, jobbra kijavítva újra kérhetem a review-t egy git pull origin master után. Bizony így megy ez 20 év fejlesztői tapasztalattal is. Ifjú kollégáim rámpirítanak, nincsenek tekintettel a tapasztalatomra, és szólnak ha valami olyat alkotok, amit nem kellene, nem illene. Pedig a múltkor igen öregnek éreztem magam:

Arról volt szó, hogy a reguláris kifejezések a Java-ban a Perl nyelvből jönnek-e. És akkor elmondtam, hogy igen is, meg nem is, mert volt előzmény: awk, meg sed és hasonlók, és akkor ifjú kollégám megkérdezte, hogy melyik könyvben olvastam ezekről. Szóval neki ez már történelem, amiről csak könyvben lehet olvasni. Én meg ezeket használtam.

Hát így… Lehet tovább gondolkodni. Azt szeretem, ha sok a komment.