Prototipleri aşamalı bir planla modüllere dönüştürün: her değişikliği küçük, test edilebilir ve geri alınabilir tutun; rotalar, servisler, DB ve UI boyunca.

Bir prototip hızlı hisseder çünkü her şey birbirine yakın durur. Bir rota veritabanına gider, cevabı şekillendirir ve UI bunu render eder. Bu hız gerçek, ama bir maliyeti saklar: daha fazla özellik eklendiğinde ilk “hızlı yol” herkesin bağımlı olduğu yol haline gelir.
İlk bozulan genellikle yeni kod değildir. Eski varsayımlar bozulur.
Bir rotada yapılan küçük bir değişiklik sessizce cevap şeklini değiştirebilir ve iki ekranı bozabilir. Üç yere kopyalanmış “geçici” bir sorgu hafifçe farklı veriler döndürmeye başlar ve hangi versiyonun doğru olduğu kimse tarafından bilinmez.
Bu aynı zamanda büyük yeniden yazımların iyi niyetle bile başarısız olmasının nedenidir. Yapıyı ve davranışı aynı anda değiştirirler. Hatalar ortaya çıktığında, sebebin yeni bir tasarım tercihi mi yoksa temel bir yanlış mı olduğunu ayırt edemezsiniz. Güven azalır, kapsam büyür ve yeniden yazım sürer gider.
Düşük riskli refaktör, değişiklikleri küçük ve geri alınabilir tutmak demektir. Herhangi bir adımın sonunda durabilmeli ve hâlâ çalışan bir uygulamanız olmalı. Pratik kurallar basittir:
Rotalar, servisler, veritabanı erişimi ve UI, her katman diğerlerinin işini yapmaya başladığında karışır. Çözme işi “mükemmel mimari” peşinden koşmak değil; bir seferde bir ipliği taşımaktır.
Refaktörü bir tadilat değil bir taşınma gibi ele alın. Davranışı aynı tutun ve yapıyı ileride değiştirmeyi kolaylaştırın. Yeniden düzenlerken özellikleri de “iyileştirirseniz”, neyin neden bozulduğunu takip edemezsiniz.
Henüz değişmeyecek şeyleri yazın. Yaygın “henüz değil” maddeleri: yeni özellikler, UI yeniden tasarımı, veritabanı şema değişiklikleri ve performans çalışmaları. Bu sınır işi düşük riskli tutar.
Bir “ana akış” kullanıcı akışı seçin ve onu koruyun. İnsanların günlük yaptığı şeylerden birini seçin, örneğin:
sign in -> create item -> view list -> edit item -> save
Bu akışı her küçük adım sonrası yeniden çalıştıracaksınız. Aynı davranıyorsa devam edebilirsiniz.
İlk commit'ten önce geri alma yönteminde anlaşın. Geri alma sıkıcı olmalı: bir git revert, kısa ömürlü bir feature flag veya geri yükleyebileceğiniz bir platform snapshot'u. Eğer Koder.ai üzerinde çalışıyorsanız, snapshot'lar ve rollback, yeniden düzenlerken yararlı bir güven ağı olabilir.
Her aşama için küçük bir “tamamlanma” tanımı tutun. Büyük bir kontrol listesine ihtiyacınız yok, sadece “taşı + değiştir”in sızmasını önleyecek kadar:
Eğer prototipte rotaları, veritabanı sorgularını ve UI formatlamasını tek bir dosya yönetiyorsa, her şeyi birden bölmeyin. Önce yalnızca rota handler'larını bir klasöre taşıyın ve mantığı aynı tutun, hatta kopyala-yapıştır olsa bile. Bu stabil olduktan sonra servisleri ve DB erişimini sonraki aşamalarda çıkarın.
Başlamadan önce bugün var olanı haritalayın. Bu bir yeniden tasarım değil. Küçük, geri alınabilir hamleler yapabilmeniz için bir güvenlik adımıdır.
Her rotayı veya endpoint'i listeleyin ve ne yaptığını bir cümleyle yazın. UI rotalarını (sayfalar) ve API rotalarını (handler'lar) dahil edin. Eğer sohbet tabanlı bir jeneratör kullandıysanız ve kodu dışa aktardıysanız, aynı şekilde ele alın: envanter, kullanıcıların gördüğüyle kodun dokunduğu şeylerin eşleşmeli.
Faydalı, hafif bir envanter:
Her rota için kısa bir “veri yolu” notu yazın:
UI event -> handler -> logic -> DB query -> response -> UI update
İlerlerken, temizlerken yanlışlıkla değiştirmemek için riskli alanları etiketleyin:
Son olarak, basit bir hedef modül haritası çizin. Yüzeysel tutun. Hedefleri seçiyorsunuz, yeni bir sistem kurmuyorsunuz:
routes/handlers, services, db (queries/repositories), ui (screens/components)
Bir kod parçasının nerede yaşaması gerektiğini açıklayamıyorsanız, o alan daha sonra refaktör için iyi bir adaydır; daha fazla test veya ürün cevabı bekleyin.
Rotaları (veya controller'ları) bir sınır olarak ele alarak başlayın, iyileştirme yapılacak yer olarak değil. Hedef, her isteğin aynı davranması iken endpoint'leri öngörülebilir yerlere koymaktır.
Her özellik alanı için users, orders veya billing gibi ince bir modül oluşturun. "Taşırken temizleme" yapmayın. Aynı commit içinde isim değiştiriyor, dosyaları yeniden düzenliyor ve mantığı yeniden yazıyorsanız neyin bozulduğunu tespit etmek zorlaşır.
Güvenli bir sıra:
Somut örnek: Tek bir dosyada JSON parse eden, alanları kontrol eden, toplamları hesaplayan, veritabanına yazan ve yeni siparişi döndüren POST /orders varsa, bunu yeniden yazmayın. Handler'ı orders/routes içine çıkarın ve eski mantığı çağırın, örneğin createOrderLegacy(req). Yeni rota modülü ön kapı olur; legacy mantık şimdilik dokunulmadan kalır.
Eğer üretilmiş bir backend ile çalışıyorsanız (örneğin Koder.ai tarafından üretilmiş bir Go backend), zihniyet değişmez. Her endpoint'i öngörülebilir bir yere koyun, legacy mantığı sarın ve yaygın isteğin hala başarılı olduğunu kanıtlayın.
Rotalar iş kuralları için iyi bir ev değildir. Hızla büyürler, endişeleri karıştırırlar ve her değişiklik riskli hissedilir çünkü her şeyi aynı anda dokunursunuz.
Kullanıcıya yönelik her eylem için bir servis fonksiyonu tanımlayın. Bir rota girdileri toplamalı, bir servisi çağırmalı ve bir cevap döndürmeli. Veritabanı çağrılarını, fiyat kurallarını ve izin kontrollerini rotalarda tutmayın.
Servis fonksiyonları bir işi yaptıklarında, net girdilere ve çıktılara sahip olduklarında daha kolay anlaşılır. "Ve ayrıca..." eklemeye devam ediyorsanız bölün.
Genellikle işe yarayan bir adlandırma deseni:
CreateOrder(input) -> orderCancelOrder(orderId, actor) -> resultGetOrderSummary(orderId) -> summaryKuralları servislere koyun, UI değil. Örneğin: UI'nin bir düğmeyi "premium kullanıcılar 10 sipariş oluşturabilir" gibi bir kurala göre devre dışı bırakması yerine, bu kuralı serviste zorlayın. UI yine dostça bir mesaj gösterebilir, ama kural tek bir yerde yaşar.
İlerlemeden önce, değişiklikleri geri almayı kolaylaştıracak kadar test ekleyin:
Hızlı iterasyon için Koder.ai gibi araçlar kullanıyorsanız, servisler bir sabit (anchor) olur. Rotalar ve UI gelişebilir, ama kurallar stabil ve test edilebilir kalır.
Rotalar stabil ve servisler mevcut olduktan sonra veritabanının “her yerde” olmasına izin vermeyi bırakın. Ham sorguları küçük, sıkıcı bir veri erişim katmanının arkasına saklayın.
Küçük bir modül (repository/store/queries) oluşturun ve GetUserByEmail, ListInvoicesForAccount veya SaveOrder gibi net isimli birkaç fonksiyon sunun. Burada zerafet peşinde koşmayın. Her SQL dizesi veya ORM çağrısı için bir bariz yer hedefleyin.
Bu aşamayı yalnızca yapı üzerine sıkı tutun. Şema değişikliklerinden, indeks düzeltmelerinden veya “buradayken” migration'lardan kaçının. Onlar kendi planlanmış değişikliklerini ve rollback'ini hak eder.
Yaygın prototip kokusu, dağınık transaction'lardır: bir fonksiyon işlem başlatır, başka bir fonksiyon sessizce kendi işlem açar ve hata işleme dosyadan dosyaya değişir.
Bunun yerine, bir callback'i bir işlem içinde çalıştıran bir giriş noktası oluşturun ve repository'lerin bir transaction context kabul etmesine izin verin.
Küçük hareketler yapın:
Örneğin, “Proje Oluştur” proje eklerken varsayılan ayarları da ekliyorsa, her iki çağrıyı tek bir transaction helper içinde sarın. Bir yerde yarıda kalınırsa, proje ayarları olmadan kalan bir proje oluşmasın.
Servisler somut bir DB istemcisi yerine bir arayüze bağımlı olduğunda, gerçek bir veritabanı olmadan çoğu davranışı test edebilirsiniz. Bu korkuyu azaltır; işte bu aşamanın amacı budur.
UI temizliği işi güzelleştirmek değil. Ekranları öngörülebilir kılmak ve sürpriz yan etkileri azaltmaktır.
UI kodunu teknik türüne göre değil, özelliğe göre gruplayın. Bir feature klasörü ekranı, daha küçük bileşenleri ve yerel yardımcıları barındırabilir. Tekrarlanan işaretlemeyi gördüğünüzde (aynı buton satırı, kart veya form alanı), bunu çıkarın ama işaretleme ve stili aynı tutun.
Props'ları sıkıcı tutun. Bileşenin gerçekten ihtiyaç duyduğu şeyi geçirin (stringler, id'ler, boolean'lar, callback'ler). Bir büyük nesneyi "olur da lazım olur diye" geçiriyorsanız, daha küçük bir şekil tanımlayın.
API çağrılarını UI bileşenlerinden çıkarın. Servis katmanı olsa bile, UI kodu genellikle fetch mantığı, retry'ler ve eşleme içerir. Ekran için hazır veriyi döndüren küçük bir client modülü per feature (veya API alanı) oluşturun.
Sonra yüklenme ve hata işleme tutarlı hale getirin. Bir desen seçin ve yeniden kullanın: öngörülebilir bir yüklenme durumu, tek bir tekrar eylemi olan tutarlı bir hata mesajı ve bir sonraki adımı açıklayan boş durumlar.
Her çıkarımdan sonra dokunduğunuz ekranın kısa bir görsel kontrolünü yapın. Ana eylemleri tıklayın, sayfayı yenileyin ve bir hata durumunu tetikleyin. Küçük adımlar büyük UI yeniden yazımlarından daha iyidir.
Küçük bir prototip hayal edin: üç ekran var — oturum açma, öğe listesi, öğe düzenleme. Çalışıyor, ama her rota auth kontrolleri, iş kuralları, SQL ve UI state'i karıştırıyor. Amaç, sadece bu özelliği geri alınabilir değişikliklerle temiz bir modüle dönüştürmek.
Önce, “items” mantığı şu şekilde dağılmış olabilir:
server/
main.go
routes.go
handlers.go # sign in + items + random helpers
db.go # raw SQL helpers used everywhere
web/
pages/
SignIn.tsx
Items.tsx # fetch + state + form markup mixed
Sonra, davranış aynı kalır ama sınırlar netleşir:
server/
routes/
items_routes.go
handlers/
items_handler.go
services/
items_service.go
repositories/
items_repo.go
web/
pages/
Items.tsx
components/
ItemForm.tsx
Önce kodu mantığını değiştirmeden taşıyarak başlayın. Fonksiyon adlarını ve dönüş şekillerini büyük ölçüde aynı tutun, böylece rollback çoğunlukla dosya taşımalara indirgenir.
Önce bir rotayı refaktör edin. Handler sadece HTTP ile ilgilenmeli, kural veya SQL ile değil:
// handlers/items_handler.go
func (h *ItemsHandler) UpdateItem(w http.ResponseWriter, r *http.Request) {
userID := h.auth.UserIDFromRequest(r) // same auth logic as before
itemID := mux.Vars(r)["id"]
var in UpdateItemInput
json.NewDecoder(r.Body).Decode(&in)
item, err := h.itemsService.UpdateItem(r.Context(), userID, itemID, in)
if err != nil { writeError(w, err); return }
writeJSON(w, item)
}
Sonra iş kurallarını bir servise taşıyın. Buraya “kullanıcı sadece kendi öğesini düzenleyebilir” veya “isim boş olamaz” gibi kontroller koyarsınız. Servis bir repository'yi DB işi için çağırır:
// services/items_service.go
func (s *ItemsService) UpdateItem(ctx context.Context, userID, itemID string, in UpdateItemInput) (Item, error) {
if strings.TrimSpace(in.Name) == "" { return Item{}, ErrInvalidName }
return s.repo.UpdateItem(ctx, userID, itemID, in)
}
Ardından DB erişimini repository fonksiyonunda izole edin:
// repositories/items_repo.go
func (r *ItemsRepo) UpdateItem(ctx context.Context, userID, itemID string, in UpdateItemInput) (Item, error) {
row := r.db.QueryRowContext(ctx,
`UPDATE items SET name=$1 WHERE id=$2 AND user_id=$3 RETURNING id, name`,
in.Name, itemID, userID,
)
var it Item
err := row.Scan(&it.ID, &it.Name)
return it, err
}
UI tarafında sayfa düzenini koruyun, ama tekrar eden form işaretlemesini hem "yeni" hem "düzenle" akışında kullanılan ortak bir bileşene çıkarın:
pages/Items.tsx veri çekme ve gezinmeyi korurcomponents/ItemForm.tsx input alanları, doğrulama mesajları ve gönder butonunu yönetirEğer Koder.ai (koder.ai) kullanıyorsanız, kaynak kodu dışa aktarma daha derin refaktörlerden önce faydalı olabilir ve snapshot/rollback, bir taşınma ters giderse hızla toparlanmanızı sağlar.
En büyük risk “taşıma” işiyle “değiştirme” işini karıştırmaktır. Dosyaları taşırken mantığı aynı anda yeniden yazdığınızda, hatalar gürültülü diff'lerde saklanır. Taşımayı sıkıcı tutun: aynı fonksiyonlar, aynı girdiler, aynı çıktılar, yeni ev.
Bir diğer tuzak davranışı değiştiren temizliktir. Değişken yeniden adlandırmak sorun değil; kavramları yeniden adlandırmak sorun yaratır. Eğer status string'den sayıya geçerse, ürün değil kodu değiştirmiş olursunuz. Bunu daha sonra net testlerle ve kasıtlı bir sürümle yapın.
Erken aşamada geleceğe hazırlık için büyük bir klasör ağacı ve çok katmanlı yapı kurmak cazip gelir. Bu genellikle sizi yavaşlatır ve işin nerede olduğunu görmek zorlaştırır. En küçük faydalı sınırlarla başlayın, bir sonraki özellik zorladığında genişletin.
Ayrıca UI'nın doğrudan veritabanına eriştiği veya ham sorguları bir yardımcı üzerinden çağırdığı kısayollara dikkat edin. Hızlı hisseder ama her ekranı izinler, veri kuralları ve hata işlemeyle sorumlu kılar.
Risk çoğaltıcılar:
null veya genel bir mesaja dönüşür)Küçük örnek: bir ekran { ok: true, data } beklerken yeni servis { data } döndürüp hatalarda throw ederse, uygulamanın yarısı kullanıcı dostu mesajları göstermeyi bırakabilir. İlk olarak sınırda eski şekli tutun, sonra çağıranları teker teker taşıyın.
Bir sonraki adıma geçmeden önce ana deneyimi bozmadığınızı kanıtlayın. Her seferinde aynı ana akışı çalıştırın (oturum aç, öğe oluştur, görüntüle, düzenle, sil). Tutarlılık küçük regresyonları fark etmenizi sağlar.
Her aşamadan sonra basit bir git/çoğunluk kapı ölçütü uygulayın:
Bunlardan biri başarısızsa, üzerine inşa etmeden önce durun ve düzeltin. Küçük çatlaklar ileride büyük olur.
Merge'den hemen sonra beş dakika harcayıp geri dönebileceğinizi doğrulayın:
Kazanım ilk temizleme değil. Kazanım, şekli koruyarak özellik eklemeye devam etmektir. Mükemmel mimari peşinde koşmuyorsunuz. Gelecek değişiklikleri tahmin edilebilir, küçük ve geri alınabilir kılıyorsunuz.
Bir sonraki modülü etki ve risk temelinde seçin, canınızı sıkan değil. İyi hedefler: kullanıcıların sık dokunduğu, davranışın zaten anlaşıldığı parçalar. Belirsiz veya kırılgan alanları daha iyi testler veya ürün cevapları elde edene kadar bırakın.
Basit bir ritim tutun: bir şeyi taşıyan küçük PR'lar, kısa inceleme döngüleri, sık dağıtımlar ve bir dur-kuralı (kapsam büyürse böl ve küçük parçayı gönder).
Her aşamadan önce bir geri alma noktası belirleyin: bir git tag, bir release branch veya çalıştığını bildiğiniz deploy edilebilir bir build. Eğer Koder.ai üzerinde çalışıyorsanız, Planlama Modu değişiklikleri aşamalamanıza ve üç katmanı birden refaktör etmemenize yardımcı olur.
Modüler uygulama mimarisi için pratik bir kural: her yeni özellik aynı sınırları izlesin. Rotalar ince kalsın, servisler iş kurallarına sahip olsun, veritabanı kodu tek bir yerde yaşasın ve UI bileşenleri gösterime odaklansın. Yeni bir özellik bu kuralları kırarsa, değişiklik küçükken erken refaktörleyin.
Varsayılan: bunu risk olarak ele alın. Küçük bir cevap-şekli (response shape) değişikliği bile birden fazla ekranı bozabilir.
Bunun yerine yapın:
İnsanların günlük olarak yaptığı, temel katmanları (auth, rotalar, DB, UI) etkileyen bir akış seçin.
Varsayılan iyi bir seçenek:
Tekrar çalıştırmak için küçük tutun. Ayrıca bir hata durumu da ekleyin (ör. gerekli alan eksik) ki hata işleme regresyonlarını erken fark edin.
Dakikalar içinde uygulayabileceğiniz bir geri alma planı kullanın.
Pratik seçenekler:
Rollback'i erken bir aşamada doğrulayın (gerçekten yapın), böylece teoride kalan bir plan olmasın.
Güvenli bir varsayılan sıra:
Bu sıra patlama alanını (blast radius) azaltır: her katman bir sonraki ele alınmadan önce net bir sınır olur.
“Taşıma” ve “değiştirme”yi ayrı görevler yapın.
Yardımcı kurallar:
Davranışı değiştirmeniz gerekiyorsa, bunu daha sonra açık testlerle ve planlı bir sürümle yapın.
Evet — diğer eski kod tabanları gibi ele alın.
Pratik yaklaşım:
CreateOrderLegacy)Üretilmiş kod, dış davranışı tutarlı tuttuğunuz sürece güvenle yeniden düzenlenebilir.
İşlemleri merkezileştirin ve sıkıcı hale getirin.
Varsayılan desen:
Bu, kısmi yazmaları (ör. bir kayıt oluşturup ilişkili ayarları oluşturmama) önler ve hataları daha kolay izole eder.
Refaktörü daha geri alınabilir kılmak için yeterli test kapsamı ile başlayın.
Minimum faydalı set:
Amaç korkuyu azaltmak, mükemmel bir test paketini gece içinde kurmak değil.
Önce düzeni ve stili değiştirmeyin; öngörülebilirlik üzerine odaklanın.
Güvenli UI temizleme adımları:
Her çıkarımdan sonra kısa bir görsel kontrol yapın ve bir hata durumunu tetikleyin.
Platformun güvenlik özelliklerini kullanarak değişiklikleri küçük ve geri alınabilir tutun.
Pratik varsayılanlar:
Bu alışkanlıklar ana hedefi destekler: küçük, geri alınabilir refaktörlerle istikrarlı ilerleme.