17 puan yazan GN⁺ 2024-08-04 | 3 yorum | WhatsApp'ta paylaş

"merchants2 tablosu mu? Evet, merchants tablosundaki kolonlar yetmediği için merchants2yi 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. Merchants tablosunda kolon kalmayınca Merchants2 tablosunu oluşturduk (500'den fazla kolon içeriyordu)
  • Merchants ve Merchants2 sistemin çekirdeğiydi. Her şey Merchants'a bağlıydı. Başka normalize tablolar da vardı ama onlar da Merchants ile 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. Calendar sü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 employees tablosu 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; merchants içinden bir telefon numarası bulmak için 7 join gerekiyordu

Satış performansı

  • Her satış temsilcisinin her ay tutturması gereken win adlı 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 win kotası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, marionette dikkat çekiyordu; ayrıca jquery ve jquery eklentileri 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 cron iş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

 
bus710 2024-08-07

İ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

 
GN⁺ 2024-08-04
Hacker News görüşleri
  • İlk şirketinde karmaşık bir VB uygulamasını yönetmiş

    • Her müşterinin gereksinimine göre uyarlanmış çok sayıda global değişken varmış
    • Hata yalnızca debug modunda ortaya çıkmadığı için müşteriye Visual Studio kurdurup uygulamayı debug modunda çalıştırmayı öğretmişler
    • Sürüm kontrolü yokmuş ve kod birden fazla klasöre kopyalandığı için ortalık karışmış
    • Müşteri tarafında sorun çıktığında kodu yerinde değiştirirlermiş
    • Nihai sürüm konusunda uzlaşma olmadığından her müşteri farklı bir sürüm kullanıyormuş
  • İlk işinde COBOL ve Java ile yazılmış legacy bir ürünü bakımını yapmış

    • Kaynak kontrol sisteminde dosyaları tek tek check-out ederek çalışıyormuş
    • Her müşteri için nihai derlenmiş ürünü temsil eden bir "master" jar dosyası varmış
    • Kod değişikliğinden sonra bir script çalıştırarak master jar dosyasını güncelliyormuş
    • Kod tabanı baştan sona derlenmiyor, elle patch uygulanıyormuş
    • Kod tabanında çok sayıda tutarsızlık oluşmuş
    • Git'e geçiş 2 yıl sürmüş
  • 12.000 satırdan uzun bir Perl scriptini refactor etmiş

    • Dizileri bilmeyen yazar, dizileri string kullanarak taklit etmiş
    • Refactor sonrası kod 200 satıra düşmüş
  • Teori ile pratik arasındaki farkı hissetmiş

    • Pek çok şirket ve proje benzer süreçlerden geçiyor
    • İdeal yöntemler tartışılıyor ama pratikte işler yürüyen şekilde ilerliyor
  • Telegram Android istemcisinin kod tabanı çok karmaşıkmış

    • Büyük dosyalar yüzünden GitHub render etmeyi bırakmış
    • Tüm mesaj render etme ve etkileşim işlemleri tek bir sınıfta ele alınıyormuş
    • Refactor izni almış ama uygulayamamış
  • İlk işinde raporlama iş yükünün bellek sorununu çözmüş

    • Takım lideri ve yöneticisi şaşırmış
    • Diğer geliştiriciler Linux'tan nefret ediyor ve .NET'e geçmek istiyormuş
  • Müşterilerle doğrudan iletişim kurup sorun çözme deneyimini sevmiş

    • Hızlıca prototip hazırlayıp müşteriye test ettirmiş
    • Kod tabanı dağınıkmış ama iyi çalışıyormuş
  • Birden fazla pazarı destekleyen bir sistem geliştirmiş

    • Orijinal sistemi kopyalayarak uluslararası sürümü oluşturmuş
    • 5 yıl sonra sistemler ayrışmak yerine birbirine dolanmış
    • Yeni sistem ile eski sistem sıkı biçimde birbirine bağlıymış
  • İlk işinde deneyimsiz insan çokmuş

    • Deneyim kazandıktan sonra daha iyi bir işe geçmiş
  • Modern SQL Server'da sorunların nasıl çözüldüğünü anlatmış

    • Müşteri özelleştirmeleri, paylaşılan ID'ler, manuel takvim tabloları, tablo partitioning, gecikmeli raporlama replikaları vb.
    • VB ve C# karışık kod tabanları yaygın
    • Otomatik dönüştürme araçları kullanılabiliyor
 
reddiana 2024-08-05

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.