Привет!
Тизер из доклада - я кажись нашёл железобетонный аргумент и пример в пользу ФА.
Это графы вызовов методов одной и той же реальной функции реального коммерческого проекта.
Слева - сделано "как обычно".
Справа - по ФА/ЭП.
Правый граф в проде (давно уже).
И это ещё на графах не подсвечена когнитивная сложность - левый при сложности всей структуры в целом, ещё будет иметь и сложность отдельных элементов намного большую - максимальная разница - 4 раза.
И правый граф работает в 300 раз быстрее (я замерял).
Оба графа сделаны на Java 8 + Spring Boot.
Левый граф сделан на Hibernate, правый - Spring JDBC Template, с небольшими вкраплениями Hibernate
Если и после этого люди ещё будут сомневаться нужно ли им ФП/ФА - я умываю руки.
#functional_architecture@ergonomic_code #whyfa@ergonomic_code #whynotjpa@ergonomic_code
Тизер из доклада - я кажись нашёл железобетонный аргумент и пример в пользу ФА.
Это графы вызовов методов одной и той же реальной функции реального коммерческого проекта.
Слева - сделано "как обычно".
Справа - по ФА/ЭП.
Правый граф в проде (давно уже).
И это ещё на графах не подсвечена когнитивная сложность - левый при сложности всей структуры в целом, ещё будет иметь и сложность отдельных элементов намного большую - максимальная разница - 4 раза.
И правый граф работает в 300 раз быстрее (я замерял).
Оба графа сделаны на Java 8 + Spring Boot.
Левый граф сделан на Hibernate, правый - Spring JDBC Template, с небольшими вкраплениями Hibernate
Если и после этого люди ещё будут сомневаться нужно ли им ФП/ФА - я умываю руки.
#functional_architecture@ergonomic_code #whyfa@ergonomic_code #whynotjpa@ergonomic_code
👍10
Привет!
В комментах к прошлому посту "внезапно" (🤦♂️ ) выяснилось что разные люди под "ФП" понимают разное.
Поэтому накатал коротенький микропост о том, что я имею ввиду говоря ФП
#terminology@ergonomic_code #fp@ergonomic_code #functional_architecture@ergonomic_code #oop@ergonomic_code #ergo_approach@ergonomic_code
В комментах к прошлому посту "внезапно" (
Поэтому накатал коротенький микропост о том, что я имею ввиду говоря ФП
#terminology@ergonomic_code #fp@ergonomic_code #functional_architecture@ergonomic_code #oop@ergonomic_code #ergo_approach@ergonomic_code
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥3
Привет!
Написал тест, что миграция вставляет коробочные данные, нашёл баг, что забыл прописать sql-файл с миграцией в ченджсет, пофиксал, сэкономил часик-другой отладки на стенде, профит.
Пишите тесты - они помогут найти баги в местах, где, казалось бы, только имбицил может баг допустить.
#tdd@ergo_approach #case@ergo_approach
Написал тест, что миграция вставляет коробочные данные, нашёл баг, что забыл прописать sql-файл с миграцией в ченджсет, пофиксал, сэкономил часик-другой отладки на стенде, профит.
Пишите тесты - они помогут найти баги в местах, где, казалось бы, только имбицил может баг допустить.
#tdd@ergo_approach #case@ergo_approach
💯11
Эргономичный код
Если собираетесь на Joker и ещё не купили билеты - не торопитесь, в прошлый раз мне чуть меньше чем за месяц до конфы дали промокод на скидку 20%
Привет!
В этот раз публичного промокода не дали, но подсобить всё равно могу - приходите в личку, если планируете покупать билет.
В этот раз публичного промокода не дали, но подсобить всё равно могу - приходите в личку, если планируете покупать билет.
Привет!
Я пару лет назад пинал декомпозицию по фичам, за то, что
И тут я кажись познал дзен. Фичи надо искать не в требованиях, домене или таблицах/сущностях.
Их надо искать в порядке и этапах реализации требований и т.д.
Я это ещё не отрефлексировал толком и может на самом деле идея тупая, но, кажется, когда начинаешь работу над задачей - очевидно, это какая-то новая фича, или доработка какой-то существующей фичи.
В первом случае - вы заводите новый пакет/директорию, во втором случае - дописываете код в старых пакетах.
Однако в целом я всё ещё не сторонник тотальной вертикальной декомпозиции в духе вертикальной архитектуры, декомпозиции по фичам или моей же декомпозиции по объектам (раз, два).
Потому что по моему опыту они ведут к слишком высокой сцепленности (явной или не явной) между слайсами/фичами/объектами.
Но вот использовать декомпозицию по фичам как вторичную - после разделения на слои приложения и домена (what-the-system-does и what-the-system-is в терминах Lean Architecture) - кажется вполне себе вариант.
#design@ergo_approach
Я пару лет назад пинал декомпозицию по фичам, за то, что
Когда же вы сядете и попытаетесь декомпозировать систему по фичам, у вас тут же возникнет множество вопросов:
"А фича - это вообще что такое?", "Как мне из требований получить набор фич?", "Судя по примерам, фича - это таблица. Мне что, заводить по пакету на каждую таблицу?", "А что делать с таблицами связками?", "Что делать с функциями, которые затрагивают две и более таблицы - в какой пакет их помещать?", "А что делать с функциями, которые работают не с таблицами, а с REST API?", "А с S3?", "А куда мне положить DSL создания Excel файлов для нескольких фич? В utils?"
И тут я кажись познал дзен. Фичи надо искать не в требованиях, домене или таблицах/сущностях.
Их надо искать в порядке и этапах реализации требований и т.д.
Я это ещё не отрефлексировал толком и может на самом деле идея тупая, но, кажется, когда начинаешь работу над задачей - очевидно, это какая-то новая фича, или доработка какой-то существующей фичи.
В первом случае - вы заводите новый пакет/директорию, во втором случае - дописываете код в старых пакетах.
Однако в целом я всё ещё не сторонник тотальной вертикальной декомпозиции в духе вертикальной архитектуры, декомпозиции по фичам или моей же декомпозиции по объектам (раз, два).
Потому что по моему опыту они ведут к слишком высокой сцепленности (явной или не явной) между слайсами/фичами/объектами.
Но вот использовать декомпозицию по фичам как вторичную - после разделения на слои приложения и домена (what-the-system-does и what-the-system-is в терминах Lean Architecture) - кажется вполне себе вариант.
#design@ergo_approach
Алексей Жидков
Подходы к декомпозиции бэкендов информационных систем - Алексей Жидков
https://azhidkov.pro/
❤3👍2
Привет!
В комментах задали вопрос:
И ответ получился размером с небольшой пост, так что решил запулить его в канал.
Прямо сейчас стратегия обработки ошибок не то, что не описана, но даже не детализирована.
Но общее видение такое:
Я исхожу из того, что существует 4 типа ошибок:
1. Ошибки оборудования
2. Ошибки программиста бэка
3. Ошибки программиста фронта/поломки обратной совместимости
4. Ошибки, которых не должно быть.
Ошибки оборудования и внешних сервисов
Это отказы жёстких дисков, сети, внешних сервисов и т.д. Их чинят девопсы. Или программисты внешних сервисов. И для починки нужен редеплой (вплоть до физического развёртывания нового сервера) оборудования или внешнего сервиса
Ошибки программиста бэка
Логические ошибки - NullPointer, IllegalArgument, IndexArrayOutOfBounds и т.д. Их чинят разрботчики бэка и для починки требуется редеплой бэка.
Ошибки программиста фронта
Все ошибки когда запрос кривой - вообще не HTTP, HTTP, но не ложится на модель бэка, на модель ложится но является внутренне противоречивым (этого лучше избегать). Их чинит разработчик фронта и для починки требуется редеплой фронта.
Ошибки которых не должно быть (ака доменные ошибки)
Это когда софт работает "нормально", но пользователь с его помощью пытается сделать то, чего нельзя. Их чинит юзер, без какого-либо редеплоя.
Возьмём пример из Trainer Advisor, где при создании приёма есть проверка на то, что нельзя создать для одного терапевта приём, пересекающейся с существующим. Но для лучшей иллюстрации давайте представим, что речь идёт не о терапевте, а о зале - нельзя создать два приёма в одном зале, которые пресекаются по времени.
И вот сейчас у меня это реализовано максимально дёшево - я проверяю наличие приёмов на запросе создания и если он есть - показываю ошибку юзеру
Более дорогой вариант позволил бы избежать избежать этой ошибки для одного терапевта - если бы я проверку выполнял фоном в процессе заполнения формы и просто блокировал бы кнопку подтверждения в случае попытки создать пересекающийся приём, то терапевт физически не смог бы сделать фигню (считаем, что терапевты не владеют curl-ом)
Ещё более дорогой вариант позволил бы минимизировать вероятность такой ошибки и для двух терапевтов - если бы при появлении нового приёма в системе я бы рассылал инфу об этом всем клиентам у которых сейчас открыто окно создания приёма, и на фронте бы блокировал кнопку подтверждения при обнаружении пересечения.
А ещё можно сделать обмен данными с форм создания/редактирования, чтобы... Ладно, в общем я утверждаю, что вероятность подобных ошибок можно довести до столь малой, что их можно "упросить" до ошибок оборудования или разработчика бэка.
И вот исходя из этой классификации у меня общая стратегия следующая:
1. Ошибки оборудования и разработчика бэка - по максимуму игнорим. Они вылетают исключениями из библиотечного кода и прямой наводкой летят в глобальный обработчик ошибок, который покажет юзеру "У нас проблемы, работаем, попробуйте позже"
2. Ошибки разработчика фронта - в идеале аналогично, но только лучше веб-фреймворк настроить так, чтобы он сам с ними разбирался.
3. А вот "доменные" ошибки - в идеале должны возвращаться в виде Result-а и контроллер/фронт должны показать юзеру понятную ошибку и дать инструкции по её устранению
Однако есть нюанс - Spring не дружит c Result. И если вернуть ошибку в виде Result, а не исключения - он транзакцию не откатит. Это можно захачить кастомной аннотацией, но не хочется.
Поэтому текущие правила работы с ошибками у меня такие:
1. Ошибки оборудования я стараюсь по максимуму игнорить.
2. Ошибки разрботки бэка (помимо тех, что рантайм мечет) я мечу стандартными error, check, require и т.д. и они улетают наружу 500-ками
3. Бизнес-логика возвращает ошибки Result-ом (в TA такого ещё нет)
4. Оркестрация выбрасывает ошибки (в том числе Result от бизнес-логики) исключениями
5. Контроллеры ловят исключения в Result и разбирают его в функциональном стиле
В комментах задали вопрос:
А есть какое-то описание принципов обработки ошибок в ЭП? Типа где обычные исключения, бизнес исключения, где возврат значения (Result?) и почему и т.п.
И ответ получился размером с небольшой пост, так что решил запулить его в канал.
Прямо сейчас стратегия обработки ошибок не то, что не описана, но даже не детализирована.
Но общее видение такое:
Я исхожу из того, что существует 4 типа ошибок:
1. Ошибки оборудования
2. Ошибки программиста бэка
3. Ошибки программиста фронта/поломки обратной совместимости
4. Ошибки, которых не должно быть.
Ошибки оборудования и внешних сервисов
Это отказы жёстких дисков, сети, внешних сервисов и т.д. Их чинят девопсы. Или программисты внешних сервисов. И для починки нужен редеплой (вплоть до физического развёртывания нового сервера) оборудования или внешнего сервиса
Ошибки программиста бэка
Логические ошибки - NullPointer, IllegalArgument, IndexArrayOutOfBounds и т.д. Их чинят разрботчики бэка и для починки требуется редеплой бэка.
Ошибки программиста фронта
Все ошибки когда запрос кривой - вообще не HTTP, HTTP, но не ложится на модель бэка, на модель ложится но является внутренне противоречивым (этого лучше избегать). Их чинит разработчик фронта и для починки требуется редеплой фронта.
Ошибки которых не должно быть (ака доменные ошибки)
Это когда софт работает "нормально", но пользователь с его помощью пытается сделать то, чего нельзя. Их чинит юзер, без какого-либо редеплоя.
Возьмём пример из Trainer Advisor, где при создании приёма есть проверка на то, что нельзя создать для одного терапевта приём, пересекающейся с существующим. Но для лучшей иллюстрации давайте представим, что речь идёт не о терапевте, а о зале - нельзя создать два приёма в одном зале, которые пресекаются по времени.
И вот сейчас у меня это реализовано максимально дёшево - я проверяю наличие приёмов на запросе создания и если он есть - показываю ошибку юзеру
Более дорогой вариант позволил бы избежать избежать этой ошибки для одного терапевта - если бы я проверку выполнял фоном в процессе заполнения формы и просто блокировал бы кнопку подтверждения в случае попытки создать пересекающийся приём, то терапевт физически не смог бы сделать фигню (считаем, что терапевты не владеют curl-ом)
Ещё более дорогой вариант позволил бы минимизировать вероятность такой ошибки и для двух терапевтов - если бы при появлении нового приёма в системе я бы рассылал инфу об этом всем клиентам у которых сейчас открыто окно создания приёма, и на фронте бы блокировал кнопку подтверждения при обнаружении пересечения.
А ещё можно сделать обмен данными с форм создания/редактирования, чтобы... Ладно, в общем я утверждаю, что вероятность подобных ошибок можно довести до столь малой, что их можно "упросить" до ошибок оборудования или разработчика бэка.
И вот исходя из этой классификации у меня общая стратегия следующая:
1. Ошибки оборудования и разработчика бэка - по максимуму игнорим. Они вылетают исключениями из библиотечного кода и прямой наводкой летят в глобальный обработчик ошибок, который покажет юзеру "У нас проблемы, работаем, попробуйте позже"
2. Ошибки разработчика фронта - в идеале аналогично, но только лучше веб-фреймворк настроить так, чтобы он сам с ними разбирался.
3. А вот "доменные" ошибки - в идеале должны возвращаться в виде Result-а и контроллер/фронт должны показать юзеру понятную ошибку и дать инструкции по её устранению
Однако есть нюанс - Spring не дружит c Result. И если вернуть ошибку в виде Result, а не исключения - он транзакцию не откатит. Это можно захачить кастомной аннотацией, но не хочется.
Поэтому текущие правила работы с ошибками у меня такие:
1. Ошибки оборудования я стараюсь по максимуму игнорить.
2. Ошибки разрботки бэка (помимо тех, что рантайм мечет) я мечу стандартными error, check, require и т.д. и они улетают наружу 500-ками
3. Бизнес-логика возвращает ошибки Result-ом (в TA такого ещё нет)
4. Оркестрация выбрасывает ошибки (в том числе Result от бизнес-логики) исключениями
5. Контроллеры ловят исключения в Result и разбирают его в функциональном стиле
❤6
Привет!
Список рекомендованных анкл Бобом книг
Я прочитал всё кроме Fundamental Algorithms и Analysis Patterns - есть ли в мире больший задрот, чем я?🤣🤓
#books@ergonomic_code
Список рекомендованных анкл Бобом книг
Я прочитал всё кроме Fundamental Algorithms и Analysis Patterns - есть ли в мире больший задрот, чем я?🤣🤓
#books@ergonomic_code
🥰3
Привет!
Недавно зарелизали Postgres 17.
Для меня актуально - как всегда всякие оптимизации и больше поддержки json-а
Недавно зарелизали Postgres 17.
Для меня актуально - как всегда всякие оптимизации и больше поддержки json-а
PostgreSQL News
PostgreSQL 17 Released!
The [PostgreSQL Global Development Group](https://www.postgresql.org) today announced the release of [PostgreSQL 17](https://www.postgresql.org/docs/17/release-17.html), the latest version of the world's most advanced …
🔥5
Привет!
Пока готовил доклад наткнулся на прикольную штуку: Cognitive Complexity - метрику оценки сложности кода, которая явно ближе к правде, чем Cyclomatic complexity.
Она, на мой взгляд, тоже не идеальна, так как не учитывает наличие и количество изменяемого состояния (а это важно) и позволяет "замести" сложность под вызовы функций, но даже в текущем виде полезна и подсвечивает места, с которыми точно надо что-то сделать.
И для Идеи даже есть плагинчик, который прям в редакторе рисует сложность методов. Только для Котлина он не учитывает ветвление потока управления даже в базовых map, filter, forEach и т.д., поэтому может сильно приврать в сторону простоты. Но если в коде откровенное кровавое месиво - он это подсветит.
#tools@ergonomic_code #craftsmanship@ergonomic_code
Пока готовил доклад наткнулся на прикольную штуку: Cognitive Complexity - метрику оценки сложности кода, которая явно ближе к правде, чем Cyclomatic complexity.
Она, на мой взгляд, тоже не идеальна, так как не учитывает наличие и количество изменяемого состояния (а это важно) и позволяет "замести" сложность под вызовы функций, но даже в текущем виде полезна и подсвечивает места, с которыми точно надо что-то сделать.
И для Идеи даже есть плагинчик, который прям в редакторе рисует сложность методов. Только для Котлина он не учитывает ветвление потока управления даже в базовых map, filter, forEach и т.д., поэтому может сильно приврать в сторону простоты. Но если в коде откровенное кровавое месиво - он это подсветит.
#tools@ergonomic_code #craftsmanship@ergonomic_code
👍6🔥2
Привет!
У меня сегодня был прогон доклада с экспертом - Максом Моревым - и на обсуждении вспомнили почему в Красной книге (второй библии ДДД) примеры на Java:
И наш с Максом опыт говорит о том же.
Так как вы в этом канале - эта цитата не про вас - и если в какой-то момент вам покажется, что вы придумываете сложности на пустом месте, а все вокруг просто нормально работают - это не так. Вы делаете нормально - а все вокруг через чур упрощают себе решение задачи в моменте, чтобы через год получить сложный неподдерживаемый ком грязи. В котором снова сделать самый примитивный "солюшен" и ещё через год получить ещё более сложный кода.
#books@ergonomic_code
У меня сегодня был прогон доклада с экспертом - Максом Моревым - и на обсуждении вспомнили почему в Красной книге (второй библии ДДД) примеры на Java:
First of all, and sad to say, I think there has been a general abandonment of good design and development practices in the Java community. These days it may be difficult to find a clean, explicit domain model in most Java-based projects.
Прежде всего, к сожалению, я думаю, что в Java-сообществе наблюдается общий отказ от хороших методов проектирования и разработки. В наши дни сложно найти чистую, явную модель предметной области в большинстве Java-проектов.
И наш с Максом опыт говорит о том же.
Так как вы в этом канале - эта цитата не про вас - и если в какой-то момент вам покажется, что вы придумываете сложности на пустом месте, а все вокруг просто нормально работают - это не так. Вы делаете нормально - а все вокруг через чур упрощают себе решение задачи в моменте, чтобы через год получить сложный неподдерживаемый ком грязи. В котором снова сделать самый примитивный "солюшен" и ещё через год получить ещё более сложный кода.
#books@ergonomic_code
Telegram
codemonsters.log
| https://codemonsters.team
| well crafted software
| Прозрачная качественная разработка
| Исследование лучших практик делом
Log Максима Морева
@maxology
| well crafted software
| Прозрачная качественная разработка
| Исследование лучших практик делом
Log Максима Морева
@maxology
🔥7
Привет!
Эх. А вот взять бы Clojure, ClojureScript, Datomic, htmx и hiccup - и тогда ВООБЩЕ ВЕСЬ проект можно сделать на ОДНОМ ЯЗЫКЕ. Фактически в одном процессе. Как будто десктопное приложение пишешь...
#clojure@ergonomic_code
Эх. А вот взять бы Clojure, ClojureScript, Datomic, htmx и hiccup - и тогда ВООБЩЕ ВЕСЬ проект можно сделать на ОДНОМ ЯЗЫКЕ. Фактически в одном процессе. Как будто десктопное приложение пишешь...
#clojure@ergonomic_code
htmx.org
</> htmx - high power tools for html
htmx gives you access to AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext
htmx is small (~14k min.gz’d), dependency-free, extendable…
htmx is small (~14k min.gz’d), dependency-free, extendable…
👍4🤯2🥴2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁7
Привет!
Так, ну большая веха пройдена, расскажу про свои ближайшие планы.
И главный ближайший план - отдохнуть. До марта.
У меня с июля идёт жёсткий спринт, где я жонглирую домом с младенцем и старшим ребёнком, который за 3 месяца сходил в сад 7 дней, выступлением и проектом Р, где дикая жопа тянется с июня.
Но перед тем как начать уже отдыхать я планирую:
1. На следующей недели съездить на оффлайн часть конфы и сделать там лайтенинг толк с кратким пересказом изначального доклада про Spring Data JDBC
2. Допричёсывать и скинуть ссылки на демо проекты для доклада про SDJ
3.Выбрать и опубликовать тестовые прогоны всех трёх докладов: оригинальной полной версии доклада про SDJ, финального доклада про структурный дизайн и лайтенинг толка про SDJ
4. Протегать все свои посты и сделать "домшнюю страницу" со ссылками на тематические подборки
5. У меня есть предвfрительная договорённость зайти в гости к @javaswag - надеюсь там ещё лицом поторгую
На это всё, думаю, у меня уйдёт месяц-полтора.
А после отпуска я планирую несколько поменять подход к проработке ЭП - хочу завести сайт-вики и там для начала просто собрать и описать список всех паттернов и моделей, которые использую в своей работе.
Вот такие дела, стейтюнед, мы найдём способ делать системы так, чтобы работать было по кайфу:)
Так, ну большая веха пройдена, расскажу про свои ближайшие планы.
И главный ближайший план - отдохнуть. До марта.
У меня с июля идёт жёсткий спринт, где я жонглирую домом с младенцем и старшим ребёнком, который за 3 месяца сходил в сад 7 дней, выступлением и проектом Р, где дикая жопа тянется с июня.
Но перед тем как начать уже отдыхать я планирую:
3.
На это всё, думаю, у меня уйдёт месяц-полтора.
А после отпуска я планирую несколько поменять подход к проработке ЭП - хочу завести сайт-вики и там для начала просто собрать и описать список всех паттернов и моделей, которые использую в своей работе.
Вот такие дела, стейтюнед, мы найдём способ делать системы так, чтобы работать было по кайфу:)
Telegram
Эргономичный код
Привет!
Я как всегда облажался с оценкой оверхеда на сетап проекта и сроки по Проекту Р начали подгорать.
Поэтому на этой недели не расскажу, как поднимаю БД на 300+ таблиц, собираемых из 8 лет миграций меньше чем за пару секунд.
Но быстренько поделюсь…
Я как всегда облажался с оценкой оверхеда на сетап проекта и сроки по Проекту Р начали подгорать.
Поэтому на этой недели не расскажу, как поднимаю БД на 300+ таблиц, собираемых из 8 лет миграций меньше чем за пару секунд.
Но быстренько поделюсь…
❤16🔥5
Хейтеры такие хейтеры:)
Относительно прошлого выступления обратная связь неоднозначния.
Отзывов больше (27 вс 23) и лучше (4.4 вс 4.1). Но досмотрели доклад до конца сильно меньше (40% вс 74%). С просмотрами, возможно, разница в значительной степени обусловлена онлайном и оффлайном
Относительно прошлого выступления обратная связь неоднозначния.
Отзывов больше (27 вс 23) и лучше (4.4 вс 4.1). Но досмотрели доклад до конца сильно меньше (40% вс 74%). С просмотрами, возможно, разница в значительной степени обусловлена онлайном и оффлайном
👍3
Привет!
История ужасов про мутабельное состояние.
Есть у нас тут в Проекте Р задачка по загрзуке файла. Отдали её юниору. Он вчера провозился весь день - не осилил загрузить, спринг ругается что не видит multipart part.
Сегодня подключился я. Сделал мастер-класс по ТДД, докинул пару параметров, тест (поверх MockMvc) прошёл. На всякий случай (не верю я этим мокам) пошёл перепроверить курлом - не работает.
Засучил рукава. Перелазил весь инет. Отдебажил эту хрень вплоть до org.apache.tomcat.util.http.fileupload.util.LimitedInputStream - я в запросе тело отправляю, а когда начинает работать StandardServletMultipartResolver - тело куда-то исчезает 😱🤯
Провозился три часа. Потом каким-то чудом, вспомнил, что у нас есть фильтр, который вычитывает тело и прокидыввает дальше обёртку, которая переопределяет getInputStream. А getParts - не переопределяет. И getParts пытается вычитать данные из инпутстрима оригинального HttpServletRequest. Из которого мы уже всё вычитали в фильтре. Занавес.
Были бы силы всё это аккуратно расписать и подать - был бы крутой кейс, почему модель данных должна быть неизменяемой. Но не в этот раз
#whyfp@ergonomic_code #project_r@ergonomic_code
История ужасов про мутабельное состояние.
Есть у нас тут в Проекте Р задачка по загрзуке файла. Отдали её юниору. Он вчера провозился весь день - не осилил загрузить, спринг ругается что не видит multipart part.
Сегодня подключился я. Сделал мастер-класс по ТДД, докинул пару параметров, тест (поверх MockMvc) прошёл. На всякий случай (не верю я этим мокам) пошёл перепроверить курлом - не работает.
Засучил рукава. Перелазил весь инет. Отдебажил эту хрень вплоть до org.apache.tomcat.util.http.fileupload.util.LimitedInputStream - я в запросе тело отправляю, а когда начинает работать StandardServletMultipartResolver - тело куда-то исчезает 😱🤯
Провозился три часа. Потом каким-то чудом, вспомнил, что у нас есть фильтр, который вычитывает тело и прокидыввает дальше обёртку, которая переопределяет getInputStream. А getParts - не переопределяет. И getParts пытается вычитать данные из инпутстрима оригинального HttpServletRequest. Из которого мы уже всё вычитали в фильтре. Занавес.
Были бы силы всё это аккуратно расписать и подать - был бы крутой кейс, почему модель данных должна быть неизменяемой. Но не в этот раз
#whyfp@ergonomic_code #project_r@ergonomic_code
👍10😱2