![]() |
Turbo Pascal.
|
Jak to się robi naprawdę?
Rozdział ten stanowi rozszerzenie poprzedniego i wcale nie musisz go czytać, chociaż może Ci się to przydać. Dowiesz się z niego, jak wyglądają poszczególne kroki procesu programowania i co oznaczają takie pojęcia jak algorytm, schemat blokowy czy projekt. Poznasz również kilka metod i wskazówek pozwalających na usystematyzowanie i uproszczenie pracy.
Problem
Programowanie nie istnieje samo dla siebie: aby w ogóle miało ono sens, musi służyć konkretnemu celowi. Przyczyną utworzenia programu musi być problem, który masz rozwiązać. Oczywiście, nie każdy problem da się rozwiązać w ten sposób, nie każdy też wymaga zastosowania komputera. Co więc kwalifikuje problem do zaprogramowania?
- Zastosowanie komputera do rozwiązania problemu powinno być uzasadnione i opłacalne. Pisanie na użytek domowy programu pozwalającego na zapamiętywanie adresów znajomych jest stratą czasu - prościej to zrobić za pomocą notesu. Inaczej wygląda sprawa w banku, w którym obsługuje się setki klientów, a od czasu do czasu trzeba wysłać do wszystkich np. zawiadomienie o stanie rachunku.
- Szczególnie podatne na zaprogramowanie są zadania wykonywane wielokrotnie lub złożone z ciągu powtarzających się czynności. Pisanie "do jednorazowego użytku" programu wykonującego zestaw skomplikowanych obliczeń na ogół mija się z celem, gdyż można je wykonać na kalkulatorze. Co innego, gdy przewidujesz możliwość wielokrotnego wykorzystania takiego programu.
- Problem powinien być dobrze określony. Oznacza to, że musisz dokładnie wiedzieć, jakie informacje masz do dyspozycji i co chcesz uzyskać, a także potrafić zapisać to w formie dającej się "wytłumaczyć" komputerowi. Przykładem problemu źle określonego może być "rozwiązanie zadania z fizyki", gdyż nie wiadomo ani jakimi informacjami dysponujemy, ani co chcemy właściwie obliczyć. Prawidłowe określenie zadania miałoby postać np. "wyznaczenie drogi przebytej przez ciało w spadku swobodnym w pierwszych 10 sekundach ruchu". Przy okazji mamy tu nawiązanie do poprzedniego punktu: te same obliczenia trzeba wykonać dziesięciokrotnie (dla 1, 2, 3,..., 10 sekund).
Problem przeznaczony do rozwiązania powinien być jasno zdefiniowany i wystarczająco złożony, by trud włożony w programowanie mógł się opłacić. Metoda
Po ustaleniu co chcesz osiągnąć i jakimi informacjami dysponujesz, musisz ustalić sposób rozwiązania problemu. Niekiedy (jak w przypadku spadku swobodnego) sytuacja jest oczywista: należy zastosować wzór, który ktoś kiedyś wymyślił. Kiedy indziej trzeba wymyślić rozwiązanie samemu. Warto również zastanowić się nad przyjęciem założeń upraszczających, które mogą zmniejszyć nakład pracy potrzebny na stworzenie programu z niewielkim uszczerbkiem na dokładności.
Przykładem niech będzie wspomniana w poprzednim rozdziale kwestia wyznaczenia średniej długości zdania w tekście. Problem nie jest wcale wzięty "z sufitu": zarówno zbyt krótkie, jak i zbyt długie zdania zmniejszają czytelność tekstu, aby więc nie znudzić czytelnika, musisz trzymać się pewnego optimum, wynoszącego np. 60 znaków. Oto kilka konkurencyjnych rozwiązań tego problemu:
- ustalamy liczbę znaków zawartych w każdym zdaniu w tekście, po czym uzyskane wartości uśredniamy. Metoda ta jest dość oczywista, jednak wymaga określenia ścisłej definicji zdania, co może być kłopotliwe;
- przyjmujemy upraszczające założenie, że każde zdanie kończy się kropką. W tym momencie liczba zdań w tekście równa będzie liczbie kropek (co dla tekstów literackich jest w zasadzie prawdziwe). Zatem wystarczy zliczyć wszystkie znaki w tekście, ustalić, ile jest wśród nich kropek, podzielić pierwszą wartość przez drugą i wynik gotowy
Najlepszą metodą na znalezienie metody jest sprawdzenie, czy ktoś jej już nie wymyślił. Po ustaleniu metody warto też zastanowić się nad jej uproszczeniem. Algorytm
Skoro już mamy metodę, musimy zapisać ją w sposób formalny i szczegółowy. Po co? Komputer nie jest niestety na tyle inteligentny, by zrozumieć polecenie "zlicz wszystkie znaki w tekście"1, toteż musimy nasze zadanie przedstawić w sposób bardziej elementarny. Jak? Właśnie za pomocą algorytmu.
Zgodnie z definicją, algorytm to "zbiór określonych reguł postępowania, które realizowane zgodnie z ustalonym porządkiem umożliwiają rozwiązanie określonego zadania". Przekładając to na bardziej ludzki język możemy powiedzieć, że algorytm jest zapisem czynności, które należy krok po kroku wykonać w celu uzyskania wyniku. Zapisując algorytm musisz więc ustalić, jakie elementarne operacje będzie trzeba wykonać w trakcie realizacji zadania i jaka powinna być ich kolejność. Dodatkowo musisz określić tak zwane kryterium stopu, czyli warunek, którego spełnienie powoduje zakończenie wykonywania operacji (nie chcesz chyba czekać na wynik w nieskończoność).
Jak zapisać algorytm? Najprostszym sposobem jest słowne wyrażenie poszczególnych operacji w postaci punktów, np. tak:
- otwórz plik z tekstem do odczytu
- wyzeruj licznik znaków
- wyzeruj licznik kropek
- jeśli koniec pliku, to idź do punktu 9
- wczytaj kolejny znak z pliku
- jeśli znak jest kropką, zwiększ licznik kropek o 1
- zwiększ licznik znaków
- idź do punktu 4
- jeśli licznik kropek wynosi zero, idź do punktu 11
- wypisz (licznik znaków/(licznik kropek))
- STOP
To samo można przedstawić w postaci graficznej, zwanej schematem blokowym lub z angielska flowchart.
Rysunek 1. Schemat blokowy obliczania średniej liczby znaków w zdaniu
Schemat postępowania można wreszcie zapisać w postaci tak zwanego pseudokodu, czyli imitacji "prawdziwego" języka programowania:
start otwórz(plik); znaki := 0; kropki := 0; dopóki nie koniec_pliku(plik) start czytaj (plik,znak) jeżeli znak = '.' kropki := kropki+1; znaki := znaki+1; stop; wypisz(znaki/kropki); stop. Każda z powyższych metod ma swoje wady i zalety. Zapis poszczególnych kroków w postaci punktów jest prosty, ale przy bardziej złożonych zadaniach staje się mało czytelny. Zapis w postaci schematu blokowego jest bardzo czytelny, ale pracochłonny w wykonaniu. Wreszcie zapis w pseudokodzie ma tę zaletę, że po przetłumaczeniu na język angielski staje się praktycznie gotowym tekstem programu.
W myśl tego, co powiedzieliśmy na zakończenie poprzedniego punktu, nie musisz, a nawet nie powinieneś, wymyślać algorytmu samodzielnie. Jest to co prawda zajęcie bardzo kształcące i przynoszące dużo satysfakcji intelektualnej, jednak często okazuje się, że korzystając z gotowych rozwiązań można zrobić to samo znacznie efektywniej i szybciej. Niektóre problemy są natomiast na tyle nietypowe, iż metodę ich rozwiązania trzeba wymyślić od podstaw.
Omawiając algorytmy nie sposób pominąć kwestii struktur danych. Jest oczywiste, iż rozwiązanie jakiegokolwiek problemu wiąże się z przetwarzaniem informacji. Tę z kolei trzeba jakoś przechować, nie mówiąc już o wprowadzeniu jej do komputera i późniejszym wyprowadzeniu. Komputerowe sposoby reprezentowania informacji są znacznie ściślej określone, a jednocześnie znacznie mniej różnorodne niż te, których używamy na co dzień. W większości przypadków dobór odpowiedniej struktury danych jest automatyczny, gdyż albo narzuca się sam (np. rozwiązując zadanie matematyczne nie będziesz przedstawiał liczb w postaci znakowej), albo jest wymuszony przez algorytm. Czasem jednak sprawa nie jest tak oczywista. Przykładowo, konstruując program zajmujący się przetwarzaniem danych osobowych pracowników możesz zdecydować się na przechowywanie tychże danych w tak zwanych tablicach lub listach. Obydwa rozwiązania mają swoje zalety i wady, jak również wiążą się z zastosowaniem odpowiednich metod przetwarzania danych, czyli właśnie algorytmów.
Projekt
Jak już powiedzieliśmy, algorytm przeznaczony jest do rozwiązania zasadniczej części zadania i "nie przejmuje się" takimi detalami, jak wprowadzenie i wyprowadzenie danych czy utworzenie struktur danych. Na dodatek większość problemów jest na tyle skomplikowana, iż nie daje się rozwiązać za jednym zamachem. W takiej sytuacji musisz rozbić swoje zadanie na mniejsze fragmenty, dające się wyrazić za pomocą prostych algorytmów i uzupełnić ten zestaw przez opis operacji pomocniczych. Wszystko to należy powiązać w spójną całość, zwaną projektem programu.
Projekty mogą być tworzone dwiema przeciwstawnymi metodami, znanymi jako projektowanie wstępujące (ang. bottom-up design) oraz projektowanie zstępujące (ang. top-down design). Pierwsza z nich jest realizacją zasady "od szczegółu do ogółu": na samym początku określamy zestaw elementarnych zadań, których wykonanie będzie konieczne do realizacji głównego problemu (np. wprowadzanie danych, wyprowadzanie wyników, obliczanie wartości pośrednich). Po skonstruowaniu takich cegiełek budujemy z nich większe struktury, zajmujące się przetwarzaniem odpowiednio większych fragmentów zadania, z tych - struktury jeszcze bardziej ogólne, aż w końcu dochodzimy do głównego schematu działania, który zarządza poszczególnymi modułami.
Projektowanie zstępujące, jak nietrudno się domyślać, wygląda odwrotnie. Początkiem procesu jest ogólne sformułowanie zadania, które następnie poddaje się analizie i rozbiciu na współdziałające ze sobą części, te zaś dzieli się dalej aż do uzyskania elementarnych fragmentów, których zaprogramowanie jest już łatwe, a nawet typowe. Jednocześnie na każdym etapie podziału ulegają uściśleniu kompetencje poszczególnych fragmentów programu (a raczej projektu), czyli zakres przetwarzanych przezeń danych i postać zwracanych wyników.
Niezależnie od tego, jaką metodę zastosujesz, efektem projektowania powinno być uściślenie wybranej metody rozwiązania zadania i dostosowanie jej do konkretnych okoliczności i możliwości. Osiąga się to rozbijając zadanie na elementarne składniki, których rozwiązanie zostało już opisane lub jest łatwe do samodzielnego opracowania. Gotowy projekt może przyjąć postać podobną do omawianych przy okazji algorytmów: zapisu słownego lub graficznej reprezentacji ciągu czynności. Odpowiednie zapisanie poszczególnych elementów projektu znacznie ułatwi Ci jego implementację oraz przyszłe wprowadzanie zmian i ulepszeń.
Implementacja
Uff. Przynajmniej w teorii wszystko powinno już działać. Dysponując odpowiednio rozpisanym projektem można przystąpić do mechanicznej w zasadzie czynności programowania. Tak, to nie pomyłka: praktycznie całość pracy umysłowej poświęcanej na rozwiązanie danego zadania poprzez programowanie skupia się w etapach opisanych poprzednio. Samo programowanie (kodowanie) jest jedynie czynnością polegającą na przetłumaczeniu zapisu projektu na odpowiedni zapis symboliczny, czyli tak zwany język programowania (najczęściej wysokiego poziomu).
Zanim do tego dojdzie, możesz jeszcze stanąć przed koniecznością wyboru odpowiedniego języka, czyli narzędzia pracy (zakładając, że masz z czego wybierać, tj. potrafisz się posługiwać kilkoma językami).
Uruchomienie
Uruchamianie świeżo napisanych programów należy do bardziej ekscytujących momentów w życiu programisty. Pełny proces uruchamiania składa się z kilku etapów, które krótko opiszemy poniżej.
Napisany program należy po pierwsze przetłumaczyć na postać wykonywalną przez komputer, czyli (na ogół) skompilować go. Większość narzędzi programistycznych skutecznie wyłapie przy tej okazji wszelkie błędy literowe i składniowe, które miałeś okazję popełnić podczas wpisywania programu (błędy takie zwane są ogólnie błędami kompilacji).
Po wyeliminowaniu wszystkich błędów kompilacji możesz spróbować wykonać program. Przedtem jednak bezwzględnie zapisz go na dysku. W przypadku bardziej skomplikowanych programów efekty pierwszego uruchomienia mogą być dość zaskakujące, z zawieszeniem komputera włącznie: lepiej zapamiętać program, niż narażać się na konieczność odtwarzania części lub całości wyników pracy. Wszelkie błędy, które pojawiają się w trakcie pracy już uruchomionego programu, noszą nazwę błędów wykonania. Błędy te mogą powodować przerwanie działania programu (a nawet zawieszenielub restart komputera) lub jego zachowanie niezgodne z oczekiwaniami (np. brak reakcji na działania użytkownika, zwracanie błędnych wyników). Jeśli program po uruchomieniu zachowuje się w poprawnie (tj. nie zawiesił się, reaguje na próby komunikowania się z nim, zwraca w miarę poprawne wyniki i daje się zakończyć), możesz przejść do jego testowania.
Testowanie programu polega z grubsza na badaniu jego reakcji na różne zachowania użytkownika. Przede wszystkim należy sprawdzić, czy wynik pracy programu jest zgodny z naszymi oczekiwaniami. Jeśli tak, warto spróbować podrzucić mu do przetworzenia inne dane, dla których wynik znamy lub potrafimy obliczyć. Dobór danych do testowania nie powinien być przypadkowy, lecz winien opierać się na przewidywaniu możliwych słabych punktów programu. Przykładowo, jeśli program zajmuje się obsługą kartoteki pracowników, warto sprawdzić jego zachowanie w przypadku niepodania żadnego nazwiska, podania nazwiska dłuższego niż przyjęte maksimum itp. Dobrą metodą jest również testowanie programów przez użytkowników, którzy zwykle nie mają pojęcia o zasadach fair play obowiązujących w programowaniu i potrafią bardzo skutecznie "rozłożyć" programy uważane przez ich twórców za całkowicie bezbłędne. W przypadku uruchamiania bardzo opornych programów nieocenione usługi oddają wreszcie tzw. narzędzia uruchomieniowe, żargonowo zwane debuggerami. Pozwalają one na śledzenie i analizę zachowania programów instrukcja po instrukcji, co umożliwia lokalizację nawet bardzo wyrafinowanych błędów.
Zdrowy rozsądek
Jest on najważniejszym elementem procesu programowania (a dokładniej, jakiejkolwiek działalności praktycznej podejmowanej w życiu). Zastosowanie zdrowego rozsądku w programowaniu sprowadza się przede wszystkim do zachowania odpowiedniej proporcji pomiędzy treścią i formą oraz doboru metod odpowiednich do realizowanych zadań. Aby rozwiązać równanie kwadratowe możesz oczywiście napisać w Borland C++ 5.0 odpowiedni program dla Windows, wykonując uprzednio solidne przygotowanie w postaci schematu blokowego, listy zmiennych i spisu literatury. Możesz również nic nie pisać, a jedynie sięgnąć po kalkulator. W większości przypadków najlepsze jest rozwiązanie kompromisowe, tj. napisanie krótkiego programiku w Turbo Pascalu.
Samo przygotowanie teoretyczne również powinno być traktowane z umiarem. Dobór algorytmu czy opracowanie projektu bardzo często wykonywane są automatycznie, zaś ich rozpisywanie ma na celu jedynie ułatwienie ich zrozumienia i nie powinno być celem samym w sobie. Przeważająca część zadań, które będziesz rozwiązywał, jest na tyle prosta, iż nie wymaga specjalnych przygotowań. Powyższe uwagi powinieneś więc traktować raczej jako sposoby ułatwienia sobie rozwiązywania bardziej złożonych problemów, ewentualnie organizowania pracy zespołowej (o ile masz zamiar zostać zawodowym programistą).
Dysponując tymi wiadomościami możesz już spokojnie przejść do dzieła. W kolejnym rozdziale zapoznasz się z narzędziem, za pomocą którego będziesz tworzył programy.
Przypisy
1. Co prawda niektóre programy, jak np. Word dla Windows, udostępniają polecenie zliczania znaków w tekście, jednak jest ono właściwością programu, nie zaś komputera, i musiało zostać wcześniej zaprogramowane przez twórców edytora. |
|
Poprzedni | Spis treści | Następny | Wersja spakowana |