Deno

Deno Nedir? Node.js‘in Yerini Alabilecek mi?

May 14, 2020

Deno v1.0.0 kararlı resmi sürümü, dün yani 13 Mayıs 2020 itibariyle yayınlandı. Peki Deno tam olarak nedir? Yazılım geliştirme süreçlerinde nasıl bir misyon üstlenecek? NodeJS’in yerini tamamen alabilecek mi? Hadi birlikte inceleyelim.

Deno, güneş gibi doğarken ardından tepelerin…

NodeJS’in de yaratıcısı olan Ryan Dahl, 2018 yılında Berlin’de düzenlenen JSConf EU sahnesinde bir konuşma ile yer almıştı. Konuşmasını NodeJS’te yanlış olduğunu düşündüğü en önemli 10 konu üzerine hazırlayan Ryannode_modules ve değişmesi mümkün olmayan legacy API’lar ile ilgili endişelerini dile getirmişti. NodeJS’in yayınlandığı günden bu yana JavaScript’in çok değiştiğine dikkat çekmişti. Tarayıcılar ve sunucu tarafıyla uyumlu olabilecek, güvenlikle ilgili tüm sorunların üstesinden gelebilecek daha iyi bir NodeJS yaratmanın mümkün olabileceğini anlatmıştı. Konuşmasının sonunda ise Deno isimli projesinden bahsetmişti.

Ryan’ın bu konuşmasının üstünden tam olarak 2 yıl geçti. Bu süre içerisinde projeye çok fazla geliştirici dahil oldu, GitHub’da Mayıs 2020 itibariyle 50k yıldız sayısı geçildi. Dün itibariyle de Deno ismi verilen proje, 1.0.0 versiyonu ile resmi olarak yayınlandı.

Javascript’in Gelişimi & Deno

JavaScript, 2009 yılında NodeJS için yararlı olabilecek bazı özelliklerden yoksundu. Bu özelliklerden bazıları bir kaç yıl içerisinde ECMAScript standartlarının birer parçası olarak JavaScript’e eklenirken, bazıları da TypeScript ile ele alınmıştı. Bu özelliklerden bazılarının üstünden geçelim.

JavaScript’te eventler ve callbackler her zaman var olsa da, işin içine async eylemleri birbirine bağlamak girdiği zaman kod oldukça karmaşık bir hal alabiliyordu. Promiseler, bu kodun karmaşıklığını kaldırarak daha okunaklı hale getirdi. Promisecallbackleri fonksiyona geçirmek yerine attach edebildiğimiz, async bir işlemin başarılı ya da başarısız sonuçlandığını döndüren bir objedir. Fonksiyonu async tanımlamak syntax’ı basitleştirirken, fonksiyon içerisinde await kullanılıp promise işlevini yerini getirinceye kadar (non-blocking şekilde) durulmasını sağlar.

NodeJS oluşturulduğunda, JavaScript modülleri için gayriresmi standart olarak CommonJS görülüyordu, ki CommonJS npm tarafından destekleniyordu. Sonrasında ECMAScript Komunitesi tarafından, ismi ES Modules olan resmi standartlar belirlendi. ES Modules, jspm ve Deno tarafından da destekleniyor.

Binary data işlemek için kullanılan bir ES6 API’ı olan Typed ArraysNodeJS tarafından desteklenmediği için tasarım açısından bazı problemlere yol açmıştı. Deno ise ham binary data işleme ihtiyacı olduğunda typed arrays kullanıyor.

TypeScript, düz JavaScript’e (ES3 veya üstü seçilebilir) derlenen JavaScript’in üst kümesidir. TypeScriptJavaScript’e isteğe bağlı türler, sınıflar ve modüller ekler, büyük ölçekli JavaScript uygulamaları için araçları destekler. (Anders Hejlsberg ‘in deyimiyle’ “ölçeklenen JavaScript”) Daha önce de belirtildiği gibi Deno, runtime’ın bir parçası olarak TypeScript derleyicisinin bir image’ını içerir. Bir TypeScript dosyasını Deno’ya iletirseniz, önce dosyayı JavaScript’e derler ve sonra bunu V8 motoruna geçirir.

Bahsettiklerimin yanlış anlaşılmasını istemem. Sonuçta NodeJS hem komunitesi hem de işlevi ile oldukça başarılı bir JavaScript runtime’ı. Ama Ryan’ın belirttiği gibi, hiç kimse bu platformun bu kadar kısa bir sürede ne kadar büyüyeceğini tahmin edemezdi. Ayrıca, 2009’da JavaScript hala herkesin eğlendiği tuhaf küçük bir dildi ve bahsetmiş olduğum gibi şimdiki özellilerin çoğu henüz yoktu.

Deno Nedir?

Detaylı şekilde bahsettiğimiz “Advanced JavaScript” olarak nitelendirebileceğimiz konular ve NodeJS’in yaşattığı bazı problemlere değindikten sonra, hep birlikte Deno’nun ne olduğuna doğru ilerleyebiliriz.

DenoGoogle’ın açık kaynaklı yüksek performanslı JavaScript motoru olan V8‘i kullanan; JavaScript ve TypeScript için basit, modern ve güvenli bir runtime’dır.

Deno;

  • Rust (Deno’nun çekirdeği Rust ile yazıldı. NodeJS ise C ++ ile yazılmıştı.)
  • Tokio (Rust ile yazılmış event loop)
  • V8 (Google’ın Chrome ve NodeJS ve diğer araçlarda da kullanılan JavaScript runtime’ı)

Kullanılarak oluşturulmuştur.

Deno özetle;

  • Varsayılan olarak güvenlidir. Açıkça etkinleştirilmedikçe dosya, ağ veya ortam erişimi yoktur.
  • Hali hazırda hem JavaScript’i hem de TypeScript’i destekler
  • Yalnızca tek bir executable dosya gönderir.
  • Bir bağımlılık denetçisi (deno info) ve bir kod formatlayıcı (deno fmt) gibi built-in yardımcı programlara sahiptir.
  • Deno ile çalışması garanti edilen bir dizi gözden geçirilmiş (denetlenmiş) standart modüle sahiptir: deno.land/std

Sonuçta hem NodeJS hem de Deno’yu tasarlayan Ryan’a göre, NodeJS üç önemli tasarım sorunundan muzdaripti:

  • Merkezi dağıtımı olan kötü tasarlanmış bir modül sistemi
  • Desteklenmesi gereken birçok eski API
  • Güvenlik eksikliği

Deno her üç sorunu da düzeltir.

Özellikler

Güvenlik

Deno’nun odaklandığı en önemli konulardan birisi kuşkusuz güvenlik sorunlarıydı. Bu nedenle DenoNodeJS’in aksine kodu varsayılan olarak Sandbox üstünde çalıştırır. Bu da runtime’ın aşağıdakilere erişimini kısıtlar;

  • Dosya Sistemi
  • Diğer komut dosyalarının çalıştırılması
  • Ortam değişkenleri

İzin sisteminin nasıl çalıştığına bir göz atalım.

(async () => {
const encoder = new TextEncoder();
const data = encoder.encode('Merhaba Dünya\n');

await Deno.writeFile('hello.txt', data);
await Deno.writeFile('hello2.txt', data);
})();

Komut dosyası, içinde “Merhaba Dünya” mesajı bulunan hello.txt ve hello2.txt adlı iki metin dosyası oluşturur. Kod bir sanal alan içinde yürütülür, bu nedenle dosya sistemine erişimi yoktur.

Ayrıca NodeJS’te yaptığımız gibi fs modülü yerine Deno namespace’ini kullanıyor olduğumuz da gözlerden kaçmasın. Deno namespace’i birçok temel yardımcı işlev sağlar.

Uygulamayı aşağıdaki gibi çalıştırdığımızda:

deno run write-hello.ts

Aşağıdakiler şekilde bir soru sorar:

⚠️Deno requests write access to "/Users/user/folder/hello.txt". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]

Sanal alandan gelen her çağrı için izin istenmesi gerektiğinden, aslında iki kez istenir. Tabii ki ilk soruya ‘Her zaman izin ver’ seçeneğini seçersek, bir daha sorulmayacaktı. deny seçeneğini seçersek ise, PermissionDenied hatası atılır ve hatayı işlemek için bir kodumuz olmadığından işlem sonlandırılır.

Komut dosyasını aşağıdaki komutla çalıştırırsak:

deno run --allow-write write-hello.ts

Bu, kodunuzun klasöre yazmasına izin verir ve bir güvenlik istisnasına sahip olursunuz, herhangi bir soru sorulmadan her iki dosya da oluşturulur. Bu, diğer platformların güvenliği nasıl ele aldığına benzer. Android kullanıcısıysanız, daha önce pek çok uygulama tarafından telefonunuzdaki farklı sistemlere (yani kişiler, telefon görüşmeleri, klasörler vb.) erişmelerine izin vermeniz istenmiştir. Burada da aynı konsept uygulanabilir. Erişim izni alınması gereken konularla ilgili flagleri, komut dosyanızı yürüten komut satırının bir parçası olarak kullanarak, kodunuzun gerektirdiği izinleri sağlarsınız.

Dosya sistemi için — allow-write işaretinin yanı sıra, ağ isteklerini etkinleştirmek, ortama erişmek ve alt işlemleri çalıştırmak için — allow-net— allow-env ve — allow-run flagleri de vardır.

Modüller

Deno, modülleri tıpkı tarayıcılar gibi URL’ler ile yükler. Çoğu kişi bu yöntemi ilk gördüğünde kafası karışmıştı ama bana kalırsa oldukça mantıklı.

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

Paketleri URL’ler ile import etmenin en önemli yanı nedir? Cevabı tahmin etmek çok da zor olmasa gerek. Deno paketleri, URL’ler ile npm’de oldukça fazla sorun yaratan merkeziyetçilikten(tamamı JSConf 2019’da anlatılmıştı) vazgeçerek dağıtık olarak kulllanılabilir.

Kodu URL yoluyla import ederek, paket oluşturucuların kodlarını uygun gördükleri her yerde barındırmasını mümkün kılıp; merkezin yokluğunun keyfini çıkarıyoruz. Müjde! Artık package.json ve node_modules yok.

Uygulamayı başlattığımızda, Deno içe aktarılan tüm modülleri indirir ve önbelleğe alır. Önbelleğe alındıktan sonra Deno, özellikle — reload flagiyle istenmedikçe, onları tekrar indirmeyecektir.

  • Bir web sitesi kapanırsa ne olur?

Merkezi kayıt olmadığından, modülü barındıran web sitesinin erişebilirliği önemlidir. Bu web sitesi birçok nedenden dolayı erişilemez olabilir. Bu da geliştirme sırasında, hatta daha da kötüsü üretim ortamında da bir risk barındırır.

Daha önce de belirttiğimiz gibi, Deno indirilen modülleri önbelleğe alır. Önbellek yerel diskimizde depolandığından, Deno’nun yaratıcıları sürüm kontrol sistemimizde (yani git) kontrol etmenizi ve repository’de tutulmasını önerir. Bu şekilde, web sitesi kapansa bile, tüm geliştiriciler indirilen sürüme erişebilir.

Deno, önbelleği $DENO_DIR ortam değişkeni altında belirtilen dizinde saklar. Değişkeni kendimiz ayarlamazsak, sistemin varsayılan önbellek dizinine ayarlanır. $DENO_DIR’i yerel depomuzda bir yere ayarlayabilir ve sürüm kontrol sistemine bakabiliriz.

  • URL ile her zaman import etmek zorunda mıyım?

Sizin de düşündüğünüz gibi, bence de URL’leri sürekli yazmak çok sıkıcı olurdu. Neyse ki, Deno bunu yapmamak için bize iki seçenek sunuyor.

İlk seçenek, içe aktarılan modülü aşağıdaki gibi yerel bir dosyadan yeniden dışa aktarmaktır:

export { test, assertEquals } from "https://deno.land/std/testing/mod.ts";

Diyelim ki yukarıdaki dosyaya local-test-utils.ts deniyor. Şimdi, ya test ya da assertEquals işlevlerinden tekrar yararlanmak istiyorsak, şu şekilde referans verebiliriz:

import { test, assertEquals } from './local-test-utils.ts';

Dolayısıyla, modülün bir URL’den yüklenip yüklenmediği önemli değildir.

İkinci seçenek ise, bir JSON dosyasında belirttiğimiz bir import map oluşturmaktır:

{
"imports": {
"http/": "https://deno.land/std/http/"
}
}

Ve sonra şu şekilde içe aktarabiliriz:

import { serve } from "http/server.ts";

Çalışması için, Deno’ya — importmap bayrağını ekleyerek import map’inden bahsetmeliyiz:

deno run --importmap=import_map.json hello_server.ts
  • Peki versiyonlama nasıl yönetilecek?

Versiyonlama, paket sağlayıcı tarafından desteklenmelidir, ancak istemci tarafından URL’deki sürüm numarasını şu şekilde ayarlamanız gerekir: https://unpkg.com/liltest@0.0.5/dist/liltest.js.

Uyumluluk

Deno, tarayıcı uyumlu olmayı hedefler. Teknik olarak, ES modüllerini kullanırken, uygulamamızı bir tarayıcıda kullanıma hazır hale getirmek için webpack gibi herhangi bir derleme aracı kullanmamız gerekmiyor.

Bununla birlikte, Babel gibi araçlar kodu JavaScript’in ES5 sürümüne aktararak ve sonuç olarak kod, dilin en yeni özelliklerini desteklemeyen eski tarayıcılarda bile çalıştıracak hale getirebilir. Ancak bu, son dosyaya çok fazla gereksiz kod ekleme ve çıktı dosyasını şişirme anlamına da geliyor.

Bu nedenle ana hedefimizin ne olduğuna karar vermek ve buna göre seçim yapmak gerekmektedir.

TypeScript Desteği

Bunu doğru okudunuz, eğer TypeScript fanıysanız, o zaman Deno sizin gönlünüzü fethedecektir. Çünkü TypeScript kullanmak için ekstra bir işleme gerek yok. Varsayılan olarak JavaScript’e çeviri dahili olarak yapılır, bu yüzden TypsScript’i nasıl kullanacağızla ilgili endişelenmenize de gerek yok.

Deno varsayılan hali hazırda ayar setine sahip olsa da, kendi tsconfig.json dosyanızı kullanarak ayarları kişiselleştirebilirsiniz:

deno run -c tsconfig.json [your-script.ts]

Dahası?

Deno’nun dahil ettiği; test runner, hata ayıklayıcı, dosya izleyici ve diğerleri gibi başka özellikleri de var. Fakat yine de, bunlardan bazıları sadece dil tarafından sağlanan API’lardır ve bunları kullanmak için kendi araçlarınızı kodlamanız gerekir.

Örneğin Nodemon’a benzer bir çözüm arıyorsanız, Deno.watchFs tarafından size sağlanan dosya izleme API’ını kullanarak kendiniz oluşturmanız gerekir. Benzer bir sorunu çözen 23 satırlı bir komut dosyası şöyle görünür:

Github’da konuyla ilgili bir repo bulunmakta. Detaylarını incelemek için tam kodu burada bulabilirsiniz.

Deno, yakında NodeJS’in yerini alabilecek mi?

Bazılarımız, v0.10 civarında olduğu günlerde NodeJS’i kullanmaya başladık ve production ortamında kullanıyorduk! Okuduğunuzda çılgınla geliyor olabilir, haklısınız. Ama inanın başka bir alternatifimiz yoktu. PHPPython ve hatta Ruby (Java veya .NET değil), JavaScript ve back-end’de async I/O modeliyle all-in-one bir çözümle karşılaştırılamazdı. Buna ek olarak, tüm bu yıllar boyunca, NodeJS (ve JavaScript) endüstrinin gereksinimlerini karşılamak için sürekli gelişti. Mükemmel konuma erişti mi? Tabii ki hayır! Ancak hayattaki her şey gibi, programlama dilleri de mükemmel değil.

Deno da farklı değil, çünkü şu anda, sadece bir fikir üzerinde yaklaşık 2 yıllık bir çalışmanın doruk noktası. Henüz production ortamlarında denenmedi ve test edilmedi. Sınır durumlarındaki davranışları gözlenmedi, garip ve normal koşullarda istenmeyen durumlara sokulmadı. Dolayısıyla bunlar gerçekleşene ve tecrübeler paylaşılana kadar, şimdi kullanmaya başlayanların oynayacağı bir oyuncak olacak. Şimdi sınırını koyamayacağınız bir süre içerisinde paylaşılan tecrübeler ile eksikleri tamamlanıp, yeni özellikleri eklendikten sonra alacağı komünite desteği ile belki de NodeJS’in tahtını sallayacak. Bu, belki de ileride gerçekten olacak. Kim bilir? Beklemek ve görmek zorundayız.

Peki siz ne düşünüyorsunuz?

— — — — — — — — — — — — — — —

Kaynaklar:

Author: Efecan Tekin

Tags

Backend Development Deno JavaScript Nodejs Typescript