講完了 Ktor 程式的撰寫、套件的使用、也講過了部署。
今天來講講為什麼我會選擇使用 Ktor,以及我主觀比較 Ktor 和其他後端開發框架的優缺點。
我第一個做網頁後端開發的語言是 PHP,目前 PHP 最知名且使用者最多的框架,非 Laravel 莫屬了。
即便是現在,我也依舊認為要快速的進入網頁開發的領域,使用 Laravel 是個很正確的選擇。
不管是撰寫之後立刻就能看結果,不需要再做編輯的流程
或者是非常易於使用的 ORM,舉個例子,這是 Laravel 宣告多對多關係時的程式寫法
// Product
public function tags()
{
return $this->belongsToMany(Tag::class);
}
// Tag
public function products()
{
return $this->belongsToMany(Product::class);
}
中介表可以不定義,預設是使用兩個類別的名稱相連接,也就是 product_tag
資料表
使用時的寫法大致是
foreach ($product->tags as $tag) {
// 針對商品標籤想做的事情
}
這麼簡單的用法,可以說在網頁開發裡面都很少見。
不過,這麼方便的框架,在處理併發事件時,由於 PHP 語言天生的限制,所以會使用進程(Process)進行處理
$pool = Process::pool(function (Pool $pool) {
$pool->path(__DIR__)->command('bash import-1.sh');
$pool->path(__DIR__)->command('bash import-2.sh');
$pool->path(__DIR__)->command('bash import-3.sh');
})->start(function (string $type, string $output, int $key) {
// ...
});
這在有些任務需要進行併發處理時,會消耗比較多的效能。
雖然有許多後端任務由於實際用量不大,不用太過在意效能,但是遇到狀況時就比較難以處理
這時候由於 Kotlin 搭配語言原生的 coroutine,就可以使用較少的效能,且寫法依舊不失簡潔的處理這種狀況
coroutineScope {
// Parallel requests
val firstRequest: Deferred<String> = async { client.get("http://localhost:8080/path1").bodyAsText() }
val secondRequest: Deferred<String> = async { client.get("http://localhost:8080/path2").bodyAsText() }
val firstRequestContent = firstRequest.await()
val secondRequestContent = secondRequest.await()
}
除去效能不提,作為一個需要編譯的語言與框架,加上 Ktor 的設計上是將自己定義為一個輕量化的框架,
使用 Ktor 開發一定會比使用 Laravel 多一些步驟
但是由於 Ktor 開發工程師的努力,以及其他套件的加入,所以開發上提升的難度,我認為是在可接受範圍內的
比方說前面所說的資料庫 ORM
Ktor 搭配 Exposed 框架的寫法如下,表會有對應的 object
,物件則有對應的 class
object ProductsTable : IntIdTable() {
val name = varchar("name", MAX_NAME_LENGTH)
}
class ProductEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<ProductEntity>(ProductsTable)
var name by ProductsTable.name
}
object TagsTable : IntIdTable() {
val name = varchar("name", MAX_NAME_LENGTH)
}
class TagEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<TagEntity>(TagsTable)
var name by TagsTable.name
}
多對多資料關係則使用 via
定義,並且要宣告中介表
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
}
可以看到確實是比較麻煩,但是我認為還在能接受的範圍裡面。
所以,如果今天有個需求是嘗試階段,或者已知流量不會很高,我會非常推薦使用 Laravel 進行開發。
如果今天需求流量已經開始逼近 5k QPS 甚至 10K QPS 了,那我就會推薦嘗試看看 Ktor。
今天的比較就到這邊,我們明天見!