czwartek, 30 września 2010

Jak w zasadzie działają moduły flexa

Ponieważ straciłem ostatnio sporo czasu na próbach podłączenia modułu do istniejącej już aplikacji (nie mając dostępu do aplikacji/źródeł), postanowiłem podzielić się swoimi przemyśleniami.

Generalnie, flex jako flex jest bardzo fajnym narzędziem, ale jak każda technologia ma trochę problemów. Ja ostatnio natrafiłem na problemy związane z podłączeniem modułu który komunikował się za pomocą WebService. Warto nadmienić, że sam moduł, został przygotowany nie jako moduł, ale jako osobna aplikacja webowa, co dostarczyło mi dodatkowych problemów. Przejdźmy do sedna:

Moduły/Aplkiacje flexowe można ładować na kilka sposobów. Po pierwsze możemy skorzystać z loadera i przy jego pomocy załadować aplikację. Przykładowy kod wygląda następująco:
MXML:

 <mx:moduleloader url="SomeModule.swf"/>

AS:


var loader : ModuleLoader = new ModuleLoader();
loader.url = "SomeModule.swf";
contentPanel.addChild(loader);


Sprawy oczywiście się dalej komplikują, bo jak można się domyślić, nie jest to jedyny sposób ładowania modułów. Po pierwsze możemy użyć różnych loaderów. Dla przykładu SwfModuleLoader nadaje się do załadowania aplikacji a nie modułu (jak również swf wykonanego we flashu). Zastosowanie tego loadera potrafi rozwiązać wiele problemów które można spotkać z innymi loaderami, w szczególności można przy jego pomocy prawidłowo ustawić moduł na ekranie. Obsługuje on również eventy związane ze zmianą wielkości obszaru aplikacji. Użycie tego loadera rozwiązało moje problemy związane z ładowaniem modułu (o których napiszę dalej).

Aby sprawy dalej skomplikować, można również użyć ModuleManager, co zostało zastosowane w przypadku aplikacji do której się podłączałem. Stosowanie ModuleManager wymaga jednak nieco innego podejścia. Jest to element który zarządza załadowanymi modułami. Przykładowy kod zastosowania wygląda następująco:


var moduleInfo : IModuleInfo;
moduleInfo = ModuleManager.getModule(_url);
moduleInfo.load();
var module:Object = moduleInfo.factory.create();
container.addChild(module);


Jak widać, flex pozwala na na prawdę dużą dowolność. W szczególności można użyć po prostu Loader. W zasadzie nie było by to aż tak skomplikowane, gdyby nie fakt, że dodatkowo jest jeszcze takie pojęcie jak ApplicationDomain. Domena aplikacji de-facto oznacza, w jakim środowisku dany moduł powinien zostać załadowany. Domenę ładuje się następująco:


var applicationDomain:ApplicationDomain = ...;

-----------------------------------------------------

var moduleInfo : IModuleInfo;
moduleInfo = ModuleManager.getModule(_url);
moduleInfo.load(applicationDomain);

-----------------------------------------------

var loader : ModuleLoader = new ModuleLoader();
loader.url = "SomeModule.swf";
contentPanel.addChild(loader, applicationDomain);




Pod zmienną applicationDomain z przykładu można podstawić 3 (w zasadzie 4) wartości. Pierwsza (domyślna) to wartość:

var applicationDomain:ApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);

lub

var applicationDomain:ApplicationDomain = null;


Tego typu zapis oznacza, że moduł jest modułem dzieckiem. Do rodzica można dostać się poprzez ApplicationDomain.parrentDomain. Niestety, jest to tylko teoria. Obie domeny co prawda są odseparowane, ale jeżeli korzystamy w naszej aplikacji z singletonów, to będą się one zachowywać na dwa sposoby. Albo będą modułowe, albo aplikacyjne. Jeżeli singleton nie został zainicjalizowany w aplikacji (a wystarczy tylko wspomnienie takie jak var sig:SomeSingleton = null), to jego zasięg będzie dotyczył tylko modułu (nawet, jeżeli występuje w innych modułach). Natomiast, jeżeli został zainicjalizowany w aplikacji, to będzie to singleton aplikacyjny. Przypomnę, że w moim wypadku nie miałem dostępu do kodu aplikacji, a więc nie byłem w stanie sprawdzić, czy singleton którego używam, był użyty w aplikacji.
Samo to nie jest jeszcze straszne, ale są dalsze konsekwencje. Może wystąpić sytuacja, w której sigleton dynamicznie powołuje do instnienia obiekty klas (po nazwie klasy). Takie zachowanie ma na przykład SchemaTypeRegistry.getInstance().registerClass(...) używane do rejestrowania klas dla WebService. Nagle pojawia się Error #1065, oznaczający, że nie można załadować klasy, ponieważ nie została ona dołączona do skompilowanego kodu. Dokładnie rzecz ujmując ApplicationDomain znajdujący się w aplikacji (w przypadku singletona aplikacyjnego) próbuje powołać do życia obiekt, dla którego klasa znana jest tylko w ApplicationDomain modułu. Osobiści podejrzewam, że jest to jakiś błąd w flexie, ale jak szukałem informacji na temat, to przekrój czasowy w jakim można znaleźć posty na ten temat jest imponujący (2005-2010). Nawet Flex 4 posiada bardzo podobnie wyglądający błąd.

Jak pisałem, są jeszcze 2 warianty przypisania AppliacationDomain:

var applicationDomain:ApplicationDomain = new ApplicationDomain();

oraz

var applicationDomain:ApplicationDomain = ApplicationDomain.curentDomain;


Pierwszy sposób tworzy całkowicie odrębną domenę aplikacji. Osobiście tematu nie zbadałem, ale to co mogę powiedzieć, to to, że aplikacja nie chciała mi się uruchomić z modułem, musiałem zmienić moduł na aplikację, żeby osiągnąć jakikolwiek efekt.

Ostatni sposób, tworzy wspólną domenę dla modułu oraz aplikacji. Takie podejście powoduje, że nagle klasy których mi brakowało, znajdują się w tej samej domenie co aplikacja. Oznacza to, że mój problem przestaje istnieć, jednak warto wspomnieć, że nie ma również separacji modułu i aplikacji.

Więcej informacji można znaleźć w tych artykułach:
http://livedocs.adobe.com/flex/3/loading_applications.pdf
http://livedocs.adobe.com/flex/3/html/help.html?content=modular_5.html
http://life.neophi.com/danielr/2006/07/flex_2_runtime_error_1065.html

czwartek, 16 września 2010

Jak uwalić projekt - Epilog

Ponieważ minęło trochę czasu, postanowiłem napisać obiecany epilog do poprzedniej historii.

Firma odkryła, że jest jakiś problem i zatrudniała Audytora. Audytor zajął się oglądaniem jak są prowadzone projekty, głównie na poziomie zarządzania. Audyt zajął około miesiąca i obejmował głównie rozmowy z project managerami i dyrektorem technicznym. Po miesiącu Audytor został nowym dyrektorem technicznym, natomiast dyrektor techniczny został architektem systemu (który przecież trwa już od ponad roku).
Projekt w tym czasie spokojnie sam posuwał się do przodu. Kierownictwo było zajęte głównie roszadami oraz przygotowywaniem papierków, negocjacjami z klientem oraz audytorem/nowym dyrektorem. Oznacza to, że tak na prawdę, nikt nie kontrolował jak idą prace. Co prawda programiści są kompetentni, więc tyle ile mogą robią, ale mimo wszystko kompletny brak kontroli jest nieco niepokojący.

W między czasie, zaczeło wychodzić (przynajmniej w gronie programistów), że nowi programiści (zdalni) w zasadzie niewiele wnoszą do projektu, a dodatkowo poświeca się im sporo czasu. Mimo to, zawsze można jeszcze pod-zlecić innej firmie część prac. O ile osobiście uważam, że jest to całkiem niezły pomysł, to w sytuacji w której dokumentacja jest na poziomie niskim (nie zgodnym z założeniami, nie dokładnym, nie aktualnym, itd.), nie da się ani dobrze oszacować czasu, ani nie da się po prostu pod-zlecić. Trzeba dodatkowo dać kogoś, w zasadzie na pełen etat kto będzie wyjaśniał wątpliwości. Mimo to, pod-zlecanie stało się nowym motto firmy. Żeby było lepiej, to zawsze można wziąć firmę po znajomości (a nie koniecznie po kwalifikacjach jej pracowników).

Miesiąc po objęciu stanowiska przez nowego dyrektora zaczęły się ruchy w poszukiwaniu czasu programistów. Pojawiły się duże znaki zapytania odnośnie urlopów oraz prośby zaplanowania go na później jeżeli tylko się da. Pojwaiły się również spotkania personalne z dyrektorem w zakresie: Co robisz, ile ci to jeszcze zajmie, kiedy planujesz urlop i jak ma on się do tego co masz zaplanowane do zrobienia. Mam jednak wrażenie, że mimo dobrych chęci, nie wnosiły one niczego w projekt. Oczywiście część programistów zajmowała się tylko komunikacją z zleceniobiorcami (w tym programistami zewnętrznymi) więc nie zajmowali się programowaniem. Co interesujące, dzięki temu ruchowi, prace spowolniły tempo.

Mniejwięcej w tamtym okresie sprawy przybrały jeszcze gorszy obrót, bo okazało się, że dwóch najbardziej doświadczonych programistów stwierdziło, że odchodzi. Ponieważ jeden miał na głowie bezpieczeństwo aplikacji a drugi silnik, to rozpoczęto działania w celu przekazania zadań związanych z silnikiem. Przekazanie bezpieczeństwa zostawiono na 2 ostatnie dni pracy. W końcu ten autorski rozbudowany system spełniający masę wymagań (często na wyrost) na pewno łatwo można przekazać...

Mniejwięcej w tamtym okresie okazało się również, że firma oficjalnie zawiesza projekt, ze względu na brak umówionej płatności ze strony klienta. W zasadzie, można by przyjąć, że to już był koniec projektu. Oczywiście firma planowała jeszcze wywiązać się ze zobowiązań kontynuując projekt wewnętrznie, ale oficjalnie projekt był zawieszony.
Klient oczywiście chciał, żeby projekt był kontynuowany, ale z punktu widzenia firmy, lepsza była ścieżka sądowa.

Na tym etapie rozpoczęto również zrywanie umów z podwykonawcami (czyli po około miesiącu).

Stan: Realizacja projektu w miarę obiektywnie 75% (ale pewne problemy nie zostały w ogóle podjęte), wg firmy 90 - 95%. Oficjalnie zawieszony.
Zespół: 3 programistów 2 osoby od kontaktów.
[EDIT] Zgodnie z komentarzem. Brak testów obciążeniowych, a funkcjonalność ta co jest, przetestowana pobieżnie, przez testerów którzy nie znają się na pisaniu testów i programowaniu (czytaj: Osoby które przeklikają aplikację).

Ta zupełnie teoretyczna historia mogła się wydarzyć na prawdę. Takich firm w Polsce jest wiele. Nie każdy, mimo tego, że potrafi wykonać mały produkt, powinien brać się za realizację dużych projektów. Dodatkowo, warto jednak zatrudnić specjalistów, w dziedzinach które dla dużych projektów są istotne, takich jak analitycy, architekci, specjaliści z danych dziedzin. Małe projekty nie wymagają tak silnego zaplecza. Można je realizować znacznie luźniej, uzupełniając pewne elementy w biegu. W przypadku dużych projektów, błędy w architekturze, dokumentacji, zarządzaniu kosztują firmy na prawdę duże pieniądze.

PS. Pozdrowienia dla tych, którzy jednak czytają tego bloga :)