Design and implement a REST API using Hibernate/Spring/SpringMVC (or Spring-Boot) without frontend.
The task is:
Build a voting system for deciding where to have lunch.
- 2 types of users: admin and regular users
- Admin can input a restaurant and it's lunch menu of the day (2-5 items usually, just a dish name and price)
- Menu changes each day (admins do the updates)
- Users can vote on which restaurant they want to have lunch at
- Only one vote counted per user
- If user votes again the same day:
- If it is before 11:00 we assume that he changed his mind.
- If it is after 11:00 then it is too late, vote can't be changed
Each restaurant provides a new menu each day.
As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it (better - Swagger).
P.S.: Make sure everything works with latest version that is on github :)
P.P.S.: Assume that your API will be used by a frontend developer to build frontend on top of that.
- Сделай новый проект и добавляй туда из Topjava только то что нужно! Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!
- Рекомендую переписать проект современно: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки.
- Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.
- API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend)
Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок). Все свои вопросы, предложения и хотелки оформляйте отдельно (в read.me
например). Если делаете что-то сложнее простейшего случая (например, справочник еды) - обязательно напишите в read.me. Как и выбор стратегии кэширования.
Совершенство достигнуто не тогда, когда нечего добавить, а тогда, когда нечего отнять
Антуан де Сент-Экзюпери
- 1: Читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять
- 2: Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу. Самое худшее в коде - обращение в базу в цикле.
- 3: Тщательно считайте количество запросов в вашем API для отображения нужной информации
- 4: Учитывайте, что пользователей может быть ОООЧЕНЬ много, а админов - МАЛО
- 5: В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы приложения код, ничего лишнего:
- 5.1 НЕ надо делать разные профили базы и работы с ней
- 5.2 НЕ надо делать абстрактных контроллеров на всякий случай
- 5.3 НЕ надо делать классов репозиториев и сервисов, если там нет ничего, кроме делегирования
- 5.4 Из потребностей приложения (которую надо самим придумать) реализовывать только очевидные сценарии. То есть НИЧЕГО ЛИШНЕГО.
- 6: База Данных
- берите без установки (H2 или HSQLDB). Одну!! Ваше приложение должно сразу запуститься, без всяких настроек и переменных окружения
- сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе
- историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.
- при популировании добавте записи за сегодняшний день - now(), чтобы всегда были актуальные исходные данные
- таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово.
date
/timestamp
- зарезервированное слово, лучше избегать их при именовании
- 7: По возможности сделать JUnit тесты
- 8: Уделяйте внимание обработке ошибок
- 9: Делаем REST API в соответствии с концепцией REST (url в общем имеют вид
{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]
) - 10: Не смешивайте TO и Entity вместе. Лучше всего, если они будут независимыми друг от друга.
- 11: Не размещайте логику приложения и преобразования в TO в слое доступа к DB
- 12: Если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера)
- 13: Use for money in java app
- 14: Еще раз про hashCode/equals в Entity: не делайте сравнение по полям!
- 15: Название пакетов, имен классов для
model/to/web
достаточно стандартные (напримерmodel/domain
). НЕ надо придумывать своих собственных правил - 16: Используйте DATA-JPA (можно без лишней делегации, напрямую из сервиса/контроллера дергать Repository)
- 17: В DATA-JPA 2.x используются
Optional
. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйтеorElseThrow
) - 18: На topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются
- 19: Проверьте, не торчат ли из кода учебные уши topjava, типа
ProfileRestController.testUTF()
,AbstractServiceTest.printResult()
или закомментированныеJdbcTemplate
. Назначение этого проекта совсем другое - 20: ORM работает с объектами. В простейших случаях fk_id как поля допустимы, но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverflow в коде обязательна!
- 21: Проверьте, станет ли код проще с
@AuthenticationPrincipal
(урок 11, Доступ к AuthorizedUser). - 22: Обновление в базе делается через
update
, даже еслиdelete/insert
сократит java код на несколько строк - 23: Кэширование
- необязательно, но желательно. Чем проще реализация - тем лучше.
- тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные)!
- проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение).
- 24: Валидация
- желательна
- одних аннотаций недостаточно. Должны быть
@Valid/@Validation
- проверяйте входные данные при
create/update
в контроллерах! В TopJava этоValidationUtil.checkNew()/assureIdConsistent()
- 25:
readme.md
:- Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English)
- Требуемые примеры
curl
не прячьте, а пишите здесь! Оптимально - ссылка на Swagger. - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:)
- 26: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу!
- Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно
restorauntId
. - Сколько раз пришлось его вызвать API для типичного сценария (нарпимер посмотреть рестораны с едой на сегодня)?
- Сколько запросов к базе было сделано? Можно ли сократить (например с FETCH/Graph или через кэширование)?
- API ДОЛЖНО соответствовать принципам REST (см. ссылки выше)
- ОБЯЗАТЕЛЬНО: запустите
mvn test
- ошибок быть не должно - ОБЯЗАТЕЛЬНО: запустите приложение без всяких предварительных настроек (базы, переменных окружения, ..), лучше на другом компьютере. Должно запускаться!