Proč vlastně hlasovat?

// demokratismus
while (!vysledekHlasovani)
{
   vysledekHlasovani = demokratickyParlament->hlasuj(zakon);
}
demokratickyParlament->uvedVPlatnost(zakon);
Jako programátor ihned vidím optimalizaci, kterou můžeme ve výše uvedeném kódu provést (kód bude přehlednější a výsledek stejný, a navíc rychleji):
// skutečná, ničím nemaskovaná totalita
totalitniParlament->uvedVPlatnost(zakon);
PS: Kontext.

PHP: PDF tabulky pomocí mPDF

Zvykl jsem si v PHP aplikacích používat knihovnu mPDF. Umí vytvářet PDF soubory z HTML šablon, takže člověk nemusí ručně kreslit každou čáru, řešit zalamování textu apod.

Tato velká výhoda je pochopitelně doprovázena i růnými nevýhodami: mPDF je docela moloch a navíc náročný na RAM. Některé části knihovny se sice dají vyházet, ne všechny problémy to však řeší.

Nyní jsem řešil problém v aplikaci, kdy zákazník potřebuje tisknout několikastránkové tabulkové přehledy v PDF. Server měl limit RAM použité na PHP skript (memory_limit) původně 32 MB, posléze 64 MB a i to už v některých případech nestačilo. S řešením požádat hosting o další navýšení jsem se nechtěl spokojit, proto jsem začal hledat možnosti optimalizace. Upgradoval jsem mPDF ze staré verze 4.něco na nejnovější 5.2. Z hlediska RAM to však nepomohlo, spíš naopak. Generovaná PDF se však zmenšila na zhruba třetinu původní velikosti, což je fajn.

Dle dostupných rad, jsem měl zapnuté nastavení mPDF->packTableData. Generování desetistránkové tabulky s okraji kolem elementů <td> zabralo 128 MB RAM. Okraje patrně žerou paměti fakt hodně, jejich vypnutí v CSS mělo za následek pokles potřebné RAM na 44 MB (!).

Experimentoval jsem dál – vypnutí nastavení mPDF->packTableData paradoxně spotřebu RAM snížilo na 21 MB (ač by dle dokumentace mělo způsobit opak – dalo by se tedy říci, že s tímto nastavením je mPDF sice pomalejší, ale zato zabere víc paměti).

Samozřejmě netvrdím, že vypnutí mPDF->packTableData vždy pomůže (u okrajů si tím skoro jist jsem) – pro konkrétní situaci tedy doporučuji zjistit velikost využité RAM pomocí XdebugFunction Traces.

Reklama pro prohlížeče zadarmo

Logika dostává v našem světě na frak snad každý den, ale pořád mě to nepřestává udivovat. Připadá tohle naprosto neuvěřitelné jen mně?

Microsoft musí z vůle EU nabízet uživatelům instalaci alternativních internetových prohlížečů. EU patrně opět považuje uživatele za naprosté idioty, kteří si neumí sami najít a stáhnout produkt, který by jim vyhovoval. A idioty je potřeba co? No podporovat…

Ale proč jen prohlížeče? Proč si obdobná nařízení nevymohli i tvůrci alternativních kalkulaček, malovátek, přehrávačů, nebo třeba souborových systémů a vrstvy abstrakce HW? Jsem zvědavý, kdy přijdu do Tesca a to mi bude muset nabídnout, jestli nechci zavézt do koloniálu Františka Vopičky na nákup.

A vůbec, proč by MS neměl mít právo dát do svého produktu, co uzná za vhodné? O jakém zneužívání monopolního postavení může být řeč? Monopol by to byl, pokud byste chtěli používat počítač a neobešli se bez produktů Microsoftu. Tak to ale vůbec není (ostatně, skutečné monopoly existují jen na základě státních regulací).

Microsoft maximálně tak využívá postavení, které si za ta léta sám vybudoval. Jakýkoliv konkurent měl možnost vyvinout produkt svůj a být s ním úspěšnější.

Chápu ale, že pro autory prohlížečů (obzvlášť těch, které dosud v podstatě nikdo neznal) musí být reklama zdarma v cizím produktu (který si dokázal najít miliony a miliony uživatelů) naprosto úžasná. Ale ještě se dokážou pohádat, na jakém místě by jejich prohlížeč měl být zobrazen.

Jenže jak k tomu přijdou ti vývojáři kalkulaček? Těm zadarmo nikdo nic nedá (a je to tak správně).

Pár hintů pro programátory začínající s Windows x64

Nedávno jsem adaptoval instalátor jedné aplikace, aby běžel bez problémů i na 64bitových Windows a zde se podělím o pár poznatků.

Nejprve jsem potřeboval zjistit, zda je moje aplikace zrovna spuštěna na systému 32bitovém nebo 64bitovém. Nápady s kontrolou velikosti číselných datových typů je třeba zavrhnout, ta by se totiž určila natvrdo již během kompilace a ne až při spuštění aplikace.

Architektura procesoru je uložená v proměnné prostředí Windows s názvem PROCESSOR_ARCHITECTURE, kde najdete buď „x86″ nebo něco jako „AMD64″ (i na Intel procesorech). Má to ale jeden háček – funkce GetEnvironmentVariable() v klidu vrátí „x86″ i na 64bitovém systému, voláte-li ji z 32bitové aplikace. Tudy cesta také nevede.

Informaci je potřeba vyčíst z registru, to funguje spolehlivě:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment\PROCESSOR_ARCHITECTURE
Další zajímavá vlastnost 64bitových Windows je oddělený přístup do části registrů. 32bitová aplikace pracuje s jinými registry, než 64bitová (týká se větve Software\ jak v HKEY_LOCAL_MACHINE, tak v HKEY_CURRENT_USER). Větve pro 32bitové aplikace jsou umístěny pod uzlem Wow6432Node, přistupuje se k nim však zcela transparentně.

Co však v případě, pokud potřebujeme přistupovat v 32bitové aplikaci do 64bitové části registru nebo naopak? Řešení je poměrně jednoduché, existují speciální příznaky pro samDesired parametr funkcí RegCreateKeyEx(), RegDeleteKeyEx() a RegOpenKeyEx(): KEY_WOW64_64KEY a KEY_WOW64_32KEY.

Z 32bitové aplikace tak můžeme otevřít klíč v 64bitové části registru třeba takto:

RegOpenKeyEx(HKEY_LOCAL_MACHINE, regPath, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
Toť zatím vše, příště možná něco třeba o podepisování ovladačů a utilitě DpInst.exe :)

Proč je dobré používat virtualizaci HW

V dnešní době mají běžné počítače dostatečně velký výkon na to, aby zvládaly provádět více věcí naráz než kdy jindy. Na co jste dříve potřebovali síť o několika strojích, dnes hravě zvládne jeden jediný.

Na jednom fyzickém počítači tak může naráz běžet několik počítačů virtuálních, z nichž každý může poskytovat určité služby, mít nainstalovaný jiný operační systém apod. Výhodou je, že tyto počítače běží zcela izolovaně a nemohou se ovlivnit navzájem. Mohou být ale propojeny do virtuální sítě a využívat všech možností, které síťování nabízí.

Jaké výhody mi to nabízí?

  1. Oddělení projektů. Když potřebuji pro jeden projekt webový server, je zbytečné ho mít instalovaný i pro projekty jiné. Sám jsem dospěl do stavu, kdy mám na fyzickém počítači instalovaný pouze prohlížeč internetu, fotek, komunikační programy, pár dalších utilit a samozřejmě VMWare.
  2. Pokusný prostor. Občas je potřeba vyzkoušet nějaký kód nebo aplikaci, které člověk nedůvěřuje. Ven z virtuálního počítače (v tomto případě tzv. sandboxu) se to nedostane a případné negativní následky lze jednoduše smazat.
  3. Přenositelnost. Když si koupíte nový hardware nebo potřebujete přenést projekt jinam, stačí pouze překopírovat pár souborů tvořících virtuální stroj (za předpokladu, že i cílový hardware používá stejnou instrukční sadu procesoru). Odpadá nutnost pokaždé instalovat všechny potřebné aplikace. S tím souvisí i snadná obnova projektu po reinstalaci fyzického počítače nebo naopak možnost reinstalovat pouze počítač virtuální.
  4. Testování. Můžete mít řadu virtuálních počítačů s různými systémy a jejich konfiguracemi a testovat na nich svůj vyvíjený software.

Praxe

Zůstal jsem věrný VMWaru, jiná řešení měla problémy třeba s USB zařízeními nebo dokonce stabilitou (MS Virtual PC). VMWare Player je zdarma, neumí však vytvářet nové virtuální počítače. V tom ho však může zastoupit třeba tento online generátor: easyvmx.com.

Používám síťový režim bridged, každý virtuální stroj pak může mít vlastní IP adresu a být tak pohodlně používaný jako server.

Virtualizujte, ulehčí vám to práci :-)

Total Commander a víceuživatelské prostředí

Total Commander je fajn aplikace, ale občas v něčem trochu opožděná. Ještě před pár lety třeba vypadala jako v dobách největší slávy Windows 3.1.

Ale časy se mění a nové verze už dokonce zvládají mít pro každého uživatele vlastní nastavení. To se samozřejmě hodí a odpadá i nutnost být administrátorem, aby se vaše konfigurace ukládala (což bylo nezbytné, když býval wincmd.ini soubor přímo v adresáři windows). Instaloval jsem tedy verzi 7.04a a během instalace zvolil, že uživatelská konfigurace má být v profilu každého uživatele (Profil/Application Data).

Pro uživatele Administrator, kde jsem prováděl instalaci, to i fungovalo. U ostatních běžných uživatelů ovšem ne, Total Commander se vytrvale pokoušel načíst a uložit konfiguraci do starého dobrého adresáře windows.

Řešení je poměrně jednoduché, pro každého uživatele je potřeba zapsat do registru tyto údaje:

[HKEY_CURRENT_USER\Software\Ghisler\Total Commander]
"IniFileName"="%APPDATA%\\GHISLER\\wincmd.ini"
"FtpIniName"="%APPDATA%\\GHISLER\\wcx_ftp.ini"
a do adresáře %APPDATA%\GHISLER\ případně nakopírovat vaši oblíbenou konfiguraci.

Proč používat verzování, i když na projektu pracujete sami

Obecně se má za to, že software pro správu verzí se vyplatí používat na větších projektech, neboť právě ohlídání kolizí ve změnách prováděných více programátory současně je jeho hlavní úkol.

Nicméně, verzovací systémy nabízejí i další funkce, které využijete i na projektech vyvíjených klidně jedním člověkem.

Práce na více počítačích

Verzovací systémy jsou výborné pro jednoduchou synchronizaci dat mezi různými počítači, na kterých pracujete.

Archivace všech změn

U jakéhokoliv souboru se vždy můžete vrátit k jeho libovolné verzi nebo se podívat na rozdíly mezi jeho různými verzemi. To se hodí v případech, kdy chcete zjistit, jak jste kdysi něco udělali; nebo nedejbože tehdy, kdy na něčem začnete pracovat, a pak vám dojde, že takto raději ne. Nemusíte se pak starat o to, jestli jste všechny změny dobře vrátili a jednoduše obnovíte poslední revizi.

Rychlý přístup ke starším verzím

Vždy když vydáte novou verzi, jednoduše si ji ve verzovacím systému pojmenujete (SVN tomu říká tag, ClearCase label). Kdykoliv se pak do této verze můžete přepnout a pracovat s ní, udělat její build pro zákazníka, který má s novější verzí problém apod. Rozhodně je to praktičtější, než staré verze třeba zipovat a pak pracně rozbalovat.

Vývoj na více větvích

Někdy se stane, že do programu chcete přidat nějaký větší balík funkcí. Jeho vývoj trvá třeba půl roku a mezitím chcete zákazníkům dodávat aktualizace původní verze. Co však rozhodně nechcete, aby v nich měli obsaženou část funkcí nových a byli tak ohroženi chybami a nestabilitou této vývojové verze.

V takovém případě oddělíte před započetím vývoje těchto novinek tzv. branch od hlavní verze a vývoj provadíte na této nové branchi. V případě potřeby se samozřejmě do hlavní verze můžete kdykoliv přepnout. Po odladění nové verze přenesete změny i do verze hlavní, nebo-li provedete merge.

Jsem přesvědčen, že jednoduchý systém pro správu verzí (jakým je třeba SVN), najde své opodstatnění pro nasazení na libovolném softwarovém projektu, který vám trvá víc než jedno odpoledne, nebo u kterého je pravděpodobnost, že se k němu někdy budete chtít vracet.

PHP a unit testy

V okamžiku, kdy začnete vyvíjet aspoň trochu seriozní webové aplikace, pak má jistě smysl uvažovat o nějakém testování, nejlépe automatizovaném.

Co jsou unit testy

Základem by měl být unit testing (testování aplikačních jednotek), tedy v případě objektového programování testování toho, zda každá třída dělá správně to, co by měla. Zjednodušeně řečeno, napíšete si testovací skript a proklepnete jím správnou funkčnost všech metod ve vaší třídě pro různé vstupy, s důrazem na různé „speciální“ případy apod.

Výhody

Testovací skripty pro celý projekt můžete sdružovat do makefilů a pak pouhým make unit_tests rychle zkontrolovat všechny zdrojáky (o tom někdy příště). Při provádění úprav ve zdrojovém kódu se následně můžete rychle přesvědčit, zda jste si nezavlekli novou chybu někam, kde byste to vůbec nečekali.

Unit testy pro PHP

Pro PHP používám knihovnu SimpleTest. Umí toho docela dost, zatím všechny možnosti ani zdaleka nevyužívám. Kdysi jsem zkoušel ještě jednu (tuším, že to byl PhpUnit), ale tato mi připadá použitelnější.

Pokusná třída (Kalkulacka.php)

Jeden komentovaný příklad vydá jistě za tisíc slov :)
/**
 * Pokusná třída, jednoduchá kalkulačka, která umí sčítat a dělit čísla.
 */
class Kalkulacka
{
	/**
	 * Prázdný konstruktor.
	 */
	function Kalkulacka()
	{
	}
	/**
	 * Metoda pro sčítání.
	 *
	 * @param a 1. sčítanec
	 * @param b 2. sčítanec
	 * @return součet a + b
	 */
	function Secti($a, $b)
	{
		return $a + $b;
	}
	/**
	 * Metoda pro dělení.
	 *
	 * @param a dělenec
	 * @param b dělitel
	 * @return a děleno b (nebo false, pokud by mělo dojít k dělení nulou)
	 */
	function Vydel($a, $b)
	{
		if ($b != 0)
		{
			return $a / $b;
		}
		else
		{
			return false;
		}
	}
}

Test pokusné třídy (KalkulackaTests.php)

// načíst knihovnu SimpleTest
require_once 'simpletest/unit_tester.php';
require_once 'simpletest/reporter.php';
// načíst naší testovanou třídu
require_once 'Kalkulacka.php';
/**
 * Třída pro testování kalkulačky.
 */
class KalkulackaTests extends UnitTestCase
{
	/**
	 * Konstruktor.
	 */
	function KalkulackaTests()
	{
 		UnitTestCase::UnitTestCase();
	}
	/**
	 * Test sčítání.
	 * (název metody by měl začínat na test...)
	 */
	function testSecti()
	{
		// vytvořit instanci třídy kalkulačka
		$instance = &new Kalkulacka();
		// otestovat, zda byla instance v pořádku vytvořena
		$this->assertNotNull($instance);
		// otestovat, zda volání Secti(1, 1) vrací správně 2
		$this->assertEqual(2, $instance->Secti(1, 1));
		// otestovat, zda volání Secti(0, 15) vrací správně 15
		$this->assertEqual(15, $instance->Secti(0, 15));
		// ... a mohli bychom pokračovat dle libosti
	}
	/**
	 * Test dělení.
	 * (název metody by měl začínat na test...)
	 */
	function testVydel()
	{
		// vytvořit instanci třídy kalkulačka
		$instance = &new Kalkulacka();
		// otestovat, zda byla instance v pořádku vytvořena
		$this->assertNotNull($instance);
		// otestovat, zda volání Vydel(1, 1) vrací správně 1
		$this->assertEqual(1, $instance->Vydel(1, 1));
		// otestovat, zda volání Vydel(0, 1) vrací správně 0
		$this->assertEqual(0, $instance->Vydel(0, 1));
		// otestovat, zda volání Vydel(15, 0) vrací false (pokus o dělení nulou)
		// a nesmí to spadnout
		$this->assertFalse($instance->Vydel(15, 0));
		// ... a mohli bychom pokračovat dle libosti
	}
}
// založíme nový test suite, tedy kolekci testovacích tříd
$test = &new TestSuite('Test pokusné třídy Kalkulacka:');
// přidáme naši testovací třídu (= test case) do tohoto test suitu
$test->addTestCase(new KalkulackaTests());
// spustíme test suite, jako výstup se použije obyčejný textový report
// vrácená hodnota je předána PHP skriptu pro možné pozdější využití
// (0 = OK, jinak se stala chyba)
exit ($test->run(new TextReporter()) ? 0 : 1);

Výsledek

Po spuštění (php -f KalkulackaTests.php) se dočkáme příznivých výsledků:
Test pokusné třídy Kalkulacka:
OK
Test cases run: 1/1, Passes: 7, Failures: 0, Exceptions: 0
SimpleTest nám sděluje, že testy proběhly a v pořádku bylo 7 kontrol, u žádné nebyla zjištěna chyba a neobjevila se ani jedna PHP výjimka.

Zkoušíme udělat chybu

Jak by to vypadalo, kdybych třeba změnil kód sčítací funkce na odčítání (v třídě Kalkulacka, řádek 22)?
return $a - $b;
Spuštění testů by ukázalo toto, tedy dvě chyby s označením testů a čísel řádků, kde k nim došlo:
Test pokusné třídy Kalkulacka:
1) Equal expectation fails because [Integer: 2] differs from [Integer: 0] by 2
at [KalkulackaTests.php line 34]
in testSecti
in KalkulackaTests
2) Equal expectation fails because [Integer: 15] differs from [Integer: -15] by 30
at [KalkulackaTests.php line 37]
in testSecti
in KalkulackaTests
FAILURES!!!
Test cases run: 1/1, Passes: 5, Failures: 2, Exceptions: 0
Dokumentaci k dalším použitelným kontrolám (asserts) lze najít zde. A příště se budu věnovat tzv. mockům :-)

Internet Explorer a výška elementu v CSS

Při tvorbě webu je stále potřeba přizpůsobovat vzhled různým obskurním prohlížečům, třeba takovému IE verze 6 (například na Trainweb chodí z IE6 18,3 % všech lidí).

Naposledy jsem se nad tím vztekal včera, kdy jsem potřeboval mít div element vysoký přesně 6 pixelů. Stylopis hovořil jasně:

.divider
{
	height: 6px;
}
Nicméně IE tvrdojíšně kreslil daný rámeček vysoký dobrých 15 pixelů. Někde jsem se dočetl, že je potřeba nastavit ještě line-height na nulu. To taky nepomohlo.

Nakonec se ukázalo, že starostlivý Internet Explorer se obával, že by se mi do tohoto elementu nevešlo písmo o velikosti 10pt (zděděno z elementu body) a tak výšku raději přizpůsoboval. Text jsem dovnitř samozřejmě dávat nehodlal. Řešení je tedy prosaické:

.divider
{
	height: 6px;
	font-size: 1pt;
}
Můžete si tak v případě potřeby ušetřit zhruba 20 minut googlování :)

PHP a Doxygen

Už přes rok kontinuálně vyvíjím jistou webovou aplikaci a již od začátku jsem si dával záležet na tom, abych ke každé třídě a metodě psal tzv. doxygen-style komentáře, popisující co která třída a metoda dělá, u metod navíc třeba dokumentaci parametrů a návratových hodnot.

Jak komentovat v kódu

/**
 * Ukázka doxygen-style komentáře.
 *
 * @class UkazkovaTrida
 * @author Hans
 *
 * @date 2008-05-29
 */
class UkazkovaTrida
{
	/**
	 * Ukázka doxygen-style komentáře.
	 * Funkce vracející nulu.
	 *
	 * @author Hans
	 *
	 * @date 2008-05-29
	 *
	 * @param zbytecny zbytečný parametr
	 * @return vždy 0
	 */
	function Nula($zbytecny)
	{
		return 0;
	}
}

Co pak s tím

Teď jsem to konečně nějak zužitkoval – stáhnul si Doxygen, v rychlosti nakonfiguroval projekt (pomocí přiloženého doxywizardu; stačilo v podstatě definovat adresář projektu a výstupní adresář pro dokumentaci) a vygeneroval konfigurační soubor projektu (Doxyfile). Ten lze pak doupravit ručně v textovém editoru (jedná se vlastně o jakýsi „makefile“ pro Doxygen).

Na ten jsem následně spustil doxygen.exe z příkazové řádky a rázem mám čtyřmegový balík provázané dokumentace v HTML včetně grafického znázornění závislosti tříd a podobných vymožeností.

To se mi líbí, v podstatě se jedná o jediný smysluplný (a zároveň snadný a nepříliš otravující) způsob dokumentování kódu. Kdysi jsem svůj kód zkoušel prohnat tuším PhpDocumentorem, ale ten se mi nepodařilo nakonfigurovat a rozchodit během jednoho odpoledne, toto šlo oproti tomu zcela samo.

Jak rozchodit Doxygen

Takže, jestli si chcete snadno dokumentovat své projekty (ať už v Javě, C, C++, PHP nebo dalších podporovaných jazycích), proveďte následující:
  • stáhněte si Doxygen
  • stáhněte si Graphviz (abyste si mohli nechat generovat i grafické části dokumentace)
  • obojí nainstalujte a pomocí prográmku doxywizard.exe si můžete rychle zkusit vytvořit první pokusný dokumentační projekt :)

Jak vypadá výsledek

Ukázka hotové dokumentace

Starší články →