Confitura 2015 - Code Quality Keepers @ Allegro

49
Code Quality Keepers opowieści z pola bitwy o jakość kodu Rafał Głowiński, Bartosz Walacik Confitura 2015

Transcript of Confitura 2015 - Code Quality Keepers @ Allegro

Page 1: Confitura 2015 - Code Quality Keepers @ Allegro

Code Quality Keepersopowieści z pola bitwy o jakość kodu

Rafał Głowiński, Bartosz WalacikConfitura 2015

Page 2: Confitura 2015 - Code Quality Keepers @ Allegro

O nas

Rafał Głowiński @GlowinskiRafal

Bartosz Walacik @BartoszWalacik

http://javers.org

Page 3: Confitura 2015 - Code Quality Keepers @ Allegro

O czym będziemy mówić

Pytania:

→ Jak dbać o jakość kodu w zespole? Code review?

→ A co jeśli mamy 40+ zespołów?

→ Jak zadbać o jakość na poziomie całej organizacji?

Page 4: Confitura 2015 - Code Quality Keepers @ Allegro

O czym będziemy mówić

Opowiemy:

→ Po co CQK?

→ Jak zdefiniować kryteria jakości i ocenić kod różnych zespołów

→ Jak robimy prawdopodobnie największe Code Review w Polsce

→ Co udało nam się znaleźć: “perełki”, typowe błędy

→ A także… co udało nam się osiągnąć

Page 5: Confitura 2015 - Code Quality Keepers @ Allegro

→ 40+ zespołów (dev + infra)

Zespoły w Allegro

→ 4 miasta (Poznań, Toruń, Warszawa, Kraków)

→ Często doświadczenie głównie w PHP

→ Większość pisze i utrzymuje mikrousługi na JVM

Page 6: Confitura 2015 - Code Quality Keepers @ Allegro

Jak powstało CQK i po co?

Pierwszy skład zespołu CQK:

→ doświadczeni inżynierowie

→ zaangażowani w community

→ autorytet nie hierarchia

→ kilka osób myślących podobnie, startup

Page 7: Confitura 2015 - Code Quality Keepers @ Allegro

Jak powstało CQK i po co?

Pierwszy Cel:Przejrzeć i ocenić (w miarę) obiektywnie cały kod

Pierwsze review:→ 1 dzień w 1 salce

→ kilkadziesiąt projektów do przejrzenia

→ 15 minut na projekt (!)

→ totalna partyzantka

Page 8: Confitura 2015 - Code Quality Keepers @ Allegro

Jak powstało CQK i po co?

Wnioski z pierwszego review:→ 15 min na projekt to za mało

→ potrzebna jest metodyka i organizacja

→ koncentracja na wybranych aspektach

Nowe Cele:→ Cel 1: podnoszenie jakości kodu w całej organizacji

poprzez review, feedback i mentoring

→ Cel 2: wkład do ocen technicznych zespołów

Page 9: Confitura 2015 - Code Quality Keepers @ Allegro

Jak pracujemy

→ Zaczęliśmy od garstki osób, teraz jest nas więcej

→ Co kwartał zmieniamy metodykę review

→ Merytoryczny feedback

→ Przejście na tryb “push”

Page 10: Confitura 2015 - Code Quality Keepers @ Allegro

Metodyka review: pierwszy kwartał

“Wrażenia artystyczne”(15 min na projekt…)

Page 11: Confitura 2015 - Code Quality Keepers @ Allegro

Metodyka review: drugi kwartał

Duże i częste naruszenia podstawowych zasad

Są błędy, ale generalnie jest ok

Jest dobrze!

Page 12: Confitura 2015 - Code Quality Keepers @ Allegro

Magic Servlet Antipattern is Back:→ logika biznesowa/dostęp do repozytorium w kontrolerze

→ nieprawidłowe wykorzystanie frameworków (np. ręczne

mapowanie wyjątków na kodu HTTP)

Metodyka review: drugi kwartał

Zwięzłość i czytelność testów:→ struktura testów, prawidłowe wykorzystanie bibliotek

→ co testują testy

→ mocks (overmocking, mockowanie nie swoich klas)

Page 13: Confitura 2015 - Code Quality Keepers @ Allegro

Szkolenia: trzeci kwartał

→ Naming i omówienie bytów w testach (Stub, Mock, Spy)

→ Spock: Data Driven, wyjątki, asercje, Groovy

→ (*) JUnit: Mockito, AssertJ, JUnitParams, catch-exception

→ Overmocking + verify = betonowy kod

→ Testy integracyjne: bazy danych, REST

Page 14: Confitura 2015 - Code Quality Keepers @ Allegro

Zwięzłość i czytelność testów cd.

Metodyka review: aktualnie

Model domenowy:

→ klasy modelu

→ organizacja pakietów

→ powiązanie z bibliotekami / infrastrukturą

Page 15: Confitura 2015 - Code Quality Keepers @ Allegro

Metodyka review: aktualnie

Model domenowy:

brak modelu domenowego: mutowalne & anemiczne POJO

operujące na nich klasy Service

Page 16: Confitura 2015 - Code Quality Keepers @ Allegro

Metodyka review: aktualnie

Model domenowy:

kod jest podzielony horyzontalnie

domena powiązana z infrastrukturą (zapytania do baz danych, skomplikowane logowanie/monitoring, itp.)

widać starania odejścia od anemiczności modelu (rozsądne podejście do mutowalności, obiekty zyskują funkcjonalności)

Page 17: Confitura 2015 - Code Quality Keepers @ Allegro

Metodyka review: aktualnie

Model domenowy:

ładny model domenowy zgodny z OOP

struktura pakietów zorientowana domenowo

domena jest wyraźnie odseparowana od infrastruktury

podział pakietowy zgodnie z wytycznymi np. Hexagonal

Architecture

Page 18: Confitura 2015 - Code Quality Keepers @ Allegro

Eksperyment: review kodu JS

Opowiemy o tym za rok ;)

Page 19: Confitura 2015 - Code Quality Keepers @ Allegro

Główna działalność CQK

Tworzenie feedbacków dla zespołów

→ Zespół zgłasza do feedbacku projekt lub PR

→ Przeciętny projekt ma ~10KLOC

Page 20: Confitura 2015 - Code Quality Keepers @ Allegro

Co to jest feedback

Kilkustronicowy dokument na WIKI, lista punktów, np:dobre testy integracyjne (np BlacklistEndpointIntegrationSpec.groovy)

SalesRegulationsFilterTest.java - do testu tego rodzaju prostych funkcji używajciepodejścia data-driven test

Klasa Pdf.java mogłyby być immutable, czyli zamiast:Pdf pdf = new Pdf();

pdf .setContent(documentContent);

lepiejPdf pdf = new Pdf (documentContent);

długa implementacja equals() w BlacklistRequest.java. Łatwo się pomylić w takim kodzie. Czy ten equals() jest do czegoś potrzebny?

Page 21: Confitura 2015 - Code Quality Keepers @ Allegro

Fazy życia feedbacku: koszt os./h

I. Review kodu + spisanie 2-3II. Weryfikacja 1-2III. Publikacja i uwagi od zespołu 1IV. Przepracowanie w zespole 0

Jak powstaje feedback

Page 22: Confitura 2015 - Code Quality Keepers @ Allegro

Faza I. Review kodu + spisanie uwag

→ Keeper klonuje repo i ogląda kod

→ Nie uruchamiamy tooli do statycznej analizy

→ Keeper tworzy dokument feedbacku i proponuje ocenę

Jak powstaje feedback

Page 23: Confitura 2015 - Code Quality Keepers @ Allegro

Faza II. Weryfikacja

→ Drugi Keeper przegląda feedback (kontrola merytoryczna)

→ Przy rozbieżnościach - uzgadniamy w ramach CQK

→ Kontrola czy feedback jest friendly

→ Drugi Keeper często dopisuje swoje uwagi

→ Approve

Jak powstaje feedback

Page 24: Confitura 2015 - Code Quality Keepers @ Allegro

Faza III. Publikacja i uwagi od zespołu

→ Feedback jest przekazywany do zespołu

→ Zachęcamy zespół do ustosunkowania się do feedback’u

Czy modyfikujemy feedback?

→ Świadome i uzasadnione naruszenia reguł

→ My czegoś nie zrozumieliśmy (brak kontekstu)

Jak powstaje feedback

Page 25: Confitura 2015 - Code Quality Keepers @ Allegro

Faza IV. Przepracowanie feedbacku w zespole

Mamy nadzieję, że zespół przekona się do naszych uwag i propozycji

Jak powstaje feedback

Page 26: Confitura 2015 - Code Quality Keepers @ Allegro

Co znaleźliśmy - big picture

Page 27: Confitura 2015 - Code Quality Keepers @ Allegro

Co znaleźliśmy - big picture

Page 28: Confitura 2015 - Code Quality Keepers @ Allegro

Główne grzechy:

→ TDD - Test Driven Development

→ Anemic Domain Model

Co znaleźliśmy - big picture

Page 29: Confitura 2015 - Code Quality Keepers @ Allegro

TDD - problemy:

→ Overmocking→ Mocking What-You-Don’t-Own→ Testy są kopią implementacji→ Za mało testów integracyjnych→ Testy pisane pod Coverage→ Testy bez wartości dokumentacyjnej→ Testowanie implementacji a nie funkcjonalności

Co znaleźliśmy - big picture

Page 30: Confitura 2015 - Code Quality Keepers @ Allegro

Anemic Domain Model

→ Anemiczne, mutowalne Encje→ Settery i gettery rządzą→ Programowanie proceduralne nie obiektowe→ Często w ogóle brak wydzielonego Modelu Domenowego

Co znaleźliśmy - big picture

Page 31: Confitura 2015 - Code Quality Keepers @ Allegro

Test unitowy prostego konstruktora

Co znaleźliśmy - ‘perełki’

Page 32: Confitura 2015 - Code Quality Keepers @ Allegro

public class ClientException extends RuntimeException {

static final long serialVersionUID = -712897190232112939L;

public ClientException(String message) {

super(message);

}

public ClientException(String message, Throwable cause) {

super(message, cause);

}

}

src

Page 33: Confitura 2015 - Code Quality Keepers @ Allegro

@Test

public void shouldSetMessageAndCauseInConstructor() {

//given

String exceptedMessage = "Very bad exception";

Exception expectedCauseException = new Exception("This is cause exception");

//when

ClientException exception = new ClientException(exceptedMessage, expectedCauseException);

String message = exception.getMessage();

Throwable causeException = exception.getCause();

//then

assertEquals(exceptedMessage, message);

assertEquals(expectedCauseException, causeException);

}

test

Page 34: Confitura 2015 - Code Quality Keepers @ Allegro

Nie testuj unitowo prostych konstruktorów oraz

metod

CQK radzi

Page 35: Confitura 2015 - Code Quality Keepers @ Allegro

Test unitowy Serwisu-przelotki

Co znaleźliśmy - ‘perełki’

Page 36: Confitura 2015 - Code Quality Keepers @ Allegro

public class SaleRegulationsService {

public List<SaleRegulations> findRegulations(String userId, Long timestamp) {

List<SaleRegulations> results;

if (timestamp == null) {

results = salesRegulationsRepository.findOneByUserId(userId);

} else {

results = salesRegulationsRepository.findByUserId(userId);

}

return results;

}

...

}

src

Page 37: Confitura 2015 - Code Quality Keepers @ Allegro

@Test

public void shouldReturnMoreResultsWhenTimestampIsGiven() {

// given

SaleRegulationsService saleRegulationsService = new SaleRegulationsService(salesRegulationsRepository, eventProducer);

SaleRegulations saleRegulations1 = new SaleRegulations(USER_ID, SALE_REGULATIONS_TEXT, TIMESTAMP);

SaleRegulations saleRegulations2 = new SaleRegulations(USER_ID, SALE_REGULATIONS_TEXT_VERSION_2, TIMESTAMP2);

List<SaleRegulations> results = new ArrayList<>();

results.add(saleRegulations1);

results.add(saleRegulations2);

when(salesRegulationsRepository.findByUserId(USER_ID)).thenReturn(results);

// when

List<SaleRegulations> regulations = saleRegulationsService.findRegulations(USER_ID, TIMESTAMP);

// then

assertThat(regulations.size()).isEqualTo(2);

assertThat(regulations.get(0)).isEqualTo(saleRegulations1);

...

test

Page 38: Confitura 2015 - Code Quality Keepers @ Allegro

Nie testuj unitowo metod typu przelotka.

Testuj integracyjnie, używając Embedded (lub Fake) DB

CQK radzi

Page 39: Confitura 2015 - Code Quality Keepers @ Allegro

Overmocking

Co znaleźliśmy - ‘perełki’

Page 40: Confitura 2015 - Code Quality Keepers @ Allegro

@RunWith(MockitoJUnitRunner. class)

public class CreateEndpointTest {

@Mock

private RefundsSoapBindingStub npRefundService;

@Mock

private RefundsClient refundsClient;

@Mock

private PayuOrders payuOrders;

@Mock

private SignatureFactory signatureFactory;

@Mock

private RefundInfo refundInfoMock;

...

test

Page 41: Confitura 2015 - Code Quality Keepers @ Allegro

unikaj Mocków z verify(), to betonowanie kodu

CQK radzi

Page 42: Confitura 2015 - Code Quality Keepers @ Allegro

Konkurs Allegro

Kod: 5mSG5t

Page 43: Confitura 2015 - Code Quality Keepers @ Allegro

Najczęstsze błędy

Wstrzykiwanie zależności: pola vs konstruktor:

→ Jasna deklaracja kolaboratorów

→ Rozróżnienie opcjonalnych zależności

→ Łatwiejsza konstrukcja obiektów w testach

Page 44: Confitura 2015 - Code Quality Keepers @ Allegro

Najczęstsze błędy

Niemutowalność:

“Classes should be immutable unless there's a very good

reason to make them mutable....If a class cannot be made

immutable, limit its mutability as much as possible.”

Joshua Bloch, Effective Java

Page 45: Confitura 2015 - Code Quality Keepers @ Allegro

Najczęstsze błędy

Mockowanie nie swoich rzeczy:(a.k.a: Don’t mock what you don’t own)

→ zmiany poza naszą kontrolą

→ podwójnie kosztowne (test / prod)

Page 46: Confitura 2015 - Code Quality Keepers @ Allegro

→ przekonaliśmy zespoły do zewnętrznego review

→ konwencja: should + given/when/then

→ przekonaliśmy większość zespołów do Spocka

→ zespoły piszą coraz lepsze testy integracyjne

→ Overmockingu mniej

→ zdecydowanie widać poprawę ogólnej jakości kodu

Sukcesy

Page 47: Confitura 2015 - Code Quality Keepers @ Allegro

→ review w ramach jednego zespołu często nie wystarcza

→ potrzeba systematyczności - jednorazowy zryw to za mało

→ otwartość na feedback

→ cierpliwość - efekty nie przyjdą od razu

Wnioski

Page 48: Confitura 2015 - Code Quality Keepers @ Allegro

Q/A?

Page 49: Confitura 2015 - Code Quality Keepers @ Allegro

Znajdziesz nas:Blog: allegrotech.io

Twitter: @allegrotechblog

pracuj z namikariera.allegro.pl