SlideShare a Scribd company logo
IDZ DO
         PRZYK£ADOWY ROZDZIA£

                           SPIS TREŒCI   Programowanie
                                         zorientowane obiektowo
           KATALOG KSI¥¯EK               Autor: Bertrand Meyer
                                         T³umaczenie: Micha³ Dadan (wstêp, rozdz. 1–6, 9, 10, 15,
                      KATALOG ONLINE     dod. A, C, D), Jaros³aw Dobrzañski (rozdz. 7, 17–25),
                                         Jan Ostrowski (rozdz. 26–32), Jaromir Senczyk (rozdz. 16,
       ZAMÓW DRUKOWANY KATALOG           33–36, dod. B), Krzysztof Szafranek (rozdz. 8, 11–14)
                                         ISBN: 83-7361-738-8
                                         Tytu³ orygina³u: Object-Oriented Software
              TWÓJ KOSZYK                Construction Second Edition
                                         Format: B5, stron: 1464
                    DODAJ DO KOSZYKA
                                                        Poznaj regu³y projektowania i programowania obiektowego
                                             • Elementy techniki obiektowej
         CENNIK I INFORMACJE                 • Metodyka tworzenia oprogramowania
                                             • Implementacja mechanizmów obiektowych
                   ZAMÓW INFORMACJE      Programowanie zorientowane obiektowo to technika, która w ci¹gu ostatnich lat
                     O NOWOŒCIACH        zyska³a niezwyk³¹ popularnoœæ. Jêzyki programowania obiektowego œwiêc¹ triumfy,
                                         a metodologie projektowania oparte na analizie obiektowej staj¹ siê standardami
                       ZAMÓW CENNIK      przemys³owymi. Za³o¿enia analizy i programowania obiektowego s¹ pozornie proste,
                                         jednak¿e bez ich w³aœciwego zrozumienia nie mo¿na zaprojektowaæ prawid³owo
                                         aplikacji implementowanej w obiektowym jêzyku programowania. Technologia
                 CZYTELNIA               obiektowa zmieni³a ca³y przemys³ programistyczny, wiêc jej opanowanie jest
                                         niezbêdnym elementem wiedzy ka¿dego informatyka, który chce wykorzystywaæ
          FRAGMENTY KSI¥¯EK ONLINE       w pracy nowoczesne metody i techniki.
                                         Ksi¹¿ka „Programowanie zorientowane obiektowo” to wyczerpuj¹ce omówienie
                                         wszystkich zagadnieñ zwi¹zanych z projektowaniem i programowaniem obiektowym.
                                         Opisuje g³ówne elementy techniki obiektowej oraz wiele spoœród ich potencjalnych
                                         zastosowañ. Dziêki ksi¹¿ce poznasz równie¿ metodykê projektowania oprogramowania,
                                         dowiesz siê, czym s¹ wzorce projektowe, i nauczysz siê, w jaki sposób
                                         zaimplementowaæ lub zasymulowaæ techniki obiektowe w ró¿nych jêzykach
                                         programowania.
                                             • Podstawowe elementy projektowania obiektowego
                                             • Wielokrotne wykorzystywanie kodu
                                             • Analiza obiektowa
Wydawnictwo Helion                           • Abstrakcyjne typy danych
ul. Chopina 6                                • Klasy i obiekty
44-100 Gliwice                               • Zarz¹dzanie pamiêci¹
tel. (32)230-98-63                           • Mechanizmy dziedziczenia
e-mail: helion@helion.pl                     • Obs³uga wyj¹tków
                                             • Metodyka projektowania obiektowego
                                             • Programowanie wspó³bie¿ne
                                             • Obiektowe bazy danych
                                             • Zastosowanie technik obiektowych w ró¿nych jêzykach programowania
                                         Wykorzystaj techniki obiektowe i popraw jakoϾ tworzonego przez siebie oprogramowania
SPIS TREŚCI
O Autorze .............................................................................................................15
Wstęp ....................................................................................................................17


Część I Podstawy                                                                                                                                           27
1.
Jakość oprogramowania .....................................................................................29
 1.1. Czynniki zewnętrzne i wewnętrzne ........................................................................................................29
 1.2. Przegląd czynników zewnętrznych ........................................................................................................30
 1.3. Konserwacja oprogramowania ...............................................................................................................45
 1.4. Kluczowe pojęcia wprowadzone w tym rozdziale .................................................................................47
 1.5. Bibliografia ............................................................................................................................................48


2.
Kryteria obiektowości .........................................................................................51
 2.1. O kryteriach ...........................................................................................................................................52
 2.2. Technika i język .....................................................................................................................................53
 2.3. Implementacja i środowisko ...................................................................................................................63
 2.4. Biblioteki ................................................................................................................................................65
 2.5. Rzut oka na konkretny projekt ...............................................................................................................67
 2.6. Bibliografia (w tym materiały na temat obiektów) .................................................................................67


Część II W stronę obiektowości                                                                                                                             69
3.
Modułowość .........................................................................................................71
 3.1. Pięć kryteriów ........................................................................................................................................72
 3.2. Pięć reguł ...............................................................................................................................................79
 3.3. Pięć zasad ...............................................................................................................................................86
4                                                                                                                                                   SPIS TREŚCI



 3.4. Kluczowe pojęcia wprowadzone w tym rozdziale .................................................................................97
 3.5. Bibliografia ............................................................................................................................................98
Ćwiczenia .......................................................................................................................................................99


4.
Wielokrotne wykorzystywanie kodu ...............................................................101
 4.1. Cele wielokrotnego wykorzystywania kodu .........................................................................................102
 4.2. Jakie elementy systemów nadają się do wielokrotnego wykorzystywania? .........................................105
 4.3. Powtórzenia w procesie tworzenia systemu .........................................................................................109
 4.4. Problemy nietechniczne .......................................................................................................................110
 4.5. Problem natury technicznej ..................................................................................................................118
 4.6. Pięć wymagań dotyczących struktury modułów ..................................................................................120
 4.7. Tradycyjne struktury modułowe ..........................................................................................................126
 4.8. Przeciążanie i generyczność .................................................................................................................131
 4.9. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................137
4.10. Bibliografia ..........................................................................................................................................138


5.
W stronę techniki obiektowej ..........................................................................141
 5.1. Składniki „obliczeń” ............................................................................................................................141
 5.2. Dekompozycja funkcjonalna ................................................................................................................143
 5.3. Dekompozycja obiektowa ....................................................................................................................155
 5.4. Programowanie zorientowane obiektowo ............................................................................................157
 5.5. Pytania .................................................................................................................................................158
 5.6. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................160
 5.7. Bibliografia ..........................................................................................................................................161


6.
Abstrakcyjne typy danych ...............................................................................163
 6.1. Kryteria ................................................................................................................................................164
 6.2. Możliwe implementacje .......................................................................................................................164
 6.3. W stronę abstrakcyjnego postrzegania obiektów .................................................................................168
 6.4. Formalizacja specyfikacji .....................................................................................................................172
 6.5. Od abstrakcyjnych typów danych do klas ............................................................................................186
 6.6. Nie tylko oprogramowanie ...................................................................................................................191
 6.7. Informacje uzupełniające .....................................................................................................................192
 6.8. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................204
 6.9. Bibliografia ..........................................................................................................................................205
Ćwiczenia .....................................................................................................................................................206


Część III Techniki obiektowe                                                                                                                            209
7.
Klasy — struktura statyczna ...........................................................................211
 7.1. Obiekty nie są najważniejsze ...............................................................................................................211
 7.2. Unikanie typowych nieporozumień ......................................................................................................212
SPIS TREŚCI                                                                                                                                                    5

 7.3. Znaczenie klas ......................................................................................................................................216
 7.4. Jednolity system typów ........................................................................................................................217
 7.5. Prosta klasa ..........................................................................................................................................218
 7.6. Podstawowe konwencje .......................................................................................................................223
 7.7. Przebieg wykonania programu obiektowego ........................................................................................227
 7.8. Eksportowanie wybiórcze a ukrywanie informacji ..............................................................................238
 7.9. Składanie wszystkiego w całość ...........................................................................................................241
7.10. Analiza .................................................................................................................................................250
7.11. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................262
7.12. Bibliografia ..........................................................................................................................................263
Ćwiczenia .....................................................................................................................................................264


8.
Struktury czasu wykonywania: obiekty .........................................................265
 8.1. Obiekty .................................................................................................................................................266
 8.2. Obiekty jako narzędzie do modelowania ..............................................................................................277
 8.3. Manipulowanie obiektami i referencjami .............................................................................................280
 8.4. Procedury tworzące ..............................................................................................................................285
 8.5. Więcej o referencjach ...........................................................................................................................289
 8.6. Operacje na referencjach ......................................................................................................................291
 8.7. Obiekty złożone i typy rozszerzone .....................................................................................................303
 8.8. Wiązanie: semantyka referencji i wartości ...........................................................................................310
 8.9. Korzystanie z referencji: korzyści i zagrożenia ....................................................................................315
8.10. Analiza .................................................................................................................................................320
8.11. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................325
8.12. Bibliografia ..........................................................................................................................................326
Ćwiczenia .....................................................................................................................................................327


9.
Zarządzanie pamięcią .......................................................................................329
 9.1. Co dzieje się z obiektami? ....................................................................................................................329
 9.2. Podejście klasyczne ..............................................................................................................................342
 9.3. Zagadnienia związane z odzyskiwaniem pamięci ................................................................................345
 9.4. Dealokacja kontrolowana przez programistę ........................................................................................346
 9.5. Rozwiązanie na poziomie komponentów .............................................................................................349
 9.6. Automatyczne zarządzanie pamięcią ...................................................................................................354
 9.7. Zliczanie referencji ...............................................................................................................................355
 9.8. Oczyszczanie pamięci ..........................................................................................................................357
 9.9. Mechanizm oczyszczania pamięci w praktyce .....................................................................................364
9.10. Środowisko z zaimplementowanym odzyskiwaniem pamięci .............................................................367
9.11. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................370
9.12. Bibliografia ..........................................................................................................................................371
Ćwiczenia .....................................................................................................................................................372


10.
Generyczność .....................................................................................................373
 10.1. Pozioma i pionowa generalizacja typów ............................................................................................374
 10.2. Potrzeba parametryzacji typów ..........................................................................................................374
 10.3. Klasy generyczne ...............................................................................................................................377
6                                                                                                                                                  SPIS TREŚCI



 10.4. Tablice ................................................................................................................................................382
 10.5. Koszt generyczności ...........................................................................................................................386
 10.6. Analiza — to jeszcze nie koniec ........................................................................................................387
 10.7. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................387
 10.8. Bibliografia ........................................................................................................................................388
Ćwiczenia .....................................................................................................................................................388


11.
Projektowanie kontraktowe: tworzenie niezawodnego oprogramowania ....391
 11.1. Proste mechanizmy niezawodności ....................................................................................................392
 11.2. O poprawności oprogramowania ........................................................................................................393
 11.3. Specyfikacja .......................................................................................................................................394
 11.4. Wprowadzanie asercji do kodu ..........................................................................................................397
 11.5. Warunki początkowe i warunki końcowe ..........................................................................................398
 11.6. Używanie kontraktów dla poprawy niezawodności ...........................................................................402
 11.7. Praca z asercjami ................................................................................................................................408
 11.8. Niezmienniki klas ...............................................................................................................................422
 11.9. Kiedy klasa jest poprawna? ................................................................................................................428
11.10. Związek z ATD ..................................................................................................................................432
11.11. Instrukcja asercji ................................................................................................................................436
11.12. Niezmienniki i zmienne pętli .............................................................................................................439
11.13. Korzystanie z asercji ..........................................................................................................................447
11.14. Analiza ...............................................................................................................................................456
11.15. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................465
11.16. Bibliografia ........................................................................................................................................466
Ćwiczenia .....................................................................................................................................................467
Postscriptum: katastrofa Ariane 5 .................................................................................................................469


12.
Gdy kontrakt nie zostaje dotrzymany: obsługa wyjątków ...........................471
 12.1. Podstawy obsługi wyjątków ...............................................................................................................471
 12.2. Obsługa wyjątków ..............................................................................................................................474
 12.3. Mechanizm wyjątków ........................................................................................................................479
 12.4. Przykłady obsługi wyjątków ..............................................................................................................482
 12.5. Zadanie klauzuli ratunkowej ..............................................................................................................488
 12.6. Zaawansowana obsługa wyjątków .....................................................................................................491
 12.7. Analiza ...............................................................................................................................................496
 12.8. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................498
 12.9. Bibliografia ........................................................................................................................................498
Ćwiczenia .....................................................................................................................................................499


13.
Mechanizmy pomocnicze ..................................................................................501
 13.1. Komunikacja z oprogramowaniem nieobiektowym ...........................................................................501
 13.2. Przekazywanie argumentów ...............................................................................................................507
 13.3. Instrukcje ............................................................................................................................................509
 13.4. Wyrażenia ..........................................................................................................................................515
SPIS TREŚCI                                                                                                                                                    7

 13.5. Łańcuchy znaków ...............................................................................................................................520
 13.6. Wejście i wyjście ................................................................................................................................521
 13.7. Konwencje leksykalne ........................................................................................................................521
 13.8. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................521
Ćwiczenia .....................................................................................................................................................522


14.
Wprowadzenie do dziedziczenia ......................................................................523
 14.1. Wielokąty i prostokąty .......................................................................................................................524
 14.2. Polimorfizm .......................................................................................................................................531
 14.3. Kontrola typów a dziedziczenie .........................................................................................................536
 14.4. Dynamiczne wiązanie ........................................................................................................................545
 14.5. Cechy i klasy abstrakcyjne .................................................................................................................547
 14.6. Techniki ponownej deklaracji ............................................................................................................556
 14.7. Znaczenie dziedziczenia .....................................................................................................................560
 14.8. Rola klas abstrakcyjnych ....................................................................................................................566
 14.9. Analiza ...............................................................................................................................................573
14.10. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................583
14.11. Bibliografia ........................................................................................................................................584
Ćwiczenia .....................................................................................................................................................585


15.
Dziedziczenie wielokrotne ................................................................................587
 15.1. Przykłady dziedziczenia wielokrotnego .............................................................................................587
 15.2. Zmiana nazw cech ..............................................................................................................................604
 15.3. Spłaszczanie struktury ........................................................................................................................611
 15.4. Powtórne dziedziczenie ......................................................................................................................614
 15.5. Analiza ...............................................................................................................................................635
 15.6. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................638
 15.7. Bibliografia ........................................................................................................................................638
Ćwiczenia .....................................................................................................................................................639


16.
Techniki dziedziczenia ......................................................................................643
 16.1. Dziedziczenie i asercje .......................................................................................................................644
 16.2. Globalna struktura dziedziczenia .......................................................................................................656
 16.3. Cechy zamrożone ...............................................................................................................................659
 16.4. Generyczność ograniczona .................................................................................................................661
 16.5. Próba przypisania ...............................................................................................................................667
 16.6. Zgodność typów i ponowne deklaracje ..............................................................................................672
 16.7. Deklaracje kotwiczone .......................................................................................................................675
 16.8. Dziedziczenie i ukrywanie informacji ................................................................................................683
 16.9. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................688
16.10. Bibliografia ........................................................................................................................................689
Ćwiczenia .....................................................................................................................................................689
8                                                                                                                                                  SPIS TREŚCI




17.
Kontrola typów ..................................................................................................691
 17.1. Problem z kontrolą typów ..................................................................................................................691
 17.2. Statyczna kontrola typów — kiedy i jak? ...........................................................................................696
 17.3. Kowariancja i ukrywanie u potomków ...............................................................................................703
 17.4. Pierwsze podejście do kwestii poprawności systemu .........................................................................711
 17.5. Bazowanie na typach zakotwiczonych ...............................................................................................713
 17.6. Analiza globalna .................................................................................................................................717
 17.7. Uwaga na polimorficzne wywołania ZDLT! ......................................................................................719
 17.8. Ocena .................................................................................................................................................722
 17.9. Idealny typ .........................................................................................................................................723
17.10. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................725
17.11. Bibliografia ........................................................................................................................................725


18.
Obiekty i stałe globalne ....................................................................................727
 18.1. Stałe podstawowych typów ................................................................................................................728
 18.2. Korzystanie ze stałych ........................................................................................................................729
 18.3. Stałe o typach będących klasami ........................................................................................................730
 18.4. Zastosowanie podprogramów jednorazowych ...................................................................................732
 18.5. Stałe typu łańcuchowego ....................................................................................................................738
 18.6. Wartości unikatowe ............................................................................................................................738
 18.7. Analiza ...............................................................................................................................................740
 18.8. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................744
 18.9. Bibliografia ........................................................................................................................................745
Ćwiczenia .....................................................................................................................................................745


Część IV Metodyka obiektowa
— prawidłowe stosowanie metody                                                                                                                         747
19.
O metodyce ........................................................................................................749
 19.1. Metodyka programowania — jak i dlaczego? ....................................................................................749
 19.2. Wymyślanie dobrych reguł — porady dla radzących .........................................................................750
 19.3. O użyciu metafor ................................................................................................................................758
 19.4. Znaczenie pokory ...............................................................................................................................760
 19.5. Bibliografia ........................................................................................................................................761
Ćwiczenia .....................................................................................................................................................761


20.
Wzorzec projektowy — wielopanelowe systemy interaktywne ....................763
 20.1. Systemy wielopanelowe .....................................................................................................................763
 20.2. Proste rozwiązanie .............................................................................................................................765
SPIS TREŚCI                                                                                                                                                    9

 20.3. Rozwiązanie hierarchiczne z funkcjami .............................................................................................766
 20.4. Krytyka rozwiązania ..........................................................................................................................770
 20.5. Architektura obiektowa ......................................................................................................................772
 20.6. Analiza ...............................................................................................................................................781
 20.7. Bibliografia ........................................................................................................................................782


21.
Dziedziczenie — studium przypadku:
operacja „cofnij” w systemie interaktywnym ................................................783
 21.1. Perseverare diabolicum ......................................................................................................................783
 21.2. Wyszukiwanie abstrakcji ....................................................................................................................787
 21.3. Wielopoziomowy mechanizm cofnij-powtórz ...................................................................................793
 21.4. Aspekty implementacyjne ..................................................................................................................796
 21.5. Interfejs użytkownika dla operacji cofania i powtarzania ..................................................................800
 21.6. Analiza ...............................................................................................................................................802
 21.7. Bibliografia ........................................................................................................................................804
Ćwiczenia .....................................................................................................................................................805


22.
Jak odnaleźć klasy? ..........................................................................................809
 22.1. Analiza dokumentu z wymogami .......................................................................................................810
 22.2. Oznaki zagrożenia ..............................................................................................................................816
 22.3. Ogólna heurystyka odnajdywania klas ...............................................................................................822
 22.4. Inne źródła klas ..................................................................................................................................826
 22.5. Wielokrotne zastosowanie ..................................................................................................................832
 22.6. Metoda uzyskiwania klas ...................................................................................................................833
 22.7. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................835
 22.8. Bibliografia ........................................................................................................................................835
Ćwiczenia .....................................................................................................................................................836


23.
Zasady projektowania klas ..............................................................................839
 23.1. Skutki uboczne w funkcjach ...............................................................................................................840
 23.2. Ile argumentów powinna mieć cecha? ................................................................................................856
 23.3. Rozmiar klasy — metoda listy zakupów ............................................................................................863
 23.4. Aktywne struktury danych .................................................................................................................867
 23.5. Cechy eksportowane selektywnie .......................................................................................................892
 23.6. Postępowanie w przypadkach nietypowych .......................................................................................893
 23.7. Ewolucja klasy — klauzula OBSOLETE ...........................................................................................898
 23.8. Dokumentowanie klasy i systemu ......................................................................................................899
 23.9. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................902
23.10. Bibliografia ........................................................................................................................................902
Ćwiczenia .....................................................................................................................................................903
10                                                                                                                                                  SPIS TREŚCI




24.
Prawidłowe stosowanie dziedziczenia .............................................................907
 24.1. Jak używać dziedziczenia? .................................................................................................................907
 24.2. Kupić czy odziedziczyć? ....................................................................................................................910
 24.3. Przykład zastosowania — technika uchwytów ...................................................................................916
 24.4. Taksomania ........................................................................................................................................919
 24.5. Zastosowanie dziedziczenia — taksonomia taksonomii .....................................................................921
 24.6. Jeden czy więcej mechanizmów? .......................................................................................................933
 24.7. Dziedziczenie podtypów i ukrywanie u potomków ............................................................................935
 24.8. Dziedziczenie implementacji .............................................................................................................944
 24.9. Dziedziczenie udogodnień .................................................................................................................947
24.10. Wielość kryteriów i dziedziczenie perspektywy ................................................................................952
24.11. Jak opracowywać struktury dziedziczenia? ........................................................................................958
24.12. Podsumowanie — prawidłowe stosowanie dziedziczenia ..................................................................962
24.13. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................963
24.14. Bibliografia ........................................................................................................................................964
24.15. Dodatek — historia taksonomii ..........................................................................................................964
Ćwiczenia .....................................................................................................................................................970


25.
Przydatne techniki ............................................................................................973
 25.1. Filozofia projektowania ......................................................................................................................973
 25.2. Klasy ..................................................................................................................................................974
 25.3. Techniki dziedziczenia .......................................................................................................................976


26.
Poczucie stylu ....................................................................................................979
 26.1. Kwestie kosmetyczne mają znaczenie! ..............................................................................................979
 26.2. Dobór odpowiednich nazw .................................................................................................................983
 26.3. Stałe ...................................................................................................................................................989
 26.4. Komentarze nagłówkowe i klauzule indeksujące ...............................................................................991
 26.5. Układ i prezentacja tekstu ..................................................................................................................997
 26.6. Czcionki ...........................................................................................................................................1006
 26.7. Bibliografia ......................................................................................................................................1008
Ćwiczenia ...................................................................................................................................................1008


27.
Analiza obiektowa ...........................................................................................1011
 27.1. Cele analizy ......................................................................................................................................1012
 27.2. Zmienna natura analizy ....................................................................................................................1014
 27.3. Wkład technologii obiektowej ..........................................................................................................1015
 27.4. Programowanie stacji telewizyjnej ...................................................................................................1016
 27.5. Użyteczność analizy — wielokrotność postaci ................................................................................1023
 27.6. Metody analizy .................................................................................................................................1027
 27.7. Notacja obiektów biznesowych — NOB ..........................................................................................1030
 27.8. Bibliografia ......................................................................................................................................1033
SPIS TREŚCI                                                                                                                                                11

28.
Proces tworzenia oprogramowania ...............................................................1035
 28.1. Klastry ..............................................................................................................................................1035
 28.2. Inżynieria symultaniczna ..................................................................................................................1036
 28.3. Kroki i zadania .................................................................................................................................1038
 28.4. Klastrowy model cyklu życia oprogramowania ...............................................................................1039
 28.5. Uogólnienie ......................................................................................................................................1040
 28.6. Jednolitość i odwracalność ...............................................................................................................1043
 28.7. Wśród nas wszystko jest twarzą .......................................................................................................1046
 28.8. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1047
 28.9. Bibliografia ......................................................................................................................................1047


29.
Nauczanie .........................................................................................................1049
 29.1. Szkolenia przemysłowe ....................................................................................................................1049
 29.2. Kursy wprowadzające ......................................................................................................................1052
 29.3. Inne kursy .........................................................................................................................................1056
 29.4. W kierunku nowych sposobów nauczania tworzenia oprogramowania ...........................................1058
 29.5. Plan wydziału związany z obiektowością ........................................................................................1062
 29.6. Kluczowe zagadnienia wprowadzone w rozdziale ...........................................................................1064
 29.7. Bibliografia ......................................................................................................................................1064


Część V Zagadnienia zaawansowane                                                                                                                   1067
30.
Współbieżność, rozproszenie, klient-serwer i internet ................................1069
 30.1. Krótkie podsumowanie ....................................................................................................................1070
 30.2. Narodziny współbieżności ...............................................................................................................1071
 30.3. Od procesów do obiektów ................................................................................................................1075
 30.4. Wykonywanie współbieżne ..............................................................................................................1083
 30.5. Kwestie synchronizacji ....................................................................................................................1097
 30.6. Dostęp do obiektów niezależnych ....................................................................................................1103
 30.7. Warunki oczekiwania .......................................................................................................................1112
 30.8. Żądania obsługi w trybie specjalnym ...............................................................................................1121
 30.9. Przykłady .........................................................................................................................................1126
30.10. W kierunku reguły dowodzenia poprawności ..................................................................................1144
30.11. Podsumowanie przedstawionego mechanizmu współbieżności .......................................................1146
30.12. Analiza .............................................................................................................................................1149
30.13. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1154
30.14. Bibliografia ......................................................................................................................................1155
Ćwiczenia ...................................................................................................................................................1157


31.
Trwałość obiektów i bazy danych ..................................................................1161
 31.1. Trwałość jako element języka ..........................................................................................................1161
 31.2. Granice implementacji trwałości ......................................................................................................1163
12                                                                                                                                                SPIS TREŚCI



 31.3. Ewolucja schematu ...........................................................................................................................1165
 31.4. Od trwałości do baz danych .............................................................................................................1172
 31.5. Współpraca obiektowo-relacyjna .....................................................................................................1173
 31.6. Podstawy obiektowych baz danych ..................................................................................................1176
 31.7. Systemy obiektowych baz danych — przykłady ..............................................................................1182
 31.8. Analiza — pozaobiektowe bazy danych ..........................................................................................1185
 31.9. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1187
31.10. Bibliografia ......................................................................................................................................1188
Ćwiczenia ...................................................................................................................................................1189


32.
Wybrane techniki obiektowe wykorzystywane w interaktywnych
aplikacjach z graficznym interfejsem użytkownika ....................................1191
 32.1. Potrzebne narzędzia .........................................................................................................................1192
 32.2. Przenośność i adaptacja do platformy ..............................................................................................1195
 32.3. Abstrakcje graficzne .........................................................................................................................1197
 32.4. Mechanizmy interakcji .....................................................................................................................1200
 32.5. Obsługa zdarzeń ...............................................................................................................................1202
 32.6. Model matematyczny .......................................................................................................................1206
 32.7. Bibliografia ......................................................................................................................................1206


Część VI Zastosowanie metody w różnych
językach i środowiskach programowania                                                                                                              1207
33.
Programowanie obiektowe i Ada ...................................................................1209
 33.1. Trochę historii ..................................................................................................................................1210
 33.2. Pakiety ..............................................................................................................................................1211
 33.3. Implementacja stosu .........................................................................................................................1212
 33.4. Ukrywanie reprezentacji ..................................................................................................................1216
 33.5. Wyjątki .............................................................................................................................................1218
 33.6. Zadania .............................................................................................................................................1222
 33.7. Ada 95 ..............................................................................................................................................1223
 33.8. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1228
 33.9. Bibliografia ......................................................................................................................................1228
Ćwiczenia ...................................................................................................................................................1229


34.
Emulacja technologii obiektowej w środowiskach nieobiektowych ...........1231
 34.1. Poziomy obsługi koncepcji obiektowych .........................................................................................1232
 34.2. Programowanie obiektowe w Pascalu? ............................................................................................1233
 34.3. Fortran ..............................................................................................................................................1234
 34.4. Programowanie obiektowe i język C ................................................................................................1239
 34.5. Bibliografia ......................................................................................................................................1245
Ćwiczenia ...................................................................................................................................................1246
SPIS TREŚCI                                                                                                                                                 13

35.
Od Simuli do Javy: główne języki i środowiska obiektowe ........................1247
 35.1. Simula ..............................................................................................................................................1248
 35.2. Smalltalk ..........................................................................................................................................1261
 35.3. Rozszerzenia języka Lisp .................................................................................................................1265
 35.4. Rozszerzenia języka C .....................................................................................................................1267
 35.5. Java ..................................................................................................................................................1271
 35.6. Inne języki obiektowe ......................................................................................................................1272
 35.7. Bibliografia ......................................................................................................................................1273
Ćwiczenia ...................................................................................................................................................1275


Część VII W praktyce                                                                                                                                1277
36.
Środowisko obiektowe ....................................................................................1279
 36.1. Komponenty .....................................................................................................................................1280
 36.2. Język ................................................................................................................................................1280
 36.3. Technologia kompilacji ....................................................................................................................1281
 36.4. Narzędzia .........................................................................................................................................1285
 36.5. Biblioteki ..........................................................................................................................................1289
 36.6. Mechanizmy interfejsu .....................................................................................................................1290
 36.7. Bibliografia ......................................................................................................................................1297



Epilog ujawnia język ......................................................................................1299


Dodatki                                                                                                                                             1301
A
Wybrane klasy bibliotek Base .......................................................................1303

B
Generyczność a dziedziczenie ........................................................................1355
 B.1. Generyczność ....................................................................................................................................1356
 B.2. Dziedziczenie ....................................................................................................................................1361
 B.3. Emulacja dziedziczenia za pomocą generyczności ............................................................................1363
 B.4. Emulacja generyczności za pomocą dziedziczenia ............................................................................1364
 B.5. Łączenie generyczności z dziedziczeniem .........................................................................................1372
 B.6. Kluczowe pojęcia wprowadzone w tym dodatku ..............................................................................1376
 B.7. Bibliografia ........................................................................................................................................1376
Ćwiczenia ...................................................................................................................................................1377
14                                                                                                                                         SPIS TREŚCI




C
Zasady, reguły, nakazy i definicje .................................................................1379

D
Określenia stosowane w technice obiektowej ...............................................1385

E
Bibliografia ......................................................................................................1397
 E.1. Prace innych autorów ........................................................................................................................1397
 E.2. Prace autora książki ...........................................................................................................................1416

Skorowidz ........................................................................................................ 1421
1
JAKOŚĆ OPROGRAMOWANIA
Słowo inżynieria nieodzownie kojarzy się z jakością. Inżynieria oprogramowania to
tworzenie wysokich jakościowo programów. Ta książka opisuje techniki, które poten-
cjalnie mogą przyczynić się do znacznego podniesienia jakości aplikacji komputerowych.
      Zanim zacznę je omawiać, muszę napisać, w jakim celu zostały wymyślone. Jakość
oprogramowania najlepiej pojmować jako sumę wielu czynników. W tym rozdziale opi-
szę kilka z nich, zidentyfikuję obszary, jakie najpilniej wymagają usprawnień, i wskażę
kierunek, w którym wspólnie będziemy szukać rozwiązań w trakcie dalszej lektury.




1.1. CZYNNIKI ZEWNĘTRZNE I WEWNĘTRZNE

Wszyscy chcemy, aby nasze oprogramowanie było szybkie, niezawodne, łatwe w obsłu-
dze, czytelne, modułowe, sensownie skonstruowane itd. Tyle tylko, że te przymiotniki
opisują dwa różne rodzaje zalet.
     Po jednej stronie mamy zalety, takie jak szybkość czy łatwość obsługi, których
obecność lub brak może z łatwością stwierdzić każdy użytkownik. Tego rodzaju właści-
wości możemy nazwać zewnętrznymi czynnikami decydującymi o jakości.

    Pod pojęciem „użytkownicy” należy rozumieć nie tylko osoby, które będą fizycznie
    korzystały z gotowych programów (na przykład pracownik linii lotniczych obsługujący
    system rezerwacji lotów), ale także decydentów, którzy podjęli decyzję o ich zakupie
    bądź zlecili ich opracowanie (analogicznie dyrektor linii lotniczych, którego uprawnienia
    na to pozwalają). Tak więc taka właściwość jak łatwość, z jaką oprogramowanie
    daje się dostosowywać do zmian w specyfikacji (w dalszej części tego rozdziału
    nazywana rozszerzalnością), jest zaliczana do kategorii czynników zewnętrznych,
    mimo iż „użytkownicy końcowi”, tacy jak pracownik dokonujący rezerwacji,
    mogą nie być nią bezpośrednio zainteresowani.

     Inne możliwe zalety programu komputerowego, takie jak czytelność czy modu-
łowość, zaliczamy do czynników wewnętrznych, ponieważ są one dostrzegalne jedynie
dla informatyków mających dostęp do kodu źródłowego programu.
30                                                 ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA



     W ostatecznym rozrachunku liczą się tylko czynniki zewnętrzne. Gdy korzystam
z przeglądarki internetowej lub mieszkam w pobliżu elektrowni atomowej sterowanej
przez program komputerowy, tak naprawdę nie obchodzi mnie to, czy jego kod źró-
dłowy jest modularny i czytelny. Ważne, żeby obrazki w przeglądarce nie wczyty-
wały się godzinami, a błędne dane wejściowe nie mogły doprowadzić do wysadzenia
elektrowni. Jednak kluczem do osiągnięcia satysfakcjonujących czynników zewnętrz-
nych są czynniki wewnętrzne. Aby użytkownicy mogli cieszyć się widocznymi ozna-
kami jakości aplikacji, ich projektanci i implementatorzy muszą stosować techniki gwa-
rantujące wysoką jakość wewnętrzną.
     W kolejnych rozdziałach przedstawiam zbiór współczesnych technik pozwalają-
cych na uzyskanie właśnie wewnętrznej jakości aplikacji. Czytając ten rozdział, nie
powinieneś jednak tracić z oczu szerszego obrazu. Techniki wewnętrzne nie są naszym
celem same w sobie. Są to jedynie środki, za pomocą których możemy uzyskać wysoką
jakość zewnętrzną tworzonych aplikacji. Dlatego też musimy zacząć od omówienia
czynników zewnętrznych. Przeznaczyłem na to pozostałą część tego rozdziału.




1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH
Poniżej opisuję najważniejsze czynniki zewnętrzne decydujące o jakości, które powinny
być obecne w każdym programie komputerowym. Doprowadzenie do takiego stanu jest
głównym celem programowania zorientowanego obiektowo.



Poprawność

                               Definicja poprawności
  Poprawność to zdolność programów komputerowych do wykonywania dokładnie
  tych zadań, które im powierzono i które zdefiniowano w ich specyfikacjach.


     Poprawność jest zdecydowanie najważniejszym czynnikiem. Jeżeli system nie robi
tego, czego się po nim oczekuje, wszystko inne — czy jest szybki, czy ma przyjemny
interfejs użytkownika itd. — nie ma większego znaczenia.
     Łatwo o niej pisać, ale znacznie trudniej ją osiągnąć. Już pierwszy krok na dro-
dze do poprawności jest trudny. Trzeba bowiem precyzyjnie określić wymagania sta-
wiane systemowi.
     Techniki stosowane w celu zapewnienia poprawności zazwyczaj odnoszą się je-
dynie do pewnego obszaru systemu. Poważne współczesne programy komputerowe,
nawet te mniejsze, odnoszą się do zagadnień z tak wielu dziedzin, że niemożliwe byłoby
zagwarantowanie ich poprawności po przeanalizowaniu komponentów i właściwości
tylko na jednej płaszczyźnie. Dlatego konieczne jest podejście warstwowe, w którym
wyższe warstwy polegają na niższych (patrz rysunek 1.1).
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                               31


                                                                RYSUNEK 1.1.
                                                                Warstwy
                                                                w procesie tworzenia
                                                                oprogramowania


      W tak zwanym warunkowym podejściu do poprawności interesuje nas jedynie
zagwarantowanie poprawności danej warstwy przy założeniu, że wszystkie warstwy
leżące niżej na pewno są poprawne. Jest to jedyne realistyczne podejście, ponieważ
pozwala rozbić problem na kilka części i koncentrować się w danym momencie tylko
na jednej z nich. Nie możesz twierdzić, że program napisany w języku wysokiego po-
ziomu X jest poprawny, jeżeli nie masz pewności, że kompilator, którym dysponu-
jesz, prawidłowo implementuje język X. Nie oznacza to wcale, że musisz ślepo ufać
kompilatorowi. Po prostu problem zostaje tu rozbity na dwie części. Poprawność kom-
pilatora i poprawność programu z punktu widzenia semantyki języka.
      W technice opisywanej w tej książce poprawność zależy od jeszcze większej liczby
warstw (patrz rysunek 1.2), ponieważ tworząc programy komputerowe, będziemy polegali
na bibliotekach komponentów przeznaczonych do wielokrotnego użycia, które mogą być
wykorzystywane do budowy wielu różnych aplikacji.




                                                                RYSUNEK 1.2.
                                                                Warstwy w procesie
                                                                tworzenia aplikacji,
                                                                w którym posługujemy
                                                                się komponentami
                                                                wielokrotnego użytku


     Również w tym przypadku stosuje się podejście warunkowe. Powinniśmy za-
gwarantować poprawność bibliotek, a następnie — w oparciu o nią — poprawność
aplikacji.
     Wielu praktykom stykającym się z zagadnieniem poprawności oprogramowania
przychodzi na myśl testowanie i lokalizowanie błędów. Jednak do problemu można
podejść bardziej ambitnie. W dalszych rozdziałach przyjrzymy się wielu technikom,
w szczególności kontroli typów i asercjom, które wymyślono po to, aby ułatwić two-
rzenie oprogramowania, które jest poprawne od samego początku. Jest to znacznie
lepsze podejście, niż zmuszanie programu do poprawności dopiero na pewnym etapie.
Jednak nie zwalnia nas ono z testowania i lokalizowania błędów, czyli czynności, które
w tym przypadku pozwalają na upewnienie się, że program faktycznie jest poprawny.
32                                                     ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA



     Można iść jeszcze dalej i przyjąć całkiem sformalizowane podejście do tworze-
nia oprogramowania. Postanowiłem stosować w książce dość potoczny język, dlatego
wspomnę jedynie, że wiele technik, które opisuję w dalszych rozdziałach, wywodzi
się bezpośrednio ze ścisłych, matematycznych technik formułowania specyfikacji pro-
gramów i ich weryfikacji, które pozwalają bardzo mocno zbliżyć się do ideału w pełni
poprawnego oprogramowania.



Odporność
                                  Definicja odporności
  Odporność to zdolność systemów komputerowych do prawidłowego reagowania
  na niestandardowe sytuacje.

     Odporność stanowi uzupełnienie poprawności (patrz rysunek 1.3). Poprawność
określa zachowanie systemów w sytuacjach przewidzianych w specyfikacji. Z kolei
odporność charakteryzuje działania podejmowane po napotkaniu sytuacji wykraczają-
cych poza specyfikację.




                                                                     RYSUNEK 1.3.
                                                                     Odporność
                                                                     kontra poprawność


     Już sama definicja pokazuje, że odporność nie jest tak ścisłym pojęciem jak po-
prawność. Ponieważ mówimy tu o przypadkach nieprzewidzianych w specyfikacji, nie
możemy powiedzieć, że system powinien wówczas po prostu „wykonywać swoje za-
dania”. Gdyby te zadania były znane, każdy taki niestandardowy przypadek stałby się
częścią specyfikacji, co przeniosłoby nas z powrotem w obszar poprawności.

     Definicja „niestandardowej sytuacji” przyda się jeszcze, gdy będziemy omawiali obsługę    Informacje
     wyjątków. Wynika z niej, że to, co nazywamy sytuacją standardową, a co niestandardową,    na temat
     zależy od przyjętej specyfikacji. Sytuacja niestandardowa to po prostu taka, która nie    obsługi
                                                                                               wyjątków
     została w niej przewidziana. Jeżeli poszerzymy specyfikację, wówczas sytuacje, które
                                                                                               znajdziesz
     były niestandardowe, staną się standardowe, nawet jeśli dotyczą takich okoliczności jak   w rozdziale 12.
     wprowadzenie przez użytkownika nieprawidłowych danych. Tak więc „standardowe” nie
     oznacza w tym przypadku „pożądane”, a jedynie „przewidziane na etapie projektowania
     programu”. Mimo iż nazywanie wprowadzenia błędnych danych „standardową sytuacją”
     może z początku wydawać się paradoksalne, każde inne rozwiązanie wymagałoby
     ustalenia obiektywnych kryteriów, a tym samym byłoby bezużyteczne.

     Zawsze mogą zdarzyć się sytuacje, których specyfikacja bezpośrednio nie prze-
widuje. Znaczenie odporności polega na gwarancji, że pojawienie się takich okolicz-
ności nie spowoduje żadnej katastrofy. Program powinien po prostu wyświetlić sto-
sowne komunikaty o błędzie i zakończyć w normalny sposób swoje wykonywanie lub
wejść w tak zwany „tryb łagodnego zejścia”.
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                             33

Rozszerzalność
                              Definicja rozszerzalności
  Rozszerzalność to możliwość łatwego dostosowywania programu komputerowego
  do zmian w specyfikacji.

Oprogramowanie, w przeciwieństwie do sprzętu, z założenia powinno dawać się łatwo
modyfikować. Tak właśnie jest, jeśli tylko mamy dostęp do kodu źródłowego. Jego zmia-
na jest w takiej sytuacji banalnie prosta. Wystarczy posłużyć się dowolnym edytorem
tekstów.
     Z zagadnieniem rozszerzalności wiąże się problem skali. W małych aplikacjach
wprowadzenie zmian zazwyczaj nie stanowi problemu. Jeśli jednak mamy do czynie-
nia z coraz bardziej rozbudowanymi programami, to coraz trudniej je modyfikować.
Tego rodzaju aplikacje przypominają czasami ogromne domki z kart, a wyciągnięcie
tylko jednego elementu może spowodować zawalenie się całej konstrukcji.
     Rozszerzalność jest potrzebna ze względu na to, że u podstaw każdego programu
komputerowego leży czynnik ludzki, co czyni go podatnym na błędy, które trzeba
później poprawiać. Weźmy pod uwagę na przykład programy biznesowe (takie jak
informacyjne systemy zarządzania). Wystarczy, że zmienią się jakieś przepisy prawa
lub firma zostanie przejęta przez konkurencję, a już założenia, na których oparty był
system, przestaną być aktualne. Jest to dość sztampowy przykład, ale niewiele osób
zdaje sobie sprawę z tego, że z podobną sytuacją mamy do czynienia nawet w pro-
gramach naukowych, w przypadku których możemy zakładać, że za miesiąc lub dwa
będą nadal obowiązywały te same prawa fizyki co dzisiaj. Jednak może ulec zmianie
sposób, w jaki je pojmujemy, lub procedura modelowania pewnych zjawisk.
     W tradycyjnym podejściu do inżynierii oprogramowania nie przykładano wy-
starczająco dużej wagi do zmian. Zamiast tego opierano się na idealistycznym po-
strzeganiu cyklu życia oprogramowania, w którym wymagania były zamrażane już na
etapie analizy potrzeb. Na dalszych etapach skupiano się już wyłącznie na projekto-
waniu i tworzeniu rozwiązania. Jest to zrozumiałe. Pierwszym krokiem na drodze
rozwoju inżynierii programowania było opracowanie przejrzystych technik formuło-
wania i rozwiązywania stałych, niezmiennych problemów. Dopiero później zaczęto
się martwić, co należy robić w sytuacji, gdy problem ulega zmianie w czasie, kiedy
wciąż szukamy rozwiązania. Obecnie podstawowe techniki inżynierii oprogramowa-
nia są już opracowane i dlatego pora zająć się opisywanym problemem. Zmiany są
nieodłącznym elementem procesu tworzenia oprogramowania. Możemy mieć do czy-
nienia ze zmianami wymagań, sposobu ich pojmowania, algorytmów, sposobu pre-
zentacji danych lub technik implementacyjnych. Umożliwienie łatwego ich wprowa-
dzania jest głównym zadaniem techniki obiektowej i tematem przewodnim tej książki.
     Choć wiele technik zwiększających rozszerzalność można prezentować na pro-
stych przykładach, ich znaczenie staje się jasne dopiero w przypadku większych pro-
jektów. Przy zwiększaniu rozszerzalności kluczową rolę odgrywają dwie zasady:

 • Prostota projektu — proste architektury zawsze łatwiej zaadaptować do zmian niż
   złożone.
 • Decentralizacja — im większa autonomia poszczególnych modułów, tym więk-
   sze prawdopodobieństwo, że prosta zmiana specyfikacji będzie wymagała zmo-
   dyfikowania tylko jednego lub kilku modułów i nie wywoła reakcji łańcuchowej
   w całym systemie.
34                                                  ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA



     Technika programowania zorientowanego obiektowo jest przede wszystkim tech-
niką tworzenia takich architektur systemów, które pomagają projektantom w tworzeniu
zdecentralizowanych programów o prostej strukturze (nawet jeśli są to duże projekty).
Prostota i decentralizacja to kluczowe zagadnienia, które będą się przewijały w naszej
dyskusji do czasu, aż w kolejnych rozdziałach sformułujemy zasady rządzące techniką
obiektową.



Przystosowanie do wielokrotnego użycia

                Definicja przystosowania do wielokrotnego użycia
  Przystosowanie do wielokrotnego użycia to zdolność elementów składowych opro-
  gramowania do pełnienia roli elementów konstrukcyjnych wielu różnych aplikacji.

Potrzeba przystosowania do wielokrotnego użycia wynika z obserwacji, że w wielu
programach komputerowych przewijają się te same wzorce. Dlatego powinna istnieć
możliwość wykorzystania tych podobieństw, pozwalająca na uniknięcie ponownego
wynajdywania koła. Dostrzegając taki wzorzec, możemy wyodrębnić element pro-
gramu, który nadaje się do wykorzystania w wielu różnych projektach.
     Przystosowanie do wielokrotnego użycia ma wpływ na wszystkie inne aspekty
jakości oprogramowania, ponieważ dzięki niemu nie trzeba pisać tak dużo kodu jak
dawniej i można skupić się (przy takim samym całkowitym koszcie projektu) na po-
prawianiu innych czynników, takich jak poprawność czy odporność.
     Jest to przykład kolejnego zagadnienia, na które nie położono wystarczająco du-
żego nacisku w tradycyjnym pojmowaniu cyklu życia aplikacji. Powody historyczne
są tu takie same jak w poprzednim przypadku. Przyjęto, że najpierw trzeba znaleźć
rozwiązanie jednego problemu, a dopiero potem można stosować je w odniesieniu do
innych problemów. Jednak rozrastanie się programów komputerowych i próba uczy-
nienia z informatyki prawdziwego przemysłu doprowadziły do tego, że przystosowanie
kodu do wielokrotnego użycia stało się palącą potrzebą.
     Przystosowanie do wielokrotnego użycia będzie odgrywało kluczową rolę przy           O przystoso-
omawianiu zagadnień przedstawionych w następnych rozdziałach. Jeden z nich jest prak-     waniu do
                                                                                          wielokrotnego
tycznie w całości poświęcony dogłębnej analizie tego czynnika decydującego o jakości,     użycia piszę
omówieniu wymiernych korzyści, jakie on daje, i problemów, jakie się z nim wiążą.         w rozdziale 4.




Zgodność
                                 Definicja zgodności
  Zgodność to łatwość, z jaką można ze sobą łączyć poszczególne składniki oprogra-
  mowania.

Zgodność jest bardzo istotna, ponieważ składniki programistyczne nie powstają w próżni.
Muszą ze sobą współpracować. Jednak bardzo często mają z tym problemy, ponieważ
ich twórcy poczynili sprzeczne założenia dotyczące świata zewnętrznego. Jednym z przy-
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                                      35

                 kładów tego typu sytuacji jest ogromna różnorodność niezgodnych ze sobą formatów
                 plików, obsługiwanych przez różne systemy operacyjne. Każdy program komputerowy
                 może bezpośrednio przyjmować wyniki działania innego programu tylko wtedy, jeżeli
                 formaty plików stosowane przez obie aplikacje są ze sobą zgodne.
                      Brak zgodności może odprowadzić do prawdziwej katastrofy. Oto skrajny przykład.

San Jose              DALLAS. W zeszłym tygodniu AMR, spółka będąca właścicielem firmy American
(Kalifornia),         Airlines, Inc., przyznała, że połamała zęby na próbie stworzenia doskonałego,
Mercury
News,
                      uniwersalnego systemu rezerwacji lotów, który miał też umożliwiać rezerwowanie
20 czerwca            samochodów i pokoi hotelowych.
1992. Artykuł
cytowany              AMR zaprzestała rozwijania swojego nowego systemu rezerwacji Confirm w parę
na grupie             tygodni po upływie pierwotnego terminu oddania go do użytku, kiedy to miała ruszyć
dyskusyjnej           współpraca w zakresie obsługi rezerwacji z partnerami firmy: Budget Rent-A-Car,
„comp.risks”,         HiltonHotels Corp. oraz Marriott Corp. Zawieszenie czteroletniego projektu, który
13.67,
w czerwcu
                      pochłonął 125 milionów dolarów, doprowadziło do zmniejszenia zysków netto firmy
1992. Niektóre        o 165 milionów dolarów i zrujnowało jej reputację lidera branży. […]
fragmenty
pominąłem.
                      Już w styczniu kierownictwo projektu Confirm zdało sobie sprawę z tego, że wysiłki
                      ponad 200 programistów, analityków systemowych i inżynierów poszły na marne.
                      Najważniejsze elementy tego ogromnego projektu, których dokumentacja zajęła 47 000
                      stron, były rozwijane niezależnie od siebie i w dodatku przy użyciu różnych technik.
                      Po złożeniu ich w jedną całość okazało się, że mimo wysiłków programistów, nie chcą
                      ze sobą współpracować. Poszczególne „moduły” aplikacji nie dawały sobie rady
                      z „wyciąganiem” potrzebnych im informacji z innych modułów.
                      Firma AMR Information Services zwolniła wtedy ośmiu głównych programistów,
                      w tym kierownika projektu.[…] Pod koniec czerwca firmy Budget i Hilton ogłosiły,
                      że wycofują się z projektu.

                      Kluczem do zgodności jest homogeniczność projektu i wypracowanie jednego stan-
                 dardu przesyłania informacji wewnątrz aplikacji. W tym celu należy zastosować:

                  • standaryzowane formaty plików, tak jak w systemie operacyjnym Unix, w którym
                    każdy plik tekstowy jest po prostu sekwencją znaków,
                  • standaryzowane struktury danych, tak jak w programach napisanych w języku Lisp,
                    w których wszystkie dane i programy są reprezentowane przez drzewa binarne,
                    nazywane listami,
                  • standaryzowane interfejsy użytkownika, tak jak w różnych wersjach systemu Win-
                    dows, OS/2 czy MacOS, w których wszystkie narzędzia komunikują się z użytkow-
                    nikiem w taki sam sposób, oparty na wykorzystaniu standardowych komponentów,
                    takich jak okna, ikony, menu itd.

Informacje            Bardziej ogólne rozwiązania uzyskujemy, definiując standaryzowane protokoły
na temat abs-    dostępu do wszystkich istotnych elementów, na których operuje oprogramowanie.
trakcyjnych
typów danych     Właśnie ta idea stoi za abstrakcyjnymi typami danych i podejściem obiektowym, a także
znajdziesz       za tak zwanymi protokołami warstwy pośredniczącej, takimi jak CORBA czy OLE-COM
w rozdziale 6.   (ActiveX) Microsoftu.
36                                                   ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA




Wydajność
                                Definicja wydajności
  Wydajność to zdolność programu do stawiania komputerowi jak najmniejszych
  wymagań sprzętowych, rozumianych między innymi jako czas procesora, prze-
  strzeń zajmowana w pamięci wewnętrznej i zewnętrznej, szerokość pasma wyko-
  rzystywanego przy przesyłaniu danych itd.

Środowisko programistów wykazuje zazwyczaj dwa różne podejścia do problemu wy-
dajności.

 • Niektórzy programiści mają na tym punkcie obsesję, w związku z czym poświę-
   cają mnóstwo czasu na optymalizację kodu i wkładają w nią wiele wysiłku.
 • Jednak istnieje również inna tendencja, przejawiająca się w mądrościach ludo-
   wych, takich jak „najpierw spraw, żeby to działało, a dopiero potem zajmij się
   przyspieszaniem”, czy „za rok komputery i tak będą o połowę szybsze”.

      Często zdarza się, że ta sama osoba raz jest zwolennikiem pierwszej, a raz dru-
giej teorii. To swego rodzaju programistyczne rozdwojenie jaźni (Dr Abstrakcja i Mr
Mikrosekunda).
      Które podeście jest lepsze? Cóż, programiści udowadniali już wielokrotnie, że
kwestię optymalizacji kodu potrafią traktować przesadnie. Jak już wspomniałem, wy-
dajność nie na wiele się zda, jeżeli oprogramowanie nie jest poprawne (to prowadzi do
sformułowania kolejnej złotej zasady: „nie przejmuj się tym, czy program jest szybki,
dopóki nie jest poprawny”, która przypomina poprzednią, ale nie do końca znaczy to
samo). Mówiąc bardziej ogólnie, musimy wprowadzić pewną równowagę między
potrzebami w zakresie wydajności a pozostałymi celami, takimi jak rozszerzalność czy
przystosowanie do wielokrotnego użycia. Przesadne optymalizacje mogą uczynić apli-
kację tak wyspecjalizowaną, że nie będzie się poddawała modyfikacjom, ani nada-
wała do wielokrotnego wykorzystania. Ponadto stale rosnąca szybkość komputerów
pozwala przyjąć bardziej luźne podejście do kwestii wydajności i zwalnia z walki o każdy
bajt i każdą mikrosekundę.
      Jednak żaden z tych czynników nie umniejsza znaczenia wydajności. Nikt nie
lubi czekać na reakcję interaktywnych aplikacji ani dokupywać pamięci tylko po to,
żeby w ogóle można było uruchomić dany program. Także luźne podejście do wydaj-
ności często jest tylko pozą. Jeżeli końcowa wersja aplikacji jest tak wolna, że trudno
z niej normalnie korzystać, to nawet osoby twierdzące, że „szybkość nie ma znaczenia”,
zaczynają narzekać.
      Ta kwestia odzwierciedla coś, co — moim zdaniem — najlepiej charakteryzuje
inżynierię oprogramowania (i myślę, że to się szybko nie zmieni). Tworzenie opro-
gramowania jest trudne głównie dlatego, że wymaga brania pod uwagę wielu różnych
czynników, z których jedne, takie jak poprawność, są abstrakcyjne i względne, a inne,
takie jak wydajność, bardzo konkretne i związane z właściwościami konkretnego
sprzętu komputerowego.
      Dla niektórych naukowców tworzenie oprogramowania jest dziedziną matema-
tyki. Dla innych jest to gałąź techniki. W rzeczywistości obie grupy mają rację. Pro-
gramista musi pogodzić abstrakcyjne idee i założenia z niedoskonałymi możliwościami
ich implementacji, a teorie matematyczne niezbędne do przeprowadzenia poprawnych
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                                     37

obliczeń z ograniczeniami czasowymi i przestrzennymi, wynikającymi z praw fizyki
i z niedoskonałości współczesnego sprzętu. Prawdopodobnie ta potrzeba zadowolenia
zarówno wilków, jak i owiec, stanowi największe wyzwanie inżynierii oprogramowania.
      Choć stale rosnąca szybkość komputerów robi duże wrażenie, nie można z jej
powodu zaniechać wysiłków na rzecz uzyskania wysokiej wydajności i to co najmniej
z trzech powodów.

 • Ktoś, to kupuje większy i szybszy komputer, chce w ten sposób osiągnąć jakieś
   konkretne korzyści — mieć możliwość rozwiązywania nowych problemów bądź
   szybszego rozwiązywania dotychczasowych lub też rozwiązywania starych pro-
   blemów w takim samym czasie jak dawniej, tyle że rozpatrywanych w większej
   skali. Natomiast kupowanie nowego komputera po to, aby rozwiązywać stare
   problemy w takim samym czasie co poprzednio, po prostu nie ma sensu!
 • Jednym z najbardziej widocznych skutków zwiększania się szybkości komputerów
   jest wzrost przewagi dobrych algorytmów nad kiepskimi. Załóżmy, że nowy kom-
   puter jest dwa razy szybszy od starego. Niech n określa rozmiary problemu, który
   należy rozwiązać, zaś N będzie maksymalnym n, jakie dany algorytm jest w sta-
   nie obsłużyć w danym czasie. Jeżeli algorytm ma złożoność O(n), to znaczy wy-
   konuje się w czasie proporcjonalnym do n, to wówczas nowy komputer pozwoli
   rozwiązać problem o rozmiarze 2∗N (dla dużego N). W przypadku algorytmów
   w postaci O(n2) nowy komputer pozwoli zwiększyć N jedynie o 41%. Natomiast
   algorytm typu O(2n), taki jak pewne algorytmy wyszukiwania, zwiększy N jedy-
   nie o jeden. Nie za dużo, jak na wydane pieniądze.
 • W niektórych sytuacjach wydajność może wpływać na poprawność. W specyfi-
   kacji może być na przykład napisane, że komputer musi zareagować na określone
   zdarzenie nie później niż po upływie określonego czasu. Na przykład komputer
   pokładowy w samolocie musi być przygotowany na wykrycie i przetworzenie
   komunikatu od czujnika przepustnicy w czasie na tyle krótkim, aby było możli-
   we przeprowadzenie ewentualnej korekty lotu. Takie powiązanie między wydaj-
   nością a poprawnością nie jest ograniczone jedynie do programów, które potocz-
   nie nazywa się aplikacjami czasu rzeczywistego. Mało kto uświadamia sobie, że
   z podobną sytuacją mamy do czynienia w programach przewidujących pogodę
   na następny dzień, które analizują na bieżąco dane napływające przez 24 godziny.

     Inna przykładowa sytuacja, która może nie stanowiła wielkiego problemu, ale strasznie
     mnie denerwowała. Używałem kiedyś systemu zarządzania oknami, który był na tyle
     wolny, że zdarzało mu się nie zarejestrować przesunięcia kursora myszy z jednego okna
     do drugiego. W rezultacie znaki wpisywane przeze mnie na klawiaturze nie trafiały
     do tego okna, do którego powinny.
     W tym przypadku ograniczenia wydajności powodują naruszenie specyfikacji, a konkretnie
     wpływają na poprawność, a to nawet w niewinnych, używanych na co dzień aplikacjach
     może mieć niemiłe konsekwencje. Pomyśl, co mogłoby się stać, gdyby dwa otwarte na
     ekranie okna, o których wspomniałem, były oknami nowych wiadomości pocztowych,
     skierowanych do dwóch różnych odbiorców. Wojny wybuchały już z dużo bardziej
     błahych powodów.

    Ponieważ w tej książce skupiam się na założeniach inżynierii obiektowej, a nie
na kwestiach implementacyjnych, tylko w kilku podrozdziałach piszę wprost o kosztach
w zakresie wydajności aplikacji. Musisz jednak pamiętać, że problem istnieje i że jestem
38                                                 ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA



jego świadomy. Za każdym razem gdy omawiam przykładowe obiektowe rozwiązanie
jakiegoś problemu, możesz być pewien, że przemyślałem je tak, aby było nie tylko
eleganckie, ale też wydajne. Zawsze gdy wprowadzam jakiś nowy mechanizm obiek-
towy, taki jak odzyskiwanie pamięci (i inne techniki zarządzania pamięcią w aplika-
cjach obiektowych), wiązanie dynamiczne, generyczność czy wielokrotne dziedziczenie,
pamiętam o tym, że musi on być zaimplementowany w taki sposób, aby był wydajny
pod względem czasu i wymaganej przestrzeni. Dlatego tam, gdzie uznam to za przy-
datne, będę wspominał o wpływie przyjętego podejścia na wydajność.
     Wydajność jest tylko jednym z czynników składających się na jakość. Dlatego nie
powinniśmy (jak niektórzy nasi koledzy po fachu) dopuszczać do tego, żeby kierowała
naszymi działaniami. Niemniej jednak należy o niej pamiętać, zarówno przy tworzeniu
konkretnej aplikacji, jak i na etapie projektowania nowego języka programowania.
Jeżeli powiesz wydajności: „Do widzenia”, wydajność to samo powie Tobie.



Przenośność
                              Definicja przenośności
  Przenośność to łatwość, z jaką dane oprogramowanie daje się przenosić między
  różnymi środowiskami sprzętowymi i programowymi.


Tak więc przenośność nie odnosi się jedynie do różnic między fizycznymi urządzeniami
sprzętowymi, ale do bardziej ogólnej, sprzętowo-programowej natury komputera.
Tej, z którą mamy styczność, pisząc aplikacje, a więc między innymi do systemu ope-
racyjnego, systemu okien (jeśli jest on stosowany) i innych podstawowych narzędzi.
W dalszej części książki tego rodzaju urządzenie sprzętowo-programowe nazywać
będziemy „platformą”. Przykładem platformy jest na przykład „komputer z proceso-
rem Intel X86, pracujący pod kontrolą Windows NT”, w skrócie „Wintel”.
      Wiele obecnych niezgodności między różnymi platformami wydaje się nie mieć
sensownego usprawiedliwienia. Naiwny obserwator mógłby nawet stwierdzić, że z pew-
nością chodzi o spisek przeciwko ludzkości, a w szczególności przeciw programistom.
W każdym razie, niezależnie od przyczyn takiego stanu rzeczy, różnorodność sprawia,
że przenośność oprogramowania jest wielkim problemem zarówno dla programistów,
jak i użytkowników.



Łatwość obsługi
                             Definicja łatwości obsługi
  Łatwość obsługi to łatwość, z jaką ludzie o różnym doświadczeniu i kwalifikacjach
  mogą nauczyć się korzystania z aplikacji i stosowania ich do rozwiązywania pro-
  blemów. Termin ten obejmuje też łatwość instalacji i nadzorowania pracy systemu.
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                                   39

                 W definicji tej położono nacisk na zróżnicowanie poziomu umiejętności potencjalnych
                 użytkowników. Stanowi to jedno z największych wyzwań dla projektantów aplikacji
                 zajmujących się kwestiami łatwości obsługi. W jaki sposób zapewnić odpowiednią po-
                 moc początkującym i wszystko im wyjaśnić, a przy tym nie zanudzić doświadczonych
                 użytkowników, którzy od razu chcą zabrać się do pracy?
                      Podobnie jak w przypadku wielu innych czynników opisywanych w tym roz-
                 dziale, jednym z kluczy do osiągnięcia łatwości obsługi jest zastosowanie prostej struktury
                 programu. Dobrze zaprojektowany system, zbudowany w oparciu o przejrzystą, prze-
                 myślaną strukturę, będzie łatwiejszy do poznania niż program, w którym panuje duży
                 bałagan. Oczywiście nie jest to warunek wystarczający (to, co może być proste i jasne
                 dla projektanta, użytkownikom może wydawać się dziwne i trudne, zwłaszcza jeśli zo-
                 stanie opisane językiem, jakim posługują się projektanci, a nie użytkownicy), ale za-
                 stosowanie się do niego bardzo pomaga.
                      Jest to jeden z obszarów, w których technika obiektowa jest szczególnie przy-
                 datna. Pewne metody, które na pierwszy rzut oka wydają się dotyczyć zagadnień
                 projektowych i implementacyjnych, pozwalają też stworzyć nowego rodzaju interfejsy
                 użytkownika, które ułatwiają obsługę aplikacji. W następnych rozdziałach podam wiele
                 konkretnych przykładów.
Patrz Wilfred         Projektanci oprogramowania zajmujący się zagadnieniem łatwości obsługi po-
J.Hansen,        winni ostrożnie podchodzić do sloganu najczęściej cytowanego w literaturze fachowej,
„User Engi-
neering          pochodzącego ze starego artykułu Hansena, który brzmi: „Poznaj użytkownika”. Stoi
Principles for   za nim argument, że dobry projektant powinien poświęcić czas na poznanie docelowej
Interactive      społeczności użytkowników programu. Jednak takie podeście nie uwzględnia jednej
Systems”,
Sprawozdanie
                 z charakterystycznych cech programów, które odnoszą rynkowy sukces. Po jakimś
z FJCC 39,       czasie są one wykorzystywane przez szerszą grupę użytkowników, niż pierwotnie są-
AFIPS Press,     dzono. (Dwoma dobrymi przykładami są tu Fortran, który miał być początkowo na-
Montvale
(NJ), 1971,
                 rzędziem służącym do rozwiązywania problemów, jakie napotkała mała grupa na-
s. 523 – 532.    ukowców i inżynierów zajmujących się pisaniem programów na komputer IBM 704,
                 oraz system operacyjny Unix, który pierwotnie miał służyć jedynie do wewnętrznych
                 zastosowań w firmie Bell Laboratories). Każdy system zaprojektowany z myślą o specy-
                 ficznej grupie użytkowników będzie oparty na założeniach, które po prostu przestaną
                 być adekwatne dla szerszego grona odbiorców.
                      Dlatego dobrzy projektanci interfejsów użytkownika trzymają się bardziej ostroż-
                 nej zasady. Czynią oni tak mało założeń dotyczących przyszłych użytkowników, jak
                 to możliwe. Projektując interaktywny program komputerowy, możesz oczekiwać, że
                 jego użytkownicy będą przedstawicielami rasy ludzkiej i będą potrafili czytać, poru-
                 szać myszą, klikać przycisk i pisać (powoli), nic ponadto. Jeżeli aplikacja ma służyć
                 do rozwiązywania problemów z jakiejś konkretnej dziedziny, można też pewnie zało-
                 żyć, że jej użytkownicy będą mieli choć podstawową wiedzę w tym zakresie. Ale nawet
                 takie założenie jest już ryzykowne. Parafrazując radę Hansena, mogę sformułować
                 zasadę projektowania interfejsu użytkownika.


                                    Zasada projektowania interfejsu użytkownika
                   Nie udawaj, że znasz użytkownika. Nie znasz.
40                                                   ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA




Funkcjonalność
                              Definicja funkcjonalności
  Funkcjonalność to zbiór możliwości oferowanych przez system.

Jednym z największych problemów, przed jakimi stają szefowie projektów, jest okre-
ślenie, jak duża funkcjonalność jest już wystarczająca. W przemyśle programistycz-
nym stale odczuwa się nacisk na dodawanie do programów kolejnych możliwości, co
powszechnie nazywane jest pogonią za wodotryskami. Jej konsekwencje są złe już dla
wewnętrznych projektów, w których naciski pochodzą ze strony pracowników tej samej
firmy, a w przypadku produktów komercyjnych jeszcze gorsze. Niestety większość pism
komputerowych przy sporządzaniu recenzji kilku konkurencyjnych produktów zazwy-
czaj skupia się jedynie na przedstawieniu tabeli, w której porównuje się ich możliwości.
      Pogoń za możliwościami to właściwie dwa oddzielne problemy, z których jeden
jest trudniejszy do rozwiązania. Prostszy problem polega na tym, że, dodając nowe funk-
cje, możemy utracić spójność, co odbije się na łatwości obsługi. Użytkownicy często
narzekają, że wszystkie te „wodotryski” dodawane do kolejnych wersji znanych pro-
gramów czynią je jedynie niesamowicie złożonymi. Tego rodzaju uwagi trzeba jednak
traktować z przymrużeniem oka, ponieważ nowe funkcje nie biorą się z próżni. Zwykle
proszą o nie użytkownicy, tyle że niekoniecznie ci sami. To, co mnie wydaje się świet-
nym ułatwieniem, dla Ciebie może być tylko nieprzydatnym gadżetem.
      Jedynym rozwiązaniem jest tu stała praca nad zachowaniem spójności całego
programu i podejmowanie prób wciśnięcia wszystkich funkcji w już wyznaczone ramy.
Każdy dobry program opiera się na kilku nowatorskich pomysłach. Jeśli nawet ma on
wiele funkcji, powinny one wynikać z podstawowych założeń. W konstrukcji pro-
gramu musi być widoczny jakiś konkretny plan, w którym każdy element ma swoje
miejsce.
      Trudniejszy problem polega na tym, iż można tak bardzo zaangażować się w do-
dawanie nowych funkcji, że zapomni się o innych czynnikach. Jest to powszechnie
popełniany błąd, zobrazowany przez Rogera Osmonda na wykresie w postaci dwóch
możliwych ścieżek prowadzących do ukończenia projektu (patrz rysunek 1.4).




                                                                     RYSUNEK 1.4.
                                                                     Krzywe Osmonda,
                                                                     za [Osmond 1995]
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                                 41

                      W życiu sytuacja wygląda najczęściej tak, jak pokazuje to dolna (czarna) krzywa.
                W szaleńczym wyścigu za dodawaniem nowych funkcji programiści zapominają o ogól-
                nej jakości programu. Ostatnia faza projektu, w której wszystko powinno być już do-
                prowadzone do porządku, potrafi być długa i stresująca. Jeżeli pod wpływem presji
                użytkowników lub konkurencji jesteś zmuszony do wypuszczenia programu we wcze-
                snej fazie produkcji, na jednym z etapów oznaczonych na wykresie czarnymi kwa-
                dratami, pamiętaj, że może to zaszkodzić Twojej reputacji.
                      Osmond sugeruje (krzywa linią przerywaną), abyś — korzystając z możliwości,
                jakie daje programowanie zorientowane obiektowo — utrzymywał ogólną jakość
                programu (poza funkcjonalnością) przez cały czas na takim samym poziomie. Chodzi
                więc o to, abyś nigdy nie oszczędzał na niezawodności, rozszerzalności itp. Nie wolno
                Ci dodawać nowych funkcji, dopóki te, które już masz, będą działać, tak jak trzeba.
                      Takie podejście jest trudniejsze do stosowania na co dzień ze względu na wspo-
                mniane naciski, ale prowadzi do wydajniejszego procesu tworzenia aplikacji, a często
                także do uzyskania w ostatecznym rozrachunku lepszego produktu. Jeśli nawet koń-
                cowe rezultaty są w obu przypadkach takie same, tak jak na przytoczonym wykresie,
                to postępując zgodnie z podanymi zasadami, powinniśmy uzyskać je szybciej (wykres
                nie uwzględnia czasu). Gdy trzymamy się sugerowanej ścieżki rozwoju projektu,
                ewentualne wypuszczenie wczesnej wersji programu (na jednym z etapów oznaczo-
                nych ukośnie kreskowanymi kwadratami) jest znacznie łatwiejsze. Trzeba jedynie
                odpowiedzieć sobie na pytanie, czy zakres funkcjonalności, który został już zaim-
                plementowany w programie, jest wystarczająco szeroki, aby przyciągnąć do niego
                klientów i nie zrazić niektórych z nich. Natomiast nie musimy już zastanawiać się
                „czy to jest wystarczająco dobre”.
                      Każdy czytelnik, który miał już okazję kierować jakimś projektem programi-
                stycznym, przyzna, że dużo łatwiej dawać takie rady, niż je stosować. Niemniej jednak
                w przypadku każdego projektu powinno się dążyć do ideału reprezentowanego przez
                wyższą krzywą Osmonda. Doskonale współgra on z modelem klastrowym wprowa-
                dzonym w jednym z kolejnych rozdziałów i będącym jednym ze schematów prowa-
                dzenia projektu programistycznego.



                Adekwatność czasowa
                                          Definicja adekwatności czasowej
                  Adekwatność czasowa to gotowość programu komputerowego do wypuszczenia na ry-
                  nek wtedy, gdy użytkownicy go potrzebują, lub jeszcze zanim pojawi się taka potrzeba.

                W przemyśle programistycznym jednym z najbardziej stresujących czynników jest
                adekwatność czasowa. Doskonały produkt, który pojawi się na rynku za późno, może
                okazać się całkowitą klapą. Oczywiście tak samo jest też w innych gałęziach przemysłu,
                ale niewiele z nich podlega tak szybkim zmianom.
„NT 4.0 Beat-        Adekwatność czasowa jest czymś rzadko spotykanym, nawet w przypadku du-
sClock”, Com-   żych projektów programistycznych. Gdy Microsoft ogłosił, że najnowsza wersja jego
puter-World,
nr 30, 22       sztandarowego systemu operacyjnego, tworzonego przez wiele lat, zostanie wypusz-
czerwca 1996.   czona na rynek o miesiąc wcześniej, niż zakładano, uznano to za tak sensacyjną wia-
                domość, że zamieszczono ją na okładce magazynu ComputerWorld (wraz z komenta-
                rzem na temat długich opóźnień, które zdarzały się tej firmie w przeszłości).
42                                                 ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA




Inne czynniki

Poza już omówionymi czynnikami decydującymi o jakości, istnieją też inne, mające
wpływ na użytkowników, decydentów zamawiających systemy komputerowe i pro-
gramistów. Oto niektóre z nich.

 • Weryfikowalność, czyli łatwość przygotowywania procedur pozwalających okre-
   ślić, czy produkt znajduje się na akceptowalnym poziomie. W szczególności chodzi
   tu o dane testowe i procedury pozwalające na wykrywanie niepowodzeń i odnaj-
   dywanie tych błędów popełnionych na etapie walidacji danych i w fazie operacyjnej,
   które są przyczyną niepowodzeń.
 • Integralność, czyli zdolność oprogramowania do chronienia swoich składników
   (programów, danych) przed nieautoryzowanym dostępem i modyfikacjami.
 • Naprawialność, czyli udostępnianie możliwości naprawiania defektów.
 • Ekonomiczność, będąca uzupełnieniem adekwatności czasowej, czyli zdolność
   systemu do zmieszczenia się w założonym budżecie.



Dokumentacja

Analizując listę czynników decydujących o jakości, możesz dojść do wniosku, że jednym
z wymagań powinna być dobra dokumentacja. Jednak nie jest to odrębny składnik.
Potrzeba takiej dokumentacji wynika z pozostałych czynników, które już omówiłem.
Możemy wyróżnić trzy rodzaje dokumentacji.

 • Dokumentacja zewnętrzna, dzięki której użytkownicy mogą zrozumieć możliwo-
   ści systemu i wygodnie z nich korzystać. Jest to konsekwencja wymagania zde-
   finiowanego jako łatwość obsługi.
 • Dokumentacja wewnętrzna, która pozwala zrozumieć strukturę i implementację
   systemu programistom. Jest to konsekwencja wymagania zdefiniowanego jako
   rozszerzalność.
 • Dokumentacja interfejsów poszczególnych modułów, dzięki której programiści
   mogą zrozumieć działanie funkcji dostarczanych przez dany moduł bez potrzeby
   zagłębiania się w jego implementację. Jest to konsekwencja wymagania zdefi-
   niowanego jako przystosowanie do wielokrotnego użycia. Wynika ona również
   z rozszerzalności, ponieważ dokumentacja interfejsów modułów pozwala określić,
   czy dana zmiana będzie miała wpływ na konkretny moduł.

     Dlatego, zamiast traktować dokumentację jako osobny produkt, lepiej pisać mak-
symalnie samodokumentujący się kod. Zasada ta odnosi się do wszystkich trzech ro-
dzajów dokumentacji.

 • Uwzględniając w programie podsystem pomocy ekranowej, a także trzymając się
   jasnych i spójnych konwencji przy tworzeniu interfejsu użytkownika, ułatwiamy
   zadanie autorom podręczników użytkownika i innych materiałów dydaktycznych.
1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH                                              43

 • Zaimplementowanie programu w dobrym języku programowania zlikwiduje w dużej
   mierze konieczność tworzenia wewnętrznej dokumentacji, jeśli tylko język ten
   będzie sprzyjał organizacji i przejrzystości kodu. Są to jedne z najważniejszych
   czynników wpływających na wygląd notacji obiektowej, którą będę wprowadzał
   w tej książce.
 • Notacja ta będzie obsługiwała ukrywanie informacji i inne techniki (takie jak aser-
   cje) pozwalające oddzielić interfejsy modułów od ich implementacji. Pozwoli to
   zastosować narzędzia, które automatycznie wygenerują dokumentację interfej-
   sów modułów na podstawie ich kodów źródłowych. Tym zagadnieniem również
   zajmiemy się dokładnie w dalszych rozdziałach.

     Wszystkie te techniki ograniczają znaczenie tradycyjnej dokumentacji, ale oczywi-
ście nie możemy od nich oczekiwać, aby całkowicie ją zastąpiły.



Kompromisy
W tym przeglądzie zewnętrznych czynników składających się na jakość oprogramo-
wania pojawiły się już wymagania, które kłócą się z innymi.
     Czy jest możliwe osiągnięcie integralności bez wprowadzania żadnych zabezpieczeń?
Z kolei wprowadzenie ich musi się negatywnie odbić na łatwości obsługi. Ekonomicz-
ność często wydaje się stać w sprzeczności z funkcjonalnością. Uzyskanie optymalnej
wydajności wymagałoby perfekcyjnego wykorzystania możliwości oferowanych przez
dane środowisko sprzętowe i programowe, co kłóci się z przenośnością. Z jednej strony,
mówi się nam, żebyśmy trzymali się ściśle specyfikacji, a z drugiej, popycha się nas
w kierunku tworzenia ogólnych rozwiązań, które nadawałyby się do wielokrotnego
użycia. Naciski na adekwatność czasową mogą skłaniać ku środowiskom szybkiego
tworzenia aplikacji (RAD), przy których mamy mocno ograniczoną rozszerzalność.
     Choć w wielu przypadkach daje się znaleźć rozwiązanie pozwalające pogodzić
ze sobą sprzeczne wymagania, czasami trzeba poświęcić pewne czynniki na rzecz
drugich. Niestety zbyt często programiści robią to niejawnie, nie zastanowiwszy się
wcześniej nad wszystkimi dostępnymi możliwościami i ich konsekwencjami. W re-
zultacie najczęściej skupiają się na wydajności. Natomiast prawdziwy inżynier oprogra-
mowania powinien zadać sobie trud jawnego sformułowania kryteriów, którymi będzie
posługiwał się przy wyborze, i podjąć w pełni świadome decyzje.
     Choć między czynnikami decydującymi o jakości trzeba często dokonywać wy-
borów, nie wolno nigdy zapomnieć, że najważniejszym z nich jest poprawność. Nic
nie usprawiedliwia zaniedbania poprawności na rzecz innych czynników, na przykład
takich jak wydajność. Jeżeli oprogramowanie nie spełnia swojej roli, to reszta nie ma
znaczenia.



Kluczowe zagadnienia
Wszystkie opisywane dotychczas czynniki są ważne. Ale w obecnym stanie przemy-
słu programistycznego cztery z nich wydają się mieć szczególne znaczenie. Są to:
44                                                ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA



 • Poprawność i odporność. W dalszym ciągu tworzenie oprogramowania pozba-
   wionego defektów jest zbyt trudne, podobnie jak usuwanie błędów, gdy już uda
   się je zlokalizować. Wszystkie techniki służące zwiększaniu poprawności i od-
   porności opierają się na tych samych pomysłach — zastosowaniu bardziej usys-
   tematyzowanego podejścia do tworzenia oprogramowania, stosowaniu bardziej
   formalnych specyfikacji, użyciu wbudowanych mechanizmów kontrolnych już
   na etapie tworzenia oprogramowania (a nie bazowanie jedynie na testowaniu i usu-
   waniu błędów już po zakończeniu projektu), wykorzystanie lepszych mechani-
   zmów językowych, takich jak statyczna kontrola typów, asercje, automatyczne
   zarządzanie pamięcią czy zdyscyplinowana obsługa wyjątków, które pozwalają
   programistom spełniać wymagania dotyczące poprawności i odporności, a na-
   rzędziom programistycznym wykrywać wszelkie niespójności, zanim doprowadzą
   one do powstania defektów. Ze względu na tak bliskie powiązanie poprawności
   z odpornością, wygodniej stosować bardziej ogólny termin — obejmujący swym
   znaczeniem oba te czynniki — niezawodność.
 • Rozszerzalność i przystosowanie do wielokrotnego użycia. Oprogramowanie po-
   winno dawać się łatwiej modyfikować. Tworzone przez nas komponenty pro-
   gramistyczne powinny stwarzać możliwość zastosowania w większej liczbie sytu-
   acji. Powinno ich też być więcej. Również w przypadku tych dwóch czynników
   źródłem usprawnień są te same pomysły. Ogólnie można by rzec, że pomocne są
   wszystkie techniki, które przyczyniają się do tworzenia bardziej zdecentralizo-
   wanych architektur, w których komponenty mają budowę zamkniętą i komunikują
   się ze sobą jedynie za pomocą ograniczonych i ściśle zdefiniowanych kanałów.
   Rozszerzalność i przystosowanie do wielokrotnego użycia będziemy określali
   wspólnym terminem modułowości.

     Technika obiektowa, z którą zapoznasz się dokładnie w kolejnych rozdziałach,
pozwala wyraźnie ulepszyć te cztery czynniki decydujące o jakości, co czyni ją tak
atrakcyjną. Przyczynia się ona również w znacznym stopniu do spełnienia pozostałych
wymagań, szczególnie takich jak:

 • Zgodność. Technika obiektowa sprzyja stosowaniu jednolitego stylu projektowa-
   nia i tworzeniu standaryzowanych modułów i interfejsów, co z kolei pomaga two-
   rzyć systemy, które mają ze sobą współpracować.
 • Przenośność. Kładąc nacisk na abstrakcyjność i ukrywanie informacji, technika
   obiektowa zachęca projektantów do rozróżniania specyfikacji i implementacji,
   co ułatwia przenoszenie aplikacji na różne platformy. Techniki, takie jak polimor-
   fizm i wiązanie dynamiczne, pozwalają nawet tworzyć systemy, które automatycznie
   dostosowują się do zastanych komponentów platformy sprzętowo-programowej, na
   przykład do różnych systemów zarządzania oknami czy bazami danych.
 • Łatwość obsługi. Wpływ, jaki narzędzia obiektowe wywarły na współczesne in-
   teraktywne programy komputerowe, a w szczególności na ich interfejsy użyt-
   kownika, jest powszechnie znany. Czasami przypisuje się temu nawet większe
   znaczenie, niż by wypadało (twórcy reklam nie są jedynymi osobami, które każ-
   dy program, w jakim są ikony i okna, obsługiwany za pomocą myszy, nazywają
   obiektowym).
 • Wydajność. Jak już wspomniałem, mimo iż z zakupem szybkiego komputera i ze
   stosowaniem technik obiektowych wiąże się pewien koszt, możliwość wykorzy-
   stywania w procesie tworzenia oprogramowania profesjonalnych komponentów
   wielokrotnego użytku pozwala znacznie zyskać na wydajności.
1.3. KONSERWACJA OPROGRAMOWANIA                                                    45

 • Adekwatność czasowa, ekonomiczność i funkcjonalność. Techniki obiektowe po-
   zwalają tym, którzy opanują je do perfekcji, tworzyć programy szybciej i przy
   mniejszych kosztach. Ułatwiają one dodawanie nowych funkcji, a czasem wręcz
   sugerują, jakie możliwości przydałoby się jeszcze wprowadzić.

     Mimo oczywistego postępu, jaki niosą ze sobą techniki obiektowe, powinniśmy
pamiętać, że nie stanowią one panaceum i że w dalszym ciągu musimy rozwiązywać
wiele klasycznych problemów inżynierii programowania. To, że coś nam w tym pomaga,
nie oznacza jeszcze, że rozwiąże to problem za nas.




1.3. KONSERWACJA OPROGRAMOWANIA
Być może zauważyłeś, że nie wymieniłem dotąd często wspominanego czynnika de-
cydującego o jakości, jakim jest łatwość konserwacji. Aby zrozumieć, dlaczego tak
postąpiłem, musisz przyjrzeć się bliżej temu, czym właściwie jest konserwacja opro-
gramowania.
     Terminem konserwacja określamy wszystko, co robi się już po przekazaniu pro-
gramu odbiorcom. Wszystkie dyskusje na temat metodyki tworzenia oprogramowania
z reguły skupiają się jedynie na programowaniu. Podobne podejście obserwuje się na
kursach programowania dla początkujących. Tymczasem powszechnie wiadomo, że
70% kosztów tworzenia oprogramowania pochłania właśnie jego konserwacja. Żadne
omówienie zagadnienia jakości oprogramowania nie jest wystarczające, jeżeli pomija
się w nim ten aspekt.
     Zatem co rozumiemy przez „konserwację” w odniesieniu do oprogramowania?
Programy komputerowe nie zużywają się od ciągłego korzystania, a tym samym nie
trzeba ich „konserwować”, tak jak samochodów czy telewizorów. Można by więc rzec,
że jest to dość nietrafione określenie. Tym bardziej, że odnosi się ono zarówno do bar-
dziej, jak i do mniej chwalebnych zajęć. Do pierwszej grupy zaliczyć można wszelkie
modyfikacje. Wiadomo, że specyfikacje systemów komputerowych zmieniają się po
to, aby odzwierciedlać zmiany zachodzące w świecie zewnętrznym. Pociąga to za so-
bą konieczność modyfikowania samych programów. Natomiast do drugiej grupy zali-
czamy czynności służące do lokalizowania i usuwania błędów, których na tym etapie
projektu w ogóle nie powinno już być.
     Wykres przedstawiony na rysunku 1.5, pochodzący z pamiętnego opracowania
Lientza i Swansona, pokazuje już bardziej konkretnie, jakie zagadnienia mieszczą się
pod pojęciem konserwacji. Autorzy przepytali 487 zespołów programistycznych roz-
wijających aplikacje różnych typów. Mimo iż badanie odbyło się już jakiś czas temu,
wyniki najnowszych ankiet potwierdzają ich odkrycia. Wykres pokazuje, jaka część
kosztów konserwacji oprogramowania przypada na poszczególne zagadnienia, wyod-
rębnione przez autorów.
     Ponad dwie piąte kosztów przeznaczane jest na rozbudowywanie i modyfikowa-
nie aplikacji na życzenie użytkowników. Są to czynności, których praktycznie nie da
się uniknąć. Natomiast bez odpowiedzi pozostaje pytanie, ilu spośród tych wysiłków
można by uniknąć, gdyby oprogramowanie było od początku projektowane z myślą
o rozszerzalności. Mamy pełne podstawy sądzić, że technika obiektowa pozwoli po-
prawić tę sytuację.
46                                                         ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA




                                                                          RYSUNEK 1.5.
                                                                          Koszty konserwacji
                                                                          oprogramowania.
                                                                          Źródło: [Lientz 1980]


     Szczególnie interesująca jest druga pozycja — zmiany w formatach danych. Gdy                    Inny przykład
zmienia się fizyczna struktura plików i innych elementów przechowujących dane, trze-                 znajdziesz
                                                                                                     w podroz-
ba zaadaptować do tych zmian istniejące aplikacje. Gdy na przykład poczta w Stanach                  dziale:
Zjednoczonych przydzieliła parę lat temu dużym firmom kody pocztowe w postaci                        „Jak długi
„5+4” (złożone z dziewięciu znaków zamiast pięciu), trzeba było przepisać od nowa                    jest środkowy
                                                                                                     inicjał?”, na
wiele programów, które „wiedziały”, że kody pocztowe składają się dokładnie z pięciu                 stronie 167.
znaków. Prasa oszacowała, że kosztowało to kilkaset milionów dolarów.

     Zapewne wielu czytelników otrzymało swego czasu piękne zaproszenia na cykl konferencji
     (nie jedną czy dwie, ale cały cykl, prowadzony w wielu miastach) poświęconych
     „problemowi roku 2000”. Mówiono na nich, w jaki sposób unowocześnić wiele
     programów służących do przechowywania bardzo istotnych danych, których autorzy
     nawet przez chwilę nie pomyśleli, że po upływie XX wieku również trzeba będzie jakoś
     wprowadzać daty. W porównaniu z tym problem kodów pocztowych wydaje się błahostką.
     Jorge Luis Borges stwierdził, że skoro dziś mało kto zastanawia się, co stanie się 1 stycznia
     3000 roku, to prawdopodobnie możemy uznać, że był to jedyny cykl konferencji
     w historii ludzkości poświęcony tak niepozornemu tematowi — jednej dziesiętnej cyfrze.

     Nie chodzi o to, że jakaś część programu zna fizyczną strukturę danych. To jest
akurat nieuniknione, ponieważ w pewnym momencie program musi mieć dostęp do
danych po to, aby mógł przeprowadzić na nich jakieś operacje. Jednak w tradycyj-
nych technikach projektowania ta wiedza jest dostępna w zbyt wielu częściach syste-
mu, przez co po zmianie fizycznej struktury danych (a to zawsze kiedyś następuje)
trzeba modyfikować wiele fragmentów programu, a wcale nie musi tak być. Innymi sło-
wy, jeżeli kody pocztowe zostaną wydłużone z pięciu do dziewięciu znaków, a daty
zaczną wymagać stosowania dodatkowej cyfry, będzie można mieć uzasadnione po-
dejrzenia, że należy zaadaptować do tych zmian programy operujące na tych wielko-
ściach. Natomiast nie do zaakceptowania jest sytuacja, w której informacje na temat
dokładnej długości danych są umieszczone w bardzo wielu miejscach w programie, tak
że zmiana tej długości pociąga za sobą konieczność modyfikowania niewspółmiernie
wielu fragmentów kodu.
1.4. KLUCZOWE POJĘCIA WPROWADZONE W TYM ROZDZIALE                                     47

                       Rozwiązaniem tego problemu są abstrakcyjne typy danych, dzięki którym pro-
                 gramy mogą odwoływać się do danych za pośrednictwem swych zewnętrznych wła-
                 ściwości, a nie fizycznych implementacji.
Szczegółowe            Kolejną ciekawą rzeczą dającą się zaobserwować na wykresie jest niski udział re-
omówienie
abstrakcyjnych
                 dagowania dokumentacji w całkowitych kosztach konserwacji (5,5%). Pamiętaj, że
typów danych     mówimy tu jedynie o kosztach czynności konserwacyjnych. Ponieważ na ten temat
znajdziesz       nie mamy bardziej precyzyjnych danych, możemy jedynie spekulować, iż wynika to
w rozdziale 6.
                 z tego, że albo dokumentacja tworzona jest na etapie rozwijania kodu, albo nie pisze
                 się jej wcale. W dalszej części książki poznasz styl projektowania, dzięki któremu większa
                 część dokumentacji trafia bezpośrednio do kodu źródłowego. Powiem też o specjalnych
                 narzędziach, które pozwalają ją stamtąd wydobyć.
                       Kolejne pozycje na liście Lientza i Swansona również są bardzo interesujące, choć
                 nie są, tak jak pozostałe, bezpośrednio związane z zagadnieniami poruszanymi w tej
                 książce. Awaryjne poprawki błędów (opracowywane w pośpiechu po tym, jak któryś
                 z użytkowników zgłosi, że program nie zwraca oczekiwanych wyników lub zachowuje
                 się w nieprawidłowy sposób) kosztują więcej niż rutynowe, zaplanowane poprawki.
                 Wynika to nie tylko z tego, że wymagają one pracy pod dużą presją, ale również z tego,
                 że konieczność ich przygotowania zmienia ustalony harmonogram wypuszczania no-
                 wych wersji programu, a w dodatku może prowadzić do wprowadzenia nowych błędów.
                 Ostatnie dwie czynności mają niewielki udział w kosztach.

                  • Pierwszą z nich jest zwiększanie wydajności. Wykres zdaje się sugerować, że gdy
                    system już działa, szef projektu i programiści nie chcą go ruszać, żeby go nie ze-
                    psuć, nawet jeśli potencjalnie mogliby zwiększyć jego wydajność. Gdy przy-
                    pomnimy sobie zasadę: „najpierw spraw, żeby to działało, a dopiero potem zajmij
                    się przyspieszaniem”, dojdziemy do wniosku, że widocznie większość projektów
                    zatrzymuje się na tej pierwszej czynności.
                  • Podobnie niski udział w kosztach ma również „przenoszenie do nowych środo-
                    wisk”. Można to interpretować w ten sposób (podobnie jak poprzednio nie mamy
                    bardziej szczegółowych danych), że pod względem przenośności programy dzielą
                    się zasadniczo na dwie kategorie, a między nimi właściwie nic nie ma, czyli na
                    programy, które od początku były projektowane z myślą o przenośności, gdzie
                    przeprowadzenie takiej operacji nie jest zbyt kosztowne, oraz programy tak mocno
                    przywiązane do swoich pierwotnych platform, że przeniesienie ich na inne byłoby
                    tak trudne, iż programiści nawet nie próbują tego robić.




                 1.4. KLUCZOWE POJĘCIA
                        WPROWADZONE W TYM ROZDZIALE
                  • Zadaniem inżynierii oprogramowania jest opracowywanie sposobów tworzenia
                    wysokich jakościowo programów komputerowych.
                  • Jakość oprogramowania nie jest pojedynczą wielkością. Należy ją raczej rozpa-
                    trywać jako sumę wielu różnych czynników, które w każdym programie występują
                    w nieco innych proporcjach.
48                                                ROZDZIAŁ 1.   JAKOŚĆ OPROGRAMOWANIA



 • Należy odróżniać zewnętrzne czynniki składające się na jakość, czyli te dostrze-
   gane przez użytkowników i klientów, od czynników wewnętrznych, widocznych
   jedynie dla projektantów i implementatorów.
 • Liczą się jedynie czynniki zewnętrzne, ale do ich uzyskania niezbędne są odpo-
   wiednie czynniki wewnętrzne.
 • Przedstawiłem listę najważniejszych czynników zewnętrznych decydujących o ja-
   kości aplikacji. Te z nich, które najwięcej zyskałyby na wprowadzeniu nowych
   technik i do których bezpośrednio odnosi się metoda obiektowa, to czynniki zwią-
   zane z bezpieczeństwem (poprawność i odporność), określane wspólnie mianem
   niezawodności, oraz czynniki wymagające stosowania zdecentralizowanych ar-
   chitektur oprogramowania (przystosowanie do wielokrotnego użycia i rozszerzal-
   ność), określane mianem modułowości.
 • Konserwacja oprogramowania, na którą przypada większa część kosztów pro-
   jektu, jest trudna ze względu na fakt, że niełatwo implementuje się zmiany w ist-
   niejących programach, oraz z powodu nadmiernego uzależnienia programów od
   fizycznej struktury danych, na których one operują.




1.5. BIBLIOGRAFIA
Próbę zdefiniowania jakości oprogramowania podjęło już wielu autorów. Spośród
pierwszych opracowań na ten temat dwa pozostają wciąż zaskakująco aktualne: arty-
kuł [Hoare 1972] oraz [Boehm 1978] — wyniki pierwszych usystematyzowanych ba-
dań na temat tworzenia oprogramowania, prowadzonych przez ludzi z TRW.
     Rozróżnienie między czynnikami zewnętrznymi a wewnętrznymi zostało wpro-
wadzone w materiałach przekazanych w 1977 roku lotnictwu Stanów Zjednoczonych
przez firmę General Electric [McCall 1977]. To, co my nazywamy czynnikami ze-
wnętrznymi, McCall określa po prostu mianem „czynników”, zaś na czynniki we-
wnętrzne mówi „kryteria”. Wiele (choć nie wszystkie) spośród opisanych przeze mnie
czynników stanowi bezpośrednie odpowiedniki czynników McCalla. Jeden z jego
czynników pominąłem (łatwość konserwacji), ponieważ, jak już wyjaśniłem, pokrywa
się on z rozszerzalnością i weryfikowalnością. W swych rozważaniach McCall nie
ogranicza się jedynie do czynników zewnętrznych, lecz opisuje też czynniki we-
wnętrzne („kryteria”), metryki oraz ilościowe techniki gwarantujące uzyskanie satys-
fakcjonujących czynników wewnętrznych. Jednak wraz z pojawieniem się techniki
obiektowej wiele z opisywanych przez niego czynników wewnętrznych i metryk
przestało mieć znaczenie ze względu na swe ścisłe powiązanie ze stosowanymi wcze-
śniej praktykami programistycznymi. Przystosowanie tej części pracy McCalla do
technik opisywanych w mojej książce jest całkiem interesującym wyzwaniem. Patrz
bibliografia i ćwiczenia w rozdziale 3.
     Omówienie zależności względnego wzrostu wydajności systemu (po wymianie
komputera na szybszy) od rodzaju stosowanego algorytmu wywodzi się z [Aho 1974].
     Klasyczną pozycją na temat łatwości obsługi jest [Shneiderman 1987], opierający
się na pracy [Shneiderman 1980], poświęconej szerszemu zakresowi zagadnień z dzie-
dziny programowania. Odnośniki do wielu materiałów na ten temat można też znaleźć
na stronie internetowej laboratorium Shneidermana, pod adresem http://www.cs.umd.
edu/projects/hcil/.
1.5. BIBLIOGRAFIA                                                                 49

     Krzywe Osmonda pochodzą z wykładu wygłoszonego przez Rogera Osmonda na
konferencji TOOLS USA [Osmond 1995]. Zwróć uwagę, że wykres pokazany w tym
rozdziale nie uwzględnia czasu, dzięki czemu możesz lepiej przyjrzeć się zależno-
ściom między funkcjonalnością a innymi czynnikami, wskazywanymi przez dwie al-
ternatywne krzywe. Pamiętaj jednak, że na tym wykresie nie widać, że postępowanie
zgodnie z czarną krzywą może doprowadzić do opóźnienia projektu. Oryginalne krzywe
Osmonda miały za zadanie ukazywać raczej czas rozwijania aplikacji, a nie zwięk-
szanie jej funkcjonalności.
     Wykres prezentujący koszty konserwacji programów pochodzi z wyników badań
przeprowadzonych przez Lientza i Swansona, którzy wysłali kwestionariusze do 487
firm [Lientz 1980]. Patrz również [Boehm 1979]. Mimo iż niektóre spośród zbiera-
nych przez nich danych dziś mogą wydawać się nieadekwatne (badanie dotyczyło
wsadowych aplikacji na komputery MIS, które składały się średnio z 23 000 wierszy
kodu, co jak na dzisiejsze warunki nie jest zbyt dużą liczbą), uzyskane przez nich wy-
niki nadal wyglądają sensownie. Stowarzyszenie Software Management Association
przeprowadza co roku ankietę na temat konserwacji. Wyniki jednej z nich znajdziesz
w [Dekleva 1992].
     Wyrażenia programowanie w dużej skali i programowanie w małej skali pochodzą
z [DeRemer 1976].
     Ogólne omówienie zagadnień z dziedziny inżynierii oprogramowania znajdziesz
w książce, którą napisali Ghezzi, Jazayeri i Mandrioli [Ghezzi 1991]. Dwóch spośród
tych autorów napisało też książkę o językach programowania, [Ghezzi 1997], stano-
wiącą uzupełnienie niektórych zagadnień poruszanych w tej książce.

More Related Content

PDF
Programowanie. Koncepcje, techniki i modele
PDF
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
PDF
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
PDF
C#. Wzorce projektowe
PDF
C++. Inżynieria programowania
PDF
Struktura organizacyjna i architektura systemów komputerowych
PDF
Visual Basic .NET. Wzorce projektowe
PDF
Head First Object-Oriented Analysis and Design. Edycja polska
Programowanie. Koncepcje, techniki i modele
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
C#. Wzorce projektowe
C++. Inżynieria programowania
Struktura organizacyjna i architektura systemów komputerowych
Visual Basic .NET. Wzorce projektowe
Head First Object-Oriented Analysis and Design. Edycja polska

Viewers also liked (12)

PDF
Profesjonalne zarządzanie barwą. Wydanie II
PDF
Red Hat Enterprise Linux i Fedora Core 2. Wprowadzenie
PDF
OpenBSD. Tworzenie firewalli za pomocą PF
PDF
MySQL. Podstawy
PDF
Po prostu Access 2002/XP PL
PDF
Uczta programistów
PDF
Po prostu Red Hat Linux 9
PDF
Oracle Database 10g. Nowe możliwości
PDF
Po prostu sieci komputerowe
PDF
Wykrywanie włamań i aktywna ochrona danych
PDF
Encyklopedia komputerów
Profesjonalne zarządzanie barwą. Wydanie II
Red Hat Enterprise Linux i Fedora Core 2. Wprowadzenie
OpenBSD. Tworzenie firewalli za pomocą PF
MySQL. Podstawy
Po prostu Access 2002/XP PL
Uczta programistów
Po prostu Red Hat Linux 9
Oracle Database 10g. Nowe możliwości
Po prostu sieci komputerowe
Wykrywanie włamań i aktywna ochrona danych
Encyklopedia komputerów
Ad

Similar to Programowanie zorientowane obiektowo (20)

PDF
Struktury danych i techniki obiektowe na przykładzie Javy 5.0
PDF
J2EE. Podstawy programowania aplikacji korporacyjnych
PDF
Programowanie obiektowe w Visual Basic .NET dla każdego
PDF
Programowanie. Od podstaw
PDF
Więcej niż architektura oprogramowania
PDF
Visual Basic .NET. Encyklopedia
PDF
Microsoft Visual Basic .NET 2003. Księga eksperta
PDF
Architektura systemów zarządzania przedsiębiorstwem. Wzorce projektowe
PDF
ABC Delphi 2006
PDF
Sprzedaj swój program. Droga do udanych projektów programistycznych
PDF
C++. Programowanie zorientowane obiektowo. Vademecum profesjonalisty
PDF
Wzorce projektowe. Analiza kodu sposobem na ich poznanie
PDF
C++ Builder. Symulacje komputerowe
PDF
Java. Aplikacje bazodanowe. Najlepsze rozwiązania
PDF
PHP5. Obiekty, wzorce, narzędzia
PDF
MS Project 2003. Zarządzanie projektami. Edycja limitowana
PDF
PDF
SolidWorks 2006 w praktyce
PDF
AutoCAD 2004
PDF
C#. Programowanie
Struktury danych i techniki obiektowe na przykładzie Javy 5.0
J2EE. Podstawy programowania aplikacji korporacyjnych
Programowanie obiektowe w Visual Basic .NET dla każdego
Programowanie. Od podstaw
Więcej niż architektura oprogramowania
Visual Basic .NET. Encyklopedia
Microsoft Visual Basic .NET 2003. Księga eksperta
Architektura systemów zarządzania przedsiębiorstwem. Wzorce projektowe
ABC Delphi 2006
Sprzedaj swój program. Droga do udanych projektów programistycznych
C++. Programowanie zorientowane obiektowo. Vademecum profesjonalisty
Wzorce projektowe. Analiza kodu sposobem na ich poznanie
C++ Builder. Symulacje komputerowe
Java. Aplikacje bazodanowe. Najlepsze rozwiązania
PHP5. Obiekty, wzorce, narzędzia
MS Project 2003. Zarządzanie projektami. Edycja limitowana
SolidWorks 2006 w praktyce
AutoCAD 2004
C#. Programowanie
Ad

More from Wydawnictwo Helion (20)

PDF
Tworzenie filmów w Windows XP. Projekty
PDF
Blog, więcej niż internetowy pamiętnik
PDF
Access w biurze i nie tylko
PDF
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
PDF
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
PDF
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
PDF
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
PDF
Makrofotografia. Magia szczegółu
PDF
Windows PowerShell. Podstawy
PDF
Java. Efektywne programowanie. Wydanie II
PDF
JavaScript. Pierwsze starcie
PDF
Ajax, JavaScript i PHP. Intensywny trening
PDF
PowerPoint 2007 PL. Seria praktyk
PDF
Excel 2007 PL. Seria praktyk
PDF
Access 2007 PL. Seria praktyk
PDF
Word 2007 PL. Seria praktyk
PDF
Serwisy społecznościowe. Budowa, administracja i moderacja
PDF
AutoCAD 2008 i 2008 PL
PDF
Bazy danych. Pierwsze starcie
PDF
Inventor. Pierwsze kroki
Tworzenie filmów w Windows XP. Projekty
Blog, więcej niż internetowy pamiętnik
Access w biurze i nie tylko
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Makrofotografia. Magia szczegółu
Windows PowerShell. Podstawy
Java. Efektywne programowanie. Wydanie II
JavaScript. Pierwsze starcie
Ajax, JavaScript i PHP. Intensywny trening
PowerPoint 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
Serwisy społecznościowe. Budowa, administracja i moderacja
AutoCAD 2008 i 2008 PL
Bazy danych. Pierwsze starcie
Inventor. Pierwsze kroki

Programowanie zorientowane obiektowo

  • 1. IDZ DO PRZYK£ADOWY ROZDZIA£ SPIS TREŒCI Programowanie zorientowane obiektowo KATALOG KSI¥¯EK Autor: Bertrand Meyer T³umaczenie: Micha³ Dadan (wstêp, rozdz. 1–6, 9, 10, 15, KATALOG ONLINE dod. A, C, D), Jaros³aw Dobrzañski (rozdz. 7, 17–25), Jan Ostrowski (rozdz. 26–32), Jaromir Senczyk (rozdz. 16, ZAMÓW DRUKOWANY KATALOG 33–36, dod. B), Krzysztof Szafranek (rozdz. 8, 11–14) ISBN: 83-7361-738-8 Tytu³ orygina³u: Object-Oriented Software TWÓJ KOSZYK Construction Second Edition Format: B5, stron: 1464 DODAJ DO KOSZYKA Poznaj regu³y projektowania i programowania obiektowego • Elementy techniki obiektowej CENNIK I INFORMACJE • Metodyka tworzenia oprogramowania • Implementacja mechanizmów obiektowych ZAMÓW INFORMACJE Programowanie zorientowane obiektowo to technika, która w ci¹gu ostatnich lat O NOWOŒCIACH zyska³a niezwyk³¹ popularnoœæ. Jêzyki programowania obiektowego œwiêc¹ triumfy, a metodologie projektowania oparte na analizie obiektowej staj¹ siê standardami ZAMÓW CENNIK przemys³owymi. Za³o¿enia analizy i programowania obiektowego s¹ pozornie proste, jednak¿e bez ich w³aœciwego zrozumienia nie mo¿na zaprojektowaæ prawid³owo aplikacji implementowanej w obiektowym jêzyku programowania. Technologia CZYTELNIA obiektowa zmieni³a ca³y przemys³ programistyczny, wiêc jej opanowanie jest niezbêdnym elementem wiedzy ka¿dego informatyka, który chce wykorzystywaæ FRAGMENTY KSI¥¯EK ONLINE w pracy nowoczesne metody i techniki. Ksi¹¿ka „Programowanie zorientowane obiektowo” to wyczerpuj¹ce omówienie wszystkich zagadnieñ zwi¹zanych z projektowaniem i programowaniem obiektowym. Opisuje g³ówne elementy techniki obiektowej oraz wiele spoœród ich potencjalnych zastosowañ. Dziêki ksi¹¿ce poznasz równie¿ metodykê projektowania oprogramowania, dowiesz siê, czym s¹ wzorce projektowe, i nauczysz siê, w jaki sposób zaimplementowaæ lub zasymulowaæ techniki obiektowe w ró¿nych jêzykach programowania. • Podstawowe elementy projektowania obiektowego • Wielokrotne wykorzystywanie kodu • Analiza obiektowa Wydawnictwo Helion • Abstrakcyjne typy danych ul. Chopina 6 • Klasy i obiekty 44-100 Gliwice • Zarz¹dzanie pamiêci¹ tel. (32)230-98-63 • Mechanizmy dziedziczenia e-mail: helion@helion.pl • Obs³uga wyj¹tków • Metodyka projektowania obiektowego • Programowanie wspó³bie¿ne • Obiektowe bazy danych • Zastosowanie technik obiektowych w ró¿nych jêzykach programowania Wykorzystaj techniki obiektowe i popraw jakoœæ tworzonego przez siebie oprogramowania
  • 2. SPIS TREŚCI O Autorze .............................................................................................................15 Wstęp ....................................................................................................................17 Część I Podstawy 27 1. Jakość oprogramowania .....................................................................................29 1.1. Czynniki zewnętrzne i wewnętrzne ........................................................................................................29 1.2. Przegląd czynników zewnętrznych ........................................................................................................30 1.3. Konserwacja oprogramowania ...............................................................................................................45 1.4. Kluczowe pojęcia wprowadzone w tym rozdziale .................................................................................47 1.5. Bibliografia ............................................................................................................................................48 2. Kryteria obiektowości .........................................................................................51 2.1. O kryteriach ...........................................................................................................................................52 2.2. Technika i język .....................................................................................................................................53 2.3. Implementacja i środowisko ...................................................................................................................63 2.4. Biblioteki ................................................................................................................................................65 2.5. Rzut oka na konkretny projekt ...............................................................................................................67 2.6. Bibliografia (w tym materiały na temat obiektów) .................................................................................67 Część II W stronę obiektowości 69 3. Modułowość .........................................................................................................71 3.1. Pięć kryteriów ........................................................................................................................................72 3.2. Pięć reguł ...............................................................................................................................................79 3.3. Pięć zasad ...............................................................................................................................................86
  • 3. 4 SPIS TREŚCI 3.4. Kluczowe pojęcia wprowadzone w tym rozdziale .................................................................................97 3.5. Bibliografia ............................................................................................................................................98 Ćwiczenia .......................................................................................................................................................99 4. Wielokrotne wykorzystywanie kodu ...............................................................101 4.1. Cele wielokrotnego wykorzystywania kodu .........................................................................................102 4.2. Jakie elementy systemów nadają się do wielokrotnego wykorzystywania? .........................................105 4.3. Powtórzenia w procesie tworzenia systemu .........................................................................................109 4.4. Problemy nietechniczne .......................................................................................................................110 4.5. Problem natury technicznej ..................................................................................................................118 4.6. Pięć wymagań dotyczących struktury modułów ..................................................................................120 4.7. Tradycyjne struktury modułowe ..........................................................................................................126 4.8. Przeciążanie i generyczność .................................................................................................................131 4.9. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................137 4.10. Bibliografia ..........................................................................................................................................138 5. W stronę techniki obiektowej ..........................................................................141 5.1. Składniki „obliczeń” ............................................................................................................................141 5.2. Dekompozycja funkcjonalna ................................................................................................................143 5.3. Dekompozycja obiektowa ....................................................................................................................155 5.4. Programowanie zorientowane obiektowo ............................................................................................157 5.5. Pytania .................................................................................................................................................158 5.6. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................160 5.7. Bibliografia ..........................................................................................................................................161 6. Abstrakcyjne typy danych ...............................................................................163 6.1. Kryteria ................................................................................................................................................164 6.2. Możliwe implementacje .......................................................................................................................164 6.3. W stronę abstrakcyjnego postrzegania obiektów .................................................................................168 6.4. Formalizacja specyfikacji .....................................................................................................................172 6.5. Od abstrakcyjnych typów danych do klas ............................................................................................186 6.6. Nie tylko oprogramowanie ...................................................................................................................191 6.7. Informacje uzupełniające .....................................................................................................................192 6.8. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................204 6.9. Bibliografia ..........................................................................................................................................205 Ćwiczenia .....................................................................................................................................................206 Część III Techniki obiektowe 209 7. Klasy — struktura statyczna ...........................................................................211 7.1. Obiekty nie są najważniejsze ...............................................................................................................211 7.2. Unikanie typowych nieporozumień ......................................................................................................212
  • 4. SPIS TREŚCI 5 7.3. Znaczenie klas ......................................................................................................................................216 7.4. Jednolity system typów ........................................................................................................................217 7.5. Prosta klasa ..........................................................................................................................................218 7.6. Podstawowe konwencje .......................................................................................................................223 7.7. Przebieg wykonania programu obiektowego ........................................................................................227 7.8. Eksportowanie wybiórcze a ukrywanie informacji ..............................................................................238 7.9. Składanie wszystkiego w całość ...........................................................................................................241 7.10. Analiza .................................................................................................................................................250 7.11. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................262 7.12. Bibliografia ..........................................................................................................................................263 Ćwiczenia .....................................................................................................................................................264 8. Struktury czasu wykonywania: obiekty .........................................................265 8.1. Obiekty .................................................................................................................................................266 8.2. Obiekty jako narzędzie do modelowania ..............................................................................................277 8.3. Manipulowanie obiektami i referencjami .............................................................................................280 8.4. Procedury tworzące ..............................................................................................................................285 8.5. Więcej o referencjach ...........................................................................................................................289 8.6. Operacje na referencjach ......................................................................................................................291 8.7. Obiekty złożone i typy rozszerzone .....................................................................................................303 8.8. Wiązanie: semantyka referencji i wartości ...........................................................................................310 8.9. Korzystanie z referencji: korzyści i zagrożenia ....................................................................................315 8.10. Analiza .................................................................................................................................................320 8.11. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................325 8.12. Bibliografia ..........................................................................................................................................326 Ćwiczenia .....................................................................................................................................................327 9. Zarządzanie pamięcią .......................................................................................329 9.1. Co dzieje się z obiektami? ....................................................................................................................329 9.2. Podejście klasyczne ..............................................................................................................................342 9.3. Zagadnienia związane z odzyskiwaniem pamięci ................................................................................345 9.4. Dealokacja kontrolowana przez programistę ........................................................................................346 9.5. Rozwiązanie na poziomie komponentów .............................................................................................349 9.6. Automatyczne zarządzanie pamięcią ...................................................................................................354 9.7. Zliczanie referencji ...............................................................................................................................355 9.8. Oczyszczanie pamięci ..........................................................................................................................357 9.9. Mechanizm oczyszczania pamięci w praktyce .....................................................................................364 9.10. Środowisko z zaimplementowanym odzyskiwaniem pamięci .............................................................367 9.11. Kluczowe pojęcia wprowadzone w tym rozdziale ...............................................................................370 9.12. Bibliografia ..........................................................................................................................................371 Ćwiczenia .....................................................................................................................................................372 10. Generyczność .....................................................................................................373 10.1. Pozioma i pionowa generalizacja typów ............................................................................................374 10.2. Potrzeba parametryzacji typów ..........................................................................................................374 10.3. Klasy generyczne ...............................................................................................................................377
  • 5. 6 SPIS TREŚCI 10.4. Tablice ................................................................................................................................................382 10.5. Koszt generyczności ...........................................................................................................................386 10.6. Analiza — to jeszcze nie koniec ........................................................................................................387 10.7. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................387 10.8. Bibliografia ........................................................................................................................................388 Ćwiczenia .....................................................................................................................................................388 11. Projektowanie kontraktowe: tworzenie niezawodnego oprogramowania ....391 11.1. Proste mechanizmy niezawodności ....................................................................................................392 11.2. O poprawności oprogramowania ........................................................................................................393 11.3. Specyfikacja .......................................................................................................................................394 11.4. Wprowadzanie asercji do kodu ..........................................................................................................397 11.5. Warunki początkowe i warunki końcowe ..........................................................................................398 11.6. Używanie kontraktów dla poprawy niezawodności ...........................................................................402 11.7. Praca z asercjami ................................................................................................................................408 11.8. Niezmienniki klas ...............................................................................................................................422 11.9. Kiedy klasa jest poprawna? ................................................................................................................428 11.10. Związek z ATD ..................................................................................................................................432 11.11. Instrukcja asercji ................................................................................................................................436 11.12. Niezmienniki i zmienne pętli .............................................................................................................439 11.13. Korzystanie z asercji ..........................................................................................................................447 11.14. Analiza ...............................................................................................................................................456 11.15. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................465 11.16. Bibliografia ........................................................................................................................................466 Ćwiczenia .....................................................................................................................................................467 Postscriptum: katastrofa Ariane 5 .................................................................................................................469 12. Gdy kontrakt nie zostaje dotrzymany: obsługa wyjątków ...........................471 12.1. Podstawy obsługi wyjątków ...............................................................................................................471 12.2. Obsługa wyjątków ..............................................................................................................................474 12.3. Mechanizm wyjątków ........................................................................................................................479 12.4. Przykłady obsługi wyjątków ..............................................................................................................482 12.5. Zadanie klauzuli ratunkowej ..............................................................................................................488 12.6. Zaawansowana obsługa wyjątków .....................................................................................................491 12.7. Analiza ...............................................................................................................................................496 12.8. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................498 12.9. Bibliografia ........................................................................................................................................498 Ćwiczenia .....................................................................................................................................................499 13. Mechanizmy pomocnicze ..................................................................................501 13.1. Komunikacja z oprogramowaniem nieobiektowym ...........................................................................501 13.2. Przekazywanie argumentów ...............................................................................................................507 13.3. Instrukcje ............................................................................................................................................509 13.4. Wyrażenia ..........................................................................................................................................515
  • 6. SPIS TREŚCI 7 13.5. Łańcuchy znaków ...............................................................................................................................520 13.6. Wejście i wyjście ................................................................................................................................521 13.7. Konwencje leksykalne ........................................................................................................................521 13.8. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................521 Ćwiczenia .....................................................................................................................................................522 14. Wprowadzenie do dziedziczenia ......................................................................523 14.1. Wielokąty i prostokąty .......................................................................................................................524 14.2. Polimorfizm .......................................................................................................................................531 14.3. Kontrola typów a dziedziczenie .........................................................................................................536 14.4. Dynamiczne wiązanie ........................................................................................................................545 14.5. Cechy i klasy abstrakcyjne .................................................................................................................547 14.6. Techniki ponownej deklaracji ............................................................................................................556 14.7. Znaczenie dziedziczenia .....................................................................................................................560 14.8. Rola klas abstrakcyjnych ....................................................................................................................566 14.9. Analiza ...............................................................................................................................................573 14.10. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................583 14.11. Bibliografia ........................................................................................................................................584 Ćwiczenia .....................................................................................................................................................585 15. Dziedziczenie wielokrotne ................................................................................587 15.1. Przykłady dziedziczenia wielokrotnego .............................................................................................587 15.2. Zmiana nazw cech ..............................................................................................................................604 15.3. Spłaszczanie struktury ........................................................................................................................611 15.4. Powtórne dziedziczenie ......................................................................................................................614 15.5. Analiza ...............................................................................................................................................635 15.6. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................638 15.7. Bibliografia ........................................................................................................................................638 Ćwiczenia .....................................................................................................................................................639 16. Techniki dziedziczenia ......................................................................................643 16.1. Dziedziczenie i asercje .......................................................................................................................644 16.2. Globalna struktura dziedziczenia .......................................................................................................656 16.3. Cechy zamrożone ...............................................................................................................................659 16.4. Generyczność ograniczona .................................................................................................................661 16.5. Próba przypisania ...............................................................................................................................667 16.6. Zgodność typów i ponowne deklaracje ..............................................................................................672 16.7. Deklaracje kotwiczone .......................................................................................................................675 16.8. Dziedziczenie i ukrywanie informacji ................................................................................................683 16.9. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................688 16.10. Bibliografia ........................................................................................................................................689 Ćwiczenia .....................................................................................................................................................689
  • 7. 8 SPIS TREŚCI 17. Kontrola typów ..................................................................................................691 17.1. Problem z kontrolą typów ..................................................................................................................691 17.2. Statyczna kontrola typów — kiedy i jak? ...........................................................................................696 17.3. Kowariancja i ukrywanie u potomków ...............................................................................................703 17.4. Pierwsze podejście do kwestii poprawności systemu .........................................................................711 17.5. Bazowanie na typach zakotwiczonych ...............................................................................................713 17.6. Analiza globalna .................................................................................................................................717 17.7. Uwaga na polimorficzne wywołania ZDLT! ......................................................................................719 17.8. Ocena .................................................................................................................................................722 17.9. Idealny typ .........................................................................................................................................723 17.10. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................725 17.11. Bibliografia ........................................................................................................................................725 18. Obiekty i stałe globalne ....................................................................................727 18.1. Stałe podstawowych typów ................................................................................................................728 18.2. Korzystanie ze stałych ........................................................................................................................729 18.3. Stałe o typach będących klasami ........................................................................................................730 18.4. Zastosowanie podprogramów jednorazowych ...................................................................................732 18.5. Stałe typu łańcuchowego ....................................................................................................................738 18.6. Wartości unikatowe ............................................................................................................................738 18.7. Analiza ...............................................................................................................................................740 18.8. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................744 18.9. Bibliografia ........................................................................................................................................745 Ćwiczenia .....................................................................................................................................................745 Część IV Metodyka obiektowa — prawidłowe stosowanie metody 747 19. O metodyce ........................................................................................................749 19.1. Metodyka programowania — jak i dlaczego? ....................................................................................749 19.2. Wymyślanie dobrych reguł — porady dla radzących .........................................................................750 19.3. O użyciu metafor ................................................................................................................................758 19.4. Znaczenie pokory ...............................................................................................................................760 19.5. Bibliografia ........................................................................................................................................761 Ćwiczenia .....................................................................................................................................................761 20. Wzorzec projektowy — wielopanelowe systemy interaktywne ....................763 20.1. Systemy wielopanelowe .....................................................................................................................763 20.2. Proste rozwiązanie .............................................................................................................................765
  • 8. SPIS TREŚCI 9 20.3. Rozwiązanie hierarchiczne z funkcjami .............................................................................................766 20.4. Krytyka rozwiązania ..........................................................................................................................770 20.5. Architektura obiektowa ......................................................................................................................772 20.6. Analiza ...............................................................................................................................................781 20.7. Bibliografia ........................................................................................................................................782 21. Dziedziczenie — studium przypadku: operacja „cofnij” w systemie interaktywnym ................................................783 21.1. Perseverare diabolicum ......................................................................................................................783 21.2. Wyszukiwanie abstrakcji ....................................................................................................................787 21.3. Wielopoziomowy mechanizm cofnij-powtórz ...................................................................................793 21.4. Aspekty implementacyjne ..................................................................................................................796 21.5. Interfejs użytkownika dla operacji cofania i powtarzania ..................................................................800 21.6. Analiza ...............................................................................................................................................802 21.7. Bibliografia ........................................................................................................................................804 Ćwiczenia .....................................................................................................................................................805 22. Jak odnaleźć klasy? ..........................................................................................809 22.1. Analiza dokumentu z wymogami .......................................................................................................810 22.2. Oznaki zagrożenia ..............................................................................................................................816 22.3. Ogólna heurystyka odnajdywania klas ...............................................................................................822 22.4. Inne źródła klas ..................................................................................................................................826 22.5. Wielokrotne zastosowanie ..................................................................................................................832 22.6. Metoda uzyskiwania klas ...................................................................................................................833 22.7. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................835 22.8. Bibliografia ........................................................................................................................................835 Ćwiczenia .....................................................................................................................................................836 23. Zasady projektowania klas ..............................................................................839 23.1. Skutki uboczne w funkcjach ...............................................................................................................840 23.2. Ile argumentów powinna mieć cecha? ................................................................................................856 23.3. Rozmiar klasy — metoda listy zakupów ............................................................................................863 23.4. Aktywne struktury danych .................................................................................................................867 23.5. Cechy eksportowane selektywnie .......................................................................................................892 23.6. Postępowanie w przypadkach nietypowych .......................................................................................893 23.7. Ewolucja klasy — klauzula OBSOLETE ...........................................................................................898 23.8. Dokumentowanie klasy i systemu ......................................................................................................899 23.9. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................902 23.10. Bibliografia ........................................................................................................................................902 Ćwiczenia .....................................................................................................................................................903
  • 9. 10 SPIS TREŚCI 24. Prawidłowe stosowanie dziedziczenia .............................................................907 24.1. Jak używać dziedziczenia? .................................................................................................................907 24.2. Kupić czy odziedziczyć? ....................................................................................................................910 24.3. Przykład zastosowania — technika uchwytów ...................................................................................916 24.4. Taksomania ........................................................................................................................................919 24.5. Zastosowanie dziedziczenia — taksonomia taksonomii .....................................................................921 24.6. Jeden czy więcej mechanizmów? .......................................................................................................933 24.7. Dziedziczenie podtypów i ukrywanie u potomków ............................................................................935 24.8. Dziedziczenie implementacji .............................................................................................................944 24.9. Dziedziczenie udogodnień .................................................................................................................947 24.10. Wielość kryteriów i dziedziczenie perspektywy ................................................................................952 24.11. Jak opracowywać struktury dziedziczenia? ........................................................................................958 24.12. Podsumowanie — prawidłowe stosowanie dziedziczenia ..................................................................962 24.13. Kluczowe pojęcia wprowadzone w tym rozdziale .............................................................................963 24.14. Bibliografia ........................................................................................................................................964 24.15. Dodatek — historia taksonomii ..........................................................................................................964 Ćwiczenia .....................................................................................................................................................970 25. Przydatne techniki ............................................................................................973 25.1. Filozofia projektowania ......................................................................................................................973 25.2. Klasy ..................................................................................................................................................974 25.3. Techniki dziedziczenia .......................................................................................................................976 26. Poczucie stylu ....................................................................................................979 26.1. Kwestie kosmetyczne mają znaczenie! ..............................................................................................979 26.2. Dobór odpowiednich nazw .................................................................................................................983 26.3. Stałe ...................................................................................................................................................989 26.4. Komentarze nagłówkowe i klauzule indeksujące ...............................................................................991 26.5. Układ i prezentacja tekstu ..................................................................................................................997 26.6. Czcionki ...........................................................................................................................................1006 26.7. Bibliografia ......................................................................................................................................1008 Ćwiczenia ...................................................................................................................................................1008 27. Analiza obiektowa ...........................................................................................1011 27.1. Cele analizy ......................................................................................................................................1012 27.2. Zmienna natura analizy ....................................................................................................................1014 27.3. Wkład technologii obiektowej ..........................................................................................................1015 27.4. Programowanie stacji telewizyjnej ...................................................................................................1016 27.5. Użyteczność analizy — wielokrotność postaci ................................................................................1023 27.6. Metody analizy .................................................................................................................................1027 27.7. Notacja obiektów biznesowych — NOB ..........................................................................................1030 27.8. Bibliografia ......................................................................................................................................1033
  • 10. SPIS TREŚCI 11 28. Proces tworzenia oprogramowania ...............................................................1035 28.1. Klastry ..............................................................................................................................................1035 28.2. Inżynieria symultaniczna ..................................................................................................................1036 28.3. Kroki i zadania .................................................................................................................................1038 28.4. Klastrowy model cyklu życia oprogramowania ...............................................................................1039 28.5. Uogólnienie ......................................................................................................................................1040 28.6. Jednolitość i odwracalność ...............................................................................................................1043 28.7. Wśród nas wszystko jest twarzą .......................................................................................................1046 28.8. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1047 28.9. Bibliografia ......................................................................................................................................1047 29. Nauczanie .........................................................................................................1049 29.1. Szkolenia przemysłowe ....................................................................................................................1049 29.2. Kursy wprowadzające ......................................................................................................................1052 29.3. Inne kursy .........................................................................................................................................1056 29.4. W kierunku nowych sposobów nauczania tworzenia oprogramowania ...........................................1058 29.5. Plan wydziału związany z obiektowością ........................................................................................1062 29.6. Kluczowe zagadnienia wprowadzone w rozdziale ...........................................................................1064 29.7. Bibliografia ......................................................................................................................................1064 Część V Zagadnienia zaawansowane 1067 30. Współbieżność, rozproszenie, klient-serwer i internet ................................1069 30.1. Krótkie podsumowanie ....................................................................................................................1070 30.2. Narodziny współbieżności ...............................................................................................................1071 30.3. Od procesów do obiektów ................................................................................................................1075 30.4. Wykonywanie współbieżne ..............................................................................................................1083 30.5. Kwestie synchronizacji ....................................................................................................................1097 30.6. Dostęp do obiektów niezależnych ....................................................................................................1103 30.7. Warunki oczekiwania .......................................................................................................................1112 30.8. Żądania obsługi w trybie specjalnym ...............................................................................................1121 30.9. Przykłady .........................................................................................................................................1126 30.10. W kierunku reguły dowodzenia poprawności ..................................................................................1144 30.11. Podsumowanie przedstawionego mechanizmu współbieżności .......................................................1146 30.12. Analiza .............................................................................................................................................1149 30.13. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1154 30.14. Bibliografia ......................................................................................................................................1155 Ćwiczenia ...................................................................................................................................................1157 31. Trwałość obiektów i bazy danych ..................................................................1161 31.1. Trwałość jako element języka ..........................................................................................................1161 31.2. Granice implementacji trwałości ......................................................................................................1163
  • 11. 12 SPIS TREŚCI 31.3. Ewolucja schematu ...........................................................................................................................1165 31.4. Od trwałości do baz danych .............................................................................................................1172 31.5. Współpraca obiektowo-relacyjna .....................................................................................................1173 31.6. Podstawy obiektowych baz danych ..................................................................................................1176 31.7. Systemy obiektowych baz danych — przykłady ..............................................................................1182 31.8. Analiza — pozaobiektowe bazy danych ..........................................................................................1185 31.9. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1187 31.10. Bibliografia ......................................................................................................................................1188 Ćwiczenia ...................................................................................................................................................1189 32. Wybrane techniki obiektowe wykorzystywane w interaktywnych aplikacjach z graficznym interfejsem użytkownika ....................................1191 32.1. Potrzebne narzędzia .........................................................................................................................1192 32.2. Przenośność i adaptacja do platformy ..............................................................................................1195 32.3. Abstrakcje graficzne .........................................................................................................................1197 32.4. Mechanizmy interakcji .....................................................................................................................1200 32.5. Obsługa zdarzeń ...............................................................................................................................1202 32.6. Model matematyczny .......................................................................................................................1206 32.7. Bibliografia ......................................................................................................................................1206 Część VI Zastosowanie metody w różnych językach i środowiskach programowania 1207 33. Programowanie obiektowe i Ada ...................................................................1209 33.1. Trochę historii ..................................................................................................................................1210 33.2. Pakiety ..............................................................................................................................................1211 33.3. Implementacja stosu .........................................................................................................................1212 33.4. Ukrywanie reprezentacji ..................................................................................................................1216 33.5. Wyjątki .............................................................................................................................................1218 33.6. Zadania .............................................................................................................................................1222 33.7. Ada 95 ..............................................................................................................................................1223 33.8. Kluczowe pojęcia wprowadzone w tym rozdziale ...........................................................................1228 33.9. Bibliografia ......................................................................................................................................1228 Ćwiczenia ...................................................................................................................................................1229 34. Emulacja technologii obiektowej w środowiskach nieobiektowych ...........1231 34.1. Poziomy obsługi koncepcji obiektowych .........................................................................................1232 34.2. Programowanie obiektowe w Pascalu? ............................................................................................1233 34.3. Fortran ..............................................................................................................................................1234 34.4. Programowanie obiektowe i język C ................................................................................................1239 34.5. Bibliografia ......................................................................................................................................1245 Ćwiczenia ...................................................................................................................................................1246
  • 12. SPIS TREŚCI 13 35. Od Simuli do Javy: główne języki i środowiska obiektowe ........................1247 35.1. Simula ..............................................................................................................................................1248 35.2. Smalltalk ..........................................................................................................................................1261 35.3. Rozszerzenia języka Lisp .................................................................................................................1265 35.4. Rozszerzenia języka C .....................................................................................................................1267 35.5. Java ..................................................................................................................................................1271 35.6. Inne języki obiektowe ......................................................................................................................1272 35.7. Bibliografia ......................................................................................................................................1273 Ćwiczenia ...................................................................................................................................................1275 Część VII W praktyce 1277 36. Środowisko obiektowe ....................................................................................1279 36.1. Komponenty .....................................................................................................................................1280 36.2. Język ................................................................................................................................................1280 36.3. Technologia kompilacji ....................................................................................................................1281 36.4. Narzędzia .........................................................................................................................................1285 36.5. Biblioteki ..........................................................................................................................................1289 36.6. Mechanizmy interfejsu .....................................................................................................................1290 36.7. Bibliografia ......................................................................................................................................1297 Epilog ujawnia język ......................................................................................1299 Dodatki 1301 A Wybrane klasy bibliotek Base .......................................................................1303 B Generyczność a dziedziczenie ........................................................................1355 B.1. Generyczność ....................................................................................................................................1356 B.2. Dziedziczenie ....................................................................................................................................1361 B.3. Emulacja dziedziczenia za pomocą generyczności ............................................................................1363 B.4. Emulacja generyczności za pomocą dziedziczenia ............................................................................1364 B.5. Łączenie generyczności z dziedziczeniem .........................................................................................1372 B.6. Kluczowe pojęcia wprowadzone w tym dodatku ..............................................................................1376 B.7. Bibliografia ........................................................................................................................................1376 Ćwiczenia ...................................................................................................................................................1377
  • 13. 14 SPIS TREŚCI C Zasady, reguły, nakazy i definicje .................................................................1379 D Określenia stosowane w technice obiektowej ...............................................1385 E Bibliografia ......................................................................................................1397 E.1. Prace innych autorów ........................................................................................................................1397 E.2. Prace autora książki ...........................................................................................................................1416 Skorowidz ........................................................................................................ 1421
  • 14. 1 JAKOŚĆ OPROGRAMOWANIA Słowo inżynieria nieodzownie kojarzy się z jakością. Inżynieria oprogramowania to tworzenie wysokich jakościowo programów. Ta książka opisuje techniki, które poten- cjalnie mogą przyczynić się do znacznego podniesienia jakości aplikacji komputerowych. Zanim zacznę je omawiać, muszę napisać, w jakim celu zostały wymyślone. Jakość oprogramowania najlepiej pojmować jako sumę wielu czynników. W tym rozdziale opi- szę kilka z nich, zidentyfikuję obszary, jakie najpilniej wymagają usprawnień, i wskażę kierunek, w którym wspólnie będziemy szukać rozwiązań w trakcie dalszej lektury. 1.1. CZYNNIKI ZEWNĘTRZNE I WEWNĘTRZNE Wszyscy chcemy, aby nasze oprogramowanie było szybkie, niezawodne, łatwe w obsłu- dze, czytelne, modułowe, sensownie skonstruowane itd. Tyle tylko, że te przymiotniki opisują dwa różne rodzaje zalet. Po jednej stronie mamy zalety, takie jak szybkość czy łatwość obsługi, których obecność lub brak może z łatwością stwierdzić każdy użytkownik. Tego rodzaju właści- wości możemy nazwać zewnętrznymi czynnikami decydującymi o jakości. Pod pojęciem „użytkownicy” należy rozumieć nie tylko osoby, które będą fizycznie korzystały z gotowych programów (na przykład pracownik linii lotniczych obsługujący system rezerwacji lotów), ale także decydentów, którzy podjęli decyzję o ich zakupie bądź zlecili ich opracowanie (analogicznie dyrektor linii lotniczych, którego uprawnienia na to pozwalają). Tak więc taka właściwość jak łatwość, z jaką oprogramowanie daje się dostosowywać do zmian w specyfikacji (w dalszej części tego rozdziału nazywana rozszerzalnością), jest zaliczana do kategorii czynników zewnętrznych, mimo iż „użytkownicy końcowi”, tacy jak pracownik dokonujący rezerwacji, mogą nie być nią bezpośrednio zainteresowani. Inne możliwe zalety programu komputerowego, takie jak czytelność czy modu- łowość, zaliczamy do czynników wewnętrznych, ponieważ są one dostrzegalne jedynie dla informatyków mających dostęp do kodu źródłowego programu.
  • 15. 30 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA W ostatecznym rozrachunku liczą się tylko czynniki zewnętrzne. Gdy korzystam z przeglądarki internetowej lub mieszkam w pobliżu elektrowni atomowej sterowanej przez program komputerowy, tak naprawdę nie obchodzi mnie to, czy jego kod źró- dłowy jest modularny i czytelny. Ważne, żeby obrazki w przeglądarce nie wczyty- wały się godzinami, a błędne dane wejściowe nie mogły doprowadzić do wysadzenia elektrowni. Jednak kluczem do osiągnięcia satysfakcjonujących czynników zewnętrz- nych są czynniki wewnętrzne. Aby użytkownicy mogli cieszyć się widocznymi ozna- kami jakości aplikacji, ich projektanci i implementatorzy muszą stosować techniki gwa- rantujące wysoką jakość wewnętrzną. W kolejnych rozdziałach przedstawiam zbiór współczesnych technik pozwalają- cych na uzyskanie właśnie wewnętrznej jakości aplikacji. Czytając ten rozdział, nie powinieneś jednak tracić z oczu szerszego obrazu. Techniki wewnętrzne nie są naszym celem same w sobie. Są to jedynie środki, za pomocą których możemy uzyskać wysoką jakość zewnętrzną tworzonych aplikacji. Dlatego też musimy zacząć od omówienia czynników zewnętrznych. Przeznaczyłem na to pozostałą część tego rozdziału. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH Poniżej opisuję najważniejsze czynniki zewnętrzne decydujące o jakości, które powinny być obecne w każdym programie komputerowym. Doprowadzenie do takiego stanu jest głównym celem programowania zorientowanego obiektowo. Poprawność Definicja poprawności Poprawność to zdolność programów komputerowych do wykonywania dokładnie tych zadań, które im powierzono i które zdefiniowano w ich specyfikacjach. Poprawność jest zdecydowanie najważniejszym czynnikiem. Jeżeli system nie robi tego, czego się po nim oczekuje, wszystko inne — czy jest szybki, czy ma przyjemny interfejs użytkownika itd. — nie ma większego znaczenia. Łatwo o niej pisać, ale znacznie trudniej ją osiągnąć. Już pierwszy krok na dro- dze do poprawności jest trudny. Trzeba bowiem precyzyjnie określić wymagania sta- wiane systemowi. Techniki stosowane w celu zapewnienia poprawności zazwyczaj odnoszą się je- dynie do pewnego obszaru systemu. Poważne współczesne programy komputerowe, nawet te mniejsze, odnoszą się do zagadnień z tak wielu dziedzin, że niemożliwe byłoby zagwarantowanie ich poprawności po przeanalizowaniu komponentów i właściwości tylko na jednej płaszczyźnie. Dlatego konieczne jest podejście warstwowe, w którym wyższe warstwy polegają na niższych (patrz rysunek 1.1).
  • 16. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 31 RYSUNEK 1.1. Warstwy w procesie tworzenia oprogramowania W tak zwanym warunkowym podejściu do poprawności interesuje nas jedynie zagwarantowanie poprawności danej warstwy przy założeniu, że wszystkie warstwy leżące niżej na pewno są poprawne. Jest to jedyne realistyczne podejście, ponieważ pozwala rozbić problem na kilka części i koncentrować się w danym momencie tylko na jednej z nich. Nie możesz twierdzić, że program napisany w języku wysokiego po- ziomu X jest poprawny, jeżeli nie masz pewności, że kompilator, którym dysponu- jesz, prawidłowo implementuje język X. Nie oznacza to wcale, że musisz ślepo ufać kompilatorowi. Po prostu problem zostaje tu rozbity na dwie części. Poprawność kom- pilatora i poprawność programu z punktu widzenia semantyki języka. W technice opisywanej w tej książce poprawność zależy od jeszcze większej liczby warstw (patrz rysunek 1.2), ponieważ tworząc programy komputerowe, będziemy polegali na bibliotekach komponentów przeznaczonych do wielokrotnego użycia, które mogą być wykorzystywane do budowy wielu różnych aplikacji. RYSUNEK 1.2. Warstwy w procesie tworzenia aplikacji, w którym posługujemy się komponentami wielokrotnego użytku Również w tym przypadku stosuje się podejście warunkowe. Powinniśmy za- gwarantować poprawność bibliotek, a następnie — w oparciu o nią — poprawność aplikacji. Wielu praktykom stykającym się z zagadnieniem poprawności oprogramowania przychodzi na myśl testowanie i lokalizowanie błędów. Jednak do problemu można podejść bardziej ambitnie. W dalszych rozdziałach przyjrzymy się wielu technikom, w szczególności kontroli typów i asercjom, które wymyślono po to, aby ułatwić two- rzenie oprogramowania, które jest poprawne od samego początku. Jest to znacznie lepsze podejście, niż zmuszanie programu do poprawności dopiero na pewnym etapie. Jednak nie zwalnia nas ono z testowania i lokalizowania błędów, czyli czynności, które w tym przypadku pozwalają na upewnienie się, że program faktycznie jest poprawny.
  • 17. 32 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA Można iść jeszcze dalej i przyjąć całkiem sformalizowane podejście do tworze- nia oprogramowania. Postanowiłem stosować w książce dość potoczny język, dlatego wspomnę jedynie, że wiele technik, które opisuję w dalszych rozdziałach, wywodzi się bezpośrednio ze ścisłych, matematycznych technik formułowania specyfikacji pro- gramów i ich weryfikacji, które pozwalają bardzo mocno zbliżyć się do ideału w pełni poprawnego oprogramowania. Odporność Definicja odporności Odporność to zdolność systemów komputerowych do prawidłowego reagowania na niestandardowe sytuacje. Odporność stanowi uzupełnienie poprawności (patrz rysunek 1.3). Poprawność określa zachowanie systemów w sytuacjach przewidzianych w specyfikacji. Z kolei odporność charakteryzuje działania podejmowane po napotkaniu sytuacji wykraczają- cych poza specyfikację. RYSUNEK 1.3. Odporność kontra poprawność Już sama definicja pokazuje, że odporność nie jest tak ścisłym pojęciem jak po- prawność. Ponieważ mówimy tu o przypadkach nieprzewidzianych w specyfikacji, nie możemy powiedzieć, że system powinien wówczas po prostu „wykonywać swoje za- dania”. Gdyby te zadania były znane, każdy taki niestandardowy przypadek stałby się częścią specyfikacji, co przeniosłoby nas z powrotem w obszar poprawności. Definicja „niestandardowej sytuacji” przyda się jeszcze, gdy będziemy omawiali obsługę Informacje wyjątków. Wynika z niej, że to, co nazywamy sytuacją standardową, a co niestandardową, na temat zależy od przyjętej specyfikacji. Sytuacja niestandardowa to po prostu taka, która nie obsługi wyjątków została w niej przewidziana. Jeżeli poszerzymy specyfikację, wówczas sytuacje, które znajdziesz były niestandardowe, staną się standardowe, nawet jeśli dotyczą takich okoliczności jak w rozdziale 12. wprowadzenie przez użytkownika nieprawidłowych danych. Tak więc „standardowe” nie oznacza w tym przypadku „pożądane”, a jedynie „przewidziane na etapie projektowania programu”. Mimo iż nazywanie wprowadzenia błędnych danych „standardową sytuacją” może z początku wydawać się paradoksalne, każde inne rozwiązanie wymagałoby ustalenia obiektywnych kryteriów, a tym samym byłoby bezużyteczne. Zawsze mogą zdarzyć się sytuacje, których specyfikacja bezpośrednio nie prze- widuje. Znaczenie odporności polega na gwarancji, że pojawienie się takich okolicz- ności nie spowoduje żadnej katastrofy. Program powinien po prostu wyświetlić sto- sowne komunikaty o błędzie i zakończyć w normalny sposób swoje wykonywanie lub wejść w tak zwany „tryb łagodnego zejścia”.
  • 18. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 33 Rozszerzalność Definicja rozszerzalności Rozszerzalność to możliwość łatwego dostosowywania programu komputerowego do zmian w specyfikacji. Oprogramowanie, w przeciwieństwie do sprzętu, z założenia powinno dawać się łatwo modyfikować. Tak właśnie jest, jeśli tylko mamy dostęp do kodu źródłowego. Jego zmia- na jest w takiej sytuacji banalnie prosta. Wystarczy posłużyć się dowolnym edytorem tekstów. Z zagadnieniem rozszerzalności wiąże się problem skali. W małych aplikacjach wprowadzenie zmian zazwyczaj nie stanowi problemu. Jeśli jednak mamy do czynie- nia z coraz bardziej rozbudowanymi programami, to coraz trudniej je modyfikować. Tego rodzaju aplikacje przypominają czasami ogromne domki z kart, a wyciągnięcie tylko jednego elementu może spowodować zawalenie się całej konstrukcji. Rozszerzalność jest potrzebna ze względu na to, że u podstaw każdego programu komputerowego leży czynnik ludzki, co czyni go podatnym na błędy, które trzeba później poprawiać. Weźmy pod uwagę na przykład programy biznesowe (takie jak informacyjne systemy zarządzania). Wystarczy, że zmienią się jakieś przepisy prawa lub firma zostanie przejęta przez konkurencję, a już założenia, na których oparty był system, przestaną być aktualne. Jest to dość sztampowy przykład, ale niewiele osób zdaje sobie sprawę z tego, że z podobną sytuacją mamy do czynienia nawet w pro- gramach naukowych, w przypadku których możemy zakładać, że za miesiąc lub dwa będą nadal obowiązywały te same prawa fizyki co dzisiaj. Jednak może ulec zmianie sposób, w jaki je pojmujemy, lub procedura modelowania pewnych zjawisk. W tradycyjnym podejściu do inżynierii oprogramowania nie przykładano wy- starczająco dużej wagi do zmian. Zamiast tego opierano się na idealistycznym po- strzeganiu cyklu życia oprogramowania, w którym wymagania były zamrażane już na etapie analizy potrzeb. Na dalszych etapach skupiano się już wyłącznie na projekto- waniu i tworzeniu rozwiązania. Jest to zrozumiałe. Pierwszym krokiem na drodze rozwoju inżynierii programowania było opracowanie przejrzystych technik formuło- wania i rozwiązywania stałych, niezmiennych problemów. Dopiero później zaczęto się martwić, co należy robić w sytuacji, gdy problem ulega zmianie w czasie, kiedy wciąż szukamy rozwiązania. Obecnie podstawowe techniki inżynierii oprogramowa- nia są już opracowane i dlatego pora zająć się opisywanym problemem. Zmiany są nieodłącznym elementem procesu tworzenia oprogramowania. Możemy mieć do czy- nienia ze zmianami wymagań, sposobu ich pojmowania, algorytmów, sposobu pre- zentacji danych lub technik implementacyjnych. Umożliwienie łatwego ich wprowa- dzania jest głównym zadaniem techniki obiektowej i tematem przewodnim tej książki. Choć wiele technik zwiększających rozszerzalność można prezentować na pro- stych przykładach, ich znaczenie staje się jasne dopiero w przypadku większych pro- jektów. Przy zwiększaniu rozszerzalności kluczową rolę odgrywają dwie zasady: • Prostota projektu — proste architektury zawsze łatwiej zaadaptować do zmian niż złożone. • Decentralizacja — im większa autonomia poszczególnych modułów, tym więk- sze prawdopodobieństwo, że prosta zmiana specyfikacji będzie wymagała zmo- dyfikowania tylko jednego lub kilku modułów i nie wywoła reakcji łańcuchowej w całym systemie.
  • 19. 34 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA Technika programowania zorientowanego obiektowo jest przede wszystkim tech- niką tworzenia takich architektur systemów, które pomagają projektantom w tworzeniu zdecentralizowanych programów o prostej strukturze (nawet jeśli są to duże projekty). Prostota i decentralizacja to kluczowe zagadnienia, które będą się przewijały w naszej dyskusji do czasu, aż w kolejnych rozdziałach sformułujemy zasady rządzące techniką obiektową. Przystosowanie do wielokrotnego użycia Definicja przystosowania do wielokrotnego użycia Przystosowanie do wielokrotnego użycia to zdolność elementów składowych opro- gramowania do pełnienia roli elementów konstrukcyjnych wielu różnych aplikacji. Potrzeba przystosowania do wielokrotnego użycia wynika z obserwacji, że w wielu programach komputerowych przewijają się te same wzorce. Dlatego powinna istnieć możliwość wykorzystania tych podobieństw, pozwalająca na uniknięcie ponownego wynajdywania koła. Dostrzegając taki wzorzec, możemy wyodrębnić element pro- gramu, który nadaje się do wykorzystania w wielu różnych projektach. Przystosowanie do wielokrotnego użycia ma wpływ na wszystkie inne aspekty jakości oprogramowania, ponieważ dzięki niemu nie trzeba pisać tak dużo kodu jak dawniej i można skupić się (przy takim samym całkowitym koszcie projektu) na po- prawianiu innych czynników, takich jak poprawność czy odporność. Jest to przykład kolejnego zagadnienia, na które nie położono wystarczająco du- żego nacisku w tradycyjnym pojmowaniu cyklu życia aplikacji. Powody historyczne są tu takie same jak w poprzednim przypadku. Przyjęto, że najpierw trzeba znaleźć rozwiązanie jednego problemu, a dopiero potem można stosować je w odniesieniu do innych problemów. Jednak rozrastanie się programów komputerowych i próba uczy- nienia z informatyki prawdziwego przemysłu doprowadziły do tego, że przystosowanie kodu do wielokrotnego użycia stało się palącą potrzebą. Przystosowanie do wielokrotnego użycia będzie odgrywało kluczową rolę przy O przystoso- omawianiu zagadnień przedstawionych w następnych rozdziałach. Jeden z nich jest prak- waniu do wielokrotnego tycznie w całości poświęcony dogłębnej analizie tego czynnika decydującego o jakości, użycia piszę omówieniu wymiernych korzyści, jakie on daje, i problemów, jakie się z nim wiążą. w rozdziale 4. Zgodność Definicja zgodności Zgodność to łatwość, z jaką można ze sobą łączyć poszczególne składniki oprogra- mowania. Zgodność jest bardzo istotna, ponieważ składniki programistyczne nie powstają w próżni. Muszą ze sobą współpracować. Jednak bardzo często mają z tym problemy, ponieważ ich twórcy poczynili sprzeczne założenia dotyczące świata zewnętrznego. Jednym z przy-
  • 20. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 35 kładów tego typu sytuacji jest ogromna różnorodność niezgodnych ze sobą formatów plików, obsługiwanych przez różne systemy operacyjne. Każdy program komputerowy może bezpośrednio przyjmować wyniki działania innego programu tylko wtedy, jeżeli formaty plików stosowane przez obie aplikacje są ze sobą zgodne. Brak zgodności może odprowadzić do prawdziwej katastrofy. Oto skrajny przykład. San Jose DALLAS. W zeszłym tygodniu AMR, spółka będąca właścicielem firmy American (Kalifornia), Airlines, Inc., przyznała, że połamała zęby na próbie stworzenia doskonałego, Mercury News, uniwersalnego systemu rezerwacji lotów, który miał też umożliwiać rezerwowanie 20 czerwca samochodów i pokoi hotelowych. 1992. Artykuł cytowany AMR zaprzestała rozwijania swojego nowego systemu rezerwacji Confirm w parę na grupie tygodni po upływie pierwotnego terminu oddania go do użytku, kiedy to miała ruszyć dyskusyjnej współpraca w zakresie obsługi rezerwacji z partnerami firmy: Budget Rent-A-Car, „comp.risks”, HiltonHotels Corp. oraz Marriott Corp. Zawieszenie czteroletniego projektu, który 13.67, w czerwcu pochłonął 125 milionów dolarów, doprowadziło do zmniejszenia zysków netto firmy 1992. Niektóre o 165 milionów dolarów i zrujnowało jej reputację lidera branży. […] fragmenty pominąłem. Już w styczniu kierownictwo projektu Confirm zdało sobie sprawę z tego, że wysiłki ponad 200 programistów, analityków systemowych i inżynierów poszły na marne. Najważniejsze elementy tego ogromnego projektu, których dokumentacja zajęła 47 000 stron, były rozwijane niezależnie od siebie i w dodatku przy użyciu różnych technik. Po złożeniu ich w jedną całość okazało się, że mimo wysiłków programistów, nie chcą ze sobą współpracować. Poszczególne „moduły” aplikacji nie dawały sobie rady z „wyciąganiem” potrzebnych im informacji z innych modułów. Firma AMR Information Services zwolniła wtedy ośmiu głównych programistów, w tym kierownika projektu.[…] Pod koniec czerwca firmy Budget i Hilton ogłosiły, że wycofują się z projektu. Kluczem do zgodności jest homogeniczność projektu i wypracowanie jednego stan- dardu przesyłania informacji wewnątrz aplikacji. W tym celu należy zastosować: • standaryzowane formaty plików, tak jak w systemie operacyjnym Unix, w którym każdy plik tekstowy jest po prostu sekwencją znaków, • standaryzowane struktury danych, tak jak w programach napisanych w języku Lisp, w których wszystkie dane i programy są reprezentowane przez drzewa binarne, nazywane listami, • standaryzowane interfejsy użytkownika, tak jak w różnych wersjach systemu Win- dows, OS/2 czy MacOS, w których wszystkie narzędzia komunikują się z użytkow- nikiem w taki sam sposób, oparty na wykorzystaniu standardowych komponentów, takich jak okna, ikony, menu itd. Informacje Bardziej ogólne rozwiązania uzyskujemy, definiując standaryzowane protokoły na temat abs- dostępu do wszystkich istotnych elementów, na których operuje oprogramowanie. trakcyjnych typów danych Właśnie ta idea stoi za abstrakcyjnymi typami danych i podejściem obiektowym, a także znajdziesz za tak zwanymi protokołami warstwy pośredniczącej, takimi jak CORBA czy OLE-COM w rozdziale 6. (ActiveX) Microsoftu.
  • 21. 36 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA Wydajność Definicja wydajności Wydajność to zdolność programu do stawiania komputerowi jak najmniejszych wymagań sprzętowych, rozumianych między innymi jako czas procesora, prze- strzeń zajmowana w pamięci wewnętrznej i zewnętrznej, szerokość pasma wyko- rzystywanego przy przesyłaniu danych itd. Środowisko programistów wykazuje zazwyczaj dwa różne podejścia do problemu wy- dajności. • Niektórzy programiści mają na tym punkcie obsesję, w związku z czym poświę- cają mnóstwo czasu na optymalizację kodu i wkładają w nią wiele wysiłku. • Jednak istnieje również inna tendencja, przejawiająca się w mądrościach ludo- wych, takich jak „najpierw spraw, żeby to działało, a dopiero potem zajmij się przyspieszaniem”, czy „za rok komputery i tak będą o połowę szybsze”. Często zdarza się, że ta sama osoba raz jest zwolennikiem pierwszej, a raz dru- giej teorii. To swego rodzaju programistyczne rozdwojenie jaźni (Dr Abstrakcja i Mr Mikrosekunda). Które podeście jest lepsze? Cóż, programiści udowadniali już wielokrotnie, że kwestię optymalizacji kodu potrafią traktować przesadnie. Jak już wspomniałem, wy- dajność nie na wiele się zda, jeżeli oprogramowanie nie jest poprawne (to prowadzi do sformułowania kolejnej złotej zasady: „nie przejmuj się tym, czy program jest szybki, dopóki nie jest poprawny”, która przypomina poprzednią, ale nie do końca znaczy to samo). Mówiąc bardziej ogólnie, musimy wprowadzić pewną równowagę między potrzebami w zakresie wydajności a pozostałymi celami, takimi jak rozszerzalność czy przystosowanie do wielokrotnego użycia. Przesadne optymalizacje mogą uczynić apli- kację tak wyspecjalizowaną, że nie będzie się poddawała modyfikacjom, ani nada- wała do wielokrotnego wykorzystania. Ponadto stale rosnąca szybkość komputerów pozwala przyjąć bardziej luźne podejście do kwestii wydajności i zwalnia z walki o każdy bajt i każdą mikrosekundę. Jednak żaden z tych czynników nie umniejsza znaczenia wydajności. Nikt nie lubi czekać na reakcję interaktywnych aplikacji ani dokupywać pamięci tylko po to, żeby w ogóle można było uruchomić dany program. Także luźne podejście do wydaj- ności często jest tylko pozą. Jeżeli końcowa wersja aplikacji jest tak wolna, że trudno z niej normalnie korzystać, to nawet osoby twierdzące, że „szybkość nie ma znaczenia”, zaczynają narzekać. Ta kwestia odzwierciedla coś, co — moim zdaniem — najlepiej charakteryzuje inżynierię oprogramowania (i myślę, że to się szybko nie zmieni). Tworzenie opro- gramowania jest trudne głównie dlatego, że wymaga brania pod uwagę wielu różnych czynników, z których jedne, takie jak poprawność, są abstrakcyjne i względne, a inne, takie jak wydajność, bardzo konkretne i związane z właściwościami konkretnego sprzętu komputerowego. Dla niektórych naukowców tworzenie oprogramowania jest dziedziną matema- tyki. Dla innych jest to gałąź techniki. W rzeczywistości obie grupy mają rację. Pro- gramista musi pogodzić abstrakcyjne idee i założenia z niedoskonałymi możliwościami ich implementacji, a teorie matematyczne niezbędne do przeprowadzenia poprawnych
  • 22. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 37 obliczeń z ograniczeniami czasowymi i przestrzennymi, wynikającymi z praw fizyki i z niedoskonałości współczesnego sprzętu. Prawdopodobnie ta potrzeba zadowolenia zarówno wilków, jak i owiec, stanowi największe wyzwanie inżynierii oprogramowania. Choć stale rosnąca szybkość komputerów robi duże wrażenie, nie można z jej powodu zaniechać wysiłków na rzecz uzyskania wysokiej wydajności i to co najmniej z trzech powodów. • Ktoś, to kupuje większy i szybszy komputer, chce w ten sposób osiągnąć jakieś konkretne korzyści — mieć możliwość rozwiązywania nowych problemów bądź szybszego rozwiązywania dotychczasowych lub też rozwiązywania starych pro- blemów w takim samym czasie jak dawniej, tyle że rozpatrywanych w większej skali. Natomiast kupowanie nowego komputera po to, aby rozwiązywać stare problemy w takim samym czasie co poprzednio, po prostu nie ma sensu! • Jednym z najbardziej widocznych skutków zwiększania się szybkości komputerów jest wzrost przewagi dobrych algorytmów nad kiepskimi. Załóżmy, że nowy kom- puter jest dwa razy szybszy od starego. Niech n określa rozmiary problemu, który należy rozwiązać, zaś N będzie maksymalnym n, jakie dany algorytm jest w sta- nie obsłużyć w danym czasie. Jeżeli algorytm ma złożoność O(n), to znaczy wy- konuje się w czasie proporcjonalnym do n, to wówczas nowy komputer pozwoli rozwiązać problem o rozmiarze 2∗N (dla dużego N). W przypadku algorytmów w postaci O(n2) nowy komputer pozwoli zwiększyć N jedynie o 41%. Natomiast algorytm typu O(2n), taki jak pewne algorytmy wyszukiwania, zwiększy N jedy- nie o jeden. Nie za dużo, jak na wydane pieniądze. • W niektórych sytuacjach wydajność może wpływać na poprawność. W specyfi- kacji może być na przykład napisane, że komputer musi zareagować na określone zdarzenie nie później niż po upływie określonego czasu. Na przykład komputer pokładowy w samolocie musi być przygotowany na wykrycie i przetworzenie komunikatu od czujnika przepustnicy w czasie na tyle krótkim, aby było możli- we przeprowadzenie ewentualnej korekty lotu. Takie powiązanie między wydaj- nością a poprawnością nie jest ograniczone jedynie do programów, które potocz- nie nazywa się aplikacjami czasu rzeczywistego. Mało kto uświadamia sobie, że z podobną sytuacją mamy do czynienia w programach przewidujących pogodę na następny dzień, które analizują na bieżąco dane napływające przez 24 godziny. Inna przykładowa sytuacja, która może nie stanowiła wielkiego problemu, ale strasznie mnie denerwowała. Używałem kiedyś systemu zarządzania oknami, który był na tyle wolny, że zdarzało mu się nie zarejestrować przesunięcia kursora myszy z jednego okna do drugiego. W rezultacie znaki wpisywane przeze mnie na klawiaturze nie trafiały do tego okna, do którego powinny. W tym przypadku ograniczenia wydajności powodują naruszenie specyfikacji, a konkretnie wpływają na poprawność, a to nawet w niewinnych, używanych na co dzień aplikacjach może mieć niemiłe konsekwencje. Pomyśl, co mogłoby się stać, gdyby dwa otwarte na ekranie okna, o których wspomniałem, były oknami nowych wiadomości pocztowych, skierowanych do dwóch różnych odbiorców. Wojny wybuchały już z dużo bardziej błahych powodów. Ponieważ w tej książce skupiam się na założeniach inżynierii obiektowej, a nie na kwestiach implementacyjnych, tylko w kilku podrozdziałach piszę wprost o kosztach w zakresie wydajności aplikacji. Musisz jednak pamiętać, że problem istnieje i że jestem
  • 23. 38 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA jego świadomy. Za każdym razem gdy omawiam przykładowe obiektowe rozwiązanie jakiegoś problemu, możesz być pewien, że przemyślałem je tak, aby było nie tylko eleganckie, ale też wydajne. Zawsze gdy wprowadzam jakiś nowy mechanizm obiek- towy, taki jak odzyskiwanie pamięci (i inne techniki zarządzania pamięcią w aplika- cjach obiektowych), wiązanie dynamiczne, generyczność czy wielokrotne dziedziczenie, pamiętam o tym, że musi on być zaimplementowany w taki sposób, aby był wydajny pod względem czasu i wymaganej przestrzeni. Dlatego tam, gdzie uznam to za przy- datne, będę wspominał o wpływie przyjętego podejścia na wydajność. Wydajność jest tylko jednym z czynników składających się na jakość. Dlatego nie powinniśmy (jak niektórzy nasi koledzy po fachu) dopuszczać do tego, żeby kierowała naszymi działaniami. Niemniej jednak należy o niej pamiętać, zarówno przy tworzeniu konkretnej aplikacji, jak i na etapie projektowania nowego języka programowania. Jeżeli powiesz wydajności: „Do widzenia”, wydajność to samo powie Tobie. Przenośność Definicja przenośności Przenośność to łatwość, z jaką dane oprogramowanie daje się przenosić między różnymi środowiskami sprzętowymi i programowymi. Tak więc przenośność nie odnosi się jedynie do różnic między fizycznymi urządzeniami sprzętowymi, ale do bardziej ogólnej, sprzętowo-programowej natury komputera. Tej, z którą mamy styczność, pisząc aplikacje, a więc między innymi do systemu ope- racyjnego, systemu okien (jeśli jest on stosowany) i innych podstawowych narzędzi. W dalszej części książki tego rodzaju urządzenie sprzętowo-programowe nazywać będziemy „platformą”. Przykładem platformy jest na przykład „komputer z proceso- rem Intel X86, pracujący pod kontrolą Windows NT”, w skrócie „Wintel”. Wiele obecnych niezgodności między różnymi platformami wydaje się nie mieć sensownego usprawiedliwienia. Naiwny obserwator mógłby nawet stwierdzić, że z pew- nością chodzi o spisek przeciwko ludzkości, a w szczególności przeciw programistom. W każdym razie, niezależnie od przyczyn takiego stanu rzeczy, różnorodność sprawia, że przenośność oprogramowania jest wielkim problemem zarówno dla programistów, jak i użytkowników. Łatwość obsługi Definicja łatwości obsługi Łatwość obsługi to łatwość, z jaką ludzie o różnym doświadczeniu i kwalifikacjach mogą nauczyć się korzystania z aplikacji i stosowania ich do rozwiązywania pro- blemów. Termin ten obejmuje też łatwość instalacji i nadzorowania pracy systemu.
  • 24. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 39 W definicji tej położono nacisk na zróżnicowanie poziomu umiejętności potencjalnych użytkowników. Stanowi to jedno z największych wyzwań dla projektantów aplikacji zajmujących się kwestiami łatwości obsługi. W jaki sposób zapewnić odpowiednią po- moc początkującym i wszystko im wyjaśnić, a przy tym nie zanudzić doświadczonych użytkowników, którzy od razu chcą zabrać się do pracy? Podobnie jak w przypadku wielu innych czynników opisywanych w tym roz- dziale, jednym z kluczy do osiągnięcia łatwości obsługi jest zastosowanie prostej struktury programu. Dobrze zaprojektowany system, zbudowany w oparciu o przejrzystą, prze- myślaną strukturę, będzie łatwiejszy do poznania niż program, w którym panuje duży bałagan. Oczywiście nie jest to warunek wystarczający (to, co może być proste i jasne dla projektanta, użytkownikom może wydawać się dziwne i trudne, zwłaszcza jeśli zo- stanie opisane językiem, jakim posługują się projektanci, a nie użytkownicy), ale za- stosowanie się do niego bardzo pomaga. Jest to jeden z obszarów, w których technika obiektowa jest szczególnie przy- datna. Pewne metody, które na pierwszy rzut oka wydają się dotyczyć zagadnień projektowych i implementacyjnych, pozwalają też stworzyć nowego rodzaju interfejsy użytkownika, które ułatwiają obsługę aplikacji. W następnych rozdziałach podam wiele konkretnych przykładów. Patrz Wilfred Projektanci oprogramowania zajmujący się zagadnieniem łatwości obsługi po- J.Hansen, winni ostrożnie podchodzić do sloganu najczęściej cytowanego w literaturze fachowej, „User Engi- neering pochodzącego ze starego artykułu Hansena, który brzmi: „Poznaj użytkownika”. Stoi Principles for za nim argument, że dobry projektant powinien poświęcić czas na poznanie docelowej Interactive społeczności użytkowników programu. Jednak takie podeście nie uwzględnia jednej Systems”, Sprawozdanie z charakterystycznych cech programów, które odnoszą rynkowy sukces. Po jakimś z FJCC 39, czasie są one wykorzystywane przez szerszą grupę użytkowników, niż pierwotnie są- AFIPS Press, dzono. (Dwoma dobrymi przykładami są tu Fortran, który miał być początkowo na- Montvale (NJ), 1971, rzędziem służącym do rozwiązywania problemów, jakie napotkała mała grupa na- s. 523 – 532. ukowców i inżynierów zajmujących się pisaniem programów na komputer IBM 704, oraz system operacyjny Unix, który pierwotnie miał służyć jedynie do wewnętrznych zastosowań w firmie Bell Laboratories). Każdy system zaprojektowany z myślą o specy- ficznej grupie użytkowników będzie oparty na założeniach, które po prostu przestaną być adekwatne dla szerszego grona odbiorców. Dlatego dobrzy projektanci interfejsów użytkownika trzymają się bardziej ostroż- nej zasady. Czynią oni tak mało założeń dotyczących przyszłych użytkowników, jak to możliwe. Projektując interaktywny program komputerowy, możesz oczekiwać, że jego użytkownicy będą przedstawicielami rasy ludzkiej i będą potrafili czytać, poru- szać myszą, klikać przycisk i pisać (powoli), nic ponadto. Jeżeli aplikacja ma służyć do rozwiązywania problemów z jakiejś konkretnej dziedziny, można też pewnie zało- żyć, że jej użytkownicy będą mieli choć podstawową wiedzę w tym zakresie. Ale nawet takie założenie jest już ryzykowne. Parafrazując radę Hansena, mogę sformułować zasadę projektowania interfejsu użytkownika. Zasada projektowania interfejsu użytkownika Nie udawaj, że znasz użytkownika. Nie znasz.
  • 25. 40 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA Funkcjonalność Definicja funkcjonalności Funkcjonalność to zbiór możliwości oferowanych przez system. Jednym z największych problemów, przed jakimi stają szefowie projektów, jest okre- ślenie, jak duża funkcjonalność jest już wystarczająca. W przemyśle programistycz- nym stale odczuwa się nacisk na dodawanie do programów kolejnych możliwości, co powszechnie nazywane jest pogonią za wodotryskami. Jej konsekwencje są złe już dla wewnętrznych projektów, w których naciski pochodzą ze strony pracowników tej samej firmy, a w przypadku produktów komercyjnych jeszcze gorsze. Niestety większość pism komputerowych przy sporządzaniu recenzji kilku konkurencyjnych produktów zazwy- czaj skupia się jedynie na przedstawieniu tabeli, w której porównuje się ich możliwości. Pogoń za możliwościami to właściwie dwa oddzielne problemy, z których jeden jest trudniejszy do rozwiązania. Prostszy problem polega na tym, że, dodając nowe funk- cje, możemy utracić spójność, co odbije się na łatwości obsługi. Użytkownicy często narzekają, że wszystkie te „wodotryski” dodawane do kolejnych wersji znanych pro- gramów czynią je jedynie niesamowicie złożonymi. Tego rodzaju uwagi trzeba jednak traktować z przymrużeniem oka, ponieważ nowe funkcje nie biorą się z próżni. Zwykle proszą o nie użytkownicy, tyle że niekoniecznie ci sami. To, co mnie wydaje się świet- nym ułatwieniem, dla Ciebie może być tylko nieprzydatnym gadżetem. Jedynym rozwiązaniem jest tu stała praca nad zachowaniem spójności całego programu i podejmowanie prób wciśnięcia wszystkich funkcji w już wyznaczone ramy. Każdy dobry program opiera się na kilku nowatorskich pomysłach. Jeśli nawet ma on wiele funkcji, powinny one wynikać z podstawowych założeń. W konstrukcji pro- gramu musi być widoczny jakiś konkretny plan, w którym każdy element ma swoje miejsce. Trudniejszy problem polega na tym, iż można tak bardzo zaangażować się w do- dawanie nowych funkcji, że zapomni się o innych czynnikach. Jest to powszechnie popełniany błąd, zobrazowany przez Rogera Osmonda na wykresie w postaci dwóch możliwych ścieżek prowadzących do ukończenia projektu (patrz rysunek 1.4). RYSUNEK 1.4. Krzywe Osmonda, za [Osmond 1995]
  • 26. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 41 W życiu sytuacja wygląda najczęściej tak, jak pokazuje to dolna (czarna) krzywa. W szaleńczym wyścigu za dodawaniem nowych funkcji programiści zapominają o ogól- nej jakości programu. Ostatnia faza projektu, w której wszystko powinno być już do- prowadzone do porządku, potrafi być długa i stresująca. Jeżeli pod wpływem presji użytkowników lub konkurencji jesteś zmuszony do wypuszczenia programu we wcze- snej fazie produkcji, na jednym z etapów oznaczonych na wykresie czarnymi kwa- dratami, pamiętaj, że może to zaszkodzić Twojej reputacji. Osmond sugeruje (krzywa linią przerywaną), abyś — korzystając z możliwości, jakie daje programowanie zorientowane obiektowo — utrzymywał ogólną jakość programu (poza funkcjonalnością) przez cały czas na takim samym poziomie. Chodzi więc o to, abyś nigdy nie oszczędzał na niezawodności, rozszerzalności itp. Nie wolno Ci dodawać nowych funkcji, dopóki te, które już masz, będą działać, tak jak trzeba. Takie podejście jest trudniejsze do stosowania na co dzień ze względu na wspo- mniane naciski, ale prowadzi do wydajniejszego procesu tworzenia aplikacji, a często także do uzyskania w ostatecznym rozrachunku lepszego produktu. Jeśli nawet koń- cowe rezultaty są w obu przypadkach takie same, tak jak na przytoczonym wykresie, to postępując zgodnie z podanymi zasadami, powinniśmy uzyskać je szybciej (wykres nie uwzględnia czasu). Gdy trzymamy się sugerowanej ścieżki rozwoju projektu, ewentualne wypuszczenie wczesnej wersji programu (na jednym z etapów oznaczo- nych ukośnie kreskowanymi kwadratami) jest znacznie łatwiejsze. Trzeba jedynie odpowiedzieć sobie na pytanie, czy zakres funkcjonalności, który został już zaim- plementowany w programie, jest wystarczająco szeroki, aby przyciągnąć do niego klientów i nie zrazić niektórych z nich. Natomiast nie musimy już zastanawiać się „czy to jest wystarczająco dobre”. Każdy czytelnik, który miał już okazję kierować jakimś projektem programi- stycznym, przyzna, że dużo łatwiej dawać takie rady, niż je stosować. Niemniej jednak w przypadku każdego projektu powinno się dążyć do ideału reprezentowanego przez wyższą krzywą Osmonda. Doskonale współgra on z modelem klastrowym wprowa- dzonym w jednym z kolejnych rozdziałów i będącym jednym ze schematów prowa- dzenia projektu programistycznego. Adekwatność czasowa Definicja adekwatności czasowej Adekwatność czasowa to gotowość programu komputerowego do wypuszczenia na ry- nek wtedy, gdy użytkownicy go potrzebują, lub jeszcze zanim pojawi się taka potrzeba. W przemyśle programistycznym jednym z najbardziej stresujących czynników jest adekwatność czasowa. Doskonały produkt, który pojawi się na rynku za późno, może okazać się całkowitą klapą. Oczywiście tak samo jest też w innych gałęziach przemysłu, ale niewiele z nich podlega tak szybkim zmianom. „NT 4.0 Beat- Adekwatność czasowa jest czymś rzadko spotykanym, nawet w przypadku du- sClock”, Com- żych projektów programistycznych. Gdy Microsoft ogłosił, że najnowsza wersja jego puter-World, nr 30, 22 sztandarowego systemu operacyjnego, tworzonego przez wiele lat, zostanie wypusz- czerwca 1996. czona na rynek o miesiąc wcześniej, niż zakładano, uznano to za tak sensacyjną wia- domość, że zamieszczono ją na okładce magazynu ComputerWorld (wraz z komenta- rzem na temat długich opóźnień, które zdarzały się tej firmie w przeszłości).
  • 27. 42 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA Inne czynniki Poza już omówionymi czynnikami decydującymi o jakości, istnieją też inne, mające wpływ na użytkowników, decydentów zamawiających systemy komputerowe i pro- gramistów. Oto niektóre z nich. • Weryfikowalność, czyli łatwość przygotowywania procedur pozwalających okre- ślić, czy produkt znajduje się na akceptowalnym poziomie. W szczególności chodzi tu o dane testowe i procedury pozwalające na wykrywanie niepowodzeń i odnaj- dywanie tych błędów popełnionych na etapie walidacji danych i w fazie operacyjnej, które są przyczyną niepowodzeń. • Integralność, czyli zdolność oprogramowania do chronienia swoich składników (programów, danych) przed nieautoryzowanym dostępem i modyfikacjami. • Naprawialność, czyli udostępnianie możliwości naprawiania defektów. • Ekonomiczność, będąca uzupełnieniem adekwatności czasowej, czyli zdolność systemu do zmieszczenia się w założonym budżecie. Dokumentacja Analizując listę czynników decydujących o jakości, możesz dojść do wniosku, że jednym z wymagań powinna być dobra dokumentacja. Jednak nie jest to odrębny składnik. Potrzeba takiej dokumentacji wynika z pozostałych czynników, które już omówiłem. Możemy wyróżnić trzy rodzaje dokumentacji. • Dokumentacja zewnętrzna, dzięki której użytkownicy mogą zrozumieć możliwo- ści systemu i wygodnie z nich korzystać. Jest to konsekwencja wymagania zde- finiowanego jako łatwość obsługi. • Dokumentacja wewnętrzna, która pozwala zrozumieć strukturę i implementację systemu programistom. Jest to konsekwencja wymagania zdefiniowanego jako rozszerzalność. • Dokumentacja interfejsów poszczególnych modułów, dzięki której programiści mogą zrozumieć działanie funkcji dostarczanych przez dany moduł bez potrzeby zagłębiania się w jego implementację. Jest to konsekwencja wymagania zdefi- niowanego jako przystosowanie do wielokrotnego użycia. Wynika ona również z rozszerzalności, ponieważ dokumentacja interfejsów modułów pozwala określić, czy dana zmiana będzie miała wpływ na konkretny moduł. Dlatego, zamiast traktować dokumentację jako osobny produkt, lepiej pisać mak- symalnie samodokumentujący się kod. Zasada ta odnosi się do wszystkich trzech ro- dzajów dokumentacji. • Uwzględniając w programie podsystem pomocy ekranowej, a także trzymając się jasnych i spójnych konwencji przy tworzeniu interfejsu użytkownika, ułatwiamy zadanie autorom podręczników użytkownika i innych materiałów dydaktycznych.
  • 28. 1.2. PRZEGLĄD CZYNNIKÓW ZEWNĘTRZNYCH 43 • Zaimplementowanie programu w dobrym języku programowania zlikwiduje w dużej mierze konieczność tworzenia wewnętrznej dokumentacji, jeśli tylko język ten będzie sprzyjał organizacji i przejrzystości kodu. Są to jedne z najważniejszych czynników wpływających na wygląd notacji obiektowej, którą będę wprowadzał w tej książce. • Notacja ta będzie obsługiwała ukrywanie informacji i inne techniki (takie jak aser- cje) pozwalające oddzielić interfejsy modułów od ich implementacji. Pozwoli to zastosować narzędzia, które automatycznie wygenerują dokumentację interfej- sów modułów na podstawie ich kodów źródłowych. Tym zagadnieniem również zajmiemy się dokładnie w dalszych rozdziałach. Wszystkie te techniki ograniczają znaczenie tradycyjnej dokumentacji, ale oczywi- ście nie możemy od nich oczekiwać, aby całkowicie ją zastąpiły. Kompromisy W tym przeglądzie zewnętrznych czynników składających się na jakość oprogramo- wania pojawiły się już wymagania, które kłócą się z innymi. Czy jest możliwe osiągnięcie integralności bez wprowadzania żadnych zabezpieczeń? Z kolei wprowadzenie ich musi się negatywnie odbić na łatwości obsługi. Ekonomicz- ność często wydaje się stać w sprzeczności z funkcjonalnością. Uzyskanie optymalnej wydajności wymagałoby perfekcyjnego wykorzystania możliwości oferowanych przez dane środowisko sprzętowe i programowe, co kłóci się z przenośnością. Z jednej strony, mówi się nam, żebyśmy trzymali się ściśle specyfikacji, a z drugiej, popycha się nas w kierunku tworzenia ogólnych rozwiązań, które nadawałyby się do wielokrotnego użycia. Naciski na adekwatność czasową mogą skłaniać ku środowiskom szybkiego tworzenia aplikacji (RAD), przy których mamy mocno ograniczoną rozszerzalność. Choć w wielu przypadkach daje się znaleźć rozwiązanie pozwalające pogodzić ze sobą sprzeczne wymagania, czasami trzeba poświęcić pewne czynniki na rzecz drugich. Niestety zbyt często programiści robią to niejawnie, nie zastanowiwszy się wcześniej nad wszystkimi dostępnymi możliwościami i ich konsekwencjami. W re- zultacie najczęściej skupiają się na wydajności. Natomiast prawdziwy inżynier oprogra- mowania powinien zadać sobie trud jawnego sformułowania kryteriów, którymi będzie posługiwał się przy wyborze, i podjąć w pełni świadome decyzje. Choć między czynnikami decydującymi o jakości trzeba często dokonywać wy- borów, nie wolno nigdy zapomnieć, że najważniejszym z nich jest poprawność. Nic nie usprawiedliwia zaniedbania poprawności na rzecz innych czynników, na przykład takich jak wydajność. Jeżeli oprogramowanie nie spełnia swojej roli, to reszta nie ma znaczenia. Kluczowe zagadnienia Wszystkie opisywane dotychczas czynniki są ważne. Ale w obecnym stanie przemy- słu programistycznego cztery z nich wydają się mieć szczególne znaczenie. Są to:
  • 29. 44 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA • Poprawność i odporność. W dalszym ciągu tworzenie oprogramowania pozba- wionego defektów jest zbyt trudne, podobnie jak usuwanie błędów, gdy już uda się je zlokalizować. Wszystkie techniki służące zwiększaniu poprawności i od- porności opierają się na tych samych pomysłach — zastosowaniu bardziej usys- tematyzowanego podejścia do tworzenia oprogramowania, stosowaniu bardziej formalnych specyfikacji, użyciu wbudowanych mechanizmów kontrolnych już na etapie tworzenia oprogramowania (a nie bazowanie jedynie na testowaniu i usu- waniu błędów już po zakończeniu projektu), wykorzystanie lepszych mechani- zmów językowych, takich jak statyczna kontrola typów, asercje, automatyczne zarządzanie pamięcią czy zdyscyplinowana obsługa wyjątków, które pozwalają programistom spełniać wymagania dotyczące poprawności i odporności, a na- rzędziom programistycznym wykrywać wszelkie niespójności, zanim doprowadzą one do powstania defektów. Ze względu na tak bliskie powiązanie poprawności z odpornością, wygodniej stosować bardziej ogólny termin — obejmujący swym znaczeniem oba te czynniki — niezawodność. • Rozszerzalność i przystosowanie do wielokrotnego użycia. Oprogramowanie po- winno dawać się łatwiej modyfikować. Tworzone przez nas komponenty pro- gramistyczne powinny stwarzać możliwość zastosowania w większej liczbie sytu- acji. Powinno ich też być więcej. Również w przypadku tych dwóch czynników źródłem usprawnień są te same pomysły. Ogólnie można by rzec, że pomocne są wszystkie techniki, które przyczyniają się do tworzenia bardziej zdecentralizo- wanych architektur, w których komponenty mają budowę zamkniętą i komunikują się ze sobą jedynie za pomocą ograniczonych i ściśle zdefiniowanych kanałów. Rozszerzalność i przystosowanie do wielokrotnego użycia będziemy określali wspólnym terminem modułowości. Technika obiektowa, z którą zapoznasz się dokładnie w kolejnych rozdziałach, pozwala wyraźnie ulepszyć te cztery czynniki decydujące o jakości, co czyni ją tak atrakcyjną. Przyczynia się ona również w znacznym stopniu do spełnienia pozostałych wymagań, szczególnie takich jak: • Zgodność. Technika obiektowa sprzyja stosowaniu jednolitego stylu projektowa- nia i tworzeniu standaryzowanych modułów i interfejsów, co z kolei pomaga two- rzyć systemy, które mają ze sobą współpracować. • Przenośność. Kładąc nacisk na abstrakcyjność i ukrywanie informacji, technika obiektowa zachęca projektantów do rozróżniania specyfikacji i implementacji, co ułatwia przenoszenie aplikacji na różne platformy. Techniki, takie jak polimor- fizm i wiązanie dynamiczne, pozwalają nawet tworzyć systemy, które automatycznie dostosowują się do zastanych komponentów platformy sprzętowo-programowej, na przykład do różnych systemów zarządzania oknami czy bazami danych. • Łatwość obsługi. Wpływ, jaki narzędzia obiektowe wywarły na współczesne in- teraktywne programy komputerowe, a w szczególności na ich interfejsy użyt- kownika, jest powszechnie znany. Czasami przypisuje się temu nawet większe znaczenie, niż by wypadało (twórcy reklam nie są jedynymi osobami, które każ- dy program, w jakim są ikony i okna, obsługiwany za pomocą myszy, nazywają obiektowym). • Wydajność. Jak już wspomniałem, mimo iż z zakupem szybkiego komputera i ze stosowaniem technik obiektowych wiąże się pewien koszt, możliwość wykorzy- stywania w procesie tworzenia oprogramowania profesjonalnych komponentów wielokrotnego użytku pozwala znacznie zyskać na wydajności.
  • 30. 1.3. KONSERWACJA OPROGRAMOWANIA 45 • Adekwatność czasowa, ekonomiczność i funkcjonalność. Techniki obiektowe po- zwalają tym, którzy opanują je do perfekcji, tworzyć programy szybciej i przy mniejszych kosztach. Ułatwiają one dodawanie nowych funkcji, a czasem wręcz sugerują, jakie możliwości przydałoby się jeszcze wprowadzić. Mimo oczywistego postępu, jaki niosą ze sobą techniki obiektowe, powinniśmy pamiętać, że nie stanowią one panaceum i że w dalszym ciągu musimy rozwiązywać wiele klasycznych problemów inżynierii programowania. To, że coś nam w tym pomaga, nie oznacza jeszcze, że rozwiąże to problem za nas. 1.3. KONSERWACJA OPROGRAMOWANIA Być może zauważyłeś, że nie wymieniłem dotąd często wspominanego czynnika de- cydującego o jakości, jakim jest łatwość konserwacji. Aby zrozumieć, dlaczego tak postąpiłem, musisz przyjrzeć się bliżej temu, czym właściwie jest konserwacja opro- gramowania. Terminem konserwacja określamy wszystko, co robi się już po przekazaniu pro- gramu odbiorcom. Wszystkie dyskusje na temat metodyki tworzenia oprogramowania z reguły skupiają się jedynie na programowaniu. Podobne podejście obserwuje się na kursach programowania dla początkujących. Tymczasem powszechnie wiadomo, że 70% kosztów tworzenia oprogramowania pochłania właśnie jego konserwacja. Żadne omówienie zagadnienia jakości oprogramowania nie jest wystarczające, jeżeli pomija się w nim ten aspekt. Zatem co rozumiemy przez „konserwację” w odniesieniu do oprogramowania? Programy komputerowe nie zużywają się od ciągłego korzystania, a tym samym nie trzeba ich „konserwować”, tak jak samochodów czy telewizorów. Można by więc rzec, że jest to dość nietrafione określenie. Tym bardziej, że odnosi się ono zarówno do bar- dziej, jak i do mniej chwalebnych zajęć. Do pierwszej grupy zaliczyć można wszelkie modyfikacje. Wiadomo, że specyfikacje systemów komputerowych zmieniają się po to, aby odzwierciedlać zmiany zachodzące w świecie zewnętrznym. Pociąga to za so- bą konieczność modyfikowania samych programów. Natomiast do drugiej grupy zali- czamy czynności służące do lokalizowania i usuwania błędów, których na tym etapie projektu w ogóle nie powinno już być. Wykres przedstawiony na rysunku 1.5, pochodzący z pamiętnego opracowania Lientza i Swansona, pokazuje już bardziej konkretnie, jakie zagadnienia mieszczą się pod pojęciem konserwacji. Autorzy przepytali 487 zespołów programistycznych roz- wijających aplikacje różnych typów. Mimo iż badanie odbyło się już jakiś czas temu, wyniki najnowszych ankiet potwierdzają ich odkrycia. Wykres pokazuje, jaka część kosztów konserwacji oprogramowania przypada na poszczególne zagadnienia, wyod- rębnione przez autorów. Ponad dwie piąte kosztów przeznaczane jest na rozbudowywanie i modyfikowa- nie aplikacji na życzenie użytkowników. Są to czynności, których praktycznie nie da się uniknąć. Natomiast bez odpowiedzi pozostaje pytanie, ilu spośród tych wysiłków można by uniknąć, gdyby oprogramowanie było od początku projektowane z myślą o rozszerzalności. Mamy pełne podstawy sądzić, że technika obiektowa pozwoli po- prawić tę sytuację.
  • 31. 46 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA RYSUNEK 1.5. Koszty konserwacji oprogramowania. Źródło: [Lientz 1980] Szczególnie interesująca jest druga pozycja — zmiany w formatach danych. Gdy Inny przykład zmienia się fizyczna struktura plików i innych elementów przechowujących dane, trze- znajdziesz w podroz- ba zaadaptować do tych zmian istniejące aplikacje. Gdy na przykład poczta w Stanach dziale: Zjednoczonych przydzieliła parę lat temu dużym firmom kody pocztowe w postaci „Jak długi „5+4” (złożone z dziewięciu znaków zamiast pięciu), trzeba było przepisać od nowa jest środkowy inicjał?”, na wiele programów, które „wiedziały”, że kody pocztowe składają się dokładnie z pięciu stronie 167. znaków. Prasa oszacowała, że kosztowało to kilkaset milionów dolarów. Zapewne wielu czytelników otrzymało swego czasu piękne zaproszenia na cykl konferencji (nie jedną czy dwie, ale cały cykl, prowadzony w wielu miastach) poświęconych „problemowi roku 2000”. Mówiono na nich, w jaki sposób unowocześnić wiele programów służących do przechowywania bardzo istotnych danych, których autorzy nawet przez chwilę nie pomyśleli, że po upływie XX wieku również trzeba będzie jakoś wprowadzać daty. W porównaniu z tym problem kodów pocztowych wydaje się błahostką. Jorge Luis Borges stwierdził, że skoro dziś mało kto zastanawia się, co stanie się 1 stycznia 3000 roku, to prawdopodobnie możemy uznać, że był to jedyny cykl konferencji w historii ludzkości poświęcony tak niepozornemu tematowi — jednej dziesiętnej cyfrze. Nie chodzi o to, że jakaś część programu zna fizyczną strukturę danych. To jest akurat nieuniknione, ponieważ w pewnym momencie program musi mieć dostęp do danych po to, aby mógł przeprowadzić na nich jakieś operacje. Jednak w tradycyj- nych technikach projektowania ta wiedza jest dostępna w zbyt wielu częściach syste- mu, przez co po zmianie fizycznej struktury danych (a to zawsze kiedyś następuje) trzeba modyfikować wiele fragmentów programu, a wcale nie musi tak być. Innymi sło- wy, jeżeli kody pocztowe zostaną wydłużone z pięciu do dziewięciu znaków, a daty zaczną wymagać stosowania dodatkowej cyfry, będzie można mieć uzasadnione po- dejrzenia, że należy zaadaptować do tych zmian programy operujące na tych wielko- ściach. Natomiast nie do zaakceptowania jest sytuacja, w której informacje na temat dokładnej długości danych są umieszczone w bardzo wielu miejscach w programie, tak że zmiana tej długości pociąga za sobą konieczność modyfikowania niewspółmiernie wielu fragmentów kodu.
  • 32. 1.4. KLUCZOWE POJĘCIA WPROWADZONE W TYM ROZDZIALE 47 Rozwiązaniem tego problemu są abstrakcyjne typy danych, dzięki którym pro- gramy mogą odwoływać się do danych za pośrednictwem swych zewnętrznych wła- ściwości, a nie fizycznych implementacji. Szczegółowe Kolejną ciekawą rzeczą dającą się zaobserwować na wykresie jest niski udział re- omówienie abstrakcyjnych dagowania dokumentacji w całkowitych kosztach konserwacji (5,5%). Pamiętaj, że typów danych mówimy tu jedynie o kosztach czynności konserwacyjnych. Ponieważ na ten temat znajdziesz nie mamy bardziej precyzyjnych danych, możemy jedynie spekulować, iż wynika to w rozdziale 6. z tego, że albo dokumentacja tworzona jest na etapie rozwijania kodu, albo nie pisze się jej wcale. W dalszej części książki poznasz styl projektowania, dzięki któremu większa część dokumentacji trafia bezpośrednio do kodu źródłowego. Powiem też o specjalnych narzędziach, które pozwalają ją stamtąd wydobyć. Kolejne pozycje na liście Lientza i Swansona również są bardzo interesujące, choć nie są, tak jak pozostałe, bezpośrednio związane z zagadnieniami poruszanymi w tej książce. Awaryjne poprawki błędów (opracowywane w pośpiechu po tym, jak któryś z użytkowników zgłosi, że program nie zwraca oczekiwanych wyników lub zachowuje się w nieprawidłowy sposób) kosztują więcej niż rutynowe, zaplanowane poprawki. Wynika to nie tylko z tego, że wymagają one pracy pod dużą presją, ale również z tego, że konieczność ich przygotowania zmienia ustalony harmonogram wypuszczania no- wych wersji programu, a w dodatku może prowadzić do wprowadzenia nowych błędów. Ostatnie dwie czynności mają niewielki udział w kosztach. • Pierwszą z nich jest zwiększanie wydajności. Wykres zdaje się sugerować, że gdy system już działa, szef projektu i programiści nie chcą go ruszać, żeby go nie ze- psuć, nawet jeśli potencjalnie mogliby zwiększyć jego wydajność. Gdy przy- pomnimy sobie zasadę: „najpierw spraw, żeby to działało, a dopiero potem zajmij się przyspieszaniem”, dojdziemy do wniosku, że widocznie większość projektów zatrzymuje się na tej pierwszej czynności. • Podobnie niski udział w kosztach ma również „przenoszenie do nowych środo- wisk”. Można to interpretować w ten sposób (podobnie jak poprzednio nie mamy bardziej szczegółowych danych), że pod względem przenośności programy dzielą się zasadniczo na dwie kategorie, a między nimi właściwie nic nie ma, czyli na programy, które od początku były projektowane z myślą o przenośności, gdzie przeprowadzenie takiej operacji nie jest zbyt kosztowne, oraz programy tak mocno przywiązane do swoich pierwotnych platform, że przeniesienie ich na inne byłoby tak trudne, iż programiści nawet nie próbują tego robić. 1.4. KLUCZOWE POJĘCIA WPROWADZONE W TYM ROZDZIALE • Zadaniem inżynierii oprogramowania jest opracowywanie sposobów tworzenia wysokich jakościowo programów komputerowych. • Jakość oprogramowania nie jest pojedynczą wielkością. Należy ją raczej rozpa- trywać jako sumę wielu różnych czynników, które w każdym programie występują w nieco innych proporcjach.
  • 33. 48 ROZDZIAŁ 1. JAKOŚĆ OPROGRAMOWANIA • Należy odróżniać zewnętrzne czynniki składające się na jakość, czyli te dostrze- gane przez użytkowników i klientów, od czynników wewnętrznych, widocznych jedynie dla projektantów i implementatorów. • Liczą się jedynie czynniki zewnętrzne, ale do ich uzyskania niezbędne są odpo- wiednie czynniki wewnętrzne. • Przedstawiłem listę najważniejszych czynników zewnętrznych decydujących o ja- kości aplikacji. Te z nich, które najwięcej zyskałyby na wprowadzeniu nowych technik i do których bezpośrednio odnosi się metoda obiektowa, to czynniki zwią- zane z bezpieczeństwem (poprawność i odporność), określane wspólnie mianem niezawodności, oraz czynniki wymagające stosowania zdecentralizowanych ar- chitektur oprogramowania (przystosowanie do wielokrotnego użycia i rozszerzal- ność), określane mianem modułowości. • Konserwacja oprogramowania, na którą przypada większa część kosztów pro- jektu, jest trudna ze względu na fakt, że niełatwo implementuje się zmiany w ist- niejących programach, oraz z powodu nadmiernego uzależnienia programów od fizycznej struktury danych, na których one operują. 1.5. BIBLIOGRAFIA Próbę zdefiniowania jakości oprogramowania podjęło już wielu autorów. Spośród pierwszych opracowań na ten temat dwa pozostają wciąż zaskakująco aktualne: arty- kuł [Hoare 1972] oraz [Boehm 1978] — wyniki pierwszych usystematyzowanych ba- dań na temat tworzenia oprogramowania, prowadzonych przez ludzi z TRW. Rozróżnienie między czynnikami zewnętrznymi a wewnętrznymi zostało wpro- wadzone w materiałach przekazanych w 1977 roku lotnictwu Stanów Zjednoczonych przez firmę General Electric [McCall 1977]. To, co my nazywamy czynnikami ze- wnętrznymi, McCall określa po prostu mianem „czynników”, zaś na czynniki we- wnętrzne mówi „kryteria”. Wiele (choć nie wszystkie) spośród opisanych przeze mnie czynników stanowi bezpośrednie odpowiedniki czynników McCalla. Jeden z jego czynników pominąłem (łatwość konserwacji), ponieważ, jak już wyjaśniłem, pokrywa się on z rozszerzalnością i weryfikowalnością. W swych rozważaniach McCall nie ogranicza się jedynie do czynników zewnętrznych, lecz opisuje też czynniki we- wnętrzne („kryteria”), metryki oraz ilościowe techniki gwarantujące uzyskanie satys- fakcjonujących czynników wewnętrznych. Jednak wraz z pojawieniem się techniki obiektowej wiele z opisywanych przez niego czynników wewnętrznych i metryk przestało mieć znaczenie ze względu na swe ścisłe powiązanie ze stosowanymi wcze- śniej praktykami programistycznymi. Przystosowanie tej części pracy McCalla do technik opisywanych w mojej książce jest całkiem interesującym wyzwaniem. Patrz bibliografia i ćwiczenia w rozdziale 3. Omówienie zależności względnego wzrostu wydajności systemu (po wymianie komputera na szybszy) od rodzaju stosowanego algorytmu wywodzi się z [Aho 1974]. Klasyczną pozycją na temat łatwości obsługi jest [Shneiderman 1987], opierający się na pracy [Shneiderman 1980], poświęconej szerszemu zakresowi zagadnień z dzie- dziny programowania. Odnośniki do wielu materiałów na ten temat można też znaleźć na stronie internetowej laboratorium Shneidermana, pod adresem http://www.cs.umd. edu/projects/hcil/.
  • 34. 1.5. BIBLIOGRAFIA 49 Krzywe Osmonda pochodzą z wykładu wygłoszonego przez Rogera Osmonda na konferencji TOOLS USA [Osmond 1995]. Zwróć uwagę, że wykres pokazany w tym rozdziale nie uwzględnia czasu, dzięki czemu możesz lepiej przyjrzeć się zależno- ściom między funkcjonalnością a innymi czynnikami, wskazywanymi przez dwie al- ternatywne krzywe. Pamiętaj jednak, że na tym wykresie nie widać, że postępowanie zgodnie z czarną krzywą może doprowadzić do opóźnienia projektu. Oryginalne krzywe Osmonda miały za zadanie ukazywać raczej czas rozwijania aplikacji, a nie zwięk- szanie jej funkcjonalności. Wykres prezentujący koszty konserwacji programów pochodzi z wyników badań przeprowadzonych przez Lientza i Swansona, którzy wysłali kwestionariusze do 487 firm [Lientz 1980]. Patrz również [Boehm 1979]. Mimo iż niektóre spośród zbiera- nych przez nich danych dziś mogą wydawać się nieadekwatne (badanie dotyczyło wsadowych aplikacji na komputery MIS, które składały się średnio z 23 000 wierszy kodu, co jak na dzisiejsze warunki nie jest zbyt dużą liczbą), uzyskane przez nich wy- niki nadal wyglądają sensownie. Stowarzyszenie Software Management Association przeprowadza co roku ankietę na temat konserwacji. Wyniki jednej z nich znajdziesz w [Dekleva 1992]. Wyrażenia programowanie w dużej skali i programowanie w małej skali pochodzą z [DeRemer 1976]. Ogólne omówienie zagadnień z dziedziny inżynierii oprogramowania znajdziesz w książce, którą napisali Ghezzi, Jazayeri i Mandrioli [Ghezzi 1991]. Dwóch spośród tych autorów napisało też książkę o językach programowania, [Ghezzi 1997], stano- wiącą uzupełnienie niektórych zagadnień poruszanych w tej książce.