Эргономичный код
819 subscribers
81 photos
3 videos
20 files
401 links
Канал о разработке поддерживаемых бакэндов - про классическую школу TDD, прагматичное функциональное программирование и архитектуру и немного DDD.

Группа: https://t.me/+QJRqaHI8YD

https://azhidkov.pro
Download Telegram
Привет!

Полезняшка

Представьте, что у вас есть json-файл с массивом на 500 объектов.
И вам надо добавить в эти 500 объектов по ключу externalId с разными UUID-ами.

Есть вариант влоб - написать скриптик.

А есть вариант попроще.

Зайти в neovim и написать:
1. qq - запустить запись макроса
2. /lastExistingKey - найти следующую строку, в которой содержится подстрока с именем последнего существующего ключа
3. A - переместить курсор в конец строки и войти в режим печати
4. , - добавить запятую в конце строки
5. <esc> - вернуться в командный режим
5. :read!uuidgen<enter> - запустить программу uuidgen и вставить её вывод в новой строке файла после курсора
6. I - перейти в начало строки и войти в режим печати
7. "externalId": " - добавить в начале стоки отступ, имя ключа и кавычку перед значением
8. <esc> - вернуться в командный режим
9. A - перейти в конец строки и войти в режим печати
10. " - добавить в конце строки кавычки
11. <esc> - вернуться в командный режим
12. q - завершить запись макроса
13. 499@q - 499 раз исполнить макрос

Вопрос примерно 2 минут вместе с гуглением uuidgen и задача решена.
Быстрее, наверное, только на sed/awk - но с ними у меня проблема, что такие задачи у меня раз в месяц появляются и за этот месяц у меня этот клингонский из головы выветривается. А вимом я пользуюсь каждый день и он у меня уже на подкорке.

Поддержка vim-режима есть во всех популярных ИДЕ/редакторов включая Emacs (😄 - если вы понимаете о чём я)

#tools@ergonomic_code
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍3😁2
Привет!

Теперь меня не только почитать, посмотреть (а некоторым даже и пощупать) можно, но и послушать:)

#talks@ergonomic_code #ergo_approach@ergonomic_code
😁4
Forwarded from javaswag
https://javaswag.github.io/episode/71/

Слушать подкаст в Apple | Spotify | Yandex

В 71 выпуске подкаста Javaswag поговорили с Алексеем Жидковым об эргономичном подходе для разработки архитектуры проекта

00:00 Начало
12:06 Работа консультанта
17:38 Эргономичный подход и его принципы
26:44 Практика применения принципов разработки
30:55 Трудности внедрения DDD на практике
37:15 Популярность DDD и его реальная эффективность
39:33 TDD и его место в эргономичном подходе
41:00 Тестирование как основа разработки
43:55 Проблемы с моками в тестировании
48:50 Архитектурные подходы и JPA
51:01 Функциональная архитектура и ее влияние на разработку
55:36 Проблемы с ORM и Hibernate
01:00:03 Эргономичность и альтернативы ORM
01:01:53 Неизменяемая модель данных
01:05:58 Эргономичный подход в разработке
01:08:32 Обсуждение стека технологий и его эволюция
01:11:21 Эргономичный подход в разработке проектов
01:17:14 Проблемы объектно-ориентированного программирования
01:20:56 Декомпозиция системы и создание API
01:22:38 Тестирование и разработка по TDD
01:27:24 Экономика эргономичной архитектуры
01:30:59 Элементы эргономичного подхода
01:40:15 Проблемы многопоточности
01:42:58 Непопулярное мнение

Гость - https://t.me/ergonomic_code
Канал в телеграме @ergonomic_code
Сайт Алексея

Кип сейф! 🖖
🔥14👍83
Эргономичный код
Привет! Кажется у меня по мотивам Проекта Э на горизонте замаячил очередной кризис Эргономичного подхода. При том зашатались одновременно два столпа - декомпозиция на базе эффектов и функциональная архитектура. С декомпозицией на базе эффектов в одном из…
Привет!

Вы, наверное, забыли, что полтора года назад в Эргономичном подходе было две проблемы (см. цитируемое сообщение), а я - нет:)

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

Проблема №1
А вот как декомозировать слой приложения - я пока не знаю.

Тут сейчас ответ такой: пофиг:) Лишь бы команде было удобно ориентироваться. Можете делать так же, как сейчас раскладываете контроллеры. Может плясать от страниц/экранов/компонентов UI, можете от ролей пользователей, можете от юз кейсов, можете от ресурсов REST API.

В Trainer-Advisor, например, сейчас код приложения сначала разбит по ролям пользователей, потом по страницам/компонентам

Проблема №2
Однако на практике у меня некоторые операции ещё и другие операции дёргают. И мне это кажется нарушением принципа одного уровня абстракции.
Но я пока не могу сформулировать к каким систематическим проблемам это ведёт.

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

Во-вторых, я нашёл решение этой проблемы.
Оно состоит из двух частей:
1. Я отказался от сервисов приложений в пользу классов-операций - класс, который имеет один публичный метод, реализующий одну операцию (эндпоинт) системы и имеющий поля для всех ресурсов (гейтвеев, репозов, клиентов внешних систем), требующихся для реализации этой операции. См, например операцию регистрации терапевта в Trainer-Advisor
2. Я завёл штуки, которые сейчас называю "доменные операции" - это процедуры (Kotlin top-level function), которые нужные им ресурсы получают в качестве параметров. В том же коде регистрации терапевта надо CreateTherapistUserWorkflow заменить на процедуру

fun createTherapistUser(
usersRepo: UsersRepo,
therapistsRepo: TherapistsRepo,
usersFactory: UsersFactory,
registerTherapistRequest: RegisterTherapistReques,
password: CharSequence) {
...
}


с кодом его реализации, которая зависимости получает явно в качестве параметров. Реального публичного кода с иллюстрацией у меня пока нет, но есть картинка №2:)

В результате, для того чтобы оценить масштаб трагедии достаточно посмотреть на кол-во зависимостей класса-операции. А для того чтобы ограничить масштаб трагедии - достаточно ввести ограничение на кол-во зависимостей.

При том вы можете избегать дублирования "подопераций" и в целом ограничивать длину методов операций и вводить промежуточные уровни абстракции.

Параметры с ресурсами, конечно, придётся таскать - но это будет напоминалкой, чтобы искать возможность повысить уровень абстракции ресурсов и/или уменьшить количество вещей, которые делает операция. В примере из TA, например, пришло время завести UsersService, который скрывает за собой usersRepo и usersFactory

вин-вин-вин, я считаю:)

#ergo_approach@ergonomic_code #ergo_arch@ergonomic_code
👍9🔥43
Привет!

Предистория.

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

У меня ссылок было аж 19 штук и Дима предложил сделать развёрнутые комментарии к ссылкам.
Но внезапно оказалось, что я не умею писать комментарии к ссылкам и вместо комментариев у меня как обычно вышел небольшой пост-очерк “Что такое ООП?”.
Но пост – уже не формат для javaswag, поэтому я его представляю вам у себя.

—-

История


В книге “What every programmer should know about object-oriented design” Пейдж-Джонс на первой же странице пишет:

Термин “объектно-ориентированный”, по сути своей, бессмысленен. “Объект” — это одно из самых общих слов в английском языке. Если вы посмотрите его значение в словаре, то увидите что-то вроде:

Объект — вещь, представленная или которую можно представить чувствам [человека].

Другими словами, объект - это практически всё что угодно.

Слово “ориентированный” также не особо помогает. Опредёленное как “направленный в сторону”, оно обычно используется для превращения термина “объекто-ориентированный” в прилагательное.
Таким образом, мы имеем:

Объектно-ориентированный — направленный в сторону практически чего угодно, о чём вы можете только подумать.

Не удивительно, что наша индустрия не смогла договориться об определении термина “объектно-ориентированный”.


Наверное, если провести опрос среди разработчиков, то самым популярным ответом будет “ООП – это наследование, полиморфизм и инкапсуляция”. И последний выпуск javaswag (см. ответ на моё непопулярное мнение), кстати, это подтверждает.

Однако Алан Кей, автор термина, в одном из своих докладов заявил: “На самом деле это я придумал термин “объектно-ориентированный” и я могу сказать вам, что я не имел С++ ввиду”.
А имел он ввиду: обмен сообщениями, сокрытие состояния и экстремально позднее связывание.

И, как следствие, Джо Армстронг, создатель Erlang считает: “Erlang, возможно, является единственным объектно-ориентированным языком, потому что три принципа объектно-ориентированного программирования заключаются в передаче сообщений, изоляции между объектами и полиморфизмом. [...] ООП — это не про объекты и классы, ООП — это про сообщения”.

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

А что такое ООП для вас?

#oop@ergonomic_code #terminology@ergonomic_code #archeology@ergonomic_code #books@ergonomic_code
👍11
Привет!

Полезняшка.

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

В итоге всё оказалось предельно просто.
Запустил компоузом nginx с network_mode: host и собрал минимальный конфиг nginx-а.

name: my-project-nginx

services:
nginx:
image: nginx
volumes:
- ./nginx/dev.conf:/etc/nginx/conf.d/default.conf
network_mode: host


server {
listen 8081;

location ~ ^/api/(public|external)/ {
proxy_pass http://localhost:8084;
}

location / {
proxy_pass http://localhost:8082;
}
}


Не сказать, что откровение века, но может кому-то ещё пригодится.

#devx@ergonomic_code #docker@ergonomic_code #nginx@ergonomic_code
👍8
Привет!

На днях перевёл Проект Р и Trainer Advisor на Kotlin 2.1.0 и Spring Boot 3.4.0
В целом всё прошло без проблем, делюсь впечатлениями

Проект Р/Котлин 2.0.0 -> 2.1.0
1. Т.к. переходил с версии 2.0.0 так же возникла проблема с пропажей продовых зависимостей в testFixtures source sets. И со второй попытки я её определил и починил быстро
2. В паре data классов с приватными конструкторами пришлось развесить @ConsistentCopyVisibility, чтобы варнинг убрать

Проект Р/Спринг 3.3.1 -> 3.4.0
1. Тест на корс, который ломился без авторизации на закрытый урл начал валиться по 401/3 (забыл уже) - перевёл его на запрос к публичному пути - заработало

Trainer Adviser/Котлин 2.0.21 -> 2.1.0
1. Заглючила идея 2024.2 и опять на testsFixtures - гредлом всё ок собирается, в редакторе ошибок нет, но при попытке сборки проектов идеевским билд тулом (я юзаю его для разработки, так как он быстрее гредлового) - ругается что не может в коде тестов найти символ из кода фикстур. Это поличилось обновлением самой идеи до 2024.3

Trainer Advisor/Спринг 3.3.5 -> 3.4.0
1. Начало взрываться responseEntity.contentLength = storedFileInputStream.metaData.size при size = 0. Добавил if (size > 0) - завелось
2. В одном из эндпоинтов на параметр принципала не был навешан @AuthenticationPrincipal. Раньше это как-то работало, после преезда перестало, после добавления аннотации снова заработало.



На обновление Проекта Р у меня ушло часа три.
Львиная доля ушла на:
1. переход на обратнонесовместимый Kover 0.8.3
2. datafaker в котором задепрекейтили один из методов
3. не связанные с обновлением разборки с гредлом

Trainer Advisor вообще за час максимум обновил.

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

#kotlin@ergonomic_code #spring@ergonomic_code #projectr@ergonomic_code #trainer_advisor@ergonomic_code
👍43👌1
Привет!

Новая рубрика в канале - челлендж! :)

Предыстория

Собрался я тут писать на свою вики статью "Функциональная (типизированная) обработка ошибок". Текст написал, решил сдобрить примерами. В качестве задачи решил взять парсинг строк в инты. Сначала запилил тупую императивную реализацию. Потом подумал, что это как-то не конгруэнтно и попробовал переписать в декларативном стиле. И такое ощущение, что получилось заметно хуже - и медленнее и сложнее.

История

Предлагаю вам поучаствовать в челлендже на самую понятную и эффективную реализацию функции парсинга:)

Условия:
1. Надо форкнуть репоз-фреймворк, реализовать функцию parseInt так, чтобы проходили тесты
2. Завести пуллреквест со своей реализацией. Ограничений на реализацию нет - можно писать и в императивном стиле, и в декларативном, и с помощью ии
3. Через выходные 16-ого декабря я опубликую в канале все варианты включая свои и заведу голосовалку, какой из вариантов наиболее понятен
4. Победитель получит почёт, свой код в вики эргономичного подхода и ссылки на себя в вики, репозе и канале:)
👍8🔥3
Эргономичный код
Привет! Новая рубрика в канале - челлендж! :) Предыстория Собрался я тут писать на свою вики статью "Функциональная (типизированная) обработка ошибок". Текст написал, решил сдобрить примерами. В качестве задачи решил взять парсинг строк в инты. Сначала…
Привет!

Так, ну чтош, обещанная голосовалка.

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

Всего вышло аш 10 вариантов - 5 моих и 5 от подписчиков.
Я решил, что корректнее будет если я не буду их выделять, поэтому варианты идут в случайном порядке.

Сейчас запилю пост с опросом - голосуем:)

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