Язык Go: выбор ORM

    Go получил славу одного из самых простых языков программирования, в числе его плюсов – простота написания и чтения кода, в большинстве случаев более простая поддержка кодовой базы. Рассказываем о нескольких преимуществах Go, благодаря которым мы в SimbirSoft использовали его в ряде высоконагруженных проектов с различными архитектурами, как веб-сервисными, так и микросервисными (SOA).

    Применение


    Этот системный язык хорош для большинства сетевых задач, любых микросервисов и макросервисов, веб-сервисов, а также для системных инструментов – недаром его любят многие специалисты DevOps. Go находит свое применение в Machine Learning, а некоторые разработчики даже пишут с его помощью веб-сайты. Мы в своей практике обращались к Go, когда разрабатывали отдельные CRM и программные продукты для внутреннего пользования, например, для страховых компаний. В стандартном репозитории языка Go есть пакет и для мобильной разработки, данный пакет поддерживается до сих пор, хотя для этого есть более подходящие инструменты.

    Go: развитие и признание


    В Google разработка языка Go началась в 2007 году. До этого компания использовала Java, Python и C++, однако, они имели определенные недостатки (в частности, большое потребление памяти) или ограниченное применение. Тогда в Google начали разработку нового языка под свои нужды.

    Какие требования предъявлялись к языку:

    • Один исполняемый файл (отсутствие зависимостей)
    • Быстрая компиляция
    • Быстрый runtime (как минимум наравне с Java и С++)
    • Сборщик мусора, минимизация утечки ресурсов
    • Оптимизация под многопроцессорные системы
    • Статическая типизация
    • Минимализм
    • Синтаксическая легкость
    • Мультипарадигменность (императивный, функциональный, объектно-ориентированный)

    Для тех, кто не работает с Go, вкратце напомним историю его создания. Спецификацию языка в Google начали продумывать в 2007 году. Релиз 1.0 состоялся в 2012 году, а в 2015 году вышел релиз 1.5, уже без единой строчки кода C++. С этого момента язык компилирует себя сам, что позволило ускорить разработку отдельных задач на Go.

    Средний возраст признания нового языка в сообществе – около 10 лет, но Go уже сейчас входит в число наиболее востребованных языков. В июне 2019 года Go поднялся на 15 место по популярности в мире, согласно индексу TIOBE, прибавив за год три позиции. Среди причин его успеха можно выделить следующие:

    • Сильная стандартная библиотека
    • Крутой стандартный тулинг
    • Наиболее необходимые функции представлены в “коробке”, а библиотеки отданы на open source
    • Очень дружелюбное сообщество

    Например, в стандартную библиотеку входят следующие пакеты (список неполный):



    Иллюстрация – github.com/ashleymcnamara/gophers

    Если вас не устраивает скорость работы вашего приложения или другие параметры, вы можете поработать с профилировщиком из “коробки”. Для этого нужно:
    • Зарегистрировать импорт профилировщика: import _ «net/http/pprof»
    • Добавить http-сервер для получения результатов от профилировщика: go http.ListenAndServe(«0.0.0.0:8080», nil)

    Go tools


    Одно из преимуществ Go – обширный набор стандартных инструментов. Мы выбрали несколько наиболее интересных утилит, на наш взгляд (на самом деле, их намного больше):

    • benchcmp — сравнение бенчмарков, производительности до и после изменений
    • go tool cover — анализ покрытия кода тестами
    • godoc — генерация документации на основе комментариев
    • goimports — анализ импортов (удаление неиспользуемых, добавление пропущенных)
    • gorename — рефакторинг
    • present — тулинг для презентаций
    • go vet — линтер часто встречающихся ошибок
    • go test — запуск тестов и бенчмарков
    • go fix — фикс изменений при смене API (до релиза 1.0)
    • go tool pprof — профилирование
    • Go fmt — форматирование кода по code style
    • Race detector — нахождение гонки данных в runtime

    Конкурентность


    Еще одна сильная сторона Go заключается в том, что на этом языке легко написать конкурентный код. Для этого вы просто перед вызовом функции используете ключевые слова.



    Обучение Go


    Если вы хотите программировать на Go, старт займет относительно немного времени. Разработчики — Core Team — поддерживают курс A Tour of Go на нескольких языках, в том числе на русском. Этот курс можно пройти буквально за 1-3 дня. В отношении обучения Go — один из самых простых языков.

    Итак, что почитать:


    ORM в Go


    Есть мнения, что одним из слабых мест Go являются ORM. Возможно, отчасти это происходит из-за того, что язык молод — в нем только начинают разрабатывать многие необходимые инструменты. В частности, для работы с базами данных можно использовать пакет database/sql. Какие требования предъявляются к пакету:

    • Общий пакет для всех sql баз данных
    • Портируемый: не содержит никаких особенностей в области работы с базами данных. В идеале все должно корректно работать, если вы поменяете драйвер.
    • Преобразование типов Go в стандартные типы базы данных (при этом должна быть возможность обработки специфичных типов)
    • Содержит пул соединений
    • Thread-safety для горутин

    Пример SELECT запроса с использованием database/sql


    defer rows.Close()
    for rows.Next() {
    	var message string
    	err := rows.Scan(&message)
    	if err != nil {
    		log.Panic(err)
    	}
    	fmt.Println(message)
    }
    if err := rows.Err(); err != nil {
    	log.Panic(err)
    }

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

    • закрывать объект rows: defer rows.Close()
    • проверять на ошибки err := rows.Err(); err != nil т.к. не понятно по какой причине rows.Next() вернул нам значение false

    Из всего этого хочется использовать что то более универсальное и простое, например, ORM.

    Виды реализаций ORM


    Когда перед разработчиками встает вопрос выбора ORM для работы с Go, они зачастую ориентируются по рейтингу на гитхабе. Когда мы выбирали ORM для себя, лучший рейтинг имел Beego (18 тысяч “звездочек”). Однако, на практике ORM входит в состав фреймворка, поэтому оценка не вполне объективна (если выбирать исключительно ORM). Также в числе лидеров Gorm, который развивается с 2013 года, поддерживает транзакции и имеет много других преимуществ.



    Однако, как показал наш опыт знакомства с Gorm, при его использовании возможны определенные проблемы, особенно при тестировании: например, гонка данных или c удалением foreign key. Можно предположить следующие причины подобных ошибок в Gorm:

    • Коммиты сразу в master
    • Отсутствие тегов
    • Непредсказуемый sql билдер

    На данный момент мы в своей работе отдаем предпочтение нескольким ORM, которые не используют interface{} — это Kallax, Reform и Sqlboiler. Обычно задействуем пакет Golang для миграций и репозиторий orm-bench с бенчмарками ORM на Go. При этом не стоит гнаться только за бенчмарками. Чаще скорость не так важна, как качество кода и его функциональность.

    Подводя итоги


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

    Статья подготовлена на основе нашего доклада на митапе Hot Backend в Самаре.
    SimbirSoft
    92,53
    Лидер в разработке современных ИТ-решений на заказ
    Поделиться публикацией

    Комментарии 14

      0
      Есть такая штука
       <source> 
      Используйте её пожалуйста, пощадите читателя.
        +2

        В качестве альтернативного решения вместо ORM также можно использовать простой генератор SQL (например, squirrel). Он неплохо показывает себя показывает в связке со встроенным пакетом database/sql и sqlx.

          +4
          Не рекомендую `GORM` и подобные ему ORM. Закопаетесь в изучении нюансов маппинга их конструкций на нативный SQL, вместо того, чтобы писать SQL напрямую. Мне лично очень нравится `reform`, писал на нём три проекта, остался доволен.
            0

            Согласен. Мы к этому и пришли. По возможности не использовать ORM на основе рефлексии, только кодогенерация на данный момент.

              0

              Кодогенерация чего, маппинга?

                0

                Да мапинг идля простых запросов.

            +1
            Когда был в Lazada, то мы писали очень шустрое решение без кодогенерации — github.com/lazada/sqle. Посмотрите, может и вам подойдёт.
              +1
              Для меня как-то сухая статья.
              Не понятно почему сделали выбор с торону этих ORM!?

              Можно было бы привести примеры работы с разными ORM ^(
                +2
                В сторону этих ORM выбор был сделан из-за безопасности типов. В строго типизированном языке принимать на вход, например, в метод Save(value interface{}) пустой интерфейс опасно, можно легко ошибиться. Когда можно использовать кодогенерацию со строгой типизацией. В поиске примеров select запросов лучше всего посмотреть репозиторий orm-bench
                +1

                А можно указать какие ORM паттерны эти библиотеки реализуют? Особенно интересно какие из них реализуют DataMapper.

                  +1
                  Чего хотелось бы от orm

                  1) работа с переводимыми полями.
                  Конечно, переводимые поля это всего лишь еще одна связанная таблица. Но, согласитесь, что если в orm есть встроенная поддержка translatable это сразу в два раза упрощает работу с данными (например как в php doctrine)

                  2) автогенерация миграций
                  Многие базы данных поддерживают, но не всегда это равноценный функционал. Поэтому часто встречаю утверждения что в ткакой-то orm «тоже есть миграции»
                  Пока что я нашел только две orm c максимальной поддержкой миграций — php doctrine и javascript/typescript typeorm
                  Под максимальной поддержкой миграций я подразумеваю
                  1) автогенерацию кода на языке программирования orm (не sql-скрипты а например php-скрипты)
                  2) автогенерацию на основании сравнения текущей реальной базы данных с моделью (а не со схемой состояния которая была сгенерирована при прошлой миграции)
                  3) возможность кастомизировать полученные автогерерируемые скрипты

                  Интересно было бы услышать как Вы работали с переводимыми полями и миграциями. Ну а что касается конкретно go тут еще добавляется известная проблема с nullable полями

                  Действительно это интересный у Вас опыт но самые интересующие разработчиков вопросы пока что не нашли своего долдного освещения. А было бы очень интересно.
                    +2

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

                      +2
                      Вот об этом я и говорю…
                      Тема не была раскрыта полностью. Много вопросов которые можно было избежать если бы пересичленные ORM были приведены в более детальном сравнении с примерами кода их использования. А не объяснять потом в комментариях…
                        +3

                        Спасибо за рекомендации. Наш доклад на Hot Backend был направлен в первую очередь на знакомство с языком Go, на детальные вопросы мы отвечали после доклада. Будем иметь в виду для следующих публикаций)

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

                  Самое читаемое