Пишем REST API сервис на Go - УЛЬТИМАТИВНЫЙ гайд

Sdílet
Vložit
  • čas přidán 7. 06. 2024
  • Пишем полноценный REST API сервис URL Shortener - это будет не игрушечный проект, а полностью готовый к использованию:
    - выберем для него актуальный http-роутер: go-chi/chi
    - Позаботимся о логах: slog
    - Напишем тесты - unit-тесты, тесты хэндлеров и функциональные
    - Настроим автоматический деплой через GitHub Actions, напишем для этого workflow
    - и др.
    Облачный сервер, который я использовал: slc.tl/torpo
    Репозиторий проекта: github.com/GolangLessons/url-...
    Другие мои ролики, дополняющие текущий:
    Интерфейсы по месту использования: • Почему интерфейсы лучш...
    Моки и их генерация: • Генерация и использова...
    Использование SQLite в Go: • SQLite в Golang - как ...
    ✍Текстовый вариант гайда: habr.com/ru/companies/selecte...
    Буду очень благодарен за вашу поддержку и там ❤
    ----
    👾 t.me/ntuzov - мой канал в Telegram-канал.
    Пишу в нём много интересного: гайды, которых нет на CZcams, интересные мысли про разработку, новости и анонсы всех моих активностей и др.
    👀 GoLang Digest: t.me/golang_digest - мои регулярные подборки интересных материалов по Go.
    🗣️ Наше сообщество GopherClub: t.me/+zsSZ63wEJDs3NGVi
    Лучшее русскоязычное Go-сообщество с очень приятной атмосферой, без токсиков. Вежливо и терпеливо помогаем новичкам, конструктивно дискутируем с профессионалами и т.п.
    Здесь также присутствуют все звезды Go-сообщества и представители интересных компаний 😄
    ❤️ Если у вас есть желание поддержать развитие канала:
    Секретный телеграм-канал:
    - В рублях: t.me/+1UPXV_DGnG1mODJi
    - В евро: t.me/+hedI8LevYTc5MDM6
    Boosty: boosty.to/nikolay.tuzov
    Patreon: / tuzov
    ----
    Тайм-коды:
    00:00 Вступление
    01:28 Почему мой Telegram-канал очень важен
    03:05 Про папку cmd
    03:46 План работ и описание используемых библиотек
    07:46 Конфигурация приложения и работа с конфигами - CleanEnv
    21:34 Настройка логгера - slog
    30:25 Пишем Storage - БД / хранилище данных сервиса - SQLite
    43:56 SaveURL() - пишем метод Storage для сохранения URLов
    50:01 GetURL() - метод Storage для получения URLов
    51:40 DeleteURL() - упражнение для самостоятельной работы
    52:29 Создаём роутер - Chi
    53:27 Middleware для роутера - что это?
    54:30 Подключаем Middleware: RequestID и RealIP
    56:19 Middleware для логирования запросов
    01:02:43 Middleware: Recover и URLFormat - удобный парсинг URL-параметров
    01:04:20 Pretty Logger - крутые красивые логи для локальной разработки
    01:08:35 Handler: Save - обработчик запросов на сохранение URL
    01:35:09 Создание и запуск HTTP сервера
    01:38:08 Пишем тест для хэндлера Save
    01:52:13 Функциональные тесты - что это такое, и чем они лучше?
    01:53:37 Handler: Redirect - редиректим пользователя на сохранённый URL
    02:00:23 Handler: Delete - упражнение для самостоятельной работы
    02:01:37 Авторизация - ограничение прав доступа к некоторым хэндлерам
    02:07:03 Авторизация: как её протестировать с помощью Postman
    02:08:06 Пишем тест для хэндлера Redirect
    02:13:18 Функциональные тесты - тестируем приложение как черную коробку
    02:28:23 Настраиваем деплой проекта на удалённый сервер
    02:28:46 Покупаем сервер у Selectel
    02:36:00 GitHub Actions: настройка автоматического деплоя проекта
    02:37:38 GitHub Actions: Пишем Worflow для деплоя
    02:47:27 systemd: настройка автоматического запуска сервиса
    02:48:58 Запускаем и проверяем деплой через наш Workflow
    02:50:32 GitHub Secrets: хранение приватной информации для деплоя
    02:52:44 Успешный деплой через наш Workflow
    02:53:18 Тестируем наш сервис на удалённом сервере
    02:55:21 Заключение
    #golang #ntuzov

Komentáře • 205

  • @nikolay_tuzov
    @nikolay_tuzov  Před 11 měsíci +13

    👾Мой канал в Telegram: t.me/ntuzov
    Пишу там новости, анонсы своих активностей и просто интересные мысли
    Также с его помощью я получаю от вас оперативный фидбэк по роликам - что нравится, что не нравится, какой ролик делать следующим и т.п.
    ❤ Если у вас есть желание поддержать развитие канала:
    Секретный телеграм-канал:
    - В рублях: t.me/+1UPXV_DGnG1mODJi
    - В евро: t.me/+hedI8LevYTc5MDM6
    boosty.to/nikolay.tuzov
    www.patreon.com/tuzov

  • @STAP2011
    @STAP2011 Před 11 měsíci +28

    Приятно видеть полезные содержательные видео для новичков на великой Гошечке без всяких ужасностей - сразу к делу, качественно на уровне продакшн кода и без воды, уважаемо!

  • @vitiok78
    @vitiok78 Před 11 měsíci +7

    Только начал смотреть, но уже по содержанию вижу, что это золотое видео! Спасибо!

  • @wat4mon
    @wat4mon Před 11 měsíci +23

    ЛУЧШЕЕ ЧТО МОЖЕТ БЫТЬ В СУББОТНЕЕ УТРО. СПАСИБО ОГРОМНОЕ ЗА КОНТЕНТ. ПРОСТО ЛУЧШИЙ!!!!

    • @paniciour
      @paniciour Před 11 měsíci +1

      э, что угодно?..

  • @oliverswanick4965
    @oliverswanick4965 Před 11 měsíci +42

    Даешь видео про миграции!

    • @radikovichkz2470
      @radikovichkz2470 Před 8 měsíci

      В golang нет миграций

    • @console.g
      @console.g Před 3 měsíci +1

      В Турцию можно мигрировать

  • @user-qp3lt4ps8c
    @user-qp3lt4ps8c Před 6 měsíci +1

    Отличный гайд, Николай. Очень познавательно и интересно смотреть твое творчество. Респект!

  • @vladosssss1088
    @vladosssss1088 Před 9 měsíci

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

  • @idgalushko
    @idgalushko Před 2 měsíci +2

    Николай, спасибо огромное за ваш труд и творчество! Благодаря вам, научился создавать веб-сервисы, которые очень удобно масштабировать, рефакторить и поддерживать, пересаживать на любые базы данных и реализации кэша, а также подключать несколько серверов, реализующих различные протоколы обмена данными! А всё благодаря разделению общей архитектуры на слои и интерфейсам! Просто топ, ещё больше стал любить писать на Go благодаря вам!

    • @nikolay_tuzov
      @nikolay_tuzov  Před 2 měsíci +2

      Рад, что помог ❤️
      Всегда очень приятно видеть такие отзывы

  • @user-sp1gr6xb7q
    @user-sp1gr6xb7q Před 2 měsíci +1

    Мужик, ты крут, спасибо тебе за такие видео. Действительно очень полезные!

  • @unicoxr5tj417
    @unicoxr5tj417 Před 11 měsíci +6

    даешь практику для народа! Таким видосам тока лайк

  • @y0oshi2
    @y0oshi2 Před 3 měsíci

    круто объясняет и самое главное, наглядно все показывает на практике👌

  • @Iongjump
    @Iongjump Před 11 měsíci +4

    Спасибо за контент ❤

  • @user-fd9bg1gm8z
    @user-fd9bg1gm8z Před 11 měsíci +2

    Спасибо огромное за контент!

  • @user-ir3eg9uc9g
    @user-ir3eg9uc9g Před 11 měsíci +2

    Спасибо за контент!

  • @purplecorvette
    @purplecorvette Před 9 měsíci +10

    почему не сетится CONFIG_PATH
    фатал печатает что конфиг пас не установлен(

    • @aleksandrpetrov3938
      @aleksandrpetrov3938 Před 2 měsíci +2

      Видимо имеется ввиду что запускать мы будем основной скрипт так CONFIG_PATH=./config/local.yaml go run main.go - и у нас есть свобода выбора какой путь к конфигу указать. Если на проде, то файл уже другой просто указываем и всё

  • @RusFarFaz
    @RusFarFaz Před 10 měsíci +4

    Хотелось бы про concurrence и паттерны их использования. Например воркеры, fan-in , fan-out

  • @jimshtepa5423
    @jimshtepa5423 Před 10 měsíci

    в самом начале когда вы перешли к написанию кода и начали создавать папку cmd, вы использовали какой то пакет который генерирует шаблон для проекта? (типа как vitejs на javascript чтобы собрать шаблон проекта?). или вы сами создали паку url-shortener и внутри создали файлы вручную?

  • @dmitriybogdanov6291
    @dmitriybogdanov6291 Před 11 měsíci +4

    Спасибо за труд!

    • @AndrewYurchenko
      @AndrewYurchenko Před 9 měsíci

      Блин. А в видео - это где можно увидеть? )) Хорошо, что уже не первый день обучалки смотрю и знаю о таких "выкрутасах от блогеров" - читать в надежде комменты. Но, все же. Это баг!!! )))

  • @soundcloudlover
    @soundcloudlover Před 10 měsíci +2

    Будут ли видео по внутренностям go? А именно как точно устроена сборка мусора и как работает планировщик/аллокаторы? спасибо

  • @dn.kolesnikov
    @dn.kolesnikov Před 11 měsíci +1

    Про slog видео будет в паблике? Интересно твоё видение его кастомизации и настройки.

  • @svfastunov
    @svfastunov Před 11 měsíci +5

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

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +6

      По мониторингу точно будет отдельное видео. У меня уже есть материал, я хотел в этом видео о нем рассказать. Но потом решил всё же отдельно, т.к. ролик слишком большой получался.

  • @crazy_fedor
    @crazy_fedor Před 6 měsíci +3

    Николай, материл от вас - просто супер. Выпустите пожалуйста видео про миграции! 🌷

    • @nikolay_tuzov
      @nikolay_tuzov  Před 6 měsíci

      А что именно интеренсо про миграции услышать? Помимо того, что было показано в этом видео

  • @user-wv7gz3lg4b
    @user-wv7gz3lg4b Před 5 měsíci

    Видео очень хорошее, спасибо автору!
    Если есть возможность, можно ещё видео про деплой не через гитхаб, а через гитлаб ci/cd? Было бы 🔥

  • @dizelvinable
    @dizelvinable Před 11 měsíci +1

    Ух, супер!

  • @alpenveg
    @alpenveg Před 11 měsíci

    Спасибо за видос!

  • @alexobzor
    @alexobzor Před 9 měsíci

    По поводу тестирования хэндлера save, почему запрос NewRequest берётся из библиотеки http, а не httptest? В основе теста же лежит именно Response Recorder, соответственно не создаётся сервера на loop back, ну и нужды в реальном запросе нет, тогда почему бы не юзать из httptest?

  • @samoiloff90
    @samoiloff90 Před 11 měsíci

    Просто огонь контент

  • @Evg2002
    @Evg2002 Před 3 měsíci

    спасибо, все очень круто!

  • @jimshtepa5423
    @jimshtepa5423 Před 10 měsíci

    какую команду выполнили когда запустили программу в самом начале чтобы убедиться что все конфиг настройки были учтены? просто git init? или что то еще

  • @inspired_by_space
    @inspired_by_space Před měsícem

    Подскажите пожалуйста, почему в каждом методе Storage , вы пересоздаете подготовленные выражения (stmt) при каждом вызове метода, а не ,например создаете специальный метод в котором эти выражения будут подготавливаться и уже потом сразу использоваться в методах?

  • @hurricane-rus
    @hurricane-rus Před 5 měsíci +1

    Хорошее видео, разобрано много интересных подходов, спасибо. До хэндлеров было в целом понятно, потом объяснения пошли очень сжато и кратко, приходилось переслушивать 3-4 раза, чтобы стало понятно. Код хэндлеров очень плохо читается из-за кучи логов - может быть, их можно обработать как-то поэлегантнее?
    В будущих видео хочется как можно меньше моментов в стиле "просто добавьте сюда этот код, который я не буду объяснять" - по мне такой код лучше вообще не добавлять в проект (ну или потратить дополнительное время на его объяснение).
    P.S. Не понял, зачем нужно было делать столько лишних папок в проекте? (фактически каждый файл лежит в отдельной папке)
    Т.е., например, зачем папка sqlite в папке storage? Можно сразу storage.go кинуть в storage. Или в lib/logger папка sl кажется лишней - можно сразу sl.go кинуть в logger, и все. Если поудалять все эти лишние папки, дерево проекта будет намного меньше.
    Чем мне мешают эти дополнительные папки - они затрудняют ориентирование в проекте и сильно раздувают дерево проекта. А поскольку программист в основном читает код, то чем компактнее будут уложены файлы, тем лучше.

  • @ThePirateHistory
    @ThePirateHistory Před 6 měsíci +1

    Было бы классно ещё понимать как описать то что ты сделал в комите, допустим сделали логер, он работает для теста вывели пару сообщений, как записать просто "Initialized logger" и всё, или допустим создали какую-то структуру, вывели возможно менять конфигурацию логера в конфиг файл

  • @mini_clop
    @mini_clop Před 11 měsíci +2

    Утро наступило!

  • @dovm5d
    @dovm5d Před 3 měsíci +1

    48:08 - mySQL как раз таки поддерживает стандартным драйвером. PostgreSql стандартным драйвером точно не поддерживает, надо в конец запроса добавлять RETURNING id и вместо экзека отправлять запрос через QueryRow

  • @user-ed6qc1pn5o
    @user-ed6qc1pn5o Před 11 měsíci +4

    Огромное спасибо! Таких видео очень не хватает, особенно на русском. Сегодня вечером просмотрю видео и сам пройду все шаги. У вас вижу GoLand, а я в vscode пишу. Но, думаю, из-за этого сложностей не будет.

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

      Сложностей быть не должно. IDE - это лишь вспомогательный инструмент. Можно хоть в блокноте писать =)

    • @paniciour
      @paniciour Před 11 měsíci +1

      ​@@nikolay_tuzov не, не можно) интеграция гита, бд, рефакторинг, навигация - у вскода из коробки ничего этого нет, можно обвешаться гирляндой расширений, но зачем если можно просто переактивировать голанд раз в месяц на диспозабл емейл 💀

    • @jojogay7297
      @jojogay7297 Před 11 měsíci

      @@paniciour а че так можно реактивировать?

    • @paniciour
      @paniciour Před 11 měsíci

      @@jojogay7297 я этого не говорил, меня взломали)

    • @yakomisar
      @yakomisar Před 11 měsíci

      @@paniciourили neovim поставить, только выиграешь в долгосрок

  • @user-zg8ij3kt1h
    @user-zg8ij3kt1h Před 8 měsíci

    Я ещё не досмотрел, но вопрос, пока не забыл: как сюда подключить ещё и обработку параметров запуска из консоли (ключей типа --config)? Как их правильно с обработкой конфига дружить?

  • @vitiok78
    @vitiok78 Před 11 měsíci +1

    Миграции очень нужны!

  • @dimmodddimmodd7199
    @dimmodddimmodd7199 Před 11 měsíci +1

    Спасибо!

  • @tumenit
    @tumenit Před 11 měsíci +1

    Спасибо!!!

  • @ginger.samurai
    @ginger.samurai Před 11 měsíci +1

    ЛУЧШИЙ

  • @cartfpv4610
    @cartfpv4610 Před 10 měsíci

    1. Rest коды не используютя по какой то причине?
    2. Динамические/настраиваемые моки языком в принципе не поддерживаются? Все создавать в статике/ генерировать?

  • @Roman-tm6qp
    @Roman-tm6qp Před 29 dny

    2:00:10 - насколько правильно передавать объект storage в хендлер роута? Не будет ли лучше это делать внутри хендлера (там где мы работаем с базой непосредственно)?

  • @PlayGameToday
    @PlayGameToday Před 9 měsíci

    Привет, как называется модель кресла твоя? )

  • @artmon2004
    @artmon2004 Před 11 měsíci

    Супер! Пробовал пройти cоревнование Codeforces на стажировку в OZON, занял 300 место из 900 примерно, народу тьма в Go идет))))))

  • @bobmoclaat8965
    @bobmoclaat8965 Před 3 měsíci +5

    Почему config_path не найден пишет? Зачем мы тогда local.yaml создавали

    • @quiqlerbeats5933
      @quiqlerbeats5933 Před měsícem

      Тебе нужно путь до него в переменной окружения указать

  • @eleimt
    @eleimt Před 8 měsíci

    подскажите, про миграции есть видео?

  • @vladimireliseev7602
    @vladimireliseev7602 Před 11 měsíci

    Здравствуйте, Николай!
    Благодарю за видео!
    Хотелось бы узнать - почему Вы возвращаете именно ссылку на конфиг, а не значение из функции MustLoad?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +2

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

    • @vladimireliseev7602
      @vladimireliseev7602 Před 11 měsíci

      @@nikolay_tuzov благодарю!

  • @galahad667
    @galahad667 Před 2 měsíci

    Лучший канал по гошке на русском ютубе!!!

  • @datokhojava6421
    @datokhojava6421 Před 7 měsíci

    в ОП ubuntu имеет значение где я создам папку?

  • @kotlinjava5228
    @kotlinjava5228 Před 11 měsíci +6

    Большое спасибо за ролик,и уважение за флаг Казахстана на фоне!

  • @vitiok78
    @vitiok78 Před 11 měsíci +3

    Последнее время я всё реже использую автоматические id в базе данных. Именно из-за того, что id может быть неизвестен сразу после вставки. Я генерирую uuid, который не полностью рандомный, а типа последовательный. Таким образом, я заранее знаю id, и этот id не так сильно влияет на производительность базы, т.к. он уже отсортирован. Да, такое поле увеличивает размер базы, но оно слишком удобное, чтобы от него отказаться.

    • @vasyarodionov1369
      @vasyarodionov1369 Před měsícem

      а как же метод returnid?

    • @vitiok78
      @vitiok78 Před měsícem

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

  • @ThePirateHistory
    @ThePirateHistory Před 6 měsíci +1

    Решил делать как говорили в начале чтобы было аля своё, решил добавил логер в ямл конфиг, сделал как с http_server, всё работает за исключение что уровень логера с нулём просто не берёт выдаёт ошибку, ставлю допустим -4(дебагинг) всё работает, всё выводится как по видео, но если в кфг ямла ставлю 0 то всё, сам struct логера уровень логера int8

  • @grigorym6107
    @grigorym6107 Před 10 měsíci +13

    Подскажите пожалуйста, где вы устанавливаете значение CONFIG_PATH, чтобы потом читать его в файле internal/config/config.go, в строке configPath := os.Getenv("CONFIG_PATH")?

    • @gorsaroyan1060
      @gorsaroyan1060 Před 8 měsíci +1

      Я запускаю так CONFIG_PATH=./config/local.yaml go run ./...

    • @alonewalker4932
      @alonewalker4932 Před 6 měsíci

      Привет! Если ты разобрался с этим подскажи пожалуйста решение данной проблемы

    • @user-pb2nv3ye9w
      @user-pb2nv3ye9w Před 4 měsíci

      вы это делаете в терминале?
      @@gorsaroyan1060

    • @user-pb2nv3ye9w
      @user-pb2nv3ye9w Před 4 měsíci

      а это в терминале вы запускаете или где?
      @@gorsaroyan1060

    • @TheWorpX
      @TheWorpX Před 3 měsíci +4

      Я пофиксил таким образом (GoLand)
      Там где у нас есть ранер, тыкаем на стрелочку и тыкаем Edit Configurations
      Там у нас высветиться автоматически созданые ранер (это когда на зеленую стрелочку play нажимаешь около func main)
      Находим там поле Environment и прописываем туда CONFIG_PATH=./config/local.yaml
      Тыкаем Apply и стартуем

  • @alexsandr9444
    @alexsandr9444 Před 9 měsíci

    Да нужно про миграции

  • @ivan42832
    @ivan42832 Před 19 dny

    Отличный материал, Николай спасибо! Знакомлюсь с go первую неделю. Я правильно понимаю что реализовывать http апи это не специализация Го? По сравнению с другими языками по удобству и читаемости это прям боль, даже js/ts логичнее выглядит. При этом я уверен что Николай лучшие практики применял. Я в основном на php уже 10 лет разрабатываю так вот там бизнес логику и доступ к ней по http в разы удобнее, проще, быстрее реализовывать да и надежнее думаю. Но конечно куча других минусов по сравнению с Го. А вообще язык заинтересовал, для чегонибудь мелкого и быстрого отличчно подойдет

  • @paniciour
    @paniciour Před 11 měsíci +1

    Го видик по b-tree?) Не, го целый видик по имплементации базки с конкаренси, б-трии и фильтром блума!

  • @deuse7222
    @deuse7222 Před 10 měsíci

    Код по работе с БД и сетью же работает в один поток синхронно, если не ошибаюсь. В продакшен коде стоит сразу писать через горутины?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 10 měsíci +4

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

  • @williba100n5
    @williba100n5 Před 3 měsíci

    Спасибо

  • @MrLotrus
    @MrLotrus Před 10 měsíci

    Насколько распространена практика хранения констант с названием и путем функций для логирования? Выглядит как возможная мина и гемор при рефакторинге. Другого способа нет? А если получать в рантайме это считается плохой практикой?

  • @georgiy_kulagin
    @georgiy_kulagin Před 11 měsíci +2

    кайф

  • @Damir-nl6tf
    @Damir-nl6tf Před 5 měsíci

    Здравствуйте! Только начал изучать Go, хотелось бы узнать, то что пишет Николай в этом видео, обычно пишут Джуны Миддлы или Сеньоры? Спасибо всем за ответы!

    • @user-gy5lg4vp9i
      @user-gy5lg4vp9i Před 4 měsíci

      ждём, бро. Но думаю без подобных проектов на тебя HR даже не посмотрят

    • @Daloshka
      @Daloshka Před 3 měsíci

      export CONFIG_PATH=./config/local.yaml

  • @user-wh6ui3pz9q
    @user-wh6ui3pz9q Před 11 měsíci +1

    Спасибо за видео! Если у storage'a и URLSaver'a будут немного отличаться сигнатуры методов, то где описывать адаптер?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

      А зачем им отличаться? Их сигнатура должна совпадать.
      Может, такое и бывает, но я не сталкивался.

    • @user-wh6ui3pz9q
      @user-wh6ui3pz9q Před 11 měsíci

      @@nikolay_tuzov если например сторедж в другом пакете, не логично же интерфейс по месту использования подстраивать под этот сторедж🤔

  • @bladesquirtsize2541
    @bladesquirtsize2541 Před 5 měsíci +1

    У меня ошибка когда я запускал программу после того как мы сделали функцию mustLoad выдавало ошибку что configPath пустой .Мне нужно создать env переменную CONFIG_PATH ?Чтобы решить эту проблему

    • @KirMC
      @KirMC Před 4 měsíci +1

      Да, и она должна указывать путь до файла (понимаю вам скорее уже не надо, но вдруг кто увидит)

  • @user-yt2sb9tl3p
    @user-yt2sb9tl3p Před 11 měsíci

    38:39 почему используется log.Error и Os.Exit, экзит же насколько я понимаю отменяет все defer. Не лучше ли тут кидать панику?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      Да, согласен, os.Exit может быть не лучшим вариантом, если используется defer. Тут нужно быть аккуратным.

    • @user-bb5xw8bd8w
      @user-bb5xw8bd8w Před 11 měsíci

      @@nikolay_tuzov прибивать пустым мешком все открытые ресурсы - самый дубовый вариант

  • @ThePirateHistory
    @ThePirateHistory Před 6 měsíci +1

    1:14:09 как реализовать так чтобы наоборот, чтобы интерфейс был в отдельном файле в пакете sqlite. папка sqlite в том же месте что и у вас, затем внутри папка interfaces и там допустим save, и соответственно это надо как-то зарегистрировать в одноимённом файле пакета sqlite, как это сделать? Чтобы мы могли брать из одноименного файла sqlite и функцию save для сохранения url, а так же чтобы могли взять интерфейс в хандлере что в сервер, подскажите куда копать пожалуйста

    • @nikolay_tuzov
      @nikolay_tuzov  Před 6 měsíci

      Советую все подобные вопросы писать в Gopher Club. Они довольно сложные, не для комментов.

    • @ThePirateHistory
      @ThePirateHistory Před 5 měsíci

      @@nikolay_tuzov
      Тг хорошо, но безумно не удобно, в тг просто 1 чат, и там люди общаются о своём, ты что-то запостишь какой-то вопрос он почти моментом скроется, а спамить этим вопрос это плохо, даже просто реплаить по кд такое себе, лучше дискорд, там можно создать каналы, чтобы просто общения было отделено от тех вопросов.
      Но как помню или тут в начале видео или из тех что в описании, был такой момент что был интерфейс Users в котором были как раз таки все методы и они были в отдельных папках, и получается что туда вручную записываются, то в файле допустим по уроку sqlite будет интерфейс по типу Users в котором будут интерфейсы, но как это правильно называется чтобы лучше разобраться вроде понял а вроде не до конца.
      И если сможете, то подскажите как называется практика при которой такие вещи они регистрируется, чтобы был допустим интерфейс в котором можно запушить свой другой интерфейс, чтобы вручную всё не писать, чтобы не было сотни интерфейсов которые содержат интерфейсы которые ссылаются на интерфейсы.
      Допустим User
      User.signUpMethod(saveDefaultData)
      и потом можно в любом месте User.saveDefaultData('...', '...')

  • @anmill
    @anmill Před 11 měsíci

    Ролик про миграции - плизззз!

  • @mrfofaify
    @mrfofaify Před 8 měsíci +1

    Сделайте видео с проектом по чистой архитектуре

  • @alexeymatveev9031
    @alexeymatveev9031 Před 2 měsíci +1

    Посмотрел анонс, но понял, что приснилось. Не может быть столько крутоты.

  • @user-lv9ko1ru7e
    @user-lv9ko1ru7e Před 11 měsíci +5

    На мой взгляд коду рано в реальное использование
    1) неоправданно сложная структура проекта(было тяжело читать код) + сервис очень напоминает код node+express
    2) явное отсутствие слоёв приложения
    3) разделение интерфейсов для обращения к бд на отдельные операции???
    4) отстутсвие контекста в методах для работы с бд(если бд находится локально, это не значит, что с таймингами будет всё ок. Например при обращении к бд может быть нагрузка на диск 100% и запрос будет схлопнут таймаутом который указали при конфигурации http сервера, что является не лучшим решением) + в серьёзных сервисах конфигурируют таймауты под каждый слой
    5) цитата: "изза одного единственного запроса хэндлера не должно приложение падать целиком". Полностью несогласен! Для такого приложения с простой логикой все запросы "одинаковые" и если у нас происходит гдето паника, значит она будет происхдить постоянно, а в таком случае приложение работать не должно(его надо чинить) + дефолтный хттп сервер сам отлавливает паники
    6) приложение никак не валидирует урлы, такое чувство, что это не сокращатель урлов, а переосмысленный редис.
    7) time.Now() используется без часового пояса
    8) нету Readme и Swagger(пришлось лезть в код, чтобы понять как запускать сервис)
    9) save_test.go:83 require.Equal(t, rr.Code, http.StatusOK) - если быть невнимательным, то создаст весёлую проблему
    10) хэлсчек! Как минимум это первое что проверяют если с сервисом проблемы, лучше всего делать через вызов db.PingWithContext(ctx)

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

      Спасибо за фидбэк, но с большинством пунктов в корне не согласен:
      1) очень абстрактное заявление, довольно субъективный. В чем конкретно сложность? Что именно тяжело читать?
      2) В предыдущем пункте вы жаловались на сложность, а добавление слоёв сложность увеличит. Их потому и нет - чтобы не переусложнять приложение. На мой взгля, в подобное проекте можно прекрасно обойтись без них. Если вы с этим не согласны, можем обсудить - приведите примеры, в которых у нас будут проблемы из-за отсутствия слоёв?
      3) Да, а что с этим не так? Если подход непонятен, смотрите мой ролик на эту тему (ссылка есть в описании)
      4) Тут согласен, контексты стоило добавить, это мой промах
      5) "если у нас происходит гдето паника, значит она будет происхдить постоянно" - абсолютно неверное утверждение. У нас есть тесты, а значит, как минимум, happy path и некоторые fail-кейсы будут работать. Если паника и появляется, то точно не во всех случаях. Так зачем падать всему приложению целиком? Чтобы перестать обрабатывать даже корректные запросы? Что нам это падение вообще даст?
      6) Посмотрите внимательней, валидация урлов - это вообще единственный валидатор, который у нас есть (помимо required), в хэндлере Save.
      7) А зачем нам часовой пояс? Вы точно смотрели ролик, и просто бегло про коду прошлись? Во всем проекте всего 2 точки использования данной функции: подсчет дельты и задание сида в рандомайзере. Для чего там часовой пояс?
      8) Readme не помешал бы, согласен. Но это явно не must have фича для работы приложения в продакшене, а скорее помощь себе в будущем.
      9) Не очень понял, о какой проблеме речь?
      10) Да, тут согласен, стоило сделать что-то простенькое. Но вообще, полноценный мониторинг будем делать в отдельном ролике

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      Если хотите обсудить подробней, приглашаю вас в наш чат Gopher Club (ссылка в описании). Приходите, подискутируем. Заодно и сообщество рассудит, кто из нас прав. Там присутствуют и гораздо более опытные коллеги, чем я.

    • @user-lv9ko1ru7e
      @user-lv9ko1ru7e Před 11 měsíci

      @nikolay_tuzov
      1) да, тяжело читается, хотя кода немного
      2) я думаю большинство тех, кто смотрел видео это джун или тот кто хочет устроиться джуном, и на мой взгляд стоило бы показать как "правильно делать", потому что придут они на работу и начнут слой данных выпиливать ссылаясь на это видео). Если это попытка в хайлоад/уменьшение расхода памяти/времени отклика, то стоило бы и с остальным кодом то же самое делать
      Про проблему отсутствия слоёв, она возникнет когда захотите сменить бд, sqlite хороша, но когда нужно будет уходить от неё, то всплывёт проблема отсутствия слоя данных(возможно не такая острая как в серьёзных сервисах, где извращаются над запросами в целях оптимизаций, но будет, как минимум сейчас нет возможности вынести в конфиг тип базы для сервиса и переключиться например на редис или монгу)
      3) ничего не имею против разделения интерфейсов, но для сервиса на пару таблиц ваш подход избыточен(возможно было бы лучше оставить как есть и обернуть их в общий интерфейс)
      5) грубо говоря сервис каждый раз проходит одни и те же проверки и если передавая два набора валидных данных, в котором один успешно проходит, а второй падает в панике, то это говорит о серьёзной ошибке в коде, которую надо чинить, а не пытаться восстановить прилагу(возможно гдето данные сломались и тогда нет никакого смыслы хранить битые данные)
      6) сорри, не заметил
      7) сорри, привычка после работы с распределёнными сервисами, не актуально для одного инстанса
      9) стоит почитать сигнатуру require.Equal()
      func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

      @@user-lv9ko1ru7e 1) Я всё ещё не вижу конкретных аргументов - что именно там тяжело? Приведите пример того, как было бы легко в данном случае?
      2) Такое ощущение, что у вас есть некое универсальное правило, какая архитектура правильная. А это не так, она сильно зависит от проекта. Писать пет-проект с кучей слоёв, которые там не пригодятся - НЕ правильно. И допускать оверинжениринг в пет-проектах, это тоже плохо.
      Это не попытка оптимизации производительности, это отсутствие бессмысленного повышения сложности проекта - кода меньше, он проще, понятней.
      3) Не соглашусь с этим утверждением
      5) А если в сервис приходит 99 запросов, и лишь 1 из них проблемный и ломает приложение? Нам нужно уронить сервис, чтобы он обрабатывал 0 запросов, пока мы чиним тот единственный проблемный? Вы действительно считаете это хорошим подходом?
      7) дело даже не в распределенных сервисах, а в том, зачем вообще используется функция time.Now(). Если она нужна только для получения дельты времени, внутри одной и той же функции, то при чем тут распределенность? В распределенном сервисе я бы тоже не стал думать здесь о временных зонах
      9) Я знаю сигнатуру, и всё ещё не понимаю, о какой конкретно проблеме речь.

    • @user-lv9ko1ru7e
      @user-lv9ko1ru7e Před 11 měsíci

      @@nikolay_tuzov лучше вынесите обсуждение в канал

  • @yakomisar
    @yakomisar Před 11 měsíci

    Прикольно, но отдельный ролик для https ты маханул конечно. Self-signed сертификат прям с Голанг идет из коробки.

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

      Self-signed не совсем то. Я обычно через Cloud Flare делаю, но при этом сильно тоже не заморачиваюсь, выбираю гибридный вариант (от клиента до CF по https, от CF до моего сервиса http)
      Заодно там можно будет показать, как настроить работу с доменом. Но в целом да, ролик получится короткий и простенький.

  • @kodikoff
    @kodikoff Před 11 měsíci

    Очень ждём миграции

  • @Trapmaloj
    @Trapmaloj Před měsícem

    Подсобите кто сможет, сделал 1:1 но падает на этапе деплоя в VM, говорит неправильный ключ

  • @madbad1310
    @madbad1310 Před 8 měsíci

    Николай, уже октябрь. Где анонсированное отдельное видео по log/slog ? )

    • @nikolay_tuzov
      @nikolay_tuzov  Před 8 měsíci +1

      Работы много, на видео очень мало времени остаётся. Но всё будет, планы в силе) Точную дату пока не могу назвать

    • @madbad1310
      @madbad1310 Před 8 měsíci +1

      @@nikolay_tuzov Николай, у вас очень полезные видео. В любом случае, спасибо вам большое.

  • @petery6775
    @petery6775 Před 9 měsíci

    подскажи, а чт оу тебя за тема и шрифт ?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 9 měsíci

      Всё стандартное для IDE GoLand. В видео я использую presentation mode

  • @jordenskraften8273
    @jordenskraften8273 Před 11 měsíci

    Будет ли что-то по golang+graphQL?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

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

  • @qoonmax
    @qoonmax Před měsícem

    В чем смысл использовать файл конфига? Почему нельзя ограничится env + дефолтные значения в env-default. Выглядит как лишний слой.

  • @user-sp1gr6xb7q
    @user-sp1gr6xb7q Před 2 měsíci

    Отличное видео, но я так и не понял 1:43:30 почему надо писать tc := tc?

  • @alexsandr9444
    @alexsandr9444 Před 9 měsíci +1

    Привет спасибо за видео)Скажи а как задается "CONFIG_PATH" в окружение?

    • @boomy842
      @boomy842 Před 9 měsíci +1

      Если ты на линуксе, то export CONFIG_PATH=
      Если на виндовс то set CONFIG_PATH=

    • @kirillgrossberg6950
      @kirillgrossberg6950 Před 9 měsíci +1

      @@boomy842 Я правильно понял, тут получается set CONFIG_PATH=./config/local.yaml go run .\cmd\shrt\main.go ?

    • @user-pb2nv3ye9w
      @user-pb2nv3ye9w Před 4 měsíci

      а это надо в терминал писать или куда?
      @@boomy842

  • @8Sapphire8
    @8Sapphire8 Před 8 měsíci +1

    Ролик бесценный что тут сказать. 5 из 5

  • @user-zg8ij3kt1h
    @user-zg8ij3kt1h Před 11 měsíci

    19:10 А почему нельзя сначала проинициализировать логгер? Как принято вообще?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

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

  • @s1ovac308
    @s1ovac308 Před 11 měsíci +1

    Николай, а zap менее актуален, нежели slog?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +1

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

  • @StreetWorkout62
    @StreetWorkout62 Před 11 měsíci

    А какой плагин ai используется для подсказки кода?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      GitHub Copilot

    • @StreetWorkout62
      @StreetWorkout62 Před 11 měsíci

      @@nikolay_tuzovон платный?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      @@StreetWorkout62 да, платный. Но там дают пару месяцев бесплатно попробовать. Если нужен бесплатный, то посмотри Codeium, говорят тоже хорош (но я не пробовал)

  • @xlzpm9722
    @xlzpm9722 Před 11 měsíci

    кто может помочь, я уже тупо переписал код, а в консоли все равно пишется CONFIG_PATH is not set, go в vs code словно ничего не видет

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

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

    • @AndrewYurchenko
      @AndrewYurchenko Před 9 měsíci

      @@nikolay_tuzov 😂😂😂 вот где кроется маленький продажник, внутри прогера. Этот ответ, заслуживает оваций!!!

  • @user-ex2mo2sn8c
    @user-ex2mo2sn8c Před 11 měsíci

    я возможно что то незаметил... но тут 2 слоя.. где usecases? прям из handler вызывать функции storage.. как то мне кажется не чисто

    • @paniciour
      @paniciour Před 11 měsíci +3

      будь прагматичнее, если юзкейс дергает бд и ничего больше, то зачем плодить слои ради слоев

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

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

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

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

  • @batyrakpanbet6292
    @batyrakpanbet6292 Před 6 měsíci

    Видос шикарный, долго искал для практики.
    Сзадий флаг Казахстана?)

  • @tyapka
    @tyapka Před 2 měsíci

    Запрос на следующие уроки:
    - Как сделать асинхронную работу (пусть запускается через API вызов) в кластере, чтоб она 1) по какому-то ключу была только одна во всем кластере и 2) востанавливалась после падения сервера (можно с использованием ZooKepera или etcd)
    - Реал лайф пример работы с Dragonboat (RAFT либа).

  • @danilakhtarov
    @danilakhtarov Před 4 měsíci

    Можно вместо alias использовать id и каждой цифре присвоить свой символ, а-ля base64

  • @user-rj5kt3ft8w
    @user-rj5kt3ft8w Před 11 měsíci +1

    вместо op можно в логгерах включить caller чтоб показывало файл с конкретной строкой

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      Это дорогостоящая операция, поэтому оно не всегда того стоит.

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      Хотя, это не чрезвычайно дорого, и каких-то случаях допустимо, согласен. К примеру, обычно логгеры добавляют стек вызовов в случае Error-сообщений

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

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

    • @user-rj5kt3ft8w
      @user-rj5kt3ft8w Před 11 měsíci

      ​@@nikolay_tuzov ну не знаю, можно и выводить какая функция выполняется, насчёт накладных расходов - не знаю, в zerolog\zap врубаю во время разработки или когда приложение на тестовом контуре

    • @paniciour
      @paniciour Před 11 měsíci

      @@nikolay_tuzov op в upspin подсмотрел?) имхо полусомнительная приставка, тк вызывающий код и так знает название вызываемой функи, ему интереснее какой именно ее бит сбойнул. ты из каждой функи ретурнишь обернутые опом ошибки?

  • @abdulmagomedov
    @abdulmagomedov Před 9 měsíci

    Как op расшифровывается?

  • @fprotimaru1944
    @fprotimaru1944 Před 11 měsíci

    стоит ли потратить 10 баксов на copilot?

  • @brawlstarsbro5301
    @brawlstarsbro5301 Před 2 měsíci

    афигеть он умный

  • @megasuperlexa2
    @megasuperlexa2 Před 11 měsíci +1

    13:30 это kebab case

  • @BabaykaMoscow
    @BabaykaMoscow Před 11 měsíci

    А где определять интерфейс, если мест его использования - 17? о.О

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      А у вас часто такое бывает? На мой взгляд, это редкий кейс. И разбираться с ним нужно в каждом конкретном случае отдельно.

    • @BabaykaMoscow
      @BabaykaMoscow Před 11 měsíci

      @@nikolay_tuzov Нет, мне просто интересно как это будет работать в Го :) После Жавы такой подход кажется необычным.

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      @@BabaykaMoscow в Го такое встречается намного реже. Если не ошибаюсь, я даже не встречал ни разу.
      Но тут важно понимать, что оно потому и встречается редко, что интерфейс описан в месте использования. Я об этом подробно рассказывал в ролике на данную тему, советую посомтреть

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci

      czcams.com/video/eYHCCht8eX4/video.html

  • @conskykek
    @conskykek Před 11 měsíci +4

    Оргазм

  • @gooseman5578
    @gooseman5578 Před 6 měsíci

    idle-timeout = keep-alive

  • @ntldrzic
    @ntldrzic Před 11 měsíci

    почему не gin?

    • @nikolay_tuzov
      @nikolay_tuzov  Před 11 měsíci +3

      chi более минималистичный и лучше совместим с net/http. При этом в нём есть всё необходимое для такого проекта.
      Но вообще, мы обсуждали выбор конкретного варианта в моём ТГ-канале (ссылка есть в описании). gin тоже был среди кандидатов.

  • @TechBusinessDev
    @TechBusinessDev Před měsícem

    Поцаны на ларке все это за 15 минут сделают
    Когда уже фреймворк будет нормальный на гошке?
    Был бы опыт побольше, сам бы написал уже

  • @research_Development
    @research_Development Před 11 měsíci

    А что у тебя за кресло ?)

  • @AndrewYurchenko
    @AndrewYurchenko Před 9 měsíci +1

    Блин, сел осваивать язык. Пока ищу, что можно тупо повторить, попутно въезжая в смысл. А тут роутер не стандарт... Хотелось бы пока с тем, что из коробки предоставляется разобраться. Но, что поделать... По любому благодарность!

    • @user-gy5lg4vp9i
      @user-gy5lg4vp9i Před 5 měsíci

      как успехи броу? похожая сейчас ситуация у меня)

    • @AndrewYurchenko
      @AndrewYurchenko Před 5 měsíci +1

      @@user-gy5lg4vp9i на тот момент отложил изучение Go, узнал про Rust. На нем освоил написание API. Но, за неимением вакансий и пока скудный спрос на рынке, вот попутно решил опять и Go добивать. После Rust намного легче вроде теперь заходит. Во всяком случае понимание работы с памятью там пришлось намного лучше освоить. Но, пока именно по Go сказать нечего. Как только доберусь до реализации, отпишусь. 👍

    • @user-gy5lg4vp9i
      @user-gy5lg4vp9i Před 5 měsíci

      @@AndrewYurchenko в путь )

  • @Daloshka
    @Daloshka Před 3 měsíci

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