Pull to refresh
-3
0

Пользователь

Send message

Ну что вы, в 5 классе что ли. Текст редактируется с клавиатуры. Фотошоп рисуется мышкой или графическим планшетом. Порнхаб нажимается мышкой.


Не все задачи сводятся к редактированию текста, даже если ограничиться программированием. Моя подколка не столько про сам vim, сколько про непонимание — нахрена в гитхаб ходить из консоли, если ты сам не скрипт на баше.

Вы вроде год уже на хабре — неужели первый раз обратили внимание?

Версия на самом деле называется 1.0.0 и праздник тут в том, что это "первый мажорный релиз" (https://semver.org/)

Я не фанат Go и у меня тоже есть мнение "как надо". Но какая разница на чём эти ребята делают свой тул?

Вы может ещё и vim используете?

Да я шучу. Смешно просто "полностью на Go".

git — это git, а gh — это если вам через броузер на гитхаб ходить западло.

Не обратил внимания, когда читал. Прямо полностью? Кто-то из знающих может подтвердить?

Ну это как раньше некоторые вместо "логика" всегда говорили "бизнес-логика", теперь вместо "сервис" говорят "микросервис".

Общий случай — это когда логика принятия решения "можно ли" требует знания тех же деталей, которые нужны для совершения самой операции.

Можно-то можно, но не понятно зачем.


@PutMapping("/comments/{id}")
@PreAuthorize("canPutComment(commentId, userId)")
public ResponseEntity<?> putComment(@PathVariable("id") commentId) {
  ...
}

Т.е. canPutComment() должен будет уметь загружать коммент, т.е. там будет вся эта логика — если коммент есть, то сравниваю автора с текущим пользователем, если коммента нет, то разрешаю, потому что создаётся новый. Аналоничная логика также будет и в putComment() — попытаться найти коммент, если он есть то редактируем, если нет, то создаём. А добились-то чего этим разделением?

В общем случае — нет. Spring Security — это скорее про аутентификацию и роли — когда хочется сказать "если не админ, то точно нет". Логика типа "если вы не друзья с Бобби и у вас нет общих друзей, то фотку Бобби мы вам 403" намного органичнее пишется "прямо по месту".

  1. Оставляем контроллеры тонкими


@GetMapping
public OperationDto getOperationById(@PathVariable("id") Long id) {
  return operationService.getById(id);
}
...
public OperationDto getById(Long id) {
    Optional<Operation> operationOptional = ... //логика получения operation
    return operationOptional
        .map(operation -> mapperFacade.map(operation, OperationDto.class))
        .orElse(EMPTY_OPERATION_DTO);
}

  1. Обычно контроллеру нужно больше контекста, чтобы дать хороший ответ. Нашлось там что запрашивали и есть доступ — 200, нашлось, но нет доступа — 403, не нашлось — 404.
  2. Многие REST API позволяют потребителю указать набор полей, которые он хочет получить: ?fields=id,name. Это знание можно использовать чтобы построить более оптимальный запрос для вытягивания данных из БД (не делать лишний join например).
  3. В случае ресурсов-коллекций конечно же потребитель хочет фильтровать: GET /orders?filter=date<2019-01-01, сортировать: GET /orders?sort=date, и паджинацию: GET /orders?skip=10&take=100. И конечно это всё вместе тоже GET /orders?filter=date<2019-01-01&sort=date&skip=10&take=100&fields=id,name.
  4. PUT (который "создать или обновить") тоже свои нюансы добавляет — там и тривиальная валидация ("name" не может быть пустым) — 400, и "глобальная" ("name" обязано быть уникальным) — 409, и разница между 201 created и 204 no content.
  5. Аж уж PATCH так вообще.

Моё мнение такое, что если делаешь "REST API фасад к сервису", совершенно всё равно как это делать — получится нечто жёсткое и нерасширяемое (но этого вполне может хватать). Если делаешь "REST API", то лучше с самого начала код писать в терминах моделей HTTP-ресурсов, маппингов между полями данных в API и полями/таблицами в БД.

REST сервис вообще должен выставлять данные как данные, а не что там дизайнеры понапридумывали в очередной версии аппликейшна. Если важно дать потребителям возможность уточнять "вот это мне надо, а вот это — нет", API должен позволять указывать всякие fields=id,name&filter=age>20.


А наделять API знанием о том, что бывают веб клиенты, а бывают — мобильные, это по-моему кривизна дизайна. Ну или можно не называть это словом REST просто.

url=settings.SHORTER_URL,
headers={'Authorization': self.api_key},

Каким образом вы принимаете решение, что SHORTER_URL берётся из settings, а api_key — из self?

Питон гениален: просто подсунуть другой обьект requests с таким же методом post

Каким образом этот "другой объект requests" передать в shorten_link если этот самый shorten_link — мне не принадлежит? Какой-то финт с манки-патчем импортов? Или код, который вы постите, пока к этому не готов — и нужно добавить ещё один параметр у shorten_link?


Как вы задокументируете, что ваш API принимает "другой объект requests с методом post"? Будучи насколько-то знакомым с библиотекой requests, я предположу, что там такой же космос возможных параметров у одного этого метода — вы их все потребуете поддерживать, или возьмётесь писать простыню текста, которая рассказывает, что в принципе нужны только хедеры, а content-type всегда application/json, и т.д.?


По-моему то, что вы пишете — крайне неудачные идеи. Код совсем не прячется за интерфейсом ("принимаю какие-то параметры, возвращаю какой-то результат") — хочешь меня использовать, изучай что я делаю внутри.

Вы путаете гибкость и "всё мясо наружу":


  1. Почему у вас URL настраивается, но метод запроса POST прибит гвоздями?
  2. Каким образом в запрос добавить свои хедеры?
  3. Если я не хочу использовать requests, как подключить туда свою библиотеку?

В мире Java это традиционно делается через какие-нибудь там RequestFactory и RequestExecutor, которые пользователь при желании может реализовать самостоятельно. И там уж хоть кукис в запрос добавляй в RequestFactory, хоть retry логику реализовывай в RequestExecutor — полная свобода. А у вас просто мясо наружу.

ещё один из питонических подходов был бы:
def shorten_link(self, *args, **kwargs):
не зависящий от интерфейса.

Это прекрасно. Как вообще угадать что в этот shorten_link нужно передать при вызове?

Проблема — не в факте кривизны использования, а в количестве переиспользований, которые надо проверить за раз.

Не получается понять что всё-таки вы имеете в виду под этой необходимостью "проверять много переиспользований". Это какая-то ручная работа?


Меньше кода — проще понять.

Так ведь его не меньше, его как минимум столько же. Только теперь вместо "Ctrl+click, Ctrl+click, Ctrl+click, о, всё понятно" это превращается в: "а, тут мы дёргаем другой сервис, окей, пошёл смотреть его код".


Перейти на мажорную версию, поправив 10 строчек — легко. Перейти на мажорную версию, поправив 1000 строчек — кошмар.

Я понял, вы имеете в виду: "с микросервисами моя задача, как разработчика, вероятно, будет ограничина одним микросервисом".


В нашем флоу, разработчик делает задачи, и ничего не знает о релизах — так что ему всё равно, сделать правку в одном сервисе, или в двух.

Вы в статье написали: "часто возникают задачи с непонятной сферой ответственности", а теперь "ему всё равно, сделать правку в одном сервисе, или в двух". Как монолитность-микросервисность влияет на владение кодом?


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

Вы удивительным образом одновременно делаете громкие заявления о мониторинге и тут же изолируетесь от него, указывая, что есть некие отдельные девопсы и это их головная боль :-) Приходят все метрики из разных частей одного монолитного сервиса или из совершенно разных сервисов — разницы нет. При монолитном подходе точно так же можно навешать измерялок на любые интересные части кода и мониторить их не "в среднем", а по-отдельности. Это же не какая-то магия, которая у микросервисов есть, а у монолитов нет.

"1. Боль в монолите", кажется, имеет мало отношения к монолитности.


и если была возможность использовать его криво — то она не была упущена.

Это проблема культуры разработки: "использовать криво" — это про людей, а не про монолиты.


Любое действие может вызвать абсолютно непредсказуемые эффекты, и не все из них отслеживаются

Это проблема дизайна: как сделать так, чтобы глядя на код было очевидно какие эффекты он вызывает. Микросервисы эту проблему вообще никак не адресуют.


Хочешь Express? Линтер? Другой фреймворк для тестов или моков? Обновить валидатор или хотя бы lodash? Обновить Node.js? Извини. Для этого придётся править тысячи строк кода.

В команде кто-то пишет код, который работает только на одной версии lodash? А виноват снова монолит? :-) Понятно, что переходы на новые мажорные версии могут вызывать проблемы, но эти проблемы точно так же возникают и у микросервисов.


Что приводит к тому, что в релизе может быть по 60 задач и больше. такое количество вызывает мердж конфликты, внезапные синергетические эффекты, полную загруженность QA на разборе логов, и прочие печали.

Насколько я понимаю, процесс продиктован непредсказуемостью ("Любое действие может вызвать абсолютно непредсказуемые эффекты"). Т.к. микросервисы эту проблему даже не пытаются решить, не понятно в чём здесь виноват монолит.


Сложный контекстный поиск (не забывайте, у нас нет статической типизации)

Это проблема JS и к монолитам отношения не имеет. Тут даже наоборот — будь у вас статическая типизация, монолит делал бы любую работу с кодом проще, чем микросервисы.


Очень часто возникают задачи с непонятной сферой ответственности — например, в смежных библиотеках.

С технической точки зрения у микросервисов ещё хуже: если 80% задачи сводится к правкам в одном сервисе, возникает искушение остальные 20% засунуть в тот же сервис, даже если этому коду там совсем не место. Искушение, конечно, вызвано тем, что зарелизить один сервис "проще", чем два.


С точки зрения рабочего процесса конечно же самый замечательный вариант когда работа ведётся "над фичами продукта", а не "над кусочками кода". Монолит отражает фичи более органично в том плане, что "весь код — в одном месте". С микросервисами фичи превращаются в "вот этот код, вон тот код, дождаться вон того релиза, и вот потом-то уже сможем зарелизить нашу фичу".


Потекла память? Выросло потребление CPU? Захотелось построить флейм графы? Извини. В монолите одновременно происходит столько всего, что локализовать какую-то проблему становится безумно сложно. Например, понять, какая из 60 задач при выкатке в продакшн вызывает повышенное потребление ресурсов (хотя локально, на тестовых и стейджинг средах это не воспроизводится) — почти нереально.

С микросервисами ещё интереснее — если сервис X внезапно стал потреблять в 10 раз больше ресурсов, из этого совершенно не следует, что проблема — в сервисе X. Часто бывает, что проблема в сервисе Z, который вызывает сервис Y, который в цикле дёргает X по 20 раз на каждую транзакцию :-)

Information

Rating
Does not participate
Location
New Jersey, США
Date of birth
Registered
Activity