Pull to refresh
27
0
Вячеслав Чернышов @xpendence

backend.developer { java, kotlin }.in(Sber)

Send message

Вы правы, контроллер не выбрасывает исключение. Исключение выбрасывает сервис.

Для каждого архитектурного решения исключение будет обрабатываться по-своему. Для REST исключение обрабатывается в ExceptionHandler, который и выбрасывает любой необходимый статус. Для GraphQL будет свой обработчик. Но исключение как логический ответ будет одним для всех архитектурных решений.

Лучше писать маперы, чем костыли, коллега :)

подгрузить и проверить что она есть

Это уже бизнес-логика. Контроллер является лишь адаптером к внешнему интерфейсу. Вы сами решаете, нужно Вам выбрасывать исключение при отсутствии ресурса. Не контроллер.

Конечно. У Вас будет public-api со своими dto и websocket-api со своими или что-то вроде.

Согласен. Даже профессионал расслабляется, если нет давления снизу. Наличие в команде непрофессиональных коллег заставляет профессионала прилагать усилия, чтобы заставить их быть профессиональнее. А, как сказано в книге, больше всего пользы от обучения получает педагог.

Постоянное сопротивление непрофессиональных коллег держит профессионала в тонусе.

Конечно, можно. Ведь код не компилируется.

Да, Вы правы. В заголовке уже было разъяснение, что такое CL, но раз Вы там не заметили, значит, лучше продублировать в самой статье, что я и сделал.

Да ну оставьте, какое синтаксическое дерево! Попросите Идею построить Вам, к примеру, диаграмму таблиц базы данных / библиотек зависимостей. Идея построит Вам абсолютно нечитаемую конструкцию. А теперь представьте, как эта диаграмма перебалансируется при добавлении каждого элемента, меняя местами элементы, и начинает жутко тупить, когда количество элементов превышает пару десятков (как начинают тупить динамически изменяемые конструкции любого графического интерфейса). Читаемый код значительно удобнее.

Коллега, набирая комментарий, Вы ведь тоже не поленились расставить предложения в правильном порядке и запятые в нужных местах. Потому что ожидаете, что Ваш комментарий прочтут, и читатель должен правильно уловить смысл написанного.

Так и с кодом - разработчики не только пишут код, но и читают - причём, читают гораздо чаще, чем пишут. Поэтому, код должен быть не только грамотно структурирован, но и написан в соответствии с определёнными правилами. Чтобы легко ориентироваться в приложении и быстро читать код, правильно понимать его смысл.

Конечно, давно уже существуют инструменты форматирования кода и предикативного ввода программных компонентов (классов, методов и проч.) - и все мы активно ими пользуемся. Но для того, чтобы грамотно ими пользоваться, мы должны точно понимать, что мы хотим увидеть на мониторе. Что поделать, грамотность никто не отменял.

Ок. ответвились от master, но вливаться из bug в master ? совсем без тестирования? не выглядит безопасным. А поскольку про тесты на feature|bug ветках вы не рассказывали, то я бы рекомендовал все таки путь "master->bug->test->master" чтобы путь релиза "test-master" не нарушался.

Да, согласен, но есть момент. Тестировать что-то на IFT в таком случае имеет смысл, если баг воспроизвёлся на IFT. Если баг на IFT не воспроизводится, тогда мы в любом случае не сможем протестировать его исправление, и максимум, что мы сможем сделать - это регресс на IFT после исправления. Тогда подойдёт путь master -> bug -> master -> test -> регресс на тесте -> релиз в мастере. На целостность кода это, по сравнению с Вашим способом, не повлияет, но путаницы будет немного меньше, чем возврат ветки bug к родителю через другую ветку.

"спринт В уже хочет на test, но там еще результаты спринта Б, который проверен на 80% и ожидается, что установка на prod через N дней допустим". Что делаете?

Ситуация знакомая :) Но тут всё просто. Спринт В может захотеть на тест только после а) выполнения всех задач спринта б) успешного тестирования на деве в) code freeze. Если команда находится на этапе отладки предыдущего спринта, а Вы уже сделали все задачи следующего, значит, Вы недооценили свои силы на спринт :) Что ж, попросите добавить в свой скоуп на спринт ещё задач :)

"спринт Б установлен на test, и в тот же день приходит critical-bug с prod от спринта А"

Хорошо, если можно вернуть стенд в состояние спринта А и воспроизвести баг на IFT, но, к сожалению, не каждый в каждом случае спринт можно откатить до состояния предыдущего релиза, да и стоимость такого отката может превышать профит от починки такого бага. git flow в любом случае будет master -> bug -> master; далее, в зависимости от состояния IFT, или регресс на IFT, или скользкая дорожка внепланового релиза на прод без регресса (тестируем на проде), после успешного исправления бага master -> test -> develop. К сожалению, такое тоже бывает.

Все примеры в посте написаны при помощи UNIT-тестов.

На этапе разработки, падение приложения, конечно, предпочтительнее. Тестировщик сразу лезет в логи и заводит багу на разработчика. В этом и смысл fail-fast! В продакшене же, конечно, приложение не должно упасть. Оно должно собрать все данные об ошибке, отправить их куда надо, а пользователю вывести сообщение, что данная фича сейчас недоступна. Короче говоря, fail-safe! - это fail-fast! + бизнес-обёртка для минимизации ущерба.

Почему же, fail-fast! - это, в первую очередь, о системе, которая останавливает свою работу при возникновении ошибки, с прекращением всякой бизнес-логики. И не более. Обработка ошибки с последующим логированием стектрейса, возвращением негативного HTTP-статуса и прочей фиксацией ошибки могут быть заложены при прекращении бизнес-логики на системном уровне (тот самый случай "громкого падения"). При этом, бизнес-логика при негативном сценарии не осуществляется.

Принцип же fail-safe! подразумевает именно бизнес-логику при негативном сценарии. В этом и их различие.

Приведу пример. Клиент стучится на сервер за данными и не получает их. При реализации fail-fast! на экране пользователя возникает сообщение об ошибке, что-то вроде "HTTP Status 500: java.util.NoSuchElementException: Document not found..." и так далее. При этом, приложение упало как можно громче, с логами, аварийными записями в базу и так далее - но оно именно упало и больше ничего. Пользователь видит сообщение, морщится, но ничего, стерпит.

В случае же применения fail-safe! произойдёт такое же громкое падение с логами и прочим, но на клиент будет возвращено сообщение: "Спокойно, нет поводов для паники, мы не можем отыскать сервер, но обязательно его отыщем! Приходите завтра." Во втором случае, в негативный сценарий заложена дополнительная бизнес-логика, которая призвана сгладить пользователю негативный эффект.

А так, конечно, Вы правы - приложение должно падать как можно громче, причём, всегда.

Да, конечно. Основной скрин регистрации бота на английском, других скринов я что-то не увидел, кроме тех, где ты запустил приложение. Но к написанию статьи это никакого отношения не имеет.

по-английски call - это и звонок, и вызов. просто "автор" спёр откуда-то статью на английском, криво перевёл в гугл-переводчике и выдал за свою

Вы хотите, чтобы я выкатил неподготовленному читателю в ознакомительной статье о SOLID формулировку от Барбары Лисков? Вы жестокий человек :)
Да, так и есть.
Нет, не проще. И уже на следующий день не понятнее. Попробуйте чистую архитектуру. Уверен, Вам понравится. Ничего хитрого там нет.
main является компонентом самого низкого уровня.

Компонент Main — это конечная деталь, политика самого низкого уровня.
Он является точкой входа в систему. От него ничего не зависит, кроме работоспособности системы. Его задача — создать все Фабрики, Стратегии
и другие глобальные средства и затем передать управление высокоуровневым абстракциям в системе.


Роберт Мартин, «Чистый код».

Я думал, Вы про микросервисы, к примеру.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Works in
Date of birth
Registered
Activity

Specialization

Backend Developer
Lead
Java
Kotlin
Clean Architecture
Designing application architecture
System analytics