poniedziałek, 12 lipca 2010

Drupal - informacja kontekstowa o pierwszym wejściu użytkownika

Drupalowe Konteksty to, jak wiadomo, alternatywne spojrzenie na temat wyświetlania pewnych elementów na stronie w zależności od aktywnego stanu otoczenia. Wcześniej z dużym zapałem stosowane były phpowskie filtry od visibility, albo wręcz w pełni ręczne rozwiązania.
Ale teraz, przy odrobinie dobrej woli i poznaniu bardzo elementarnego API, możemy cieszyć się niespotykaną kontrolą nad obrazem witryny. Jest to rozwiązanie (konteksty) w obecnej formie już bardzo "na wypasie", ale jeśli twórcy modułu pójdą jeszcze o krok dalej, to w efekcie możemy mieć naprawdę całkiem efektywną i przejrzystą State Maszinę.
Moja cegiełka do tego ogródka, to prosty moduł-plugin do contextów (przystosowany do wersji 2.0. Wersja 3.0 w momencie pisania nadal jest w wersji beta i osobiście nie do końca mi "podchodzi") dający informacje o pierwszych odwiedzinach użytkownika.
Zrobienie portu do 3-ki jest oczywiście niewymagającym zadaniem. Jeśli komuś zechciałoby się tego "dokonać", albo zainwestować w dokonanie, to proszę dać znać -)
Rozwój modułu jest przewidywany, ale zawieszony. Proponowane sugestie rozbudowy zawarte są w pliku *.module.
link:
http://statics.altart.pl/drupal/modules/first_time_visitor-6.x-1.0.tar.gz

czwartek, 10 czerwca 2010

Drupal 6.x, Ubercart 2.x: Obsługa podatku VAT

Aby skonfigurować obsługę podatku VAT dla systemu Drupal e-commerce opartego na modułach z paczki Ubercart 2.x, należy wykonać następujące kroki:
  1. instalacja modułu uc_vat (standardowa procedura intalacyjna Drupala)
  2. stworzenie odpowiedniej liczby klas produktów (należy stworzyć tyle klas ile chcemy mieć stawek podatkowych w sklepie - przy moich instalacjach domyślna klasa produktu reprezentuje produkty z 22% VATem) pod adresem /admin/store/products/classes.
  3. konfiguracja stawek podatkowych: /admin/store/settings/taxes - dodajemy potrzebne stawki podatkowe i przypisujemy je do stworzonych wcześniej klas produktów
  4. konfigurujemy moduł uc_vat do naszych potrzeb (sposób prezentacji cen, ceny z/bez vatu itp.)
gotowe.

poniedziałek, 24 maja 2010

Typografia stron www

Typografia stron jest ograniczona przez czcionki dostępne w systemie operacyjnym użytkownika.

Za czcionki najbardziej rozpowszechnione uważa się:

  • wśród bezszeryfowych: Arial / Helvetica
  • wśród szeryfowych: Times New Roman / Times
  • stałej szerokości: Courier New / Courier

Do czcionek między platformowych zaliczyć można również:

  • Palatino
  • Garamond
  • Bookman
  • Avant Garde

Popularne czcionki dostępne na Windows i Mac, ale nie dostępne w systemach Unix to:

  • Verdana
  • Georgia
  • Comic Sans MS
  • Trebuchet MS
  • Arial Black
  • Impact

(na postawie http://web.mit.edu/jmorzins/www/fonts.html)

Nie daje to niestety wystarczającej elastyczności jeśli chodzi o stylizację strony, a użycie bardziej nietypowej czcionki z dużym prawdopodobieństwem spowoduje, że część użytkowników zobaczy inny niż zaprojektowany wygląd strony. Istnieje na szczęście wiele rozwiązać, które pozwalają poradzić sobie z tym problemem, m. in.:
  • przykrywanie tekstu statycznym obrazkiem
  • dynamiczne zastępowanie tekstu przy pomocy JavaScript/Flash
  • osadzanie czcionek przy pomocy deklaracji @font-face
Poszczególne możliwości opiszę w kolejnym poście.

piątek, 21 maja 2010

Optymalizacja Drupala - modyfikacja rdzenia

Optymalizacja rdzenia ( oraz modułów pobranych z repozytorium )

Z mojego, firmowego doświadczenia wynika, że jest to rozwiązanie o największym potencjale. Przykładów i miejsc optymalizacji można by szukać (i skutecznie znajdować) bardzo dużo, ale w zależności od platformy i konkretnej instalacji rozwiązaniem dającym nam największy zysk będzie prawdopodobnie co innego.

Mimo tego, jest kilka elementów na które warto by zwrócić uwagę niezależnie od platformy działania aplikacji:

  1. optymalizacja kodu (PHP)
  2. keszowanie statyczne (SQL)
w nawiasach podane są podsystemy na które dana optymalizacja ma największy wpływ:

SQL - baza danych PHP - szybkość wykonywania kodu

ad. 1 optymalizacja kodu

  • wpływa na: szybkość parsowania PHP
  • możliwa ogólna poprawa wydajności systemu: niska

Co można poprawić:

  1. derekursywacja procedur
  2. optymalizacja struktur danych
  3. optymalizacja przebiegu programu (czyli przepisanie nieefektywnych pętli i konstrukcji warunkowych)

Potencjalnie najbardziej czasochłonne zadanie, uzasadnione jedynie w przypadku bardzo intensywnego wykorzystania kodu, lub w systemach wymagających bardzo szybkich obliczeń. Nie będę wdawał się w szczegóły odnośnie tego zagadnienia, polecę natomiast książkę Piotra Wróblewskiego: "Algorytmy, struktury danych i techniki programowania", gdzie znajdziemy wiele informacji o różnych typach struktur danych wraz z analizą wydajności. Gorąco polecam!

ad. 2 keszowanie statyczne

  • wpływa na: bazę danych
  • możliwa poprawa wydajności systemu: duża

Jest to technika wypływająca z samej architektury języka, polegająca na zapisywaniu w lokalnych zmiennych statycznych informacji pobranych z bazy danych.

Fakt że musimy stosować ten mechanizm jest bezpośrednim skutkiem tego, że Drupal z systemami czysto obiektowymi nie ma wiele wspólnego. Jest on napisany i utrzymywany w oparciu o techniki programowania strukturalnego, chociaż sama architektura (i pewne założenia koncepcyjne) posiadają znamiona obiektowości. W środowisku obiektowym posługiwalibyśmy się tzw. modelami

Przykładem zastosowania keszowania statycznego jest funkcja node_load, która jedynie przy pierwszym wywołaniu faktycznie "kręci" bazą danych i systemem hooków, natomiast przy każdym następnym, zwraca wygenerowany obiekt zapisany w zmiennej statycznej.

Jak optymalizować nieefektywny kod pod tym kątem ?

Po pierwsze instalacja modułu devel. Następnie włączenie w nim wyświetlania logów z bazy danych i odpalenie najbardziej newralgicznych ( potencjalnie najbardziej obciążonych, lub posiadających najbardziej rozległe funkcje ) stron w witrynie. Obserwowane wyniki powinny dać nam bardzo wyraźny sygnał o tym, gdzie występują nadprogramowe zapytania (sam devel podpowie nam zaznaczając liczbę zapytań kolorem czerwonym ), przykład: ( case z naszej firmowej strony )

Mamy zaznaczone na czerwono dwie pozycje. Są to, w obu przypadkach, identyczne zapytania które zostały wykonane przez system więcej niż raz - dobre miejsca aby przeprowadzić próbę optymalizacji z użyciem zmiennych statycznych. Spójrzmy gdzie zostały one wywołane:

"SELECT * FROM users u WHERE uid = 1" odpalany jest w funkcji user_load, natomiast druga kwerenda w funkcji cache_get ( czyli z systemu Drupalowego kesza ). W pierwszym przypadku ze zlokalizowaniem funkcji nie ma problemów, w drugim potrzebne będzie małe dochodzonko; zajmę się więc pierwszym zapytaniem.

Funkcja user_load jest niekrótka - nie będę jej zamieszczał w orginale, a jedynie przedstawię swoje uwagi odnośnie potencjalnych problemów z wdrożeniem tej metody optymalizacji i ich rozwiązaniem:

Parametry funkcji Całkiem oczywisty jest fakt, że jedna, dobra dla każdego wywołania tej funkcji zmienna statyczna nie wystarczy. Możemy mieć różne parametry określające sposób ładowania użytkowników, a więc i prawdopodobnie (choć w tym wypadku na pewno) różne zapytania. Metoda która rozwiązuje nam ten problem jest prosta, ale wiąże się z nią dodatkowy czas obliczeniowy. Tworzymy zmienną statyczną będącą tablicą i zapisujemy do jej kluczy parametry wywołania, a do wartości obiekty użytkowników. Klucze obliczamy przy pomocy funkcji serialize ( i tu jest ten minus wydajnościowy ). Przykładowa implementacja funkcji user_load, z zastosowaniem wyżej opisanej metody: (wersja 6.16 Drupala)

function user_load($array = array()) { static $staticCache = array(); // obliczamy klucz w keszu statycznym $cacheKey = serialize($array); // jeśli nie posiadamy informacji zapisanej pod tym kluczem // w keszu statycznym if(!isset($staticCache[$cacheKey])) { // tu zapiszemy sobie wynikowy obiekt USER $res; // to lecimy z całą procedurą obliczającą obiekt USER // Dynamically compose a SQL query: $query = array(); $params = array(); // flaga, dzieki ktorej ominiemy niefajny "return" w środku kodu $canComputeFlag = TRUE; if (is_numeric($array)) { $array = array('uid' => $array); } elseif (!is_array($array)) { // w tym miejscu powinnismy wyjsc z funkcji, ale // wtedy obsluga kesza nie będzie bezproblemowa // korzystamy więc z canCompute'a $res = FALSE; $canComputeFlag = FALSE; } if($canComputeFlag) { // wszystko gra foreach ($array as $key => $value) { if ($key == 'uid' || $key == 'status') { $query[] = "$key = %d"; $params[] = $value; } else if ($key == 'pass') { $query[] = "pass = '%s'"; $params[] = md5($value); } else { $query[]= "LOWER($key) = LOWER('%s')"; $params[] = $value; } } $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params); if ($user = db_fetch_object($result)) { $user = drupal_unpack($user); $user->roles = array(); if ($user->uid) { $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; } else { $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; } $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid); while ($role = db_fetch_object($result)) { $user->roles[$role->rid] = $role->name; } user_module_invoke('load', $array, $user); } else { $user = FALSE; } $res = $user; } // ustawiamy obiekt w kluczu kesza statycznego $staticCache[$cacheKey] = $res; } // zwracamy to co mamy pod kluczem return $staticCache[$cacheKey]; }

Efekt prezentuje się następująco:

Podobną procedurę można stosować z dużym powodzeniem do wielu istniejących w jądrze Drupala funkcji oraz do modułów dodatkowych. Rozumiem zamierzenie twórców, którzy zdecydowali kosztem bazy danych, zachować większą szybkość i czytelność kodu, ale jednak z doświadczenia wynika, że dużo łatwiej zapchać jest bazę niż proces PHP, a każda dodatkowa kwerenda w Drupalu (bo i tak jest ich nie mało), stanowi potencjalne wąskie gardło całego systemu. To jest moim zdaniem droga, która powinna przyświecać gronu twórców Drupala z każdym następnym wydaniem

Przyspieszanie Drupala 6.x

Przyśpieszanie Drupala 6.x

Mechanizmy pamięci podręcznej dane z "automatu" przez CMS Drupal są oczywiście rewelacyjne. Przemyślane, stabilne i rozszerzalne. Mało przejrzyście zaimplementowane co prawda, ale nie mam tu zastrzeżeń, bo wynika to głównie z konstrukcji samego języka PHP i z cudownie nieeleganckiej dowolności jaką on daje.
Osobiście, po cichu liczę na to, że w kolejnych wersjach Core Drupala zacznie bardziej przypominać nowoczesne systemy typu business i enterprise. Z tym jednak przyjdzie poczekać do pierwszej, w pełni obiektowej, zgodnej ze standardami, wersji języka PHP.

Duża plastyczność systemów opartych na Drupalu i próba utrzymywania spójnego API na przestrzeni pojedynczych wersji głównych (ale nie pomiędzy nimi - sposób pracy z core w wersji 5.x jest inny od tego, co mamy w 6.x), wymusza utrzymanie pewnej warstwy abstrakcji, nie zawsze dającej pole do łatwej optymalizacji pod konkretny projekt. Dodatkowo głównym zadaniem tej platformy jest bezawaryjna i bezproblemowa praca w ogromnej ilości potencjalnych środowisk działania. Co samo "przez się" daje nam czytelny sygnał, że w naszym danym, konkretnym przypadku pojawią się mechanizmy, z których nie będzie można automatycznie skorzystać i będzie potrzeba ( a nawet konieczność ) dostosowania kilku rzeczy przed przeniesieniem aplikacji z serwera developerskiego na maszynę produkcyjną.

Co nam daje taka optymalizacja ? Oczywiście: "to zależy", ale na pewno daje nam więcej niż jej brak. Cenna jest więc w ogóle świadomość, że możemy takiej optymalizacji dokonać, a zupełnie bezcenna staje się wiedza jak tego dokonać. Pamiętajmy że optymalizacja jest jednym z podstawowych etapów tworzenia oprogramowania, i choć nieraz będziemy mogli spokojnie oprzeć się na warstwie optymalizacyjnej oferowanej przez nasz framework: będzie to dla stron, które nie wymagają dynamicznych zmian i nie obsługują znacznej liczby użytkowników jednocześnie ( mniej niż 100 ), to już dla nieco większych systemów będziemy musieli zatroszczyć się o ręczne opracowania stosownej, dodatkowej warstwy optymalizującej aplikacje. Znane i powszechnie dostępne moduły optymalizacyjne do Drupala są wyśmienicie opisane na wielu stronach i blogach.
Ja natomiast, w kolejnych wpisach, chciałbym skupić się nad innym podejściem do osiągnięcia lepszej wydajności wdrażanych stron:

1. modyfikacja rdzenia
2. tworzenie optymalnych autorskich modułów
3. szukanie alternatywnych źródeł pamięci podręcznej
4. odchudzanie instalacji
5. optymalizacja bazy danych

Każdy z tych elementów (razem lub z osobna) jest stosowany w naszych wdrożeniach cms, a więc poparty jest żywą analizą działania i bogatym zapleczem testującym.

czwartek, 8 kwietnia 2010

Altart blog start

Witamy na blogu firmy Altart Intermedia. Tworzymy nowy obraz polskiego internetu. Poprzez stylowy design i wykorzystanie zaawansowanych technologii możemy oferować unikalne rozwiązania dla każdego klienta. Postaramy dzielić się Wami naszymi spostrzeżeniami, doświadczeniem i nowymi technologiami nad którymi pracujemy, aby pomóc szerzyć najlepsze i najświeższe rozwiązania wśród użytkowników i developerów wirtualnego świata www. Wkrótce pierwsze wpisy; tymczasem zapraszamy na naszą stronę internetową, na której można zapoznać się z naszą ofertą i portfolio.