Nazewnictwo:
- Nazwy pakietów z dużej litery - tego ogólnie nie robimy. Np. zamiast
com.example.carrentalsystem.Controllers powinno być com.example.carrentalsystem.controllers
- Nazywanie enumów od
E, np. ERole. Zazwyczaj pisze się RoleEnum, ewentualnie Roles (chociaż to dużo rzadsze).
- Korzystaj z camelCase i nie używaj podkreślnika w nazwach (np.
getBrand_Name() -> getBrandName())
Design:
- Brak warstwy serwisów, cała logika siedzi w kontrolerach
- Brak testów jednostkowych
- Z jakiegoś powodu
Rental.price jest Integerem, a nie Longiem, przy czym w samym kodzie jest sprawdzenie, czy przy liczeniu nowej ceny licznik się nie przekręci
- Używasz
LocalDate.now() zamiast oddzielnego serwisu do dat - takie coś utrudnia testowalność.
Kod:
- Dziwne nullchecki. Np.
Kopiuj
Brand brand;
if (brandRepository.findByName(carRequest.getBrand()) != null)
brand = brandRepository.findByName(carRequest.getBrand);
} else {
brand = brandRepository.save(new Brand(carRequest.getBrand()));
}
Oznacza to, że zawołasz bazę danych dwa razy - raz, żeby sprawdzić, czy dany brand istnieje, drugi - żeby przypisać. Nie ma to większego sensu i można napisać to tak:
Kopiuj
Brand brand = brandRepository.findByName(carRequest.getBrand());
if (brand == null) {
brand = brandRepository.save(new Brand(carRequest.getBrand()));
}
Albo jeszcze lepiej - użyć optionala:
Kopiuj
Brand brand = Optional.ofNullable(brandRepository.findByName(carRequest.getBrand()))
.orElseGet(() -> brandRepository.save(new Brand(carRequest.getBrand()));
Ewentualnie przerobić BrandRepository.findByName(String) tak, żeby zwracało Optional<Brand>. Tego typu rzeczy jest trochę w kodzie - to tylko jeden z przykładów.
- Ogólnie zacznij wydzielać kod do oddzielnych metod lub klas (to się łączy z poprzednim komentarzem o kontrolerach). Na przykładzie
RentalController.changeRentalInformation(EditCarRentalRequest):
Jest:
Kopiuj
public ResponseEntity<?> changeRentalInformation(@RequestBody @Valid EditCarRentalRequest request){
if(rentalRepository.existsById(request.getRentId())){
Rental rental = rentalRepository.getReferenceById(request.getRentId());
rental.setPrice(Math.toIntExact((ChronoUnit.DAYS.between(request.getStartDate(), request.getEndDate())+1) * rental.getCar().getPrice()));
rental.setStartDate(request.getStartDate());
rental.setEndDate(request.getEndDate());
rentalRepository.save(rental);
return new ResponseEntity<>("Rent details changed", HttpStatus.OK);
}
return new ResponseEntity<>("No rental found", HttpStatus.NOT_FOUND);
}
}
Napisałbym to mniej-więcej tak:
Kopiuj
public ResponseEntity<?> changeRentalInformation(@RequestBody @Valid EditCarRentalRequest request){
if(rentalRepository.existsById(request.getRentId())){
Rental rental = rentalRepository.getReferenceById(request.getRentId());
updateEntity(rental, request);
rentalRepository.save(rental);
return new ResponseEntity<>("Rent details changed", HttpStatus.OK);
}
return new ResponseEntity<>("No rental found", HttpStatus.NOT_FOUND);
}
}
private void updateEntity(Rental entity, EditCarRentalRequest request) {
entity.setPrice(Math.toIntExact((ChronoUnit.DAYS.between(request.getStartDate(), request.getEndDate())+1) * rental.getCar().getPrice()));
entity.setStartDate(request.getStartDate());
entity.setEndDate(request.getEndDate());
}
Oczywiście w tym przypadku może nie widać zbytnich korzyści z tego, ale już jeśli zrobisz coś podobnego przy CarController.editCar(EditCarRequest) to różnica będzie duża.
- Brak spójności - czasem sprawdzasz, czy encja istnieje w bazie danych przez
existsBy, czasem pobierając listę przez findAll i sprawdzając, czy są elementy, a czasem przez countBy.
- Brak spójności x2 - tj. w niektórych repozytoriach używasz
findById, a np. CarRepository ma już getCarById który robi praktycznie to samo