昨天聊完了和 PHP Laravel 框架的比較
今天來聊聊我主觀對 Ktor 和 Golang 進行後端開發的比較
首先比較語言層面的部分,也就是 Kotlin 和 Golang 的差異。
Golang 作為一個編譯式語言,而且運作時不需要像是 Kotlin 這樣透過虛擬機器進行運作
所以在效能上,Golang 和 Kotlin 相比較是很有優勢的。
而且 Kotlin 有 coroutine,Golang 也有自己對應協程的實作 Goroutine。所以在非同步系統上的比較,Golang 也不會輸給 Kotlin
不過,Golang 的(設計原則)[https://golang.org.tw/doc/faq#principles]上,很強調「簡化」的概念
Go 嘗試在兩種意義上減少“打字”的量。在整個設計過程中,我們一直努力減少混亂和複雜性。沒有前向宣告,也沒有標頭檔案;所有內容都只宣告一次。初始化具有表現力、自動化且易於使用。語法簡潔,關鍵字少。透過使用 := 宣告並初始化構造的簡單型別推導,減少了重複(foo.Foo* myFoo = new(foo.Foo))。也許最根本的是,沒有型別層次結構:型別就是型別,它們不必宣告它們之間的關係。這些簡化使 Go 語言既富有表現力又易於理解,同時又不犧牲生產力。
在 Go 為什麼沒有特性 X? 也說
每種語言都包含新穎的特性,並省略了某人最喜歡的特性。Go 的設計著眼於程式設計的愉悅性、編譯速度、概念的正交性以及支援併發和垃圾回收等特性的需求。您最喜歡的特性可能缺失,因為它不適合,因為它影響了編譯速度或設計的清晰度,或者因為它會使基本系統模型過於複雜。
個人認為,這樣的設計方針,讓整體語法變得調理且簡化,但是也犧牲了很多可以讓程式碼更加簡潔的設計。
下面我們用幾個框架作為例子
使用 Golang 的網頁開發,很常見的就是使用 gin 這個框架。
一個簡單的路由如下
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/test", test)
router.Run(":80")
}
func test(c *gin.Context) {
str := []byte("Hello World")
c.Data(http.StatusOK, "text/plain", str)
}
這邊 gin 設計使用 Byte Array 來進行傳輸。
如果要回傳 Json 格式的內容,需要定義 struct
func test(c *gin.Context) {
type Result struct {
Status string `json:"status"`
Message string `json:"message"`
}
var result = Result{
Status: "OK",
Message: "This is Json",
}
c.JSON(http.StatusOK, result)
}
這種寫法對熟悉 C 或者 C++ 的工程師,或許比較容易上手。但是面對撰寫物件導向程式語言習慣的工程師,個人覺得會有點負擔
再來,我們來看看 Golang 的 ORM 作法
我們可以選用常見的 gorm 框架
使用 gorm 進行條件存取的程式碼如下
db.Where("name = ?", "jinzhu").First(&user)
個人認為,可以很明顯的看出由於語法的簡化,所以這邊使用了類似 Query 的方式進行條件設定,而不是透過函式進行設定。這樣的寫法對我來說已經比較難以接受,會希望既然已經使用 ORM 了,那常見的需求應該都要有對應的函式或方法去生成才對。
關聯的部分,一對一或者一對多的案例比較單純,如前面的比較,我直接使用多對多的案例進行比較
Gorm 定義多對多的寫法如下
type User struct {
gorm.Model
Languages []*Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
Users []*User `gorm:"many2many:user_languages;"`
}
這邊定義了兩個 struct,中間用 user_languages
資料表作為中介表。
這邊我們可以看到,由於型態的簡化以及框架本身的設計,
我們不會像是 Laravel 一樣有框架定義的 Collection,也不會像是 Exposed 一樣取得 SizedIterable
而是取得一個 struct 的陣列。在後續的存取上,自然也不會像是 Collection 或者 SizedIterable 一樣方便。
另外在定義 struct
時,我們也不會像是使用物件導向語言一樣,去定義內部的函式。而是需要使用 struct tag 進行標記,類似使用反射的方式去標記這個變數的關聯。
所以我認為,gorm 和 Laravel Model 或者 Exposed 相比,是一個比較簡化後的 ORM 框架。
因此在框架比較上,這點會讓我比較視為弱項。
Goravel 這個框架是 Golang 參考 Laravel 所設計的一個框架
The framework style is consistent with Laravel, allowing PHPer to create powerful Golang applications without learning a new framework. Tribute to Laravel!
所以一些設計和使用方式上幾乎和 Laravel 一樣。
像是 Controller 的設計
package controllers
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
)
type UserController struct {
// Dependent services
}
func NewUserController() *UserController {
return &UserController{
// Inject services
}
}
func (r *UserController) Show(ctx http.Context) http.Response {
return ctx.Response().Success().Json(http.Json{
"Hello": "Goravel",
})
}
以及路由的設計
package routes
import (
"github.com/goravel/framework/facades"
"goravel/app/http/controllers"
)
func Api() {
userController := controllers.NewUserController()
facades.Route().Get("/{id}", userController.Show)
}
以及資料庫存取的設計,也比較能使用方法來進行定義,不像是使用 gorm 語法那麼的原生
facades.Orm().Query().Where("name", "tom").Order("sort asc").Order("id desc").Get(&users)
但是我們可以看到,在設計關聯時,由於基於 gorm,所以還是得用宣告 struct tag 的方式來定義關聯
type User struct {
orm.Model
Name string
Roles []*Role `gorm:"many2many:role_user"`
}
type Role struct {
orm.Model
Name string
Users []*User `gorm:"many2many:role_user"`
}
相比於 Exposed 的做法
object ProductsTagsTable : Table() {
val product = reference("product", ProductsTable)
val tag = reference("tag", TagsTable)
}
class ProductEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<ProductEntity>(ProductsTable)
var name by ProductsTable.name
var tags by TagEntity via ProductsTagsTable
}
class TagEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<TagEntity>(TagsTable)
var name by TagsTable.name
var products by ProductEntity via ProductsTagsTable
}
一但要調整的部分變多,goravel 的這部分還是讓我比較難以接受。
這邊藉由介紹 Golang 的三個後端框架,來看 Kotlin 比較,並簡單地說出我認為各自的特點。
如果你比較熟悉 C 和 C++ 的語法,或者你已經很熟悉 Golang,那麼我覺得使用 Golang 作為後端開發沒有問題。
如果不是的話,那麼我還是會推薦使用 Laravel 或者 Ktor。
今天的部分就到這邊,我們明天見!