Jak wyciągnąć projekt z szamba?

1

Ponieważ nasz zespół backendowy nie wyrabia z taskami, zacząłem mu ostatnio pomagać. Zaczęło się od zadań potrzebnych dla mnie z punktu widzenia aplikacji mobilnych, gdzie tworzyłem nowy kod, pisałem własne testy bez żadnych mocków praktycznie i było znośnie. Teraz pomagam przy rozwijaniu już gotowego kodu. W skrócie to się trochę załamałem, jak zacząłem przeglądać. Wczoraj i dzisiaj implementowałem zadanie, którego implementacja zajęła mi może tak z 2 godziny. Pozostały czas został poświęcony na konfigurację mocków. Tak naprawdę ta sytuacja skłoniła mnie, do stworzenia tego tematu.

Żeby nakreślić charakter projektu trochę bardziej, to napiszę, że nasz architekt od backendu to tak naprawdę człowiek orkiestra, który robi jednocześnie za scrum mastera i nie ma dogłębnej wiedzy w żadnej dziedzinie. To pomaga na iOS'ie, to na Androidzie, to na backendzie. Często ja z kolegą musimy myśleć jak zaprojektować API, jak połączyć ze sobą komponenty itd. Nad nim jest jeszcze jeden architekt, który ma dosyć dogłębną wiedzę, ale bardzo lubi kobylaste rozwiązania ze swojego drugiego projektu, które przemyca ze sprintu na sprint do nas. Zazwyczaj też feruje wyroki bez zbadania tematu i jego zdanie jest najważniejsze w kwestiach rozwiązań. Do tego mam wrażenie, że klient bezgranicznie wierzy, że jego decyzje są te właściwe. Potem oczywiście trzeba te rozwiązania poprawiać. Obaj są fajnymi ludźmi, ale ciężko się przebić przez beton momentami.

Teraz o samym projekcie.

  • Spring, bo a jakże. Niby wersja 5, ale tylko dla picu. Piekło adnotacyjne i Tomcat wiecznie żywi.
  • Klasy z konstruktorami przyjmującymi nawet i po 15 argumentów.
  • Klasy domenowe splugawione wstrzykiwanymi propertisami. Nie mogę ich przez to nawet użyć w testach bez stawiania kontekstu.
  • Mockito Driven Development. Zmieniam linijkę kodu produkcyjnego i testy wymuszają na mnie zmianę w 100 różnych miejscach.
  • Kontrolery po 1000 linii z kluczową logiką biznesową. Korzystają zarówno z repozytoriów, jak i serwisów. W zasadzie można rzucać monetą, żeby odgadnąć, co zostanie użyte.
  • Wszędobylska mutowalność i nullowalność.
  • Sterowanie wyjątkami.
  • Kfiatki tego typu to normalka.
  • Rozwijanie dwóch osobnych zadań zazwyczaj prowadzi do konfliktów przy mergowaniu.
  • Menadżment przyjmuje taktykę, że w zasadzie nieważne co umiesz jako programista. Bylebyś miał jakiegokolwiek taska z JIRY. Ostatnio nasz człowiek od iOS'a robił zadania na backend (proste, ale zawsze), podczas gdy ostatni raz Javę na oczy widział 10 lat temu na studiach.

Mam wrażenie, że jestem jedyną osobą, która jednocześnie to widzi i chce jej się to zmienić. Większość osób narzeka, ale w gruncie rzeczy ma to gdzieś. Uciekać z projektu jeszcze nie chcę, bo jest niesamowicie ciekawy. Teraz moje pytanie. Jak przekonać wyższe instancje, że należy coś z tym zrobić? Jest to w ogóle możliwe z mojej pozycji (pozycji programisty Androida, który pomaga przy backendzie głowom „mądrzejszym” od siebie)? Od czego w ogóle przy tym wszystkim zacząć? Jak przy tym wszystkim przekonać klienta, żeby dał czas? Argument, że z każdym deploymentem są jakieś problemy do niego nie trafia.

Dodam, że jak przyszedłem do projektu, to w Androdzie było dokładnie to samo. Kod odziedziczony po projekcie matce, który był kupą gówna. W pewnym momencie miałem tego dość i odciąłem się całkowicie od jedynej słusznej drogi i przepisałem całą aplikację (z wyjątkiem jednego modułu, z którego niestety muszę korzystać). Dalej jest mnóstwo rzeczy do poprawy, ale przynajmniej da się w tym odnaleźć i szybko dostosowywać kod do nowych wymagań. Na backendzie nie mogę sobie niestety na to pozwolić. Brakuje mi autorytetu i czasu.

7

Odpowiadając na pytanie postawione w wątku: nie warto. Serio. Nikt tego nie doceni, a jeszcze będą narzekać że zajmujesz sie bzdurami zamiast klepać ficzery. Moja rada: zacznij rozsyłać CV :)

11

Dostrzeżmy najpierw pozytywy:

  • Spring, bo a jakże. Niby wersja 5, ale tylko dla picu. Piekło adnotacyjne i Tomcat wiecznie żywi.

Szęściarze. Nie macie websphere i JavaEE.

  • Klasy z konstruktorami przyjmującymi nawet i po 15 argumentów.

Konstruktory... Ale luksusy! Przynajmniej nie wszystko przez settery.

  • Klasy domenowe splugawione wstrzykiwanymi propertisami. Nie mogę ich przez to nawet użyć w testach bez stawiania kontekstu.

Klasy domenowe - czyli macie nawet jakąs architekturę. Cholerni farciarze.

  • Mockito Driven Development. Zmieniam linijkę kodu produkcyjnego i testy wymuszają na mnie zmianę w 100 różnych miejscach.

Testy macie. My musieliśmy pół dnia konfuigurowac kod w XMLu, wrzucać na produkcję i czekać na telefony od klientów.

  • Kontrolery po 1000 linii z kluczową logiką biznesową. Korzystają zarówno z repozytoriów, jak i serwisów. W zasadzie można rzucać monetą, żeby odgadnąć, co zostanie użyte.

Repozytoria i serwisy, a do tego kontrollery. Prawie clean architekture. My mieliśmy jedną klasę z dwoma metodami, każda po 20tys linii.

itd. [CIACH!]

Mam dobre doświadczenia w wieloletnim, mozolnym wyciąganiu z bagna. Bez rewolucji i przepisywania. (W sumie 2 takie większe projekty: jeden wyciągniety z totalnego spaghetti - koszmar. drugi nie był tragiczny, ale był męczący i miał dużo podobieństw do twojego (mockito, spring itd)). W obu przypadkach team wiedział, że jest źle i większość zespołu była zdeterminowana, żeby to poprawiać.

Najważniejsza zasada to, żeby nie pogarszać. Tylko lekko poprawiać przy każdym zadaniu i żeby zespół był mniej zgodny co znaczy lepiej. To zabawne ale szybko widać efekty: poprawiają się tzw. hotspoty - czyli miejsca, gdzie się często zagląda, zmienia i psuje. Nie ruszamy starych i zaśniedziałych fragmentów.

W tego typu systemach zwykle nikt nie oczekuje, że zadania są zrobione w 5 minut i jest kasa na to żeby robić dobrze. Biznes się nie buntuje jak się mówi, że zrobimy coś w 2 tygodnie, ale porządnie, zamiast w tydzień po łebkach. Masz tak? Ważne, żeby zespoł poczuł, że nie ma presji na szybko, a na lepiej. (to zadziwiające, ale w ostatnim takim projekcie to naprawdę był problem przekonać developerów(!), że nie musza się spieszyć i mogą dawać wysokie estymaty. Tzw. biznes ani razu się nie zająknął. ).

Trzeba w zespole zrobić takie mentalne nastawienie, że jak ktoś coś rusza i dostawia to patrzy co w okolicy da się lekko, przy okazji poprawić. Da się? Masz sprzymierzeńców? Narzekanie to jedno (ważne), ale czy ludzie umieją coś pisać dobrze ? Da się ich edukować? Choć kilka osób ma jakąś chęć poprawiania ? (nie muszą wszyscy). Z opisu wynika, że to w twoim projekcie największe wyzwanie. Spróbuj ich mentalnie podciągnąć. To narzekanie to jest jakaś iskierka nadziei.

Unikaj bardzo dużych refaktoringów (przekrojowych). To nie wychodzi dobrze. Jak musisz zatrzymać/zdezorganizować development całego zespołu na ponad tydzień to jest raczej za duży refaktoring.

Dawaj przykład, rób wolno, poprawiaj okolice. Mów o tym. Jak koledzy robią zadania to dawaj delikatne uwagi co można by poprawić, przy okazji, niedużym kosztem. Małymi krokami, wszystkiego naraz się nie zmieni.

  • Jak się okaże, że managment i koledzy to akceptuja to zrobiłeś coś dobrego.
  • Jak się okaże, że mają pretensje, że się nie wyrabiasz itp. to uciekaj, nie ma dla nich nadziei.
    IMO to drugie jest dużo mniej prawdowpodobne.
0
Shalom napisał(a):

Odpowiadając na pytanie postawione w wątku: nie warto. Serio. Nikt tego nie doceni, a jeszcze będą narzekać że zajmujesz sie bzdurami zamiast klepać ficzery. Moja rada: zacznij rozsyłać CV :)

Rozważam przynajmniej zmianę projektu. Ale wolę zapytać jeszcze tutaj, bo może jednak się da. Szczerze to nawet lubię się babrać w błocie, pod warunkiem że mogę z tym coś zrobić.

jarekr000000 napisał(a):

Najważniejsza zasada to, żeby nie pogarszać. Tylko lekko poprawiać przy każdym zadaniu i żeby zespół był mniej zgodny co znaczy lepiej. To zabawne ale szybko widać efekty: poprawiają się tzw. hotspoty - czyli miejsca, gdzie sięczęsto zagląda, zmienia i psuje. Nie ruszamy starych i zaśniedziałych fragmentów.

Tu właśnie moje pytanie w praktyce. Jak ratować coś takiego? Dosłownie nie jestem w stanie zmienić jeden linijki w kodzie, żeby nie wywalić 10 testów. Nie są to testy w pełni londyńskie na szczęście, ale czasami o nie zakrawają.

Powiedzmy dodam jakąś metodę do serwisu i chcę napisać testy. Stowrzyć zupełnie osobną klasę testową, która by nie korzystała z mocków tylko z prawdziwych klas ewentualnie moich sztucznych, jeżeli trzeba? Potem stopniowo migrować testy ze starej klasy do nowej aż pozbędziemy się mocków? Nie mogę tego tak po prostu wywalić, bo archytekty mi zaczną mówić po germańsku.

Przyznam też, że szczerze brakuje mi najzwyczajniej w świecie wiedzy ze Springa, żeby rozumieć jak wszystko działa i umieć to zrefaktorować.

jarekr000000 napisał(a):

W tego typu systemach zwykle nikt nie oczekuje, że zadania są zrobione w 5 minut i jest kasa na to żeby robić dobrze. Biznes się nie buntuje jak się mówi, że zrobimy coś w 2 tygodnie, ale porządnie, zamiast w tydzień po łebkach. Masz tak?

Nie mam. Projekt miał powiedzmy dwie fazy. Pierwsza pilotażowa, która skończyła się w czerwcu 2017. Druga produkcujna, która rozpoczęła się w styczniu 2018. Pod koniec pierwszej fazy, gdy z budżetem było już naprawdę krucho, musieliśmy się tłumaczyć biznesowi czemu coś zajmie 30 minut a nie 15. Nie ironizuję. W obecnej fazie zespół jest zdecydowanie za mały i budżet dalej jest problemem (ale nie aż takim jak pod koniec pilota). Dalej trzeba się tłumaczyć czemu coś, co drastycznie zmienia zachowanie w systemie, zajmie więcej niż tydzień.

jarekr000000 napisał(a):

Trzeba w zespole zrobić takie mentalne nastawienie, że jak ktoś coś rusza i dostawia to patrzy co w okolicy da się lekko, przy okazji poprawić. Da się? Masz sprzymierzeńców? Narzekanie to jedno (ważne), ale czy ludzie umieją coś pisać dobrze ? Da się ich edukować? Choć kilka osób ma jakąś chęć poprawiania ? (nie muszą wszyscy).

Sprzymierzeńcy są w teorii. Niemeccy sprzymierzeńcy się w gruncie rzeczy zgadzają, ale klient ma zawsze rację i jak machnie palcem, że coś za dużo zajmuje czasu, to kulą ogon od razu i godzą się na bylejakość. Polscy sprzymierzeńcy na backendzie byli, ale się zmyli po pilocie. Jest jeden kumaty kolega na backendzie, który jest non stop tym wszystkim poirytowany i umie w Javę. A jak pisze "ciekawy" kod, to da się z nim porozmawiać i przekonać, że można lepiej. Niestety widzę, że bardzo go projekt wypalił i nie ma siły już na to wszystko, ale może udałoby mi się go przekonać. Momentami nawet wzbudzałem w nim falę pozytywnej złości.

Tak przy okazji. Wiem, że duża część Twojej pracy, to właśnie ratowanie Titanica. Nie myślałeś kiedyś, żeby zrobić z tego prezentację?

4

Tak przy okazji. Wiem, że duża część Twojej pracy, to właśnie ratowanie Titanica. Nie myślałeś kiedyś, żeby zrobić z tego prezentację?

Ratowaniem Titanica to bym nie nazwał. Odwrotnie. Te projekty to właśnie góry lodowe, o które rozbijaja się dusze młodych, zdolnych programistów.
Nad prezentacja nawet się kiedyś zastanawiałem:

  • słabo się robi prezentacje w stylu - mamy w kodzie taki niezły syf. Milion klientów nawet nie wie jaka masakra obrabia ich dane...
  • w zasadzie wszystko jest opisane u Feathers (Working Effectively...) i Uncle Boba (clean coś tam, coś tam) ,
  • tak w zasadzie to nie ma jakiś spektakularnych osiągnieć - projekt wyciąga się z szamba powoli i dopiero po roku albo dłużej czuć, że chyba jest jakoś lepiej, jakby, (choć pewne efekty pozytywne sa prawie od razu - w nastawieniu/ morale).

Jakkolwiek, teraz akurat nie pracuję w firmie mającej taki bardzo stary, straszny kod. (To nasi klienci czasem mają - COBOL na przykład, ale nie muszę ich wymieniać).
I w zasadzie to natchnąłeś mnie, że może to jest jakiś pomysł, na teraz,
ameryki nie odkryję - ale jakieś podsumowanie + kilka historii z pola walki może z tego zrobić ciekawą prezentację.

0

Z Titaniciem w punkt :). Feathers nie czytałem. Dzięki.

A co do prezentacji miałem właśnie na myśli bardziej coś w stylu własnych odczuć, anegdot itd. Myślę, że nie musi być techniczna. Taka forma opowiadania byłaby też ciekawa.

0

Tak mi sie odnosnie testow i Titanica przypomnialo: http://devhumor.com/content/uploads/images/February2017/passing-unit-tests.jpg
Po prostu czasami jest sie w sytuacji ze na ratunek jest za pozno. I trzeba to potrafic ocenic.
Czasem tez pracuje sie przy aplikacji ktora zostala skazana na wymarcie, tylko trzeba ja jeszcze jakis czas suportowac. To wtedy nie ma sensu isc w cos wiecej niz surivival and maintanance.

1
  1. Przykryć ładną fasadą.
  2. Pokryć testami ingetracyjnymi.
  3. Podzielić na moduły.
  4. Refaktoryzować moduły.

Wszystko zgodnie z zasadą Pareto - czyli najpierw kluczowe części, w których kod często się zmienia, a na te, które jakimś cudem działają ale ich biznes się nie zmienia i nikt do nich nie zagląda, raczej nie warto tracić czasu.

No i oczywiście ten przepis nie zawsze pomoże.

0
Michał Sikora napisał(a):
  • Mockito Driven Development. Zmieniam linijkę kodu produkcyjnego i testy wymuszają na mnie zmianę w 100 różnych miejscach.

A może jako frontendowiec nie jesteś przyzwyczajony do testów junit? One są potrzebne, w zrównoważonej ilości. Udowodnić ich bezsens można tylko po zrozumieniu ich i wykazaniu, że nic nie testują albo są nadmiarowe. Wtedy nic nie dodają, a tylko utrudniają development. Wtedy do kasacji. Każdy się ucieszy i doceni :)

1

Pytanie o nieprzyzwyczajnie do junitów jest niezasadne. Android to jednak dużo więcej niż frontend. Boryka się prawie z tymi samymi problemami co backend i ma jeszcze własne związane głównie z frameworkiem, cyklem życia i głównym wątkiem. Do tego kultura Mockito na Androidzie jest dużo większa niż w Springach itd.

Testy to testy i mocki powinny być użyte tylko do zewnętrznych zależności. W przypadku klas, które ciężko przetestować, bo są zależne od frameworka, ale należą do naszej aplikacji, należy albo testować na frameworku albo skorzystać z DIP i napisać własne sztuczne klasy dla tych interfejsów (a nie mocki). Te sztuczne klasy powinny być poddane tym samym testom co prawdziwe klasy. Potem możesz sobie w junitach stosować te sztuczne klasy i spać spokojnie, że zachowuje się to w miarę tak samo jak w rzeczywistości.

Żeby nie być gołosłownym wklejam przykład testu z mojego komentarza wcześniej. W pracy na backendzie na szczęście aż tak źle nie jest, bo coś w stylu getAndSaveUser nie zwracałoby void i nikt nie korzysta z InOrder, ale jest blisko.

public class MyClassTest {
  @Test public void londonStateOfMind() {
    Foo foo = Mockito.mock(Foo.class);
    Bar bar = Mockito.mock(Bar.class);
    Baz baz = Mockito.mock(Baz.class);

    String username = "username";
    String password = "password";
    UserDto userDto = new UserDto("token", username, 20);
    String avatarUrl = "avatarUrl";
    User user = new User(username, userDto.age, avatarUrl);

    Mockito.when(foo.signIn(username, password)).thenReturn(userDto);
    Mockito.when(baz.avatarUrl(username)).thenReturn(avatarUrl);

    MyClass myClass = new MyClass(foo, bar, baz);

    myClass.getAndSaveUser(username, password);

    InOrder inOrder = Mockito.inOrder(foo, bar, baz);
    inOrder.verify(foo).signIn(username, password);
    inOrder.verify(bar).saveToken(userDto.token);
    inOrder.verify(baz).avatarUrl(username);
    inOrder.verify(bar).saveUser(user);
  }
}

interface Foo {
  UserDto signIn(String username, String password);
}

interface Bar {
  void saveToken(String token);

  void saveUser(User user);
}

interface Baz {
  String avatarUrl(String username);
}

class MyClass {
  private final Foo foo;
  private final Bar bar;
  private final Baz baz;

  MyClass(Foo foo, Bar bar, Baz baz) {
    this.foo = foo;
    this.bar = bar;
    this.baz = baz;
  }

  void getAndSaveUser(String username, String password) {
    UserDto userDto = foo.signIn(username, password);
    bar.saveToken(userDto.token);
    String avatarUrl = baz.avatarUrl(username);
    bar.saveUser(new User(username, userDto.age, avatarUrl));
  }
}

I właśnie problemem jest to, że nie każdy się ucieszy i doceni. Wyższa instacja jest zadowolona z takich testów i je nagminnie naprawia zamiast przepisać na coś normalnego.

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