Задать вопрос
  • Как должен выглядеть идеальный контроллер?

    Если хотите идеал, то он должен соответствовать следующим пунктам:

    1. Сериализация/десериализация - это дорогостоящее мероприятие, поэтому оно должно делаться только в двух местах: прямо на входе и прямо на выходе. Вход - это ваш контроллер, Выход - это другой сервис, куда вы передаёте данные, или база данных (тут тоже происходит сериализация, либо явно, либо в ORM). Во всех остальных слоях инфообмен должен совершаться уже при помощи объектов PHP либо нативных типов. Это экономит ресурсы. При передаче между слоями приложения объектов вместо значений либо ассоциативных массивов вы сразу будете видеть очепятки, IDE вам прекрасно поможет при помощи автодополнения, объекты могут иметь какие-то полезные методы.

    2. Очень желательно в каждом из слоёв иметь собственный класс, отвечающий за данные. Например, нам в слой API приходит JSON-чик с новым пользователем.
    - Сериализуем JSON в DTO UserInAPI, сразу валидируем всё то, что мы можем валидировать без слоя бизнес-логики, и либо отдаём клиенту ошибку, либо передаём сам объект UserInAPI в следующий слой: слой бизнес-логики
    - В слое бизнес логики, получаем DTO UserInAPI на входе, преобразуем его в свой бизнес-объект UserInBusiness, валидируем его уже с точки зрения бизнеса, и либо возвращаем ошибку в слой API, либо совершаем над ним действия, и передаём объект класса UserInBusiness в слой работы с базой
    - В слое работы с базой данных получаем на входе объект UserInBusiness, преобразуем его уже в сущность базы данных UserInDB, валидируем всё на предмет корректности данных для базы, и либо возвращаем ошибку в бизнес, либо сохраняем сущность класса UserInDB в базу.

    Зачем такие сложности, вы спросите? А просто обратите внимание на то, что скорость изменения кода в разных слоях разная.
    - API вообще должен меняться раз в сто лет, чтобы не злить клиентов. Поэтому DTO класс UserInAPI будет стабильным и редко будет меняться.
    - Бизнес-логика меняется очень часто. У класса UserInBusiness постоянно будут добавляться поля и методы, тут жизнь будет кипеть.
    - Слой базы данных будет меняться реже, чем слой бизнеса, но чаще, чем слой API, потому что нам нужны будут новые поля в базе, новые таблицы и связанные таблицы.
    - И если мы один тип сущности протащим во все слои, то эта сущность обрастёт таким количеством различной хрени, что нам плохо станет, когда будем на неё смотреть. Либо она обрастёт кучей декораторов в каждом из слоёв. Поэтому лучше всё разделить.

    3. Теперь внимание, казалось бы, что мы слишком сильно связываем наши слои, и нижестоящие слои знают что-то о вышестоящих, а это неправильно. Ведь мы передаём объект UserInAPI в слой бизнеса, т.е. слой бизнеса должен уметь работать с этим объектом. И так же слой базы должен уметь работать с объектом бизнеса UserInBusiness. Как же быть? А очень просто. На входе слоёв использовать интерфейсы. Т.е. в слое бизнеса мы будем принимать не сам класс UserInAPI, а объект, имплементирующий интерфейс UserIncoming, который объявим в бизнес слое, и заставим слой API сделать так, чтобы его класс UserInAPI имплементировал этот интерфейс. Таким образом слой бизнеса ничего не будет знать о слое API, а будет ждать на входе данные по контракту, описанному в интерфейсе. Бизнесу плевать на конкретную реализацию, ему нужны только методы getUsername, getEmail из интерфейса. А какой класс ему их предоставит - пофигу. Таким образом мы практически полностью разделяем слои и в два счёта сможем поменять слой API, где у нас HTTP контроллеры, на слой RabbitMQ, SOAP, Grpc и т.д.
    Ответ написан
    6 комментариев
  • Как правильно делать большие сайты? обязательно ли писать каждую страницу по отдельности?

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

    Итого, есть три пути:

    1. Беспроигрышный. Это Wordpress. Берете, делаете, все счастливы. Туториалов миллиарды, плагинов ещё больше, всё будет зашибись. Проблема одна: если надо будет тонко настраивать, то надо будет хоть немного изучить PHP.

    2. Когда надо быстро что-то добавить, даже с мобилы или с компьютера девушки, и чтобы оно сразу отобразилось на сайте, то либо смотрим в сторону п.1, либо если не хотите изучать PHP, выбираете себе CMS на базе Javascript. Есть даже так называемые headless cms, которые генерируют вам только JSON, а вы у себя на фронтенде сами его обрабатываете и рисуете всё на основе полученных данных.

    Это самый сложный вариант из трёх

    Вот список некоторых из таких CMS
    https://jamstack.org/headless-cms/

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

    Сразу посоветую вам Astro https://astro.build/

    Прелесть Astro в том, что новый контент вы можете писать в Markdown. Это такой простейший язык разметки текстовых документов. Вы сможете его выучить за час, не больше. Там всё настолько интуитивно и просто, что больше времени вам не понадобится. При этом формат мощный, убедиться в этом можно, посмотрев почти любой репозиторий на Гитхабе. Практически каждый из них имеет файл README.MD, где как раз всё написано в Markdown (MD)

    В Astro вам надо будет создать несколько шаблонов astro (html). Шаблон хедера, футера, сайдбара, основного контента, разных типов страниц (статья, список статей, и т.д.). И в этих шаблонах будет указано, где нужно выводить сгенерированный из Markdown контент. И далее новые странички вы будете добавлять путём добавления в соответствующие папки файликов с Markdown разметкой. Это очень просто, быстро и не напряжно.

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

    Берите youtube, набирайте там "Astro markdown", и изучайте туториалы. Процесс всего этого чрезвычайно прост, вы много времени не потеряете, зато сэкономите себе массу времени на создании новых материалов на сайте

    Можете посмотреть и другие генераторы статических сайтов тут https://jamstack.org/generators/
    Ответ написан
    Комментировать
  • Не находит пакет gitlab-ee на Ubunty. Что делать?

    Не мучайтесь. Берите докер.

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

    docker run --detach \ # Запускаем контейнер в фоновом режиме
      --publish 443:443 --publish 80:80 --publish 22:22 \ # Открываем порты. Можете поставить те, что вам нужны, если эти уже используются где-то
      --name gitlab \ # Имя контейнера
      --restart always \ # Перезапускать контейнер при его остановке или перезагрузке
      --volume gitlab_config:/etc/gitlab \ # Подключаем том для конфигурации
      --volume gitlab_logs:/var/log/gitlab \ # Подключаем том для логов
      --volume gitlab_data:/var/opt/gitlab \ # Подключаем том для данных
      --shm-size 2gb \ # Устанавливаем размер разделяемой памяти
      gitlab/gitlab-ee:latest


    Или же можете использовать docker-compose.yml файл и запускать, находясь в этой же дириктории, через:

    docker compose up -d

    version: '3.6'
    services:
      web:
        image: 'gitlab/gitlab-ee:latest'
        container_name: gitlab
        restart: always
        ports:
          - '80:80'
          - '443:443'
          - '22:22'
        volumes:
          - 'gitlab_config:/etc/gitlab'
          - 'gitlab_logs:/var/log/gitlab'
          - 'gitlab_data:/var/opt/gitlab'
        shm_size: '2gb'
    
    volumes:
      gitlab_config: {}
      gitlab_logs: {}
      gitlab_data: {}


    Если докер у вас свежий и будет ругаться на наличие 'version', то просто удалите строчку с version

    Чтобы узнать начальный пароль, выполните:

    docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
    Ответ написан
    4 комментария
  • Что пытается сделать злоумышленник на моем сайте?

    На первом скрине, похоже, атака через "Stacked Queries". Хацкер надеется, что вы не отфильтровали входящие данные.

    Допустим у вас из бройзера приходит ID товара. И в программе запрос:

    SELECT * FROM products WHERE productid={нефильтрованный ID};


    Хакер отправляет вместо ID товара следующее:

    1; SELECT pg_sleep(25)


    В результате получится запрос:

    SELECT * FROM products WHERE productid=1; SELECT pg_sleep(25);


    И ваш сервер при каждом таком запросе будет спать 25 секунд. И порядочное количество таких запросов в случае удачи атаки смогут повесить вам там всё.

    То, что он продолжает долбиться, ничего не значит. Он, наверняка, использует какого-то бота, где накиданы в кучу различные векторы атаки, и они все применяются, пока ваш сервер не упадёт в результате срабатывания какой-то из них.
    Ответ написан
    Комментировать
  • Проблема SEO во Vue 3?

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

    Вот вам рантайм, написанный на чистом Go:
    https://github.com/dop251/goja

    Я не специалист в SEO, но где-то слышал, что поисковики научились индексировать SPA.
    НО!!!

    1. Это не точно) И вам надо провести мини исследование. Найти какие-то популярные SPA сайты и поглядеть архив Гугла и Яндекса по ним.

    2. Если это работает, то самое главное, что вам нужно усвоить, это то, что каждый чих должен отражаться в URL. History API должен стать вашим всем. Выбрали какую-то сортировку или фильтр таблицы с данными или списка статей? Всё это должно ОБЯЗАТЕЛЬНО отражаться в URL, как если бы вы писали какой-то традиционный сайт на PHP. Только в этом случае вам можно надеяться, что контент хоть как-то будет проиндексирован. Это, кстати, даст вам ещё одно преимущество: вы сможете без последствий нажать кнопку перезагрузки страницы, и её содержимое не должно измениться.

    3. Умение сказать заказчику НЕТ, одно из важнейших умений программиста. Пусть он взвесит на весах SEO и Go, и примет решение. Запросите у него космические деньги за сервер-рендеринг на Go, либо скажите, что можно гораздо дешевле сделать это на Nuxt.

    Либо можно пойти на компромисс, и сделать на Nuxt только лишь тупую мини-прослойку между фронтендом и основной бизнес-логикой, которая будет реализована в отдельном сервисе на Go
    Ответ написан
    3 комментария
  • Когда лучше использовать cms?

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

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

    - Во всех остальных случаях я предлагаю сперва задать себе вопрос: "А с какой целью я делаю этот проект?"

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

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

    3. Не задумывайтесь сильно о качестве кода. Вам всё равно предстоит сильно переделывать проект в будущем. Если вашу задачу по зарабатыванию денег решит один единственный файл index.php, то и наплевать на всё остальное. Совсем говнокодить, конечно, не надо. Ваша задача сделать код максимально простым и понятным. Чтобы через несколько месяцев вы, только взглянув на участок кода, сразу понимали бы, что там происходит. А то бывает, напишешь настолько изящную систему типов, монады, рекурсии, чистые функции, отложенные вычисления, разобьешь код на функции по три строчки каждая, приправишь это всё DDD, чистой архитектурой, SOLID, DRY и прочим, а потом целый день разбираешься, почему не можешь поменять цвет кнопки с красного на синий...

    Мораль: Да, инструмент всегда нужно выбирать под конкретную задачу. Но если вы, забив шуруп в доску микроскопом, обнаружите, что размера вашего кармана не хватает для потолстевшего кошелька, то можете смело плевать в лицо тем, кто будет вас осуждать за такое решение...
    Ответ написан
    2 комментария
  • Как правильно в Symfony десериализовать Request в DTO, а последний потом в сущность?

    Как человек, который в своё время так переусложнял код, что потом сам не понимал, что и где в проекте происходит, посоветую вам использовать самый лучший принцип на свете - "KISS"

    Поэтому, ничего сложного пока не выдумывайте, поверьте, вы всегда сможете потом всё усложнить)))

    Я бы сделал так:

    • В контроллере сериализуем JSON в DTO ( можно вообще вот так https://symfony.com/blog/new-in-symfony-6-3-mappin... )
    • Далее создаёс сервис, который будет нашим маппером, и который будет иметь 2 метода "fromDtoToEntity" и "fromEntityToDto", и он будет заниматься всеми преобразованиями туда-сюда.
    • В этом маппере пишем наитупейшую логику, как вы и писали $user-setAge($DTO->getAge());
    • Отдаём клиенту ответ из контроллера


    Этот вариант максимально прозрачен и сильно сэкономит вам время при дебаге, потому что вы в два клика сможете найти всю логику.
    Ответ написан
    9 комментариев
  • Как сделать импорт переменной из 1 пакета, когда она в другой?

    Go не любит лишних усложнений. У языка такая философия.
    Вы ведь всё равно все ошибки держите в одном пакете, т.е. они всё равно в одной куче с точки зрения программы. Почему бы тогда вместо папок не использовать просто файлы? Т.о. плоская структура с именами файлов вместо папок будет соответствовать вашим нуждам.

    err.go
    account.go
    auth.go
    json.go
    registation.go
    Ответ написан
    Комментировать
  • Как сделать кривую линию между двумя блоками диаграммы?

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

    https://github.com/clientIO/joint

    Примеры:
    https://codepen.io/jointjs
    Ответ написан
    Комментировать
  • Шифрование уникальной ссылки для пользователя. Как реализовать?

    Можно вообще отказаться от базы, и использовать JWT токен. В нём можно указать идентификатор пользователя в зашифрованном виде, время жизни ссылки и любую другую необходимую информацию. В базе данных ничего хранить не надо. Однако учтите, информация в JWT токене не зашифрована по умолчанию, любой может её из него вытащить. Прелесть JWT токена в том, что его нельзя изменить, потому что он подписан ключом шифрования. Это на случай, если база данных - драгоценный ресурс, который вы не хотите использовать.
    Ответ написан
    Комментировать
  • По какому принципу работает алгоритм с массивом очереди?

    Вот вам готовая простейшая очередь в виде объекта без всяких переборов:

    class Queue {
      constructor() {
        this.items = {};
        this.front = 0;
        this.rear = 0;
      }
      enqueue(item) {
        this.items[this.rear] = item;
        this.rear++;
      }
      dequeue() {
        const item = this.items[this.front];
        delete this.items[this.front];
        this.front++;
        return item;
      }
      peek() {
        return this.items[this.front];
      }
      get size() {
        return this.rear - this.front;
      }
      isEmpty() {
        return this.rear == 0;
      }
    }
    const queue = new Queue();
    queue.enqueue(1);
    queue.enqueue(2);
    queue.enqueue(3);
    queue.enqueue(4);
    queue.enqueue(5);
    
    console.log("Объект очереди: ", queue);
    
    const removed_element = queue.dequeue();
    console.log("Обработанный (удаленный) элемент: ", removed_element);
    
    console.log("Объект очереди:", queue);
    
    const top_element = queue.peek();
    console.log("Текущий элемент очереди для обработки (без удаления): ", top_element);
    
    const queue_length = queue.size;
    console.log("Размер очереди: ", queue_length);
    Ответ написан
    Комментировать
  • Где писать логику работы с БД?

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

    Однако, лично я считаю этот паттерн вредным, потому что он намешивает всё в одну кучу. Это моё субъективное мнение, и я вам его не навязываю. Я бы отделил мух от котлет, и оставил бы структуру чистой, т.е. только данные и какие-то методы, которые работают конкретно с этими данными из структуры, а взаимодействие с базой данных организовал бы через паттерн проектирования Repository. Т.е. мы делаем уже отдельную структуру ProductRepository, которая содержит в себе методы, принимающие и отдающие структуру Product, и уже в этих методах реализуем вызов базы данных.

    Я набросаю вам простенький интерфейс для использования этого паттерна, а конкретную структуру, реализующую этот интерфейс вы уже напишете сами. Интерфейсы использовать в таких случаях считаю вообще обязательным условием. Например, так нам будет гораздо проще тестировать код, всё становится гораздо гибче. Ведь структурку Product вы сможете без проблем использовать не только при работе с базой, но и при передаче данных в другие системы, не волнуясь о лишних методах, висящих на ней. Так же вы сможете легко менять реализации репозитория, не меняя бизнес-логику проекта. (Это позволит, например, легко заменить базу данных)

    package models
    
    type Product struct {
    	ID    int    `json:"id"`
    	Title string `json:"title"` //Название
    	Price int    `json:"price"` //Цена
    }
    
    type ProductGetter interface {
        GetAll() ([]Product, error)
        GetByID(id int) (Product, error)
    }
    
    type ProductCreator interface {
        Create(product Product) (Product, error)   
    }
    
    type ProductUpdater interface {
        Update(product Product) (Product, error)
    }
    
    type ProductDeleter interface {
        Delete(id int) error
    }
    
    type ProductRepository interface {
        ProductGetter
        ProductCreator
        ProductUpdater
    }
    Ответ написан
    4 комментария
  • Получил заказ на первый сайт от знакомых, выбираю бэкенд систему - cms либо python, что в связи с этим посоветуете?

    Язык программирования, фреймворки, CMS и т.д. - это только лишь инструменты для выполнения главной задачи: решить бизнес-проблему заказчика.
    С этим пониманием сделаем вывод, что выбирать инструмент нужно наиболее подходящий к задаче, но так же надо учитывать и то, насколько хорошо вы владеете тем или иным инструментом. Но всё же научиться пользоваться молотком гораздо быстрее и проще, чем мучиться, забивая гвоздь микроскопом.
    А при слове "визитка" мой опыт громогласно кричит WordPress!
    Ответ написан
  • Что делать, если unexpected end, но код раньше работал?

    У вас открывающих тегов "<?php" 28 штук, а закрывающих "?>" - 29 штук. Один из ваших открывающих тегов укороченный "<?" (строка 155).  Я не знаю, какая у вас сейчас версия PHP и какая настройка по поводу коротких тегов, но рекомендую короткие открывающие теги не использовать.

    Плюс рекомендую исправить ошибку, два раза закрываете один и тот же тег
    668a9eff0f49b708574679.png

    А еще всегда попробуйте везде добавить пробел перед вопросом в закрывающей конструкции "?>".
    Очень часто именно это является проблемой
    Ответ написан
    6 комментариев
  • А возможно ли сделать свой дублирующий хостинг-сервер?

    Для надёжности вам нужно 3 сервера:
    1 - ваш VPS
    2 - ваш домашний сервак
    3 - Load balancer, который будет настроен таким образом, чтобы направлять трафик на сервер 1, но если он лёг, то направлять его на сервер 2.

    Чтобы не покупать отдельный сервер под Load balancer, можете посмотреть в сторону специальных сервисов. Например Cloudflare: https://developers.cloudflare.com/load-balancing/
    Ответ написан
  • Из-за чего инкрементация в for и while срабатывает по разному?

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

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

    Уяснив этот момент, можно пойти в документацию, прочитать там все, а особенно обратить внимание на табличку, где расписано, когда именно выполняется каждая составная часть цикла for. И тогда вам всё станет гораздо понятнее.
    https://learn.javascript.ru/while-for

    Советы:
    1. Всегда читайте документацию, если вам что-то не понятно в конструкциях языка. Не туториалы от балбесов с Ютуба, а документацию. И желательно оригинальную на английском, потому что переводчики иногда такие же балбесы.

    2. Не используйте никаких циклов, кроме for. Он очень мощный и позволяет реализовать функциональность и while и do-while. Так вы убережёте себя от таких ситуаций. Я за много лет работы понял, что большое количество конструкций языка скорее вредно, чем полезно.
    Ответ написан
    2 комментария
  • Как эффективнее всего вести создание продукта?

    Если у вас уже устойчивый бизнес, приносящий твердый доход, вы точно знаете, что за инструмент вам нужен, точно знаете, что этот инструмент принесёт вам ощутимую дополнительную прибыль (не обязательно в ближайшее время), то не стоит обращать слишком большое внимание на его исходную стоимость. И в этом случае нужно брать исключительно первый вариант. Почему? Потому что тут важно не изначальное создание сервиса, а его грамотная и ответственная поддержка. Я вас уверяю, что у вас не получится сразу создать идеальное решение, потому что практически всегда после изначального создания продукта появляются подводные камни, с которыми надо как-то бороться. И пусть с ними борются ответственные люди, которые проект создали. Это будет быстро и качественно.

    Если же вы хоть немного сомневаетесь в том, будет ли этот сервис приносить вам прибыль, или сомневаетесь в том, какие из функций вам действительно нужны, какие вредны, а от каких можно отказаться, то вот тут можно сэкономить, создав сервис в режиме чуть ли не "прототипа" за недорого. Если вы увидите, что он работает, начнёт приносить какую-то дополнительную прибыль, то уже из этой прибыли вы сможете выделить средства на то, чтобы переписать его с нуля, либо основательно развивать уже с более ответственной и профессиональной командой. А если он окажется не прибыльным и без перспектив, то вы не потеряете очень много денег, отказавшись от него.
    Ответ написан
  • Как включить режим высокой производительности?

    - Если приложение, в котором вы сравниваете производительность, написано для Винды и только потом портировано на Linux, то вы можете увидеть даже падение производительности. И то же самое наоборот: если приложение или сервис изначально сделаны для Linux, то тут может быть разница уже в его сторону. Типичный пример - Docker

    - Производительность хорошо оптимизированных приложений, которые выжимают все соки из CPU/GPU будет примерно одинакова.

    - Gnome, который стоит у вас в Ubuntu в качестве окружения - тормозящая и жрущая все ресурсы какашка. Если вы установите какое-то легковесное окружение или даже просто какой-то Window manager, вот тут вы заметите явный прирост в отзывчивости всего и вся.

    - И, наконец, главный источник производительеости - это работа с памятью. Если вы замените Gnome на лёгкое окружение, то расход памяти значительно уменьшится. На Linux обычно нет встроенной телеметрии, рекламы и остального шпионского мусора, как в Винде. Это тоже экономит память. И вот, когда на Винде наступит момент забраться в swap, на Linux останется ещё много свободной памяти. В этот момент Винда начнёт лагать, а Linux продолжит летать.
    Ответ написан
    4 комментария
  • Как маппить результат запроса бд в структуры со вложенностями Golang?

    - Я считаю, что свой кастомный маппер - это отличное решение. Чтобы быть уверенней, обязательно напишите тесты. Как unit, так и интеграционные, например, с помощью testcontainers.

    - Можете вместо pgx посмотреть в сторону sqlc. У него совершенно другой подход. Вы пишете запрос со всеми джойнами, а он вам автоматически генерирует код со всеми структурами и функциями. Правда, там по джойнам практически отсутствует документация, но уж погуглите.

    - Ну, и если совсем сложно... то... может одним глазком глянуть в сторону ORM? Я никому не расскажу...
    Ответ написан
    5 комментариев