Bir üretim işini kuyruğa almak, bitiş anı önceden bilinemeyen model çağrısını onu başlatan isteğin dışına çıkarıp çıktısını ayrı bir iş olarak üretmektir. Kuyruk kararı tek başına verilmiyor; çıktının yazılacağı yer ve işin bittiğini haber verecek yol aynı anda seçiliyor. Vipkurum soru kırpma aracında pahalı adım bir kez ödeniyor; kırpılan görsel kayda yazıldığı için aynı soru ikinci kez kırpılmıyor.
İşi isteğin dışına çıkardığınız anda tasarım sorusu da değişiyor. Artık “kullanıcı ne kadar bekler” diye sormuyorsunuz, “biten çıktı kullanıcıya nasıl ulaşır” diye soruyorsunuz.
Karakter bir görsel istediğinde iş ilk nereye düşer
İlk karar akışın ilk adımından önce veriliyor: üretim isteğinin iliştirileceği kalıcı bir kayıt var mı, yok mu. Secretum şu an inşa ettiğimiz karakter platformu ve orada kurduğumuz kurguda karakter, sohbet oturumuna değil hesaba bağlı kalıcı bir kayıt olarak duruyor. Kullanıcı karakterini bir kez tanımlıyor; karakter, o oturum kapandıktan sonra da hesabın altında yaşamaya devam ediyor.
Ayrım küçük görünüyor, sonucu değil. Karakter oturuma bağlı olsaydı, oturum kapandığı anda üretim isteğinin iliştirileceği kayıt da ortadan kalkardı. İş bittiğinde çıktıyı hangi kaydın içine koyacağını bilmeyen bir sistem, çıktıyı hiç üretmemiş gibi davranmak zorunda kalır. Karar bu yüzden akışın ilk adımından önce veriliyor. Sonradan eklenemiyor, çünkü kaydın nerede oluştuğunu değiştirmek yazılmış bütün kayıtları yeniden tanımlamak demek.
Kaydın biçimi de aynı sınıfta. Karakter kaydını doküman yapısında tutuyoruz; karakter yeni özellikler kazandıkça yapı esniyor ve her eklemede şemayı baştan kurmamız gerekmiyor. Üretim isteği ile onun çıktısı, bu kaydın üstüne binen yeni alanlar demek. Kayıt katı bir tabloya bağlı olsaydı, akışa eklenecek her yeni üretim tipi bir şema değişikliğine bağlanırdı.
Üçüncü karar ilk ikisinin üstüne oturuyor. İsteğin uygulamaya düşmesi ile üretimin kendisi ayrı iki şey olarak kurgulanıyor: kullanıcı düğmeye bastığında bir istek kaydı açılıyor, üretim ise o kayda bağlı ayrı bir iş olarak açılıyor. Bu ayrımı yapmayan bir kurguda istek ile üretim tek şeydir ve yanıt süresi zorunlu olarak üretim süresine eşitlenir. Ayrım koda değil akışa yazılıyor; üretim yavaş çıktığında araya sonradan sokulamıyor.
Üretim süresi anlık değilse akış nerede kesilir
İstek bir adrese düştükten sonra bedelin nerede oluştuğu görünür hâle geliyor. Görsel üretimi anlık bitmiyor ve kullanıcıyı üretim bitene kadar ekranda tutmak akışı kesiyor. Secretum’da çözmeye çalıştığımız sorunun kendisi bu.
Kesilen şeyin ne olduğuna dikkat etmek gerekiyor. Kesilen üretim değil, kullanıcının akıştaki hareketi. Ürünün kendisi bir akış: kullanıcı kendi karakterini kuruyor, karakter akışta paylaşım yapıyor, başkalarının karakterleri o akışta görünüyor. Bekleme ekranı, akışta ilerlemeyi tek bir gönderinin bitişine bağlıyor. Kullanıcı o sırada başka bir karaktere bakmak, başka bir gönderiyi okumak ya da yeni bir şey yazmak isteyebilir. Bunların hiçbiri bekleyen üretimle ilgili değil, ama hepsi onun bitmesini bekliyor.
Bedel bu yüzden genel bir “kullanıcı sıkılır” iddiası değil. Bu üründe akışın kendisi ürünün vaadi ve vaat, tek bir işin bitişi bütün adımların önkoşuluna dönüştüğü anda askıya alınıyor. Hedef, görsel kendi işinde üretilirken kullanıcıyı akışta bekletmeden ilerletmek; şu an inşa ettiğimiz kurgu bunun üzerine oturuyor.
Akla gelen ilk çözüm bekleme ekranını iyileştirmek oluyor. Göstergeye bir ilerleme çubuğu, tahmini bir süre ya da işin hangi aşamada olduğunu anlatan bir satır eklenir. Bu yol sorunu çözmüyor, çünkü hiçbiri kullanıcının önündeki adımı açmıyor. Daha iyi anlatılmış bir bekleme yine beklemedir; akışta ilerlemek isteyen kullanıcı hâlâ tek bir gönderinin bitişine bağlı. Ekranı daha bilgilendirici yapmak sorunu görünür kılıyor, ortadan kaldırmıyor.
Buna karşı en sık duyduğumuz itiraz modellerin hızlanacağı yönünde: birkaç sürüm sonra sorun kendiliğinden kalkar. Karar modelin ne kadar sürdüğüne bakmıyor, bitiş anının önceden beklenebilir olup olmamasına bakıyor. Ortalama süre düşse bile, bir işin ne zaman biteceğini söyleyemiyorsanız o işi isteğin içinde tutmak, ürünün en yavaş anını her kullanıcıya taahhüt etmek olur. Üstelik bu kurgu sonradan değiştirilebilir bir ayar değil. Kalıcı kayıt, çıktının yazıldığı yer ve biten işin duyurulma yolu birlikte kararlaştırılıyor.
Metin ile görsel aynı üretim yolundan geçmiyor
Bedeli gördükten sonra sıradaki soru hangi işin taşınacağı. Secretum’da metin ile görsel aynı üretim yolundan geçmiyor: kuyruğa alınan tek iş görsel üretimi, metin üretimi isteğin içinde kapanıyor.
Yolları ayıran ölçüt sağlayıcı adı değil. Hangi model hangi işi yapıyorsa yapsın, ölçüt işin bitiş anının önceden beklenebilir olup olmaması. Proje kaydında anlık bitmediği yazan tek iş görsel üretimi; ayrım oradan çıkıyor. Metin ve görsel taraflarında hangi arayüzlerin çalıştığını yapay zeka kararlarında insan denetimi yazısında yazdık; buradaki soru yığın değil akış.
Ölçütü kendi ürününüze uygulamak da mümkün. Özellik listesini tek tek okuyup her adım için aynı soruyu sorabilirsiniz: bu iş, onu başlatan isteğin içinde güvenilir biçimde kapanıyor mu. Cevap evetse kuyruk fazladan bir parça.
Kuyruk varsayılan bir tercih değil, ödenmesi gereken bir bedel. Kuyruğa alınan her iş beraberinde bir iş kaydı getiriyor: işin hangi aşamada olduğunu tutan bir durum, hata çıktığında ne yapılacağına dair bir karar ve çıktının kullanıcıya dönme yolu. Bunların hiçbiri bedava değil ve hepsi bakılacak yeni bir yüzey demek. Şu an inşa ettiğimiz kurguda metin üretiminin kuyruğa girmemesinin nedeni tam olarak bu. Bitiş anı isteğin içinde kapanabiliyorsa kuyruk sorunu çözmüyor, sisteme yeni parça ekliyor.
Bedelin en görünmez kalemi hata tarafı. İstek içinde kapanan bir üretim başarısız olduğunda kullanıcı bunu aynı adımda görüyor ve yeniden deneyebiliyor. Kuyruğa alınan bir iş başarısız olduğunda kullanıcı çoktan başka bir yere gitmiş oluyor; hatanın kime, nerede ve ne zaman gösterileceği ayrı bir karar hâline geliyor. Kuyruk kararını verirken bu sorunun da cevabı veriliyor. Cevap verilmezse başarısız iş sessizce kayboluyor ve kullanıcı istediği görselin neden hiç gelmediğini anlamıyor.
Kararın “model çağrısı geldiyse kuyruğa al” diye kurulmadığını gösteren şey de bu. Aynı üründe iki üretken iş var ve ikisi farklı yollardan geçiyor.
Üretilen dosya nereye yazılıyor, akış onu neden ikinci kez üretmiyor
İş isteğin dışına alındığı anda sıradaki soru çıktının nereye düştüğü oluyor. Kuyruğun ucundaki çıktıyı kalıcı bir dosya olarak yazıyoruz; hedef, akışta her görüntülemede aynı görseli yeniden üretmemek.
Bu karar kuyrukla birlikte alınıyor, sonrasında değil. Çıktı kalıcı değilse her bakış yeni bir kuyruk işi doğurur ve kuyruk sorunu çözmek yerine çoğaltır. Kullanıcıyı bir kez beklettiğiniz iş, akışı her açanın önünde yeniden beklemeye dönüşür.
Kalıcılığın ikinci yüzü paylaşılabilirlik. Karakterin ürettiği görseller hiçbir yerde durmuyorsa başkasına gösterilemiyor; sosyal bir akışta bu, üretimin kendisini anlamsız kılıyor. Geliştirmede olan kurguda üretilen görsel akışta paylaşılabiliyor, çünkü ortada gösterilebilecek yazılmış bir dosya duruyor.
Aynı desen yayında olan bir işte de var. Vipkurum soru kırpma aracında kırpılan görseller ve soru kayıtları veritabanında duruyor; kırpma her bakışta yeniden çalışmıyor. Pahalı iş bir kez yapılıyor ve çıktısı kayıt olarak tanımlanıyor. Aynı araçta cevap anahtarı da ayrı bir belge olmaktan çıkıp kırpılan soru kaydının içine yazılıyor. Çıktının nereye yazıldığı sorusunun ikinci yüzü bu: yalnız dosyanın nerede durduğu değil, hangi kaydın parçası hâline geldiği.
Kaydın içine yazılmanın ayrı bir kazancı var. Cevap anahtarı ayrı bir belgede dursaydı, sorunun kullanıldığı her yerde o belgeyi bulmak, doğru satırı eşleştirmek ve iki kaydın birbirinden ayrışmadığını ummak gerekirdi. Kaydın içine yazıldığında çıktı, ait olduğu sorunun gittiği her yere onunla birlikte gidiyor. Aynı ilke görsel tarafında da geçerli: kurduğumuz kurguda dosyanın bir yerde durması yetmiyor, hangi kayda ait olduğunun da belli olması gerekiyor.
| Adım | İşin çalıştığı yer | Çıktının yazıldığı yer | Kullanıcının o anda gördüğü |
|---|---|---|---|
| Karakterin metin üretmesi (Secretum, geliştiriliyor) | İsteğin içinde; ayrı bir işe alınmıyor | Karakterin hesaba bağlı kalıcı kaydı, biriken geçmişin içine | Yanıtı aynı adımda alıyor |
| Karakterin görsel üretmesi (Secretum, geliştiriliyor) | Sunucudaki iş kuyruğunda, istekten ayrı | Kalıcı dosya deposu | Akışta ilerlemeye devam ediyor; üretimin başında durmuyor (hedeflenen kurgu) |
| Üretilmiş görselin akışta ikinci kez görüntülenmesi | Hiçbir yerde; üretim tekrarlanmıyor | Dosya bir kez yazıldı, ikinci kez yazılmıyor | Yazılmış dosyayı görüyor, bekleme yok |
| Soru kırpma çıktısının kayda yazılması (Vipkurum, canlı) | Görüntü işleme servisinde, kırpma anında bir kez | Soru kaydı ve kırpılan görsel veritabanında; cevap anahtarı da aynı kaydın içinde | Havuzdaki hazır soruyu görüyor; kırpma yeniden çalışmıyor |
Üçüncü satır kararın asıl kazancını taşıyor: orada çalışan hiçbir iş yok. Pahalı adım bir kez ödendiğinde ikinci görüntüleme kuyruğa hiç uğramıyor.
Biten iş kullanıcıya hangi yoldan duyurulur
Tablonun son sütunu kendiliğinden dolmuyor. Kuyruğa alınan iş, bittiğini duyuracak bir yol zorunlu kılıyor ve o yol kuyruk kararıyla aynı anda kararlaştırılıyor.
Secretum’da bunun için sunucu tarafında tek bir canlı yayın katmanı kuruyoruz; hem web arayüzü hem telefon istemcisi aynı yayını dinliyor. İkinci bir yayın yolu yazmıyoruz. İki ayrı yol, aynı işin iki farklı “hazır oldu” anını üretir ve hangi istemcinin neyi ne zaman gördüğü kurgudan değil tesadüften çıkar. Web ile mobil aynı anda canlı güncelleme istiyor; tek yayın katmanı bu isteği tek yerden karşılıyor.
İki yolun neden ayrıştığını görmek için tek bir yeni özellik yeterli. Görselin yanına bir etiket ya da bir durum bilgisi eklendiğinde, iki ayrı yayın yolu olan bir sistemde bu bilgi iki yerde güncellenmek zorunda kalır. Biri güncellenip öteki unutulduğunda telefonu kullanan ile tarayıcıyı kullanan aynı gönderiyi farklı görür. Tek katman bu ihtimali baştan kapatıyor; yeni özellik tek yerde yazılıyor ve iki istemci de aynı bildirimi alıyor.
Adımın tamamı sırayla şöyle kurgulanıyor. İstek, hesaba bağlı kalıcı karakter kaydına iliştiriliyor. Üretim işi sunucudaki kuyruğa alınıyor ve isteği bekletmiyor. Çıktı kalıcı bir dosyaya yazılıyor. Yayın katmanı işin hazır olduğunu istemcilere bildiriyor. Hedeflenen sonuç, kullanıcının bu süre boyunca akışta kalabilmesi; sıradaki adımların hiçbiri onun ekranını rehin almıyor.
Sıralamada dikkat çeken şey, her adımın bir öncekinin bıraktığı boşluğu kapatması. Kalıcı kayıt olmasa isteğin adresi olmaz. Kuyruk olmasa istek üretim süresine bağlanır. Kalıcı dosya olmasa kuyruk her görüntülemede yeniden dolar. Yayın katmanı olmasa biten iş kimseye ulaşmaz. Dördü ayrı ayrı alınabilen kararlar gibi görünüyor; pratikte tek bir kararın dört yüzü.
Geriye bir boşluk kalıyor. Kullanıcı iş bittiğinde uygulamada değilse canlı yayın kimseye ulaşmıyor. O durumda gereken şey ekranı güncellemek değil, kullanıcıyı geri çağırmak.
Cihazdaki kuyruk ile sunucudaki kuyruk aynı sorunu çözmez
“Kuyruk” kelimesi iki farklı mekanizmayı birden taşıyor ve ikisi karıştırıldığında yanlış sonuç veriyor.
AlgoKlima’nın saha uygulamasında servis kaydı önce telefonun yerel kuyruğuna yazılıyor ve uygulama bağlantı beklemeden çalışmaya devam ediyor. Oradaki kuyruğun karşıladığı arıza bağlantının olmaması. Kuyruk cihazda duruyor, tetikleyicisi bağlantının dönmesi. Teknisyenin çalıştığı kazan dairesinde kapsama bitiyor; kayıt yine de yazılıyor. Kuyruğun hangi sırayla boşaldığı ve çakışan değişikliklerin nasıl çözüldüğü ayrı bir konu; onu çevrimdışı çalışan mobil uygulama yazısında anlatıyoruz.
Secretum için şu an inşa ettiğimiz kuyruk başka bir yerde duruyor: sunucuda. Tetikleyicisi bağlantı değil, işin bitmesi. İstek sunucuya ulaşıyor, kayıt sunucuda oluşuyor, iş orada bekliyor. İki kurgunun ayrıldığı yer kaydın nerede oluştuğu; birinde telefonda, ötekinde sunucuda.
Ayrım pratikte şuna yarıyor. Mobil tarafında zaten çevrimdışı kuyruğu olan bir ekip, üretim süresi sorununu çözdüğünü sanabiliyor. Çözmüş olmuyor. Cihazdaki kuyruk isteği sunucuya taşıyor, sunucudaki işin ne kadar süreceğine dair hiçbir şey söylemiyor.
Tersi de doğru ve aynı ölçüde önemli. Sorun bağlantıysa sunucudaki kuyruk işe yaramıyor; istek sunucuya hiç ulaşamadığı için kuyruğa girecek iş de doğmuyor. AlgoKlima’da kuyruğun telefonda olmasının nedeni bu. İki kuyruk aynı kelimeyi paylaşıyor, aynı arızayı çözmüyor: biri bağlantının döndüğü anı bekliyor, öteki işin bittiği anı.
Bildirim kullanıcıyı sonuca geri çağırıyor
Kullanıcı iş bittiğinde uygulamada değilse ne olacağı sorusunun cevabı Tahlil.com’da akışın kendisine yazılmış. Hasta tahlil değerlerini giriyor, ön okuma hazırlanıyor, hekim yorumu panelde yazıp onaylıyor. Akışın sonraki adımı bu onayla başlıyor.
Onayın iki yüzü var. Hastaya ulaşan metnin son sözünün neden hekimde kaldığını insan denetimi yazısında açtık; burada onay yalnız bir zaman işareti, sonraki adımı tetikleyen olay.
İki alternatif de eleniyor. Zamanlayıcı, işin ne zaman biteceğini bildiğinizi varsayar; bilmiyorsanız ya erken bakıp boş dönersiniz ya da geç bakıp kullanıcıyı hazır çıktının üstünde bekletirsiniz. Kullanıcının sayfayı tekrar tekrar açması ise bekleme yükünü ekrandan alıp kullanıcının aklına taşır. İkisi de aynı hatayı yapıyor: sonucun kullanıcıya ulaşmasını kullanıcının kendi çabasına bağlıyor. Olayla tetiklenen bildirim bu yükü sistemin tarafında bırakıyor.
Yorum onaylandığında push bildirimi hastayı sonuca geri çağırıyor. Hasta sonucun başında beklemiyor; işi bittiğinde çağrılıyor.
Geri çağırmanın bir yüzeye ihtiyacı var. Tahlil.com’da bildirimi alan taraf, aynı çekirdeğe bağlı hasta uygulaması ve o yüzey ürün kurulurken kararlaştırılmış. Üretim yavaş çıktığında sonradan eklenen bir parça değil. Böyle bir yüzey yoksa geriye kullanıcının kendi kendine dönmesini beklemek kalıyor. O zaman da sorun kuyrukta değil, çıktının kullanıcıya ulaşma yolunun hiç kurulmamış olmasında.
Karar sırası bu yüzden hep aynı. Hangi iş isteğin içinde kapanıyor, hangisi kendi işine alınıyor, çıktı nereye yazılıyor, biten iş kullanıcıya nasıl ulaşıyor. Dördü birbirine bağlı ve dördü de ürün kurulurken veriliyor. Kendi ürününüzde bu sıranın nerede kırıldığına birlikte bakabiliriz; yapay zeka danışmanlığı çalışmalarımız tam olarak bu ayrımı konuşmakla başlıyor.