V0 ve AI-first framework'ler: prompt'tan ürüne
Geçen ay bir dashboard prototipi için V0'a şu prompt'u yazdım: "A responsive analytics dashboard with a sidebar, a date range picker, and three KPI cards above a line chart." On saniye içinde çalışan bir React bileşeni döndü. Tailwind sınıfları düzgündü, shadcn/ui bileşenlerini doğru kullanıyordu, hatta Recharts entegrasyonu bile vardı. İlk izlenim etkileyici. Ama o kodu production branch'e merge etmem üç gün sürdü.
Bu yazı, V0 başta olmak üzere prompt'tan UI üreten araçların gerçekte neyi iyi yaptığını, nerede sessizce borç biriktirdiğini ve insan incelemesinin neden hâlâ darboğaz olduğunu anlatıyor.
"AI-first framework" ne demek?
Terim biraz şişirilmiş durumda. Bugün "AI-first" denen araçlar kabaca iki kategoride:
- Prompt-to-UI araçları: V0 (Vercel), Bolt.new, Lovable, Create.xyz. Doğal dilde tarif edilen arayüzü React/Svelte/Vue bileşeni olarak üretirler.
- AI-native çatılar: Cursor Tab, Windsurf gibi editör seviyesinde kod üretimi yapanlar. Bunlar framework değil, geliştirme ortamı. Ama "AI-first" şemsiyesi altında anılıyorlar.
Bu yazıda odak V0 ve benzeri prompt-to-UI araçlarında. Editör tabanlı AI asistanlarını ayrı bir yere koyuyorum; onlar mevcut kodu anlayıp tamamlıyor, sıfırdan UI üretmek yerine.
V0 neyi iyi yapıyor?
V0, shadcn/ui bileşen kütüphanesini ve Tailwind CSS'i baz alıyor. Bu teknik tercih, üretilen kodun tutarlılığını ciddi şekilde artırıyor. Rastgele class isimleri ya da inline style yerine, belirli bir design system'in token'larıyla çalışan çıktılar geliyor.
Şu prompt'u düşünün:
A settings page with a form: name (text input), email (text input),
notification preferences (switch), and a save button. Use card layout.V0'ın döndüğü kod şuna benzer:
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Button } from "@/components/ui/button";
export default function SettingsPage() {
return (
<Card className="max-w-lg mx-auto mt-8">
<CardHeader>
<CardTitle>Ayarlar</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-1">
<Label htmlFor="name">Ad</Label>
<Input id="name" placeholder="Adınız" />
</div>
<div className="space-y-1">
<Label htmlFor="email">E-posta</Label>
<Input id="email" type="email" placeholder="ornek@mail.com" />
</div>
<div className="flex items-center justify-between">
<Label htmlFor="notifications">Bildirimler</Label>
<Switch id="notifications" />
</div>
<Button className="w-full">Kaydet</Button>
</CardContent>
</Card>
);
}Bu kod çalışır. Erişilebilirlik açısından htmlFor ve id eşleşmeleri doğru. Tailwind sınıfları makul. Ama dikkat: burada state yok, form submission yok, validation yok. Gördüğünüz şey bir kabuk.
Prototip hızı gerçekten fark yaratıyor
V0'ın asıl değeri, bir fikri görselleştirme süresini dakikalara indirmesi. Tasarımcıya Figma mockup'ı göstermek yerine, çalışan bir React bileşeni gösterebiliyorsunuz. Bu, geri bildirim döngüsünü kısaltıyor. Müşteri toplantısında "şöyle bir sayfa olsa" dediğiniz anda üretip ekranda gösterebilmek, iletişim açısından değerli.
Ama prototip ile production arasındaki mesafe, V0'ın pazarlama sayfasında göründüğünden daha uzun.
Teknik borç nerede birikiyor?
State yönetimi yokluğu
V0'ın ürettiği bileşenler neredeyse her zaman stateless. Yukarıdaki form örneğinde "Kaydet" butonuna tıklamak hiçbir şey yapmıyor. Gerçek bir uygulamada React Hook Form ile Zod validation entegrasyonu, hata mesajları, loading state'i, optimistic update'ler gerekiyor. Bunların hiçbiri prompt'tan çıkmıyor.
Bu boşluğu elle doldurmak, bazen bileşeni sıfırdan yazmaktan daha uzun sürüyor. Çünkü V0'ın tercih ettiği DOM yapısı, sizin state yönetim yaklaşımınıza uymayabiliyor.
Bileşen parçalama kararları
V0, genellikle tek bir büyük bileşen döndürüyor. 200 satırlık monolitik bir JSX. Gerçek bir projede bunu 4-5 alt bileşene ayırmanız gerekir. Bu ayırma sırasında prop drilling kararları, context kullanımı, memoization ihtiyaçları devreye girer. V0 bu kararları sizin yerinize almıyor.
Erişilebilirlik yanılsaması
V0, label-input eşleşmeleri gibi temel erişilebilirlik kurallarını genelde doğru uyguluyor. Ama klavye navigasyonu, focus trap (modal'larda), screen reader announcement'ları, aria-live bölgeleri gibi konularda tutarsız. Üretilen kodun "erişilebilir görünmesi" ile gerçekten erişilebilir olması farklı şeyler. WCAG 2.2 AA uyumluluğu kontrol listesine göre V0 çıktılarını test ettiğimde, modal ve dropdown bileşenlerinde sık sık eksikler buldum. Özellikle Popover API ve dialog gibi native HTML çözümleri yerine custom implementasyonlar tercih ediliyor.
Tekrarlayan Tailwind sınıfları
V0 çıktılarında className="flex items-center justify-between gap-4 p-4" gibi uzun sınıf dizileri, benzer bileşenlerde tekrar tekrar yazılıyor. Proje büyüdükçe bu sınıf gruplarını bir yerde soyutlamanız gerekiyor, yoksa bir spacing değişikliği 40 dosyada arama-değiştir gerektiriyor.
Prompt mühendisliği ile kaliteyi artırabilir misiniz?
Kısmen evet. V0'a daha spesifik prompt vermek çıktı kalitesini artırıyor. Örneğin:
A multi-step form wizard with 3 steps. Step 1: personal info
(name, email with validation). Step 2: preferences (checkboxes).
Step 3: review and submit. Use react-hook-form for state management.
Include a progress bar showing current step.Bu prompt ile dönen kod gerçekten react-hook-form import ediyor ve temel useForm hook'unu kullanıyor. Ama validation şeması eksik, step geçişlerinde form verisi korunmuyor, error boundary yok.
Prompt ne kadar detaylı olursa olsun, V0 sizin projenizin context'ini bilmiyor. Hangi API endpoint'ine istek atacağınızı, auth state'ini nasıl yönettiğinizi, error handling konvansiyonlarınızı bilmesi mümkün değil. Bu bilgi, prompt'a sığmıyor.
Agentic coding yaklaşımlarında olduğu gibi, V0 da "plan, üret, incele" döngüsüne ihtiyaç duyuyor. Ama bu döngünün "incele" adımı tamamen insana kalıyor.
İnsan incelemesi neden darboğaz?
V0'ın ürettiği kodu review etmek, sıfırdan yazılmış kodu review etmekten farklı bir zihinsel yük taşıyor. Sıfırdan yazılan kodda, yazarın niyetini commit mesajından ve kod yapısından okuyabilirsiniz. V0 çıktısında niyet yok; sadece prompt var. Ve prompt çoğu zaman koda eşlik etmiyor.
Bir de "işe yarıyor gibi görünüyor" tuzağı var. V0 çıktısı genelde derlenir, render olur, görsel olarak doğru durur. Bu yüzden review sırasında "çalışıyorsa dokunma" refleksi devreye giriyor. Ama altında:
- Gereksiz re-render'lar olabilir. React Compiler bu problemin bir kısmını çözebilir ama V0 çıktılarında object referansları sık sık inline tanımlanıyor.
- Key prop'ları index bazlı olabiliyor.
- useEffect dependency array'leri eksik ya da fazla geniş olabiliyor.
Bunları yakalamak için V0 çıktısını satır satır okumak gerekiyor. Bu da "hızlı prototipleme" vaadini production aşamasında zayıflatıyor.
Gerçekçi bir iş akışı nasıl görünür?
V0'ı production'da kullanan takımlarda gördüğüm en sağlıklı model şu:
H3: Prototip aşaması (V0 burada)
Fikir doğrulama ve görsel keşif için V0 kullanılıyor. Üretilen kod, projeye doğrudan kopyalanmıyor. Bunun yerine "bu layout'u beğendik, bunu referans alarak yazalım" şeklinde bir input oluyor.
H3: Bileşen iskeleti olarak kullanım
Daha pratik bir yaklaşım: V0 çıktısını bir başlangıç noktası olarak alıp, state yönetimi, validation, API entegrasyonu gibi katmanları elle eklemek. Bu durumda V0'ın değeri, JSX yapısı ve Tailwind sınıflarının ilk taslağını vermesi. Hala zaman kazandırıyor ama "prompt'tan production'a" diye satılamayacak kadar fazla insan müdahalesi gerekiyor.
H3: Design system uyumu kontrolü
Eğer projenizde shadcn/ui kullanıyorsanız, V0 çıktıları zaten design system'inize yakın oluyor. Ama custom theme token'larınız, spacing scale'iniz ya da renk paletiniz farklıysa, her çıktıyı adapte etmeniz gerekiyor. Bu adaptasyon maliyeti, design system'in V0'ın varsayılanlarından ne kadar saptığıyla doğru orantılı.
Bolt.new, Lovable ve diğerleri
V0 sadece UI bileşeni üretiyor. Bolt.new ve Lovable gibi araçlar daha iddialı: tam bir uygulama üretmeye çalışıyorlar. Backend, veritabanı şeması, auth katmanı dahil.
Bu araçlarla bir hafta sonu projesi yapabilirsiniz. Ama production'a taşımak istediğinizde karşılaşacağınız sorunlar V0'dakinin katbekat fazlası: ORM seçimi sizin tercihiniz olmayabilir, auth implementasyonu güvenlik açıkları barındırabilir, veritabanı migration stratejisi olmayabilir.
Better Auth ya da Auth.js v5 gibi olgun kütüphanelerin doğru yapılandırılması, bir prompt'un çözeceği iş değil. Session yönetimi, CSRF koruması, token rotation gibi detaylar domain bilgisi gerektiriyor.
Ne zaman kullanmalı, ne zaman uzak durmalı?
V0, bir sayfanın görsel iskeletini hızla oluşturmak için iyi bir araç. Tasarım toplantılarında, kullanıcı testi için hızlı mockup'larda, hackathon'larda gerçek değer üretiyor.
Ama "V0 ile production-ready uygulama çıkarıyoruz" diyen bir takımda, birileri o kodu sessizce yeniden yazıyor demektir. Bu yeniden yazma maliyetini görünür kılmak, teknik lider olarak yapılacak en dürüst iş.
Prompt'tan production'a giden yol, bugün hâlâ bir insan köprüsünden geçiyor. O köprüyü kaldırmaya çalışmak yerine, kısa tutmaya çalışmak daha gerçekçi bir hedef.