iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
Software Development

每天一點 Ktor 3.0:一個月學會 Kotlin 後端開發系列 第 14

Day 14:Ktor 和 Golang 進行後端開發的比較

  • 分享至 

  • xImage
  •  

昨天聊完了和 PHP Laravel 框架的比較

今天來聊聊我主觀對 Ktor 和 Golang 進行後端開發的比較

Kotlin vs 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 的設計著眼於程式設計的愉悅性、編譯速度、概念的正交性以及支援併發和垃圾回收等特性的需求。您最喜歡的特性可能缺失,因為它不適合,因為它影響了編譯速度或設計的清晰度,或者因為它會使基本系統模型過於複雜。

個人認為,這樣的設計方針,讓整體語法變得調理且簡化,但是也犧牲了很多可以讓程式碼更加簡潔的設計。

下面我們用幾個框架作為例子

gin

使用 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++ 的工程師,或許比較容易上手。但是面對撰寫物件導向程式語言習慣的工程師,個人覺得會有點負擔

gorm

再來,我們來看看 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

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。

今天的部分就到這邊,我們明天見!


上一篇
Day 13:Ktor 和 Laravel 寫法比較
系列文
每天一點 Ktor 3.0:一個月學會 Kotlin 後端開發14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言