Вступление

Веб-разработчики, работающие исключительно на JavaScript, естественно, выберут Node.js в качестве бэкенда. Будучи средой исполнения на основе JavaScript, он представляет собой самый простой путь для разработчиков фронтенда к созданию бэкенда. Однако сегодня существует множество вариантов для фронтенд-разработчиков, желающих перейти на full-stack.

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

В этой статье мы рассмотрим эти парадигмы и возможности, а также причины, по которым стоит попробовать Go для разработки backend/full-stack веб-сайтов. Мы также рассмотрим некоторые новые паттерны, опыт разработчиков Go и то, чего стоит ожидать разработчику фронтенда, впервые взявшему в руки Go.

Примеры использования Go

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

Благодаря возможностям компиляции код Go можно легко развернуть на серверной инфраструктуре и соответствующим образом обновлять различные установки. Он также поддерживает множество ОС и процессорных архитектур, что является огромным преимуществом.

Более того, Go стал предпочтительным языком для программного обеспечения инфраструктуры с открытым исходным кодом, а некоторые из самых крупных и популярных проектов написаны полностью на Go. Например, Docker полностью написан на Go.

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

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

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

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

Параллелизм: Ключевая особенность Go

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

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

Если вы пытались реализовать параллелизм в других языках программирования, особенно в JavaScript, вы понимаете, что сделать это довольно сложно. В отличие от этого, породить goroutine так же просто, как добавить ключевое слово go перед функцией. Рассмотрим пример ниже.

import "fmt"

package main

func doSomething(str sting) {
     for i := 1; i <= 3; i++ {
          fmt.Printf("%s: %d", str, i)
     }
}

func main() {
    // calling this function the normal way
    doSomething("Hello")

    // Running it inside a go routine
    go doSomething("World")

    go func() {
        fmt.Print("Go routines are awesome")
    }()
}
//add return value for func

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

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

«Это означает, что каждая программа на Go поставляется с уже встроенными инструментами, которые могут заставить написанные нами программы работать лучше, если разработчики правильно их используют».

“This means that every Go program comes with already built-in tools that can make the programs we write perform better, if properly utilized by developers.”

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

Конечно, выполнение действий в одной горутине означает, что она должна иметь возможность взаимодействовать с другими горутинами. Для этого в Go предусмотрены каналы.

Каналы — это проводники, которые позволяют двум параллельным горутинам общаться друг с другом, посылая и получая значения. Синтаксис channel <- можно использовать для отправки значения в канал, а синтаксис <-channel можно использовать для чтения чего-либо из канала, например, так:

package main
import "fmt"
func main() {
// make a new channel
messages := make(chan string)
go func() {
// write to channel
message <- "Hello World!"
}()
// read from channel
message :=  <-messages
fmt.Printf("I got the message %s", message)
}

N.B., при чтении из канала мы блокируем его, пока не получим сообщение. Отправитель и получатель должны быть готовы; то есть мы не можем отправить сообщение, пока не найдется соответствующий получатель для этого канала.

Почему фронтенд разработчики должны изучать язык Go

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

Если вы привыкли к объектно-ориентированному стилю программирования, вы найдете в Go знакомые концепции. В нем есть типы и методы в виде структур, что позволяет использовать объектно-ориентированный стиль программирования. Здесь нет иерархии типов; методы в Go более общие, поскольку их можно определить для любого типа данных, даже для встроенных типов.

Структуры имеют методы и свойства, подобно тому, как это делают классы в типичных объектно-ориентированных языках программирования. Например:

package worker

import "fmt"

type Person struct {
    Name string
    Age int
}

func (p *Person) Talk(phrase string) {
    return fmt.Sprintf("%s says: %s", p.Name, phrase)
}

Здесь Person — это тип struct с полями Name и A«ge. Talk — это метод, определенный на структуре Person, который печатает что-то. Мы можем использовать это как:

person := &Person{"Vivan", 22}
person.Talk("Go is awesome")

Давайте рассмотрим еще несколько причин, по которым Go демонстрирует стремительный рост популярности в последние годы, и почему фронтенд-разработчики, стремящиеся перейти на full-stack, должны выбрать именно Go.

Простое управление пакетами

Программы Go строятся из пакетов, свойства которых позволяют эффективно управлять зависимостями. В инструментарий Go встроена система управления версионными наборами связанных пакетов, называемых модулями. Модули были введены в Go 1.11 и готовы к использованию в производстве с версии 1.14.

Чтобы создать проект с использованием модулей, выполните команду go mod init. Эта команда создает файл go.mod, в котором отслеживаются версии зависимостей. Чтобы добавить, обновить или понизить версию зависимости, выполните go get — например, go get golang.org/x/[email protected]. Дополнительную информацию о создании модуля и дополнительные руководства по управлению зависимостями с помощью модулей можно найти на официальном сайте Go.

Меньше языковых конструкций и ключевых слов

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

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

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

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

Например, новые дополнения к стандартной библиотеке появляются редко, и планка для включения в нее высока. Создатели утверждают, что код, включенный в стандартную библиотеку, несет большие текущие расходы на обслуживание. На стандартную библиотеку Go распространяется обещание совместимости с Go 1 (блокирование исправлений любых недостатков в API) и график выпуска Go.

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

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

Строго типизированный по умолчанию

Go — статически типизированный язык. Компилятор работает над тем, чтобы код не только правильно компилировался, но и чтобы преобразование типов и совместимость были обеспечены. Это помогает избежать проблем, с которыми вы сталкиваетесь в динамически типизированных языках, таких как JavaScript, где проблемы обнаруживаются только после выполнения кода.

Статический анализ кода

Go в значительной степени полагается на статический анализ кода. Примеры: godoc для документирования, gofmt для форматирования кода, golint для линтинга стиля кода и многие другие. Статический анализ кода дает разработчику чувство безопасности и спокойствия при выполнении задач.

Встроенные утилиты для тестирования кода

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

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

Чтобы создать файл тестирования, создайте новый файл, заканчивающийся на _test.go, в том же каталоге, что и исходные тексты вашего пакета. Внутри этого файла импортируйте testing и напишите функции вида. Мы можем запустить go test в том же каталоге. Сценарий найдет тестовые функции, создаст тестовый бинарник и запустит его.

 func TestFoo(t *testing.T) {

    }

N.B., Go предоставляет возможность тестирования пакетов, которые вы пишете. С помощью команды go test вы можете протестировать код, написанный в любых файлах *_test.go.

Производительность

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

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

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

Встроенный механизм шаблонизации HTML

Go поставляется со встроенным механизмом шаблонизации HTML, который можно найти в пакете html/template. Поначалу синтаксис не кажется интуитивно понятным, особенно если вы работаете с фронтендом, но на самом деле он довольно прост и отлично справляется со своей задачей.

Большие команды могут легко поддерживать приложения на Go

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

Более того, для работы с Go существует достаточно большое количество онлайн-курсов и множество инструментов, включая автоматическое документирование, статический анализ кода, встроенную среду тестирования, обнаружение условий гонки и так далее.

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

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

Заключительные выводы

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

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

Go — простой, но в то же время выразительный язык. Его автоматический вывод типов очень похож на динамические языки, поэтому он предлагает знакомые ощущения для разработчиков JavaScript. Кроме того, автоматическое документирование Go позволяет нам автоматически получать код, документированный на том же уровне качества, что и стандартная библиотека и встроенные API.

Наконец, благодаря сильной стандартной библиотеке, он отлично подходит для создания API/бэкендов. Go также является кроссплатформенным — он работает на Linux, macOS и Windows — и поставляется с полезными инструментами для линтинга кода, генерации кода, сборки, тестирования и многого другого.

Более подробную информацию о том, почему разработчикам фронтенда, переходящим на full-stack, стоит выбрать Go, можно найти на странице FAQ документации по Go. Спасибо!

оригинал