All streams
Search
Write a publication
Pull to refresh
31
0
Антон Куранов @Throwable

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

Send message

Теоретически да, практически — далеко не всегда.


  • Во-первых, поскольку нет единообразия, и учитывая, что для решения одной задачи уже существуют как правило несколько альтернатив на выбор, многие транзитивные модули будут зависеть от разных библиотек, предоставляющих один и тот же функционал.
  • Во вторых, транзитивные зависимости могут тащить разные версии одной библиотеки, и привести все это к общему знаменателю — серьезная проблема. Например производители дистрибутивов Linux или метафреймворков типа Spring Boot как раз решают эту проблему, унифицируя в каждой версии платформы большинство зависимостей.

С другой стороны проблемы не в размере самих библиотек, а в том, что современные технологии неприспособлены для автоматического dead code elimination. В сях все было просто: неважно сколько библиотек ты подключил — линкер урежет все, что статически недосягаемо из main(), делая очень компактный бандл. В других языках как Java, Python, JS пришлось искусственно городить модульную систему и требовать от пользователя каждый раз въявную указывать компоненты, которые он будет использовать. Так что это по большей части шаг назад.

Чаще всего ваши DTO так или иначе повторяют Domain model. Поэтому по большей части приходится дублировать свойства плюс писать ненужные мэпперы к каждому классу. Мы стараемся сразу определить у domain-класса группы полей, которые потом будут использоваться в DTO при помощи соответствующих интерфейсов:


class User implements BasicInfo, ExtendedInfo, SecurityInfo {
   ...
}
interface BasicInfo {
    String getId();
    String getName();
    String getEmail();
    LocalDate getBirthDate();
}
interface SecurityInfo {
    EnumSet<Role> getRoles();
    LocalDateTime getLastLoginTime();
}

Сериализатору указывается интерфейс DTO, и он пишет только соответствующий сет свойств.
В итоге:


  • исключает дублирование объектов и свойств
  • не нужны мепперы (филдсет сериализуется автоматически)
  • поддержка IDE и все такое

Есть одна жирная проблема с автоматическими миграциями: они должны быть линейно упорядочены. Это сильно усложняет жизнь, если несколько девелоперов пилят фичи в разных ветках. Приходится вручную контролировать порядок версий при сливе в master main, а каждый девелопер при апдейте из main должен ломать голову как применить предыдущие миграции на своей локальной базе. Есть ли какие-то рекомендации по этому поводу?

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

Именно поэтому и появилась вся эта хрень про юниты — в эпоху серверов приложений, когда билда и деплоя приходилось ждать по нескольку минут. Поэтому люди начали извращаться — мокать сервисы контейнера, чтобы хоть как-то тестировать куски кода локально без деплоя. И отсюда же пошло большинство современных (анти-)паттернов проектирования типа Repository, Context Object, etc. Более того, большинство кейсов вообще невозможно протестировать юнитами, ибо их логика зависит от контейнера и контекста выполнения (Transactional, RequestScoped, etc...).


Поднять систему за 10 секунд — это плохо. Система должна стартовать локально за 1-2 секунды в тестовой конфигурации, причем по возможности без моков и с персистенцией. И гнать надо ссаными тряпками все эти фреймворки, которые стартятся 10 секунд и больше.

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

Именно работающую конечную форму и стоит проверять по всем критериям, записанным в спецификации, иначе вашу форму будут тестировать конечные пользователи. И приемочных сценариев тут отнюдь не два, а гораздо больше: валидация полей, сообщение об ошибке плюс "специфичные" зависимые сценарии. Тем не менее, это не невозможно и даже проще, чем делать полное покрытие юнитами отдельно на всех уровнях.

expectThat(haystack).not().contains(needle)

Большинство библиотек так или иначе пытаются мимикрировать под человечный язык, оставляя, однако, за бортом тот факт, что последний изначально был задуман для соблазнения самок (согласно одной из теорий) и плохо подходит для лаконичных и четких высказываний, которыми оперируем мы, роботы :) Поэтому чем больше требуется иностранных букав, чтобы описать простое выражение, тем хуже общая читаемость и вдупляемость кода.

Круто! Как раз есть мощная серверная тачка, на которой все билдится и тестируется, давно хотел вынести туда и разработку проекта.


Есть одна возможная деталь по этому поводу: Websocket-ы в браузерах как правило не включают TCP_NODELAY (Nagle's algorithm), который приводит к некоторым лагам при передаче коротких пакетов. Более того, было замечено, что некоторые мобильные браузеры еще больше грешат "оптимизацией траффика", и задержки вебсокета составляют несколько секунд. К сожалению, протокол Websocket не позволяет напрямую включить TCP_NODELAY.

в большинстве случаев упор на юнит-тесты является пустой тратой времени.

Алилуйя! Не прошло и 10 лет, чтобы осознать это. Еще в недалеком прошлом адепты секты TDD буквально растерзали бы за подобного рода заявления.


Добавлю.


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


.6. Согласно Lean, юнит тесты не привносят value в конечный продукт. Это внутренняя инициатива разработчика, однако их написание и поддержка связаны с затратами.
Как правило проект состоит из компонентов, которые связываются в функциональные модули, которые в свою очередь используются в необходимых бизнес сценариях. С точки зрения заказчика именно правильное выполнение сценариев является изначальной задачей и критерием приемки работы. И, как правило если не работает какой-то компонент, бизнес сценарий также должен вальнутся. Юниты иногда помогают быстрее локализовать этот сбой.

При этом все подходы при реализации МСА настолько отличаются от монолитной

Да ладно? Модульная архитектура существовала еще 40 лет назад, и с тех пор подходы не изменились. Отличаются лишь средства: каждый раз более громоздкие, ресурсо и трудозатратные и менее надежные.


Команда не обязана выносить на корпоративный уровень вопросы о языке, на котором будет написан микросервис. Одни могут выбрать Java, а другие — Python.

Ну написали они на пайтоне свой сервис и что дальше? Будут сидеть баластом верхом на своем коде? Другой модуль, который написан на Java уже не в их компетенции? О ротации ресурсов не подумали?


В МСА каждый микросервис отделен ненадежными и компроментируемыми сетевыми коммуникациями.

Это вы про Rest/HTTP? :)) Или про отсутствие ACID в микросервисной архитектуре? Для надежной сетевой коммуникации еще 20 лет назад использовались Queue Managers, кроме того наличие распределенных транзакций гарантировало отказоустойчивость системы при сбое в любом месте. И не надо ломать голову как координировать откат операции или повторное выполнение — все ACID.


Oracle, Postgres, MySQL — это все жуткое старье, которое было построено из расчета, что база данных должна крутиться на одном сервере.

Это было построено из рассчета, чтобы был ACID. Ваши NoSQL — это по большей мере хаки, которые жертвуют конситстентностью в угоду распределенности, поэтому никто не собирается отказываться от классических реляционных баз. Практически во всех проектах именно реляционные БД являются маэстро данных, а NoSQL используются по большей части как кэши и производные. Но, внезапно, архитектура хайлоад к микросервисам не имеет практически никакого отношения.

Возможность развивать продукт независимыми сегментами.

Это в идеале. Реально же практически каждая новая фича затрагивает сразу кучу микросервисов и требует доработки процессов, изменения многих API и координации цикла разработки. Причем как ни организуй архитектуру — все-равно всплывет задача, которая не ляжет ровно на ваш шедевр.


Адекватное масштабирование микросервисов.

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


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

Фактически то же самое, что и 1. Координирование изменений в микросервисной архитектуре на порядки сложнее, чем в монолите. Пример: если надо поменять сервис в монолите, берем IntelliJ Idea и по Alt-F7 получаем все места, где он используется. В микросервисной же архитектуре сделать impact analysis — это настоящая головная боль.


Управление контурами безопасности. Монолит имеет доступ ко всем данным. Это грандиозная дыра.

Да вот нифига подобного. Микросервисы общаются при помощи API, которые требуют постоянного контроля за доступом (и постоянно где-то выявляется дыра). Монолит же въявную экспортирует только те API, которые будут использоваться извне, и со всеми необходимыми привилегиями и контролем.


Вобщем, на мой взгляд микросервисы хороши, если у вас:


  • система натурально может быть разделена на относительно независимые компоненты, сильно отличающиеся по функционалу, каждый из которых участвует во многих бизнес процессах
  • компоненты поддерживаются и разрабатываются разными командами и имеют разный релизный цикл
Это какой же код на Java 7 не заработает на Java 8, и его потребуется переписывать?

По большей части тот, который изначально заточен под Java 7, но запускается в среде Java 8 с классами, откомпилированными для восьмерки: фреймворки, библиотеки, сервера приложений. Основные сбои — это непроспособленность к новым default-методам коллекций, оптимистичное использование рефлексии, сериализация, операции на уровне байт-кода. Кроме того лямбды потребовали пересмотра и эволюции API для большинства фреймворков и библиотек. Однако jdk8 нарушало соместимость по байт-коду с ранними версиями, поэтому во многих проектах долгое время поставлялись две версии библиотек: для jdk7 и jdk8.

Отвечу за Java: на самом деле одна из лучших технологий, которая максимально поддерживает обратную совместимость. То есть легаси код, написанный под Java 1.1, с большой вероятностью заработает на последней Java без всякого допиливания. Переход на Java 9+ не столь критичен, а лишь затрагивает способ упаковки и изолирования кода (modulepath), кроме того он опционален (classpath все еще в моде). Гораздо более тяжелым бы переход с Java 7 на Java 8 — потребовалось переписывание практически всей экосистемы, затачивая ее под лямбды. Но ничего, как-то справились.


Те не менее сравнивать ситуацию с COBOL с современными проектами не совсем корректно, потому как сильно изменилась бизнес-модель и цикл разработки. Если раньше клиенты платили единоразово за продукт или функционал, то сегодня компании продают по большей части сервис, который включает себя поддержку и сопровождение втечение всего цикла использования, а также гарантирует актуальность используемых технологий. Вопросы сопровождения и миграции, а также связанные с ними расходы, провайдер как правило берет на себя.

  1. Flyway maven plugin

По большей части бесполезная вещь. В билд-скрипте нужно содержать коннекшн к каждому из environment. Плюс делать миграции с девелоперского компа заведомо неправильно. Миграцию должен делать задеплоенный артефакт при запуске.


Что плохо и неудобно в Flyway, так это то, что все миграции линейны. Это делает их неудобными, если у вас в git-е есть несколько веток. Например если есть версии Vx и Vy, которые друг от друга не зависят, и находятся в разных ветках, то при сливе в master нужно будет вручную переупорядочивать. Кроме того, на бенчах, где уже применился Vy из другой ветки не будет применен Vx, если его версия меньше, а точнее все вылетит с ошибкой. Это требует много ручного геморроя.

… и ЧТО замеряет — это Micronaut 2.0 M2 на пустом Rest. Берем Javalin/SparkFramework и получаем то же самое, но быстрее. А как начнем наваливать технологии, запуск опять сильно просядет.

Совершенно согласен. На собственном опыте женщины кодят аккуратнее, предпочитая произвести наименьшее воздействие на уже существующий код, тогда как мужчины кодят борлее конструктивно. К примеру для имплементации нового сценария мужчина вынесет общий функционал в суперкласс, и отнаследит от него два других класса — старый кейс и новый. Женщина как правило понатыкает везде if-ов в код и закроет тикет. Вполне логично, что во втором случае есть меньше вероятности что-то сломать. Поэтому процент прохождения review не может быть объективным критерием для качества разработки. Зато женщины очень хорошо тестируют софт и более способны к долговременной поддержке кода.

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


Применительно к разрабам психотипы накладывают свои отпечатки, но отнюдь не являются показателем для роли архитектора или строителя. Здесь гораздо больше играет роль знания и опыт.


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

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

Это заявление означает, что даже для сложного проекта, над которым работает несколько команд по нескольким направлениям надо вести линейный

Это заявление означает, что для простого проекта с одним-двумя разработчиками нет необходимости городить ветки и пайплайны, которые предлагает автор. Если есть возможность делать проще, нужно делать проще.

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

Information

Rating
Does not participate
Location
Madrid, Испания
Registered
Activity