Miesiąc temu zajmowaliśmy się konstruowaniem i oceną algorytmów, czyli metod rozwiązywania zadań. Jeśli ktoś z was miał problemy z zapisaniem podanych algorytmów w postaci programów, to może pomogą w tym szkice programów realizujących podane miesiąc temu metody.
Jakie wnioski możemy wyciągnąć? Jeśli dwa programy napisane są w tym samym języku i działają na takim samym komputerze, w identycznych warunkach, to decydującym czynnikiem określającym czas działania jest algorytm każdego z tych programów. Inaczej mówiąc, szybkość działania programu zostaje wstępnie określona jeszcze przed napisaniem pierwszej instrukcji - poprzez wybór metody rozwiązania. Co dalej? Ano to, że warto docenić rolę algorytmu, a więc także rolę i znaczenie przygotowania przemyślanego projektu programu zanim zaczniemy pisać sam program. Warto wreszcie, gdy już wymyślimy metodę rozwiązania zadanego problemu, zastanowić się, czy jest to metoda wystarczająco efektywna, czy też raczej należy próbować znaleźć jakiś lepszy sposób.
Tutaj niewielka dygresja. Wśród informatyków zawodowych samo zapisanie gotowego algorytmu w postaci programu nie jest zwykle uważane za największy problem. Ten etap często nazywany jest "kodowaniem", a przecież kodowanie w swoim typowym znaczeniu to czynność prawie mechaniczna, nie wymagająca wiele myślenia. Mamy tutaj do czynienia ze świadomym i celowym oddzieleniem czynności opracowania (wymyślenia nowego lub wybrania kilku istniejących i opublikowanych) algorytmu od czynności zapisania tego algorytmu we właściwym języku programowania. U początkujących programistów jedną z przyczyn trudności jest to, że zaczynają pisać program niezbyt dokładnie wiedząc jakie czynności musi ten program wykonać, żeby otrzymać rozwiązanie. Na to nakłada się słaba znajomość konstrukcji języka i w rezultacie napisanie nieskomplikowanego programu zaczyna stwarzać duże problemy. Skoro już była mowa o "zawodowcach", warto dodać że istnieje wiele publikacji zawierających właśnie opisy znanych algorytmów rozwiązywania typowych, spotykanych w codziennej praktyce zadań, a ambicją wielu autorów jest wymyślenie algorytmu rozwiązującego jakiś konkretny problem szybciej niż wszystkie inne znane do tej pory metody.
Ale wróćmy do naszego głównego wątku. Ustaliliśmy, że gdy komputer i język są już ustalone czas działania programu zależy przede wszystkim od metody rozwiązania problemu. W tej sytuacji nie ma się co łudzić, że radykalnie skrócimy czas działania programu stosując różne dziwne sztuczki, np. stosowanie zmiennych o możliwie najkrótszych nazwach (dotyczy to tych interpreterów BASIC-a, które dają do dyspozycji nazwy wieloznakowe), czy też usuwanie z programów komentarzy. Tak naprawdę, to wśród krążących między mikrofanami metod na przyśpieszenie działania programów nastąpiło przemieszanie pomysłów wartościowych z pomysłami przypominającymi spluwanie przez lewe ramie i wymawianie magicznych zaklęć, np. obecność komentarzy może mieć naprawdę znaczący wpływ tylko na wielkość programu, ale nie na czas jego działania.
Dlaczego tak zdecydowanie wypowiadam się przeciwko, ogólnie mówiąc sztuczkom, czy nie można ich stosować równolegle z wyborem efektywnego algorytmu? Otóż dlatego, że ogromna większość tych "sposobów" powoduje znaczne zmniejszenie czytelności tekstu programu dla człowieka. A to z kolei znacznie zwiększa nakład pracy potrzebny na zrobienie czegokolwiek z programem - znalezienie w nim błędu, wprowadzenie modyfikacji itd. Inaczej mówiąc, zyskujemy troszkę czasu na skróceniu działania programu, ale za to stracimy go dużo więcej przy okazji pracy z programem. Spróbujcie sobie uświadomić, ile razy programista musi przeczytać tekst dużego programu podczas jego uruchamiania. To, że programy są czytane nie tylko przez komputery, ale również (a może nawet przede wszystkim) przez ludzi jest oczywiste chyba dla wszystkich. Wynikający z tego faktu, równie oczywisty wniosek, że programy należy pisać tak, by ludzie mieli jak najmniej kłopotów z ich odczytywaniem jest niestety przez wielu programistów ignorowany. Powiedzmy to sobie szczerze i brutalnie, dotyczy to przede wszystkim programistów słabych.
Aby zademonstrować różnicę w odbiorze tekstu jaką może spowodować różny sposób zapisu, starałem się odpowiednio "preparować" teksty algorytmów i programów zamieszczonych w tym artykule. Efekt pozostawiam Wam do oceny i ewentualnie jako materiał do wyciągnięcia własnych wniosków.
Świetnie, powie ktoś, moje programy piszę sam i sam je czytam, poza tym doskonale wiem, co jest w którym miejscu, nawet bez komentarzy i niezależnie od układu graficznego tekstu. Na pewno jest to prawdą dla programistów małych, ale czy rzeczywiście można łatwo zapamiętać wszystkie szczegóły programu mającego kilkaset czy nawet kilka tysięcy linii? Poza tym pamiętajmy, że czasami trzeba wrócić do programu po dłuższej przerwie. Czy za rok nie dojdziesz do wniosku, że jakiś program warto przerobić? I czy przypadkiem nie okaże się wtedy, iż jest on napisany tak, że zupełnie nie widać co się w nim dzieje.
Zbliżyliśmy się w ten sposób do problemu tzw. dokumentacji technicznej, czyli opisu tworzonych programów. Nie będziemy rozwijać tego tematu, gdyż od amatorów programujących dla przyjemności nikt takiej dokumentacji nie będzie wymagał (od zawodowych programistów jest ona wymagana). Może jednak pisząc duży program warto zrobić kilka stron notatek - na pewno przydadzą się w przyszłości. Zwróćmy wreszcie uwagę, że najprostszą formą takiej dokumentacji - opisu działania programu są właśnie komentarze. Ich dodatkową zaletą jest to, że dopóki mamy tekst programu nie mogą nam zginąć, no i zawsze są pod ręką gdy czytamy program. Pamiętajmy tylko, że jeśli wprowadzamy zmiany do programu, część komentarzy może stać się nieaktualna i zamiast pomagać, będzie wprowadzać w błąd. Czyli, zmieniając program zmieniamy również komentarze - od razu, a nie kiedyś później!
Pisanie dobrych komentarzy, krótkich a równocześnie treściwych i zrozumiałych nie tylko dla autora jest rzeczą trudną - trzeba się tego uczyć tak jak dobrego programowania. Najlepiej zacznij już od dziś.
Jak wspomniałem, pisanie programów w sposób czytelny nie ma większego wpływu na szybkość jego działania, może natomiast zwiększyć ilość zajętego przez program miejsca. Co robić, gdy miejsca zaczyna brakować. W większości wypadków wyjście jest następujące: znaczną część miejsca w programie zajmują dane, np. tablice, bardzo długie zmienne tekstowe itp. Na ogół do testowania programu pełna wielkość obszarów danych nie jest potrzebna, co pozwala uzyskać dodatkowe miejsce na dłuższy program. Po ostatecznym przetestowaniu wersję z komentarzami zapisujemy do archiwum - bo może jeszcze kiedyś się przyda, natomiast z wersji roboczej usuwamy komentarze, uzyskując dodatkowo miejsce w pamięci. Możemy to zrobić na spokojnie, bo od tej pory tę wersję programu będzie czytał tylko komputer, który komentarze i tak ignoruje.
Teraz szata graficzna programu. Trudno ustalić jednoznacznie kryteria rozmieszczenia tekstu, zapewniające jego największą czytelność, gdyż zależy tutaj od indywidualnych upodobań, jednak wieloletnia praktyka wykazuje, że są pewne typowe rozwiązania. Można tu zaliczyć:
- Umieszczenie instrukcji zmieniających sterowanie w programie (instrukcje warunkowe, pętle) jako pierwszych instrukcji w linii.
- Tzw. wcięcia, czyli dodanie przed każdą instrukcją pętli kilku spacji. Powoduje to, że zawartość pętli jest na wydruku przesunięta w prawo, przez co wyróżnia się z treści programu. To samo dotyczy instrukcji wykonywanych warunkowo - zawartych wewnątrz IF THEN
- Oddzielanie od siebie fragmentów programu realizujących odrębne funkcje. np. pustą linią, lub rzędem gwiazdek.
- Używanie nazw mnemotechnicznych, tzn. kojarzących się z zawartością nazywanego obiektu (nie na wszystkich mikrokomputerach dysponujemy nazwami o długości odpowiedniej do tego celu).
Nie ma w tej dziedzinie jednolitego, zaakceptowanego przez absolutnie wszystkich standardu, jednak powyższe zasady są akceptowane dość powszechnie i dobrze byłoby nie oddalać się od nich zbyt daleko.
Pora na małe podsumowanie. Nie namawiałem nikogo do pisania nieefektywnych programów, chciałem tylko wskazać gdzie należy szukać, efektywności, gdzie zaś oszczędności nie należy robić, gdyż mogą to być oszczędności nieopłacalne. Równocześnie musimy sobie zdawać sprawę, że wybór algorytmu i czytelny zapis to tylko część składników określających jakość programu. pozostałymi zajmiemy się w niedalekiej przyszłości.
0001 REM realizacja algorytmu 1 0010 DIM T%(1000): PRINT "Długość tekstu" 0015 INPUT N: FOR I=1 TO N 0020 T%(I)=32: NEXT: FOR I=1 TO N STEP 2 0030 T%(I)=100: NEXT: GOSUB 1000: I=1 0040 IF I=N GOTO 100 0050 IF T%(I)<>32 GOTO 0090 0055 FOR J=I+1 TO N 0060 T%(J-1)=T%(J): NEXT 0070 N=N-1 0080 GOTO 0040 0090 I=I+1: GOTO 0040 0100 GOSUB 1000 0110 END 1000 FOR I=1 TO N: PRINT T%(I): NEXT 1010 RETURN 0010 REM realizacja algorytmu 2 0020 DIM T%(1000) 0021 REM do testowania wykorzystujemy 0022 REM początkowy fragment tablicy T 0023 REM o długości N, którą wczytamy: 0024 PRINT "Podaj długość tekstu " 0025 INPUT N 0030 REM wypełniamy tablicę spacjami - 0040 REM dane do testów 0050 FOR I=1 TO N 0060 T%(I)=32 0070 NEXT 0080 REM wstawienie znaków innych niż 0090 REM spacja pozwoli sprawdzić program 0100 FOR I=1 TO N STEP 2 0102 T%(I)=100 0105 NEXT I 0160 GOSUB 1000: REM wyświetl. danych 0170 REM *********************** 0180 REM ** zaczynamy program ** 0190 I=1 0200 REM szukamy pierwszej spacji 0210 IF T%(I)=32 GOTO 0260 0220 I=I+1 0230 GOTO 0210 0240 REM spacja znaleziona, 0250 REM ustawiamy w1 i w2 0260 W1=I 0270 W2=I 0280 REM pętla przeglądania tekstu 0290 IF W2=N+1 GOTO 0370: REM 0370=koniec 0300 W2=W2+1 0310 IF T%(W2)=32 GOTO 0290 0320 REM tu w2 wskazuje niespacje - 0330 REM przepisanie znaku 0340 T%(W1)=T%(W2) 0350 W1=W1+1 0360 GOTO 0290: REM na początek pętli 0370 N=W1-1 0380 GOSUB 1000: REM wyświetl. wyników 0390 END 1000 REM ************************* 1005 REM procedura wydruku tablicy 1010 PRINT "TABLICA T%" 1040 FOR I=1 TO N 1050 PRINT T%(I) ","; 1060 NEXT I: PRINT " " 1070 RETURN
Andrzej Pilaszek - Bajtek 05/1987r.