Podobné články obvykle začínají slovy „zapomeňte vše, na co jste zvyklí z Windows“. Je nesmysl po uživatelích něco takového žádat, protože návyků získaných za mnoho let používání počítače se nijak snadno zbavit nejde.
Namísto toho se s vámi chci podělit o tipy a zkušenosti, které jsem získal za 2 měsíce používání Macbooku. Se spoustou věcí jsem bojoval, narážel na slepé uličky, propadal zoufalství. V poslední době mám ale pocit, že se situace obrací a začínám poznávat výhody Mac OS X oproti PC.
Pravidlo č. 1 - zapomeňte na semafor! Trojice barevných tlačítek v levém horním rohu okna každému připomene podobnou trojici z Windows, ale jejich funkce se liší. Zelené + většinou okno nemaximalizuje - namísto toho změní velikost okna na tu, o které si myslí, že je ideální. Mezi žlutým a červeným tlačítkem prakticky není rozdíl. Obě de facto skrývají okno, jen stisk žlutého provází animace.
Namísto snahy strefit se do malých tlačítek je daleko pohodlnější používat klávesové zkratky. Cmd+W je nejčastější zkratka, kterou v současnosti používám. Je to ekvivalent stisku červeného tlačítka. Aplikace se nevypne a dál běží na pozadí, pouze se zavře její aktuální okno. Kompletně se dá aplikace vypnout přes Cmd+Q, ale zjistil jsem, že to dělám naprosto minimálně, spíš v nouzových situacích. Proti Cmd+Q hovoří i to, že se nedá použít ve Finderu.
OS X smazává rozdíl mezi vypnutými a běžícími aplikacemi. Abych tuto myšlenku podpořil, vypnul jsem si v nastavení zobrazování modrých teček pod ikonami v Docku. (System Preferences - Dock - Show indicator lights for open applications) Jednak mě iritovalo, že modrá tečka u aplikace zůstávala i po stisknutí červeného tlačítka a druhak mi to připomínalo indikátor nových příspěvků na Twitteru (myslel jsem tedy, že je v aplikaci „něco nového“, na co bych se měl podívat). Netuším tedy, jaké aplikace mi tu zrovna běží a jako uživatele mě to ani nezajímá.
Na Macbooku se nedá nastavit, co se má stát po zavření víka. Pokud není připojený k externímu monitoru a zároveň k napájení, uspí se. Pokud chcete skončit s prací nebo se přesunout, nemusíte v nastavení lovit nějaký režim spánku, stačí ho zaklapnout. Probuzení po otevření je téměř okamžité.
Doporučuji si projít System Preferences - Trackpad. Je tam seznam všech gest, které lze na touchpadu provádět a případně si je pozapínat/povypínat. Touchpad se dá stisknout kdekoli, lze tedy používat stejný prst pro přesouvání kurzoru i kliknutí. Překvapuje mě, kolik lidí tuhle zásadní věc neví.
Trochu divoce na mě působilo ovládání Finderu. Enter přejmenovává soubor, otevírá se pomocí Cmd+O. Zásadní vlastností je ale náhled, který se vyvolává mezerníkem. Zvládá mnoho typů souborů a neotevírá se kvůli němu specializovaná aplikace, jeho zobrazení je tudíž velice rychlé. Dokonce dokáže zobrazit i .docx, což v základu neumí ani Windows. O PDF nemluvě. Možnosti Finderu rozšiřuje TotalFinder.
Aplikace, které nejsou z App Store, se instalují prostým přetáhnutím souboru .app z archivu do adresáře Applications ve Finderu.
Kapitolou sama pro sebe je klávesnice. Oproti PC je zde jedna modifikátorová klávesa navíc, Cmd. Tam, kde se na PC používá Ctrl, zde Cmd. Pro práci s textem tedy slouží Cmd+X, Cmd+C, Cmd+V. Ctrl zde slouží jen jako náhrada v případech, kdy Cmd nelze použít. Hledání se ve všech aplikacích vyvojá přes Cmd+F, ale pokud jsem v textovém editoru a chci použít Najít+Nahradit, nemohu použít Cmd+H, protože tu má rezervovanou systém pro minimalizaci okna. Musím tedy stisknout Ctrl+H. Pokud chci přecházet v nějaké aplikaci mezi taby, nemohu použít Cmd+Tab, protože to má opět rezervované systém pro zobrazení seznamu oken. Opět zde zafunguje Ctrl+Tab. Takto se dá odvodit většina zkratek.
OS X i autoři aplikací význam klávesových zkratek dodržují. Ve všech funguje Cmd+čárka pro přechod do nastavení. Pokud v aplikaci existuje více různých pohledů, dá se mezi nimi přecházet přes Cmd+1, Cmd+2, … Stisk funkčních kláves F1 - F12 ve výchozím stavu provede to, co je na nich nakreslené, tedy ztmavení/zesvětlení displeje a klávesnice, přehrávání hudby apod. Skutečný stisk F1 - F12 se dá provést s modifikační klávesou Fn. Ale ještě jsem to nepotřeboval. Pro obnovení stránky, což při vývoji webů potřebuji velice často, se dá ve všech prohlížečich použít Cmd+R namísto F5, na které jsem byl zvyklý na Windows.
Na klávesnici chybí Home, End a Page Up/Down. Nahrazuje ho Cmd v kombinaci s kurzorovými šipkami. Stejně tak chybí Delete pro dopředné mazání textu, funguje ovšem Cmd+Backspace.
Dokud jsem nepotřeboval na Macbooku něco naprogramovat, vyhovovala mi výchozí česká klávesnice. Speciální znaky jsou na ni umistěny ovšem tak netradičně, že jsem lámání prstů po dvou dnech vzdal. Existuje nástroj Ukulele, který umožňuje nadefinovat si pohodlně vlastní rozložení klávesnice. Další možnosti skýtá „KeyRemap4Macbook“, který např. umožňuje z klávesy Eject udělat klasický Delete. Ale pozor, Airy už Eject nemají.
Konečně se dostávám k aplikacím. Nejdůležitější je stále webový prohlížeč, i když nemá zdaleka takový význam jako na Windows. Smysl má uvažovat pouze o Google Chrome nebo Safari. Mozilla Firefox si s Macem příliš nesedí. Pro Chrome hovoří jeho svižnost a neustále se zvětšující podíl na trhu, ze Safari je zas cítit lepší provázanost se systémem.
Webový prohlížeč na Macu ustupuje do pozadí, protože pro většinu webových aplikací jsou zde k dispozici jejich desktopové varianty, které se se svými webovými protějšky umí synchronizovat. Nativní aplikace na Macu jsou velice příjemné a pohodlnější, než jejich webové protějšky. Je přirozené, aby aplikace, se kterou stále pracuji, měla zvláštní okno na ploše, než jen jeden titěrný tab ve webovém prohlížeči. Zastávám teorii, že webové aplikace slaví takový úspěch jen kvůli tomu, že na Windows není nikdo schopný vytvořit funkční a pěknou aplikaci.
Pro uživatele Gmailu doporučuji Sparrow, klient s příjemným minimalistickým rozhraním. Podporuje všechny hlavní funkce Gmailu - štítky, hvězdičky, vyhledávání. To probíhá nikoli procházením veškeré pošty na disku, ale dotazováním se na servery Googlu, jako kdybyste použili vyhledávací pole. Odezva je tedy okamžitá. Vzpomínám si, když jsem před lety dal něco vyhledávat v Outlooku, mohl jsem si jít uvařit kafe, kdybych ho tehdy pil.
Pro uživatele Google Readeru je Reeder (existuje i pro iPhone a iPad). Taktéž se synchronizuje s webovým rozhraním, umí házet články do Read It Later a podporuje Readability (očesání webové stránky o zbytečnosti okolo pro pohodlné čtení).
Samozřejmostí je oficiální Twitter for Mac, který taktéž jde ve šlépějích svých protějšků pro iPhone a iPad.
Kalendáře z Google Calendaru jsem si naházel do předinstalovaného iCalu.
Protože jsem si na Windows vypěstoval oprávněnou nenávist vůči iTunes, ohlížel jsem se po alternativním přehrávači hudby. Ve stručnosti - neexistuje. Jako útěchu můžu říct to, že iTunes jsou na Macu docela jiný software. Dobře to popisuje moje příhoda, kdy jsem k Macbooku poprvé připojil svůj iPhone k synchronizaci a čekal celosystémový několikavteřinový lag jako na Windows. Ale nic se nedělo. Kontroloval jsem tedy iPhone, jestli je zapnutý, kontroloval jsem, jestli jsem správně zapojil kabel. Vše bylo v pořádku a přesto se nic nedělo. Otevřel jsem iTunes a ten mi signalizoval právě dokončenou zálohu iPhonu :) Dá se s nimi tedy vyjít.
Pro instant messaging se hojně používá Adium, to mi ale příliš do oka nepadlo. Existuje ovšem málo známý multiplatformní messenger od Mozilly, který se jmenuje Instantbird. Hodně mi připomíná Mirandu, na kterou nedám dopustit.
Na poznámky používám Evernote, který snad není třeba představovat.
Pro evidenci úkolů jsem si nedávno začal pohrávat s Things, který do puntíku dodržuje metodiku GTD. Představuje ovšem nemalou investici. Já využil toho, že nyní probíhá betatesting synchronizace do cloudu, takže zatím používám vývojovou verzi. Pokud se osvědčí, koupím si je.
Pokud často pracujete s příkazovou řádkou, doporučuji iTerm. Oproti výchozímu terminálu přináší značná zlepšení použitelnosti.
Příští neděli mířím na Appleforum, je tedy dost možné, že po něm budu muset tento článek z půlky přepsat, nebo celý zahodit.
Jakub Vrána na dnešním Barcampu ve své přednášce srovnával Doctrine 2 ORM se svou knihovnou NotORM. V jednoduchosti kódu, počtu řádků a vykonaných dotazů nutných pro vypsání článků a přiřazených tagů z databáze zvítězilo nepřekvapivě NotORM, což z něj u naivních programátorů hned dělá kandidáta na modelovou část webové aplikace. Z čehož mi přebíhá mráz po zádech.
Hlavní motivací pro používání Doctrine je konzistentní reprezentace dat v aplikaci a práce s nimi. A tu mi zařídí objekty. Nikoli obálky nad funkce (třida se samými statickými metodami), ani obálky nad data (třída s public proměnnými či obecným ukládacím mechanismem jako DibiRow), ale skutečné objekty reprezentující nějaký smysluplný celek s nenarušitelnou konzistencí a metodami, které mi umožní práci s nimi.
Pokud to vezmu z toho konce, že chci do databáze uložit nějaké řádky a pak je zase vybrat, pak mám s Doctrine skutečně o mnoho víc psaní, které nedává smysl. Ale pokud si primárně stanovím, že chci v aplikaci pohodlně pracovat s konzistentními objekty, jak se to standardně dělá třeba v Javě (a PHPčkařům to stále neleze pod kůži), pro ukládání do databáze pomocí Doctrine už musím udělat jen minimum - napsat ke třídě a jejím proměnným pár anotací.
Jakou máme motivaci pro tento způsob psaní aplikace a odstoupení od jednoduchých databázových vrstev, jako je právě NotORM nebo dibi? Ve chvíli, kdy velikost aplikace překročí určitou mez, je model s de facto statickými metodami, ve kterém se míchá přístup do databáze, zápis do souborů a posílání mailů, dlouhodobě neudržitelný chaos. Na řadu pak přichází dnes již legendární pětivrstvý model, jehož nejbližší implementací v PHP je právě Doctrine 2.
Tato architektura umožňuje snadnou testovatelnost a tudíž i spolehlivost, flexibilitu (API modelu a tudíž ani prezentační vrstva se při překopání databáze nemusí měnit), je dlouhodobě udržitelná a když přijde řeč na vícejazyčnost a verzování, lze to udělat čistě a bez vytrhání všech vlasů. V této oblasti se NotORM, ani klasické Nette modely, jak byly dlouhou dobu komunitou upřednostňovány, skutečně nechytají.
Samozřejmě to není jediný správný způsob, jak k problému přistoupit. Některé firmy/projekty volí přístup mít všechnu logiku v databázi. PHP aplikace je pak stavěná pouze do role jednoduché prezentační vrstvy a všechny operace se provádějí pomocí databázových procedur. Proč ne.
V Doctrine je určitě prostor pro optimalizaci pokládaných dotazů a umím si představit, že by k tomu použila NotORM. Ale mít tuto knihovnu jako jedinou vrstvu modelu u rozsáhlejších aplikací vyvíjenými více lidmi moc dobře nejde.
Stále se ještě setkáváme s názory, že jednotkové testování je práce navíc a že není, kdo by ho zaplatil. Tento článek si klade za cíl poodhalit tuto techniku vývojářům a projektovým manažerům, kteří v ni nevěří, nebo neví, že dokáže výrazně usnadnit a zkvalitnit odvedenou práci.
Zápis některých aspektů objektově orientovaného programování v PHP má poměrně velký WTF faktor a nejednou jsem narazil na pokročilého programátora, jak tápal, proč jeho kód způsobuje parse error či nějakou jinou chybu. Rozhodl jsem se proto oprášit můj blog a přehledně na jednom místě shrnout OOP syntax v PHP.
U jednotlivých popisů budu velice stručný, článek si neklade za cíl vysvětlit OOP, zaměřuje se pouze na způsob zápisu.
K hezkému objektovému kódu patří i jeho jednotná podoba, doporučuji k nastudování Nette Coding Standard.
Třídy
Definice nové třídy
//obecná třídaclassA{}//abstraktní třída - nelze vytvořit instanci, to až u potomkaabstractclassA{}//finální třída - nelze poděditfinalclassA{}//definice třídy B, která dědí od třídy AclassBextendsA{}
Konstruktor
Metoda, která se jmenuje __construct() a volá se při vytvoření instance nové třídy.
classA{publicfunction__construct(){}}//konstruktor může mít parametryclassA{publicfunction__construct($name){}}
Vytvoření instance
$a=newA;//pokud konstruktor nemá žádné povinné parametry$a=newA();//ekvivalentní zápis$a=newA('foo');//konstruktor s povinným parametrem
Rozhraní (interfaces)
//obecný interfaceinterfaceA{}//interface B, který dědí od interface AinterfaceBextendsA{}//třída B, která implementuje interface AclassBimplementsA{}/* PHP umožňuje implementaci více rozhraní naráz *///třída C, která implementuje interfaces A a BclassCimplementsA,B{}
Viditelnost (zapouzdření)
U metod a statických/instančních členů (atributů třídy) lze nastavit viditelnost pro volání (u metod), resp. pro čtení a zápis (u atributů). PHP, stejně jako ostatní jazyky, podporuje tři typy viditelnosti:
public: volat metody a přistupovat k atributům může každý
protected: pouze samotná třída, její potomci (při překrývání - overriding - i předci) a sourozenci (dvě různé instance typu B či nadtypu A si navzájem mohou sahat na protected metody a atributy)
private: pouze samotná třída
Atributy
Definice atributů
Konvence říká, že všechny atributy by měly být definovány na začátku definice třídy.
classA{//instanční atributyvar$a;//zastaralý zápis publicpublic$b;protected$c;private$d;//statické atributypublicstatic$e;//atributům lze předat výchozí hodnoty primitivních datových typů anebo pole//složitější data se musí předávat v konstruktoruprivate$f='';private$g='foo';private$h=108;private$i=array('bar');}
Přistupování k atributům
$a=newA;//zvenčí, k instančním$a->a='foo';//zvenčí, ke statickýmA::$e='bar';//zevnitř třídy, k instančním$this->c='foo';echo$this->f;//zevnitř třídy, ke statickýmself::$e='bar';
Konstanty
PHP umožňuje definovat neměnitelné atributy třídy, např. pro všelijaká nastavení a podporu principu DRY.
classA{//metody bez uvedení viditelnosti jsou brány jako publicfunctionmethodFoo(){}publicfunctionmethodBar(){}protectedfunctionmethodFooBar(){}privatefunctionmethodBarFoo(){}//metoda může být abstraktní, její definici pak necháváme na potomkovi třídyabstractpublicfunctionmethodAbstract();//metoda může být i finální, nelze ji pak v potomkovi překrýtfinalpublicfunctionmethodFinal(){}}
Parametry metod
classA{//metoda, která přijímá dva parametrypublicfunctionmethodExample($a,$b){}//PHP neumožňuje přetěžování metod (overloading), umí ale nepovinné parametry//metodu lze zavolat se dvěma nebo třemi parametrypublicfunctionmethodFoo($name,$age,$sex='male'){}//lze definovat, jakého typu má přijímaný parametr být//nejde použít pro primitivní datové typy - lze vynutit pouze pole, interface nebo třídu - funguje zde polymorfismuspublicfunctionmethodBar(array$names,Person$p,Traversable$t){}//i metody mohou být staticképublicstaticfunctionmethodStatic(){}}
Pokud v potomkovi definuji atribut nebo metodu s názvem, který existuje už v předkovi, a jejich viditelnost je public či protected, dojde k překrytí (overriding).
classA{public$foo='foo';publicfunctionmethodExample(){return'foo';}}classBextendsA{public$foo='bar';publicfunctionmethodExample(){return'bar';//pomocí parent::methodExample() mohu zavolat metodu předka}}$b=newB;echo$b->foo;//vypíše barecho$b->methodExample();//vypíše bar
Pokud se v třídním předkovi odkazuji na public/protected atribut či metodu, která je v potomkovi přepsána, volá se/přistupuje se k implementaci potomka.
Pozor! Tento způsob nefunguje u statických atributů a metod, tam se při přístupu pomocí self:: bude stále volat implementace v předkovi. Tento nedostatek řeší late static binding v PHP 5.3, viz níže.
classA{protected$foo='foo';publicfunctiongetFoo(){return$this->foo;}}classBextendsA{protected$foo='bar';}$b=newB;echo$b->getFoo();//vypíše bar
Špatné návyky
Zdrojové kódy v této části doma, v práci, ani ve škole nezkoušejte! ;)
PHP kvůli své skriptovací povaze umožňuje v OOP opravdu nehezké věci.
$a='foo';$b='bar';//podmíněné dědění? 11 z 10 programátorů pláčeif($a==$b){classB{}}else{classBextendsA{}}//pokud chci pracovat s nějakým atributem, musí být ve třídě vždy definovanýclassA{//fuj!if('foo'=='bar'){public$aaa;}publicfunctionfooBar(){if(isset($this->aaa)){//nesmyslná kontrola, ve správném kódu musí $this->aaa vždy existovat//...}}}
Dynamické názvy
Pokud k tomu máme důvod, můžeme na základě nějaké proměnné či výpočtu rozhodovat, jaká třída se použije, k jakému atributu se přistoupí a jaká metoda se zavolá.
Musíme být samozřejmě připraveni na všechny hodnoty, kterých daná proměnná může nabýt.
$den=date('D');//nabývá hodnot Mon až Sun$a=new$den;//zavolá se třída s názvem dne v týdnu//od PHP 5.3 lze přistupovat i ke statickým atributům/konstantám/metodám$den::TRIDNI_KONSTANTA;$den::methodStatic();//volání metody$method='mojeMetoda';//zavolá se instanční metoda mojeMetoda() třídy Thu (pokud je čtvrtek ;))$a->$method();//pokud chci zapsat složitější logiku, slouží k tomu složené závorky$bool=true;//zavolá se metoda allow() nebo deny()$a->{$bool?'allow':'deny'}();
Jmenné prostory (namespaces) (PHP 5.3)
Pokud se vám hodí mít dvě třídy stejného názvu, tak je stačí dát do dvou různých jmenných prostorů a nemáte problém. Ale pozor! Namespaces spíše přidělávají práci, než aby ji ulehčovali. Přesto se dá přijít na způsob, jak práci s namespaces minimalizovat na nejmenší možnou mez.
//lze mít více úrovní jmenných prostorů, \ je oddělovačnamespaceFoo\Bar;//v jiných souborech je nyní ke třídě A nutné přistupovat jako k Foo\Bar\AclassA{}
namespaceMujNamespace;classB{publicfunctionmethodTest(){/** * pokud chci uvnitř nějakého namespace přistoupit k úplně jinému namespace, * musím zvolit absolutní "cestu" s \ na začátku */$a=new\Foo\Bar\A;/** * jinak by došlo k tomuto: */$a=newA;//třída MujNamespace\A neexistuje!/** * Pokud na začátku souboru pod definicí namespace zavolám: * use \Foo\Bar\A; * ...tak už se na třídu mohu odvolávat klasicky: */$a=newA;//funguje!}}
Late static binding (PHP 5.3)
Problém s překrýváním statických atributů a metod jsem zmínil už výše, zde uvedu jen praktický příklad:
Nette Framework má mnoho předností. Hlavní z nich je rychlá a efektivní tvorba kvalitních webových aplikací.
Už dávno jsou ty doby, kdy jsem v PHP půl odpoledne patlal obstojný formulář s kontrolou vyplněných textových polí, validitou e-mailové adresy a jakž-takž ucházejícím vzhledem odesílané zprávy.
V Nette je tvorba dokonalého a neprůstřelného kontaktního formuláře práce na 10 minut. Framework totiž obsahuje třídu jak pro práci s formuláři, tak třídu pro odeslání e-mailu (včetně podpory tvorby zprávy šablonovým způsobem).
Jak vypadá zdrojový kód takového formuláře? Vytvoříme si ho v továrničce v Presenteru:
Jednoduchým zavoláním makra widget vykreslíme formulář v té šabloně, kde ho chceme:
{control contactForm}
Napíšeme metodu, která se při odeslání formuláře zavolá (a dbáme při tom na pattern Post/Redirect/Get):
publicfunctioncontactFormSubmitted(BaseForm$form){try{$this->sendMail($form->getValues());$this->flashMessage('Zpráva úspěšně odeslána!');$this->redirect('this');}catch(\Nette\InvalidStateException$e){$form->addError('Nepodařilo se odeslat e-mail, zkuste to prosím za chvíli.');}}
Napíšeme samotné odeslání e-mailu (včetně plnění souboru se šablonou):
privatefunctionsendMail($values){$mail=newMessage;$mail->setSubject('Nová zpráva z kontaktního formuláře');$mail->setFrom($values['email'],$values['name']);$mail->addTo('ondrej@mirtes.cz','Ondřej Mirtes');$template=$this->createTemplate();$template->setFile(__DIR__.'/../templates/Mail.phtml');$template->name=$values['name'];$template->email=$values['email'];$template->text=$values['text'];$mail->setHtmlBody($template);$mail->send();}
A vytvoříme šablonu, jak bude e-mail vypadat (Mail.phtml):
<h3>Nová zpráva z kontaktního formuláře</h3><ul><li><strong>Jméno</strong> {$name}</li><li><strong>E-mail</strong><ahref="mailto:{$email}">{$email}</a></li></ul><h1>Text zprávy</h1>
{$text}
To je celé. Máme formulář, který se neodešle, pokud nejsou vyplněna všechna povinná pole (včetně klientské validace Javascriptem), u kterého nebude hrozit vícenásobné odeslání pomocí F5 a který by nám zabral daleko více času, kdybychom se ho snažili vytvořit bez frameworku.
P.S. Vložit tento článek do mého CMS (tento blog jsem programoval půl roku před tím, než jsem začal s Nette dělat) se ukázalo jako daleko náročnější, než tvorba celého formuláře - neescapuje mi správně znaky (vyřešilo by dibi) a neobarví mi PHP kód (vyřešilo by Texy!). Davide, co bychom bez tebe dělali? :)
P.P.S. Začátkem října jsem celý blog přepsal do Nette, dibi a Texy, takže přesun článku a obarvení kódu v novém systému bylo daleko pohodlnější :)
XML deklarace by měla být součástí validní XHTML stránky, i když není povinná.
Problém nastává v momentě, kdy tuto deklaraci chceme použít na začátku PHP skriptu. Jak deklarace XML, tak PHP kód používají < > závorky. PHP se tady snaží překousat kód deklarace, ale neúspěšně - skript se zastaví na první možné řádce.
Jak toto omezení obejít a mít XML deklaraci v libovolném PHP skriptu? Stačí použít echo s jednoduchými uvozovkami:
Jelikož můj původní web poháněl vlastní systém, implementoval jsem do něj postupně funkce tehdy, až když jsem je potřeboval. Když roboti po pár měsících od startu přišli na to, jak přidávat komentáře pod články a ty se začaly objevovat opravdu ve velkém množství, situaci bylo potřeba vyřešit.
Nechtěl jsem uživatele obtěžovat s opisováním znaků z nečitelných obrázků, ani s matematikou. Problém za mě vyřešil Jakub Vrána. Nutno říct, že jeho způsob eliminace spamu u mě fungoval na sto procent, od jeho nasazení mi nepřišel do komentářů jediný nevyžádaný příspěvek (od automatu).
A jak na to? Předpokládáme, že botům stále nebyl dán do vínku JavaScript. Uživateli tedy položíme nějakou otázku či zadáme úkol vyplnit dodatečné pole formuláře, JavaScriptem toto pole skryjeme a požadovanou hodnotou vyplníme. Uživatelé s JavaScriptem o ničem nevědí. Uživatelé bez JavaScriptu nejsou nijak omezeni, pouze musí vyplnit o jednu hodnotu navíc. Ve zpracování odeslaného formuláře pak nepokračujeme, pokud v dané proměnné není požadovaná hodnota.
E-mailové adresy na webech jsou vystaveny útokům spamrobotů, kteří je indexují a ukládají do své databáze. Stačí mít tedy svůj e-mail 1x na nějakém zaindexovaném webu a už to jede. Obvyklé obrany proti těmto způsobům získávání adres pro spam jsou pro uživatele nepřívětivé. V případě, že je zavináč nahrazen nějakým jiným znakem, nemusí méně zkušeného návštěvníka napadnout při psaní e-mailu ten znak správně nahradit. A v případě adres zobrazených jako obrázky ji musí uživatel přepisovat celou. Navíc už boti disponují kvalitním OCR, na technologii CAPTCHA se nedá spolehnout.
Martin Jurča mi poradil ochranu, kterou sám ke své plné spokojenosti používá. Ta sází na skutečnost, že boti neumí JavaScript. Pomocí JS se zapíše odkaz v normálním tvaru a objeví se na stránce tak, jak ho známe. Uživatelé nejsou omezeni a boti jsou (aspoň na nějakou dobu) eliminování.
Kód pro její implementování na web je následující: