"Kolonlar yetmiyor" - Hem en iyi hem de en kötü olan kod tabanı
(jimmyhmiller.github.io)"
merchants2tablosu mu? Evet,merchantstablosundaki kolonlar yetmediği içinmerchants2yi oluşturduk."
- Programlamaya ilk başladığımda, insanların programlamadan para kazandığını bilmiyordum
- İlk yazılım işimde çok şey öğrendim ve oradaki kod tabanı hem en kötüsüydü hem de en iyisiydi
Veritabanları sonsuza kadar yaşar
- Legacy sistemlerde veritabanı, basit bir veri deposundan daha fazlasıdır. Tüm sistemin kısıtlarını belirler ve tüm kodun buluştuğu noktadır
- SQL Server'da tablolardaki kolon sayısı için bir sınır vardır. O zamanlar 1024'tü, bugün 4096.
Merchantstablosunda kolon kalmayıncaMerchants2tablosunu oluşturduk (500'den fazla kolon içeriyordu) MerchantsveMerchants2sistemin çekirdeğiydi. Her şeyMerchants'a bağlıydı. Başka normalize tablolar da vardı ama onlar daMerchantsile foreign key ilişkisine sahipti
SequenceKey
SequenceKey, tek bir kolon ve tek bir değere sahip basit bir tabloydu- ID üretmek için kullanılıyordu. SQL Server'ın otomatik artan ID'leri desteklemediği düşünülerek yapılmış gibiydi
- Tüm stored procedure'ler
SequenceKey'den anahtar alıp artırıyor ve bunu birden çok tablonun ID'si olarak kullanıyordu. Örtük join görevi görüyordu
Calendar
Calendar, elle doldurulmuş bir takvim tablosuydu.Calendarsüresi dolarsa sisteme giriş yapılamıyordu- Birkaç yıl önce bu gerçekten oldu ve bir stajyer 5 yıllık daha veri ekledi. Bunu hangi sistemin kullandığını kimse bilmiyor
Employees
- Her sabah 7:15'te
employeestablosu siliniyor ve ADP'den gelen bir CSV ile yeniden dolduruluyordu - Bu işlem sırasında sisteme giriş yapılamıyordu. Bazen bu işlem başarısız oluyordu
- Verinin merkeze replikasyonu gerektiği için e-postayla bir kişiye gönderiliyor ve o kişi her gün bir düğmeye basarak veriyi kopyalıyordu
Yedek veritabanı
- İnsan, veritabanını temizleyip toparlayamaz mıyız diye düşünebilir. Şirket de böyle düşündü
- Veritabanının bir kopyası vardı ama veri yaklaşık 10 dakika geriden geliyordu. Senkronizasyon yalnızca tek yönlüydü
- Bu veritabanı normalize edilmişti;
merchantsiçinden bir telefon numarası bulmak için 7 join gerekiyordu
Satış performansı
- Her satış temsilcisinin her ay tutturması gereken
winadlı bir kotası vardı - Bunu yöneten tablo çok karmaşıktı. Her gün bir iş çalışıyor, eklenen/değiştirilen satırları bulup merkez sistemle senkronize ediyordu
- Bir satış temsilcisi bir kaydı elle değiştirmemizi isteyince sorun başladı
- Bu temsilci zaten
winkotasını doldurmuştu ve aynı ay içinde büyük bir satış daha yapmıştı; bunu sonraki aya taşımak istiyordu - Bu iş bir stajyere verildi ve dedikodu yayılınca 3 yıl boyunca talepler katlanarak arttı
- Bir ara 3 stajyerin tüm işi SQL cümleleri yazmaktı. Bunun için uygulama yapmak fazla zor görülüyordu
Kod tabanı
- Karşılaştığım ilk kod tabanı Team Foundation Server'daydı. Merkezi bir versiyon kontrol sistemiydi
- En çok üzerinde çalıştığım kod tabanı yarı VB, yarı C# idi. IIS üzerinde çalışıyordu ve her yerde session state kullanıyordu
- Bu pratikte şu anlama geliyordu: bir sayfaya Path A'dan mı yoksa Path B'den mi geldiğinize bağlı olarak tamamen farklı şeyler görebiliyordunuz
- O dönemde var olan neredeyse tüm JavaScript framework'leri bu repoya check-in edilmişti. Genelde yazarının gerekli gördüğü özel değişikliklerle birlikteydi. Özellikle
knockout,backbone,marionettedikkat çekiyordu; ayrıcajqueryvejqueryeklentileri de vardı - Bu kod tabanının dışında yaklaşık 12 SOAP servisi ve birkaç native Windows uygulaması daha vardı
Gilfoyle'un sabit diski
- Gilfoyle inanılmaz hızlı bir programcı olarak biliniyordu. Onunla hiç tanışmadım ama kodundan ve sabit diskinde kalan kodlardan onu tanıyordum
- Munch, Gilfoyle şirketten ayrıldıktan yıllar sonra bile onun sabit diskini RAID yapılandırmasıyla masasının üstünde tutuyordu
- Çünkü Gilfoyle, kodunu check-in etmemesi ve tek kullanıcı için rastgele tek seferlik Windows uygulamaları yapmasıyla ünlüydü
- Kullanıcıların, yalnızca Gilfoyle'un sabit diskinde bulunan uygulamalarla ilgili hata raporlarıyla gelmesi olağan dışı değildi
Kargo hatası
- İşimin büyük bölümü, ekibin üstlenmek istemediği bug'ların peşine düşmekti
- Birkaç ayda bir görülen özellikle sinir bozucu bir hata vardı: gönderilmiş siparişler sevkiyat kuyruğunda takılı kalıyor, yani hem gönderilmiş oluyor hem de gönderilmemiş gibi görünüyordu
- Bunu çözmek için çeşitli yollar denedik (SQL script'leri, Windows uygulamaları vb.). Kök nedeni araştırmamam tavsiye edilmişti ama dayanamıyordum
- Bu süreçte Gilfoyle'un nasıl düşündüğünü öğrendim. Kargo uygulaması tüm veritabanını çekiyor, sonra tarihe göre filtreleyip uygulamanın başlangıç tarihinden sonraki tüm siparişleri tutuyordu
- Uygulama bir SOAP servisine bağlıydı ama servis gibi davrandığı için değil; aslında saf fonksiyonlardan ibaretti. Tüm yan etkileri yaratan istemciydi
- İstemcide devasa bir sınıf hiyerarşisi keşfettim: çeşitli metotlara sahip 120 sınıf vardı ve kalıtım 10 seviyeye kadar iniyordu
- Tek sorun, tüm metotların boş olmasıydı
- Bunun nedeni reflection kullanılabilecek bir yapı kurmaktı. Bu reflection, pipe (
|) ile ayrılmış bir string oluşturuyor (veritabanına dayalı ama tamamen statik bir yapı) ve bunu socket üzerinden gönderiyordu - Sonunda bu veri, taşıyıcılarla iletişim kuran bir servis olan Kewill'e gidiyordu. Bug'ın nedeni, Kewill'in her ay 9 haneli numaraları yeniden kullanması ve birinin eski siparişleri silen
cronişini devre dışı bırakmış olmasıydı
Güzel kaos
- Bu kod tabanı hakkında anlatacak çok şey var. Örneğin 5 yıl boyunca kod yayımlamadan her şeyi baştan yazan kıdemli geliştirici ekibi ya da her şeyi kontrol edecek tek bir veritabanı kurmaya çalışan Red Hat danışmanları
- Bu kod tabanında pek çok çılgın köşe vardı ve tek bir özelliği sıfırdan başlatmak için özel bir ekip gerektirecek birçok sebep bulunuyordu
- Ama en önemli hikâye, Justin'in Merchants Search sayfasını iyileştirmesiydi. Bu sayfa tüm uygulamanın giriş noktasıydı
- Tüm müşteri hizmetleri temsilcileri, telefonda bir tüccarla konuşurken ID ya da ad girip bilgi arıyordu. Sonra tüm bilgileri içeren devasa bir sayfaya gidiyorlardı
- Bu sayfa, ihtiyaç duyulan her bilgiyle ve gitmek istenen tüm linklerle doluydu; en iyi anlamda bilgi yoğun bir yapıdaydı. Ama korkunç derecede yavaştı
- Justin benim grubumdaki tek kıdemli geliştiriciydi. Zeki ve alaycıydı, iş tarafına da pek ilgisi yoktu
- Gerçeği söylerdi, lafını esirgemezdi ve etrafındaki ekiplerden her zaman daha hızlı şekilde sorunları tek başına çözebilirdi
- Bir gün Justin, tüccar arama sayfasının ne kadar yavaş olduğuna dair şikâyetleri duymaktan bıktı ve gidip bunu düzeltti
- Ekrandaki her kutu kendi endpoint'ine dönüştü. Yükleme sırasında ekranın üst kısmındaki her şey çekilmeye başlıyor, biri yüklenince daha fazla istek geliyordu
- Sayfa yükleme süresi birkaç dakikadan 1 saniyenin altına indi
Decoupling için iki yöntem
- Justin'in bunu yapabilmesinin nedeni, bu kod tabanında bir master plan olmamasıydı
- Sistemin uyması gereken kabaca bir plan yoktu; API'lerin beklenen formatı, dokümante edilmiş bir tasarım sistemi ya da tutarlılığı garanti eden bir mimari inceleme kurulu da yoktu
- Uygulama tam bir keşmekeşti. Kimse düzeltemediği için denemiyordu bile. Bunun yerine herkes kendi küçük akıl adasını kuruyordu
- Bu monolitik uygulama, tamamen ihtiyaç nedeniyle kenarlarında iyi ve küçük uygulamalardan oluşan bir mikrokozma dönüştü
- Uygulamanın bir bölümünü iyileştirme görevi verilen herkes, er ya da geç o örümcek ağını çözmeye çalışmaktan vazgeçiyor ve yeni bir şey inşa edebileceği iyi, küçük bir köşe buluyordu. Sonra da linkleri yavaş yavaş güncelleyip yeni iyi şeyi işaret ediyor, eskisini yetim bırakıyordu
- Bu kulağa dağınık gelebilir. Ama üzerinde çalışmak şaşırtıcı derecede keyifliydi. Kod tekrarından kaygı duymuyordunuz, tutarlılığı dert etmiyordunuz, ölçeklenebilirlik de bir endişe olmaktan çıkıyordu
- Kod kullanılmak için yazılıyordu; çevresindeki alanlara mümkün olduğunca az dokunuyor ve kolayca değiştirilebilecek şekilde tasarlanıyordu. Kodumuz decoupled'dı, çünkü coupling kurmak basitçe daha zordu
Sonrası
- Sonraki kariyerimde bir daha bu kadar şaşırtıcı derecede çirkin bir kod tabanında çalışma ayrıcalığına sahip olmadım
- O günden sonra karşılaştığım tüm çirkin kod tabanları, tutarlılık ihtiyacını aşmayı başaramadı
- Belki de bunun sebebi, “ciddi” geliştiricilerin kod tabanını çok önceden terk etmiş olmasıydı. Geriye sadece dağınık stajyerler ve junior geliştiriciler kalmıştı
- Ya da belki geliştiricilerle kullanıcılar arasında bir ara katman olmadığı içindi. Çeviri yoktu, gereksinim toplama yoktu, kartlar yoktu. Sadece müşteri hizmetleri temsilcisinin masasının önünde durup hayatlarını nasıl iyileştirebileceğinizi soruyordunuz
- O doğrudan bağı özlüyorum. Hızlı geri bildirimi, büyük planlar yapma gereği olmayışını, basit problemlerle kod arasındaki bağlantıyı
- Belki de bu sadece saf bir nostaljidir. Ama nasıl çocukluğumun en kötü yıllarına dönmek istiyorsam, “enterprise design patterns” ile her karşılaştığımda zihnim o güzel ve korkunç kod tabanına geri dönüyor
GN⁺ görüşü
- Bu yazı, legacy sistemlerle uğraşan geliştiricilere empati ve teselli sunabilir. Kusursuz olmayan kod tabanlarının da değerli olabileceğini ve çok şey öğretebileceğini gösteriyor
- Ancak bu kod tabanındaki sorunlar romantize edilmemeli. Teknik borç biriktiğinde geliştirme hızını ciddi biçimde düşürür ve bakımı zorlaştırır. Uzun vadede maliyeti daha yüksektir
- Kod tabanını iyileştirme çabasından vazgeçip geçici çözümler üstüne yenilerini eklemek doğru cevap değildir. Legacy sistemleri kademeli olarak iyileştirecek ya da migrate edecek bir strateji gerekir
- Geliştirme kültürü ve süreçler de önemlidir. Code review, mimari tasarım, dokümantasyon gibi mühendislik pratiklerini iyi uygulamak, daha iyi bir kod tabanı oluşturmaya yardımcı olur
- Kullanıcılarla yakın iletişim ve hızlı geri bildirim olumlu yönlerdir. Bunu Agile gibi metodolojilerle teşvik ederken aynı zamanda kod kalitesini de yönetmek ideal olandır
- Sonuçta her şey denge meselesidir. Mükemmelliği kovalamaktan ziyade, kullanıcı ihtiyaçlarını sürdürülebilir bir şekilde karşılamak ve teknik borcu yönetmek önemlidir
3 yorum
İlk işimde firmware geliştiricisi olarak aldığım görev, geliştiricisi ve kaynak kodu olmayan bir ürünün 8051 MCU’sunun hex’inden çıkarılan assembly kodunu analiz edip C ile yeniden gerçekleştirmekti…
En azından çalışan bir ürün vardı; koda bakıp ürünü test ederek bir şekilde başarmıştım…
Taşra iş seyahatine gidip ya tamir edip geleceğim ya da parmağımı kesip döneceğim şeklinde tehditler de duymuştum
Sebebi bilinmeyen bir bug’ın aslında cihazın kurulu olduğu duvarın arkasındaki asansörden kaynaklandığı bir zaman da olmuştu
Bir de Busan Dongbaekseom APEC toplantı salonuna resmî açılıştan önce girip şunu bunu kurduğumu hatırlıyorum haha
Hacker News görüşleri
İlk şirketinde karmaşık bir VB uygulamasını yönetmiş
İlk işinde COBOL ve Java ile yazılmış legacy bir ürünü bakımını yapmış
12.000 satırdan uzun bir Perl scriptini refactor etmiş
Teori ile pratik arasındaki farkı hissetmiş
Telegram Android istemcisinin kod tabanı çok karmaşıkmış
İlk işinde raporlama iş yükünün bellek sorununu çözmüş
Müşterilerle doğrudan iletişim kurup sorun çözme deneyimini sevmiş
Birden fazla pazarı destekleyen bir sistem geliştirmiş
İlk işinde deneyimsiz insan çokmuş
Modern SQL Server'da sorunların nasıl çözüldüğünü anlatmış
Numaralandırma tablosu (SequenceKey) ve iş günü tablosu (Calendar)
İnsana nostalji yaşatıyor. Şimdi nasıl yapılıyor bilmiyorum ama eskiden yaygın olarak kullanılan tablolardı. SI yapıldığında, işin ortak bölümünde ilgili işlevler implemente edilirdi.