Co byście poprawili w swoich projektach?

2

Jestem ciekawy jakie rzeczy chcielibyście poprawić w swoich obecnych projektach, gdyby był na to czas :)

Zacznę ode mnie:

  • pozbycie się PagedList z architecture components, kod wokół nich zaczął być strasznie skomplikowany poprzez obchodzenie braku wsparcia dla mutowalnych elementów na liście, początkowo miało nie być takich elementów, wyszło jak zawsze :)
  • rozbicie trzech dużych modulów domain/network/common na mniejsze
  • przeniesienie usecase'ów, być może razem z ViewModelami do modułów kotlinowych
  • ujednolicenie styli i zredukowanie palety kolorów w aplikacji
  • więcej testów, zwłaszcza ui'owych i zautomatyzowanie uruchamiania testów ui'owych na jakiejś maszynce
  • przerobić konfigurację Gradle na Kotlin DSL
2

Nie wszystkie punkty są związane z brakiem czasu. Niektóre są niemożliwe do zrealizowania, bo ktoś decyzyjny po stronie klienta albo naszej nie wyraża zgody "bo tak". Niektóre są moimi preferencjami. Niektóre są moimi mrzonkami i tak naprawdę bym nie wdrażał, ze względu na rotację ludzi w projekcie.

  • Lepsza modularyzacja Gradle'a. Niestety tutaj w kilku punktach przeszkadza backend, bo API nie jest jednolite dla wszystkich aplikacji, mimo że mogłoby być. Dodatkowo blokuje Room, bo nie da się go modularyzować za bardzo.
  • Napisanie sztucznych implementacji backendu i urządzenia Bluetooth, które mogłyby być wykorzystywane w testach i deweloperskiej wersji aplikacji.
  • Przepisanie komponentu odpowiedzialnego za współpracę z kamerą/laserem i skanowanie kodów kreskowych. Niestety był "prikaz", żeby go dodać i teraz musimy się z tym użerać.
  • Zmienić UI na coś, co nie wygląda jakby było robione 30 lat temu i UX na coś, co jest intuicyjne. Niestety tak to się kończy bez współpracy z projektantami i jak biznes "wie lepiej" i mówi, żeby skopiować z bliźniaczego, przedpotopowego projektu.
  • Nie korzystać z własnego wydumanego protokołu na warstwie BLE tylko użyć Protocol Buffers.
  • Przejście z Room na SQLDelight. Wywalić fragmenty i AppCompatActivity. Wywalić ViewModel z Android Architecture Components.
  • Pozbyć się nadmiarowej ilości interfejsów, którą niczemu nie służą poza pisaniem testów, które tak średnio testują.
  • Dodać testy UI.
  • Naprawić CI, który nie działa od grubo ponad roku. Dodać CD.
  • Dodać wewnętrzne repozytorium Mavena dla projektu i przenieść tam część rzeczy jako biblioteki.
  • Przejść na Kotlina i pozbyć się AutoValue.
  • Nie obfuskować kodu.
  • Poprawić kilka rzeczy w grafie Daggera, ale to wymaga zrealizowania kilku z powyższych punktów.

Sporo tego wymieniłem, ale szczerze z kodem nie ma tragedii poza tym brakiem CI, co jest absurdem i kuriozum, które chyba tylko mi w rzeczywistości zdaje się przeszkadzać. OGROM rzeczy bym zmienił natomiast na backendzie, bo tam się dzieje totalna patologia, ale germański Agile i sposób prowadzenia projektu są niezłomne. Na szczęście jeszcze tylko dwa tygodnie.

0
Michał Sikora napisał(a):

Wywalić ViewModel z Android Architecture Components.

Czemu to byłoby ulepszeniem?

  • Pozbyć się nadmiarowej ilości interfejsów, którą niczemu nie służą poza pisaniem testów, które tak średnio testują.

Takie stwierdzenie sugeruje, że prawdziwym, głębszym problemem są kiepsko napisane testy. A nadmiar interfejsów to tylko jeden z objawów. "Stłucz pan termometr, nie będziesz mieć gorączki".

Co do Koina i Daggera (wspomnianych w komentarzach), oczywiście Koin jest znacznie prostszym rozwiązaniem, i ściśle rzecz biorąc to jest nie tyle "pełnoprawny" DI, co service locator. Ale - dzięki Kotlinowi - dość cywilizowany.

Dagger wymaga namotania większej ilości boilerplate'u, i w wielu projektach jest to strzelanie z armaty do wróbli. To trochę tak, jak z RxJavą, która jest niezłą kobyłą, a w 90% przypadków używa się jej tylko do przerzucania zadań na wątki w tle :)

W przypadku prostych projektów Koin na pewno jest alternatywą wartą rozważania. Jest jeszcze Kodein, ale sam nie używałem, więc się nie wypowiadam.

0
V-2 napisał(a):
Michał Sikora napisał(a):

Wywalić ViewModel z Android Architecture Components.

Czemu to byłoby ulepszeniem?

Ponieważ ViewModel jest ograniczony pod względem tego, jak się go tworzy. Wolałbym zastapić zwykłą klasą, która nie ma narzuconych ograniczeń.

  • Pozbyć się nadmiarowej ilości interfejsów, którą niczemu nie służą poza pisaniem testów, które tak średnio testują.

Takie stwierdzenie sugeruje, że prawdziwym (głębszym) problemem są kiepsko napisane testy. A nadmiar interfejsów to tylko jeden z objawów. "Stłucz pan termometr, nie będziesz mieć gorączki".

No to przecież napisałem, że są testy, które prawie niczego nie testują. Usunięcie tych interfejsów wymusiłoby napisanie prawidłowych testów. Głównie w warstwie prezentacji w moim przypadku. Przykładowo wolałbym pozbyć się interfejsu LoginUseCase, bo niczego nie wnosi. Wtedy wystarczy dostarczyć sztuczną implementację AuthService na potrzeby testów. Uporściłoby to też graf obietków.

public interface LoginUseCase extends ObservableTransformer<LoginAction, LoginResult> { }

public final class LoginTransformer implements LoginUseCase {
  private final AuthService authService;
  private final TokenCache tokenCache;
  private final Moshi moshi;

  @Inject public LoginTransformer(AuthService authService, TokenCache tokenCache, Moshi moshi) {
    this.authService = authService;
    this.tokenCache = tokenCache;
    this.moshi = moshi;
  }
}

@Binds abstract LoginUseCase bindLoginPickupUseCase(LoginTransformer transformer);

Dagger wymaga namotania większej ilości boilerplate'u, i w wielu projektach jest to strzelanie z armaty do wróbli.

Zgadzam się z drugim stwierdzeniam, bo Dagger wymaga większej ilośc kodu na starcie pod fundamenty dostarczania zależności, ale to Koin wymaga więcej boilerplatu niezależnie od fazy aplikacji.

0
Michał Sikora napisał(a):
V-2 napisał(a):
Michał Sikora napisał(a):

Wywalić ViewModel z Android Architecture Components.

Czemu to byłoby ulepszeniem?

Ponieważ ViewModel jest ograniczony pod względem tego, jak się go tworzy. Wolałbym zastapić zwykłą klasą, która nie ma narzuconych ograniczeń.

Ale dobrze rozwiązuje problemy związane z cyklem życia widoków. Dzięki temu nie trzeba wyważać drzwi otwartych. Nowy programista w projekcie zastaje rozwiązanie standardowe. A nie zwykłe klasy, które w każdym projekcie rozwiązują te same problemy w inny sposób.

Dagger wymaga namotania większej ilości boilerplate'u, i w wielu projektach jest to strzelanie z armaty do wróbli.

Zgadzam się z drugim stwierdzeniam, bo Dagger wymaga większej ilośc kodu na starcie pod fundamenty dostarczania zależności, ale to Koin wymaga więcej boilerplatu niezależnie od fazy aplikacji.

W dalszych fazach są plus minus równorzędne. Zamiast @Inject masz by inject(), lub dodanie do modułu jednej linijki z konstruktorem get(), get(), get(). I nie trzeba pisać własnych anotacji. Do tego skraca się czas budowania projektu. Oczywiście ma to swój koszt - jest ryzyko, że niektóre błędy przerzucimy do runtime'u.

0
V-2 napisał(a):

Ale dobrze rozwiązuje problemy związane z cyklem życia widoków. Dzięki temu nie trzeba wyważać drzwi otwartych. Nowy programista w projekcie zastaje rozwiązanie standardowe. A nie zwykłe klasy, które w każdym projekcie rozwiązują te same problemy w inny sposób.

Dlatego zaznaczyłem, że niektórych rzeczy bym w rzeczywistości nie zmieniał ze względu m.in. na rotację ludzi w projekcie. :)

W dalszych fazach są plus minus równorzędne. Zamiast @Inject masz by inject(), lub dodanie do modułu jednej linijki z konstruktorem get(), get(), get(). I nie trzeba pisać własnych anotacji. Do tego skraca się czas budowania projektu. Oczywiście ma to swój koszt - jest ryzyko, że niektóre błędy przerzucimy do runtime'u.

Nie są. W Daggerze nie muszę pisać żadnego boilerplatu, bo sam go generuje, dostarcza zależności wewnątrz zbudowanego grafu i nie muszę robić tego tam manulanie.

1

W dalszych fazach są plus minus równorzędne. Zamiast @Inject masz by inject(), lub dodanie do modułu jednej linijki z konstruktorem get(), get(), get(). I nie trzeba pisać własnych anotacji. Do tego skraca się czas budowania projektu. Oczywiście ma to swój koszt - jest ryzyko, że niektóre błędy przerzucimy do runtime'u.

Nie są. W Daggerze nie muszę pisać żadnego boilerplatu, bo sam go generuje, dostarcza zależności wewnątrz zbudowanego grafu i nie muszę robić tego tam manulanie.

Nie rozumiemy się chyba. Nie chodzi mi przecież o kod generowany, tylko o kod konfiguracyjny. Te wszystkie komponenty itd. Na Daggerze jest tego dość sporo. Za to np. scoping na Koinie jest rozwiązany bajecznie prosto.

Zainteresowani tematem mogą poczytać kilka case stories dotyczących migracji, np. https://medium.com/@charbgr/bye-bye-dagger-1494118dcd41

Once finished replacing all the call sites, we deleted every Dagger class annotated with Module, Component etc, resulting in 93 additions and 1803 deletions. Quite a lot huh?

0

Ok, to faktycznie nie zrozumieliśmy się. Myślałem, że mówisz o boilerplacie a nie kodzie konfiguracyjnym. A tak poza tym, to ja się zgadzam, że Dagger ma wady, których nie ma w Koinie, ale nie są one dla mnie na tyle znaczące, żeby porzucać Daggera. Głównie dlatego, że kontener DI będzie się skalował dużo lepiej niż lokator serwisowy niezależnie od konkretniej implementacji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1