Powrót

Pora wrócić do pisania pracy magisterskiej.

Na jakim etapie jestem?

Wykonałem testy. Każdy test generuje dużą ilość obrazów. Zajmują one w sumie 140 GB.
Niektóre obrazy wykorzystałem do stworzenia gifów, które przedstawiają etap budowania harmonogramu. Trochę zajęło mi usprawnienie procesu tworzenia gifów: zdjęcia są ciężkie, programy do tworzenia gifów nie są często darmowe, a te darmowe tworzą gifa bardzo długo. Rozwiązanie okazało się bardzo proste. Nie tworzę plików z rozszerzeniem .gif. Używam do pisania pracy systemu LaTex. Umożliwia on zagnieżdżanie w pdfie właśnie gifów. Prawie zero pracy – kod generujący gifa jest bardzo podobny do tego, który wstawia zdjęcie.

Co zostało do zrobienia? Napisać tekst. Dużo tekstu. Wybrać odpowiednie zdjęcia, wykresy, tabele. A zatem, do dzieła!

Nazywaj zmienne mądrze

Zapewne nieraz słyszałeś lub czytałeś, aby pisać czysty i samokomentujący się kod. Jak mantrę słyszysz: używaj znaczących nazw dla zmiennych, nazywaj zmienne mądrze, nie używaj słów: foo, bar, a jednoliterowe nazwy zmiennych zachowaj tylko dla indeksów w trywialnych pętlach. Wydaje mi się, że programista piszący kod, który dzisiaj poprawiałem, zapomniał o jednym: nazwy nie mogą kłamać!

W wyżej wspomnianym programie mam grupę elementów, która ma jeden nagłówek. Użytkownik wykonuje na nich różne operacje. Jest pewna operacja, która jeśli jest wykonana na elemencie grupy niebędącym nagłówkiem, to zostanie ona również wykonana na nagłówku tej grupy.

Wszystkie elementy z grupy wyświetlane są użytkownikowi w tabeli. W zależności od kryteriów, w tabeli mogą znajdować się elementy z wielu grup, ale również może być tak, że nie wyświetlone są wszystkie elementy z konkretnej grupy.

Wejdźmy głębiej w szczegóły naszej operacji:

  1. Wykonaj operację X na elemencie grupy
  2. Jeśli element nie jest nagłówkiem, to zacznij próbę wykonania operacji X dla nagłówka, w tym celu:
    1. Znajdź nagłówek
    2. Jeśli znalazłeś nagłówek wykonaj operację X
  3. Koniec algorytmu

Wszystko ładnie i pięknie, ale… w punkcie 3 nie znajduje nagłówka. Dlaczego? Program nie szuka nagłówka w bazie danych, ale w naszej tabeli, która np. (przez odpowiednie kryteria) wyświetla tylko jeden wiersz, który właśnie przerobiliśmy w punkcie pierwszym.

Cóż, bug jak bug, trzeba poprawić. Szybko dopisuję więc kilka linii: jak nie znajdujesz w tabeli nagłówka, to poszukaj go w bazie danych i jak go masz, to wykonaj na niej zadaną operację. Biorę klasą odpowiedzialną za pobieranie danych. Jest nawet zaimplementowana funkcja, która zwróci mi tabelę zawierającą elementy grupy i jako parametr przyjmuje id takiego elementu (nagłówek też jest elementem grupy).

F5 i zaczynamy testować. Nic się niestety nie zmieniło. Nagłówek nie został przetworzony…. Aplikacja stop, breakpoint i F6. Jestem. Mam id nagłówka, uruchamiam funkcję pobrania z bazy danych i… dostaję nulla. Jakim cudem? Nie może być!

Wchodzę w ciało funkcji. W skrócie funkcja ta jest adapterem i wywołuje kolejną funkcję. Wchodzę w nią i… ta funkcja nie przyjmuje już jako parametru id elementu, ale całej grupy….

Programisto, nazywaj zmienne mądrze, nazywaj zmiennie poprawnie i nie oszukuj :) (a jak refaktoryzujesz, to rób to z głową, nie tylko testy muszą świecić się na zielono)

Aktualna baza danych

Baza danych została zaktualizowana. Zmieniłem nazwy tabel i kolumn, dodałem relacje, usunąłem niepotrzebne kolumny. Zostawiłem stare nazwy, nowe wyglądają następująco: stara_nazwa_nowa_nazwa. Tabele służące tworzeniu relacji wiele do wielu nazwałem zgodnie z formatem: tabela1_AND_tabela2.

Poniższy diagram przedstawia nową strukturę bazy danych.

database

Bazę danych tworzy 15 tabel:

  1. ElectricityBorders – tabela przedstawia limit prądu, zaplanowane zużycie oraz różnice między tymi wartościami na dany dzień oraz czas.
  2. Equipments – tabela zawiera informację o przynależności konkretnego gniazdka. W pierwotnej wersji zawierało informację o wyposażeniu sali (np. komputer, rzutnik). Obecnie zawiera informację o tym, do którego budynku należy gniazdko poprzez symbol budynku.
  3. Group_Plugs – tabela zawiera informacje o wtyczkach urządzeń. W pierwotnej wersji studenci należeli do konkretnych grup dydaktycznych. Obecnie urządzenia przynależą do konkretnych wtyczek. Założono, że jedno urządzenie ma tylko jedną własną wtyczkę.
  4. Plan – tabela przedstawia plan używania wtyczek urządzeń z użyciem konkretnego gniazdka w konkretnym dniu i czasie.
  5. Properties – tabela przechowuje informacje o parametrach systemu, jak np. ilość dni, liczbę okresów, na którą podzielona jest doba.
  6. RejectGroup_Plugs – tabela zawiera wtyczki (pierwotnie grupy), które zostały odrzucone w fazie planowania.
  7. Room_Socket_And_Equipment – tabela wiele do wielu łącząca gniazdka (pierwotnie sale) z ich przynależnością do budynku (wyposażeniem).
  8. Room_Sockets – tabela przedstawia dane o gniazdkach (pierwotnie sale).
  9. Student_User_And_Group_Plug – tabela wiele do wielu między właścicielami budynków a wtyczkami (pierwotnie relacja przynależności studentów do grup).
  10. Student_Users – tabela przedstawia dane o właścicielach wtyczek, a przez relację jeden do jednego z urządzeniami, są to właściciele tychże urządzeń (pierwotnie byli to studenci należący do konkretnych grup. Mogło być wielu studentów w jednej grupie, teraz wtyczka ma tylko jednego właściciela).
  11. Subject_Building_And_Equipment – tabela z relacją wiele do wielu między symbolem budynku a budynkiem (pierwotnie każdy przedmiot miał wymagania, np. Podstawy programowania – laboratorium wymagało komputerów w sali).
  12. Subject_Buildings – tabela przechowujące informacje o budynkach (pierwotnie przedmiotach).
  13. Subject_BuildingTypes – tabela z typami budynków, np. administracja, dom, (pierwotnie typy przedmiotów, np. wykład, ćwiczenia).
  14. Teacher_Device_And_Group_Plug – tabela przechowująca relację między urządzeniem a wtyczką (pierwotnie zawierała informację o grupach, które prowadził konkretny nauczyciel).
  15. Teacher_Devices – tabela z informacjami o urządzeniach (pierwotnie o nauczycielach). Znajdują się tu m.in. informacje o predyspozycjach uruchomienia (np. drugiego dnia). Pierwotnie był tu dane o wykładowcach.

Generowanie diagramów struktury bazy danych

W poprzednim poście zamieściłem diagramy bazy danych. Pierwszy uzyskałem od osoby, od której dostałem rozwiązanie i bazę danych. Znajdował się tam diagram bazy danych stworzony w programie DIA. W ramach moich prac dodałem kilka pól do bazy danych. W celu przedstawienia tych zmian poprawiłem również otrzymany diagram. Wszystko to znajduje się w dwóch poprzednich postach.

Pewnego dnia przysiadłem nad drastycznymi zmianami w bazie danych, tzn. zmiana nazw, usunięcie niepotrzebnych pól, etc. Od programisty, który stworzył ten system, otrzymałem również SQLa generującego bazę danych. Wszystkie poprawki jej dotyczącej sprowadzały się tak naprawdę do edycji jednego pliku SQLowego, co bardzo ułatwiało prace (oczywiście równolegle wykonywałem zmiany w reszcie projektu, tzn. w plikach Javowych).

Wykonałem sporo zmian w bazie i chciałem narysować nowy diagram. Tych zmian było jednak tak wiele, że po chwili zrezygnowałem z pomysłu poprawiania diagramu programem DIA. Skoro mam już działającą bazę danych, pomyślałem, to wykorzystam narzędzie, które wygeneruje mi diagram przedstawiający jej strukturę. I tu zaczęły się małe schody:

  1. Znalazłem w internecie informację, że MS Visio wspiera database reverse engineering, tzn. z istniejącej bazy danych mogę wygenerować diagram przedstawiający jej strukturę.
  2. Ściągnąłem więc Visio i chciałem go zainstalować. Po małych kłopotach (za mało pamięci, trzeba usunąć niepotrzebne rzeczy) udało mi się to.
  3. Niestety, Visio w wersji 2016 nie wspiera już tego procesu. Szukamy więc narzędzia do baz MySQLowych, które zrobi diagram za mnie. Na moje szczęście MySQL Workbench ma to wbudowane. A właśnie tego narzędzia używam do zarządzania bazą.
  4.  Baza, z której korzystam, jest bazą relacyjną. Niestety, plik sqlowy nie przedstawiał tego (prócz używania tych samych nazw dla kluczy w różnych tabelach). Miałem więc dwa wyjścia: dorysować na diagramie połączenia lub napisać kilka linii w sqlu. Oczywiście wybrałem to drugie rozwiązanie. Plik sqlowy na początku miał usuwanie wszystkich tabel. Musiałem więc zadbać o odpowiednią kolejność ich usuwania, właśnie ze względu na dodane relacje.
  5. Po chwili miałem diagram przedstawiający strukturę nowej bazy danych. Przedstawię ją w następnym poście.

Podsumowując:

  • MS Visio 2016 nie wspiera tworzenia diagramów bazy danych na podstawie istniejącej bazy,
  • MySQL Workbench wspiera ten proces,
  • lepiej zrobić jest w bazie danych jawne relacje niż za każdym razem dorysowywać połączenia lub przeszukiwać wszystkie tabele w poszukiwaniu zależności.

Baza danych

W ramach zaadaptowania algorytmu układającego plan zajęć na uczelni do problemu harmonogramu urządzeń została trochę zmieniona baza danych. Przedstawia ją poniższy obrazek:

DatabaseDiagram

Dodano tabelę ElectricityBorder, która zawiera informację o ograniczeniu na prąd w danym dniu oraz czasie, przechowuje również wykorzystany już w tym czasie prąd oraz różnicę między tymi wartościami.

Tabela Teachers została rozszerzona o kolumnę electricity_value – wartość prądu, jaką zużywa nauczyciel.

Definicje tabel uległy zmianom. Można to zauważyć obserwując ich nazwy:

  • Tabela Teachers zmieniła się na Teachers_Devices – wiersze tabeli reprezentują konkretne urządzenie.
  • Groups -> Groups_Plugs – tabela reprezentuje wtyczkę urządzenia.
  • TeachGroup -> Teach_DeviceGroup  – relacja wiele do wielu dla tabeli Teachers_Devices  i Groups_Plugs, odpowiednio dodawane dane sprawią jednak, że ta relacja będzie 1-1.
  • SubjectTypes -> Subject_BuildingTypes – tabela zawiera typy budynków. W moim przypadku będą dwa typy: Administracja i Dom. Mają one różne priorytety w algorytmie układania harmonogramu.
  • Subjects -> Subjects_Buildings – wiersze tabeli reprezentują konkretne budynki na osiedlu.
  • Rooms -> Rooms_SocketHouses – wiersze reprezentują konkretne gniazdka.
  • Students – Students_Users -> tabela zawiera wpisy z konkretnymi użytkownikami konkretnego urządzenia.

Pozostałe tabele nie zmieniły pierwotnej funkcji swojego działania, więc ich nazwy też nie uległy zmianom.

Agent planner

W celu ułożenia harmonogramu dla urządzeń wykorzystuję kod źródłowy układający plan zajęć na Politechnice Gdańskiej. Kod ten stanowi pracę magisterską Rafała Tkaczyka. Oparty jest on o agentów programowych (zaimplementowanych w technologii JADE) oraz relacyjnej bazie MySQL. Poniższy rysunek przedstawia pierwotny model bazy danych:

databaseDiagram

Stan projektu

W trakcie tworzenia mojej pracy magisterskiej dotarłem do momentu stworzenia i zaimplementowania algorytmu tworzenia harmonogramu dla urządzeń bazujący na agentach programowych. Wykonałem jego okrojoną wersję, która wymagała jeszcze wiele pracy. Niespodziewanie mój promotor uszczęśliwił mnie działającym algorytmem rozwiązującym problem tworzenia harmonogramu zajęć na Politechnice Gdańskiej, który bazuje na agentach programowych.

Kod napisany jest w Javie i również korzysta z biblioteki JADE. Wykorzystuje on jednak relacyjną bazę danych MySQL. To jednak nie jest żaden problem. Zainstalowałem bazę danych, zmieniłem trochę otrzymany kod, aby działał na mojej maszynie, i po chwili miałem ułożony harmonogram dla uczelni gdańskiej.

Z otrzymanym rozwiązaniem zrobiłem kilka rzeczy:
– wykorzystałem moją klasę uruchamiającą agentów,
– scenariusz dla konkretnego problemu zapisałem w kodzie, a następnie zapisuję ten scenariusz w XMLu,
– usunąłem szkielet mojego algorytmu,
– rysuje wykresu dla planu w kontekście włączania urządzeń i zużywania prądu,
– w momencie uruchamiania środowiska agentów, usuwam dane z bazy danych i wczytuję wszystko z XMLa.

Obecnie jestem w momencie implementowania przystosowania modelu bazy danych z problemu uczelni na model z problemu osiedla.

Hashtable

Spotkałem ostatnio w kodzie bardzo denerwujące mnie wyrażenie. Metoda jako jeden z parametrów przyjmowała Hashtable, który stanowił zbiór różnych parametrów wykorzystywanych przez tę metodę. Około osiem kolejnych linijek kodu stanowił komentarz informujący co ta hashtabela zawierać powinna.

Super, fajnie, ale po co?

Czy nie lepiej napisać jest anemiczną klasę, która znacznie czytelniej przekaże parametry do tejże metody? Co w przypadku, gdy zrobiliśmy literówkę w kluczu dla tej hashtabeli. Musimy wtedy poprawić go wszędzie, również w komentarzach, a narzędzia refactoringu mogą nam w tym nie pomóc…

Strasznie nie lubię odwoływania się w kodzie do różnych elementów przez napis w cudzysłowach. Bardzo łatwo o pomyłkę, a jeszcze trudniej utrzymać takie rozwiązanie. Cały ten komentarz rozpoczynający metodę mógłby zostać przeniesiony do klasy anemicznej w postaci kodu, czyli czegoś, co musi być poprawne. Moim zdaniem kod stałby się przez to czytelniejszy i łatwiejszy w utrzymaniu!

Architektury systemów wieloagentowych

Jorg P. Muller w Control Architectures for Autonomous and Interacting Agents: A Survey wymienia architektury systemów wieloagentowych:

  1. Dla agentów reaktywnych:
    1. Broks: subsumpcja architektury – jest to dekompozycja systemu na aktywnych agentów będących producentami, którzy pracują równolegle.
    2. Steels: roboty  behawioralne – stawianie na samoorganizujący się świat, gdzie agenci składają się z obiektów, które mają wykonywać proste zadania (swarm intelligence).
    3. Arkim: architektura AuRA (Autonomous Robot Architecture) – rozszerza model Brooks’a o pięć komponentów. Jest podobny do Procedural Reasoning System oraz Firby’s RAP System.
    4. Maes: dynamiczny wybór – agent decyduje (dynamicznie) jaką akcję wykona w następnym momencie swojego życia.
  2.  Dla agentów deliberatywnych (naradzających się)
    1. Bratman: IRMA – architektura agentów ograniczonych zasobami. Opisuje jak agent wybiera swój kierunek działania na podstawie swoich doznań, wierzeń, pragnień i intencji.
    2. Rao i Georgeff: formalny model BDI – sformalizowany model BDI. Wierzenia, pragnienia i intencje opisywane są przez operatory modalne.
    3. Rao i Georgeff:interpretacja BDI – dodanie interpretera, który interpretuje BDI agentów, ponieważ wcześniej model mógł nie mieć pełnej listy aksjomatów.
    4. Shoham i Thomas: programowanie zorientowane na agentów – architektura AOP (Agent-oriented programming). Przedstawili agenta jako jeden obiekt, który posiada wierzenia, możliwości, wybory i zobowiązania.
  3. Dla agentów interaktywnych:
    1. Fisher: MAGSY – agenta reprezentuje zestaw faktów będący jego wiedzą, zestaw zasad będących strategia i zachowaniami, zestaw serwisów będących interfejsem zewnętrznym agenta. Jeden agent może zawołać serwis innego agenta.
    2. Jennings: GRATE – zawiera warstwę wiedzy powszechnej (znanej i dostępnej dla każdego agenta)
    3. Steiner: MECCA – agent składa się z ciała (aplikacja), głowy (cele agenta), komunikatora.
    4. Sundermeyer: COSY – opisuje agenta jako zachowania, zasoby i intencje
  4. Architektury hybrydowe.

Refaktoryzacja

Refaktoryzacja – z pewnością każdy, kto napisał już trochę kodu, zna to słowo.

W tym roku już drugi raz trafiła w moje ręce książka:

Refaktoryzacja. Ulepszanie struktury istniejącego kodu. Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts.

Bardzo polecam tę książkę. Osobiście dużo czasu poświęcam refaktoryzacji. Wynika to ze sposobu tworzenia przeze mnie oprogramowania: mało modelowania w początkowej fazie, najpierw zróbmy coś działającego, potem to uporządkujmy. Z czasem i doświadczeniem nie poświęcam wcale więcej czasu na modelowanie, lecz od razu tworzę lepsze modele. Często przez kilka dni nie tworzę żadnej wartości dodanej, prócz tego, że mój kod jest przejrzystszy, lżejszy i bardziej logiczny. Dlaczego to robię? Sprawia mi to przyjemność i daje sporo satysfakcji. Zabawne jest, gdy czytasz swój stary kod i myślisz sobie: kto to napisał?

Jak zabieram się do refaktoryzacji?

Robię to na trzy sposoby:

Przede wszystkim czytam kod i używam przekształceń z wyżej wymienionej książki.

Do mojego kodu piszę często dokumentację. Pisząc ją, można łatwo zauważyć, że coś z naszym kodem może być nie do końca w porządku.

Bardzo przydatne w procesie refaktoryzacji są diagramu UML: diagramy klas oraz przepływu. Daje nam to szerokie spojrzenie na tworzone oprogramowanie.