Problem
Jak wygląda praca z Javascriptem z punktu widzenia server-side’owego developera?
Przeszliśmy pierwszą falę szału nad bibliotekami JS: Prototype, Mootools, jQuery (czy mniej buzzowe ext.js, YUI). Zachwycamy się ładnymi rzeczami tworzonymi przy użyciu canvas, które znajdujemy na oursignal.com (też przecież napisanym w JS). Widzimy, jak za pomocą jednej linii możemy schować, animować, przetransformować i zrobić milion rzeczy z DIVem, Paragrafem czy Anchorem. Wybieramy jedną z bibliotek. Czytamy dokumentację, widzimy milion fajnych selektorów, czytamy książki, w których zachwycamy się jak fajnie można rozszerzyć funkcjonalność o pluginy… Myślimy sobie: “tak, teraz, gdy JS nie jest tak paskudny i skopmlikowany jak kiedyś, mogę stać się JS-developerem!”. Piszemy więc accordion, animujemy kilka rzeczy w naszej aplikacji (żeby user widział, że się dzieje!), kilka formularzy wysyłamy AJAXem. Wszystko jest ładne i unobtrusive. I co?
Zdajemy sobie nagle sprawę, że nasz application.js ma o kilkaset linii kodu za dużo, że kod jest nieczytelny, że nie wszystko da się wrzucić do document.ready(), że kilku rzeczy moglibyśmy użyć w kilku miejscach – zaczynamy pisać więc funkcje, staramy się przyjąć jakąś konwencję nazewnictwa… I kończymy z jeszcze większym bałaganem – chociaż bałaganem rozszerzonym o DRY.
Rozwiązanie?
Dobrym punktem wyjścia jest trzymanie wszelkich akcji w jednym obiekcie – korzystając z object literal (kawałek kodu korzysta z jQuery):
Co nam teraz pozostaje? Wywołanie funkcji bob.init(); w document.ready. Korzyści? Mając jeden obiekt “bob” możemy wywoływać jego funkcje w środku odwołując się do self. Trzymając wszelkie informacje, które mogą ulec zmianie – takie, jak długość timeoutu, klasy css czy wiadomości komunikatów – w bob.config – możemy łatwo je zmienić (gdy np. mamy konflikt z koderem CSS). Zresztą kod jest całkiem “samowyjaśniający się“.
Potencjalne zastosowanie? Dajmy na to, że wszystkim input type=submit podpinamy event, który powoduje, że po kliknięciu na niego zmienia value na “ładuję…” i staje się disabled. Ok, pięknie działa dla wszystkich przycisków wygenerowanych przez aplikację. Co jednak, gdy stworzymy nowy input przez javascript? Mamy doczepić mu event w momencie tworzenia? Nie, po umieszczeniu go w DOMie wywołujemy tę samą funkcję, która jest wywoływana przy init(). Warto rozpisywać nawet najmniejsze rzeczy w osobnych funkcjach – nigdy nie wiadomo, czy nie będziemy musieli ich kiedyś użyć ponownie.
Co dalej? Walidujemy nasz JS przy użyciu JSLint, przez co oszczędzimy sobie żmudnego procesu debugowania (który nie jest, swoją drogą, zbyt przyjazny). Kilka ciekawych praktyk zawarł w swojej prezentacji Chris Heilmann (część 1, część 2, wygrzebane przez Filipa Teppera) – m.in. jak umożliwić designerowi/koderowi CSS pracę nad wyglądem strony z Javascriptem lub bez niego – korzystając jedynie z CSS.