PHP чи Go: яку мову програмування обрати

У світі зростає популярність Go, тоді як РНР — падає. Усе частіше талановиті РНР-розробники переходять на Gо або вивчають її як другу мову програмування. У цій статті я вирішив порівняти ці дві мови, щоб допомогти вам зробити вибір.

Трохи про мене

В індустрії я працюю понад 10 років, зараз обіймаю позицію Lead Software Engineer в ЕРАМ. Більшу частину професійного життя розробляю застосунки на РНР і лише рік тому відкрив для себе Go.

Маю досвід роботи з JavaScript та TypeScript, трохи знаю Python, а з університетських часів пам’ятаю основи Java і C++. Обожнюю дізнаватися нове й занурюватись у тонкощі, і ця стаття тому підтвердження.

Якщо у вас виникнуть питання, пишіть у коментарях. Лайк, підписка ;-)

Основні завдання PHP i Go

РНР створили далекого 1995 року для розробки вебсторінок. Завдяки вкрапленням HTML у коді, цією мовою програмування можна було створювати динамічні вебсторінки. Головний тодішній конкурент РНР — Perl. За своє існування РНР пройшла масу змін, і тепер її використовують для створення різних стартапів та enterprise-рішень.

Зараз на РНР створюють різні CMS-системи (Drupal, Wordpress), e-commerce рішення (Magento, Spryker), LMS (Moodle), CRM (SugarCRM) тощо.

Go з’явилася у 2007 році як відповідь на нові виклики — масштабованість коду та підтримка concurrency (далі — багатопотоковості). На відміну від РНР, Gо із самого початку мала чіткі концепції синтаксису та була розроблена для великих застосунків з нахилом у продуктивність.

Сьогодні на Gо створюють не лише вебзастосунки, а й різні хмарні або DevOps-рішення. Наприклад, усім відомий Docker написаний на Gо.

Компіляція vs. інтерпретація

Якщо Gо — мова компільована, то РНР — інтерпретована.

  • РНР: код виконується одразу, майже послідовно, що спрощує налагодження і дозволяє швидко вносити зміни.
  • Gо: компілятор спочатку аналізує весь код, а потім збирає його в програму, яку можна застосовувати. Це сприяє створенню безпечнішого та ефективнішого коду, а також суттєво прискорює виконання програми наприкінці. Однак зміна коду призводить до перекомпіляції всієї програми, що може уповільнювати збірку на великих проєктах.

Трохи про синтаксис

Обидві мови мають С-подібний синтаксис. Gо — лаконічніша та має усього 25 зарезервованих ключових слів, тоді як у РНР — 71. Отже, Go відсікає все зайве. Один мій колега казав: «У Gо немає синтаксичного цукру. Ми на дієті».

Що PHP, що Go не мають нової функціональності: вони запозичують її з інших мов програмування. РНР вдало бере її з Java, Swift, Kotlin, JavaScript, тоді як Gо — із С, Pascal, Limbo, Oberon, Modula (як на мене, синтаксис Modula та Oberon взагалі не схожі на Gо).

Статична vs. динамічна типізація

PHP — мова з динамічною типізацією, де тип змінних визначається в момент виконання програми й може змінитися впродовж використання. З появою версії PHP 7.1 кількість інструментів контролю над типами зросла — зараз у РНР можна контролювати всі типи даних для класів, методів, властивостей, функцій, констант, проте змінні досі залишаються динамічними.

<?php

$number = 10;        // Integer
$name = "Alice";     // String
$isOnline = true;    // Boolean
$price = 99.99;      // Float

echo $number;        // 10
echo $name;          // Alice
echo $isOnline;      // 1 (true is displayed as 1)
echo $price;         // 99.99

$number = 'Ten'; // не призведе до помилки

Go — це мова зі статичною типізацією. Це означає, що тип кожної змінної визначається розробником до виконання програми й не може бути змінений у процесі. Щоб спростити визначення типу, у Gо є короткий синтаксис для створення змінних, який дозволяє компілятору визначити тип змінної, проте його також не можна змінити в процесі виконання програми.

package main

import "fmt"

func main() {
	var number int = 10       // Integer
	var name string = "Alice" // String
	isOnline := true          // Boolean
	price := 99.99            // Float

	fmt.Println(number)   // 10
	fmt.Println(name)     // Alice
	fmt.Println(isOnline) // true
	fmt.Println(price)    // 99.99

      number = false // призведе до помилки
}

Керування залежностями

Більшість залежностей у РНР — це С-бібліотеки, які встановлюють із PECL-репозиторію (їх називають PECL-розширеннями) через менеджер пакетів PEAR. Завдяки PECL-розширенням PHP може приєднатися й до бази даних, кешу або використати функції архівації. Процес встановлення дуже простий:

  • треба встановити менеджер залежностей (далі інструкція для MacOS):
brew install pear
  • потім — розширення:
sudo pecl install mongodb
  • додати розширення до РНР:
# php.ini 
extension=mongodb.so

Щодо залежностей, написаних на самому РНР, тут використовують пакети з Сomposer — сучасніший менеджер залежностей. Деякі пакети в Сomposer можуть потребувати встановлення PECL-розширень.

composer require mongodb/mongodb

Тож використання обох менеджерів важливе для роботи PHP-застосунків.

<?php

require_once __DIR__ . '/vendor/autoload.php'; // Path to the Composer autoload file

use MongoDB\Client;

// Connect to MongoDB
$client = new Client("mongodb://localhost:27017");

У Gо є схожий на Composer власний менеджер залежностей (у цій мові їх називають модулями), який вбудований у компілятор, що дозволяє використовувати один і той самий інтерфейс як для збірки застосунку, так і для встановлення модулів. Щоб установити модуль, треба виконати одну команду.

go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/mongo/options

Менеджер залежностей у Gо працює із сучасними репозиторіями, як-от GitHub, Bitbucket, GitLab тощо.

package main

import (
	"context"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// Set client options
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")

	// Connect to MongoDB
	client, err := mongo.Connect(context.TODO(), clientOptions)
}

Парадигми програмування

Обидві мови підтримують декілька парадигм одночасно.

РНР

ООП, функціональне, імперативне (процедурне), рефлективне програмування

ООП, функціональне, імперативне (процедурне), рефлективне, багатопотокове програмування

Різниця помітна одразу. Однак детальніше про це поговоримо пізніше, а зараз пройдемося по основах.

ООП

Gо не можна цілковито називати ООП-мовою, адже вона не підтримує звичну ієрархію класів і трохи інакше імплементує інтерфейси.

Класи та структури

РНР загалом використовує звичні класи.

class User {
}

У Gо є лише структури.

type User struct {
}

Наслідування

У РНР ми можемо успадковувати поведінку через наслідування іншого класу.

class Admin extends User {
}

У Gо ми це робимо вбудованими типами embedded (іноді плутають з декорацією, хоча на практиці вони відрізняються):

type Admin struct {
    User
}

Інкапсуляція

Люблю в цьому контексті цитувати Роберта Мартіна. «У мові С була чудова підтримка інкапсуляції, — каже Боб про .h-файли. — Але потім зʼявилась об’єктноорієнтована С++, і чудова інкапсуляція в С виявилась зруйнованою. Введенням у мову public, protected і private інкапсуляція була частково відновлена».

РНР саме використовує ці ключові слова разом із розділенням класів за namespaces, щоб інкапсулювати код.

<?php

namespace App;

class User {
 public string $email; // Доступ до властивості не обмежений
 protected string $username; // Доступ обмежений класом та його нащадками
 private string $password; // Доступ до властивості обмежений лише класом
}

namespace Main;

$user = new User(); // ERROR: Клас знаходиться в іншому namespace. Його треба конкретно зазначити

У Gо інкапсуляція досягається завдяки спеціальним правилам найменування (так званий Capital Case) та пакетів (що нагадують .h-файли з цитат Боба). Жодних додаткових ключових слів:

package app

type User struct { // Структура також доступна для експорту
    Email string // Доступний для експорту
    password string // Не доступний для експорту
}

package main

function main() {
    usr := new(User) // ERROR: Треба імпортувати пакет app
}

Поліморфізм

Серед таких типів поліморфізму, як Ad-hoc polymorphism, parametric polymorphism (далі параметричний поліморфізм) і subtyping (далі підтипи), РНР підтримує лише останній через наслідування та імплементацію інтерфейсів:

<?php

interface User {
    public function print();
}

class Admin implements User {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function print() {
        echo "Admin Name: " . $this->name . "\n";
    }
}

class Moderator implements User {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function print() {
        echo "Moderator Name: " . $this->name . "\n";
    }
}

function printAllUsers(array $users) {
    foreach ($users as $user) {
        $user->print();
    }
}

$admins = [
    new Admin("Alice"),
    new Admin("Bob"),
    new Admin("Charlie")
];

$moderators = [
    new Moderator("Dave"),
    new Moderator("Eve"),
    new Moderator("Frank")
];

printAllUsers($admins);
printAllUsers($moderators);

Окрім підтипів, Gо також підтримує параметричний поліморфізм через застосування Generics:

package main

import (
	"fmt"
)

type User interface {
	Print()
}

type Admin struct {
	Name string
}

func (a Admin) Print() {
	fmt.Println("Admin Name:", a.Name)
}

type Moderator struct {
	Name string
}

func (m Moderator) Print() {
	fmt.Println("Moderator Name:", m.Name)
}

func PrintAllUsers[T User](users []T) {
	for _, user := range users {
		user.Print()
	}
}

func main() {
	admins := []Admin{{Name: "Alice"}, {Name: "Bob"}, {Name: "Charlie"}}
	moderators := []Moderator{{Name: "Dave"}, {Name: "Eve"}, {Name: "Frank"}}

	PrintAllUsers(admins)
	PrintAllUsers(moderators)
}

Функціональне та імперативне

Тут мови мало чим відрізняються. Обидві можуть створювати функції з аргументами та повертати значення. Обидві мають контрольні структури типу if, switch, goto. Я сфокусуюся лише на відмінностях.

Цикли

У РНР є чотири способи створити цикл:

<?php

do {
    // код
} while (умова);

while (умова) {
    // код
}

for ($i = 0; $i < 10; $i++) {
    // код
}

foreach ($array as $key => $value) {
    // код
}

Кожен з варіантів можна використовувати в різних ситуаціях (немає конкретного правила). Помилково деякі розробники поширюють чутки, що способи відмінні між собою за продуктивністю, та це неправда. Частіше на практиці використовують while або foreach.

Ось як виглядають цикли в Gо.

package main

func main() {
    for {
        // код
    }

    for умова {
        // код
    }

    for j := 0; j < 10; j++ {
        // код
    }

    for idx, val := range nums {
       // код
    }
}

Як бачите, є лише один правильний варіант створення циклу.

Значення, які повертаються

Будь-яка функція створена, щоб отримати вхідні дані, опрацювати їх та повернути результат. У РНР ми можемо повернути одне значення або декілька у вигляді масиву чи обʼєкта.

function calculate(int $a, int $b): array {
    $sum = $a + $b;
    $product = $a * $b;

    return [$sum, $product];
}

list($sum, $product) = calculate(10, 5);
echo "Sum: $sum\n";
echo "Product: $product\n";

У Gо можна повертати декілька значень. Як правило, перше значення — це результат виконання, а друге — помилка функції. Але такий порядок не обов’язковий, і ви можете віддавати по три, чотири й більше значень.

func calculate(a, b int) (sum int, product int) {
	sum = a + b
	product = a * b
	return // Automatically returns sum, product
}

sum, product := calculate(10, 5)
fmt.Printf("Sum: %d\n", sum)
fmt.Printf("Product: %d\n", product)

Багатопотоковість

Суттєва й основна перевага Gо над РНР — багатопотоковість, що, на мою думку, є водночас недоліком. Однак передусім розглянемо, як РНР працює зазвичай.

PHP-FPM

Отже, РНР використовує FPM (FastCGI Process Manager). FastCGI — варіація попереднього інтерфейсу Common Gateway Interface (CGI), розроблена для того, щоб дозволити застосункам обробляти постійні процеси, таким чином знижуючи навантаження внаслідок запуску нового процесу для кожного вебзапиту. Це надійний і здатний до високого налаштування вебінтерфейс для PHP, який часто використовують з вебсерверами, тож для запуску вебзастосунків найчастіше використовують Nginx або Apache.

PHP-FPM підтримує пули робочих процесів, які чекають на вхідні запити. Ці пули можна налаштувати для обробки різних вебсайтів або різних частин вебсайту залежно від навантаження та вимог до ресурсів. Кожен пул може мати різну кількість робочих процесів, що дозволяє точно управляти продуктивністю.

Go-routine

У Gо код працює трохи інакше. По-перше, щоб запустити вебзастосунок, вам не потрібен окремий сервер. Завдяки стандартній бібліотеці на Go можна створити власний сервер.

Виконувати код паралельно цій мові дозволяють Gо-рутини. Рутина є легкою надбудовою над потоками (threads). Вони використовують менше пам’яті та ресурсів, оскільки Go має власний планер, який керує розподілом рутин на доступні процесорні ядра.

Для створення нової Go-рутини використовують ключове слово go, за яким іде виклик функції. Завдяки цьому функція виконується асинхронно.

package main

import (
    "fmt"
    "time"
)

func sendMessage(c chan string, message string) {
    time.Sleep(2 * time.Second)
    c <- message // Відправлення повідомлення через канал
}

func main() {
    c := make(chan string)
    go sendMessage(c, "Привіт, світ!")
    msg := <-c // Отримання повідомлення з каналу
    fmt.Println(msg)
}

У цьому прикладі функція sendMessage виконується в Go-рутині й відправляє повідомлення через канал c. Головна рутина чекає на повідомлення в каналі та продовжує виконання після його отримання.

Профілювання та налагодження

РНР використовує окремий застосунок для профілювання та налагодження — xDebug. Деякі розробники стикаються зі складнощами під час його встановлення (особливо в Docker), бо процес заплутаний і без танців з бубном іноді не обійтись. Для обробки результатів профілювання використовують, як правило, додаткове програмне забезпечення KCacheGrind, QCacheGrind, Webgrind. Часом профілювання роблять також окремим застосунком — XHProf, а іноді платними на кшталт Blackfire.

У Gо інструменти для дебагу (Delve) і профілювання (pprof) вбудовані, проте з візуалізацією результатів є маленьке ускладнення, яке потребує встановлення graphviz.

Декілька слів про SPL

SPL, або Standard PHP Library, — це спеціальна бібліотека для PHP, яка надає набір інтерфейсів та класів для реалізації стандартних структур даних (наприклад, стеків, черг, хеш-таблиць), ітераторів для перебору колекцій даних, різних інтерфейсів для доступу до файлової системи та інших корисних утиліт. SPL була введена для того, щоб стандартизувати рішення для загальних задач, з якими стикаються розробники PHP.

Standard Library в Gо містить широкий спектр пакетів, які надають базові інструменти та функціональності для розробки програм. Ці пакети охоплюють, зокрема, введення-виведення даних, обробку мережевих з’єднань, криптографію, обробку тексту, роботу з датами й часом і багато іншого.

Підходи Go та PHP (SPL) до стандартних бібліотек і вбудованих функцій різняться.

  • У Go — більш інтегрований та уніфікований підхід, де багато структур даних вбудовані просто в мову. Це спрощує розробку та підтримку коду, коли функціональності для роботи з базами, мережею або криптографією винесені в окремі пакети.
  • PHP, з іншого боку, використовує SPL для надання додаткових структур, а рішення щодо підключення до бази або використання функцій криптографії вбудовані в мову.

Різниця в продуктивності

Для прикладу я скористався платформою leetcode, де розв’язав найпростішу алгоритмічну задачу зі знаходження числа, що утворює суму.

Рішення на PHP:

function twoSum($nums, $target) {
    $result = [];
    foreach ($nums as $key => $value) {
        $term = $target - $value;
        if (array_key_exists($term, $result)) {
            return [$key, $result[$term]];
        }

        $result[$value] = $key;
    }
}

Виконання зайняло 0 мілісекунд та 20 мегабайтів пам’яті.

func twoSum(nums []int, target int) []int {
    result := map[int]int{}

    for key, value := range nums {
        term := target - value
        if _, ok := result[term]; ok {
            return []int{key, result[term]}
        }
        result[value] = key
    }

    return []int{-1, -1}
}

Рішення на Go зайняло теж 0 мілісекунд, але вже 5 мегабайтів пам’яті.

У реальному продакшені різниця буде ще більшою, і результати з leetcode є виключно демонстраційними, тож раджу вам самим попрацювати з цими мовами й написати власний тест порівняння продуктивності.

Висновки

У статті наведені лише технічні аспекти обох мов програмування. Я не став занурюватись у кількість вакансій, пов’язаних з конкретною мовою, та їхню частку на ринку. З власних спостережень можу сказати, що позицій на РНР наразі суттєво більше, хоча і значна їхня кількість змусить вас зламати мізки та пальці. Та я не можу стверджувати те саме про Gо.

У будь-якому разі мова Gо значно лаконічніша і має продуманішу архітектуру, аніж РНР. Ця мова молода і з часом буде щораз більше популяризуватись.

На мій особистий розсуд, більший потенціал має Gо — її варто тримати як другу мову програмування, а то й основну. Проте я продовжую писати гарні застосунки на РНР та в жодному разі не відмовляюся від неї.

А що думаєте ви? Пишіть у коментарях, буду радий конструктивній дискусії.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось6
До обраногоВ обраному8
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

ви забули про roadrunner

PHP починався з ідеї, що кожен двірник Василь може взяти і за вихідні накрутити собі веселенький особистий сайтик, де все блимає і переливається.

Go починався з ідеї, що можна взяти вчорашнього студента і посадити писати високонавантажені сервіси, які може будуть тримати мільйони юзерів (тому треба, щоб тримало), а може доведеться завтра викинути (тому треба щоб писалось швидко).

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

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

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

PHP починався з ідеї...
GO починався з ідеї...

хіба це шось погане) але я шось не бачу щоб у кожній підворотні стояли двірники та студенти з написами на картонці «пишу код на пхп, го, за їжу»)

РНР з’явився 30 років тому, і взагалі не як мова, орієнтуватися на ту ідею вже не актуально

В РНР не можна динамічно змінити тип змінної, якщо її тип задекларований (наприклад, змінна класу). На жаль, локальним змінним не можна вказати тип, і це сумно. Проте, якщо, наприклад, декларація функції повертає дійсне число, а коли віддає локальну змінну, яка внаслідок помилки розробника вертає стрічку, то це призведе до помилки під час виконання. Але є статичні аналізатори, які ці проблеми можуть виявити.

Стосовно пам’яті — не варто порівнювати обсяг пам’яті, яку займе ціла ВМ і нативний бінарник. А от в контексті веб сервера, зокрема, ФПМ, ситуація буде не така однозначна.

Трохи незрозуміло, що мається на увазі під «підключенням до ДБ чи криптографія вбудовані в мову» і порівнянням і SPL. Це все — розширення. РНР можна в принципі скомпілювати так, що в ньому нічого не буде :) РНР по суті від інших інтерпретованих (і не лише їх) мов не відрізняється — майже все забезпечується С бібліотеками, ну або ж написаними на РНР пакетами.

А ещё сервис на Go можно скомпилить под Linux и залить в докер-образ под scratch. И он будет занимать около 20-30 мегабайт всего, вместе со всеми зависимостями. Один контейнер при этом будет работать многопоточно.

Хорошо сравнивать PHP и Go на примере бэкенда.
Значительно интереснее будет вопрос, можно ли написать на PHP Kubernetes.

с другой стороны, а можно ли написать на Go сложную бизнес логику. Вот прямо такую, чтобы развесистую.
Ну точнее, можно то оно можно, но это будет боль. Язык очень бедный на синтаксический сахар. и там, где на ПХП или Питоне можно сделать в одну строчку, на Гоу будет 4 строки.
Пример условный, но Гоу хорош в микросервисах, а вот там, где уже сильно появляется доменная логика (CRM/ERP/и тд), то тут он уже проиграывает.

Я же написал — функциональная замена С. Очень простой язык, на котором пишутся очень простые утилиты из которых собираются. сложные системы.

Я же написал — функциональная замена С.

вибач, але ти ж такого не писав.

Хорошо сравнивать PHP и Go на примере бэкенда.
Значительно интереснее будет вопрос, можно ли написать на PHP Kubernetes.

так тойво — оця ось конкретна гілка коментів окрема. не продовження якогось діалогу, не має явних посилань на інші коменти.
Як на мене логічно очікувати, що все обговорення в межах гілки йде в локальному контексті, або в контексті статті. Тому в Я же написал ... має йти мова про написане в цій гілці раніше. Або ж явно посилатися назовні (бо хз хто що де написав. гітлєр теж написав майнкрафт).

да ладно вам. мы же айтишники. скил телепатии прокачан.

dou.ua/...​rums/topic/51783/#2918446

а какое это имеет отношение к этой ветке дискуссии?

Я вважаю це цілком можливо, дивлячись, що ви маєте наувазі під складною бізнес логікою. Go дійсно доволі лаконічний, проте він також гарно масштабується. Я вважаю, що синтаксичний цукор, не є обовʼязковою умовою для цього.

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

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

опять же, оно можно на гоу, но да простят меня адепты Go, но на нему if err функцию из 10 строк при необходимости кучи проверок, раздувают ее до 30 строк и значит, что не влезет на 1 экран.

Раніше теж писав такі системні сервіси або hi load мікро сервіси переписував доречі з php. Чогось складного дійсно там не було
Зараз проект такий солідний монолітик із вжареною бізнес логікою і 90% тасок у стилі «юзер тут нажимав 10 разів кнопку у продовж секунди і на 11й обійшов певне бізнес правило» Все як ми любимо. Жити можна. Складніше ніж у інших бо подекуди треба лісапеди пилити, але нічого прям тяжкого. Це не на c такий же сервіс пилити. Багато чого є. І патрони усі працюють обсервери там ті ж, і тестування красиве у стилі given when then і dependency injection є автоматичне

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

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

На го класно писати щось дуже просте або надзвичайно складне. В обох випадках рішення виходять досить елегантні. А от коли діло доходить до чогось середнього, але досить тривіального, то го перетворюється в повне лайно. Як приклад — взаємодія з базою даних. Навіть на такі популярні рішення, як gorm, неможливо дивитися без сліз після того, як хоть раз попробував eloquent, alembic чи entity framework.

Я коли подививсь на gorm остаточно переконався що Пайк не жартував, коли неодноразово пояснював що він навмисно, цільоспрямовано обрізав можливості мови так, щоб ніякою Джавою, а тим більш С++ не пахло, щоб геть не було можливості писати як на них.

І коли адепти Go кажуть про потужність мови, то то вони якось не зрозуміли кілер фічу Go яку заклав в нього Пайк — радикальне, принципове зниження потужності.

Всі пишуть за «швидкість» у php але де??
з часів компоузу, всі ці ларавель і все з ним це купа колупання і геометричне ускладнення коду з часом якщо проект зростае
Go же як php з часів його молодісті — поставив і полетіли. Всі пакети підключаются просто, складно написати запутані вермішелі так як сама мова против, прямо в мові е нормальні тести і аналізатори. І як вершина — воно компілюеться

Перейщов на Go з C++ в свій час тільки заради серверних обробників (не веб) як раз із-за простоти з майще тіеюж бистродіею. Але з часом побачив всю силу і всі нові веб-застосунки все на Go.

Приємно чути, і справді перехід з С++ на Go також доволі поширений кейс.

PHP — для гвіздків. раз-два, і готово) Go — для саморізів. все чітко й надійно. Порівнювати ці інструменти — це як намагатися забити саморіз або закрутити гвіздок. Може й вийде, але виглядає це дивно.

Я теж не дуже зрозумів для чого автор порівнює ПХП із Го.

Є кейси, коли інженери переходять з РНР на Go. Мета цієї статті заохотит адиторію до вивчення інших мов програмування та сприяти переходи.

Десь, я це вже чув. Хм...
В будь якому разі, я вважаю, що мови порівнювати можна. Можливо, щодо цієї статті, то варто було тоді порівняти усі аспекти (взяти трохи ширше), щоб читач міг визначитись чи хоче він забивати цвяхи, чи закрутити самонарізний шуруп.

не одним php-fpm, добре якби згадали про reactphp / roadrunner / swoole

Дякую за підказку. Це доволі цікава тема для статті.

Однак зміна коду призводить до перекомпіляції всієї програми, що може уповільнювати збірку на великих проєктах.

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

ООП

там нет ооп, это ОП

багатопотокове програмування

это не многопоточность, а псевдомногопоточность

параметричний поліморфізм

это не полиморфизм, а его разновидность, и работает как шаблонизатор
go.googlesource.com/...​/43651-type-parameters.md
This design suggests extending the Go language to add a form of parametric polymorphism, where the type parameters are bounded not by a declared subtyping relationship (as in some object oriented languages) but by explicitly defined structural constraints.

Щодо компіляції, тут я погоджусь з вами. У наш час різниця не відчувається.
Щодо ООП, ви, мабуть, дуже поверхнево прочитали статтю, рядком нижче написано:

Gо не можна цілковито називати ООП-мовою

Щодо багатопотоковості — це труднощі перекладу. З усіх варіантів перекладу слова concurrency я вибрав цей.

та підтримка concurrency (далі — багатопотоковості)

Щодо параметрирчного полімофрмізму, не дуже розумію, що ви хочете сказати.

Серед таких типів поліморфізму, як Ad-hoc polymorphism, parametric polymorphism (далі параметричний поліморфізм) і subtyping (далі підтипи),

а зачем тот ООП головного мозга нужен?

У вас є краща пропозиція?

Ці мови не мають ООП безпосередньо (у класичному розумінні), проте все одно викристовують концепції притаманні ООП.

вы плохо прочитали.
«зачем он нужен?»

это ответ на ваше

проте все одно викристовують концепції притаманні ООП.
а зачем?
зверхньо

«поверхнево» дещо зверхньо промовив олександир

Аксіома Ескобара в чистому виді.

Не могли би ви пояснити свою думку? Аксіома Ескобара — це мем, який вживається у відповідь на ситуації, коли потрібно обрати один з двох однаково поганих варіантів.
Чому ви вважаєте обидва варіанта поганими?

ради новогоднего срачу предположу, что он Java/C++ dev

исключительно вброс.

PHP чи Go: яку мову програмування обрати

Стаття не відповідає заголовку. Яка була мета статті?

У статті наведені лише технічні аспекти обох мов програмування. Я не став занурюватись у кількість вакансій, пов’язаних з конкретною мовою, та їхню частку на ринку.

Пропускаємо неоднозначність терміну «технічні аспекти мов програмування».
Кількість вакансій, а скоріше тренди по різним показникам в вакансіях — це зрозуміла метрика, в контексті вибору мови/інфраструктури для розвитку як технічний спеціаліст. Окремо можна виділити «область застосування».
З точки зору обрати мову для нового проекту, можна було б розглядати специфічні тули. Умовно на ПХП купа ЦМС і розробників (відносно дешевих під них), тому для якихось сайтів — це краще. У Го свої особливості.

Що має показати дана стаття не зрозуміло.

Є кейси, коли інженери переходять з РНР на Go. Мета цієї статті заохотит адиторію до вивчення інших мов програмування та сприяти переходи.

Стаття показує синтаксичні відміннсоті цих двох мов, та частково висвітлює різницю у застосуванні. Частково погоджуюсь, що тема у назві не до кінця розкрита. Можливо краще було б назвати статтю — «PHP vs. Go. Cинтаксичні відмінності».

Embedding — це не inheritance. Embedding в Go використовується для композиції і суттєво відрізняється від inheritance.

І в пхп є трейти для цього також

Так, можливо ви праві і краще було б порівняти Embedding з PHP traits, та я таким прикладом хотів сказати, що у Go немає наслідування.

Згоден. Я не мав на меті ввести читача в оману. Emdedding не є наслідуванням. Вони стоять поруч, щоб продемонструвати альтернативу, відміннсоті. Наслідування в Go немає, а в РНР є.

Рішення на Go зайняло теж 0 мілісекунд, але вже 5 мегабайтів пам’яті.

Варто було порівнювати у мікросекундах або наносекундах, щоб показати приріст швидкодії

Варто бенчмарк написати, бо літкод дуже погано це робить. 😂

Згоден на усі 100%. Leetcode був вибраний за принципом економії часу та ресурсів.

Якщо ви хочете бути максимально ефективним тоді потрібно знати обидві мови. Go дає можливість писати відносно швидкий код, а PHP чи Python писати швидко.
Немає сенсу фігачити з 0 на Go чергову АПІху чи адмінку, коли Laravel/Symfony/Django зі своїми батареями вже давно для того все мають.

Я ще хотів би прикладу, коли в вебі треба саме та швидкість, і боттлнеком є саме мова. Бо скільки я громіздких проектів не бачив — в 99% все впирається в запити до бази або до сторонніх вендорів. Такого щоб от саме в php була проблема — ще не зустрічав. А я власноруч писав на php репортинг що в реал-таймі підраховує 500к+ фінансових записів та будує статистику по ним

p.s. фейсбуки і гугли в приклад не приводити — цікавіше більш наближені до життя приклади

Як вам ідея створення власного DNS-серверу? Такий запит, може бути прикладом де Go підійде краще, аніж PHP.

Хоча це більше cloud, аніж web. Може бути ще варіант із обробкою PDF.

Для чего писать собственный DNS-сервер? Для того, чтобы использовать где-то Go? Или чтобы поддержать отрасль велосипедостроения? ))

Bind решает 99,999% таких задач, если не больше.

Вобще-то есть тенденция переписывать старый юниксовый стафф на Go. Потому что Go внезапно разрабатывался как замена C, а не PHP.

Частково ви праві, проте Go не розроблявся з метою замінити С. Раджу перечитати Origins: go.dev/doc/faq#Origins

We decided to take a step back (from C++ and Java)

Интересно куда?

Eugene,

  • по-перше не змінюте цитату. В документації Go (посилання я надавав вище) такої цитати нема:
    We decided to take a step back and think about what major issues were going to dominate software engineering in the years ahead as technology developed
  • По-друге, мова йде про те що С++ та Java розроблялись за інших обставин, за інших часів і дизайном мови деякі аспекти не були передбачені. Це не означає, що Go передбачивши ці аспекти у своєму дизайні, свторена з наміром замінити або стати successor для С++ або Java, ось як наприклад мова Carbon (github.com/...​rbon-language/carbon-lang).
    Мова Go себе так не позиціонує.
  • По-третє, і я тут трохи докопуюсь, але С та С++ все ж такі різні мови.

Вот именно, что народ трохи подустал от сверхнавороченных плюсов и джавы и вернулся к корням — очень простой компилируемый язык расширяемый через библиотеку.
Другими словами: мы берём концепцию С и прикладываем ее к сегодняшним реалиям.
А именно:
1. Делаем легковесную многопоточность на неявной многопроцессорности
2. Юникод из коробки.
3. Автоматическое управление памятью.
4. Встроенные простые контейнеры.
5. Максимально упрощённое ООП.

Вуаля, и мы имеем язык умеющий работать и с абстракциями, и с железом, не такой замороченный, как плюсы и не требующий той кошмарной работы со строками и потоками, как old plain C.

Историю пишут победители ©
Ці «оріджінс» писались постфактум. Погугліть виступи Роба Пайка 15-ти річної давності, де він дуже добре пояснює причини створення Го.

Одна із причин полягала в тому, що дуже багато софта в гуглі було написано на чистому Сі і компляція деяких проектів займала десятки годин. Також в Гуглі було дуже багато коду для роботи з стрічками, а в Сі це дуже великий гемор. Розробки внутрішньої мови для обробки великих об’ємів тексту в Гугл велися ще з нульових, в тому числі Робом Пайком, який уже тоді (2002) був відомим дизайнером мов програмування.

Також одною з важливий причин було ще те, що в Гугл не було своєї мови програмування для повного циклу розробки ПО, як в інших компаніях. Наприклад, у Майкрософт був Сі-шарп, у Оракл Джава, у Фейсбук Франкенштейн на основі ПХП, у Еппл Свіфт. Гугл пробували підганяти комітети по розробці С/C++, щоб ті швидше стандартизували потрібні їм фічі, але процес йшов дуже довго. Вони навіть в якийсь момент найняли Гвідо ван Россума і дали йому повну свободу пиляти Пайтон, але взамін хотіли швидкого апрува їх власних пропоузалів до мови і в результаті феєрично розісралися, бо Ван Россум хворів синдромом вахтьора (як і містер Пайк).

Саме за таких обставин народився Го.

Нажаль, я не можу навести вам конкретних бізнес специфікації, проте такі кейси існують. Сподіваюсь ви розумієте, що на ринку можуть бути присутні декілька схожих рішень. Я точно впевнений, що Bind не єдине рішення. Щодо Go імпліментацій є github.com/coredns/coredns.

Я би не назвав це «велосипедостроением», бо якщо у вас є система, і вона застаріла і замість її оновлення дешевше створити нову, це не зовсім підходить під «велосипедостроение». Ви згодні?

500к+

Ви хотите сравнить перебор 500к+ в цикле чего-либо, даже пофиг чего на PHP с перебором того же на Go? PHP тут будет в пролёте по перфомансу — сразу можно сказать.

+. в 1 billion record challenge взагалі java всіх заборює github.com/gunnarmorling/1brc Для PHP найшвидше що бачив це 12 секунд dev.to/...​-billion-rows-in-php-3eg0

Якщо коротко — начхаті на ті наносекунди в бенчмарку.

Мабуть мова іде про те що обчислюваної потужності процесорів зараз хоч дупой жуй і на будь якій мові(класичні попсові) можна писати класичний софтваре що молотить бізне логіку, ганяє стрінги та інти туди сюди між базою та юайем. І те що там десь націдили наносекунд на 500К+ циклі бо хтось не зміг у батч процесінг, пейджин, кешування і накидав усе в одном циклі.
От і виходить що пофіг чи то го чи то пхм чи джава із дотнетом. Бо витрати на більш потужну віртуалку для кубера просто копійки на фоні витрат на повноцінну команду що пише та обслуговує софт. Особливо коли треба компанії міняти стек чи шукати спеціалістів що не просто уміють у «батч процесінг, пейджин, кешування» а іще в декілька мов та платформ.

Багато мов до сих пір не вміють толком в багатопоточність і нічого, написалу мілярди строк коду вже, по типу того ж джава скрипта.

Если бы ты сталкивался с HFT, серверами на миллионы подключений, базами данных ты бы такого не говорил.
Там и ассеблерная оптимизация в большой цене.

Ви хотите сравнить перебор 500к+ в цикле чего-либо, даже пофиг чего на PHP с перебором того же на Go? PHP тут будет в пролёте по перфомансу — сразу можно сказать.

де тут про нфт і мільйони підключень?

Бо витрати на більш потужну віртуалку для кубера просто копійки

а когда 100 виртуалок или даже 500 то «копейки» вываливаются в неплохую сумму, из-за того что цпу молотит тонны говнокода, у меня кусок проекта, написанный индусами постоянно в фоне молотил что-то даже когда 0 активности было, как это дерьмо пожирало батарею ноута я уже промолчу, а проект не работал локально без докер контейнеров, в которых крутилось это индусское говно

Так проблема була в індусах чи мові програмування?

для такого прикладу потрібно виключити запити до БД :-)
наприклад: парсинг csv, генерація файлів pdf, docx etc.

Я би сказав, уся справа в костах та перформансі, проте можуть бути і додаткові фактори. Все це дуже субʼєктивно.

concurrency (далі — багатопотоковості).

🤔🤔🤔
Parallelism?

Щоб отримати відповідь на це питання, я би радив подивитись відео: www.youtube.com/watch?v=oV9rvDllKEg

Роб Пайк краще за мене пояснить у чому різниця ;-)

Так але багатопотоковстю це теж не можна назвати.
Канкаренсі це канкаренсі Вигадали для цього нормальний же термін, нащо шукати замінники

Частково з вами погоджуюсь. Для мене було принципово знайти саме український аналог цьому слову. З усіх варіантів я вибрав цей. Труднощі перекладу)

> У Gо є лише структури.

У Go є типи. Типи можуть мати методи і частково задовольняти ООП.

Ви маєте рацію, що типи частково задовільняють ООП за рахунок наявності методів. Структури були наведенні, як приклад альтернативи РНР класам, щоб показати різницю між мовами.
Більш детальніше про типи можна прочитати в Language Specification:
go.dev/ref/spec#Types

Залишилось дочекатись коли в Go з’явиться веб-фреймворк хоча б рівня Zend чи Yii 2, про рівень лари чи сімфоні навіть не говорю

why? це вже буде не про симпліті

ну симпліті це класно хеллоу ворлди писати. мовляв дивіться як легко, 3 рядочки і готово.

а швидко підняти rest api на десяток ендпоінтів, з аутентифікацією, троттлінгом та кешом — хочеться чогось готового, замість свого «простого» велосипеда

сходу github.com/kataras/iris
з коробки все що можна тільки побажати, навіть proto
і таких модулів безліч під кожну вашу задачу (iris максимально широко влазить в усе, тому його згадав)

А взагалі як раз це плюс Go шо ти збираєш як конструктор з модулів. Швидко і гнучко.
Все що ви описали «із готового» збирається за пару годин максимум.

Що ви маєте на увазі, коли говорите «рівня Zend чи Yii2»? Чи знайомі ви з цим переліком: github.com/...​e-ov-file#web-frameworks

цей перелік тільки підтверджує незрілість мови. етап, коли кожен пише свій велосипед

в цьому списку 30+ (!!!!) бібліотек для роботи... з JSON 🤣

робота з json — це одна з найбазовіших речей. але люди наклепали три десятки якихось обгорток без єдиного стандарту, бо очевидно, що стандарту (як psr в php) ще не придумали, а вбудованих фіч мови — не вистачає. відповідно кожен знає як краще, і скоріш за все, кожен проект — це свій окремий, унікальний набір

до речі, і веб-фреймворків в цьому списку — під 4 десятки. порівняйте це зі «зрілими» мовами, де продакшн-реді рішень зазвичай один — два конкуруючих, і третій доганяючий

короче те що я бачу по цьому списку — це стан php 2008го року 🤷‍♂️

якщо що, це не означає що go погана мова. просто потрібен час, щоб екосистема дозріла

в цьому списку 30+ (!!!!) бібліотек для роботи... з JSON 🤣

дляя джсона есть 3 либы
— стандартная, которая по максимуму поддерживает всю спеку, но и самая худшая по производительности
— sonic, jsoniter которые поддерживают стандартный интерфейс, но намного лучше по производительности
Все остальное хлам либо кастомные либы, например, чтоб вытаскивать или патчить джсон на лету не применяя парсер.
Фреймворки на го не нужны от слова совсем, полно либ которые реализуют http сервер с мидлварами, в го жирные фреймворки типа laravel/symphony не нужны

в го жирные фреймворки типа laravel/symphony не нужны

Їх складно або неможливо написати. Тому їх немає, а не тому, що вони не потрібні. Завжди фреймворки потрібні.

хуйню якусь городите
фреймворки це «цукор» для розробника, котрого нема в мові стосовно задачі
як на мене це найкраще показує — не потрібно робити якогось єдиного динозавра і потім його підтримувати для задач.

Для Go сотні «фреймворків» і всі вони актуальні тільки для тих хто починає знайомитись з мовою.
В великому ентерпрайзі фреймворки в першу чергу захищають від занадто розумних (чи тупих) розробників. Шоб з часом читання та підтримка не вимагала більшого часу. В Go немає такої проблеми бо він вже зі старту робився з оглядом на це.

І головне воно компілюються під все що захочеш. І навіть під те що ше не існує можна написати код що буде працювати. Як на мене, кращім показником мови е те, що вона «розвивається» на самий собі. Той же питон майже всі популярні нормальні ліби сішні для швидкості та універсальності. Про PHP взагалі мовчу, це цільна цеглина з якої можно будувати, но нічого не додаш і не віднімеш.

Фреймворки робляться для того, щоб автоматизувати розробку та досягати результатів швидше при обмежених ресурсах. Go не розроблявся для цього, там сильно низький рівень та сильно простий синтаксис, який вимагає складних багатослівних конструкцій. Ви можете скільки завгодно сперечатися з цим, але факти кажуть що кількість вакансій, великих проектів та фреймворків на Go мізерна. Реальне використання мови не співпадає з рекламними прокламаціями фанатів.

Ви мабуть плутаете використання мови вами зі всім світом.
Останні три роки бачу тенденцію що всі хто був з php переходять на го.
Безліч вакансій, особливо з формулюванням «go + php, перенос функціоналу з php»
Великі компаніі же чи го чи раст якшо говоримо за веб

Ви вперто ігноруєте факти та видаєте бажане за дійсне. Давайте візьмемо просту статистику. Вона може бути не суперточною, але кількість вакансій на Go знаходиться на рівні 5 частини від того ж PHP, а порівнювати з JS/Python/Java взагалі немає сенсу. Якщо роздивитися графік уважно, то видно, що попит на Go-внярів (вибачте за грубість, але дуже хотілося пожартувати) не зростає та ніякої прогресії немає. Якщо попит не зростає, то й переходу з інших мов на Go не відбувається.

Те, що ви спостерігаєте якийсь локальне збільшення попиту на Go, не є світовою тенденцією.

дуже дивна аналітика.
Зараз такий час що на будь яку точку зору можна знайти пруфи.

Те що «php не вмирае» це не новина, всеж таки 90% вебу написано ним и досі більша частина хостерів не підтримуе нічого окрім php в рамках дешевих тарифів.

Але (як дивно то) всі великі гравці все кілька років переходять на Go. А ті кому була критична бистродія/розробка перейшли на нього вже давно і зараз якщо все ще потрібна бистродія мігрують на раст.
А за великими гравцями потягнувся і весь інщий світ. Ще два роки тому Го зустрічався в якихось вузьких рішеннях в «великому ентерпрайзі» а зараз візми любу ноунейм-контору шо сайтики кліпають і вони працююсь з Го

Але (як дивно то) всі великі гравці все кілька років переходять на Go.

Ви в курсі про сенс термінів «всі великі гравці» та «переходять»? Хто з великих гравців окрім Гугла на нього переходить? Перехід — це відмова від однієї мови на користь іншої. Максимальна заміна. Не один-два мікросервіси напедалити, а переписати наявні продукти на іншу мову. Оце перехід. Так про кого ви мову ведете?

А за великими гравцями потягнувся і весь інщий світ.

Не видавайте бажане за дійсне.

а зараз візми любу ноунейм-контору шо сайтики кліпають і вони працююсь з Го

А, ось кого ви мали на увазі, коли казали про «великих гравців»...

спеціально в гугл пішов, якшо вам релігія забороняе:
brainhub.eu/...​ry/companies-using-golang
www.softkraft.co/companies-using-golang
careerkarma.com/blog/who-uses-go

якщо ж гуглити аналітику по рокам то видно шо «актуалізація» пішла піля 2021 (як і у тайпскрипта доречі)
те що ви з цим в житті не стикаетесь не означае що цього не існуе

Відкрив рандомне посилання з першої статті — Dropbox.

github.com/...​box/repositories?type=all — 229 всього репозиторіїв

github.com/...​es?type=all&q=language:go — 22 го репозиторія

Тобто, 10% репозиторіїв на го, останній коміт в Jun 27, 2024 — більше ніж півроку тому.

Бачу коміти в JavaScript, TypeScript, Python буквально годину чи кілька днів тому.

Тож схоже, що вони залишились на пітоні, терраформ переписали на Го. Чи це «перейшли»? Щось не схоже, скоріше знайшло свою нішу.

подивився комміти за вашим посиланням — більше всього (і самих свіжих) кліент, кліент, кліент..
Дійсно, писати кліенти на go таке собі, він для цього не пристосован.

Зато бачу багато расту — то про що я писав вище, якщо все ще потрібна бистродія з пам’ятью то з Го переходять на раст.

Коли людина каже «всі великі компанії», то там мусять бути 100% від top 500 Fortune. А наведені приклади — пара крупних, решта — дріб’язок.

я проходил разные фреймворки, всегда появлялась задача, как сделать то, что не умеет фреймворк без говнкода и вписаться в максимум предоставляемым им хелперов, интерфейсов, классов и тд. Было что и полдня тупо дебажишь месиво ядра кода фреймворка и результатов 0. Если задача использовать вылизанный фреймворк, то берите symphony, spring и кучу подобных ентерпрайзного уровня. Практически все го фреймворки реализуют какую-то конкретную задачу и когда надо выпрыгнуть за ее пределы появляется ворох вышеперечисленных проблем. Поэтому каркас апп проще собрать самому, выбирая то что нужно из кучи готовых либ типа github.com/avelino/awesome-go

Можливо ви праві, що оскільки Go — це мова молодша за PHP, то тут є безліч варіантів не обовʼякзово вдалих. На мою думку, фреймворк Fiber менш вдалий, аніж Echo або Gin. Проте, я би не квапився називати мову «не зрілою» через це.

Не дай Боже. Подобається Go за те що зайшов і ти розумієш код без контексту на якому фреймворку це було написано.
Взагалі писав на фреймворку такого типу де без знань фреймворку робити нічого. Такі є на Go. Тільки під web3 — cosmos SDK. Це вже не той експірієнс Go розробки де ти контролюєш усе та нема ніякої фреймворкової магії (ну добре ще треба враховувати особливості web3 де не можна користуватись time.Now, рандомом, float, uuid і тому подібне)

розумієш код без контексту на якому фреймворку це було написано.

ага, і кожного разу розбираєшся по-новому що за структуру винайшов цей розробник

фреймворки не на рівному місці зʼявились, і не по приколу

В Go строга типізація і неможливо як в інших мовах поліморфізмом підкинути «гівна» чи накинути макарон коли один класс/метод пересікается в різних рівнях вкладеності.
Навіть якщо написали якийсь велосипед — це все лінійно і відслідковуеться в IDE.

Якщо вам довподоби мова в мові (котру потрібно окремо вивчати) зі своїми приколами та точками відмови, то це ваша справа.
Фреймворки з’явились як «цукор» для мови яка «з коробки» не могла робити просто те, що робить фреймворк.
Вони з’явились для контролю складності та підтримуваності коду з часом.
Вони з’явились в мовах які робились під свої задачі, і зазвичай не встигали або навіть не хотіли розвиватись разом з потребами комьюніті.

Go це фреймворк на С++ (та інші мови хоч асемблер) якщо вам так краще розуміється))
І в цьому його сила. Не один складній інструмент для групи завданнь, а один простий інструмент під будь яку задачу.
Нема мови (окрім расту і то там інша парадигма і підключаемі бібліотеки мають свої особливості) яка могла б так же (з тим же синтаксисом) працювати над будь якою задачею, на будь-якій платформі (навіть пітон, з ним дуже багато підводних в кросплатформі, тема для окремої статі)

На мою думку, розібратися у трьох простих файлах значно легше, ніж у десятках залежностей конкретної інсталяції фреймворку. На Go ніхто не створює монструозних монолітів — навпаки, пропагуеться Unix-філософія: простота, модульність і мінімалізм.

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

Не розумію для чого. Треба монструозний фреймворк? йдеш і вибираєш з того, що є (Spring, .Net, Zend, Yii і ще міліон іншого). Го жеж про інше.

Web-розробка це один з кейсів де можна застосувати Go. Фреймоврк — це набір інстурментів для розробки у більшу приємному інтерфейсі. Я вважаю вони мають місце бути в будь які мові. Ви же не бути кожен раз писати свій Router від початку?

Підписатись на коментарі