JustPaste.it

Planowanie aplikacji WWW

Artykuł omawia zalety dobrego planowania swoich aplikacji WWW oraz podsuwa garść ciekawych uwag odnośnie tego etapu prac.

Choć zdolności improwizacyjne bardzo się wśród programistów ceni, bardzo często, szczególnie przy złożonych lub nastawionych "na eksport" projektach przed przystąpieniem do prac musimy wszystko dokładnie zaplanować. Inaczej okaże się, że zadania nas przerosną, a my wciąż nie będziemy widzieć końca i projekt zawiesimy. Planowanie jest wręcz niezbędne przy dużych aplikacjach, których złożoność rośnie wraz ze wzrostem kodu. Jeśli nie opracujemy odpowiednich mechanizmów, w końcu problem nas przerośnie, a całość nie będzie w stanie efektywnie realizować swoich zadań.

Plan naszej aplikacji składa się z dwóch lub trzech części. Pierwsza opisuje, jakie zadania mamy do wykonania i co konkretnie musi umieć realizować nasz projekt. W drugiej zajmujemy się sprawami technicznymi: opracowujemy strukturę kodu, wybieramy bazę danych oraz dodatkowe biblioteki. Opcjonalnie wykonujemy także schematy menusów i przejść między poszczególnymi ekranami. Czasami wszystko to może wydać się odrobinę nużące, ale procentuje w przyszłości łatwością rozbudowy kodu. Dobrze zaplanowana struktura ma jeszcze jedną zaletę: przenośność. Jeżeli zajmujesz się wykonywaniem aplikacji WWW na zamówienie, cecha ta powinna mieć dla Ciebie znaczenie pierwszorzędne. Zamiast pisać wszystko za każdym razem od nowa, dobierasz sobie elementy z twojego zestawu bibliotek, a czasem bierzesz cały poprzedni projekt i zmieniasz tylko to, co jest niezbędne. Zaoszczędza to czasu oraz pozwala uniknąć błędów. Pracuję w ten sposób już dość długo i jestem zadowolony z efektów. Nie zmagam się w każdym projekcie z tworzeniem nowego silnika i opracowywaniem części ekranów. Mój kod jest oparty o programowanie obiektowe, zatem nietrudno dodać do niego inne elementy. Ponadto korzystam z technologii szablonów oraz dbam o możliwości personalizacyjne. To pozwala mi na szybkie dostosowywanie kodu do potrzeb i dostarczenie go do klienta.

Po omówieniu na przykładzie zalet planowania przejdziemy do konkretów. Opiszemy sobie wszystkie etapy wraz z niewielkimi przykładami.

Określanie celu prac

Pierwszym zadaniem jest określenie celu prac oraz kroków na drodze do niego. Wyszczególniamy wszystko, co aplikacja będzie realizowała w formie listy wypunktowanej. Poprzez zagłębianie tworzymy już teraz pierwszy system zależności między elementami. Oto przykładowy spis zadań dla projektu blogu internetowego.

Cel: blog internetowy na użytek prywatny
Czas: nieokreślony
Priorytety: ewentualna późniejsza łatwość rozbudowy
Zadania:
1. Część zewnętrzna
a) Wyświetlanie listy wpisów (tytuł+wstęp)
- Powiadamianie o nowych wpisach: e-mail, jabber
b) Widok szczegółowy wpisu: tytuł+wstęp+dalsza część
c) Możliwość komentowania wpisów
- Powiadamianie o nowych komentarzach: e-mail, jabber
d) Linki do polecanych stron
e) Wyszukiwarka
f) Archiwum
g) System RSS
2. Część administracyjna
a) Logowanie na hasło
b) Dodawanie, edycja, usuwanie wpisów
- Formatowanie wiki
- Generowanie nowych RSS
c) Edycja, usuwanie komentarzy
d) Dodawanie, edycja, usuwanie linków do polecanych stron
e) Konfiguracja strony: zmiana hasła, tytułu, słów kluczowych
f) Proste zarządzanie bazą danych
- Eksport
- Optymalizacja
- Naprawa

W ten sposób wiemy dokładnie, co chcemy pisać. Listę taką można sporządzić na papierze, na którym łatwo jest śledzić postęp prac. Wykonane podzespoły po prostu odfajkowujemy i już jesteśmy w każdej chwili zorientowani, na czym stoimy.

Warto zwrócić uwagę na dwie pierwsze linijki, to jest "Cel" i "Czas". W pierwszym wspominamy, że piszemy tę aplikację na użytek prywatny. Ma to znaczący wpływ na dalsze etapy, bowiem możemy pozwolić sobie na pewne braki konfiguracyjne, które wbudujemy bezpośrednio w kod lub które zmieniać będziemy bezpośrednio w bazie. Zwracam uwagę na słowo "możemy", a nie "musimy". Jeżeli mamy chęci, nic nie stoi na przeszkodzie, aby zbudować w pełni funkcjonalny panel. Nieokreślony czas pracy informuje nas, że nie trzeba nam martwić się o terminy. Po prostu kiedy zrobimy, wtedy będzie.

Lista zadań odpowiada strukturze serwisu: główne punkty to "Część administracyjna" i "Część zewnętrzna". Każda z nich rządzi się własnymi prawami i należy wypisać, co dokładnie obie będą potrafiły. Do niektórych zadań dodane są kolejne podpunkty. Wyszczególniają one, na co musimy zwrócić uwagę w tym momencie. Dzięki takiemu ujęciu sprawy wiemy, że generowanie nowych RSS'ów zachodzi przy zarządzaniu wpisami, a one same korzystają z formatowania wiki.

Kolejną rzeczą wartą wzmianki jest określenie, jakie dane chcemy gromadzić we wpisach oraz komentarzach. Czy linki będą miały opisy? Czy jest przewidziana rubryka na przypisy? Jakie dane będzie musiał podać internauta przy dodawaniu komentarza? Na takie właśnie pytania musimy odpowiedzieć.

1. Wpisy:
- Tytuł
- Data dodania: dokładna oraz sam miesiąc i rok dla archiwum
- Wstęp
- Dalsza treść - pokazuje się przy widoku szczegółowym wpisu pod wstępem
- Przypisy - dodatkowe linki związane z treścią wpisu
- Opublikowany - Nieopublikowane wpisy widoczne są w panelu administracyjnym, lecz nie pokazują się na stronie.
Są to wersje robocze
2. Komentarze:
- Nick autora - niezbędny
- E-mail autora - niezbędny
- Adres IP autora - zbierany automatycznie
- Strona WWW autora - opcjonalna
- Treść - min. 10 znaków
3. Linki:
- Nazwa
- Adres URL
- Opis - pokazuje się przy przytrzymaniu myszy nad linkiem
4. RSS:
- Tytuł
- Wstęp
- Data
- Adres do wpisu na stronie

Teraz wiemy już, jakie zbiory danych wezmą udział w naszym projekcie. Spis zawiera także niektóre informacje o poszczególnych polach. Dla wpisów są do dodatkowe definicje mówiące o przeznaczeniu każdego z nich. Przy komentarzach z kolei skupiliśmy się na tym, czy taką informację internauta musi podać, czy też skrypt automatycznie ją zbierze.

W analogiczny sposób możemy określać kolejne podzespoły takie, jak szczegóły formatowania Wiki, czy powiadamiania użytkowników. Im więcej rzeczy wypiszemy, tym jaśniejszy będziemy mieli obraz sytuacji. Podane przykładowe schematy niekiedy trzeba będzie zastosować inaczej. Jeżeli np. nasza aplikacja będzie zezwalała na dodawanie i edycję nowych części serwisu, zestawienie trzymające się sztywnego przedziału nie będzie miało racji bytu, a my będziemy musieli wymyślić jakiś inny sposób zapisania wszystkiego.

Planowanie kodu

To jest najważniejsza część prac. Im lepiej zaprojektujemy strukturę naszego kodu, tym dłużej będzie on nam służyć i tym lepiej będzie spełniał powierzone mu zadanie. Pierwszą rzeczą jest oczywiście wybór oprogramowania, na którym będziemy pracować. Jako że zdecydowana większość czytelników Webcity zna PHP, na nim też się skoncentruję. Pierwszą sprawą jest wersja samego PHP. Czasem jest to uzależnione od możliwości finansowych i providera, lecz gdy mamy wybór, musimy go dokładnie przemyśleć. PHP 5 posiada naprawdę niezły system programowania obiektowego, który ułatwia prace przy złożonych serwisach oraz dla którego łatwo projektuje się kod. Z drugiej strony wciąż nie wszyscy providerzy go oferują, a stare biblioteki niekoniecznie muszą z nim współpracować. Gdybyśmy jednak zamierzali pomóc sobie kompletnym gotowym rozwiązaniem (framework, MVC itd.), zapewne stanie się on niezbędny, bowiem programiści pracujący nad takimi rzeczami tłumnie przenoszą się na tę właśnie wersję z powodu jej możliwości. PHP 4 nie ma aż takiej piorunującej oferty, lecz w tym przypadku możemy być pewni ponad 4-letniego cyklu rozwojowego, a także kompatybilności wszystkich pomniejszych i starszych bibliotek. Ograniczamy sobie jednak ewentualny dostęp do wszelkiej maści frameworków. W parze z wyborem odpowiedniej wersji idzie także dylemat: pisać wszystko samodzielnie, czy też (i na ile) posiłkować się gotowymi bibliotekami? Biblioteki mają to do siebie, że możemy za ich pomocą realizować bardziej egzotyczne rzeczy, np. łączyć się z usługami sieciowymi, czy wysyłać powiadomienia na Jabbera. Musimy jednak brać poprawkę, że niekoniecznie muszą one w pełni odpowiadać naszym potrzebom.

Dwie najprzydatniejsze biblioteki to system szablonów oraz sterownik bazy danych (albo inaczej warstwa abstrakcji bazy danych. Tworzą one coś w rodzaju bufora między naszym skryptem, a elementami, których dotyczą i pozwalają na znaczną automatyzację prac. Dzięki szablonom oddzielimy kod HTML od PHP, a sterownik wykona za nas najbardziej żmudne zadania: kontrolę błędów zapytań, cache'owanie itd. Problem polega na tym, czy skorzystamy z własnych bibliotek, czy z gotowych. O ile w systemach szablonów do wszelkich bardziej zaawansowanych problemów raczej nie mamy wyjścia i musimy wybrać coś gotowego, o tyle napisanie całkiem sprawnego sterownika nie jest rzeczą aż tak trudną i warto się na nie zdecydować.

Kolejna kwestia dotyczy właśnie bazy danych, a konkretniej oprogramowania, na którym ją postawimy. Jeżeli nie ogranicza nas hosting, zazwyczaj do wyboru mamy MySQL w wersjach 4.0 lub 4.1, PostgreSQL i ew. SQLite. Każda z nich ma swoje wady i zalety, które warto poznać i zastanowić się, czy będą nam one przeszkadzać, czy pomagać w realizacji celów. MySQL jest bardzo szybki, a w sieci jest duża liczba materiałów pomocniczych. PostgreSQL ma potężne możliwości. SQLite jest ultra szybki, lecz bazę trzyma w plikach i nie da się w nim zrobić bardziej zaawansowanych rzeczy. Do wyboru, do koloru.

Najlepszą metodą zakodowania dużej aplikacji jest wykorzystanie programowania obiektowego. Jest ono intuicyjne z tego powodu, że odpowiada ludzkiemu sposobowi myślenia i klasyfikowania różnych rzeczy. Szczegółowy poradnik odnośnie jego użycia znajduje się w artykułach "Programowanie obiektowe w PHP 5". Pierwszą rzeczą wymagającą rozstrzygnięcia są wzorce projektowe. Ogólnie rzecz biorąc są to sprawdzone schematy realizowania różnych zadań przy użyciu OOP. Wielu programistów je wręcz chołubi i stosuje je na potęgę. Ja, jako umiarkowany ich zwolennik, proponuję inne podejśce: zastanowić się, które z nich naprawdę nam się przydadzą. Niektóre ze wzorców są naprawdę rozbudowane i często wiele ich założeń jest nam niepotrzebnych. Tutaj zwracam uwagę, aby konsekwentnie trzymać się wyboru. Jeśli zdecydowałeś się na singletony, operuj na nich i nie pracuj przy pomocy instrukcji global.

Do wzorców dołączamy klasy, które są specyficzne dla naszego projektu. Zastanówmy się, które elementy możemy jeszcze odwzorować za ich pomocą. Każda podstrona, oprócz zawartości specyficznej dla niej, wyświetla także elementy stałe typu "nagłówek" i "stopka". Możemy zatem utworzyć klasę "widok", której zadaniem będzie właśnie ich generowanie. Ponadto umożliwi nam ona ustawienie tytułu strony oraz dostarczy funkcji do szybkiego wysyłania na ekran komunikatów w stylu "Podany wpis nie istnieje."

<?php
 
class widok
{
private $title;
private $template;
 
// ustawia szablon HTML
public function setTemplate($template)
{
$this -> template = $template;
} // end setTemplate;
 
// ustawia tytul strony
public function setTitle($title)
{
$this -> title = $title;
} // end setTitle;
 
// wyswietla naglowek i stopke wokol podanego szablonu
public function display()
{
$tpl = template::getInstance();
$tpl -> assign('title', $this -> title);
$tpl -> parse('naglowek.tpl');
$tpl -> parse($this->template);
$tpl -> parse('stopka.tpl');
} // end display();
 
// obsluguje komunikaty
public function message($msg)
{
$this -> template = 'message.tpl';
$tpl = template::getInstance();
$tpl -> assign('msg', $msg);
$this -> display();
die();
} // end message();
}
?>

Inne elementy, które można zrealizować przy pomocy klas:

  1. Sterownik bazy danych - to w zasadzie nie podlega dyskusji. OOP jest najwygodniejszy. Tworzymy jedną klasę reprezentującą połączenie i drugą dla zbioru wyników. Szczegóły w artykule "Sterownik bazy danych".
  • System szablonów - OOP jest wygodny także w tym przypadku. Przykłady w innych artykułach na Webcity.
  • Kontrola danych wejściowych - patrz: artykuł o podobnym tytule
  • Zbieranie danych o internaucie - tworzymy klasę "visit", która zbiera i udostępnia dane o np. adresie IP, z którego nadeszło żądanie, przeglądarce użytkownika itd.
  • Konfiguracja - zbieranie i udostępnianie danych konfiguracyjnych
  • Router - odpowiada za generowanie adresów URL. Routerów może być kilka, z czego każdy będzie je tworzył na trochę inny sposób, a każda podstrona naszej aplikacji będzie mogła decydować o tym, który weźmie.

Przy pomocy klas możemy również odwzorować same rodzaje danych w naszym projekcie, tworząc tzw. DAO (Data Access Objects). Pojedyncza klasa reprezentuje wpis w blogu. Posiada pola takie same, jak on w bazie, a także kilka metod pomagających zarządzać nim:

class note
{
public $title;
public $intro;
public $body;
public $published;
public $date;
 
public function addNote()
{
// dodaj wpis, korzystajac z danych wprowadzonych w powyzsze pola
} // end addNote();
 
public function editNote($id)
{
// zmien wpis, korzystajac z danych wprowadzonych w powyzsze pola
} // end editNote();
 
public function removeNote($id)
{
// usun wpis o podanym ID
} // end removeNote();
}

Podobną rzecz możemy stworzyć dla linków i komentarzy. DAO ma taką zaletę, że odpowiednio zaprojektowane pozwala na błyskawiczne wręcz tworzenie stron administracyjnych. Swego czasu stworzyłem pewien silnik, w którym dodanie nowego ekranu w administracji zajmowało dwie minuty. Odbywało się to na zasadzie: wybierz szablony, wybierz nazwę strony, wprowadź nazwę pliku oraz nazwę klasy DAO. Klucz do sukcesu polegał na tym, że wszystkie klasy DAO miały metody o identycznych nazwach: "addItem()", "editItem()". Różniły się jedynie ich zawartością, ale w ten sposób przy zmianie danych, na których strona operowała, nie musiałem tychże nazw podmieniać w całym kodzie. Uzyskałem to dzięki wcześniejszemu dobremu zaplanowaniu struktury i działania mojej aplikacji.

W sprawie kodu pozostały nam jeszcze dwie rzeczy do określenia: zależności między elementami oraz styl kodowania. Zaczniemy od tych pierwszych. Rzadko kiedy (czyt: nigdy) zdarza się, że silnik składa się z niepowiązanych ze sobą elementów. Między nimi istnieją pewne zależności, które powinniśmy uwzględnić już na tym etapie prac. Oto przykład: system dzielenia listy wyników na strony musi tworzyć linki do poszczególnych stron, zatem jest zależny od routera. Można to ukazać następująco:

System dzielenia na strony.
a) Wymaga:
- Router - tworzenie adresów URL
- System kontroli danych - pobieranie informacji o tym, która strona jest przeglądana

Przejdźmy teraz do systemu kontroli danych. Operuje on na danych, gdy te leżą już spokojnie w tablicach $_POST i $_GET, ale przy niestandardowych adresach trzeba je najpierw tam wsadzić. Stąd też potrzebny nam będzie router, który odczyta z adresu URL parametry i je tam przeniesie.

System kontroli danych.
a) Wymaga:
- Router - odbieranie danych z adresu

Zauważ jedną rzecz: opracowując system zależności otrzymamy w końcu schemat, jak nasza aplikacja powinna działać, tj. które elementy powinny być uruchamiane w jakiej kolejności. Dodatkowo wiemy, w jakiej kolejności mamy je w ogóle pisać!

Ostatnią rzeczą jest wybór stylu kodowania, tj. sposobu zapisu nazw, klamer, nawiasów. O ile przy samodzielnym projekcie zwykle zastosujesz taki, do którego przywykłeś, o tyle przy projektach zbiorowych trzeba iść na kompromis. Ponownie podkreślam: trzymaj się konsekwentnie wyboru. Jeżeli ustaliłeś, że wszystkie nazwy i identyfikatory tworzysz w języku angielskim w formacie "nazwaNazwa", a nie "nazwa_nazwa", to pisz tak i tylko tak. Niech w twoim kodzie nie pojawia się żaden inny sposób. Najgorzej jest szczególnie, gdy wymieszasz ze sobą języki. Ta sama rada tyczy się w ogóle całego procesu projektowania.

Schematy

W ostatnim etapie planowania chodzi o zaprojektowanie układu formularzy oraz sposobu przemieszczania się między nimi. Robi się to dość prosto. Bierzemy arkusz papieru i ołówek. Rysujemy na nim niewielki prostokącik odpowiadający np. liście i rysujemy tam schematycznie zawartość ekranu, dodatkowo ją opisując. Podkreślamy linki i inne elementy służące nawigacji, po czym prowadzimy od nich strzałki do innych ekranów, opisując przy tym ich wymagania. Tak powstaje nawigacja po twoim serwisie. O ile większość podstron szczególnie w administracji dysponuje bardzo podobnym schematem, o tyle niektóre nietypowe problemy wymagają przemyślenia tych kwestii. Zostawianie tego na ostatnią chwilę sprawi, że otrzymasz niewygodny skrypt zarządzający jakimś elementem i ty, albo użytkownik, będziecie niezadowoleni.

Przy tej okazji możemy pokusić się o określenie dostępu do poszczególnych części. Bierzemy w tym celu jakiś kolorowy przyrząd rysujący. Zawieramy część ekranów wewnątrz obszaru ograniczonego linią przerywaną, po czym podpisujemy, kto będzie miał do danej sekcji jaki dostęp. Pozwoli to na uniknięcie nielogiczności w stylu: "tutaj do edycji wymagane są dodatkowe uprawnienia, a tam w analogicznym elemencie nie. Co jest?"

Zakończenie

Era, gdy kod serwisu pisało się ciurkiem bez żadnego podziału na funkcje itd. minęła bezpowrotnie. Obecnie ktoś, kto tworzy strony w ten sposób i twierdzi, że jest profesjonalistą, naraża się jedynie na śmieszność. Od kodu wymaga się elastyczności, automatyzacji czynności oraz pomocy programiście poprzez odpowiednio zaprojektowane biblioteki. Z kolei aplikacje pisane w szczególności dla klientów muszą mieć logiczną i jednolitą strukturę, bez niekonsekwencji. Nie da się tego osiągnąć bez jakiejś formy planowania. Z pierwszymi planami zejdzie Ci trochę czasu, gdyż musisz nabrać trochę wprawy. Po pewnym okresie, gdy wypracujesz już pewne schematy realizowania niektórych problemów, będziesz mógł pomijać niektóre fazy. Mogę to zagwarantować, bowiem sam postępuję w ten właśnie sposób. Mam z dawna utrwalone wzorce tworzenia np. silników stron WWW oraz samych podstron. Wszystko znajduje się w mojej głowie, co oznacza, że od razu mogę przystąpić do pracy. Plan (a także sporą część kodu, hehe :)) przecież opracowałem już dawno temu, teraz tylko realizuję go po raz n-ty. Projektowaniu podlegają jedynie elementy nowe oraz wykaz czynności, które aplikacja musi umieć spełniać. Mimo wszystko to właśnie dzięki tej swoistej formie planowania odniosłem sukces.

Autor: Tomasz "Zyx" Jędrzejewski, www.zyxist.com

 

Źródło: http://webcity.pl/webcity/planowanie_aplikacji_www

Licencja: Creative Commons - użycie niekomercyjne - bez utworów zależnych