В программировании постоянно разрабатываются новые языки. В каждом из них разработчики стремятся расширять возможности предыдущих технологий. Одним из таких примеров является язык Go, или Golang (Google language). Разработанный в компании Google, Golang был создан с целью объединить черты своих предшественников и предложить программистам новый инструмент для создания приложений. Когда создатели Golang приступили к разработке, они учитывали опыт различных языков, таких как C, C++, Java и Python.

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

C и C++


Начнем с истоков. Как уже было сказано многие языки программирования появляются из других языков, как бы парадоксально это не звучало. Объединяя преимущества и убирая недостатки одних – и создаются новые инструменты. Так, язык программирования C был разработан в начале 1970-х годов в лаборатории Bell Labs (Bell Telephone Laboratories) компании AT&T (American Telephone and Telegraph Company). Его создателями являются Деннис Ритчи и Кен Томпсон.

В начале 1970-х годов в Bell Labs для разработки операционной системы UNIX был создан язык программирования «B», который был расширением языка BCPL. Однако «B» имел некоторые недостатки. В связи с этим, Деннис Ритчи и Кен Томпсон начали разрабатывать новый язык, в который внесли множество улучшений и новых функций. Первый прототип языка получил название NB (New B). Позже язык был переименован в «С» в отношении его предшественника «B». Этот выбор имени имел и символический смысл – «С» был «следующим» языком после языка «B». A, B, C…ну, вы поняли.

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

В 1978 году была выпущена первая версия стандарта ANSI C (American National Standards Institute C), что стало ключевым моментом в истории развития языка. В последующие десятилетия язык C оставался одним из самых популярных и широко используемых, став основой для множества других языков, таких как C++.

Перейдем к C++, до 2007 года он был одним из самых популярных языков программирования. Создан он был Бьёрном Страуструпом с целью разработки такого инструмента, который позволял бы ему более эффективно писать программы для UNIX.



Бьёрн Страуструп
Бьёрн Страуструп – датский ученый, программист, создатель языка программирования C++. Он объединил возможности языка C с концепциями объектно-ориентированного программирования.


Страуструп хотел расширить возможности C, добавив в него некоторые возможности объектно-ориентированного программирования (ООП), чтобы сделать код более структурированным и упорядоченным. В 1983 году он создал прототип языка, который назвал «C with Classes» (C с классами), что стало первым шагом к созданию C++. Окончательная же версия языка была выпущена в 1985 году, где уже были реализованы основные концепции: классы, наследование, инкапсуляция и полиморфизм.

Google и Go


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

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



Все это работает на миллионах машин, которые рассматриваются как небольшое количество независимых вычислительных кластеров, объединенных в сеть. Короче говоря, разработка в Google могла быть довольно медленной.

В принципе из-за этого и была собрана группа из разработчиков, в которую вошли Роберт Гризмер, Роб Пайк и Кен Томпсон, сотрудники Google. Они должны были разработать такой язык, который сочетал бы в себе простоту и эффективность C и C++, с возможностями параллельного программирования и современным подходом к разработке.



Цель проекта – создать язык, который был бы таким же быстрым, как C++, простым в написании, как Python, и масштабируемым, как Java.

Разработка началась в сентябре 2007 года. По мере развития, конечно, к ним присоединялись и другие программисты. В январе 2008 года началась работа над исходным компилятором.
Первая версия Go была выпущена в ноябре 2009 года, и с тех пор она претерпела несколько крупных релизов. Потребовалось еще несколько лет, чтобы выпустить первую стабильную версию Go в марте 2012 года. Подробнее о выпуске можно прочитать в примечаниях.

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

Самый значимый релиз был представлен в августе 2015 года – Golang 1.5 (примечания к выпуску), где инструментарий компилятора был полностью преобразован с C на Go. На этом этапе Golang принял тот вид, к которому стремились его авторы. Дальше он уже переходил в фазу доработки и создания новых полезных фич (дополнительных библиотек, фреймворков, инструментов и т.п.).

Самые большие изменения в реализации из примечаний к выпуску:
  • Компилятор и среда выполнения теперь полностью написаны на Go (с небольшим количеством Ассемблера).
  • Сборщик мусора теперь является параллельным и обеспечивает значительно меньшее время простоя.
  • По умолчанию программы Go запускаются с GOMAXPROCS установленным количеством доступных ядер; в предыдущих выпусках по умолчанию он был равен 1.
  • Поддержка внутренних пакетов теперь предоставляется для всех репозиториев, а не только для ядра Go.
  • Команда go теперь обеспечивает экспериментальную поддержку внешних зависимостей «vendoring».
  • Новая go tool trace команда поддерживает детальную трассировку выполнения программы.
  • Новая go doc команда настроена для использования в командной строке.

Талисман


Талисман у Go – Суслик. Интересно, что первоначальная версия талисмана была создана задолго до рождения языка. Его создала Рене Френч для рекламы радиостанции WFMU в Нью-Джерси. Рене Френч было поручено создать футболку для ежегодного сбора средств.



Далее суслик появился в Bell Labs в качестве аватара Боба Фландрена в почтовой системе Bell Labs. Другие рисунки Рене стали аватарами для ken, r, rsc и других. Когда начался проект Go, необходимо было разработать логотип и Рене вызвалась его нарисовать. Он был изображен на первой футболке Go и на сайте Google Code.



Для запуска с открытым исходным кодом в 2009 году Рене предложил адаптировать суслика WFMU в качестве талисмана. И родился суслик-гофер.



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



Особенности языка Go


Golang был разработан с учетом особенностей разных языков программирования, включая C, C++, Java, Python и другие. В результате Golang заимствовал и улучшил некоторые черты от своих предшественников, рассмотрим некоторые из них:

Из C и C++
  • Синтаксис Go схож с языками из семейства C (такими как C и C++). Включает в себя использование фигурных скобок для блоков кода, точку с запятой в качестве разделителя, операторы присваивания и т.д.
  • Golang является компилируемым языком программирования, что позволяет ему достигать высокой производительности. Исходный код на Golang компилируется в машинный код, что делает его эффективным в выполнении.
  • Go поддерживает указатели, что позволяет эффективно работать с памятью и применять указатели для передачи данных по ссылке.
  • Строки в Golang заключаются в двойные кавычки, что делает их удобными для работы с текстовыми данными.
  • Горутины в Golang – это легковесные потоки, а многопоточность в Golang реализуется через механизм горутин. Этот подход аналогичен модели потоков C и C++, но более прост и эффективен.
  • В Golang используется возвращаемое значение ошибки для обработки ошибок в функциях.
  • Golang занимает промежуточное положение между скоростью выполнения C/C++ и удобством Python/Java.

Из Python
  • Golang также как и Python, стремится к простоте и читаемости синтаксиса. Это делает код на Golang более понятным и читаемым, что упрощает разработку и поддержку программ.
  • Как Python и Java, Golang также обладает сборщиком мусора (garbage collector), что позволяет автоматически управлять выделением и очисткой памяти, освобождая разработчика от необходимости делать это вручную.
  • Golang предоставляет набор встроенных функций и библиотек, аналогичных некоторым из тех, которые доступны в Python. Например, работу с файлами, строками, временем, математическими операциями и т.д.
  • Как и в Python, Golang предоставляет свой встроенный тестовый фреймворк для написания модульных тестов и обеспечения стабильности кода.

Из Java
  • Сборщик мусора есть как в Python, так и в Java, поэтому Go заимствовал эту функцию из обоих языков.
  • Golang также поддерживает интерфейсы, которые позволяют абстрагироваться от конкретной реализации и создавать более гибкий и расширяемый код.
  • Как и в Java, Golang предоставляет механизм обработки ошибок с использованием исключений. Однако, в отличие от Java, Golang больше рекомендует использовать возвращаемые значения ошибок для их обработки, чем исключения.
  • Подобно Java, Golang использует пакетную структуру, что делает организацию и управление проектами более удобным и позволяет избежать конфликтов имен.
  • Golang является языком со строгой статической типизацией. Это означает, что типы данных должны быть объявлены заранее, что обеспечивает более надежный код и облегчает его отладку.


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

Простотой синтаксис


Официальная документация Go занимает около 50 страниц, просто читается и содержит примеры. Базовый синтаксис в основном относится к семейству C, с некоторым вдохновением от Pascal, Modula и Oberon для деклараций и пакетов. Подход со статически связанными двоичными файлами еще больше снижает сложность времени выполнения.
Пример:
package main

import "fmt"

func main() {

    // Строки могут быть сложены с помощью символа `+`.
    fmt.Println("go" + "lang")

    // Целый числа и числа с плавающей точкой.
    fmt.Println("1+1 =", 1+1)
    fmt.Println("7.0/3.0 =", 7.0/3.0)

    // Логические значения с логическими операторами
    fmt.Println(true && false)
    fmt.Println(true || false)
    fmt.Println(!true)
}

Многопоточность


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

Наличие «сборщика мусора»


Go использует алгоритм сборки мусора для автоматического определения неиспользуемых объектов и освобождения занимаемой ими памяти. Основным алгоритмом сборки мусора в Go является трёхцветная сборка мусора (tricolor garbage collection), который основан на алгоритме «пометки и освобождения» (mark and sweep). Процесс сборки мусора в Go происходит в фоновом режиме, что позволяет продолжать работу программы без прерываний.

Компилируемость


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

Инструменты разработчика


В Go есть инструменты, которые ускоряют разработку и помогают решать разные задачи:
  • go toolchain – комплект инструментов Go включает в себя компилятор, средства форматирования (gofmt) и статического анализа (go vet), а также утилиту для работы с зависимостями (go mod).
  • gofmt – инструмент для автоматического форматирования исходного кода в соответствии с официальным стилем Go.
  • godoc – найдет комментарии и подготовит из них мануал к программе.
  • go vet – утилита для статического анализа и поиска потенциальных ошибок в коде.
  • go get – команда для загрузки и установки пакетов из репозитория.
  • go mod – инструмент для управления зависимостями в проекте с использованием модулей Go.
  • go test – команда для запуска тестов в проекте.
  • Delve – отладчик для Go, который позволяет отлаживать код с использованием командной строки или интегрированной среды разработки (IDE).
  • Gin или Echo – популярные веб-фреймворки для создания веб-приложений на Go.
  • Cobra – библиотека для создания удобных командной строки интерфейсов (CLI) для ваших приложений.
  • gRPC и Protobuf – библиотеки для реализации механизма удаленного вызова процедур (RPC) с использованием Protocol Buffers.
  • Swagger и go-swagger – инструменты для создания и документирования API с помощью спецификации OpenAPI (Swagger).
  • sqlx – библиотека для упрощения работы с базами данных SQL.
  • testify – библиотека для упрощения написания и запуска тестов.
  • goimports – инструмент для автоматического добавления или удаления импортов в Go-файлах.
  • gas – найдет уязвимости.
  • typecheck – проверяет соответствие типов в коде.


Для чего используется Golang


Сетевые и веб-серверы, микросервисы, распределенные системы, облачные сервисы и DevOps, веб-разработка, командные интерфейсы (CLI), базы данных и хранилища, проекты с открытым исходным кодом.

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

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

Автономные инструменты и утилиты
Поскольку программы на Go быстро запускаются и могут быть легко упакованы для дальнейшего распространения, они полезны для разработки утилит и других инструментов. Экземпляром является сервер доступа Teleport (в том числе для SSH). Teleport можно быстро и просто установить на серверы, загрузив готовый двоичный файл или создав его из исходного кода.

Материалы по Golang



Видео



Курсы



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

Комментарии (18)


  1. nirom
    01.08.2023 12:33
    +3

    А как дела с фреймворками? Есть ли полноценные каркасы приложений уровня Spring, Django?


    1. Xeldos
      01.08.2023 12:33
      +8

      Здесь так не принято.


    1. akurilov
      01.08.2023 12:33
      +1

      Не надо, пожалуста


    1. Falldot
      01.08.2023 12:33

      Все замечательно! Gin, Fiber, Echо. Для работы с БД GORM, Ent и многое другое.


      1. gnomeby
        01.08.2023 12:33
        +1

        Не знаю как сейчас дела обстоят, но 3 года назад GORM было решением вида компромисс на компромисе, и, хотя оно работало, всё-таки переехали на sqlx.


    1. gnomeby
      01.08.2023 12:33
      +1

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

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


      1. Xeldos
        01.08.2023 12:33

        Даже бекенд сайта в котором будет чуть больше чем просто API уже начинает вызывать боль

        Но почему тогда мыши продолжают жевать кактус?


        1. gnomeby
          01.08.2023 12:33

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


  1. sv_kozlov
    01.08.2023 12:33
    +1

    с некоторым вдохновением от Pascal, Modula и Oberon для деклараций и пакетов.

    Вся идея структур с привязкой методов с помощью приемников/ресиверов (receiver) в их объявлениях кажется цельнотянутой с Оберона(2). Ну один в один.
    Не только оператор присваивания ":="


  1. anonymous
    01.08.2023 12:33

    НЛО прилетело и опубликовало эту надпись здесь


    1. GospodinKolhoznik
      01.08.2023 12:33
      +5

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

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

      Но то, что создатели Go послали лесом ООП, за это им огромный плюс в карму.


      1. lazy_val
        01.08.2023 12:33
        +1

        Что именно в Go вы считаете "нелепыми костылями из старых языков"?

        Про ООП согласен. Про дженерики тоже.


        1. GospodinKolhoznik
          01.08.2023 12:33

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


  1. svanichkin
    01.08.2023 12:33
    -4

    Рассказать про golang и не рассказать про limbo? хмхм..


  1. Error1024
    01.08.2023 12:33

    Ясно, понятно - опять все взято из «си», ок.

    А мб стоило посмотреть доклад от одного из создателей Go, чтобы понять что почти все было взято из Modula/Pascal/Oberon, ну, а из «си» элементы синтаксиса, чтобы меньше «воняли».

    https://youtu.be/ZbtB1Aqc41A


  1. MigAru
    01.08.2023 12:33

    Я думаю(и знаю что всем по барабану), что сравнивать интерфейсы с java не очень корректно тк по большей части все с С взяли, вроде структур и как раз интерфейсы


    1. includedlibrary
      01.08.2023 12:33

      Только в си нет интерфейсов


      1. MigAru
        01.08.2023 12:33

        Разве?

        а это чем не интерфейс

        typedef struct base {

        int (*foo)(base* me);

        } base;