Sürdürülebilir Yazılım 101, Esnek Bağın Önemi – Loose Coupling

Uzun bir aradan sonra tekrar merhaba 👋

Şubat 2020’den beri Appcent şirketi adına Türkiye İş Bankası’nda, Maximum İşyerim ve bazen de bağlılığımızdan dolayı Maximum Mobil ürünlerinde backend developer olarak görev aldım. Daha henüz 11 yaşında satranç federasyon ücretimi yatırmak için, milli duygularla da 18 yaşına gelir gelmez ilk kez banka hesabımı açmak için gittiğim bu kuruma, yıllar sonra geliştirici olarak gelecektim.

Bu süreçte sprintlerimiz içerisinde yeni geliştirmeleri, yeni özellikleri canlı ortama aldık. Özellikle WeChat entegrasyonu, Türkiye İş Bankası’nın yeni iştiraki, yeni e-ticaret platformu olan Pazarama şirketleşmesinde büyük rol oynayacak; ticari ve bireysel kullanıcılara Gördüm Aldım modülünün yayımlanması, BKM Karekod entegrasyonu (FAST), POS’um Cepte ile mobil uygulamadan temassız kartlarla ödeme alma ve talep adlarını hatırlamadığım, yazmayı unuttuğum diğer nice geliştirmeleri ekipçe başardık. Ekibime bu yüzden çok teşekkür ederim.

Böylesine büyük kurumlarda çalışmak, yazılım geliştirme açısından neden işlerin doğru yürütülmesi gerektiğini bir kez daha hatırlattı. Diyeceklerimi ister bireysel geliştirmelerinizde isterseniz ekipçe geliştirmelerinizde dikkate alınız. Büyük yazılımlar geliştirmeler tek başına olabilecek bir şey değildir, ekip işidir. Özellikle beş milyondan fazla kullanıcıya hitap eden uygulamalar/bileşenler geliştiriyorsanız ekibe/ekiplere ihtiyacınız vardır. Ekip/ekipler kendi sorumluluğunda geliştirmeler yapar. Tam bu noktada ekibin yönetilmesi, yapılacak işler, uygulanacak süreçler, metotlar vb. durumlar ortaya çıkar. Ekibin bu iş kolundaki faaliyetteki bilgisi, yazılım geliştirme konularında deneyim yeterliliği; müşterinin beklentileri (geliştirmeyi talep eden kişi/kurum), oluşabilecek sorunlarda destek noktalarının oluşturulması ve en önemlisi her zaman sürdürülebilir uygulama yaratmak bu işin en önemli kriterlerindendir. Sürdürülebilir uygulama derken, ilgili uygulamada yeni geliştirmeleri tamamlayabilmekten, bakımları gözardı edilmeyen test edilebilir bir uygulamadan bahsediyorum.

Her ekip planlı teslimat yapmak (canlı ortama taşımak) hedefindedir. Kullanılan proje yönetim modeline göre (Scrum, Kanban) ekipler kendi planlarında geliştirmelerini yapabilir. Planlı teslimat aslında bu işin sihirli kelimesi. Hedef bellidir, X geliştirmesini Y tarihinde yayına almak istiyoruz.

Örnekler

Biraz daha derine gidelim, net örnekler verelim. Olabildiğince basit tutalım. Basit bir login uygulamamız olsun.

Sistemdeki kullanıcılar için yukarıdaki kodları içeren bir oturum uygulamamız olsun. Ardından müşterimiz, bizimle şöyle bir user story (kullanıcı hikayesi) paylaşarak yeni bir geliştirme talebi olsun:

Sistemdeki kullanıcılar için giriş ekranlarından, giriş bilgilerini girerek oturumlarını açarlar. Oturum açma esnasında bilgileri doğru olan kullanıcılara, ikinci bir kontrol daha yapılmak üzere kendilerine bir sms gitmesi gerekmektedir. Sistemde kayıtlı olan telefon numarasına, gönderilecek sms bilgisi içerisinde yer alan şifre, kullanıcı tarafından bir sonraki ekranda istenilmek üzere iletilir. Bu kontroller sonrası bireysel kullanıcının başarılı giriş yaptığı kabul edilir.

Çok basit bir talep değil mi? 😅 Tahmin ediyorum ki, SMS servisini hızlıca uyarlayıp aşağıdakine benzer bir kod yazacaktınız.

Yalnız yukarıdaki kodu yazarken sizi tebrik ederim, ister istemez bir bağımlılık yarattınız. SMSSenderService nesnesi doğrudan UserManager tarafından bağımlı nesne haline geldi. Ek olarak kodunuz test edilemez haline de gelmiş oldu. Çünkü SMSSenderService nesnesini hem Dependency Injection (Bağımlılık Enjeksiyonu) kullanmadınız hem de doğrudan concrete (somut) nesne oluşturdunuz. Bir interface, bir arayüz mü yazsaydık hayrına? Belki ileride lazım olurdu?

Anahtar Kelimeler: Interface ve abstract
Anahtar Yöntem: Injection

Ekip ve ekiplerden bahsetmiştik. Bu ekip/ekipler geliştirme sürelerince kendi sorumluluk alanlarında kaçınılmaz bir bağımlılık yaratır. Düşük maliyetli gibi gözükse de kendi ekosistemleri ya da kendilerine/kendilerinin entegre oldukları diğer alt/üst sistemlerde yaşanan bağımlılıklar, uzun vadede büyük sorunlara yol açabilir. Mesela test edilemeyen bir kod yazmak, ileride size ya da ekibinize ciddi bakım/değişim maliyeti doğuracaktır. Süresini tahmin edebiliyor musunuz? Ben sizin yerinize tecrübelerime göre cevaplayayım, X zamanda test edilemeyen bir kod geliştirdiyseniz, orta vadede X zamanda geliştirdiğinizden daha fazla efor harcanılıyor. Çünkü bağımlı olduğunuz bir kod bloğuna, bir yapıya, bir nesneye test yazamadınız, onu debug etmeniz, sorunu tespit etmeniz ya da mocklayabilmek için geliştirme yapmanız gerekecektir. Bir defa ilk eforunuz bunu düzeltmekle başlıyor.

Sadece test yazmak üzerinden cevaplamayalım bağımlı nesneleri. Bağımlı nesnelerin içerisindeki kodu ileriki zamanlarda, sıradaki taleplere ya da canlı ortamdaki sorunlara göre değiştirmeniz gerekecektir. SMSSenderService nesnemizi bağımlı hale getirmiştik. Üstelik işlevini yerine getirecek noktada instance alma gafletinde bulunduk. Öncelikle nesneye erişeceksek bunu mümkünse Dependency Injection yaparak, yapıcı metotlar (constructor) üzerinden geçirmemiz bizim yararımıza olacaktır.

Bu kod sayesinde SMSSenderService servisimizi az da olsa esnek hale getirdik fakat hala bağımlıyız. Çünkü SMSSenderService hala bir concrete nesne. Yarın bir gün A SMS servisi yerine, B SMS servisine geçtiğinizde, SMSSenderService nesnesi düzenlemek tam bir iş yükü olacaktır! Bu yüzden anahtar kelimelerimizden interface kullanarak önce SMSSenderService nesnesini arayüz haline getireceğiz. Getireceğiz ki, yarın bir gün ihtiyaç halinde servisleri entegre edebilelim, kodumuzu sürdürülebilir hale getirelim.

Farkettiniz mi, UserManager sınıfında artık istediğim SMS servisini kullanabilirim. Tek yapmam gereken şey yeni kullanacağım nesneyi ISMSSenderService’den miras almak (implement) ve servisin SMS gönderebilmek için ihtiyacı olabilecek iş kurallarını yazmak. Yeter ki esnek bir yapı en başta kurayım. Bu sayede ISMSSenderService’i miras almak şartıyla herhangi bir mock nesne oluşturarak, unit test bile yazabilirim 😁 İşte şimdi esnek bağ yapısını oturttuk. (Yalnız A ya da B servisini de dependency injection ile geçebiliyorsak, bunu böyle yapmanız her zaman tavsiye edilir)

Hadi gelelim bir talep daha yapalım ve örneğimizi pekiştirelim:

Sistemdeki kullanıcılarımızın, ikinci oturumunu kontrol etmek için gönderilen sms mesajlarına ek olarak, aynı anda telefon numaraları üzerinden tanımlı aktif cihaz ya da cihazlarına mobil uygulama üzerinden bildirim ile aynı mesaj metninin gönderilmesi gerekmektedir.

Hmmm.. Aynı telefon numarasına, aynı mesaj.. Bir dakika bunu interface ile yapabilir miyiz?
Yaparız..

Çıkaracağımız Dersler

  • En basit bağımlı gözüken kod, uzun vadede büyük efor getirebilir.
  • Interface ve Abstract keywordleri ve önemi
  • Dependency Injection yöntemi ve önemi
  • Esnek bağ yaratmanın bize nasıl faydalar sağladığı

Kalın sağlıcakla.

Leave a Comment

en_USEnglish
tr_TRTurkish en_USEnglish