Go — язык, который разделил веб-разработку на «до» и «после»
Когда в 2009 году Роберт Гризмер, Роб Пайк и Кен Томпсон представили Go (Golang), мало кто мог предположить, что этот компилируемый язык станет одним из главных инструментов современного backend'а. Сегодня Go — это не просто «убийца C++» или «альтернатива Python». Это язык, который перевернул представление о том, как должна выглядеть высоконагруженная серверная разработка.
Но что насчёт frontend? Можно ли использовать Go там, где раньше безраздельно правил JavaScript? И если да — то зачем? В этой статье мы разберём реальные плюсы и минусы Go для backend и frontend, подкрепим их кодом и поможем вам решить, стоит ли учить этот язык прямо сейчас.
Go для backend: почему его выбирают гиганты
Docker, Kubernetes, Prometheus, Terraform — все эти проекты написаны на Go. И это не случайность. Backend-разработка на Go даёт то, что сложно получить от интерпретируемых языков: производительность на уровне C и скорость разработки на уровне Python.
1. Горутины — секретное оружие Go
Главная фишка Go — лёгкие потоки выполнения, называемые goroutines. В отличие от потоков ОС, горутина занимает всего несколько килобайт памяти. Вы можете запустить десятки тысяч горутин без риска «убить» сервер.
package main
import (
"fmt"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Worker %d обрабатывает задачу %d\n", id, job)
time.Sleep(time.Second)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Запускаем 10 воркеров
for w := 1; w <= 10; w++ {
go worker(w, jobs, results)
}
// Отправляем 50 задач
for j := 1; j <= 50; j++ {
jobs <- j
}
close(jobs)
// Собираем результаты
for r := 1; r <= 50; r++ {
<-results
}
}
Этот код обрабатывает 50 задач всего через 10 параллельных воркеров. В Python или Node.js подобная архитектура потребовала бы сложных библиотек (asyncio, worker_threads) и большего расхода памяти.
2. Простота деплоя и минимализм
Go компилируется в один бинарник. Никаких виртуальных машин, никаких runtime-зависимостей. Вы просто закидываете исполняемый файл на сервер — и он работает. Для веб-разработки на Go это означает:
- Минимальный размер Docker-образов (часто < 10 MB вместо 500+ MB для Node.js)
- Мгновенный запуск (нет времени на JIT-компиляцию)
- Простота CI/CD — один бинарник = одна артефакт
3. Встроенная стандартная библиотека
Для создания полноценного HTTP-сервера вам не нужен фреймворк. Стандартная библиотека Go уже содержит всё необходимое:
package main
import (
"encoding/json"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func userHandler(w http.ResponseWriter, r *http.Request) {
user := User{ID: 1, Name: "Алексей"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func main() {
http.HandleFunc("/api/user", userHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Этот сервер готов к продакшену: он поддерживает Keep-Alive, маршрутизацию, обработку ошибок. Всё из коробки.
Минусы Go в backend: честный разбор
Было бы нечестно хвалить Go, не упомянув его недостатки. Плюсы и минусы Go — это всегда компромисс между скоростью и удобством.
1. Дженерики — всё ещё «сырые»
Дженерики появились в Go только в версии 1.18 (2022 год). И хотя они работают, их синтаксис и ограничения (например, отсутствие ковариантности) раздражают разработчиков, привыкших к Java или C#.
// Go 1.18+ дженерики — пока не идеал
func Sum[T int | float64](values []T) T {
var result T
for _, v := range values {
result += v
}
return result
}
Для сравнения: дженерики в TypeScript или Kotlin гораздо гибче.
2. Отсутствие традиционного ООП
В Go нет классов и наследования. Есть только структуры и интерфейсы. Если вы привыкли к полиморфизму через наследование, Go-стиль с композицией покажется вам неудобным.
// Go: нет классов, только структуры
type Animal struct {
Name string
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Гав!"
}
Это работает, но для сложных иерархий приходится писать больше кода.
3. Экосистема пакетов — всё ещё уступает JS/Python
Хотя pkg.go.dev растёт, количество библиотек для Go значительно меньше, чем для Python или JavaScript. Если вам нужно редкое API — скорее всего, придётся писать обёртку самому.
Go для frontend: WebAssembly меняет правила игры
А теперь самое интересное. Можно ли использовать Go во frontend? Официальный ответ — да, через WebAssembly (Wasm). Начиная с Go 1.11, компилятор умеет собирать код в .wasm-файлы, которые выполняются в браузере.
Как это работает
Вы пишете логику на Go, компилируете её в Wasm и подключаете к HTML как обычный JavaScript-модуль. Браузер выполняет этот код с почти нативной производительностью.
// main.go — компилируется в main.wasm
package main
import "syscall/js"
func main() {
c := make(chan struct{}, 0)
js.Global().Set("calculateFibonacci", js.FuncOf(calculateFibonacci))
<-c
}
func calculateFibonacci(this js.Value, args []js.Value) interface{} {
n := args[0].Int()
// Вычисляем число Фибоначчи (тяжёлая математика)
result := fib(n)
return js.ValueOf(result)
}
func fib(n int) int {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}
<!-- HTML — подключаем Wasm -->
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
.then((result) => {
go.run(result.instance);
// Теперь можно вызвать Go-функцию из JS
console.log(calculateFibonacci(40));