Blog robi się powoli monotematyczny, dziś znowu o programowaniu, głownie na Androida.
Klient już czwarty tydzień załatwia papiery, a oczywiście terminy zakończenia poszczególnych etapów już ustalone i potem czasu będzie mało. No ale nie moje zmartwienie, ja zrobię co się da, ale tym razem o nadgodzinach mogą zapomnieć. Za to siedzę w domu i rozpracowuję prywatne programowanie pod Androida na koszt pracodawcy. Całkiem dobry układ. Jakbym był na własnym rozrachunku, to mogłoby boleć, a tak nie mam stressu (oczywiście poza stressem związanym z oddawaniem co miesiąc braterskiej części tego co klient płaci pracodawcy, ale coś za coś).
Do mojego nowego komputera dokupiłem porządny zasilacz. Dwa tej firmy (BeQuiet!) już w domu miałem, do serwera kupiłem nówkę, modularnego (znaczy kabelki dołącza się według potrzeby) serii 8 (im mniejszy numer, tym starszy, aktualne serie to 11), drugi to była używka dla syna, niemodularny serii 8 (syn ma komputer w normalnej obudowie mini tower, więc kabelki nie przeszkadzają specjalnie w przepływie powietrza). Teraz też nastawiłem się na używkę na eBayu, modularnego serii 7 lub 8. Prawie aktualne (serii 10) jako używki chodzą po 70-80 EUR, jak mocne to nawet wyżej. Serie 7 i 8 dają się kupić za jakieś 35-40 z wysyłką. Udało mi się wylicytować za zaledwie 31 z wysyłką, bo sprzedawca się trochę przechytrzył wystawiając cenę startową aż 25 EUR i nikt poza mną się nie zainteresował. A zasilacz jest z bardzo drogich serii high-endowych (Dark Power Pro P7), wygląda na nie używany (niemal wszystkie kabelki mają jeszcze oryginalne zawieszki), jak go obejrzałem to szczęka mi opadła. Już opakowanie wyraźnie różni się od tych tańszych (ma okienko, kabelki pakowane są indywidualnie w kartoniki), zasilacz jest trochę większy niż standardowy (znaczy pasuje jako ATX, tylko w jedną stronę jest trochę dłuższy, w moją małą obudowę wszedł bez problemu). Kabelków jest duży asortyment w różnych kombinacjach, wentylator zasilacza jest podłączany do złącza monitoringu na płycie głównej, a zasilacz może jeszcze sterować czterema dodatkowymi wentylatorami. Praktycznie go nie słychać, nawet z bliska. Super rzeczy, te zasilacze, polecam.
Decyzja o zrobieniu sobie komputera z 8GM RAM była bardzo dobra - system + Thunderbird + Firefox + inne drobiazgi + Android Studio + emulator biorą łącznie 6-6,5 GB, jeżeli ktoś ma zamiar próbować robić apki na 4GB to odradzam z góry, szkoda nerwów.
Wróćmy do programowania. Próbuję robić aplikację, i Android nie za bardzo mi się podoba. Znaczy API sporo potrafi, jest tam trochę niezłych koncepcji, ale wyraźnie za mało zastanawiali się nad usability. Bo wygląda to tak:
Aplikacja Androidowa zbudowana jest z Activities. Activity (upraszczając) to jest screen + kod do niego, ma to swój wieloetapowy lifecycle, można wydzielić sobie reusable kawałki GUI zwane Fragment. Fragment ma znowu swój lifecycle, trochę inny niż Activity. No i porządnego, pełnego diagramu tych lifecykli nie znajdziecie na http://developer.android.com, trzeba szukać gdzie indziej. Zasadniczy problem polega jednak na tym, że w Androidzie wszystko jest asynchroniczne, nie ma nawet czegoś takiego jak windowsowy dialog modalny. Nawet okienko w rodzaju Yes/No/Cancel jest niemodalne, aplikacja biegnie dalej i trzeba wszystko synchronizować we własnym zakresie. Nie byłby to aż taki wielki problem, gdyby nie to, że ma to również znaczenie podczas lifecycle Activity/Fragmentu. Na przykład mogą one wymagać uprawnień dostępu do jakichś serwisów (na przykład kamery). I jak praw nie ma to albo trzeba o nie interaktywnie zapytać, albo rzucić jakimś błędem. No ale to jest w trakcie startu, nasz kawałek jeszcze nie jest w żadnym stabilnym stanie! Nie da się zatrzymać startu, a o wyniku zapytania użytkownika (czyli czy w ogóle jest sens startować) dowiemy się dopiero później. Przecież to wcale nie chce współgrać ze sobą! Zacząłem więc kombinować jak powinna wyglądać architektura standardowej aplikacji, żeby to wszystko sensownie działało i to wcale nie jest proste. Poguglałem i widzę, że co bardziej kumaci deweloperzy też mają podobne uwagi i kombinują różne rozwiązania. Muszę jeszcze trochę poczytać, co proponują. Na razie znalazłem rady żeby robić Reactive Programming przy pomocy JavaRx, no jest to jakaś propozycja, ale nie jestem całkiem przekonany czy będzie to pasować do moich koncepcji.
Ale tak według mnie, to powinno być zadanie projektantów systemu! Jeżeli każdemu deweloperowi każemy wymyślać koncepcje, jak by tu ogarnąć chaotycznie zaprojektowany system, nie dając mu nawet szkicowych szablonów rozwiązań, to z góry można założyć, że minimum dziewięćdziesiąt kilka procent wymyślonych rozwiązań będzie marnych. Nawet jak deweloper jest ogólnie dobry, to dopiero po paru skończonych aplikacjach będzie wiedział, co robił źle. Co się dzieje jak nie ma patternów to ja widzę na codzień w pracy. Na moje oko to Androidowi brakuje jakiejś porządnej warstwy albo frameworku żeby łatwo dało się pisać bardziej złożone aplikacje. Bo proste quick and dirty idzie łatwo i przyjemnie, ale porządne, z pełną obsługą błędów i wszystkimi szykanami to duży problem. Powiedziałbym, że to prawie jak programowanie aplikacji windowsowych bez MFC. (Tylko nie bierzcie tego porównania zbyt dosłownie - API Androida jest znacznie bliższe MFC niż czystym Windowsom z ręcznie robionym event loopem, w końcu sporo lat minęło od tamtych czasów, tyle że API Androida jest o wiele bardziej skomplikowane niż windowsowe).
A tu jeszcze dokłada się fakt, że system jest w ciągłej zmianie. Nowe idee się pojawiają, stare zmieniają się (i to często więcej niż raz), jeżeli aplikacja ma chodzić na iluś wersjach wstecz to zaczynają się schody. Google dostarcza biblioteki robiące kompatybilność wsteczną, ale o dokłada tylko następny stopień złożoności - której trzeba użyć, a bez której można się obyć. A potem aplikacja na latarkę ma dwa megabajty, bo ciągnie ze sobą bez sensu ileś bibliotek kompatybilnościowych - nie są reusowalne w systemie, o nie. Ma to swoje uzasadnienie w koncepcji systemu (każda aplikacja to osobny user unixowy i nie ma sharingu czegokolwiek wprost między aplikacjami, zawsze musi to iść przez mechanizmy systemowe), ale skutki są niemiłe.
Dla ilustracji: Najstarsze urządzenie Androidowe jakie w domu mam, ma wersję Androida 4.1.2 (kryptonim: Jelly Bean, co to za US-amerykański pomysł, żeby nazywać wersje od jakichś obrzydliwych słodyczy, Lollipop, Marshmallow, rzygać mi się chce jak to czytam) to jest API numer 16. Logiczne więc, że chcę żeby moje apki chodziły przynajmniej od tej wersji. Ma to oczywiście również związek z wielkością rynku docelowego - w użyciu są urządzenia rożnych wersji, im wcześniej zaczynać, tym większa ilość potencjalnych klientów. Startując od API 16 pokrywamy jakieś 96% używanych na świecie urządzeń, im późniejsze API tym urządzeń mniej. Nadchodzący Android 8 (SDK i emulacja już jest, można sobie obejrzeć) to będzie API 26. W wersjach 4.x prawa dostępu były akceptowane przez użytkownika podczas instalacji, przy braku akceptacji aplikacja nie była instalowana. W późniejszych wersjach użytkownik był pytany dopiero przy starcie aplikacji i mógł odpowiedzieć tak albo nie, zależnie od humoru, a aplikacja mogła mu pokazywać wyjaśnienie, po co potrzebuje dostęp do tego. No i to oczywiście są kompletnie różne koncepcje, jednolite obsłużenie tego żeby chodziło w dowolnej wersji jest trudne. Ponieważ jest trudne, to Google wrzucił na GitHuba całkiem niezłą bibliotekę do tego (nazywa się easypermissions), zastrzegając sobie przy tym brak jakiejkolwiek odpowiedzialności i wsparcia, ale ja się pytam, dlaczego to nie jest wprost w API, a przynajmniej w SDK? I skąd początkujący developer ma wiedzieć, że takie rozwiązanie w ogóle jest, a nawet, że go potrzebuje?
Co do marnej obsługi wyjątków, na którą narzekałem poprzednio to powoli widzę, dlaczego nie dało się zrobić jej porządnie, z checked exceptions, ale oczywiście to nie jest komplement. Znalazłem natomiast, co można zrobić z nieobsłużonymi wyjątkami - jest taki serwis, do którego informacje o wyjątkach mogą być wysyłane. Nazywa się to fabric, wymyślił to Twitter, teraz należy do Googla. Ze dwie linie w programie, rejestracja w sieci i można mieć informacje o wszystkich nieobsłużonych wyjątkach w swojej aplikacji u dowolnego użytkownika z wszystkimi danymi (stack trace, sprzęt, czy rootowany, wersja systemu itd.). Do tego można mieć jeszcze life data o swojej aplikacji - ilu użytkowników używa jej w danej chwili, chyba nawet można wiedzieć co robią (jeszcze nie sprawdzałem tak dokładnie). Z jednej strony piękna rzecz przy developmencie, z drugiej to aż się zimno człowiekowi robi - przy każdym starcie aplikacji wysyłany jest do Google również AdvertisingId, co pozwala imiennie zidentyfikować każdego użytkownika z wszystkimi jego najprywatniejszymi danymi. Deweloper oczywiście tego nie dostaje do ręki, ale Google to ma. Podobno większość aplikacji używa tego fabrica, więc żadna różnica czy ja go użyję, czy nie - Google ma użytkownika na talerzu i tak. No i jeszcze trzeba zainstalować plugin u siebie, w Android Studio, i ten plugin zna każdy projekt w workspace. Kto zagwarantuje, że Google nie ogląda sobie tych projektów żeby wyłapać nowe idee i wejść z tym samym wcześniej?
Pamiętam hejt na Microsofta ćwierć wieku temu (Gates w mundurze SA, z flagą w której swastyka została zastąpiona logo Windowsów, na czele rzeszy SA-manów, pod hasłem "Ein Reich, ein Führer, ein OS") , pamiętam jak mieli koncepcje żeby Windowsy były na wszystkim (Windows for Pen, Windows for TV...), wczesne reklamy Apple sugerowały że Microsoft to Wielki Brat. No ale przecież najdalej posunięte pomysły MS to było małe miki w porównaniu z tym co robi "Don't be evil" Google. A Google jakoś nikt w podobny sposób nie karykaturuje.
Rysunek o MS znalazłem tylko we fragmencie, pewnie pousuwali te całe ze względu na tekst.