OBIEKTOWA MAPA KODU W ŚRODOWISKU MS ACCESS Maciej Puchalski Wprowadzenie Jednym z prostszych i najpowszechniejszych narzędzi pozwalających na szybkie tworzenie oprogramowania dostosowanego do indywidualnych potrzeb jest MS Access. Zaletą tego środowiska jest moŝliwość łatwego i szybkiego tworzenia aplikacji i baz danych, co jest waŝne w przypadku dynamicznie zmieniających się potrzeb informacyjnych firmy. Niestety wiąŝe się to często z zaniedbywaniem dobrych praktyk programistycznych w trakcie tworzenia systemu, jeśli nadrzędnym celem jest najkrótszy czas wytworzenia oprogramowania. Powoduje to duŝe problemy w późniejszych fazach eksploatacji programu, gdy aplikacja musi być utrzymywana (modyfikowana, dostosowywana do nowych potrzeb) 1. W takich przypadkach kaŝde narzędzie wspierające programistów w rozwikłaniu niezrozumiałych lub skomplikowanych elementów kodu będzie niezwykle pomocne. Model mapy kodu Accessa MS Access to program o szerokiej funkcjonalności, umoŝliwiający jednocześnie tworzenie baz danych i obsługujących je aplikacji. Czasami moŝe powstać wątpliwość, czy plik taki określić jako bazę MS Access, czy aplikację MS Access, dlatego przyjmijmy, Ŝe będziemy je nazywać systemami pod MS Access 2, niezaleŝnie od tego czy zawierać będą dane, aplikację, czy dowolną kombinację wymienionych. 1 Szczególnie gdy inne osoby odpowiedzialne są za utrzymanie aplikacji, a inne były zaangaŝowane w jej wytworzenie. Definicja i proces utrzymania oprogramowania zob. [ChKo2000]. 2 Dla odróŝnienie od systemu MS Access, czyli samego programu do tworzenia (i jednocześnie środowiska do uruchamiania) systemów pod MS Access. 529
ROZDZIAŁ V Systemy pod MS Access składają się z róŝnorodnych obiektów 3, takich jak: Tabela, Kwerenda, Formularz, Raport, Makro, Moduł. Obiekty te moŝna przeglądać w głównym oknie systemu (nazywanym Oknem bazy danych ), stąd moŝna je uruchamiać lub otwierać do projektowania. W MS Access (w wersji 2003) znalazła się teŝ funkcja badania zaleŝności między obiektami głównymi Accessa. Dzięki niej moŝna sprawdzić, które inne obiekty główne wykorzystują dany obiekt, jak równieŝ, których obiektów głównych dany obiekt uŝywa. Funkcja ta jednak ma znaczące ograniczenia, gdyŝ umoŝliwia tylko sprawdzenie zaleŝności na poziomie obiektów głównych (zresztą nie wszystkich typów) [MSDN2003]. MoŜna zbudować narzędzie pozwalające na sprawdzanie bardziej złoŝonych zaleŝności między obiektami na podstawie obiektowej mapy kodu. Obiektową mapę kodu zdefiniujemy 4 jako reprezentację kodu źródłowego oprogramowania za pomocą obiektów, gdzie kaŝdy z obiektów reprezentuje pewien fragment kodu, a powiązania między obiektami odzwierciedlają zaleŝności występujące w kodzie. W zaleŝności od rodzaju kodu poddawanego mapowaniu naleŝy określić, jakie obiekty mapy będą uŝywane, co będą reprezentować, jakie będą ich właściwości i w jaki sposób będą powiązane z innymi obiektami mapy. Na przykład, obiektowa mapa kodu dla języka Pascal zdefiniowana w [Puch2000] jako obiekty mapy traktowała m.in. deklarację zmiennej, deklarację procedury, instrukcję wykonywalną (wywołanie procedury, instrukcję przypisania, instrukcję warunkową, itp.). MoŜemy wyróŝnić ogólną mapę kodu, która odwzorowuje tylko część najwaŝniejszych elementów kodu (np. deklaracje procedur, deklaracje zmiennych globalnych) oraz szczegółową mapę kodu, która przedstawia pełną reprezentację kodu źródłowego (w tym np. poszczególne instrukcje wewnątrz procedur). Ograniczymy się do zdefiniowania mapy kodu dla systemów pod MS Access na poziomie ogólnym. Będzie to pozwalało na badanie zaleŝności w kodzie między głównymi obiektami Accessa i ich składnikami, nie będzie zaś moŝliwe badanie zaleŝności w wewnętrznej strukturze kodu podprogramów (sub, function), czyli poszczególnych instrukcji wykonywalnych. Badanie tych drugich zaleŝności jest jednak prostsze, gdyŝ na tym poziomie wszystkie elementy kodu zawarte są w jednym fragmencie tekstu. Śledzenie zaleŝności między elementami kodu takimi jak formularze lub kwerendy wymaga równoczesnego przeglądania wielu rodzajów kodu (róŝnego typu obiektów), dlatego w tym wypadku mapa kodu moŝe być bardziej przydatna. 3 Dokumentacja [MSDN2003] nazywa te obiekty AccessObject, dla odróŝnienia od innych obiektów występujących w środowisku MS Access przyjmijmy nazwę: główne obiekty Access. 4 Na podstawie [Puch2000], gdzie zdefiniowano obiektową mapę kodu dla języka TUR- BO Pascal. 530
REALIZACJA SYSTEMÓW WSPOMAGANIA ORGANIZACJI I ROZWIĄZANIA... Na mapie kodu dla systemu pod MS Access powinny znaleźć się przede wszystkim elementy kodu, które: 1. mogą być wywoływane z innych elementów kodu 2. mogą zawierać elementy określone w punkcie 1 (być dla nich obiektem nadrzędnym; potrzebne są by mapa była kompletna) 3. mogą zawierać odwołania do innych elementów kodu Mapa kodu będzie zatem zawierać obiekty typu (w nawiasie podano kod uŝywany dalej do oznaczenia typu): Tabela (w tym tabele przyłączone, np. przez ODBC; kod: TABLE) Pole w tabeli (kod: TFIELD) Kwerenda (kod: QUERY) Pole kwerendy (kod: QFIELD) Formularz (kod: FORM) Kontrolka formularza (ang. Control, np. etykieta, przycisk; kod: FCTRL) Moduł formularza lub raportu (kod: FMODULE, RMODULE) Raport (kod: REPORT) Kontrolka raportu (np. pole tekstowe, etykieta; kod: RCTRL) Makro (kod: MACRO) Moduł klasy (kod: CLASS) Właściwość klasy (typu GET, LET lub SET; kod odpowiednio: PROPGET, PROPLET, PROPSET) Moduł standardowy (kod: MODULE) Stała zadeklarowana na poziomie modułu (słowo kl. CONST, kod: CONST) Zmienna zadeklarowana na poziomie modułu (słowo kl. DIM; kod: VAR) Typ zadeklarowany na poziomie modułu (słowo kl. TYPE; kod: TYPE) Pole składowe typu (kod: TYPE_FIELD) Typ wyliczeniowy (ang. Enumeration, słowo kl. ENUM; kod: ENUM) Procedura (słowo kluczowe SUB; kod: SUB) Funkcja (słowo kluczowe FUNCTION; kod: FUNC) Zdarzenie (słowo kluczowe EVENT; kod: EVENT) Procedura/funkcja biblioteczna (przyłączana z biblioteki DLL, słowo kl. DECLARE SUB/DECLARE FUNCTION; kod: DLLPROC, DLLFUNC) Nazwa zdefiniowana przez uŝytkownika 5 (kod: USR_DEF_ID) 5 Nazwa zdefiniowana do wyszukania przez uŝytkownika; nie oznacza obiektu występującego w kodzie wg Ŝadnego z wymienionych na liście typów, ale dla której uŝytkownik chce znaleźć elementy kodu jej uŝywające, np. nazwa profilu ODBC poprzez który przyłączone są tabele, słowo ERROR (by wyszukane zostały punkty obsługi błędów instrukcje ON ERROR...), itp. 531
ROZDZIAŁ V Obiekty wytypowane do umieszczenia na mapie kodu to wszystkie obiekty główne Accessa oraz obiekty do nich naleŝące, np. Formularz i Kontrolka formularza. Dlatego do przedstawienia mapy kodu przydatna będzie hierarchiczna struktura drzewiasta. MoŜna ją uzyskać poprzez zastosowanie identyfikatorów obiektów oraz identyfikatorów wskazujących obiekt nadrzędny. Obiekt mapy kodu powinien teŝ posiadać atrybuty odzwierciedlające podstawowe cechy kodu, który reprezentują, czyli np. nazwę elementu, typ elementu kodu, linię deklaracji, zasięg, itp. Dodatkowo moŝna dołączyć atrybuty pomocnicze dla procesu wyszukiwania zaleŝności, czyli np. znaczniki przeszukiwania, czy identyfikator unikatowej nazwy obiektu (znaczenie tego drugiego zostanie dokładniej wyjaśnione przy opisie sposobu tworzenia referencji między obiektami). Zdefiniujmy obiekt mapy jako klasę z następującymi właściwościami: ID (identyfikator liczbowy obiektu mapy, kolejny numer) Name (nazwa obiektu mapy, czyli np. nazwa deklarowanej zmiennej, nazwa deklarowanej procedury, nazwa formularza) ObjType (typ obiektu mapy, wg typów zdefiniowanych wyŝej, np. FORM, FCTRL, CLASS, SUB) ParentObjID (identyfikator liczbowy nadrzędnego obiektu mapy, np. dla kontrolki na formularzu identyfikator obiektu mapy zawierającego ją formularza) Description (dodatkowy opis obiektu mapy) StartLine (pierwsza linia kodu dla obiektów kodu zawartych w module) DataType (typ danych obiektu kodu, np. typ danych deklarowanej zmiennej lub typ danych zwracanych przez funkcję) Modifiers (modyfikatory w deklaracji, np. STATIC, WITH EVENTS, etc.) Range (zasięg deklaracji obiektu: PRIVATE, FRIEND, PUBLIC) Search_in (znacznik poszukiwania referencji w obiekcie, jeśli ustawiony na Tak, w obiekcie będą poszukiwane odwołania do innych obiektów mapy) Search_for (znacznik poszukiwania referencji obiektu, jeśli ustawiony na Tak, będą poszukiwane odwołania do obiektu w innych obiektach mapy) ID_Uname (identyfikator nazwy obiektu w słowniku unikatowych nazw) Na podstawie powyŝszej definicji moŝna utworzyć listę obiektów kodu Accessa, zawierającą wszystkie obiekty wskazanych wcześniej typów. Pozwala to na badanie przynaleŝności jednych obiektów do innych (nadrzędny podrzędny). Bardziej skomplikowane, a zarazem bardziej warte zbadania, są zaleŝności odwołań, czyli pokazanie jak obiekty wykorzystują kod innych obiektów. Wywołanie kodu zwykle wiąŝe się z odwołaniem do innego obiektu poprzez nazwę. Nazwy moŝna odnaleźć za pomocą stosunkowo prostego wyszukiwania tekstowego (poszukiwanie nazw obiektów wywoływanych w tekstowych właściwościach lub tekstowym kodzie obiektów wywołujących). Problem w tym, Ŝe 532
REALIZACJA SYSTEMÓW WSPOMAGANIA ORGANIZACJI I ROZWIĄZANIA... nazwy obiektów kodu nie są unikatowe w ramach całości kodu, np. moŝe istnieć formularz o nazwie takie samej jak tabela, czy raport. JeŜeli jednak utworzymy listę unikatowych nazw i kaŝdej przypiszemy identyfikator, a następnie ten identyfikator wpiszemy do obiektu kodu (do właściwości ID_Uname), to będziemy mogli wyszukać wywołania tych nazw, a w sposób pośredni obiektów, którym te nazwy odpowiadają (później trzeba ręcznie wskazać na mapie właściwy obiekt spośród wszystkich obiektów o takiej nazwie). ZaleŜności wzajemnego wykorzystania kodu między obiektami mapy moŝna oddać za pomocą obiektów referencji zdefiniowanych jako klasa o następujących właściwościach: ID (identyfikator referencji) AObjID (identyfikator obiektu mapy, z którego wychodzi zaleŝność, czyli tego, który uŝywa kodu innego obiektu mapy) UNameID (identyfikator unikatowej nazwy, która jest wywoływana) RefID (identyfikator obiektu mapy, którego kod jest wywoływany automatycznie wypełniany, jeŝeli tylko jeden obiekt uŝywa nazwy UNameID) PosLine pozycja (linia), gdzie znaleziono nazwę innego obiektu kodu PosCol pozycja (kolumna), gdzie znaleziono nazwę innego obiektu kodu RefDescr pomocniczy opis znalezionego odwołania, np. nazwa właściwości obiektu, w której wystąpiło odwołanie InheritedRef flaga, czy badana właściwość, z której nastąpiło wywołanie, jest dziedziczona (aby oznaczyć przypadki, gdy Access zwraca wartości właściwości obiektu nadrzędnego, które zostały juŝ osobno przeszukane) FalseRef flaga wskazująca, czy znaleziona nazwa jest przypadkowym wystąpieniem tekstu, a nie odwołaniem do nazwy obiektu Aby zbudować mapę kodu potrzebny jest jeszcze system, który przeanalizuje zadany kod, utworzy obiekty mapy i obiekty referencji wg powyŝszych specyfikacji. Model takiego systemu opisany został poniŝej. Model systemu mapującego System mapujący powinien realizować następujące funkcje: Interfejs sterowania, np. wybór pliku z kodem do utworzenia mapy Przechowywanie danych obiektowej mapy kodu Ustawianie parametrów mapowania Przeszukiwanie kodu i mapowanie obiektów kodu Przeszukiwanie kodu i mapowanie referencji Interfejs sterowania programem powinien pozwalać na wywoływanie jego pozostałych funkcji i moŝe być wykonany w dowolny sposób. 533
ROZDZIAŁ V Dane obiektów mapy mogą być przechowywane w tabelach bazy danych, gdzie kolumny będę odpowiadały właściwościom obiektu, a kolejne rekordy będą reprezentować poszczególne obiekty mapy. Potrzebne będą tabele dla obiektów kodu, unikatowych nazw oraz obiektów referencji. Ustawianie parametrów mapowania pozwoli na określenie stopnia szczegółowości, z jaką mają być zbierane dane do mapy kodu (np. czy mapować tylko publiczne, czy teŝ prywatne metody obiektów) oraz zdefiniowanie nazw uŝytkownika (obiektów kodu typu USER_DEF_ID). Proces tworzenia mapy złoŝony będzie z dwóch głównych oddzielnych funkcji, a przebiegał będzie następująco. Po uruchomieniu systemu mapującego naleŝy wskazać plik, którego kod poddany będzie mapowaniu, ustawić parametry i uruchomić pierwszą fazę mapowania tworzenie listy obiektów kodu. W tej fazie otwierany jest kolejno kaŝdy obiekt główny Accessa, sprawdzane są jego składniki, wyszukiwane elementy do umieszczenia na mapie kodu, np. odczytywane są kolekcje kontrolek na formularzu lub raporcie, analizowany jest kod modułów. Znalezione obiekty kodu zapisywane są do tabeli bazy danych. Po przetworzeniu wszystkich obiektów głównych Accessa tworzony jest słownik nazw unikatowych. Przed przystąpieniem do drugiej fazy moŝna przejrzeć odnalezione obiekty kodu i ustawić dla nich indywidualne parametry mapowania (np. search_in, search_for). W drugiej fazie mapowania nastąpi tworzenie obiektów referencji. Ponownie otwarte zostaną kolejno wszystkie obiekty główne Accessa oraz ich składniki, które na mapie kodu oznaczone zostały flagą Search_in. Dla kaŝdego z tych obiektów i składników przeszukiwane są wszystkie ich tekstowe właściwości, a w kaŝdej z nich poszukiwane jest kaŝde słowo ze słownika nazw unikatowych (o ile przynajmniej jeden obiekt kodu o takiej nazwie jest oznaczony flagą Search_for). W przypadku znalezienia słowa z tego słownika zapisywany jest fakt wystąpienia w analizowanym obiekcie odwołania do unikatowej nazwy (a jeŝeli jest to nazwa uŝywana przez jeden tylko obiekt, to równieŝ identyfikator wywoływanego obiektu). Oznaczana jest równieŝ pozycja, na której znaleziono odwołanie do nazwy (szczególnie waŝne w przypadku przeszukiwania modułów), nazwa właściwości, w której występuje referencja (RefDescr) oraz flaga dziedziczenia (InheritedRef, jeŝeli przeszukiwana właściwość dziedziczy wartość z obiektu nadrzędnego). Moduły są przeszukiwane linia po linii na tej samej zasadzie co właściwości tekstowe innych obiektów. Po zakończeniu drugiej fazy moŝna przejrzeć listę referencji i sprawdzić ich poprawność. Mogą zaistnieć przypadki, Ŝe nazwa w kodzie wystąpiła w innym kontekście, ale znajdowała się w słowniku nazw unikatowych i została wykryta jako referencja, np. jeśli istniał formularz o nazwie DOKUMENT, a w pewnym module zawarty był kod: MsgBox Czy chcesz zapisać ten dokument?. MoŜna ją wtedy oznaczyć flagą FalseRef, by nie była brana pod uwagę w dalszych analizach. 534
REALIZACJA SYSTEMÓW WSPOMAGANIA ORGANIZACJI I ROZWIĄZANIA... MoŜliwości i zastosowania obiektowej mapy kodu Łącząc dane z tabeli obiektów kodu i tabeli referencji moŝemy otrzymać następujące informacje o referencjach w kodzie: ACC_ OBJ.O bjtype Informacja o zaleŝnościach w kodzie wg obiektowej mapy kodu 6 ACC_OBJ.Na Uname Ref- Ref Ref- RefTypeme Desc Co Type Parent TABLE DOKUMENTY fosuser- Name r unt Filter 1 TABLE DOKUMENTY KTOXXX Filter 2 Tabela nr 1 RefNameParent FUNC MODULE KtoZalogowany Obydwa wiersze tabeli informują o występowaniu referencji w kodzie obiektu DOKUMENTY (typu TABLE), we właściwości Filter. Pierwsza referencja jest odwołaniem do obiektu fosusername (funkcja z modułu o nazwie KtoZalogowany), a druga odwołuje się do nazwy KTOXXX, która jest uŝywana przez dwa obiekty, dlatego nie przypisano automatycznie konkretnego obiektu. W rzeczywistości właściwość Filter tabeli Dokumenty wygląda następująco: KTOXXX = fosusername(), gdzie KTOXXX jest polem w tabeli Dokumenty (ale teŝ pole KTOXXX występuje w pewnej kwerendzie), moŝemy więc ręcznie ustawić referencję na obiekt KTOXXX, naleŝący do tabeli Dokumenty. Na podstawie powyŝszej informacji moŝemy dokonać analizy wpływu zmian w kodzie na pozostałe elementy kodu, np. jeŝeli musimy zmienić nazwę pola KTOXXX na KTO_KSIEGOWAL, to trzeba będzie równieŝ zmodyfikować właściwość Filter w tabeli DOKUMENTY. Podobnie, jeŝeli wymagane są zmiany w funkcji fosusername, to trzeba będzie sprawdzić, jaki wpływ będzie to miało na działanie filtru w tabeli DOKUMENTY. Obiektową mapę kodu moŝemy teŝ zastosować do innych zadań, w szczególności dzięki mapie kodu moŝna: dokonać analizy wpływu zmian kodu na inne obiekty kodu zidentyfikować potencjalne konflikty nazw zidentyfikować obiekty nieuŝywane (brak referencji) i najczęściej wywoływane (nie najczęściej wykonywane, bo moŝe być jedna referencja zawarta w wielokrotnie powtarzanej pętli) 6 Przykładowy fragment wybrany z mapy kodu utworzonej na bazie rzeczywistego systemu pod MS Access. 535
ROZDZIAŁ V Zakończenie Obiektowa mapa kodu dla systemów pod MS Access okazała się przydatna w procesie utrzymania (modyfikacji) oprogramowania. MoŜna prowadzić dalsze badania nad jej szerszym zastosowaniem oraz zwiększeniem dokładności mapowania, w tym nad stworzeniem modelu szczegółowej obiektowej mapy kodu. Literatura [Boratyn97] Boratyn D.: Access 97. System oblicze ku aplikacjom, Croma, 1997. [ChKo2002] Chodoła T., Kobyliński A.: Utrzymalność oprogramowania, w Systemy Wspomagania Organizacji SWO 2002, Wydawnictwo AE w Katowicach, 2002. [MSDN2003] http://msdn.microsoft.com/library/default.asp?url=/library/enus/vbaac11/html/acobjdependencyinfo_hv01030882.asp, Microsoft, 2003. [Puch2000] Puchalski M.: Narzędzia wspomagające kodowanie. Obiektowa mapa kodu., praca magisterska obroniona w SGH, 2000. 536