Linux az asszony gépén, avagy az eddigi legnagyobb próbatétel

Hogyan vegyünk rá valakit, hogy használjon linuxot? Egyszerű. Rakjunk fel a gépére Windows Vista-t.

Még örülni is fog neki, hisz pozitívan áll hozzá a hosszúra nyúlt XP használat után. Pedig nem ez volt a szándékom, amikor felraktam egy Vista-t a menyasszonyomnak. Eleinte még én is meg voltam elégedve vele, bár minden apró beállításhoz többszáz visszakérdezésre kellett gondolkodás nélkül “igen”-t kattintani, de egy egyszerű felhasználónak sokat jelent az a néhány képi hatás (ami mellesleg elbújhat egy beryl mellett, de annak az értelmes beállítása még gyakorlott linuxosoknak sem egyszerű feladat). Persze, ronda inkonzisztenciák vannak a felületben (ahogy azt [[http://cubussapiens.hu/node/563|Stampie cikke]] bemutatta), de ezek a laikus szem számára nem, vagy csak nehezen észrevehetőek. Az átlag felhasználó (értsd: vindóz júzer) alkalmazkodik az adott körülményekhez, mert megszokta, hogy nem lehet azokon változtatni.

Hogyan vegyünk rá valakit, hogy használjon linuxot? Egyszerű. Rakjunk fel a gépére Windows Vista-t.

Még örülni is fog neki, hisz pozitívan áll hozzá a hosszúra nyúlt XP használat után. Pedig nem ez volt a szándékom, amikor felraktam egy Vista-t a menyasszonyomnak. Eleinte még én is meg voltam elégedve vele, bár minden apró beállításhoz többszáz visszakérdezésre kellett gondolkodás nélkül “igen”-t kattintani, de egy egyszerű felhasználónak sokat jelent az a néhány képi hatás (ami mellesleg elbújhat egy beryl mellett, de annak az értelmes beállítása még gyakorlott linuxosoknak sem egyszerű feladat). Persze, ronda inkonzisztenciák vannak a felületben (ahogy azt [[http://cubussapiens.hu/node/563|Stampie cikke]] bemutatta), de ezek a laikus szem számára nem, vagy csak nehezen észrevehetőek. Az átlag felhasználó (értsd: vindóz júzer) alkalmazkodik az adott körülményekhez, mert megszokta, hogy nem lehet azokon változtatni.

Sokáig elégedett voltam vele, hiszen a célközönség (életem értelme) is az volt. A problémák idővel alakultak ki, egyre hosszabb várakozás bekapcsolás után, mire végre hozzányúlhatunk az egérhez, néha (azaz szinte mindig) az MSN Live nevű csoda egy nem túl kedves “nem válaszol” üzenettel szenderült jobb létre, amivel a kedves laikus felhasználó nem tud mit kezdeni. A felháborodása is jogos, hiszen nem az ő dolga működésre bírni a gépet, ő a gép szolgáltatásait akarja használni. Összességében a gép egyre több türelmet ígényelt a felhasználó felöl, amiből természetesen egyre kevesebb lett, és egyszer csak el is fogyott. A Vista-nak mennie kell.

A döntés viszont nehéz. Ugyanis, ha nem Vista, akkor vissza a jól megszokott, a 7 év alatt viszonylag stabillá forott XP-hez. Az XP grafikus felülete azonban már egyszerű és unalmas. Körülbelül annyira, mint 2001-ben a win98 volt. Ne felejtsük el, hogy ez nagyon fontos annak, akinek a számítógép egy fekete doboz (nem rendelkezik logikai modellel a gép belső működéséről). Az egyszerű felhasználó számára a “felhasználói élményt” jelentős részben a látvány határozza meg. Alternatívaként megjelenik még a linux. A félelmetes, ismeretlen linux, ami csak eldugott, ember számára ritkán látott szervereken fut. És persze az én gépemen. A KDE4.1 RC1 felület asztali elemei pedig nagyon látványossá teszik a mindennapi munkát. A fent említett leányzó néhány esetben (bár csak kényszerből) használta a gépemet, így látta, hogy mégsem különbözik annyira a linux a windowstól, mint gondolta. Talán megér egy próbát.

Ahhoz nem volt merszem, hogy fejlesztés alatt álló KDE4-el átkozzam meg, hiszen a felállítandó rendszer legfontosabb követelménye a stabilitás. Így maradt az általam jól ismert Kubuntu KDE3-al, majd ha KDE4 stabilitása a megítélésem szerint eléri a megfelelő szintet, egy kattintással fel tudom neki rakni. Linuxra jellemző, hogy ha egy hardvert azonnal felismer, akkor az tökéletesen működik, de ha bármi probléma van vele, csak rengeteg szenvedés árán, vagy egyáltalán nem lehet értelmes működésre bírni (persze kis idő, és néhány kernel-verzió lépés megoldja). De szerencsém volt, a live CD környezet futtatásával meggyőződtem róla, hogy minden egyes hardverelemet megfelelően kezel a rendszer. A telepítés lefuttatása után leültettem a leendő felhasználót az új szerzemény elé, hogy a segítségemmel megismerkedjen vele. Az első mozdulatok pozitívak voltak, a felület testreszabhatósága valósággal elvarázsolta, négy asztalt hozott létre, mindegyiket más háttérrel, hogy az mindig tükrözze a hangulatát. A “programok telepítése/törlése..” funkció is mosolyt váltott ki, a programok ilyen egyszerű kezelése is kedvére valónak bizonyult. Általában véve a kezdeti félelmeit azonnal elsöpörték a KDE szolgáltatásai.

Az élet persze nem fenékig tejfel, a telepítés után derült ki, hogy a hangkártya mixere nem megy tökéletesen. Ez annyiban nyílvánúl meg, hogy a kmix egyáltalán nem használható, bár a hang megy, a hangerőt csak minden egyes alkalmazásban külön lehet állítgatni, nincs erre globális funkció. Ez volt a kisebbik gond. A nagyobbik az volt, hogy egy kritikus pillanatban a rendszer gondolt egyet, és lefagyott. A kép kimerevedett, és a CAPS-lock LED egyenletes villogása jelezte, hogy a Kernel eltávozott az örök vadászmezőkre. Érezhető volt a csalódottság, és a kétségbeesés a levegőben, ami fokozódott ahogy az eset újra és újra megismétlődött. A rendszer teljesen váratlanul és indeterminisztikusan lefagyott. A dolog érdekessége, hogy a fagyás gyakorisága megritkult azáltal, hogy kilőttem az ALSA hangrendszert (gondolván arra, hogy a fagyás oka az egyetlen hibásan működő hardverelem lehet csak).

A megoldás egy nappal később jött, amikor észrevettem, hogy egy lefagyás után a rendszeróra nullázódott. A gyanút beigazolta, hogy egy másik fagyás utáni induláskor a gép egy pittyegés után kiírta, hogy a CMOS akkumlátor bizony lemerült. Csavarhúzó, aksi ki, boltba el, új aksi be, csavarhúzó, és láss csodát, azóta nem fagy le (lekopogtam). Elképesztő mekkora galibát tud okozni egy ekkora kis bigyó. Persze vannak a gépben sokkal kisebb dolgok is, amik drágább hibát okozhatnak.

Mindenesetre most működik. A menyasszonyom pedig elégedett. Könnyedén, boldogan használja a rendszert, ami reményeink szerint a stabilitását is bizonyítani fogja a továbbiakban.

Európa-fogyatkozás

Elég hamar kicseréltem az Eclipse 3.3 Europa integrált fejlesztői környezetemet az új verzióra. Hamarabb, mint eredetileg terveztem. Ennek annyi volt az oka, hogy letöltöttem az M6-os release-üket kipróbálásra, és amikor meghalt a rendes fejlesztői környezetem (volt 900 MB telepítve, rendes kis pluginkönyvtár :p ), úgy döntöttem, megspórolom az egész újratöltését, és inkább berakom a Ganymede-be a cuccokat.

Nem mondom, akkor még korai volt egy kicsit (de csak egy kicsit), nem volt (sokkal) nagyobb szívás ott újra összerakni a munkakörnyezetet, mint az Europa-ban lett volna. Mostanra meg már, hogy van végleges 3.4-es változat, nem mennék vissza.

Elég hamar kicseréltem az Eclipse 3.3 Europa integrált fejlesztői környezetemet az új verzióra. Hamarabb, mint eredetileg terveztem. Ennek annyi volt az oka, hogy letöltöttem az M6-os release-üket kipróbálásra, és amikor meghalt a rendes fejlesztői környezetem (volt 900 MB telepítve, rendes kis pluginkönyvtár :p ), úgy döntöttem, megspórolom az egész újratöltését, és inkább berakom a Ganymede-be a cuccokat.

Nem mondom, akkor még korai volt egy kicsit (de csak egy kicsit), nem volt (sokkal) nagyobb szívás ott újra összerakni a munkakörnyezetet, mint az Europa-ban lett volna. Mostanra meg már, hogy van végleges 3.4-es változat, nem mennék vissza.

Ami a leghasznosabb újdonság számomra, az a megújult csomagkezelő. Egyrészt az az előnye, hogy nem kell előre eldönteni, hogy én most új csomagot akarok telepíteni, vagy a meglevő csomagokon akarok valamit módosítani (korábban idegesítő volt, amikor a rossz menüpontra kattintottam, és egy percig várhattam, amíg megnézte, hogy mit lehet csinálni), ugyanis két almenüpont helyett egy közös dialógusablakból lehet változtatni két fül között – ezek a fülek tartalmazzák a korábbi funkcionalitást. Legalábbis nagyrészt.

Ami úgy tűnik számomra, hogy hiányzik, az a korábbi változatban Select required nevű gomb a telepítendő csomagok választásánál. Lehet, hogy már nincs rá szükség, mert automatikusan bejelöli (nem vagyok benne egészen biztos, ezért ezt nem merem elítélni). Amiben biztosabb vagyok, az a csomagok eltávolítása. Ezt még egyáltalán nem sikerült az új verzióban véghezvinni.

Ami viszont roppant hasznos új funkcionalitás, az a dropin mappa koncepciója. Ez egy kijelölt mappa, amibe ha bedobunk letöltött csomagokat, akkor azokat a csomagkezelő látja, és a függőségeivel együtt telepíthetőek. Ez nagyon hasznos lehet akkor, ha valami olyan projektet akarunk telepíteni, ami valami miatt nem szerepel az Eclipse csomagkezelőben.

Egy másik apró változás, amivel találkoztam, az az Eclipse pluginek (illetve RAP programok) fejlesztésekor jött elő: bizonyos fájlokat megnyitva az Eclipse nem jön rá, hogy én egy megadott futtatási konfigurációval akarom futtatni egy automatikus futtatás parancs kiadásakor, hanem kézzel kell megjelölni. Az Europaban erre nem találtam alternatív megoldást, de a Ganymede sokkal kevésbé idegesítő. A problémát ugyen nem oldották meg, de legalább megkerülték: első futtatáskor lehet, hogy ki kell választanom a futtatási konfigurációt, de utána megjegyzi, és nyugodtan futtatja úgy is.

Az Eclipse 3.4 lesz Ubuntuhoz is – az Europa nem volt, mert valami ütközött az SWT-ben és az Ubuntuban, és ezt csak az új verzióra javították ki; ezért is van az, hogy még az LTS kiadásban is csak a két éves 3.2 (Callisto) került be. Nem tudom, hogy végül is kijavították-e, mert per pillanat nincs lehetőségem ezt ellenőrizni, de valamikor majd ezt is meg lehet tenni. Ez a probléma egyébként akkor merült fel, amikor Balage a leírásom alapján telepíteni próbálta az [[PHP debug Eclipse PDT-ben|Eclipse PDT-t debuggerrel]].

Apropó PHP debugger: a PDT projekt nincs szinkronizálva az Eclipse kiadásokkal, ebből még nincs hivatalosan kiadott verzió (sem pedig update site). De a dropin megoldás segítségével könnyen telepíthető a rendszerbe, és utána minden gond nélkül megy. A php debugger is szépen megy.

Viszont még egy negatívumról is írnék: az SWT widget-készlet még mindig Carbon-alapú OSX alatt, ami nem jó hír. Java 6-tal nem megy, mert az OSX-en kötelezően 64 bites, míg a Carbon 32. De szerencsére már elkezdődött a Cocoa-alapú változat fejlesztése, ha minden jól megy, a következő kiadásba már be is kerülhet. Ha ez tényleg így lesz, akkor lehet, hogy megint kiadás előtt fogok váltani. De ez majd kiderül. 🙂

Szóval egy hasznos új változatról van szó, nagyon forradalmi változás nincs benne, de megfelelő továbbfejlesztése a népszerű IDE-nek. Úgy gondolom, tele lehet még az előzőekhez hasonló apró változtatásokkal, de ezek felismeréséhez nem használtam eleget a korábbi változatokat, ezért nem kívánok most róla írni. Majd esetleg máskor. Mindenesetre bárki számára javaslom a verziófrissítést, ha nincs túlságosan előrehaladott állapotban egy projektjében, mert akkor kellemetlen lehet a váltás. De érdemesnek érdemes szerintem, nem sok helyen van inkompatibilitás a következő verziókkal. Az egyedüli gond az lehet, ha valami szükséges plugin nem érhető el az új változatban.

De ha valakinek nincs valami nagyon különleges igénye, akkor nyugodtan lehet frissíteni, szépen megy az új Ganymede is.

Java osztályok tárolása MySQL adatbázisban

A cím talán megtévesztő lehet, most nem arról van szó, hogy hogyan lehet szérializált osztálypéldányokat tárolni adatbázisban. Ehelyett magukat a Java osztályokat (típusokat) tárolom ilyen módon. Ez megtehető, hiszen a Java futásidőben tölti be az osztályokat, egészen pontosan az osztály első aktív használata elött. A továbbiakban a cikk feltételezi a Java és a MySQL alapszintű ismeretét, és a [[http://java.sun.com/javase/technologies/database/|JDBC]] használatát se fogom részletezni. Kezdetnek essen pár szó a Java osztálybetöltő mechanizmusáról.

A cím talán megtévesztő lehet, most nem arról van szó, hogy hogyan lehet szérializált osztálypéldányokat tárolni adatbázisban. Ehelyett magukat a Java osztályokat (típusokat) tárolom ilyen módon. Ez megtehető, hiszen a Java futásidőben tölti be az osztályokat, egészen pontosan az osztály első aktív használata elött. A továbbiakban a cikk feltételezi a Java és a MySQL alapszintű ismeretét, és a [[http://java.sun.com/javase/technologies/database/|JDBC]] használatát se fogom részletezni. Kezdetnek essen pár szó a Java osztálybetöltő mechanizmusáról.

A Java ClassLoader osztály használható arra, hogy egy keresett osztályt betöltsön a memóriába. Minden JVM indulásakor létrejön egy alapértelmezett rendszer ClassLoader, és ha nem teszünk semmit ez marad végig az egyetlen ilyen jellegű objektum a JVM-ben. A ClassLoader-ek működésének megértéséhez meg kell ismernünk néhány metódusát:

  • A konstruktor: ClassLoader(ClassLoader parent) : Minden ClassLoader-nek létezik pontosan egy szűlője (kivéve az alapértelmezett ClassLoader-t), ugyanis mielött az adott ClassLoader megpróbálná betölteni a keresett osztályt, megkérdezi a szülőt, hogy ő be tudja-e tölteni, és csak akkor próbálkozik meg, ha a még nincs betöltve, és a szülő sem tudja betölteni.
  • Class loadClass(String name) :ez hívódik meg, amikor felmerül az igény egy osztály betöltésére. Ez a metódus elöször meghívja a szülő ClassLoader hasonló metódusát, és ha az ClassNotFoundException-t dob, akkor meghívja ezen osztály findClass metódusát.
  • Class findClass(String name) :a fentiekből látszik, hogy ez a metódus hívódik meg akkor, ha már ránk hárult az osztály betöltésének a feladata. Ha új ClassLoader-t írunk, rendszerint ezt a függvényt akarjuk felülírni.
  • Class defineClass(String name, byte[] b, int off, int len) :ez a lényeg. Ez a függvény hozza létre az osztályt a memóriában a beolvasott bytecode-ból, aminek meg kell egyeznie egy “.class” fájl tartalmával.

Már látszik a turpisság: a fentiek alapján lehet írni egy ClassLoader-t, ami nem fájlból, hanem adatbázisból olvassa be a megfelelő bytesorozatot. Első lépésként írjuk meg az adatbázis réteget, ami a kérdéses bytecode-ot tudja menteni/kiolvasni az adatbázisból (az adatbázisba a bytecode-ot Base64 kódolásban mentem, amit egy segédosztály végez. Lásd: lent. Ugyanúgy nem térek ki a File beolvasására, annak a megoldásában is a Google segített):


package mysqlclasses;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class ClassSaver {

public static byte[] getBytesFromFile(File file) throws IOException {
.....
}

public static void saveToDB(Connection con, String name, byte[] data){
try{
Statement s = con.createStatement();
s.execute("CREATE TABLE IF NOT EXISTS classes (name VARCHAR(120) NOT NULL,bytecode TEXT)");

String bytecode = new String(Base64Coder.encode(data));

ResultSet rs = s.executeQuery("SELECT * FROM classes WHERE name = '"+name+"'");
if (rs.next()){
//update
s.execute("UPDATE classes SET bytecode = '"+bytecode+"' WHERE name = '"+name+"'");
}else{
//insert
s.execute("INSERT INTO classes SET name = '"+name+"', bytecode = '"+bytecode+"'");
}
}catch(Exception e){
System.err.println(e.getMessage());
}
}

public static byte[] loadFromDB(Connection con, String name){
try{
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT * FROM classes WHERE name = '"+name+"'");
if (rs.next()){
return Base64Coder.decode(rs.getString("bytecode"));
}else{
return null;
}
}catch(Exception e){
System.err.println(e.getMessage());
return null;
}

}
}

Ezek után következzék a MySQLClassLoader:


package mysqlclasses;

import java.sql.Connection;

/**
* @author balage
*
*/
public class MySQLClassLoader extends ClassLoader {

Connection con;

public MySQLClassLoader(Connection sqlcon) {
con = sqlcon;
}

public MySQLClassLoader(Connection sqlcon,ClassLoader arg0) {
super(arg0);
con = sqlcon;
}

@Override
protected Class< ?> findClass(String name) throws ClassNotFoundException{
System.out.println("Searching for class: "+name);
byte[] data = ClassSaver.loadFromDB(con, name);
if (data != null){
return defineClass(name, data, 0, data.length);
}else{
throw new ClassNotFoundException();
}
}

}

Meglepően egyszerű, nemde? A kipróbálásához létrhozunk pár egyszerű osztályt:

package test;

public interface Test {
public void some();
}


package test;

public class TestA implements Test {

@Override
public void some() {
System.out.println("I'm an A instance.");
}

}


package test;

public class TestB implements Test {

@Override
public void some() {
System.out.println("I'm a B instance.");
}

}

Az egyszerűbb tesztelés érdekében hoztam létre egy Interface-t is, ami fordítás időben ismert, így egyszerűen meghívható a some() metódus. A létrehozott osztályokkat most le kell fordítani, és be lehet írni az adatbázisba:


Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "balage", "");

Test a = new TestA();
a.some();
Test b = new TestB();
b.some();

ClassSaver.saveToDB(con, a.getClass().getName(), ClassSaver.getBytesFromFile(new File("bin/test/TestA.class")));
ClassSaver.saveToDB(con, b.getClass().getName(), ClassSaver.getBytesFromFile(new File("bin/test/TestB.class")));

Ezen a ponton érdemes ellenőrizni az adatbázis tartalmát, ahol jól láthatóan szerepel egy “classes” tábla, benne a két osztály bytecode-jával. Ezek után lehet kiovasni onnan őket a következő kóddal (Arra vigyázzunk, hogy a kiolvasandó osztályok NE legyenek elérhetőek a classpath-ban, különben az adatbázis helyett az alapértelmezett ClassLoader fogja őket betölteni!):


Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "balage", "");
MySQLClassLoader loader = new MySQLClassLoader(con);

Class< ?> clsa = loader.loadClass("test.TestA");
Test a = (Test)clsa.newInstance();

a.some();

Ha mindent jól csinálunk, a kimeneten a TestA osztály üdvözlőüzenete elött látni fogjuk a MySQLClassLoader-ben elrejtett kiírást is, ami egyértelműen jelzi, hogy valóban ő olvasta be az osztályt. Siker. Mielött még kikiáltanám a cikk végét, had tegyek pár megjegyzést, ami szükséges lehet a módszer komolyabb használatához:

Jól láthatóan szövegként hivatkozunk a betölteni kívánt test.TestA osztályra. Ekkor felmerül a kérdés, mi van azokkal az osztályokkal, amikre a betöltött test.TestA osztály hivatkozik? Például létrehoz egy test.TestB osztályt, ami ugyancsak az adatbázisból érhető el, és nem szerepel a megadott classpath-ban. A válasz egyszerű. Azokat akkor próbálja betölteni, amikor aktívan használni próbáljuk. Akkor az osztály nevét átadja az alapértelmezett ClassLoader-nek, ami megkeresi a classpath-ban és.. ClassNotFoundException. A probléma ott van, hogy arra már nem a mi MySQLClassLoader-ünket használja. A teendő tehát: alapértelmezetté kell tenni a létrehozott MySQLClassLoader-t, amit megtehetünk az aktuális Thread ismeretében:


MySQLClassLoader loader = new MySQLClassLoader(con);
Thread.currentThread().setContextClassLoader(loader);

Ezen sor után a futásidőben felmerült osztályhivatkozásokat már az általunk megadott ClassLoader-rel fogja betölteni. Kiemelném, hogy ekkor is létezik a MySQLClassLoader szűlője, ami prioritást élvez, azaz mindig az próbálja meg betölteni a keresett osztályt elsőként (persze csak akkor, ha nincs még betöltve).

Még egy probléma: az általunk létrehozot ClassLoader-t csak futásidőben tudjuk használni, a javac fordításkor csak a beépített ClassLoader-t tudja használni, azaz fordításkor minden hivatkozott osztálynak kéznél kell lennie, csak fordítás után lehet az egyes osztályokat bepakolni az adatbázisba. Ami után viszont az adatbázisból hivatkozott .class fájlok törölhetőek a classpath-ból. A programunkat indító osztálynak, és a MySQLClassLoader-nek viszont minden esetben elérhetőnek kell lennie a classpath-ban, ugyanis a java indulásakor csak az alapértelmezett ClassLoader áll rendelkezésünkre.

Végezetül pár hasznos link:

  • [[http://java.sun.com/docs/books/tutorial/ext/basics/load.html]] Egy részletesebb leírás a Java ClassLoader-ek működéséről
  • [[http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Class.html]] A Class metaosztály javadoc-ja
  • [[http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html]] A ClassLoader osztály javadoc-ja
  • [[http://www.source-code.biz/snippets/java/2.htm]] A Base64 kódolást végző osztály
  • [[http://www.java-tips.org/java-se-tips/java.io/reading-a-file-into-a-byte-array.html]] Egy függvény, ami egy fájlból beolvassa a byte-okat tömbbe

Felhasználói felületek és a programozás

Ennek az írásnak az ötlete már jó ideje motoszkál bennem. Mindig is érdekelt a programozás – magas szinten. Azaz érdekelt, hogyan lehet nagy rendszereket tervezni, érdekelt, hogy ezek a rendszerek hogyan használhatóak az egyszerű felhasználó szemében. Érdekelt, hogyan lehet megcsinálni, de valahogy sosem csináltam meg. Egyszer ki kéne próbálni, de erre a közeljövőben ismételten nem lesz időm.

Ez persze nem akadályozott meg abban, hogy utánaolvasgassak a témának. Illetve azon oldalak ajánlásait kövessem, akikre már amúgy is feliratkoztam. 🙂 Így találtam rá az Ars Technica cikksorozatára, ami a fejlesztési eszközöket, nyelveket, APIkat veszi górcső alá. Korábban már volt szerencsém az Ars Technicahoz, ők képesek voltak korábban például a Leopardot tizenegynéhány oldalban elemezni, elvárásokkal, hiányokkal és hasonló dolgokkal. Szerintem tanulságos volt, ezért érdemesnek láttam a cikksorozatba is belekóstolni.

Ennek az írásnak az ötlete már jó ideje motoszkál bennem. Mindig is érdekelt a programozás – magas szinten. Azaz érdekelt, hogyan lehet nagy rendszereket tervezni, érdekelt, hogy ezek a rendszerek hogyan használhatóak az egyszerű felhasználó szemében. Érdekelt, hogyan lehet megcsinálni, de valahogy sosem csináltam meg. Egyszer ki kéne próbálni, de erre a közeljövőben ismételten nem lesz időm.

Ez persze nem akadályozott meg abban, hogy utánaolvasgassak a témának. Illetve azon oldalak ajánlásait kövessem, akikre már amúgy is feliratkoztam. 🙂 Így találtam rá az Ars Technica cikksorozatára, ami a fejlesztési eszközöket, nyelveket, APIkat veszi górcső alá. Korábban már volt szerencsém az Ars Technicahoz, ők képesek voltak korábban például a Leopardot tizenegynéhány oldalban elemezni, elvárásokkal, hiányokkal és hasonló dolgokkal. Szerintem tanulságos volt, ezért érdemesnek láttam a cikksorozatba is belekóstolni.

Az írás alapvető példája, mint mondtam, az volt, hogy összevesse a lehetőségeket. Előrebocsátom, hogy az ő írásuk is (az enyém meg pláne) az Apple megoldását preferálja a Microsoftéval szemben, ezért aki ebből flamet csinálna, az inkább most hagyja abba. Annak semmi értelme sincs (mondom ezt én 🙂 ).

Na, ideje belevágni a témába. A vonatkozott cikksorozat engem leginkább egy vonatkozásban fogott meg: a második részben feszegette azt, hogy a Microsoft APIk mennyire nem kifinomultak – valószínűleg ez lehet az oka, hogy szerte a cégen belül is a “kerék újra feltalálása” a divat. Ezt talán a mellékelt kép is szemlélteti (a kép eredeti változata a http://arstechnica.com/articles/culture/microsoft-learn-from-apple-II.media/vista.png címen érhető el).

A Microsoft konzisztensnek nem nevezhető kínálata felhasználói felület témában

A helyzet rossz. Nagyon. A képen szereplő ablakok a Visual Studio 2005 kivételével az aktuálisan elérhető legfrissebb változatok. Érdemes megfigyelni, hogy vannak alkalmazások menüvel és menü nélkül (utóbbi esetben szalaggal vagy rejtett menüvel). További érdekesség, hogy az Office család szereplő tagjainál alapvető eltérések vannak szerkezetben (szalag nézet a Wordben, hagyományos nézet a Visioban, és az Outlook mindig is egyedi volt). Másik érdekesség az előre-hátra nyilak az Intézőben, az Internet Exporerben és a Windows Media Playerben. Pontosabban a mellette levő lefele nyíl, ami a listát jelenítené meg: minő véletlen, ebből is van háromféle változat.

Biztos, hogy van még különbség, de ezek felderítését az unatkozó olvasókra bízom. 🙂

Azzal semmi bajom sincs, hogy a Vistában a felület máshogy néz ki, mint korábban. Lehet vitatkozni rajta, hogy jobb lett vagy rosszabb, mint a korábbi, én nem teszem meg, mert csak képernyőképeken láttam a rendszert. De ez így katasztrófa. Az Ars Technica sorozatában még mondott egy érdekes példát: a Vista kezdeti változatában azért voltak gondok a hangkártyadriverekkel, mert a Microsoft a fejlesztés végső szakaszában módosította a hangrendszert. Az ok: leültek multimédiában érintett emberekkel, és azok jelezték, hogy a lejátszóprogramok feleslegesen terhelik a gépet, ha pollozzák a hangbuffer állapotát, jobb lenne, ha az értesítené őket, hogy fogyóban az adat. Felmerül a kérdés: ez miért nem került a cég multimédiás programjának, a Windows Media Player fejlesztésekor? Például mert nem használja a saját APIt?

Ezzel szemben OSX-en az Apple szinte minden programja (nem állítom, hogy minden, mert azért az sem lenne igaz) egy közös megjelenítési APIt használ, és ez az API elérhető a fejlesztők számára is. Ezen felül elérhető még [[http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/|Apple Human Interface Guidelines]] című dokumentum is, ami egyfajta szakácskönyvet ad a fejlesztők kezébe, hogy az Apple milyen elvek szerint építi fel a programjait (többé-kevésbé). Eredmény: ha jön egy programozó, aki OSXre szeretne szoftvert írni, megnézi ezt a dokumentációt, és ez alapján tervezi meg a felhasználói felületet, és a beépített APIt felhasználva valósítja meg. Következmény: a 3rd party programok is hasonlóak lesznek a beépítettekhez. Ez a Microsoftos káosznál elérhetetlen állapot…

Persze a dolog messze nem ilyen egyértelmű: a http://www.neopoleon.com/home/blogs/neo/archive/2008/03/17/29941.aspx oldalon például a szerző azt részletezi, hogy miért nem szereti az OSX APIjait. Ez érthető is. Ahogy az Ars Technicas cikk harmadik részében szerepel, az Apple által erőltetett Objective-C nyelv alapvetően különbözik a megszokott objektum-orientált nyelvektől, csak OSX-en lehet használni, az XCode nevű program semmi különöset nem nyújt egy Visual Studiohoz képest, sőt, az extrák tekintetében le is van maradva. Szintén ebben a cikkben szerepel, hogy OSX-en meg hiányolja a .NET bizonyos részeit vagy éppen az Office 2007-et. Más szóval a helyzet messze nem egyértelmű, érdemes a továbbiakban is figyelni a témát, milyen változások lesznek.

Frissítés: Az Ars Technica cikksorozatára való hivatkozásokat pótolom.

  • [[http://arstechnica.com/articles/culture/what-microsoft-could-learn-from-apple.ars|Áttekintés, történelem]]
  • [[http://arstechnica.com/articles/culture/microsoft-learn-from-apple-II.ars|A Microsoft megoldásainak összegzése]]
  • [[http://arstechnica.com/articles/culture/microsoft-learn-from-apple-III.ars|Az Apple APIk ismertetése]]

Lonely HDR, azaz HDR kép készítése egyetlen képből

Sok mindenre képes az ember, ha van egy kis ideje. Például elgondolkodhat, hogyan tudná a rengeteg közepesen jól sikerült fényképét egyszerűen feltúrbózni, amit már szívesebben mutogat bárkinek. Kis gyakorlással csodát lehet művelni Photoshop (vagy a nyílt forráskód híveinek – küztük nekem – Gimp) segítségével, azonban ez néhány ezer kép nagyságrendnél kicsit idő- és munkaigényes. Fontos tehát, hogy mindezt automatikusan tudjuk csinálni. Már csak egy jó ötlet hiányzik. Ezen segít ha kicsit ránézünk a HDR technológiára.

High Dynamic Range imaging, avagy mi is ez? – dióhéjban

Sok mindenre képes az ember, ha van egy kis ideje. Például elgondolkodhat, hogyan tudná a rengeteg közepesen jól sikerült fényképét egyszerűen feltúrbózni, amit már szívesebben mutogat bárkinek. Kis gyakorlással csodát lehet művelni Photoshop (vagy a nyílt forráskód híveinek – küztük nekem – Gimp) segítségével, azonban ez néhány ezer kép nagyságrendnél kicsit idő- és munkaigényes. Fontos tehát, hogy mindezt automatikusan tudjuk csinálni. Már csak egy jó ötlet hiányzik. Ezen segít ha kicsit ránézünk a HDR technológiára.

High Dynamic Range imaging, avagy mi is ez? – dióhéjban

Kicsit bővebb leíráshoz: http://en.wikipedia.org/wiki/High_dynamic_range_imaging

A HDR célja általában olyan képek létrehozása, amelynek minden része teljes részletességgel látszik, attól függetlenül, hogy az sötét-e vagy világos. Ami azért nehéz, mert ha a világos részt kiemelve rövid ideig exponál a gép, a sötét részek nem fognak látszódni, míg túlexponált képpel előhozhatóak a sötét részletek, de a világos rész lesz kivehetetlen. A HDR alapötlete az, hogy egyetlen kép helyett csináljunk többet, különböző exponálással. Ezen képek alapján aztán összerakható olyan kép, amelynek minden részlete a megfelelő exponálással készült.

HDR-hez több kép kell, de nekünk csak egy van?

Nyílván egyetlen képből nem nyerhető annyi információ, mint akár három különbözőből, azonban nem is ezt akaruk elérni. A cél csupán az, hogy a rendelkezésre álló képből hozzuk ki a lehető legtöbbet, és ehhez használjuk fel a HDR-nél is használt technikát. A módszer nem más, mint a képet visonylag apró szegmensekre bontjuk, és minden szegmensre kiválasztjuk a rendelkezésre álló variánsok közül a legjobbat. A HDR esetén fizikailag van több képünk, ebben az esetben ugyanazt a képet világosítjuk/sötétítjük néhányszor. A világosság változtatásával ugyan nem nyerünk információt, a kép hatását a nézőre azonban jelentősen befolyásolhatjuk. Így tehát minden szegmensre kiválasztjuk az optimálisat, elsimítjuk az illesztéseket, végül kicsit megnöveljük a színtelítettséget, hogy tényleg szép legyen.

A fenti ötlet alapján készült egy kis java program, ami mély elmélkedés árán egész szép eredményt ér el a bemeneti képpel. Letöltés után valami ilyesmit kell beírni egy parancssorba:


java -jar lonelyhdr.jar input.jpg output.jpg

Rövid várakozás után egy kicsinosítgatott kép kacsint vissza ránk:

input.jpg output

Letöltés: lonelyhdr.jar

Fontos megjegyzés: a program értelmes eredményt csak megfelelő méretű (értsd: mai átlagos fényképezőgép által készített) képpel tud elérni. A fenti kép például egy 5 megapixeles szappantartóal készült, és a képet eredeti méretében (2592 x 1944 pixel) eresztettem át a programon.