2 puan yazan GN⁺ 2024-06-27 | 1 yorum | WhatsApp'ta paylaş
  • Triplit, sunucu ile tarayıcı arasında verileri gerçek zamanlı senkronize eden açık kaynaklı bir veritabanıdır; uygulamaya bir Typescript paketi olarak eklenen bir full-stack veritabanı yaklaşımını benimser
  • Sunucu depolaması ile istemci sorgu senkronizasyonunu birlikte ele alır; artımlı güncellemeler, özellik düzeyinde çakışma çözümü, yerel önbellekleme, çevrimdışı mod ve otomatik yeniden bağlanmayı destekler
  • SQLite, IndexedDB, LevelDB ve Memory gibi takılabilir depolama seçeneklerini destekler; sunucu tarafı kalıcı depolama ve yönetim paneli sunar
  • React ve vanilla Javascript içinde sorgu/değişiklik API'leri kullanılabilir; React, Svelte binding'leri, CLI, Console ve Server'dan oluşan bir monorepo olarak sunulur
  • Hızlı etkileşim için iyimser güncellemeler, başarısız güncellemeler için geri alma/yeniden deneme, sunucuda zorunlu kılınan okuma-yazma izinleri ve CRDT tabanlı iş birliği özellikleri de sağlar

Triplit'in sundukları

  • Triplit, sunucu ile tarayıcı arasında verileri gerçek zamanlı senkronize eden açık kaynaklı bir veritabanıdır
  • Uygulamaya Typescript paketi olarak eklenebilen bir senkronize veri deposu sunar
  • Verileri sunucuda saklar ve istemcinin sorgularını akıllıca senkronize eder
  • Triplit bu yapıyı full-stack veritabanı olarak adlandırır
    • Local First topluluğu için yapılmış sunum videosu da vardır: presentation

Temel özellikler

  • Gerçek zamanlı senkronizasyon

    • Artımlı güncellemeleri destekler
    • Özellik düzeyinde çakışma çözümü sunar
  • Yerel öncelikli kullanım deneyimi

    • Tam istemci tarafı veritabanı tabanlı yerel önbellekleme sunar
    • İyimser güncellemeler sayesinde tüm etkileşimlerin hızlı hissedilmesini sağlar
    • Çevrimdışı mod, otomatik yeniden bağlanma ve tutarlılık garantisini destekler
  • Sunucu depolaması ve operasyon

    • Sunucu tarafı kalıcı depolama sunar
    • Bir yönetim paneli içerir
    • SQLite, IndexedDB, LevelDB ve Memory gibi takılabilir depolama sağlayıcılarını destekler
  • Veri modeli ve API

    • Karmaşık veri modelleri için ilişkisel sorguları destekler
    • Şema üzerinden veri güvenliği ve Typescript otomatik tamamlama sağlar
    • vanilla Javascript ve React içinde sorgu/değişiklik için basit API sunar
  • İş birliği ve güvenlik

    • Sunucuda hem okuma hem yazma için izinleri zorunlu kılar
    • CRDTs tabanlı iş birliği/çok oyunculu özellikler sunar
    • Delta patch kullanarak ağ trafiğini azaltır ve düşük gecikmeyi hedefler
    • Başarısız güncellemeler için geri alma ve yeniden denemeleri yönetir

Monorepo yapısı

  • TriplitDB: Tarayıcı, Node, Deno, React Native gibi JS ortamlarında çalışacak şekilde tasarlanmış; ağ üzerindeki çoklu yazarı ve tutarlılığı korurken hızlı ve canlı güncellenen sorgular sunan veritabanı
  • Client: Yerel ve uzak TriplitDB ile etkileşime giren tarayıcı kütüphanesi
  • CLI: Proje iskeleti oluşturma, full-stack geliştirme ortamını çalıştırma, sunucu migration'ları gibi işler için komut satırı aracı
  • React: @triplit/client için React binding'i
  • Svelte: @triplit/client için Svelte binding'i
  • Console: Triplit proje verilerini görüntüleme ve değiştirme, ayrıca şema yönetimi için uygulama
  • Server: Triplit istemcileri arasında verileri senkronize eden Node sunucusu
  • Server-core: Triplit sunucusu oluşturmak için protokolden bağımsız kütüphane
  • Docs: Nextra ile hazırlanmış Triplit dokümantasyonu
  • Types: Triplit projelerinin paylaştığı tipler
  • UI: shadcn tabanlı paylaşımlı UI bileşenleri

Hızlı başlangıç akışı

  • Yeni bir proje npm create triplit-app@latest my-app ile başlar
  • Mevcut bir projede önce @triplit/cli geliştirme bağımlılığı olarak kurulur, ardından npm run triplit init çalıştırılır
  • my-app/triplit/schema.ts içinde şema tanımlanır
    • Örnekte todos koleksiyonunda id, text, completed alanları tanımlanır
    • completed, varsayılan değeri false olan bir Boolean alanı olarak ayarlanır
  • npm run triplit dev ile geliştirme amaçlı senkronizasyon sunucusu başlatılır
  • Geliştirme sunucusu, uygulamanın sunucuyla senkronize olması için gereken ortam değişkenlerini çıktılar
    • Vite örneğinde VITE_TRIPLIT_SERVER_URL=http://localhost:6543
    • VITE_TRIPLIT_TOKEN=copied-in-from-triplit-dev

React kullanım örneği ve senkronizasyonu doğrulama

  • React örneğinde TriplitClient ve useQuery kullanılır
  • İstemci; şema, sunucu URL'si ve token alarak oluşturulur
  • useQuery(client.query('todos')) ile todos sorgu sonuçlarına abone olunur
  • Checkbox değiştiğinde client.update ile completed değeri tersine çevrilir
  • Uygulama başlatıldıktan sonra başka bir tarayıcı sekmesi açılarak verilerin gerçek zamanlı senkronize olduğu görülebilir

Dokümantasyon ve iletişim kanalları

1 yorum

 
GN⁺ 2024-06-27
Hacker News görüşleri
  • Triplit’i https://github.com/thanhnguyen2187/cryptaa projesinde kullandım ve beklendiği gibi çalıştı
    Veri modeli, tek bir merkezi DB’yi doğruluğun kaynağı yapmak yerine daha dağıtık/P2P’ye yakın bir tasarımla iyi örtüşüyor, ancak self-hosting ve sorgu dili tarafı biraz zayıf
    Sunucu kimlik doğrulama token’ının nasıl oluşturulacağı dokümanda net değildi; ben de CLI’nin dev komutuyla token oluşturdum. Sistem servisinde token’ın düz metin loglara düşmesi güvenlik açısından iyi değil, ama bunun zaten daha büyük bir erişim yetkisi sorunu varsaydığını düşünüyorum
    Özel sorgu DSL’i, SQL’deki UNIQUE, COUNT gibi ifadelerin gücüne sahip değil; bu yüzden bazı agregasyonları elle yapmak gerekiyor
    Kısa süre önce Evolu’ya baktım https://www.evolu.dev/docs; kapsam ve özellikler açısından benzer görünüyor. Triplit’te .subscribe() var, Evolu’da yok; Evolu, Kysely tabanlı type-safe SQL kullandığı için sorguları daha tanıdık ve gelişmiş görünüyor. Tarayıcıda Evolu, OPFS üzerinde SQLite kullanırken Triplit sanırım IndexedDB kullanıyor
    Reddit’e yazdığım gönderi: https://www.reddit.com/r/sveltejs/comments/1dndpj8/cryptaa_a...

    • Self-hosting dokümanlarını yapılandırma daha net olacak şekilde düzenliyoruz; işaret ettiğin noktalar faydalı oldu
      Sorgu tarafında henüz agregasyon yok ama yol haritasında var; ayrıca artımlı sorgu motoru kullanılırsa çok ilginç bir yöne gidilebileceğini düşünüyorum
      Örneğin saat başı güncellenen bir veri panosunda, mevcut sistemlerde (Postgres, MongoDB vb.) sorgunun her seferinde baştan çalıştırılması gerekir; ama Materialize’a benzer bir yaklaşımla yalnızca yeni veriyi işlerseniz çok daha verimli biçimde sürekli güncel kalabilir
      Evolu’yu henüz kendim denemedim, ama Discord’da karşılaştırmış biri olabilir: https://triplit.dev/discord
    • Evolu’yu paylaştığın için teşekkürler; Triplit ve Evolu ikisi de ilginç görünüyor, bu ikisinin karşılaştırmasını görmek isterim
    • Evolu da useQuery veya ayrı bir yaklaşımla subscribe desteği sunuyor
  • Böyle harika bir çevrimdışı senkronizasyon protokolü olan bir DB kullanırken, farklı istemci sürümlerini aynı anda yükseltemediğiniz durumlarda şema evriminin nasıl ele alındığını merak ediyorum
    Daha önce bir mobil sağlık uygulamasında bu yüzden çok uğraşmıştım

    • Yeni tablolar oluşturup mevcut tablolarda geriye dönük uyumluluğu bozan değişiklikler yapmamak en iyisi
      Gerekirse bir süre iki sürüme aynı anda yazan dual-write yapılır
      Bu, SQL DB’de uyumluluğu bozan değişiklikleri kesinti olmadan canlıya taşımaya benziyor; ama geçiş zamanı müşteriye bağlı olduğu için bu mantığı daha uzun süre korumak gerekiyor
      En güncel sürümü koordine eden bir tablo da önemli; kırıcı bir değişiklik varsa geride kalan istemcinin kullanıcıdan yükseltme yapmasını istemesi gerekir
      Ayrıca tüm istemcilerin desteklediği minimum sürüme göre dual-read/write ne kadar süre tutulacağına da karar verilebilir
    • Kısaca söylemek gerekirse, şemada geri uyumluluğu korumak uyumluluğu sağlamanın en kolay yolu
      Triplit, geriye uyumlu olmayan bir değişiklik yaptığınızda uyarı veriyor; bunu dokümanda görebilirsiniz: https://www.triplit.dev/docs/schemas/updating#pushing-the-sc...
      Yine de zamanla adı kafa karıştıran çok sayıda alan içeren dağınık şema tanımları doğal olarak oluşabiliyor
      Bunu düzeltmeye yönelik bir çözüm henüz yayımlamadık, ama süreci daha az acı verici hale getirecek birkaç şey üzerinde çalışıyoruz. Farklı yaklaşımların arka planı için Cambria dokümanı çok iyi: https://www.inkandswitch.com/cambria/
    • Bazı istemcilerin, örneğin sunucunun, çok eski şemalarla bile senkronize olabilmesi gerektiğini düşünüyorum
      Sonuçta bir kullanıcı telefonunu iki yıl boyunca çekmecede tutmuş olabilir; bu yüzden her istemci mümkün olan en kısa sürede kendini migrate etse yeterli
    • Geçmiş migration’ları tanımlayıp destekleyen yerleşik bir yöntem olsa öldürücü bir özellik olurdu
      Böylece herkesin migration yönetimi için sıfırdan kendi çözümünü kurması gerekmezdi
  • İstemcinin DB’ye doğrudan yazabilmesinin hangi uygulamalarda makul olduğunu ve backend mantığı olmadan bunun nasıl ayakta kalabildiğini pek anlayamıyorum
    Supabase ve Firestore için de aynı soruyu düşünüyorum; sanki bir şeyi kaçırıyorum

    • Gerçek dünyada yapılan şeylerin çoğunda iş mantığı neredeyse yoktur; daha çok düz CRUD’a yakındır
      Kurumsal tarafta ise durum elbette tersidir; bunu yok sayan tartışmaları görünce insanın canı sıkılıyor
      Özellikle teknoloji Twitter’ında belirli bir stack’i ya da çalışma biçimini savunan paylaşımlarda, insanların iş sistemleri hiç kurmadan sadece CRUD uygulamaları yaptıkları o kadar belli oluyor ki; bu yüzden deneyimli geliştiricilerin neden katılmadığını anlayamıyorlar
    • Firebase ile işbirlikçi bir uygulama yaptım; herkesin kendi yorumu veya kartı üzerinde yapabileceklerini sıkı şekilde sınırlayıp yalnızca belirli işlemlere izin verirseniz idare ediyor
      Ama yoğun backend mantığı olan şeyler için pek uygun görünmüyor
    • Her ikisinde de backend tarafında zorlanan erişim kontrolü var; yani ortada tamamen backend’siz bir mantık yok
      Örneğin Supabase’te satır düzeyi güvenlik diye bir özellik var
      İstemci Supabase’e istek gönderebilir, ancak Supabase backend’de ek sorgular çalıştırarak gelen isteğin izinli olup olmadığını değerlendirir
      Basit bir örnek olarak, yalnızca UserID sütununun değeri isteği yapan kimliği doğrulanmış kullanıcıyla aynıysa o satırın okunmasına, yazılmasına ve güncellenmesine izin verebilirsiniz
  • Kullanıcı ayarlarını Triplit'te saklıyorlardı ve bu ayarların yöneticiler tarafından yönetilebilmesi gerekiyordu
    Kullanıcının uygulama her zaman yerelde çalışıyormuş gibi hissetmesi gerekiyordu ve internet kalitesi de sık sık iyi olmuyordu; ancak kullanıcılar birden fazla cihaz arasında geçiş yaparak kullanıyor ve yöneticilerin diğer kullanıcıların ayarlarını görüp yönetmesi gerekiyordu, bu yüzden senkronizasyon gerekliydi
    Genel olarak Triplit'in hem frontend geliştirici deneyimi hem de sunduğu destek harikaydı; issue ya da özellik isteği açıldığında ekip bunları çok hızlı ele alıyordu
    Yüksek erişilebilirlikli dağıtım konusunda bir yanıt ortaya çıkarsa, Postgres yerine daha kritik verileri de taşımayı planlıyorlar

  • Neden AGPL lisansını seçtiklerini merak ediyorum

    • Triplit'i AGPL lisansıyla kolayca self-host edilebilir kılmak isterken, değiştiren kişilerin bu değişiklikleri topluluğa geri katkı olarak sunmasını da güvenceye almak istemişler
    • Kullandığım veritabanı yüzünden ürünümü de AGPL yapmak zorunda kalacaksam bundan kaçınmak isterim
  • Local First Discord sunucusu https://localfirstweb.dev/ üzerinden YouTube sunumunu https://www.youtube.com/playlist?list=PLTbD2QA-VMnXFsLbuPGz1... görmüş gibiyim; Show HN'de karşıma çıkması sevindirici
    TypeScript kullanmadığım için ana hedef kitlesi olmayabilirim ve web'den farklı olarak bağlantının kararsız olduğu mobil uygulamalarda çoğunlukla local-first kullanıyor, Flutter ve Rust backend kullanıyorum
    ElectricSQL ve PowerSync gibi diğer local-first çözümleri istemci ve sunucu veritabanlarını doğrudan senkronize ettiği için istemci/sunucudan daha bağımsız
    CRDT tabanlı çözümler de FFI ile istemci ve sunucuda kullanılabiliyor; örneğin automerge Rust olduğu için Flutter tarafında flutter_rust_bridge üzerinden FFI ile, web'de WASM ile, backend'de ise Rust olarak kullanılabiliyor
    Triplit, farklı istemciler arasındaki çatışmasız çözümden ziyade sunucuyu doğruluğun kaynağı yapan daha klasik bir istemci-sunucu senkronizasyonu gibi görünüyor
    Neden istemci ve sunucudan daha bağımsız bir veritabanı katmanı yaklaşımı yerine dil düzeyinde bir çözüm seçtiklerini merak ediyorum; ayrıca gelecekte JS tabanlı olmayan diller ve framework'leri desteklemenin zor göründüğünü düşünüyorum
    Ayrıca Supabase ile rekabet etmeye çalışıyor gibi görünüyorlar; Supabase de Postgres'in veritabanı düzeyindeki senkronizasyonu ve CRDT üzerinde deneyler yapıyor, bu yüzden https://news.ycombinator.com/item?id=33931971 yakalayıp geçebilir gibi görünüyor

    • Flutter ve diğer native destekler hakkında çok düşündük; özellikle de Flutter sık sık gündeme geliyor
      Ancak başlangıçta saf TypeScript'e odaklanmaya karar verdik; pazarın yeterince büyük olduğunu ve PWA'nın geleceğine inandığımızı düşünüyoruz, ayrıca en iyi deneyimi yaratmak için buna odaklanmamız gerektiğine inanıyoruz
      Bir gün daha platformdan bağımsız bir şey inşa edeceğimizi düşünüyorum ama bunun zamanı net değil
      ElectricSQL ve Supabase ekiplerinin ikisi de son derece iyi ve düşünceli; SQL alanında büyümeye devam edecekler gibi görünüyor, yaklaşımın en temel farkı da burada
      Triplit, SQL'den kaçınarak geliştiriciye en iyi deneyimi sunabileceğini düşünüyor ve bu iki felsefenin bir arada var olması için fazlasıyla alan var
  • LWW ise, istemci tarafındaki bilgi miktarının işlem sayısıyla doğrusal biçimde artıp artmadığını merak ediyorum
    Yani kullanıcı veritabanını daha çok değiştirdikçe işlem günlüğü sürekli büyüyor mu, yoksa checkpoint alınıyor mu; kullanıcı günde yüz binlerce hatta milyonlarca işlem yaptığında alan açısından nasıl ölçekleniyor?

    • Triplit, belirli özelliklerin değişiklik geçmişini saklıyor ancak en güncel değer indeksi sayesinde sorgular hızlı kalıyor
      Yine de LWW register'ın kendisi geçmiş saklamayı zorunlu kılmıyor; bu, uzun süre çevrimdışı kalan istemcilerin de verimli biçimde senkronize olabilmesini sağlamak için mevcut uygulamanın bir tercihi
      Günde bir milyon işleme gerçekten ulaştığımızı söylemek için henüz erken olabilir ama sunucunun otorite olması bir avantaj sağlıyor
      Gelecekte Triplit sunucusu her istemcinin son senkronizasyon zaman damgasını takip edebilir ve Postgres'in ölü tuple'ları VACUUM ile temizlemesine benzer şekilde geçmişi kademeli olarak budayabilir
  • Tauri'de kullanılabilmesi için Rust binding'leri olsa iyi olurdu
    Tauri'nin büyümesi, yakında gelecek mobil cihaz desteği ve son dönemde SQLite'ın popülerliği birleşince, offline-first uygulamalardaki boşluğu kapatabilir ve birçok geliştirme ekibi için varsayılan tercih haline gelebilir

    • Benzer bir senkronizasyon çözümü olan ElectricSQL'e Rust binding'leri eklemeyi planlıyorum
      ElectricSQL veritabanı katmanında çalıştığı için dilden bağımsız ve sunucuda Rust kullanıyor; bu nedenle Rust binding'leri hem istemci hem de sunucu tarafında çalışabilir
      Birlikte geliştirmek istersen haber vermen iyi olur
    • Tauri native web renderer kullanmıyor mu?
      Öyleyse Triplit'in doğrudan çalışması gerekir gibi görünüyor
  • Bir süredir React Native uygulamamda Triplit kullanıyorum ve çok iyi çalışıyor
    Kesinlikle tavsiye ederim; benim için gerekli tüm koşulları karşılayan tek local-first DB oldu
    Uygun ve mantıklı bir sorgu dili (SQL değil), mükemmel TypeScript desteği, offline destek, React Native desteği var; ayrıca açık kaynak ve self-host edilebilir olması da çok iyi

  • Mevcut bir PostgreSQL DB ile birlikte kullanmak mümkün değil mi diye merak ediyorum

    • Şu anda değil, ancak Postgres'in replikasyon protokolünü ve WAL2JSON'u kullanarak çift yönlü senkronizasyon yapan dahili bir aracımız var
      Henüz kamuya açmaya tam hazır değil ama yakında insanların deneyebilmesini sağlamayı hedefliyoruz
    • Mevcut Postgres ile çalışan ElectricSQL'e bakmak iyi olabilir
      Ben de onu kullanmaya daha çok yaklaşıyorum