Analizy i publikacje
Pliki do pobrania:
BMU20.pps (prezentacja PowerPoint), BMU20.zip (projekt pakietu i kod źródłowy).
Biblioteka BMU
Istotną niedogodnością metodyczną pojawiającą się w
zintegrowanych środowiskach programistycznych jest nadmierne
znaczenie, jakie projektanci tych środowisk nadali zagadnieniom
dostępu do baz danych. Dotyczy to zarówno komponentów integrujących
aplikację z relacyjnymi bazami danych, jak i komponentów
realizujących obsługę odpowiednich elementów graficznego interfejsu
użytkownika – komponentów, które umożliwiają użytkownikowi wizualną
edycję danych. Sytuacja ta, niezależnie od zalet tego typu środowisk
programistycznych, ogranicza w pewnym stopniu ich potencjalne
możliwości. Zmusza bowiem programistów do łączenia funkcji
związanych z przetwarzaniem danych, z funkcjami obsługującymi
interfejs użytkownika. Dotyczy to najczęściej tych fragmentów kodu
źródłowego programu, które są odpowiedzialne za obsługę okien
formularzy edycyjnych. Kod źródłowy programu jest wówczas dosyć
nieczytelny, przez co uruchamianie i późniejsza konserwacja programu
są w znacznym stopniu utrudnione.
Środowisko programistyczne C++ Builder™, podobnie zresztą, jak
opracowane wcześniej w firmie Borland środowisko Delphi™, jest
bardzo popularne wśród programistów i firm informatycznych
zajmujących się wytwarzaniem oprogramowania. Oba środowiska
programistyczne posługują się rozbudowaną biblioteką komponentów VCL
(ang. Visual Component Library), która znacznie przyspiesza i
ułatwia tworzenie aplikacji działających w środowiskach graficznych
systemów operacyjnych. Rrzeba stwierdzić, że wspomniana wcześniej
funkcjonalność tychże środowisk zintegrowanych odpowiedzialna za
komunikację z bazami danych została bardzo dobrze zaprojektowana i
to ona właśnie zadecydowała o ich dużej popularności. Niezależnie od
tego faktu, narzucony przez twórców środowiska model aplikacji jest
bardzo odległy od rozwijanych i wdrażanych w ostatnich latach
obiektowych metod analizy i projektowania systemów informatycznych,
co jest istotą niedogodności, o których tu mowa.
Powstaje zatem poważna przeszkoda w stosowaniu środowiska
zintegrowanego C++ Builder™ w realizacjach tych projektów, w których
oprogramowanie wytwarza się z zastosowaniem metodyk obiektowych.
Problem polega w głównej mierze na braku możliwości sprzężenia
obiektowego modelu systemu informatycznego z jego implementacją, a
właściwe z tą częścią implementacji, która realizuje funkcje
komunikacji z bazą danych i edycją jej zawartości. Problem ten
najbardziej uwidacznia się w przypadku, w którym w procesie
wytwarzania systemów informatycznych korzysta się z oprogramowania
narzędziowego typu CASE (ang. Computer Aided Software Engineering),
szczególnie zaś w przypadku posługiwania się udostępnianymi przez to
oprogramowanie generatorami kodu źródłowego.
W ramach projektu BMU (projekt prowadzony częściowo w ramach badań
finansowanych przez Ministerstwo Nauki) podjęto próbę
rozwiązania opisanego powyżej problemu dla platformy zintegrowanego
środowiska programistycznego C++ Builder™. W ramach prac nad
artykułem opracowane zostały projekt i implementacja biblioteki
komponentów nazwanej przez autorów skrótem BMU (od ang. Business
Model Utility). Biblioteka ta umożliwia implementację w wymienionym
środowisku, oprogramowania, którego projekt powstał z zastosowaniem
metodyki obiektowej, np. metodyki RUP™(ang. Rational Unified
Process) oraz związanych z tą metodyką programów narzędziowych typu
CASE.
Analiza problemu i jej wyniki
Podstawowe pytanie, jakie należy zadać rozważając możliwości
rozszerzenia środowiska Borland C++ Builder™ o elementy integrujące
jego koncepcję z koncepcją metodyki obiektowej RUP™, dotyczy
ustalenia sposobu implementacji, który zagwarantuje pełne
wykorzystanie sporych przecież możliwości biblioteki VCL.
Szczególnie dotyczy to tej funkcjonalności biblioteki, która
znajduje się w warstwie komunikacji aplikacji z bazą danych. Aby móc
odpowiedzieć na tak postawione pytanie, należy zastanowić się nad
kilkoma aspektami rozważanej integracji.
Pierwszy aspekt dotyczy pokonania różnic koncepcyjnych pomiędzy
podejściem obiektowym i strukturalnym, które to podejście de facto
zostało narzucone programistom przez twórców środowiska, pomimo, iż
sama biblioteka VCL stanowiąca jego trzon zrealizowana została z
zastosowaniem technik obiektowych. Sięgając głębiej należy zauważyć,
że przyczyna tych różnic leży w rozbieżnościach pomiędzy schematem
obiektowym, który jest istotą samego podejścia obiektowego, a
schematem relacyjnym, na którym oparto koncepcję stosowanych nadal
bardzo powszechnie relacyjnych baz danych.
Drugi aspekt problemu związany jest z zaprojektowanymi przez twórców
biblioteki VCL mechanizmami integracji aplikacji z bazami danych i
potencjalnymi możliwościami wykorzystania ich funkcjonalności.
Innymi słowy chodzi o to, by nie powtarzać wykonanej już raz pracy,
a w szczególności o to, by móc uchwycić precyzyjnie miejsce w
strukturze klas biblioteki VCL pozwalające na pobranie danych
niezbędnych do odtworzenia schematu obiektowego, który wynika z
projektu budowanej aplikacji. Odtworzenie schematu obiektowego klas
realizujących zasadnicze funkcje aplikacji jest bowiem
najważniejszym elementem integracji środowiska programistycznego
ukierunkowanego na współpracę z bazami relacyjnymi, z metodyką
obiektową, taką jak np. metodyka RUP™.
Trzecim elementem rozważań podjętych przez autorów niniejszej pacy
jest techniczny aspekt realizacji wspomnianego mechanizmu
odtwarzania struktury klas, których stan wyrażony jest przez
wartości atrybutów zapisane w relacyjnej bazie danych. W warstwie
bardziej technologicznej oczywiste jest tutaj wybranie przewidzianej
przez twórców środowiska C++ Builder™ drogi wprowadzania doń
własnych rozszerzeń poprzez implementację dodatkowych komponentów. W
warstwie koncepcyjnej, należy ustalić, jakie to powinny być
komponenty i jakie funkcje powinny realizować.
Koncepcja biblioteki BMU
Przyjęta koncepcja rozwiązania problemu dotyczącego rozbieżności
pomiędzy schematami: relacyjnym i obiektowym opiera się na trzech
założeniach:
1) W kwestii odzwierciedlania relacji uogólnienia można pozostawić
projektantowi aplikacji możliwość zastosowania dowolnego podejścia:
bądź to spłaszczenia kraty dziedziczenia, bądź jej dokładnego
odwzorowania w bazie danych. Możliwe jest także zastosowanie
podejścia pośredniego.
2) Odwzorowanie typu klasy powinno nastąpić poprzez jawne
skojarzenie typu klasy z nazwą tabeli lub zbiorem krotek relacji
będących wynikiem określonej projekcji i (lub) selekcji, względnie
złączenia.
3) Problem gromadzenia instancji klas najlepiej rozwiązać poprzez
zastosowanie uniwersalnych agregatorów, tj. kolekcji klas
pozwalających na gromadzenie odnośników do abstrakcyjnej klasy
obiektu bazowego – klasy-korzenia mogącej być przodkiem wszystkich
innych klas w budowanej strukturze.
Aby najpełniej wykorzystać możliwości biblioteki VCL ułatwiające
programiście konstruowanie warstwy komunikacji z bazą danych, trzeba
skorzystać z komponentu, który w strukturze klas usytuowany jest
możliwie jak najwyżej, a jednocześnie posiada odpowiednie funkcje.
Chodzi o to, żeby zachowując pełną funkcjonalność nie uzależniać
jednocze-śnie implementacji przyszłej biblioteki od szczegółów
związanych z obsługą konkretnych standardów komunikowania się
aplikacji z bazami danych. Rolę takiego uogólnienia w bibliotece VCL
pełni abstrakcyjna klasa TDataSet. Klasa ta reprezentuje dowolny
zbiór krotek relacji i jest całkowicie niezależna od źródła, z
którego pochodzą dane. Wszystkie wyspecjalizowane klasy
reprezentujące tabele, zapytania, wyniki wykonani procedur SQL
składowanych w bazie lub zbiory rekordów rezydujące w pamięci są
potomkami tej właśnie klasy. Z tego względu to właśnie z poziomu
klasy TDataSet najlepiej pobierać wartości atrybutów podczas
odtwarzania schematu obiektowego utrwalonego w bazie danych.
Mechanizmy utrwalania i odtwarzania obiektów na podstawie danych
zapisanych w różnej postaci w plikach lub bazach danych – generalnie
chodzi o zapis na nośnikach pamięci masowej, który to zapis różni
się o zapisu w pamięci operacyjnej – są już dobrze znane. Część z
tych mechanizmów utrwalono w ogólnie przyjętych i stosowanych
szablonach projektowania i implementacji, czyli w tzw. wzorcach
projektowych (ang. design patterns). Jednym z takich mechanizmów
jest mechanizm tzw. fabryki klas (ang. class factory), który również
utrwalono we wspomnianych wzorcach projektowych. Wzorzec ten opisuje
działanie klasy posiadającej funkcje pozwalające na wywoływanie
odpowiednich konstruktorów klas w zależności od danych zapisanych w
pliku lub bazie danych. Jedną z odmian tego wzorca jest tzw.
abstrakcyjna fabryka klas (ang. abstract class factory). Klasa ta
potrafi sama odtwarzać klasy, przy czym na poziomie kodu źródłowego
klasy nie są zawarte żadne informacje na temat tego, jakie klasy
mogą być przez nią konstruowane. Innymi słowy w kodzie tym nie
wymienia się jawnie konstruktorów określonych klas. Konieczne jest
jednak wcześniejsze zarejestrowanie w klasie identyfikatora klasy, a
w językach o silnych typach, takich jak c++ w swoim standardzie,
konieczne jest skojarzenie z identyfikatorem klasy adresu funkcji,
najczęściej statycznej, która zawiera wywołanie konstruktora
określonej kasy i zwraca w wyniku adres będący wskazaniem na obiekt
abstrakcyjnej klasy-korzenia (ang. root class). Warunkiem jest
jednak to, aby klasa, którą chcemy odtworzyć była pochodną
wspomnianej klasy-korzenia. W opracowanej w ramach prac nad
artykułem bibliotece BMU zastosowano takie właśnie rozwiązanie.
Jedynym problemem, jaki pozostaje do rozwiązania jest problem
gromadzenia instancji odtwarzanych klas. Ponieważ jednak wszystkie
odtwarzane obiekty mają wspólną klasę bazową, wystarczy w
odpowiedniej strukturze zapisać referencje lub wskazania na
utworzone obiekty.
Na rys. 1 przedstawiono analityczną strukturę klas
zaimplementowanych w bibliotece BMU. Struktura ta jest oczywiście
jedynie zarysem dalszego projektu i implementacji, pozwala jednak na
zobrazowanie przebiegu procesu odtwarzania instancji klasy. Proces
ten zobrazowano dokładniej na rys. 2. w postaci diagramu przebiegu.
Warto w tym momencie zauważyć, że jedyna znaczeniowa zależność
pomiędzy klasami bibliotek VCL i przedstawionych na diagramie klas
biblioteki BMU dotyczy wyłącznie klasy TDataSet, co pozwala na
całkowite uniezależnienie działania biblioteki od szczegółów
implementacyjnych związanych z konkretnym standardem komunikowania
się aplikacji z bazą danych.
Rysunek 1. Analityczna struktura klas biblioteki BMU.
Rysunek 2. Diagram przebiegu interakcji związanej z odtwarzaniem i kasowaniem obiektu.

Projekt i implementacja
Zasadniczą część modelu projektowego (rys. 3) biblioteki BMU stanowi pięć klas. Trzy z nich odpowiadają dokładnie klasom modelu analitycznego, a więc klasom Root Class, Abstract Class Factory oraz klasie Container. Są to klasy abstrakcyjne, którymi są odpowiednio: TBMUBusiness Object, TBMUClassFactory i TBMUObjectHandler. Dwie pozostałe, tj. TBMUSingleObjectHandler i TBMUMultipleObjectHandler precyzują określony sposób odtwarzania schematu. Pierwsza klasa, którą nazwać można zarządcą pojedynczej instancji, odtwarza w pamięci operacyjnej tylko jedna instancję klasy, zawsze tą, która związana jest bieżącym rekordem zbioru danych. Rekord bieżący to ten, na którym ustawiony jest wskaźnik pozycji. Wartości pól tegoż rekordu zapisywane są już na poziomie biblioteki VCL w odpowiedniej strukturze (właściwość Fields) klasy TDataSet, co ułatwia znacznie ich odczytywanie i zapisywanie. Druga z wymienionych, tzn. TBMUMultipleObjectHandler, pozwala na zarządzanie wieloma instancjami. Dlatego też nazwano ją zarządcą wielu instancji. Klasa ta tworzy instancje dla wszystkich rekordów znajdujących się w zbiorze danych po uwzględnieniu ustawień filtrowania.
Rysunek 3. Diagram klas biblioteki BMU - model projektowy.

Istotną cecha zaprojektowanej biblioteki jest możliwość odtwarzania struktur
obiektów na podstawie struktur powiązań pomiędzy zbiorami danych. Dotyczy to
zbiorów reprezentujących powiązane ze sobą tabele bazy danych. Jeśli tak
zadecyduje projektant aplikacji, zarządca instancji może sam podążać śladem
powiązań typu Master-Detail pomiędzy zbiorami danych i odtwarzać kolejne
elementy schematu zapisanego bazie danych (właściwości AutoFindDetails i
BuildWithParts ustawione na wartość true). Możliwe jest także jawne wskazanie
zbiorów, które chcemy w danym momencie odtworzyć w budowanym schemacie
obiektowym podając nazwy zarządców dla tych zbiorów danych, które tworzą
określoną strukturę (właściwość BoundHandlers). Dzięki temu mechanizmowi możliwe
stało się odtwarzanie schematu obiektowego dla bardziej złożonych sytuacji, np.
dla formularzy edycyjnych operujących na kilku tabelach bazy danych.
Jak już wspomniano podczas implementacji biblioteki posłużono się standardowymi
mechanizmami rozszerzania środowisk IDE firmy Borland. Ich istota polega na
umożliwieniu użytkownikowi środowiska, implementacji własnych wyspecjalizowanych
komponentów. Implementacja własnych komponentów jest stosunkowo prosta i
sprowadza się do utworzenia odrębnego projektu tzw. pakietu (ang. Package).
Pakiet zawiera zazwyczaj kod źródłowy kilku komponentów składających się na
określoną bibliotekę. Po wykonaniu kompilacji pakietu i jego zainstalowaniu,
użytkownik środowiska może korzystać z nowych komponentów na takich samych
zasadach, na jakich korzysta z komponentów dostarczonych wraz ze środowiskiem.
Interfejs biblioteki BMU stanowią trzy komponenty, które reprezentują fabrykę
klas oraz omówionych wcześniej zarządców instancji. Widok palety komponentów
biblioteki BMU w obecnej wersji (wersja 2.0) przedstawiono na rys. 4.
Rysunek 4. Paleta komponentów biblioteki BMU.
Podsumowanie
Ponowne spotkanie się obu zasadniczych nurtów metodologicznych, jakie
wyłoniły się na przestrzeni ostatnich kilku dekad rozwoju inżynierii
oprogramowania, tzn. historycznie wcześniej rozpoczętego nurtu strukturalnego i
późniejszego, obiektowego jest niewątpliwie zjawiskiem ciekawym. Nie spodziewali
się tego z pewnością stojący w opozycji do zasad modelowania strukturalnego
pomysłodawcy metod obiektowych. Zaistniała sytuacja ma jednak swoje głębokie
przesłanki praktyczne. Wynika ona bowiem z faktu utrwalenia się tych elementów
obu podejść, które zyskały, ze względu na swoją przydatność, szerokie praktyczne
zastosowanie. W przypadku modelu strukturalnego utrwalił się przyjęty relacyjny
model danych oraz oprogramowanie systemów zarządzania bazami danych, które
realizuje jego postulaty. Sama metodyka projektowania, być może poza jej
elementami odnoszącymi się do formułowania wymagań, nie przyjęła się. Została
ona wyparta przez podejście obiektowe, szczególnie takie, w którym bazuje się na
zastosowaniu notacji języka UML. Metodyka obiektowa pozwoliła na przeniesienie
do struktur programów komputerowych elementów rzeczywistego świata i znacznie
ułatwiła analitykom i projektantom dekompozycję bardziej złożonych zagadnień.
Jej słabym elementem były jednak mechanizmy składowania danych, a w
szczególności niemożność ugruntowania się i upowszechnienia określonych
standardów dla tzw. obiektowych baz danych. Stąd wyniknęła konieczność ponownego
odwołania się do mechanizmów składowania danych przyjętych w koncepcji
strukturalnej.
Opracowane przez autorów artykułu rozwiązanie problemu integracji modelu
obiektowego z środowiskiem programistycznym pracującym z bazami relacyjnymi jest
z pewnością sporym uproszczeniem zarysowanego w artykule problemu. W porównaniu
z innymi rozwiązaniami, szczególnie tworzonymi komercyjnie, jego funkcjonalność
jest pewnością ograniczona. Jak jednak wynika z praktycznych testów,
zastosowanie biblioteki BMU pozwala na tworzenie znacznie bardziej czytelnych i
poprawnych metodycznie aplikacji obiektowych i ułatwia pracę projektanta.
Ponadto zastosowanie biblioteki wymusza na projektancie wcześniejsze zrozumienie
dziedziny problemowej programu, co wpływa bardzo pozytywnie na jakość
powstającej aplikacji.
Nakreślając plan dalszych prac nad rozwiązaniem opisanym w artykule należy
uwzględnić fakt, że firma Borland wprowadziła do najnowszej wersji swojego
środowiska IDE, a mianowicie w ukazującym się na rynku w momencie powstawania
tego artykułu Borland Developer Studio 2006, rozwiązanie Borland ECO będące
komercyjnym rozwiązaniem dla problemu integracji obiektowo-relacyjnej. Należy
jednak podkreślić, że pełna wersja platformy ECO dostępna jest jedynie w wersji
Enterprise środowiska, która jest wersją najdroższą. Co z pewnością uniemożliwi
jej wykorzystanie w mniejszych firmach oraz dla celów edukacyjnych. Tak więc
prace nad zagadnieniem będą kontynuowane. Te najbliższe dotyczyć będą sprzężenia
podążającego w odwrotnym kierunku, tzn. konstruowania schematu relacyjnego na
podstawie struktur tworzonych przez obiekty.