Conversation
MateuszRasinski
left a comment
There was a problem hiding this comment.
Na plus: zrealizowano funkcjonalność rezerwacji wraz z walidacją miejsc. Dobry interfejs, zmapowane wyjątki, pieniądze w BigDecimal. Widać, że lubisz się i dobrze sobie radzisz z SQLem.
Na minus: brak testu przynajmniej happy path (chociaż jest w bashu, więc tyle dobrze). Pakiety dzielone horyzontalnie (po warstwach technicznych) zamiast wertykalnie (po domenie biznesowej, funkcjonalnościach). Uboga domena, wszystko dzieje się proceduralnie i głównie po stronie bazy danych. Wszystko oprócz walidacji miejsc, która jest bardzo skomplikowana i nieczytelna.
Proszę, nie poprawiaj kodu, ale odnieś się do komentarzy. Dzięki!
| @PostMapping | ||
| public ShortReservationDTO postReservation(@RequestBody ReservationPostDTO postDTO) { | ||
| Reservation reservation = mapper.toReservation(postDTO); | ||
| return mapper.toShortReservationDTO(service.saveReservation(reservation)); |
There was a problem hiding this comment.
nie jestem fanem mapperów, ale spoko. Generalnie do service'u mogłoby przyjść DTO i mogłoby być zwrócone DTO i byłoby OK
| private String director; | ||
|
|
||
| @Basic | ||
| private java.time.LocalTime length; |
There was a problem hiding this comment.
Nie wiem o który import tutaj chodzi, prawdopodobnie o import static. Słyszałem, że dobrą praktyką jest import statyczny tych stałych (zwłaszcza gdy w jednej adnotacji może ich występować więcej). A adnotacja @basic to chyba pozostałość po wcześniejszych wersjach springa, ogólnie wzorowałem się na: https://www.baeldung.com/hibernate-date-time a tam pola oznaczone są tą adnotacją. W springu 5 działa dobrze już bez tej adnotacji.
There was a problem hiding this comment.
Chodziło mi o to, że tą klasę LocalTime można zaimportować i nie mieć kropeczek wtedy (java.time można się pozbyć)
|
|
||
| import lombok.Data; | ||
|
|
||
| import javax.persistence.*; |
There was a problem hiding this comment.
importy z gwiazdkami nie są preferowane - dobre IDE i tak ci je schowa, a jak chcesz zobaczyć jaka klasa jest importowana to tak nie zobaczysz :(
There was a problem hiding this comment.
Nie wiedziałem o tym, ale to kwestia ustawień IDE. Teraz już będę pamiętał
| private Room room; | ||
|
|
||
| @Column(name = "is_on_edge") | ||
| private Boolean isOnEdge; |
There was a problem hiding this comment.
ciekawa koncepcja. A bez tego by się dało? I bez dodatkowej tabelki złączeniowej?
There was a problem hiding this comment.
Przyjąłem dodatkowe założenie, że miejsce na skraju może być zawsze zarezerwowane( Przy samym założeniu, że nie można zostawić jednego miejsca wolnego byłby problem z rezerwacją tego miejsca na skraju [ REZERWOWANE, WOLNE, ZAJĘTE, .... ]. Wtedy nie musimy sprawdzać sąsiednich miejsc. To pozwala również na układ sali taki, że np. na środku sali może być przejście, wtedy mamy kolejne miejsca na skraju. ) Stąd ta zmienna isOnEdge. Z kolei obeszło by się bez tabelki złączeniowej, po prostu wrzucić numer rzędu i siedzenia do tej klasy.
|
|
||
| private String typeName; | ||
|
|
||
| private BigDecimal price; |
| } | ||
| }); | ||
| return seats; | ||
| } |
There was a problem hiding this comment.
dlaczego to nie jest w jakiejś klasie? abstrakcji zamykającej salę kinową?
There was a problem hiding this comment.
Tak, tutaj można by to opakować w abstrakcje, jakiś typ generyczny implementujący interfejs do pobierania danych zamiast RoomSeat
| } | ||
|
|
||
| return true; | ||
| } |
There was a problem hiding this comment.
ta klasa ma tyle ifów i switchów, że nigdy nie chciałbyś takiej reviewować / utrzymywać.
There was a problem hiding this comment.
Sporo ifów się zrobiło z powodu iterowania po liście po sąsiednich miejscach (nie zawsze występują w sąsiedztwie dwa na lewo i dwa na prawo jak w ogólnym przypadku). Nie zastosowałem listIterator, ponieważ po wywołaniu next() lub previous() zmienia się index wskazywanego elementu, a tutaj było to niepożądane.
|
|
||
| private boolean hasNext(List<SeatModel> neighbourhood, int index) { | ||
| return index + 1 < neighbourhood.size(); | ||
| } |
There was a problem hiding this comment.
te 4 metody wyglądają jakby zawsze dotyczyły tego samego. Może można by je zamknąć w jakiejś jednej klasie? Jest coś takiego jak programowanie obiektowe.
There was a problem hiding this comment.
Racja, mogłem to opakować, ewentualnie zamienić na abstrakcję z typem generycznym
| import static org.junit.runners.Parameterized.Parameters; | ||
|
|
||
| @RunWith(Enclosed.class) | ||
| public class SeatValidationServiceTest { |
There was a problem hiding this comment.
jeżeli miałbyś napisać jeden test, to jaki byłby to test? Test tego, że osoba wyświetla filmy, wybiera sens, dokonuje rezerwacji i system tą rezerwację przyjmuje; czy testy walidacji zajętych miejsc?
There was a problem hiding this comment.
Przyznaję, że brakuje tutaj testów use casów (same w sobie zawierałyby kilka testów rezerwacji miejsc). A test napisany z powodu dużej ilości kombinacji ustawień siedzeń, ciężkie do sprawdzenia w sposób ręczny.
Więc jeśli miałbym wybierać to test use case - sprawdza więcej elementów.
|
|
||
| @Test | ||
| public void test_validate_good() { | ||
| assertTrue(service.validate(reserved, occupied, all)); |
There was a problem hiding this comment.
Tutaj kwestia nazewnictwa - te metody mogłyby nazywać się lepiej oraz brakuje wyrównania parametrów w metodach
Screening room seats arrangement